/* Automatically generated from Squeak on an Array(9 May 2008 11:25:02 am)
by VMMaker 3.8b6
 */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* Default EXPORT macro that does nothing (see comment in sq.h): */
#define EXPORT(returnType) returnType

/* Do not include the entire sq.h file but just those parts needed. */
/*  The virtual machine proxy definition */
#include "sqVirtualMachine.h"
/* Configuration options */
#include "sqConfig.h"
/* Platform specific definitions */
#include "sqPlatformSpecific.h"

#define true 1
#define false 0
#define null 0  /* using 'null' because nil is predefined in Think C */
#ifdef SQUEAK_BUILTIN_PLUGIN
#undef EXPORT
// was #undef EXPORT(returnType) but screws NorCroft cc
#define EXPORT(returnType) static returnType
#endif
#include <cairo.h>
#include <cairo-ft.h>
#include <pango/pangocairo.h>
#include "SurfacePlugin.h"
#define NUM_OF(array) (sizeof (array) / sizeof *(array))
#define lastIndex(array) (NUM_OF(array) - 1)
#define degrees(a) (a * 3.141592653589793 / 180.0)

#define log(msg) fprintf(stderr, "Squeak-Rome: " msg "\n")
#define logwith(msg, a) fprintf(stderr, "Squeak-Rome: " msg "\n", a)
#define logwithwith(msg, a, b) fprintf(stderr, "Squeak-Rome: " msg "\n", a, b)
#define logwithwithwith(msg, a, b, c) fprintf(stderr, "Squeak-Rome: " msg "\n", a, b, c)
#define logwithwithwithwith(msg, a, b, c, d) fprintf(stderr, "Squeak-Rome: " msg "\n", a, b, c, d)
#define logwithwithwithwithwith(msg, a, b, c, d, e) fprintf(stderr, "Squeak-Rome: " msg "\n", a, b, c, d, e)

#define primFail interpreterProxy->primitiveFail()
#define fail(msg) log(msg "!"); primFail
#define failwith(msg, a) logwith(msg "!", a); primFail
#define failwithwith(msg, a, b) logwithwith(msg "!", a, b); primFail


#include "sqMemoryAccess.h"


/*** Constants ***/
#define CairoExtendRepeat CAIRO_EXTEND_REPEAT
#define CairoOperatorSource CAIRO_OPERATOR_SOURCE
#define CanvasFlagFill 256
#define CanvasFlagStroke 255
#define CanvasFlagsIndex 2
#define CanvasHandleIndex 0
#define CanvasInstSize 8
#define CanvasStrokeColorIndex 3
#define CanvasTargetIndex 1
#define FormBitsIndex 0
#define FormDepthIndex 3
#define FormHeightIndex 2
#define FormInstSize 5
#define FormWidthIndex 1
#define PluginVersion 35
#define TextLineBottomIndex 3
#define TextLineEndIndex 5
#define TextLineInternalSpaceIndex 6
#define TextLineLeftIndex 0
#define TextLinePaddingWidthIndex 7
#define TextLineRightIndex 1
#define TextLineStartIndex 4
#define TextLineTopIndex 2

/*** Function Prototypes ***/
static sqInt addAlignmentinto(sqInt attrArrayOop, PangoAttrList * pangoAttrList);
static sqInt addColorinto(sqInt attrArrayOop, PangoAttrList * pangoAttrList);
static void addColorStopTooffsetrgbalpha(cairo_pattern_t* pattern, sqInt intOffset, sqInt rgb, sqInt alpha);
static sqInt addDefaultInto(PangoAttrList * pangoAttrList);
static sqInt addEmphasisinto(sqInt attrArrayOop, PangoAttrList * pangoAttrList);
static sqInt addFontinto(sqInt attrArrayOop, PangoAttrList * pangoAttrList);
static sqInt addLanguageinto(sqInt attrArrayOop, PangoAttrList * pangoAttrList);
static sqInt addSelectionAtpixelwith(PangoRectangle * rect, unsigned int c, cairo_t* context);
static sqInt addSelectionFromtopixelinto(sqInt start, sqInt end, unsigned int c, PangoAttrList * pangoAttrList);
static cairo_t* contextFrom(sqInt canvasOop);
static sqInt createContextFor(sqInt canvasOop);
static sqInt createSurfaceFor(sqInt formOop);
static sqInt destroyContextFor(sqInt canvasOop);
static sqInt destroySurface(sqInt surfaceID);
static void fillOrStrokefrom(cairo_t* context, sqInt canvasOop);
static cairo_surface_t* findSurface(sqInt surfaceID);
static VirtualMachine * getInterpreter(void);
#pragma export on
EXPORT(const char*) getModuleName(void);
#pragma export off
static sqInt getSurfaceFormatgetWgetHgetDgetMsb(cairo_surface_t * surfaceHandle, int* wReturn, int* hReturn, int* dReturn, int* mReturn);
static sqInt halt(void);
#pragma export on
EXPORT(sqInt) initialiseModule(void);
#pragma export off
static sqInt loadSurfacePlugin(void);
static unsigned char* lockSurfacegetPitchxywh(cairo_surface_t* surfaceHandle, int* pitchReturn, sqInt x, sqInt y, sqInt w, sqInt h);
#pragma export on
EXPORT(sqInt) moduleUnloaded(char * aModuleName);
#pragma export off
static sqInt msg(char * s);
static void polyPathfrom(cairo_t* context, sqInt pointsOop);
#pragma export on
EXPORT(sqInt) primitiveClear(void);
EXPORT(sqInt) primitiveClipRectangleLeftRightTopBottom(void);
EXPORT(sqInt) primitiveClose(void);
EXPORT(sqInt) primitiveCreateFormHandle(void);
EXPORT(sqInt) primitiveDestroyFormHandle(void);
EXPORT(sqInt) primitiveDrawArcRadiusXYFromTo(void);
EXPORT(sqInt) primitiveDrawCurveFromXYviaXYandXYtoXY(void);
EXPORT(sqInt) primitiveDrawCurveFromXYviaXYtoXY(void);
EXPORT(sqInt) primitiveDrawGeneralBezierShape(void);
EXPORT(sqInt) primitiveDrawImageSrcLRTBDestLRTB(void);
EXPORT(sqInt) primitiveDrawLineFromXYtoXY(void);
EXPORT(sqInt) primitiveDrawOvalLeftRightTopBottom(void);
EXPORT(sqInt) primitiveDrawPolygon(void);
EXPORT(sqInt) primitiveDrawPolyline(void);
EXPORT(sqInt) primitiveDrawRectangleLeftRightTopBottom(void);
EXPORT(sqInt) primitiveDrawRoundRectLeftRightTopBottomRadiusCorner(void);
EXPORT(sqInt) primitiveDrawZeroTerminatedUtf8StringXY(void);
EXPORT(sqInt) primitiveFillBitmapOriginXYdirectionXYnormalXYRepeatImage(void);
EXPORT(sqInt) primitiveFillColorAlpha(void);
EXPORT(sqInt) primitiveFillLinearOriginXYdirectionXYcolorStops(void);
EXPORT(sqInt) primitiveFillRadialOriginXYdirectionXYnormalXYcolorStops(void);
EXPORT(sqInt) primitiveFontFace(void);
EXPORT(sqInt) primitiveFontSize(void);
EXPORT(sqInt) primitiveGetLineWidth(void);
EXPORT(sqInt) primitiveGetTransform(void);
EXPORT(sqInt) primitiveOpen(void);
EXPORT(sqInt) primitivePangoBlockAtIndex(void);
EXPORT(sqInt) primitivePangoComposeString(void);
EXPORT(sqInt) primitivePangoFontDescriptionIndex(void);
EXPORT(sqInt) primitivePangoIndexAtPoint(void);
EXPORT(sqInt) primitivePangoIsAvailable(void);
EXPORT(sqInt) primitivePangoShowString(void);
EXPORT(sqInt) primitivePluginVersion(void);
EXPORT(sqInt) primitiveRestoreState(void);
EXPORT(sqInt) primitiveRotateBy(void);
EXPORT(sqInt) primitiveSaveState(void);
EXPORT(sqInt) primitiveScaleBy(void);
EXPORT(sqInt) primitiveSetLineWidth(void);
EXPORT(sqInt) primitiveSetTransform(void);
EXPORT(sqInt) primitiveShowZeroTerminatedUtf8StringXY(void);
EXPORT(sqInt) primitiveStencilImageSrcLRTBDestLRTB(void);
EXPORT(sqInt) primitiveTransformBy(void);
EXPORT(sqInt) primitiveTranslateBy(void);
#pragma export off
static sqInt registerSurface(cairo_surface_t* surfaceHandle);
#pragma export on
EXPORT(sqInt) setInterpreter(struct VirtualMachine* anInterpreter);
#pragma export off
static void setSourcergbalpha(cairo_t* context, sqInt rgb, sqInt alpha);
static sqInt showSurfacexywh(cairo_surface_t * surfaceHandle, sqInt x, sqInt y, sqInt w, sqInt h);
#pragma export on
EXPORT(sqInt) shutdownModule(void);
#pragma export off
static sqInt sqAssert(sqInt aBool);
static sqInt sqCharCountInfromto(unsigned char* aString, sqInt from, sqInt to);
static void strokefrom(cairo_t* context, sqInt canvasOop);
static cairo_surface_t* surfaceFrom(sqInt formOop);
static sqInt translateSqAttrsToPangoAttrsinto(sqInt sqAttrsArrayOop, PangoAttrList * pangoAttrList);
static sqInt unlockSurfacexywh(cairo_surface_t* surfaceHandle, sqInt x, sqInt y, sqInt w, sqInt h);
static sqInt unregisterSurface(sqInt surfaceID);
/*** Variables ***/
static cairo_t* contexts[64];
static PangoFontDescription *defaultFontDescription;
static fn_ioFindSurface findSurfaceFn;
static PangoFontDescription *fontDescriptions[256];
static int formatToDepth[] = {
32, 32, 8, 1, 16};

#ifdef SQUEAK_BUILTIN_PLUGIN
extern
#endif
struct VirtualMachine* interpreterProxy;
static sqInt maxSurfaceID;
static const char *moduleName =
#ifdef SQUEAK_BUILTIN_PLUGIN
	"RomePlugin bf.35 9 May 2008 (i)"
#else
	"RomePlugin bf.35 9 May 2008 (e)"
#endif
;
static fn_ioRegisterSurface registerSurfaceFn;
static sqSurfaceDispatch surfaceDispatch = {
  1,
  0,
  (fn_getSurfaceFormat) getSurfaceFormatgetWgetHgetDgetMsb,
  (fn_lockSurface) lockSurfacegetPitchxywh,
  (fn_unlockSurface) unlockSurfacexywh,
  (fn_showSurface) showSurfacexywh
};
static fn_ioUnregisterSurface unregisterSurfaceFn;


static sqInt addAlignmentinto(sqInt attrArrayOop, PangoAttrList * pangoAttrList) {
	sqInt end;
	int pangoAlignment;
	sqInt start;
	sqInt * attrArray;
	sqInt alignment;

	attrArray = interpreterProxy->firstIndexableField(attrArrayOop);
	start = ((attrArray[1]) >> 1);
	end = ((attrArray[2]) >> 1);
	alignment = ((attrArray[3]) >> 1);
	if (alignment == 0) {
		pangoAlignment = PANGO_ALIGN_LEFT;
	}
	if (alignment == 1) {
		pangoAlignment = PANGO_ALIGN_RIGHT;
	}
	if (alignment == 2) {
		pangoAlignment = PANGO_ALIGN_CENTER;
	}
	if (alignment == 3) {
		null;
	}
}

static sqInt addColorinto(sqInt attrArrayOop, PangoAttrList * pangoAttrList) {
	sqInt * attrArray;
	PangoAttribute * pangoAttr;
	sqInt b;
	sqInt g;
	sqInt end;
	sqInt start;
	sqInt alpha;
	unsigned int c;
	sqInt r;

	attrArray = interpreterProxy->firstIndexableField(attrArrayOop);
	start = ((attrArray[1]) >> 1);
	end = ((attrArray[2]) >> 1);
	c = interpreterProxy->positive32BitValueOf(attrArray[3]);
	logwith("color: %u", c);
	alpha = ((usqInt) (c && 4278190080U)) >> 24;
	r = ((usqInt) (c & 16711680)) >> 16;
	g = ((usqInt) (c & 65280)) >> 8;
	b = c & 255;
	if (!(r == 0)) {
		r = r * 257;
	}
	if (!(g == 0)) {
		g = g * 257;
	}
	if (!(b == 0)) {
		b = b * 257;
	}
	logwithwithwithwith("%d %d %d %d", alpha, r, g, b);
	pangoAttr = pango_attr_foreground_new(r, g, b);
	pangoAttr->start_index = start;
	pangoAttr->end_index = end;
	pango_attr_list_change(pangoAttrList, pangoAttr);
}

static void addColorStopTooffsetrgbalpha(cairo_pattern_t* pattern, sqInt intOffset, sqInt rgb, sqInt alpha) {
	sqInt r;
	sqInt b;
	sqInt g;

	r = (((usqInt) rgb) >> 20) & 1023;
	g = (((usqInt) rgb) >> 10) & 1023;
	b = (((usqInt) rgb) >> 0) & 1023;
	if (alpha == 255) {
		cairo_pattern_add_color_stop_rgb(pattern, intOffset / 65536.0, r / 1023.0, g / 1023.0, b / 1023.0);
	} else {
		cairo_pattern_add_color_stop_rgba(pattern, intOffset / 65536.0, r / 1023.0, g / 1023.0, b / 1023.0, alpha / 255.0);
	}
}

static sqInt addDefaultInto(PangoAttrList * pangoAttrList) {
	PangoLanguage * lang;
	PangoAttribute * pangoAttr;

	pangoAttr = pango_attr_foreground_new(0, 0, 1);
	pangoAttr->start_index = 0;
	pangoAttr->end_index = 0x7fffffff;
	pango_attr_list_insert(pangoAttrList, pangoAttr);
	pangoAttr = pango_attr_font_desc_new(defaultFontDescription);
	pangoAttr->start_index = 0;
	pangoAttr->end_index = 0x7fffffff;
	pango_attr_list_insert(pangoAttrList, pangoAttr);
	lang = pango_language_from_string("en-US");
	pangoAttr = pango_attr_language_new(lang);
	pangoAttr->start_index = 0;
	pangoAttr->end_index = 0x7fffffff;
	pango_attr_list_insert(pangoAttrList, pangoAttr);
}

static sqInt addEmphasisinto(sqInt attrArrayOop, PangoAttrList * pangoAttrList) {
	sqInt end;
	sqInt start;
	sqInt * attrArray;
	PangoAttribute * pangoAttr;
	sqInt c;

	attrArray = interpreterProxy->firstIndexableField(attrArrayOop);
	start = ((attrArray[1]) >> 1);
	end = ((attrArray[2]) >> 1);
	c = ((attrArray[3]) >> 1);
	if (c & 1) {
		pangoAttr = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
		pangoAttr->start_index = start;
		pangoAttr->end_index = end;
		pango_attr_list_change(pangoAttrList, pangoAttr);
	}
	if (c & 2) {
		pangoAttr = pango_attr_style_new(PANGO_STYLE_OBLIQUE);
		pangoAttr->start_index = start;
		pangoAttr->end_index = end;
		pango_attr_list_change(pangoAttrList, pangoAttr);
	}
	if (c & 4) {
		pangoAttr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
		pangoAttr->start_index = start;
		pangoAttr->end_index = end;
		pango_attr_list_change(pangoAttrList, pangoAttr);
	}
	if (c & 8) {
		pangoAttr = pango_attr_stretch_new(PANGO_STRETCH_CONDENSED);
		pangoAttr->start_index = start;
		pangoAttr->end_index = end;
		pango_attr_list_change(pangoAttrList, pangoAttr);
	}
	if (c & 16) {
		pangoAttr = pango_attr_strikethrough_new(1);
		pangoAttr->start_index = start;
		pangoAttr->end_index = end;
		pango_attr_list_change(pangoAttrList, pangoAttr);
	}
}

static sqInt addFontinto(sqInt attrArrayOop, PangoAttrList * pangoAttrList) {
	sqInt end;
	sqInt start;
	sqInt * attrArray;
	PangoFontDescription * desc;
	PangoAttribute * pangoAttr;
	sqInt fontDescIndex;

	attrArray = interpreterProxy->firstIndexableField(attrArrayOop);
	start = ((attrArray[1]) >> 1);
	end = ((attrArray[2]) >> 1);
	fontDescIndex = interpreterProxy->fetchIntegerofObject(5, attrArray[4]);
	if (fontDescIndex < 0) {
		return null;
	}
	if (fontDescIndex > 255) {
		return null;
	}
	desc = fontDescriptions[fontDescIndex];
	if (desc == null) {
		return null;
	}
	pangoAttr = pango_attr_font_desc_new(desc);
	pangoAttr->start_index = start;
	pangoAttr->end_index = end;
	pango_attr_list_change(pangoAttrList, pangoAttr);
}

static sqInt addLanguageinto(sqInt attrArrayOop, PangoAttrList * pangoAttrList) {
	sqInt end;
	sqInt start;
	sqInt lang;
	sqInt * attrArray;
	PangoAttribute * pangoAttr;
	PangoLanguage * pangoLang;
	char * cLang;

	attrArray = interpreterProxy->firstIndexableField(attrArrayOop);
	start = ((attrArray[1]) >> 1);
	end = ((attrArray[2]) >> 1);
	lang = ((attrArray[3]) >> 1);
	if (lang == 0) {
		cLang = "en-US";
	}
	if (lang == 5) {
		cLang = "ja-JP";
	}
	if (lang == 6) {
		cLang = "zh-CN";
	}
	if (lang == 7) {
		cLang = "ko-KR";
	}
	if (lang == 9) {
		cLang = "zh-TW";
	}
	if (lang == 13) {
		cLang = "el-EL";
	}
	pangoLang = pango_language_from_string(cLang);
	pangoAttr = pango_attr_language_new(pangoLang);
	pangoAttr->start_index = start;
	pangoAttr->end_index = end;
	pango_attr_list_change(pangoAttrList, pangoAttr);
}

static sqInt addSelectionAtpixelwith(PangoRectangle * rect, unsigned int c, cairo_t* context) {
	sqInt b;
	sqInt alpha;
	sqInt r;
	sqInt g;

	alpha = ((usqInt) (c && 4278190080U)) >> 24;
	r = ((usqInt) (c & 16711680)) >> 16;
	g = ((usqInt) (c & 65280)) >> 8;
	b = c & 255;
	if ((alpha == 0) && ((r == 0) && ((g == 0) && (b == 0)))) {
		return null;
	}
	if (!(r == 0)) {
		r = r * 257;
	}
	if (!(g == 0)) {
		g = g * 257;
	}
	if (!(b == 0)) {
		b = b * 257;
	}
	cairo_save(context);
	cairo_set_source_rgb(context, r, g, b);
	cairo_new_path(context);
	cairo_move_to(context, PANGO_PIXELS(rect->x), PANGO_PIXELS(rect->y));
	cairo_line_to(context, PANGO_PIXELS(rect->x), PANGO_PIXELS(rect->y+rect->height));
	cairo_stroke(context);
	cairo_restore(context);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
}

static sqInt addSelectionFromtopixelinto(sqInt start, sqInt end, unsigned int c, PangoAttrList * pangoAttrList) {
	sqInt b;
	PangoAttribute * pangoAttr;
	sqInt alpha;
	sqInt r;
	sqInt g;

	alpha = ((usqInt) (c && 4278190080U)) >> 24;
	r = ((usqInt) (c & 16711680)) >> 16;
	g = ((usqInt) (c & 65280)) >> 8;
	b = c & 255;
	if ((alpha == 0) && ((r == 0) && ((g == 0) && (b == 0)))) {
		return null;
	}
	if (!(r == 0)) {
		r = r * 257;
	}
	if (!(g == 0)) {
		g = g * 257;
	}
	if (!(b == 0)) {
		b = b * 257;
	}
	pangoAttr = pango_attr_background_new(r, g, b);
	pangoAttr->start_index = start;
	pangoAttr->end_index = end;
	pango_attr_list_change(pangoAttrList, pangoAttr);
}


/*	Get contexts[canvasOop's handle] */

static cairo_t* contextFrom(sqInt canvasOop) {
	sqInt contextIndex;
	cairo_t* context;
	sqInt targetOop;

	if ((interpreterProxy->slotSizeOf(canvasOop)) < CanvasInstSize) {
		fail("canvas oop invalid");
		return null;
	}
	contextIndex = interpreterProxy->fetchIntegerofObject(CanvasHandleIndex, canvasOop);
	if (interpreterProxy->failed()) {
		contextIndex = interpreterProxy->fetchPointerofObject(CanvasHandleIndex, canvasOop);
		if (!(contextIndex == (interpreterProxy->nilObject()))) {
			fail("canvas handle not an integer");
		}
		return null;
	}
	if ((contextIndex < 0) || (contextIndex > (lastIndex(contexts)))) {
		failwith("canvas handle %i out of bounds", contextIndex);
		return null;
	}
	context = contexts[contextIndex];
	if (context == null) {
		failwith("canvas handle %i invalid", contextIndex);
		return null;
	}
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	targetOop = interpreterProxy->fetchPointerofObject(CanvasTargetIndex, canvasOop);
	if (!((surfaceFrom(targetOop)) == (cairo_get_target(context)))) {
		failwith("canvas handle %i does not match target", contextIndex);
		return null;
	}
	return context;
}

static sqInt createContextFor(sqInt canvasOop) {
	cairo_surface_t* targetSurface;
	sqInt contextIndex;
	sqInt targetOop;
	cairo_t* context;
	sqInt i;
	sqInt targetID;

	if ((interpreterProxy->slotSizeOf(canvasOop)) < CanvasInstSize) {
		fail("canvas oop invalid");
		return null;
	}
	targetOop = interpreterProxy->fetchPointerofObject(CanvasTargetIndex, canvasOop);
	if ((interpreterProxy->slotSizeOf(targetOop)) <= FormBitsIndex) {
		fail("target oop invalid");
		return null;
	}
	targetID = interpreterProxy->fetchIntegerofObject(FormBitsIndex, targetOop);
	if (interpreterProxy->failed()) {
		fail("target handle not an integer");
		return null;
	}
	targetSurface = findSurface(targetID);
	if (!((targetSurface != null) && ((cairo_surface_status(targetSurface)) == 0))) {
		fail("target surface invalid");
		return null;
	}
	contextIndex = -1;
	i = 0;
	while (i <= (lastIndex(contexts))) {
		if ((contexts[i]) == null) {
			contextIndex = i;
			i = lastIndex(contexts);
		}
		i += 1;
	}
	if (contextIndex < 0) {
		fail("too many canvases");
		return null;
	}
	context = cairo_create(targetSurface);
	contexts[contextIndex] = context;
	/* missing DebugCode */;
	return contextIndex;
}


/*	create a surface, register it in SurfacePlugin and answer its surface plugin ID */

static sqInt createSurfaceFor(sqInt formOop) {
	sqInt width;
	sqInt height;
	sqInt depth;
	sqInt bits;
	sqInt status;
	cairo_format_t format;
	cairo_surface_t* surface;

	if ((interpreterProxy->slotSizeOf(formOop)) < FormInstSize) {
		fail("form oop invalid");
		return -1;
	}
	width = interpreterProxy->fetchIntegerofObject(FormWidthIndex, formOop);
	height = interpreterProxy->fetchIntegerofObject(FormHeightIndex, formOop);
	depth = interpreterProxy->fetchIntegerofObject(FormDepthIndex, formOop);
	if (interpreterProxy->failed()) {
		fail("form fields are not integers");
		return -1;
	}
	switch(depth) {
		case 32: format = CAIRO_FORMAT_ARGB32; break;
		case 24: format = CAIRO_FORMAT_RGB24; break;
		case 16: format = CAIRO_FORMAT_RGB16_565; break;
		case  8: format = CAIRO_FORMAT_A8; break;
		case  1: format = CAIRO_FORMAT_A1; break;
		default: format = -1;
	}
	if ((width <= 0) || ((height <= 0) || (format < 0))) {
		fail("form fields out of range");
		return -1;
	}
	bits = interpreterProxy->fetchPointerofObject(FormBitsIndex, formOop);
	if (!(bits == (interpreterProxy->nilObject()))) {
		fail("form handle not nil");
		return -1;
	}
	surface = cairo_image_surface_create(format, width, height);
	status = cairo_surface_status(surface);
	if (!(status == 0)) {
		failwith("failed to create surface - %s", cairo_status_to_string(status));
		cairo_surface_destroy(surface);
		return -1;
	}
	return registerSurface(surface);
}

static sqInt destroyContextFor(sqInt canvasOop) {
	sqInt contextIndex;
	cairo_t* context;

	if ((interpreterProxy->slotSizeOf(canvasOop)) < CanvasInstSize) {
		fail("canvas oop invalid");
		return null;
	}
	contextIndex = interpreterProxy->fetchIntegerofObject(CanvasHandleIndex, canvasOop);
	if (interpreterProxy->failed()) {
		fail("canvas handle not an integer");
		return null;
	}
	if ((contextIndex < 0) || (contextIndex > (lastIndex(contexts)))) {
		failwith("canvas handle %i out of bounds", contextIndex);
		return null;
	}
	context = contexts[contextIndex];
	if (context == null) {
		failwith("canvas handle %i invalid", contextIndex);
		return null;
	}
	/* missing DebugCode */;
	cairo_destroy(context);
	contexts[contextIndex] = null;
	return null;
}


/*	fetch surface from surfaceID, destroy it and unregister from SurfacePlugin */

static sqInt destroySurface(sqInt surfaceID) {
	cairo_surface_t* surface;

	surface = findSurface(surfaceID);
	if (surface == null) {
		failwith("could not find surface %i", surfaceID);
		return null;
	}
	cairo_surface_destroy(surface);
	unregisterSurface(surfaceID);
	return null;
}


/*	fill or stroke depending on canvasOop's flags */

static void fillOrStrokefrom(cairo_t* context, sqInt canvasOop) {
	sqInt fill;
	sqInt canvasFlags;
	sqInt rgb;
	sqInt stroke;

	canvasFlags = interpreterProxy->fetchIntegerofObject(CanvasFlagsIndex, canvasOop);
	if (interpreterProxy->failed()) {
		fail("canvas flags not an integer");
	} else {
		fill = canvasFlags & CanvasFlagFill;
		stroke = canvasFlags & CanvasFlagStroke;
		if (fill != 0) {
			if (stroke != 0) {
				cairo_fill_preserve(context);
			} else {
				cairo_fill(context);
			}
		}
		if (stroke != 0) {
			rgb = interpreterProxy->fetchIntegerofObject(CanvasStrokeColorIndex, canvasOop);
			cairo_save(context);
			setSourcergbalpha(context, rgb, stroke);
			cairo_stroke(context);
			cairo_restore(context);
		}
	}
}


/*	Answer surface handle for surfaceID */

static cairo_surface_t* findSurface(sqInt surfaceID) {
	sqInt surfaceHandle;

	if (findSurfaceFn == null) {
		if (!(loadSurfacePlugin())) {
			return null;
		}
	}
	if (!((*findSurfaceFn)(surfaceID, &surfaceDispatch, &surfaceHandle))) {
		return null;
	}
	return ((cairo_surface_t*) surfaceHandle);
}


/*	Note: This is coded so that plugins can be run from Squeak. */

static VirtualMachine * getInterpreter(void) {
	return interpreterProxy;
}


/*	Note: This is hardcoded so it can be run from Squeak.
	The module name is used for validating a module *after*
	it is loaded to check if it does really contain the module
	we're thinking it contains. This is important! */

EXPORT(const char*) getModuleName(void) {
	return moduleName;
}

static sqInt getSurfaceFormatgetWgetHgetDgetMsb(cairo_surface_t * surfaceHandle, int* wReturn, int* hReturn, int* dReturn, int* mReturn) {
	sqInt width;
	sqInt height;
	sqInt depth;
	sqInt msb;

	/* missing DebugCode */;
	width = cairo_image_surface_get_width(surfaceHandle);
	height = cairo_image_surface_get_height(surfaceHandle);
	depth = formatToDepth[cairo_image_surface_get_format(surfaceHandle)];
	msb = 1;
	*wReturn = width;
	*hReturn = height;
	*dReturn = depth;
	*mReturn = msb;
	return 1;
}

static sqInt halt(void) {
	;
}

EXPORT(sqInt) initialiseModule(void) {
	sqInt i;

	for (i = 0; i <= (lastIndex(contexts)); i += 1) {
		contexts[i] = null;
	}
	for (i = 0; i <= (lastIndex(fontDescriptions)); i += 1) {
		fontDescriptions[i] = null;
	}
	defaultFontDescription = pango_font_description_from_string("Times New Roman 10");
	registerSurfaceFn = null;
	unregisterSurfaceFn = null;
	findSurfaceFn = null;
	return 1;
}


/*	Load the surface support plugin */

static sqInt loadSurfacePlugin(void) {
	sqInt found;

	registerSurfaceFn = ((fn_ioRegisterSurface) (interpreterProxy->ioLoadFunctionFrom("ioRegisterSurface", "SurfacePlugin")));
	unregisterSurfaceFn = ((fn_ioUnregisterSurface) (interpreterProxy->ioLoadFunctionFrom("ioUnregisterSurface", "SurfacePlugin")));
	findSurfaceFn = ((fn_ioFindSurface) (interpreterProxy->ioLoadFunctionFrom("ioFindSurface", "SurfacePlugin")));
	found = (registerSurfaceFn != null) && ((unregisterSurfaceFn != null) && (findSurfaceFn != null));
	if (!(found)) {
		fail("could not load SurfacePlugin");
	}
	maxSurfaceID = -1;
	return found;
}

static unsigned char* lockSurfacegetPitchxywh(cairo_surface_t* surfaceHandle, int* pitchReturn, sqInt x, sqInt y, sqInt w, sqInt h) {
	sqInt pitch;
	unsigned char* data;

	/* missing DebugCode */;
	cairo_surface_flush(surfaceHandle);
	data = cairo_image_surface_get_data(surfaceHandle);
	pitch = cairo_image_surface_get_stride(surfaceHandle);
	*pitchReturn = pitch;
	return data;
}


/*	The module with the given name was just unloaded.
	Make sure we have no dangling references. */

EXPORT(sqInt) moduleUnloaded(char * aModuleName) {
	if ((strcmp(aModuleName, "SurfacePlugin")) == 0) {
		registerSurfaceFn = null;
		unregisterSurfaceFn = null;
		findSurfaceFn = null;
	}
	return 1;
}

static sqInt msg(char * s) {
	fprintf(stderr, "\n%s: %s", moduleName, s);
}

static void polyPathfrom(cairo_t* context, sqInt pointsOop) {
	sqInt i;
	sqInt pointsCount;
	float* points;

	points = interpreterProxy->arrayValueOf(pointsOop);
	pointsCount = interpreterProxy->slotSizeOf(pointsOop);
	if (!(interpreterProxy->failed())) {
		if (pointsCount >= 2) {
			cairo_move_to(context, points[0], points[1]);
			for (i = 2; i <= (pointsCount - 1); i += 2) {
				cairo_line_to(context, points[i], points[i + 1]);
			}
		}
	}
}

EXPORT(sqInt) primitiveClear(void) {
	sqInt canvasOop;
	cairo_t* context;
	sqInt fill;
	sqInt canvasFlags;
	sqInt op;

	canvasOop = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	canvasFlags = interpreterProxy->fetchIntegerofObject(CanvasFlagsIndex, canvasOop);
	if (interpreterProxy->failed()) {
		fail("canvas flags not an integer");
		return null;
	}
	fill = canvasFlags & CanvasFlagFill;
	if (!(fill)) {
		cairo_set_source_rgba(context, 0.0, 0.0, 0.0, 0.0);
	}
	op = cairo_get_operator(context);
	cairo_set_operator(context, CairoOperatorSource);
	cairo_paint(context);
	cairo_set_operator(context, op);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	return null;
}

EXPORT(sqInt) primitiveClipRectangleLeftRightTopBottom(void) {
	sqInt canvasOop;
	cairo_t* context;
	double left;
	double right;
	double top;
	double bottom;

	left = interpreterProxy->stackFloatValue(3);
	right = interpreterProxy->stackFloatValue(2);
	top = interpreterProxy->stackFloatValue(1);
	bottom = interpreterProxy->stackFloatValue(0);
	canvasOop = interpreterProxy->stackValue(4);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_new_path(context);
	cairo_rectangle(context, left, top, right - left, bottom - top);
	cairo_clip(context);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(4);
	return null;
}

EXPORT(sqInt) primitiveClose(void) {
	sqInt canvasOop;

	canvasOop = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	destroyContextFor(canvasOop);
	if (!(interpreterProxy->failed())) {
		interpreterProxy->storePointerofObjectwithValue(CanvasHandleIndex, canvasOop, interpreterProxy->nilObject());
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	return null;
}

EXPORT(sqInt) primitiveCreateFormHandle(void) {
	sqInt formOop;
	sqInt surfaceID;
	sqInt _return_value;

	formOop = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	surfaceID = createSurfaceFor(formOop);
	if (surfaceID < 0) {
		interpreterProxy->primitiveFail();
	}
	if (!(interpreterProxy->failed())) {
		_return_value = interpreterProxy->integerObjectOf(surfaceID);
		if (interpreterProxy->failed()) {
			return null;
		}
		interpreterProxy->popthenPush(1, _return_value);
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	return null;
}

EXPORT(sqInt) primitiveDestroyFormHandle(void) {
	sqInt surfaceID;

	surfaceID = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	if (!(interpreterProxy->failed())) {
		destroySurface(surfaceID);
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}

EXPORT(sqInt) primitiveDrawArcRadiusXYFromTo(void) {
	sqInt canvasOop;
	cairo_t* context;
	double radius;
	double x;
	double y;
	double angle1;
	double angle2;

	radius = interpreterProxy->stackFloatValue(4);
	x = interpreterProxy->stackFloatValue(3);
	y = interpreterProxy->stackFloatValue(2);
	angle1 = interpreterProxy->stackFloatValue(1);
	angle2 = interpreterProxy->stackFloatValue(0);
	canvasOop = interpreterProxy->stackValue(5);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_new_path(context);
	if (radius > 0.0) {
		cairo_arc(context, x, y, radius, angle1, angle2);
	} else {
		cairo_arc_negative(context, x, y, -1.0 * radius, angle1, angle2);
	}
	fillOrStrokefrom(context, canvasOop);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(5);
	return null;
}

EXPORT(sqInt) primitiveDrawCurveFromXYviaXYandXYtoXY(void) {
	sqInt canvasOop;
	cairo_t* context;
	double x0;
	double y0;
	double x1;
	double y1;
	double x2;
	double y2;
	double x3;
	double y3;

	x0 = interpreterProxy->stackFloatValue(7);
	y0 = interpreterProxy->stackFloatValue(6);
	x1 = interpreterProxy->stackFloatValue(5);
	y1 = interpreterProxy->stackFloatValue(4);
	x2 = interpreterProxy->stackFloatValue(3);
	y2 = interpreterProxy->stackFloatValue(2);
	x3 = interpreterProxy->stackFloatValue(1);
	y3 = interpreterProxy->stackFloatValue(0);
	canvasOop = interpreterProxy->stackValue(8);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_new_path(context);
	cairo_move_to(context, x0, y0);
	cairo_curve_to(context, x1, y1, x2, y2, x3, y3);
	fillOrStrokefrom(context, canvasOop);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(8);
	return null;
}

EXPORT(sqInt) primitiveDrawCurveFromXYviaXYtoXY(void) {
	sqInt canvasOop;
	cairo_t* context;
	double x0;
	double y0;
	double x1;
	double y1;
	double x2;
	double y2;

	x0 = interpreterProxy->stackFloatValue(5);
	y0 = interpreterProxy->stackFloatValue(4);
	x1 = interpreterProxy->stackFloatValue(3);
	y1 = interpreterProxy->stackFloatValue(2);
	x2 = interpreterProxy->stackFloatValue(1);
	y2 = interpreterProxy->stackFloatValue(0);
	canvasOop = interpreterProxy->stackValue(6);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_new_path(context);
	cairo_move_to(context, x0, y0);
	cairo_curve_to(context, ((2.0 * x1) + x0) / 3.0, ((2.0 * y1) + y0) / 3.0, ((2.0 * x1) + x2) / 3.0, ((2.0 * y1) + y2) / 3.0, x2, y2);
	fillOrStrokefrom(context, canvasOop);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(6);
	return null;
}

EXPORT(sqInt) primitiveDrawGeneralBezierShape(void) {
	sqInt yFrom;
	short* seg;
	sqInt i;
	sqInt shapeCount;
	sqInt contourOop;
	sqInt segmentCount;
	sqInt j;
	cairo_t* context;
	sqInt canvasOop;
	sqInt xFrom;
	sqInt xVia;
	sqInt yVia;
	sqInt yTo;
	sqInt xTo;
	sqInt shapeOop;

	shapeOop = interpreterProxy->stackValue(0);
	canvasOop = interpreterProxy->stackValue(1);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	shapeCount = interpreterProxy->slotSizeOf(shapeOop);
	cairo_new_path(context);
	for (i = 0; i <= (shapeCount - 1); i += 1) {
		contourOop = interpreterProxy->fetchPointerofObject(i, shapeOop);
		if (!(interpreterProxy->isMemberOf(contourOop, "ShortPointArray"))) {
			failwith("bezier contour %i is no ShortPointArray", i + 1);
			return null;
		}
		segmentCount = (interpreterProxy->slotSizeOf(contourOop)) / 3;
		seg = interpreterProxy->arrayValueOf(contourOop);
		for (j = 0; j <= (segmentCount - 1); j += 1) {
			xFrom = seg[0];
			yFrom = seg[1];
			xVia = seg[2];
			yVia = seg[3];
			xTo = seg[4];
			yTo = seg[5];
			if (j == 0) {
				cairo_move_to(context, xFrom, yFrom);
			}
			if ((xFrom == xVia) && (yFrom == yVia)) {
				cairo_line_to(context, xTo, yTo);
			} else {
				cairo_curve_to(context, (xFrom + (2.0 * xVia)) / 3.0, (yFrom + (2.0 * yVia)) / 3.0, ((2.0 * xVia) + xTo) / 3.0, ((2.0 * yVia) + yTo) / 3.0, xTo, yTo);
			}
			seg += 6;
		}
		cairo_close_path(context);
	}
	fillOrStrokefrom(context, canvasOop);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}

EXPORT(sqInt) primitiveDrawImageSrcLRTBDestLRTB(void) {
	cairo_t* context;
	sqInt canvasOop;
	cairo_surface_t* srcSurface;
	sqInt formOop;
	double dstL;
	double dstR;
	double dstT;
	double dstB;
	double srcL;
	double srcR;
	double srcT;
	double srcB;

	formOop = interpreterProxy->stackValue(8);
	dstL = interpreterProxy->stackFloatValue(7);
	dstR = interpreterProxy->stackFloatValue(6);
	dstT = interpreterProxy->stackFloatValue(5);
	dstB = interpreterProxy->stackFloatValue(4);
	srcL = interpreterProxy->stackFloatValue(3);
	srcR = interpreterProxy->stackFloatValue(2);
	srcT = interpreterProxy->stackFloatValue(1);
	srcB = interpreterProxy->stackFloatValue(0);
	canvasOop = interpreterProxy->stackValue(9);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	srcSurface = surfaceFrom(formOop);
	if (!((srcSurface != null) && ((cairo_surface_status(srcSurface)) == 0))) {
		fail("source surface invalid");
		return null;
	}
	if ((srcR != srcL) && (srcT != srcB)) {
		cairo_save(context);
		cairo_translate(context, dstL, dstT);
		cairo_scale(context, (dstR - dstL) / (srcR - srcL), (dstB - dstT) / (srcB - srcT));
		cairo_new_path(context);
		cairo_rectangle(context, 0.0, 0.0, srcR - srcL, srcB - srcT);
		cairo_set_source_surface(context, srcSurface, 0.0 - srcL, 0.0 - srcT);
		cairo_fill(context);
		cairo_restore(context);
	}
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(9);
	return null;
}

EXPORT(sqInt) primitiveDrawLineFromXYtoXY(void) {
	sqInt canvasOop;
	cairo_t* context;
	double fromX;
	double fromY;
	double toX;
	double toY;

	fromX = interpreterProxy->stackFloatValue(3);
	fromY = interpreterProxy->stackFloatValue(2);
	toX = interpreterProxy->stackFloatValue(1);
	toY = interpreterProxy->stackFloatValue(0);
	canvasOop = interpreterProxy->stackValue(4);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_new_path(context);
	cairo_move_to(context, fromX, fromY);
	cairo_line_to(context, toX, toY);
	strokefrom(context, canvasOop);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(4);
	return null;
}

EXPORT(sqInt) primitiveDrawOvalLeftRightTopBottom(void) {
	sqInt canvasOop;
	cairo_t* context;
	double left;
	double right;
	double top;
	double bottom;

	left = interpreterProxy->stackFloatValue(3);
	right = interpreterProxy->stackFloatValue(2);
	top = interpreterProxy->stackFloatValue(1);
	bottom = interpreterProxy->stackFloatValue(0);
	canvasOop = interpreterProxy->stackValue(4);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	if ((right != left) && (top != bottom)) {
		cairo_save(context);
		cairo_new_path(context);
		cairo_translate(context, (left + right) / 2.0, (top + bottom) / 2.0);
		cairo_scale(context, (right - left) / 2.0, (bottom - top) / 2.0);
		cairo_arc(context, 0.0, 0.0, 1.0, 0.0, degrees(360.0));
		cairo_restore(context);
		fillOrStrokefrom(context, canvasOop);
	}
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(4);
	return null;
}

EXPORT(sqInt) primitiveDrawPolygon(void) {
	sqInt canvasOop;
	cairo_t* context;
	sqInt pointsOop;

	pointsOop = interpreterProxy->stackValue(0);
	canvasOop = interpreterProxy->stackValue(1);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_new_path(context);
	polyPathfrom(context, pointsOop);
	cairo_close_path(context);
	fillOrStrokefrom(context, canvasOop);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}

EXPORT(sqInt) primitiveDrawPolyline(void) {
	sqInt canvasOop;
	cairo_t* context;
	sqInt pointsOop;

	pointsOop = interpreterProxy->stackValue(0);
	canvasOop = interpreterProxy->stackValue(1);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_new_path(context);
	polyPathfrom(context, pointsOop);
	fillOrStrokefrom(context, canvasOop);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}

EXPORT(sqInt) primitiveDrawRectangleLeftRightTopBottom(void) {
	sqInt canvasOop;
	cairo_t* context;
	double left;
	double right;
	double top;
	double bottom;

	left = interpreterProxy->stackFloatValue(3);
	right = interpreterProxy->stackFloatValue(2);
	top = interpreterProxy->stackFloatValue(1);
	bottom = interpreterProxy->stackFloatValue(0);
	canvasOop = interpreterProxy->stackValue(4);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_new_path(context);
	cairo_rectangle(context, left, top, right - left, bottom - top);
	fillOrStrokefrom(context, canvasOop);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(4);
	return null;
}


/*		x1	x2		x3	x4
	y1	+	/	-	\	+
	y2	/	.		.	\
		|				|
	y3	\	.		.	/
	y4	+	\	-	/	+ */

EXPORT(sqInt) primitiveDrawRoundRectLeftRightTopBottomRadiusCorner(void) {
	double x3;
	double ry;
	double y3;
	double x2;
	cairo_t* context;
	sqInt canvasOop;
	double rx;
	double y2;
	double r;
	double x1;
	double x4;
	double y1;
	double y4;
	double radius;
	sqInt cornerFlags;

	x1 = interpreterProxy->stackFloatValue(5);
	x4 = interpreterProxy->stackFloatValue(4);
	y1 = interpreterProxy->stackFloatValue(3);
	y4 = interpreterProxy->stackFloatValue(2);
	radius = interpreterProxy->stackFloatValue(1);
	cornerFlags = interpreterProxy->stackIntegerValue(0);
	canvasOop = interpreterProxy->stackValue(6);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	rx = (x4 - x1) / 2.0;
	ry = (y4 - y1) / 2.0;
	r = (((((radius < rx) ? radius : rx)) < ry) ? (((radius < rx) ? radius : rx)) : ry);
	x2 = x1 + r;
	x3 = x4 - r;
	y2 = y1 + r;
	y3 = y4 - r;
	cairo_new_path(context);
	if (cornerFlags & 1) {
		cairo_arc(context, x2, y2, r, degrees(180), degrees(270));
	} else {
		cairo_move_to(context, x1, y1);
	}
	if (cornerFlags & 8) {
		cairo_arc(context, x3, y2, r, degrees(270), degrees(360));
	} else {
		cairo_line_to(context, x4, y1);
	}
	if (cornerFlags & 4) {
		cairo_arc(context, x3, y3, r, degrees(0), degrees(90));
	} else {
		cairo_line_to(context, x4, y4);
	}
	if (cornerFlags & 2) {
		cairo_arc(context, x2, y3, r, degrees(90), degrees(180));
	} else {
		cairo_line_to(context, x1, y4);
	}
	cairo_close_path(context);
	fillOrStrokefrom(context, canvasOop);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(6);
	return null;
}


/*	draw a string including its outline if selected */

EXPORT(sqInt) primitiveDrawZeroTerminatedUtf8StringXY(void) {
	sqInt canvasOop;
	cairo_t* context;
	char *aString;
	double x;
	double y;

	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(2)));
	aString = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	x = interpreterProxy->stackFloatValue(1);
	y = interpreterProxy->stackFloatValue(0);
	canvasOop = interpreterProxy->stackValue(3);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_move_to(context, x, y);
	cairo_text_path(context, aString);
	fillOrStrokefrom(context, canvasOop);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(3);
	return null;
}

EXPORT(sqInt) primitiveFillBitmapOriginXYdirectionXYnormalXYRepeatImage(void) {
	cairo_pattern_t* pattern;
	cairo_matrix_t mdata;
	sqInt canvasOop;
	cairo_t* context;
	cairo_matrix_t* m;
	cairo_surface_t* surface;
	double ox;
	double oy;
	double dx;
	double dy;
	double nx;
	double ny;
	sqInt aBoolean;
	sqInt formOop;

	ox = interpreterProxy->stackFloatValue(7);
	oy = interpreterProxy->stackFloatValue(6);
	dx = interpreterProxy->stackFloatValue(5);
	dy = interpreterProxy->stackFloatValue(4);
	nx = interpreterProxy->stackFloatValue(3);
	ny = interpreterProxy->stackFloatValue(2);
	aBoolean = interpreterProxy->booleanValueOf(interpreterProxy->stackValue(1));
	formOop = interpreterProxy->stackValue(0);
	m = &mdata;
	canvasOop = interpreterProxy->stackValue(8);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	surface = surfaceFrom(formOop);
	if (!((surface != null) && ((cairo_surface_status(surface)) == 0))) {
		fail("surface invalid");
		return null;
	}
	pattern = cairo_pattern_create_for_surface(surface);
	cairo_matrix_init(m, dx, dy, nx, ny, ox, oy);
	cairo_matrix_invert(m);
	cairo_pattern_set_matrix(pattern, m);
	if (aBoolean) {
		cairo_pattern_set_extend(pattern, CairoExtendRepeat);
	}
	if (cairo_pattern_status(pattern)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_pattern_status(pattern)));
		return null;
	}
	cairo_set_source(context, pattern);
	cairo_pattern_destroy(pattern);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(8);
	return null;
}

EXPORT(sqInt) primitiveFillColorAlpha(void) {
	sqInt canvasOop;
	cairo_t* context;
	sqInt rgb;
	sqInt alpha;

	rgb = interpreterProxy->stackIntegerValue(1);
	alpha = interpreterProxy->stackIntegerValue(0);
	canvasOop = interpreterProxy->stackValue(2);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	setSourcergbalpha(context, rgb, alpha);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(2);
	return null;
}

EXPORT(sqInt) primitiveFillLinearOriginXYdirectionXYcolorStops(void) {
	int* colorStops;
	cairo_pattern_t* pattern;
	sqInt i;
	sqInt canvasOop;
	cairo_t* context;
	sqInt colorStopsCount;
	double ox;
	double oy;
	double dx;
	double dy;
	sqInt colorStopsOop;

	ox = interpreterProxy->stackFloatValue(4);
	oy = interpreterProxy->stackFloatValue(3);
	dx = interpreterProxy->stackFloatValue(2);
	dy = interpreterProxy->stackFloatValue(1);
	colorStopsOop = interpreterProxy->stackValue(0);
	canvasOop = interpreterProxy->stackValue(5);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	colorStops = interpreterProxy->arrayValueOf(colorStopsOop);
	colorStopsCount = interpreterProxy->slotSizeOf(colorStopsOop);
	if (interpreterProxy->failed()) {
		fail("bad colorStops array");
		return null;
	}
	pattern = cairo_pattern_create_linear(ox, oy, ox + dx, oy + dy);
	if (cairo_pattern_status(pattern)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_pattern_status(pattern)));
		return null;
	}
	for (i = 0; i <= (colorStopsCount - 1); i += 3) {
		addColorStopTooffsetrgbalpha(pattern, colorStops[i], colorStops[i + 1], colorStops[i + 2]);
	}
	cairo_set_source(context, pattern);
	cairo_pattern_destroy(pattern);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(5);
	return null;
}

EXPORT(sqInt) primitiveFillRadialOriginXYdirectionXYnormalXYcolorStops(void) {
	int* colorStops;
	cairo_pattern_t* pattern;
	sqInt i;
	cairo_matrix_t mdata;
	sqInt canvasOop;
	cairo_t* context;
	sqInt colorStopsCount;
	cairo_matrix_t* m;
	double ox;
	double oy;
	double dx;
	double dy;
	double nx;
	double ny;
	sqInt colorStopsOop;

	ox = interpreterProxy->stackFloatValue(6);
	oy = interpreterProxy->stackFloatValue(5);
	dx = interpreterProxy->stackFloatValue(4);
	dy = interpreterProxy->stackFloatValue(3);
	nx = interpreterProxy->stackFloatValue(2);
	ny = interpreterProxy->stackFloatValue(1);
	colorStopsOop = interpreterProxy->stackValue(0);
	m = &mdata;
	canvasOop = interpreterProxy->stackValue(7);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	colorStops = interpreterProxy->arrayValueOf(colorStopsOop);
	colorStopsCount = interpreterProxy->slotSizeOf(colorStopsOop);
	if (interpreterProxy->failed()) {
		fail("bad colorStops array");
		return null;
	}
	pattern = cairo_pattern_create_radial(0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
	cairo_matrix_init(m, dx, dy, nx, ny, ox, oy);
	cairo_matrix_invert(m);
	cairo_pattern_set_matrix(pattern, m);
	if (cairo_pattern_status(pattern)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_pattern_status(pattern)));
		return null;
	}
	for (i = 0; i <= (colorStopsCount - 1); i += 3) {
		addColorStopTooffsetrgbalpha(pattern, colorStops[i], colorStops[i + 1], colorStops[i + 2]);
	}
	cairo_set_source(context, pattern);
	cairo_pattern_destroy(pattern);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(7);
	return null;
}

EXPORT(sqInt) primitiveFontFace(void) {
	cairo_font_face_t* crFace;
	sqInt canvasOop;
	cairo_t* context;
	FT_Face ftFace;
	char *faceHandle;

	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(0)));
	faceHandle = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(0))));
	canvasOop = interpreterProxy->stackValue(1);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	ftFace = *(void**)faceHandle;
	crFace = cairo_ft_font_face_create_for_ft_face(ftFace, FT_LOAD_NO_HINTING);
	cairo_set_font_face(context, crFace);
	cairo_font_face_destroy(crFace);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}

EXPORT(sqInt) primitiveFontSize(void) {
	sqInt canvasOop;
	cairo_t* context;
	double size;

	size = interpreterProxy->stackFloatValue(0);
	canvasOop = interpreterProxy->stackValue(1);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_set_font_size(context, size);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}

EXPORT(sqInt) primitiveGetLineWidth(void) {
	sqInt canvasOop;
	cairo_t* context;
	double width;
	sqInt _return_value;

	canvasOop = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	width = cairo_get_line_width(context);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	_return_value = interpreterProxy->floatObjectOf(width);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(1, _return_value);
	return null;
}

EXPORT(sqInt) primitiveGetTransform(void) {
	sqInt canvasOop;
	cairo_t* context;
	cairo_matrix_t m;
	float *aTransform;

	aTransform = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(0))));
	canvasOop = interpreterProxy->stackValue(1);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_get_matrix(context, &m);
	aTransform[0] = (m.xx);
	aTransform[1] = (m.xy);
	aTransform[2] = (m.x0);
	aTransform[3] = (m.yx);
	aTransform[4] = (m.yy);
	aTransform[5] = (m.y0);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}

EXPORT(sqInt) primitiveOpen(void) {
	sqInt handleOop;
	sqInt contextIndex;
	sqInt canvasOop;

	canvasOop = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	contextIndex = createContextFor(canvasOop);
	if (!(interpreterProxy->failed())) {
		handleOop = interpreterProxy->integerObjectOf(contextIndex);
		interpreterProxy->storePointerofObjectwithValue(CanvasHandleIndex, canvasOop, handleOop);
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	return null;
}

EXPORT(sqInt) primitivePangoBlockAtIndex(void) {
	sqInt atEnd;
	sqInt index;
	PangoRectangle pos;
	sqInt trailing;
	sqInt origin;
	sqInt corner;
	sqInt canvasOop;
	cairo_t* context;
	PangoAttrList* attrList;
	PangoLayout* layout;
	char *aString;
	sqInt utf8Index;
	sqInt x;
	sqInt y;
	sqInt sqAttrArray;
	sqInt w;
	sqInt h;
	sqInt withWrap;
	sqInt charData;
	sqInt _return_value;

	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(8)));
	aString = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(8))));
	utf8Index = interpreterProxy->stackIntegerValue(7);
	x = interpreterProxy->stackIntegerValue(6);
	y = interpreterProxy->stackIntegerValue(5);
	interpreterProxy->success(interpreterProxy->isKindOf(interpreterProxy->stackValue(4), "Object"));
	sqAttrArray = interpreterProxy->stackValue(4);
	w = interpreterProxy->stackIntegerValue(3);
	h = interpreterProxy->stackIntegerValue(2);
	withWrap = interpreterProxy->booleanValueOf(interpreterProxy->stackValue(1));
	interpreterProxy->success(interpreterProxy->isKindOf(interpreterProxy->stackValue(0), "Object"));
	charData = interpreterProxy->stackValue(0);
	;
	canvasOop = interpreterProxy->stackValue(9);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	layout = pango_cairo_create_layout(context);
	attrList = pango_attr_list_new();
	translateSqAttrsToPangoAttrsinto(sqAttrArray, attrList);
	pango_layout_set_text(layout, aString, strlen(aString));
	pango_layout_set_attributes(layout, attrList);
	pango_layout_set_width(layout, w * (PANGO_SCALE));
	if (withWrap) {
		pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
	}
	cairo_translate(context, x, y);
	pango_cairo_update_layout(context, layout);
	if (utf8Index == ((strlen(aString)) + 1)) {
		atEnd = 1;
		pango_layout_index_to_pos(layout, utf8Index - 1, &pos);
		pos.x = pos.x + pos.width;
	} else {
		atEnd = 0;
		pango_layout_index_to_pos(layout, utf8Index, &pos);
	}
	pango_attr_list_unref(attrList);
	g_object_unref(layout);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	origin = interpreterProxy->makePointwithxValueyValue((PANGO_PIXELS(pos.x)) + x, (PANGO_PIXELS(pos.y)) + y);
	corner = interpreterProxy->makePointwithxValueyValue((PANGO_PIXELS(pos.x+pos.width)) + x, (PANGO_PIXELS(pos.y+pos.height)) + y);
	interpreterProxy->storePointerofObjectwithValue(0, charData, origin);
	interpreterProxy->storePointerofObjectwithValue(1, charData, corner);
	index = sqCharCountInfromto(aString, 0, utf8Index);
	if (!(atEnd)) {
		index += 1;
	}
	interpreterProxy->storePointerofObjectwithValue(2, charData, ((index << 1) | 1));
	_return_value = interpreterProxy->integerObjectOf(index);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(10, _return_value);
	return null;
}

EXPORT(sqInt) primitivePangoComposeString(void) {
	sqInt linesSize;
	sqInt lineIndex;
	sqInt baseline;
	sqInt next;
	PangoRectangle ink;
	PangoRectangle logical;
	sqInt lastLine;
	sqInt lineCount;
	sqInt sqStart;
	sqInt prevBaseline;
	PangoLayoutLine* line;
	sqInt newW;
	sqInt sqEnd;
	sqInt start;
	sqInt canvasOop;
	cairo_t* context;
	PangoLayoutIter* lineIter;
	sqInt totalY;
	PangoAttrList* attrList;
	sqInt addition;
	PangoLayout* layout;
	char *aString;
	sqInt x;
	sqInt y;
	sqInt sqAttrArray;
	sqInt w;
	sqInt h;
	sqInt withWrap;
	sqInt lines;
	sqInt _return_value;

	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(7)));
	aString = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(7))));
	x = interpreterProxy->stackIntegerValue(6);
	y = interpreterProxy->stackIntegerValue(5);
	interpreterProxy->success(interpreterProxy->isKindOf(interpreterProxy->stackValue(4), "Object"));
	sqAttrArray = interpreterProxy->stackValue(4);
	w = interpreterProxy->stackIntegerValue(3);
	h = interpreterProxy->stackIntegerValue(2);
	withWrap = interpreterProxy->booleanValueOf(interpreterProxy->stackValue(1));
	interpreterProxy->success(interpreterProxy->isKindOf(interpreterProxy->stackValue(0), "Object"));
	lines = interpreterProxy->stackValue(0);
	;
	canvasOop = interpreterProxy->stackValue(8);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	layout = pango_cairo_create_layout(context);
	attrList = pango_attr_list_new();
	translateSqAttrsToPangoAttrsinto(sqAttrArray, attrList);
	pango_layout_set_text(layout, aString, strlen(aString));
	pango_layout_set_attributes(layout, attrList);
	pango_layout_set_width(layout, w * (PANGO_SCALE));
	if (withWrap) {
		pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
	}
	cairo_translate(context, x, y);
	pango_cairo_update_layout(context, layout);
	lineCount = pango_layout_get_line_count(layout);
	lineIter = pango_layout_get_iter(layout);
	baseline = pango_layout_iter_get_baseline(lineIter);
	prevBaseline = 0;
	cairo_translate(context, 0, PANGO_PIXELS(baseline));
	logwithwith("lineCount %d %d", lineCount, strlen(aString));
	sqEnd = 0;
	totalY = 0;
	linesSize = interpreterProxy->stSizeOf(lines);
	lastLine = (((lineCount < linesSize) ? lineCount : linesSize)) - 1;
	for (lineIndex = 0; lineIndex <= lastLine; lineIndex += 1) {
		line = pango_layout_iter_get_line_readonly(lineIter);
		pango_layout_line_get_extents(line, &ink, &logical);
		sqStart = sqEnd + 1;
		start = line->start_index;
		sqEnd = (sqStart + (sqCharCountInfromto(aString, start, start + (line->length)))) - 1;
		logwithwith("sqStart, sqEnd: %d %d", sqStart, sqEnd);
		if (((start + (line->length)) < (interpreterProxy->stSizeOf(((int) aString)))) && ((aString[start + (line->length)]) == 13)) {
			sqEnd += 1;
		}
		logwith("sqEnd: %d", sqEnd);
		logwithwithwithwith("logical %d %d %d %d", logical.x, logical.y, logical.width, logical.height);
		interpreterProxy->storeIntegerofObjectwithValue(TextLineStartIndex, interpreterProxy->fetchPointerofObject(lineIndex, lines), sqStart);
		interpreterProxy->storeIntegerofObjectwithValue(TextLineEndIndex, interpreterProxy->fetchPointerofObject(lineIndex, lines), sqEnd);
		interpreterProxy->storeIntegerofObjectwithValue(TextLineLeftIndex, interpreterProxy->fetchPointerofObject(lineIndex, lines), (PANGO_PIXELS(logical.x)) + x);
		interpreterProxy->storeIntegerofObjectwithValue(TextLineRightIndex, interpreterProxy->fetchPointerofObject(lineIndex, lines), (PANGO_PIXELS(logical.x+logical.width)) + x);
		interpreterProxy->storeIntegerofObjectwithValue(TextLineTopIndex, interpreterProxy->fetchPointerofObject(lineIndex, lines), totalY + y);
		interpreterProxy->storeIntegerofObjectwithValue(TextLineInternalSpaceIndex, interpreterProxy->fetchPointerofObject(lineIndex, lines), ((0 << 1) | 1));
		interpreterProxy->storeIntegerofObjectwithValue(TextLinePaddingWidthIndex, interpreterProxy->fetchPointerofObject(lineIndex, lines), ((0 << 1) | 1));
		next = pango_layout_iter_next_line(lineIter);
		if (next) {
			addition = (logical.height) + (pango_layout_get_spacing(layout));
		} else {
			addition = logical.height;
		}
		totalY += PANGO_PIXELS(addition);
		interpreterProxy->storeIntegerofObjectwithValue(TextLineBottomIndex, interpreterProxy->fetchPointerofObject(lineIndex, lines), totalY + y);
	}
	pango_layout_get_extents(layout, &ink, &logical);
	newW = PANGO_PIXELS(logical.width);
	pango_layout_iter_free(lineIter);
	pango_attr_list_unref(attrList);
	g_object_unref(layout);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	_return_value = interpreterProxy->integerObjectOf(newW);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(9, _return_value);
	return null;
}

EXPORT(sqInt) primitivePangoFontDescriptionIndex(void) {
	sqInt newInd;
	char *familyName;
	char cFamilyName[128];
	PangoFontDescription * desc;
	sqInt i;
	sqInt ind;
	sqInt familyNameSize;
	sqInt isAbsolute;
	sqInt size;
	sqInt pangoStyle;
	sqInt familyNameOop;
	sqInt ptSize;
	sqInt _return_value;

	interpreterProxy->success(interpreterProxy->isKindOf(interpreterProxy->stackValue(1), "Object"));
	familyNameOop = interpreterProxy->stackValue(1);
	ptSize = interpreterProxy->stackIntegerValue(0);
	;
	if (interpreterProxy->failed()) {
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	familyNameSize = interpreterProxy->stSizeOf(familyNameOop);
	if (familyNameSize > 127) {
		return null;
	}
	if ((ptSize < 0) || (ptSize > 1000000)) {
		_return_value = ((-1 << 1) | 1);
		if (interpreterProxy->failed()) {
			return null;
		}
		interpreterProxy->popthenPush(3, _return_value);
		return null;
	}
	familyName = interpreterProxy->firstIndexableField(familyNameOop);
	for (i = 0; i <= (familyNameSize - 1); i += 1) {
		cFamilyName[i] = (familyName[i]);
	}
	cFamilyName[familyNameSize] = 0;
	newInd = -1;
	ind = 0;
	desc = null;
	while (newInd == -1) {
		desc = fontDescriptions[ind];
		if (desc == null) {
			newInd = ind;
		} else {
			isAbsolute = pango_font_description_get_size_is_absolute(desc);
			size = pango_font_description_get_size(desc);
			if (isAbsolute) {
				size = size;
			}
			if (((strcmp(cFamilyName, pango_font_description_get_family(desc))) == 0) && (size == (ptSize * (PANGO_SCALE)))) {
				newInd = ind;
			}
		}
		ind += 1;
		if (ind > 255) {
			newInd = 256;
		}
	}
	if (newInd == 256) {
		_return_value = ((-1 << 1) | 1);
		if (interpreterProxy->failed()) {
			return null;
		}
		interpreterProxy->popthenPush(3, _return_value);
		return null;
	}
	if (desc == null) {
		null;
	} else {
		_return_value = ((newInd << 1) | 1);
		if (interpreterProxy->failed()) {
			return null;
		}
		interpreterProxy->popthenPush(3, _return_value);
		return null;
	}
	desc = pango_font_description_new();
	pango_font_description_set_family(desc, cFamilyName);
	pangoStyle = PANGO_STYLE_NORMAL;
	pango_font_description_set_style(desc, pangoStyle);
	pango_font_description_set_size(desc, ptSize * (PANGO_SCALE));
	fontDescriptions[newInd] = desc;
	_return_value = ((newInd << 1) | 1);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(3, _return_value);
	return null;
}

EXPORT(sqInt) primitivePangoIndexAtPoint(void) {
	sqInt lineIndex;
	sqInt index;
	PangoRectangle pos;
	sqInt xPos;
	PangoLayoutLine* line;
	sqInt inside;
	sqInt trailing;
	sqInt origin;
	sqInt corner;
	sqInt canvasOop;
	cairo_t* context;
	PangoAttrList* attrList;
	PangoLayout* layout;
	char *aString;
	sqInt x;
	sqInt y;
	sqInt sqAttrArray;
	sqInt w;
	sqInt h;
	sqInt withWrap;
	sqInt charData;
	sqInt _return_value;

	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(7)));
	aString = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(7))));
	x = interpreterProxy->stackIntegerValue(6);
	y = interpreterProxy->stackIntegerValue(5);
	interpreterProxy->success(interpreterProxy->isKindOf(interpreterProxy->stackValue(4), "Object"));
	sqAttrArray = interpreterProxy->stackValue(4);
	w = interpreterProxy->stackIntegerValue(3);
	h = interpreterProxy->stackIntegerValue(2);
	withWrap = interpreterProxy->booleanValueOf(interpreterProxy->stackValue(1));
	interpreterProxy->success(interpreterProxy->isKindOf(interpreterProxy->stackValue(0), "Object"));
	charData = interpreterProxy->stackValue(0);
	;
	canvasOop = interpreterProxy->stackValue(8);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	layout = pango_cairo_create_layout(context);
	attrList = pango_attr_list_new();
	translateSqAttrsToPangoAttrsinto(sqAttrArray, attrList);
	pango_layout_set_text(layout, aString, strlen(aString));
	pango_layout_set_attributes(layout, attrList);
	pango_layout_set_width(layout, w * (PANGO_SCALE));
	if (withWrap) {
		pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
	}
	cairo_translate(context, x, y);
	pango_cairo_update_layout(context, layout);
	inside = pango_layout_xy_to_index(layout, x * (PANGO_SCALE), y * (PANGO_SCALE), &index, &trailing);
	pango_layout_index_to_pos(layout, index, &pos);
	line = null;
	if (!(inside)) {
		pango_layout_index_to_line_x(layout, index, trailing, &lineIndex, &xPos);
		line = pango_layout_get_line_readonly(layout, lineIndex);
		if (line == null) {
			index = 0;
		} else {
			if (!(trailing)) {
				index = line->start_index;
			}
		}
	}
	if (!(line == null)) {
		pango_layout_line_unref(line);
	}
	pango_attr_list_unref(attrList);
	g_object_unref(layout);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	origin = interpreterProxy->makePointwithxValueyValue(PANGO_PIXELS(pos.x), PANGO_PIXELS(pos.y));
	corner = interpreterProxy->makePointwithxValueyValue(PANGO_PIXELS(pos.x+pos.width), PANGO_PIXELS(pos.y+pos.height));
	interpreterProxy->storePointerofObjectwithValue(0, charData, origin);
	interpreterProxy->storePointerofObjectwithValue(1, charData, corner);
	index = (sqCharCountInfromto(aString, 0, index + trailing)) + 1;
	interpreterProxy->storePointerofObjectwithValue(2, charData, ((index << 1) | 1));
	_return_value = interpreterProxy->integerObjectOf(index);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(9, _return_value);
	return null;
}

EXPORT(sqInt) primitivePangoIsAvailable(void) {
	sqInt canvasOop;
	cairo_t* context;
	PangoLayout* layout;
	sqInt _return_value;

	canvasOop = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	layout = pango_cairo_create_layout(context);
	if (layout == null) {
		_return_value = interpreterProxy->integerObjectOf(2);
		if (interpreterProxy->failed()) {
			return null;
		}
		interpreterProxy->popthenPush(1, _return_value);
		return null;
	}
	g_object_unref(layout);
	_return_value = (1? interpreterProxy->trueObject(): interpreterProxy->falseObject());
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(1, _return_value);
	return null;
}

EXPORT(sqInt) primitivePangoShowString(void) {
	PangoRectangle ink;
	PangoRectangle logical;
	unsigned int cursorColor;
	sqInt lineCount;
	sqInt prevBaseline;
	PangoLayoutLine* line;
	sqInt indexToX;
	sqInt newW;
	PangoRectangle startRect;
	sqInt canvasOop;
	cairo_t* context;
	PangoLayoutIter* lineIter;
	PangoAttrList* attrList;
	PangoLayout* layout;
	char *aString;
	sqInt x;
	sqInt y;
	sqInt sqAttrArray;
	sqInt w;
	sqInt h;
	sqInt withWrap;
	sqInt selStart;
	sqInt selEnd;
	sqInt cPixel;
	sqInt _return_value;

	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(9)));
	aString = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(9))));
	x = interpreterProxy->stackIntegerValue(8);
	y = interpreterProxy->stackIntegerValue(7);
	interpreterProxy->success(interpreterProxy->isKindOf(interpreterProxy->stackValue(6), "Object"));
	sqAttrArray = interpreterProxy->stackValue(6);
	w = interpreterProxy->stackIntegerValue(5);
	h = interpreterProxy->stackIntegerValue(4);
	withWrap = interpreterProxy->booleanValueOf(interpreterProxy->stackValue(3));
	selStart = interpreterProxy->stackIntegerValue(2);
	selEnd = interpreterProxy->stackIntegerValue(1);
	interpreterProxy->success(interpreterProxy->isKindOf(interpreterProxy->stackValue(0), "Object"));
	cPixel = interpreterProxy->stackValue(0);
	;
	canvasOop = interpreterProxy->stackValue(10);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	cursorColor = interpreterProxy->positive32BitValueOf(cPixel);
	if (interpreterProxy->failed()) {
		return null;
	}
	layout = pango_cairo_create_layout(context);
	attrList = pango_attr_list_new();
	translateSqAttrsToPangoAttrsinto(sqAttrArray, attrList);
	if (!(selStart == selEnd)) {
		if ((selStart >= 0) && (selEnd >= 0)) {
			addSelectionFromtopixelinto(selStart, selEnd, cursorColor, attrList);
		}
	}
	pango_layout_set_text(layout, aString, strlen(aString));
	pango_layout_set_attributes(layout, attrList);
	pango_layout_set_width(layout, w * (PANGO_SCALE));
	if (withWrap) {
		pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
	}
	cairo_translate(context, x, y);
	pango_cairo_update_layout(context, layout);

	/* 	lineIter := self pangoLayoutGetIter: layout.
	baseline := self pangoLayoutIterGetBaseline: lineIter.
	prevBaseline := 0.
 */

	lineCount = pango_layout_get_line_count(layout);
	if (1) {
		pango_cairo_show_layout(context, layout);
	} else {
		null;
	}
	if (selStart == selEnd) {
		if ((selStart >= 0) && (selEnd >= 0)) {
			pango_layout_index_to_pos(layout, selStart, &startRect);
			addSelectionAtpixelwith(&startRect, cursorColor, context);
		}
	}
	pango_layout_get_extents(layout, &ink, &logical);

	/* self pangoLayoutIterFree: lineIter. */

	newW = PANGO_PIXELS(logical.width);
	pango_attr_list_unref(attrList);
	g_object_unref(layout);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	_return_value = interpreterProxy->integerObjectOf(newW);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(11, _return_value);
	return null;
}

EXPORT(sqInt) primitivePluginVersion(void) {
	sqInt _return_value;

	_return_value = interpreterProxy->integerObjectOf(PluginVersion);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(1, _return_value);
	return null;
}

EXPORT(sqInt) primitiveRestoreState(void) {
	sqInt canvasOop;
	cairo_t* context;

	canvasOop = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_restore(context);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	return null;
}

EXPORT(sqInt) primitiveRotateBy(void) {
	sqInt canvasOop;
	cairo_t* context;
	double angle;

	angle = interpreterProxy->stackFloatValue(0);
	canvasOop = interpreterProxy->stackValue(1);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_rotate(context, angle);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}

EXPORT(sqInt) primitiveSaveState(void) {
	sqInt canvasOop;
	cairo_t* context;

	canvasOop = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_save(context);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	return null;
}

EXPORT(sqInt) primitiveScaleBy(void) {
	sqInt canvasOop;
	cairo_t* context;
	double x;
	double y;

	x = interpreterProxy->stackFloatValue(1);
	y = interpreterProxy->stackFloatValue(0);
	canvasOop = interpreterProxy->stackValue(2);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_scale(context, x, y);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(2);
	return null;
}

EXPORT(sqInt) primitiveSetLineWidth(void) {
	sqInt canvasOop;
	cairo_t* context;
	double width;

	width = interpreterProxy->stackFloatValue(0);
	canvasOop = interpreterProxy->stackValue(1);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_set_line_width(context, width);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}

EXPORT(sqInt) primitiveSetTransform(void) {
	sqInt canvasOop;
	cairo_t* context;
	cairo_matrix_t m;
	float *aTransform;

	aTransform = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(0))));
	canvasOop = interpreterProxy->stackValue(1);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_matrix_init(&m, aTransform[0], aTransform[3], aTransform[1], aTransform[4], aTransform[2], aTransform[5]);
	cairo_set_matrix(context, &m);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}


/*	Show a string - ignores outline (use drawString primitive for outlines) */

EXPORT(sqInt) primitiveShowZeroTerminatedUtf8StringXY(void) {
	sqInt canvasOop;
	cairo_t* context;
	char *aString;
	double x;
	double y;

	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(2)));
	aString = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	x = interpreterProxy->stackFloatValue(1);
	y = interpreterProxy->stackFloatValue(0);
	canvasOop = interpreterProxy->stackValue(3);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_move_to(context, x, y);
	cairo_show_text(context, aString);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(3);
	return null;
}

EXPORT(sqInt) primitiveStencilImageSrcLRTBDestLRTB(void) {
	cairo_t* context;
	sqInt canvasOop;
	cairo_surface_t* srcSurface;
	sqInt formOop;
	double dstL;
	double dstR;
	double dstT;
	double dstB;
	double srcL;
	double srcR;
	double srcT;
	double srcB;

	formOop = interpreterProxy->stackValue(8);
	dstL = interpreterProxy->stackFloatValue(7);
	dstR = interpreterProxy->stackFloatValue(6);
	dstT = interpreterProxy->stackFloatValue(5);
	dstB = interpreterProxy->stackFloatValue(4);
	srcL = interpreterProxy->stackFloatValue(3);
	srcR = interpreterProxy->stackFloatValue(2);
	srcT = interpreterProxy->stackFloatValue(1);
	srcB = interpreterProxy->stackFloatValue(0);
	canvasOop = interpreterProxy->stackValue(9);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	srcSurface = surfaceFrom(formOop);
	if (!((srcSurface != null) && ((cairo_surface_status(srcSurface)) == 0))) {
		fail("source surface invalid");
		return null;
	}
	if ((srcR != srcL) && (srcT != srcB)) {
		cairo_save(context);
		cairo_translate(context, dstL, dstT);
		cairo_scale(context, (dstR - dstL) / (srcR - srcL), (dstB - dstT) / (srcB - srcT));
		cairo_new_path(context);
		cairo_rectangle(context, 0.0, 0.0, srcR - srcL, srcB - srcT);
		cairo_clip(context);
		cairo_mask_surface(context, srcSurface, 0.0 - srcL, 0.0 - srcT);
		cairo_restore(context);
	}
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(9);
	return null;
}

EXPORT(sqInt) primitiveTransformBy(void) {
	sqInt canvasOop;
	cairo_t* context;
	cairo_matrix_t m;
	float *aTransform;

	aTransform = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(0))));
	canvasOop = interpreterProxy->stackValue(1);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_matrix_init(&m, aTransform[0], aTransform[3], aTransform[1], aTransform[4], aTransform[2], aTransform[5]);
	cairo_transform(context, &m);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}

EXPORT(sqInt) primitiveTranslateBy(void) {
	sqInt canvasOop;
	cairo_t* context;
	double x;
	double y;

	x = interpreterProxy->stackFloatValue(1);
	y = interpreterProxy->stackFloatValue(0);
	canvasOop = interpreterProxy->stackValue(2);
	if (interpreterProxy->failed()) {
		return null;
	}
	context = contextFrom(canvasOop);
	if (interpreterProxy->failed()) {
		return null;
	}
	cairo_translate(context, x, y);
	if (cairo_status(context)) {
		failwith("cairo error: %s", cairo_status_to_string(cairo_status(context)));
		return null;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(2);
	return null;
}


/*	Register the given surface, answer an ID or -1 on failure */

static sqInt registerSurface(cairo_surface_t* surfaceHandle) {
	sqInt surfaceID;

	if (registerSurfaceFn == null) {
		if (!(loadSurfacePlugin())) {
			return -1;
		}
	}
	if (!((*registerSurfaceFn)((int)surfaceHandle, &surfaceDispatch, &surfaceID))) {
		fail("could not register surface");
		return -1;
	}
	/* missing DebugCode */;
	if (surfaceID > maxSurfaceID) {
		maxSurfaceID = surfaceID;
	}
	return surfaceID;
}


/*	Note: This is coded so that is can be run from Squeak. */

EXPORT(sqInt) setInterpreter(struct VirtualMachine* anInterpreter) {
	sqInt ok;

	interpreterProxy = anInterpreter;
	ok = interpreterProxy->majorVersion() == VM_PROXY_MAJOR;
	if (ok == 0) {
		return 0;
	}
	ok = interpreterProxy->minorVersion() >= VM_PROXY_MINOR;
	return ok;
}

static void setSourcergbalpha(cairo_t* context, sqInt rgb, sqInt alpha) {
	sqInt r;
	sqInt b;
	sqInt g;

	r = (((usqInt) rgb) >> 20) & 1023;
	g = (((usqInt) rgb) >> 10) & 1023;
	b = (((usqInt) rgb) >> 0) & 1023;
	if (alpha == 255) {
		cairo_set_source_rgb(context, r / 1023.0, g / 1023.0, b / 1023.0);
	} else {
		cairo_set_source_rgba(context, r / 1023.0, g / 1023.0, b / 1023.0, alpha / 255.0);
	}
}

static sqInt showSurfacexywh(cairo_surface_t * surfaceHandle, sqInt x, sqInt y, sqInt w, sqInt h) {
	return 0;
}

EXPORT(sqInt) shutdownModule(void) {
	PangoFontDescription* desc;
	sqInt i;
	cairo_surface_t* surface;
	sqInt id;

	for (i = 0; i <= (lastIndex(contexts)); i += 1) {
		if (!((contexts[i]) == null)) {
			logwith("context %i still active when unloading module!", i);
			cairo_destroy(contexts[i]);
			contexts[i] = null;
		}
	}
	for (id = 0; id <= maxSurfaceID; id += 1) {
		surface = findSurface(id);
		if (surface != null) {
			logwith("surface %i still active when unloading module!", id);
			destroySurface(id);
		}
	}
	for (i = 0; i <= 255; i += 1) {
		desc = fontDescriptions[i];
		if (desc != null) {
			pango_font_description_free(desc);
			fontDescriptions[i] = null;
		}
	}
	if (defaultFontDescription != null) {
		pango_font_description_free(defaultFontDescription);
		defaultFontDescription = null;
	}
	return 1;
}

static sqInt sqAssert(sqInt aBool) {
	/* missing DebugCode */;
}

static sqInt sqCharCountInfromto(unsigned char* aString, sqInt from, sqInt to) {
	sqInt sqCount;
	sqInt index;
	sqInt aChar;

	index = from;
	sqCount = 0;
	while (index < to) {
		aChar = aString[index];
		if (aChar < 128) {
			index += 1;
		} else {
			if (aChar < 224) {
				index += 2;
			} else {
				if (aChar < 240) {
					index += 3;
				} else {
					if (aChar < 248) {
						index += 4;
					} else {
						if (aChar < 252) {
							index += 5;
						} else {
							if (aChar >= 252) {
								index += 6;
							}
						}
					}
				}
			}
		}
		sqCount += 1;
	}
	return sqCount;
}


/*	stroke depending on canvasOop's stroke flag */

static void strokefrom(cairo_t* context, sqInt canvasOop) {
	sqInt rgb;
	sqInt canvasFlags;
	sqInt stroke;

	canvasFlags = interpreterProxy->fetchIntegerofObject(CanvasFlagsIndex, canvasOop);
	if (interpreterProxy->failed()) {
		fail("canvas flags not an integer");
	} else {
		stroke = canvasFlags & CanvasFlagStroke;
		if (stroke != 0) {
			rgb = interpreterProxy->fetchIntegerofObject(CanvasStrokeColorIndex, canvasOop);
			cairo_save(context);
			setSourcergbalpha(context, rgb, stroke);
			cairo_stroke(context);
			cairo_restore(context);
		}
	}
}


/*	answer a surface by looking up its surface plugin ID stored as bits in formOop */

static cairo_surface_t* surfaceFrom(sqInt formOop) {
	sqInt surfaceID;

	if ((interpreterProxy->slotSizeOf(formOop)) < FormInstSize) {
		fail("form oop invalid");
		return null;
	}
	surfaceID = interpreterProxy->fetchIntegerofObject(FormBitsIndex, formOop);
	if (interpreterProxy->failed()) {
		fail("form handle not an integer");
		return null;
	}
	return findSurface(surfaceID);
}

static sqInt translateSqAttrsToPangoAttrsinto(sqInt sqAttrsArrayOop, PangoAttrList * pangoAttrList) {
	sqInt * sqAttrsArray;
	sqInt attrArray;
	sqInt symbolOop;
	sqInt sqAttrsSize;
	sqInt ind;
	char * symbol;

	sqAttrsSize = interpreterProxy->stSizeOf(sqAttrsArrayOop);
	sqAttrsArray = interpreterProxy->firstIndexableField(sqAttrsArrayOop);
	addDefaultInto(pangoAttrList);
	for (ind = 0; ind <= (sqAttrsSize - 1); ind += 1) {
		attrArray = sqAttrsArray[ind];
		symbolOop = interpreterProxy->fetchPointerofObject(0, attrArray);
		symbol = interpreterProxy->firstIndexableField(symbolOop);
		if ((symbol[0]) == 65) {
			addAlignmentinto(attrArray, pangoAttrList);
		}
		if ((symbol[0]) == 67) {
			addColorinto(attrArray, pangoAttrList);
		}
		if ((symbol[0]) == 69) {
			addEmphasisinto(attrArray, pangoAttrList);
		}
		if ((symbol[0]) == 70) {
			addFontinto(attrArray, pangoAttrList);
		}
		if ((symbol[0]) == 76) {
			addLanguageinto(attrArray, pangoAttrList);
		}
	}
	return 1;
}

static sqInt unlockSurfacexywh(cairo_surface_t* surfaceHandle, sqInt x, sqInt y, sqInt w, sqInt h) {
	/* missing DebugCode */;
	if ((w > 0) && (h > 0)) {
		cairo_surface_mark_dirty_rectangle(surfaceHandle, x, y, w, h);
	}
	return 1;
}


/*	Unregister the surface, answer true if successful */

static sqInt unregisterSurface(sqInt surfaceID) {
	if (unregisterSurfaceFn == null) {
		if (!(loadSurfacePlugin())) {
			return 0;
		}
	}
	/* missing DebugCode */;
	if (!((*unregisterSurfaceFn)(surfaceID))) {
		failwith("could not unregister surface %i", surfaceID);
		return 0;
	}
	return 1;
}


#ifdef SQUEAK_BUILTIN_PLUGIN


void* RomePlugin_exports[][3] = {
	{"RomePlugin", "primitiveDestroyFormHandle", (void*)primitiveDestroyFormHandle},
	{"RomePlugin", "primitiveTransformBy", (void*)primitiveTransformBy},
	{"RomePlugin", "primitivePangoBlockAtIndex", (void*)primitivePangoBlockAtIndex},
	{"RomePlugin", "shutdownModule", (void*)shutdownModule},
	{"RomePlugin", "primitiveSaveState", (void*)primitiveSaveState},
	{"RomePlugin", "primitivePluginVersion", (void*)primitivePluginVersion},
	{"RomePlugin", "primitiveClose", (void*)primitiveClose},
	{"RomePlugin", "setInterpreter", (void*)setInterpreter},
	{"RomePlugin", "primitivePangoFontDescriptionIndex", (void*)primitivePangoFontDescriptionIndex},
	{"RomePlugin", "primitiveClear", (void*)primitiveClear},
	{"RomePlugin", "primitiveDrawRectangleLeftRightTopBottom", (void*)primitiveDrawRectangleLeftRightTopBottom},
	{"RomePlugin", "primitiveScaleBy", (void*)primitiveScaleBy},
	{"RomePlugin", "primitiveFillRadialOriginXYdirectionXYnormalXYcolorStops", (void*)primitiveFillRadialOriginXYdirectionXYnormalXYcolorStops},
	{"RomePlugin", "primitiveDrawCurveFromXYviaXYandXYtoXY", (void*)primitiveDrawCurveFromXYviaXYandXYtoXY},
	{"RomePlugin", "primitivePangoIsAvailable", (void*)primitivePangoIsAvailable},
	{"RomePlugin", "moduleUnloaded", (void*)moduleUnloaded},
	{"RomePlugin", "primitivePangoIndexAtPoint", (void*)primitivePangoIndexAtPoint},
	{"RomePlugin", "primitiveCreateFormHandle", (void*)primitiveCreateFormHandle},
	{"RomePlugin", "primitiveDrawGeneralBezierShape", (void*)primitiveDrawGeneralBezierShape},
	{"RomePlugin", "primitiveStencilImageSrcLRTBDestLRTB", (void*)primitiveStencilImageSrcLRTBDestLRTB},
	{"RomePlugin", "primitiveDrawImageSrcLRTBDestLRTB", (void*)primitiveDrawImageSrcLRTBDestLRTB},
	{"RomePlugin", "primitiveFillBitmapOriginXYdirectionXYnormalXYRepeatImage", (void*)primitiveFillBitmapOriginXYdirectionXYnormalXYRepeatImage},
	{"RomePlugin", "primitiveRotateBy", (void*)primitiveRotateBy},
	{"RomePlugin", "initialiseModule", (void*)initialiseModule},
	{"RomePlugin", "primitiveSetTransform", (void*)primitiveSetTransform},
	{"RomePlugin", "primitiveSetLineWidth", (void*)primitiveSetLineWidth},
	{"RomePlugin", "primitiveFillLinearOriginXYdirectionXYcolorStops", (void*)primitiveFillLinearOriginXYdirectionXYcolorStops},
	{"RomePlugin", "primitiveFillColorAlpha", (void*)primitiveFillColorAlpha},
	{"RomePlugin", "primitiveOpen", (void*)primitiveOpen},
	{"RomePlugin", "primitivePangoComposeString", (void*)primitivePangoComposeString},
	{"RomePlugin", "primitiveDrawRoundRectLeftRightTopBottomRadiusCorner", (void*)primitiveDrawRoundRectLeftRightTopBottomRadiusCorner},
	{"RomePlugin", "primitiveDrawZeroTerminatedUtf8StringXY", (void*)primitiveDrawZeroTerminatedUtf8StringXY},
	{"RomePlugin", "primitiveRestoreState", (void*)primitiveRestoreState},
	{"RomePlugin", "primitiveTranslateBy", (void*)primitiveTranslateBy},
	{"RomePlugin", "primitiveFontFace", (void*)primitiveFontFace},
	{"RomePlugin", "getModuleName", (void*)getModuleName},
	{"RomePlugin", "primitiveGetTransform", (void*)primitiveGetTransform},
	{"RomePlugin", "primitiveDrawCurveFromXYviaXYtoXY", (void*)primitiveDrawCurveFromXYviaXYtoXY},
	{"RomePlugin", "primitiveDrawArcRadiusXYFromTo", (void*)primitiveDrawArcRadiusXYFromTo},
	{"RomePlugin", "primitivePangoShowString", (void*)primitivePangoShowString},
	{"RomePlugin", "primitiveDrawPolyline", (void*)primitiveDrawPolyline},
	{"RomePlugin", "primitiveShowZeroTerminatedUtf8StringXY", (void*)primitiveShowZeroTerminatedUtf8StringXY},
	{"RomePlugin", "primitiveFontSize", (void*)primitiveFontSize},
	{"RomePlugin", "primitiveDrawPolygon", (void*)primitiveDrawPolygon},
	{"RomePlugin", "primitiveGetLineWidth", (void*)primitiveGetLineWidth},
	{"RomePlugin", "primitiveClipRectangleLeftRightTopBottom", (void*)primitiveClipRectangleLeftRightTopBottom},
	{"RomePlugin", "primitiveDrawLineFromXYtoXY", (void*)primitiveDrawLineFromXYtoXY},
	{"RomePlugin", "primitiveDrawOvalLeftRightTopBottom", (void*)primitiveDrawOvalLeftRightTopBottom},
	{NULL, NULL, NULL}
};


#endif /* ifdef SQ_BUILTIN_PLUGIN */

