/* Smalltalk from Squeak4.6 with VMMaker 4.20.6 translated as C source on 2 December 2023 1:37:17 pm */
/* Automatically generated by
	SmartSyntaxPluginCodeGenerator VMMaker-dtl.440 uuid: d347df2d-ee8f-4564-8178-f628d7327704
   from
	VectorEnginePlugin VectorEnginePlugin-mt.16 uuid: eb9cb5f6-37a7-e042-946d-a80971ef3451
 */
static char __buildInfo[] = "VectorEnginePlugin VectorEnginePlugin-mt.16 uuid: eb9cb5f6-37a7-e042-946d-a80971ef3451 " __DATE__ ;




/* Configuration options */
#include "sqConfig.h"

#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"
/* 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 <stdint.h>

#include "sqMemoryAccess.h"


/*** Constants ***/

/*** Function Prototypes ***/
#pragma export on
EXPORT(sqInt) primAntiAliasingWidthsubPixelDeltaHopLength(void);
EXPORT(sqInt) primArc(void);
EXPORT(sqInt) primArcWP(void);
#pragma export off
static sqInt blendFillOnlyAtredIsInsidegreenIsInsideblueIsInsideantiAliasAlphasWord(sqInt pixelIndex, sqInt isRedInside, sqInt isGreenInside, sqInt isBlueInside, uint32_t antiAliasAlphasWord);
#pragma export on
EXPORT(sqInt) primBlendFillOnly(void);
#pragma export off
static sqInt blendFillOnlyWPOTAtantiAliasAlphaByte(sqInt pixelIndex, uint8_t antiAliasAlphaBits);
#pragma export on
EXPORT(sqInt) primBlendFillOnlyWPOT(void);
#pragma export off
static sqInt blendStrokeAndFillAtredIsInsidegreenIsInsideblueIsInsideantiAliasAlphasWord(sqInt pixelIndex, sqInt isRedInside, sqInt isGreenInside, sqInt isBlueInside, uint32_t antiAliasAlphasWord);
static sqInt blendStrokeAndFillInsideWPOTAtantiAliasAlphaByte(sqInt pixelIndex, uint8_t antiAliasAlphaBits);
#pragma export on
EXPORT(sqInt) primBlendStrokeAndFill(void);
#pragma export off
static sqInt blendStrokeAndFillOutsideWPOTAtantiAliasAlphaByte(sqInt pixelIndex, uint8_t antiAliasAlphaBits);
#pragma export on
EXPORT(sqInt) primBlendStrokeAndFillWPOT(void);
#pragma export off
static sqInt blendStrokeOnlyAtantiAliasAlphasWord(sqInt pixelIndex, uint32_t antiAliasAlphasWord);
#pragma export on
EXPORT(sqInt) primBlendStrokeOnly(void);
#pragma export off
static sqInt blendStrokeOnlyWPOTAtantiAliasAlphaByte(sqInt pixelIndex, uint8_t antiAliasAlphaBits);
#pragma export on
EXPORT(sqInt) primBlendStrokeOnlyWPOT(void);
EXPORT(sqInt) primClipCurrentMorph(void);
EXPORT(sqInt) primClipLeftclipTopclipRightclipBottom(void);
EXPORT(sqInt) primCubicBezier(void);
EXPORT(sqInt) primCubicBezierWP(void);
EXPORT(sqInt) primCurrentMorphIdcurrentClipsSubmorphs(void);
EXPORT(sqInt) primDisplayString(void);
EXPORT(sqInt) primDisplayStringWP(void);
EXPORT(sqInt) primDisplayUtf32(void);
EXPORT(sqInt) primDisplayUtf32WP(void);
EXPORT(sqInt) primDisplayUtf8(void);
EXPORT(sqInt) primDisplayUtf8WP(void);
EXPORT(sqInt) primFillRGBA(void);
EXPORT(sqInt) primGeometryTxSet(void);
EXPORT(const char*) getModuleName(void);
#pragma export off
static sqInt halt(void);
#pragma export on
EXPORT(sqInt) primInitializePath(void);
EXPORT(sqInt) primLine(void);
EXPORT(sqInt) primLineWP(void);
EXPORT(sqInt) primNewTrajectoryFragment(void);
EXPORT(sqInt) primPathSequence(void);
EXPORT(sqInt) primPathSequenceWP(void);
EXPORT(sqInt) pluginApiVersion(void);
#pragma export off
static sqInt pvt_cubicBezierFromXytoXycontrol1Xycontrol2Xy(float xFrom, float yFrom, float xTo, float yTo, float xControl1, float yControl1, float xControl2, float yControl2);
static sqInt pvt_cubicBezierWPFromXytoXycontrol1Xycontrol2Xy(float xFrom, float yFrom, float xTo, float yTo, float xControl1, float yControl1, float xControl2, float yControl2);
static sqInt pvt_lineFromXytoXy(float xFrom, float yFrom, float xTo, float yTo);
static sqInt pvt_lineWPFromXytoXy(float xFrom, float yFrom, float xTo, float yTo);
static sqInt pvt_quadraticBezierFromXytoXycontrolXy(float xFrom, float yFrom, float xTo, float yTo, float xControl, float yControl);
static sqInt pvt_quadraticBezierWPFromXytoXycontrolXy(float xFrom, float yFrom, float xTo, float yTo, float xControl, float yControl);
#pragma export on
EXPORT(sqInt) primQuadraticBezier(void);
EXPORT(sqInt) primQuadraticBezierWP(void);
EXPORT(sqInt) primReset2Contour(void);
EXPORT(sqInt) setInterpreter(struct VirtualMachine*anInterpreter);
EXPORT(sqInt) primSpanBottom(void);
EXPORT(sqInt) primSpanLeft(void);
EXPORT(sqInt) primSpanRight(void);
EXPORT(sqInt) primSpanTop(void);
EXPORT(sqInt) primStrokeRGBA(void);
EXPORT(sqInt) primStrokeWidth(void);
EXPORT(sqInt) primSetTarget(void);
EXPORT(sqInt) primSetTargetWP(void);
#pragma export off
static sqInt updateAlphasForXy(float x, float y);
static sqInt updateAlphasWPForXy(float x, float y);
static sqInt updateAlphasWPZeroStrokeForXy(float x, float y);
static sqInt updateContourForXy(float x, float y);
#pragma export on
EXPORT(sqInt) primUpdate2ContourLastLine(void);
#pragma export off
static sqInt updateEdgeCountAtXy(float x, float y);
static sqInt updateEdgeCountWPAtXy(float x, float y);
/*** Variables ***/
static uint32_t * alphaMask;
static uint8_t * alphaMaskWP;
static float antiAliasingWidth;
static float auxAntiAliasingWidthScaledInverse;
static float auxStrokeWidthDilatedHalf;
static float auxStrokeWidthDilatedHalfSquared;
static float auxStrokeWidthErodedHalfSquared;
static sqInt clipBottom;
static sqInt clipCurrentMorph;
static sqInt clipLeft;
static sqInt clipRight;
static sqInt clipTop;
static float * contour;
static sqInt currentClipsSubmorphs;
static uint32_t currentMorphId;
static uint32_t * edgeCounts;
static uint8_t * edgeCountsWP;
static float fillA;
static float fillB;
static float fillG;
static float fillR;
static float hop;

#ifdef SQUEAK_BUILTIN_PLUGIN
extern
#endif
struct VirtualMachine* interpreterProxy;
static float leftAtThisY;
static const char *moduleName =
#ifdef SQUEAK_BUILTIN_PLUGIN
	"VectorEnginePlugin 2 December 2023 (i)"
#else
	"VectorEnginePlugin 2 December 2023 (e)"
#endif
;
static uint32_t * morphIds;
static sqInt prevYRounded;
static sqInt prevYTruncated;
static float rightAtThisY;
static sqInt simulator;
static float spanBottom;
static float spanLeft;
static float spanRight;
static float spanTop;
static float strokeA;
static float strokeB;
static float strokeG;
static float strokeR;
static float strokeWidth;
static float subPixelDelta;
static uint32_t * targetBits;
static sqInt targetHeight;
static sqInt targetWidth;
static float txA11;
static float txA12;
static float txA13;
static float txA21;
static float txA22;
static float txA23;


EXPORT(sqInt) primAntiAliasingWidthsubPixelDeltaHopLength(void) {
	double aFloat;
	double otherFloat;
	double anotherFloat;

	aFloat = interpreterProxy->stackFloatValue(2);
	otherFloat = interpreterProxy->stackFloatValue(1);
	anotherFloat = interpreterProxy->stackFloatValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	antiAliasingWidth = aFloat;
	auxAntiAliasingWidthScaledInverse = 127.0 / aFloat;
	subPixelDelta = otherFloat;
	hop = anotherFloat;
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(3);
	return null;
}

EXPORT(sqInt) primArc(void) {
	float d;
	float tcy;
	float trx;
	float x;
	sqInt h;
	float xp;
	float scale;
	float try;
	float y;
	float angle;
	int hops;
	float yp;
	float tcx;
	double centerX;
	double centerY;
	double radiusPointX;
	double radiusPointY;
	double startAngle;
	double sweepAngle;
	double tthetaCos;
	double tthetaSin;
	unsigned *otherWordArray;
	unsigned *anotherWordArray;
	float *aFloat32Array;

	centerX = interpreterProxy->stackFloatValue(10);
	centerY = interpreterProxy->stackFloatValue(9);
	radiusPointX = interpreterProxy->stackFloatValue(8);
	radiusPointY = interpreterProxy->stackFloatValue(7);
	startAngle = interpreterProxy->stackFloatValue(6);
	sweepAngle = interpreterProxy->stackFloatValue(5);
	tthetaCos = interpreterProxy->stackFloatValue(4);
	tthetaSin = interpreterProxy->stackFloatValue(3);
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(2)));
	otherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(1)));
	anotherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	aFloat32Array = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	tcx = ((centerX * txA11) + (centerY * txA12)) + txA13;
	tcy = ((centerX * txA21) + (centerY * txA22)) + txA23;
	scale = sqrt(txA11*txA11 + txA21*txA21);;
	trx = radiusPointX * scale;
	try = radiusPointY * scale;
	hops = (((sqInt)(((((trx < try) ? try : trx)) * (fabs(sweepAngle))) / hop))) + 2;
	d = hops;
	edgeCounts = otherWordArray;
	alphaMask = anotherWordArray;
	contour = aFloat32Array;
	for (h = 0; h <= hops; h += 1) {
		angle = ((float)h / d) * sweepAngle + startAngle;;
		xp = (cos(angle)) * trx;
		yp = (sin(angle)) * try;
		x = ((tthetaCos * xp) - (tthetaSin * yp)) + tcx;
		y = ((tthetaSin * xp) + (tthetaCos * yp)) + tcy;
		spanLeft = ((spanLeft < x) ? spanLeft : x);
		spanTop = ((spanTop < y) ? spanTop : y);
		spanRight = ((spanRight < x) ? x : spanRight);
		spanBottom = ((spanBottom < y) ? y : spanBottom);
		updateAlphasForXy(x, y);
		if (!(fillA == 0.0)) {
			updateEdgeCountAtXy(x, y);
		}
		updateContourForXy(x, y);
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(11);
	return null;
}

EXPORT(sqInt) primArcWP(void) {
	float d;
	float tcy;
	float trx;
	float x;
	sqInt h;
	float xp;
	float try;
	float scale;
	float y;
	float angle;
	int hops;
	float yp;
	float tcx;
	double centerX;
	double centerY;
	double radiusPointX;
	double radiusPointY;
	double startAngle;
	double sweepAngle;
	double tthetaCos;
	double tthetaSin;
	char *otherByteArray;
	char *anotherByteArray;
	float *aFloat32Array;

	centerX = interpreterProxy->stackFloatValue(10);
	centerY = interpreterProxy->stackFloatValue(9);
	radiusPointX = interpreterProxy->stackFloatValue(8);
	radiusPointY = interpreterProxy->stackFloatValue(7);
	startAngle = interpreterProxy->stackFloatValue(6);
	sweepAngle = interpreterProxy->stackFloatValue(5);
	tthetaCos = interpreterProxy->stackFloatValue(4);
	tthetaSin = interpreterProxy->stackFloatValue(3);
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(2)));
	otherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(1)));
	anotherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	aFloat32Array = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	tcx = ((centerX * txA11) + (centerY * txA12)) + txA13;
	tcy = ((centerX * txA21) + (centerY * txA22)) + txA23;
	scale = sqrt(txA11*txA11 + txA21*txA21);;
	trx = radiusPointX * scale;
	try = radiusPointY * scale;
	hops = (((sqInt)(((((trx < try) ? try : trx)) * (fabs(sweepAngle))) / hop))) + 2;
	d = hops;
	edgeCountsWP = otherByteArray;
	alphaMaskWP = anotherByteArray;
	contour = aFloat32Array;
	for (h = 0; h <= hops; h += 1) {
		angle = ((float)h / d) * sweepAngle + startAngle;;
		xp = (cos(angle)) * trx;
		yp = (sin(angle)) * try;
		x = ((tthetaCos * xp) - (tthetaSin * yp)) + tcx;
		y = ((tthetaSin * xp) + (tthetaCos * yp)) + tcy;
		spanLeft = ((spanLeft < x) ? spanLeft : x);
		spanTop = ((spanTop < y) ? spanTop : y);
		spanRight = ((spanRight < x) ? x : spanRight);
		spanBottom = ((spanBottom < y) ? y : spanBottom);
		updateAlphasWPForXy(x, y);
		if (!(fillA == 0.0)) {
			updateEdgeCountWPAtXy(x, y);
		}
		updateContourForXy(x, y);
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(11);
	return null;
}


/*	Blends fill color over background. Target translucency computed correctly.
	For blending, alphas are in [0 .. 1.0] and R, G, B color components are in [0 .. 255] */

static sqInt blendFillOnlyAtredIsInsidegreenIsInsideblueIsInsideantiAliasAlphasWord(sqInt pixelIndex, sqInt isRedInside, sqInt isGreenInside, sqInt isBlueInside, uint32_t antiAliasAlphasWord) {
	uint32_t resultGBits;
	uint32_t antiAliasGreenAlphaBits;
	float antiAliasGreenAlpha;
	uint32_t antiAliasRedAlphaBits;
	float unAlphaR;
	float clippingAntiAlias;
	uint32_t antiAliasBlueAlphaBits;
	float unAlphaB;
	float resultAlphaG;
	uint32_t clippingAntiAliasBits;
	float resultR;
	float resultB;
	uint32_t resultAlphaBits;
	uint32_t resultRBits;
	float alphaG;
	float antiAliasBlueAlpha;
	uint32_t morphIdWord;
	float targetAlpha;
	float resultAlphaR;
	uint32_t resultBBits;
	float resultAlphaB;
	uint32_t antiAliasGreenAlphaBitsShifted;
	float unAlphaG;
	uint32_t targetWord;
	float alphaR;
	float antiAliasRedAlpha;
	float resultG;
	float alphaB;

	antiAliasRedAlphaBits = antiAliasAlphasWord & 0x7F0000;
	antiAliasGreenAlphaBits = antiAliasAlphasWord & 0x7F00;
	antiAliasBlueAlphaBits = antiAliasAlphasWord & 0x7F;
	if (isRedInside) {
		antiAliasRedAlphaBits = 0x7F0000 - antiAliasRedAlphaBits;
	}
	if (isGreenInside) {
		antiAliasGreenAlphaBits = 0x7F00 - antiAliasGreenAlphaBits;
	}
	if (isBlueInside) {
		antiAliasBlueAlphaBits = 0x7F - antiAliasBlueAlphaBits;
	}
	antiAliasRedAlpha = antiAliasRedAlphaBits * (1.0 / ((127.0 * 256) * 256));
	antiAliasGreenAlpha = antiAliasGreenAlphaBits * (1.0 / (127.0 * 256));
	antiAliasBlueAlpha = antiAliasBlueAlphaBits * (1.0 / 127.0);
	alphaR = antiAliasRedAlpha * fillA;
	alphaG = antiAliasGreenAlpha * fillA;
	alphaB = antiAliasBlueAlpha * fillA;
	if (currentClipsSubmorphs) {

		/* Don't clip us, but do clip submorphs */

		morphIdWord = morphIds[pixelIndex];
		clippingAntiAliasBits = morphIdWord & 0x7F;
		
					antiAliasGreenAlphaBitsShifted = antiAliasGreenAlphaBits >> 8;;
		if (antiAliasGreenAlphaBitsShifted > clippingAntiAliasBits) {
			clippingAntiAliasBits = antiAliasGreenAlphaBitsShifted;
		}
	} else {
		if (clipCurrentMorph) {

			/* Clip ourselves to the border anti aliasing of the morph we are clipping at. Keep it for further use. */

			morphIdWord = morphIds[pixelIndex];
			clippingAntiAliasBits = morphIdWord & 0x7F;
			clippingAntiAlias = clippingAntiAliasBits * (1.0 / 127.0);
			alphaR = alphaR * clippingAntiAlias;
			alphaG = alphaG * clippingAntiAlias;
			alphaB = alphaB * clippingAntiAlias;
		} else {

			/* Don't do any additional clipping or preparation for further clipping */

			clippingAntiAliasBits = 0;
		}
	}
	if (!(((alphaR + alphaG) + alphaB) == 0.0)) {
		targetWord = targetBits[pixelIndex];
		resultAlphaBits = targetWord & 0xFF000000U;
		resultRBits = targetWord & 0xFF0000;
		resultGBits = targetWord & 0xFF00;
		resultBBits = targetWord & 0xFF;

		/* These if are not really needed. just ignore them if we use simd instructions. */

		targetAlpha = resultAlphaBits * (1.0 / (((255.0 * 256) * 256) * 256));
		if (!(alphaR == 0.0)) {
			unAlphaR = 1.0 - alphaR;
			resultAlphaR = alphaR + (unAlphaR * targetAlpha);
			
					resultR = (alphaR * fillR) + ((unAlphaR * (resultRBits >> 16)) * targetAlpha);
					resultRBits = (uint32_t)(resultR / resultAlphaR + 0.5) << 16;;
		}
		if (!(alphaG == 0.0)) {
			unAlphaG = 1.0 - alphaG;
			resultAlphaG = alphaG + (unAlphaG * targetAlpha);
			
					resultG = (alphaG * fillG) + ((unAlphaG * (resultGBits >> 8)) * targetAlpha);
					resultGBits = (uint32_t)(resultG / resultAlphaG + 0.5) << 8;
					resultAlphaBits = (uint32_t)(resultAlphaG * 255.0 + 0.5) << 24;;
		}
		if (!(alphaB == 0.0)) {
			unAlphaB = 1.0 - alphaB;
			resultAlphaB = alphaB + (unAlphaB * targetAlpha);
			
					resultB = (alphaB * fillB) + ((unAlphaB * resultBBits) * targetAlpha);
					resultBBits = (uint32_t)(resultB / resultAlphaB + 0.5);;
		}
		targetWord = ((resultAlphaBits | resultRBits) | resultGBits) | resultBBits;
		targetBits[pixelIndex] = targetWord;
		morphIdWord = (currentMorphId << 8) + clippingAntiAliasBits;
		morphIds[pixelIndex] = morphIdWord;
	}
	return null;
}


/*	Blends fill color over background. Target translucency computed correctly.
	For blending, alphas are in [0 .. 1.0] and R, G, B color components are in [0 .. 255] */

EXPORT(sqInt) primBlendFillOnly(void) {
	uint8_t edgesUpToThisPixelR;
	uint8_t edgesUpToThisPixelB;
	uint8_t edgesThisPixelG;
	sqInt pixelIndex;
	uint32_t edgesThisPixelWord;
	sqInt isRedInside;
	sqInt isBlueInside;
	uint8_t edgesThisPixelR;
	uint8_t edgesUpToThisPixelG;
	uint8_t edgesThisPixelB;
	sqInt isGreenInside;
	sqInt displayX;
	uint32_t antiAliasAlphasWord;
	sqInt displayY;
	sqInt l;
	sqInt t;
	sqInt r;
	sqInt b;
	unsigned *aBitmap;
	unsigned *aWordArray;
	unsigned *otherWordArray;
	unsigned *anotherWordArray;

	l = interpreterProxy->stackIntegerValue(7);
	t = interpreterProxy->stackIntegerValue(6);
	r = interpreterProxy->stackIntegerValue(5);
	b = interpreterProxy->stackIntegerValue(4);
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(3)));
	aBitmap = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(3))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(2)));
	aWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(1)));
	otherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(0)));
	anotherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	targetBits = aBitmap;
	morphIds = aWordArray;
	edgeCounts = otherWordArray;
	alphaMask = anotherWordArray;
	for (displayY = t; displayY <= b; displayY += 1) {
		edgesUpToThisPixelR = 0;
		edgesUpToThisPixelG = 0;
		edgesUpToThisPixelB = 0;
		pixelIndex = ((displayY * targetWidth) + l) - 1;
		for (displayX = l; displayX <= r; displayX += 1) {
			pixelIndex += 1;
			edgesThisPixelWord = edgeCounts[pixelIndex];
			if (!(edgesThisPixelWord == 0)) {
				edgeCounts[pixelIndex] = 0;
			}
			
					edgesThisPixelR = (uint32_t) (edgesThisPixelWord & 0xFF0000) >> 16;
					edgesThisPixelG = (uint32_t) (edgesThisPixelWord & 0xFF00) >> 8;
					edgesThisPixelB = (uint32_t) (edgesThisPixelWord & 0xFF);;
			edgesUpToThisPixelR += edgesThisPixelR;
			edgesUpToThisPixelG += edgesThisPixelG;

			/* In C, integers already behave like booleans */

			edgesUpToThisPixelB += edgesThisPixelB;
			
					isRedInside = edgesUpToThisPixelR;
					isGreenInside = edgesUpToThisPixelG;
					isBlueInside = edgesUpToThisPixelB;;
			antiAliasAlphasWord = alphaMask[pixelIndex];
			if (antiAliasAlphasWord != 0) {
				alphaMask[pixelIndex] = 0;
			}
			if ((antiAliasAlphasWord != 0) || (isRedInside || (isGreenInside || (isBlueInside)))) {
				blendFillOnlyAtredIsInsidegreenIsInsideblueIsInsideantiAliasAlphasWord(pixelIndex, isRedInside, isGreenInside, isBlueInside, antiAliasAlphasWord);
			}
		}
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(8);
	return null;
}


/*	Blends fill color over background.
	WP: Whole pixel anti aliasing.
	OT: Target ignored on input and set to opaque on output.
	For blending, alphas are in [0 .. 1.0] and R, G, B color components are in [0 .. 255] */

static sqInt blendFillOnlyWPOTAtantiAliasAlphaByte(sqInt pixelIndex, uint8_t antiAliasAlphaBits) {
	uint32_t resultGBits;
	float unAlpha;
	float clippingAntiAlias;
	uint32_t clippingAntiAliasBits;
	float resultR;
	float resultB;
	uint32_t resultRBits;
	float antiAliasAlpha;
	uint32_t morphIdWord;
	uint32_t resultBBits;
	float alpha;
	uint32_t targetWord;
	float resultG;


	/* 1.0/127.0 */

	antiAliasAlpha = antiAliasAlphaBits * 0.007874;
	alpha = antiAliasAlpha * fillA;
	if (currentClipsSubmorphs) {

		/* Don't clip us, but do clip submorphs */

		morphIdWord = morphIds[pixelIndex];
		clippingAntiAliasBits = morphIdWord & 0x7F;
		if (antiAliasAlphaBits > clippingAntiAliasBits) {
			clippingAntiAliasBits = antiAliasAlphaBits;
		}
	} else {
		if (clipCurrentMorph) {

			/* Clip ourselves to the border anti aliasing of the morph we are clipping at. Keep it for further use. */

			morphIdWord = morphIds[pixelIndex];
			clippingAntiAliasBits = morphIdWord & 0x7F;

			/* 1.0/127.0 */

			clippingAntiAlias = clippingAntiAliasBits * 0.007874;
			alpha = alpha * clippingAntiAlias;
		} else {

			/* Don't do any additional clipping or preparation for further clipping */

			clippingAntiAliasBits = 0;
		}
	}
	if (!(alpha == 0.0)) {
		targetWord = targetBits[pixelIndex];
		resultRBits = targetWord & 0xFF0000;
		resultGBits = targetWord & 0xFF00;
		resultBBits = targetWord & 0xFF;
		unAlpha = 1.0 - alpha;
		
				resultR = (alpha * fillR) + (unAlpha * (resultRBits >> 16));
				resultRBits = (uint32_t)(resultR + 0.5) << 16;
				resultG = (alpha * fillG) + (unAlpha * (resultGBits >> 8));
				resultGBits = (uint32_t)(resultG + 0.5) << 8;
				resultB = (alpha * fillB) + (unAlpha * resultBBits);
				resultBBits = (uint32_t)(resultB + 0.5);;
		targetWord = ((0xFF000000U | resultRBits) | resultGBits) | resultBBits;
		targetBits[pixelIndex] = targetWord;
		morphIdWord = (currentMorphId << 8) + clippingAntiAliasBits;
		morphIds[pixelIndex] = morphIdWord;
	}
	return null;
}


/*	Blends fill color over background.
	WP: Whole pixel anti aliasing.
	OT: Target ignored on input and set to opaque on output.
	For blending, alphas are in [0 .. 1.0] and R, G, B color components are in [0 .. 255] */

EXPORT(sqInt) primBlendFillOnlyWPOT(void) {
	uint32_t resultGBits;
	uint8_t antiAliasAlphaBits;
	uint8_t edgesUpToThisPixel;
	sqInt pixelIndex;
	uint32_t optimizedOpaqueTargetWord;
	uint32_t resultRBits;
	sqInt displayX;
	uint8_t edgesThisPixel;
	uint32_t resultBBits;
	uint32_t optimizedOpaqueMorphIdWord;
	sqInt displayY;
	sqInt l;
	sqInt t;
	sqInt r;
	sqInt b;
	unsigned *aBitmap;
	unsigned *aWordArray;
	char *otherByteArray;
	char *anotherByteArray;

	l = interpreterProxy->stackIntegerValue(7);
	t = interpreterProxy->stackIntegerValue(6);
	r = interpreterProxy->stackIntegerValue(5);
	b = interpreterProxy->stackIntegerValue(4);
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(3)));
	aBitmap = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(3))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(2)));
	aWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(1)));
	otherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(0)));
	anotherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	targetBits = aBitmap;
	morphIds = aWordArray;
	edgeCountsWP = otherByteArray;

	/* Optimize most common case: Fully opaque fill color, inside fill, away from stroke (no anti aliasing), no clipping at this point. */

	alphaMaskWP = anotherByteArray;
	optimizedOpaqueTargetWord = 0;
	if (fillA == 1.0) {
		
			resultRBits = (uint32_t)(fillR + 0.5) << 16;
			resultGBits = (uint32_t)(fillG + 0.5) << 8;
			resultBBits = (uint32_t)(fillB + 0.5);;
		optimizedOpaqueTargetWord = ((0xFF000000U | resultRBits) | resultGBits) | resultBBits;
		if (clipCurrentMorph || (currentClipsSubmorphs)) {
			optimizedOpaqueMorphIdWord = (currentMorphId << 8) + 0x7F;
		} else {
			optimizedOpaqueMorphIdWord = currentMorphId << 8;
		}
	}
	for (displayY = t; displayY <= b; displayY += 1) {
		edgesUpToThisPixel = 0;
		pixelIndex = ((displayY * targetWidth) + l) - 1;
		for (displayX = l; displayX <= r; displayX += 1) {
			pixelIndex += 1;
			edgesThisPixel = edgeCountsWP[pixelIndex];
			if (!(edgesThisPixel == 0)) {
				edgeCountsWP[pixelIndex] = 0;
				;
				edgesUpToThisPixel += edgesThisPixel;
			}
			antiAliasAlphaBits = alphaMaskWP[pixelIndex];
			if (edgesUpToThisPixel == 0) {

				/* Still in the anti aliasing area, but outside the shape, strictly speaking. */

				if (!(antiAliasAlphaBits == 0)) {
					alphaMaskWP[pixelIndex] = 0;
					blendFillOnlyWPOTAtantiAliasAlphaByte(pixelIndex, antiAliasAlphaBits);
				}
			} else {

				/* Inside the shape */

				if ((optimizedOpaqueTargetWord != 0) && ((antiAliasAlphaBits == 0) && ((!clipCurrentMorph) || (((morphIds[pixelIndex]) & 0x7F) == 0x7F)))) {

					/* Optimize most common case: Fully opaque fill color, inside fill, away from stroke (no anti aliasing), no clipping at this point. */

					targetBits[pixelIndex] = optimizedOpaqueTargetWord;
					morphIds[pixelIndex] = optimizedOpaqueMorphIdWord;
				} else {
					if (!(antiAliasAlphaBits == 0)) {
						alphaMaskWP[pixelIndex] = 0;
					}
					antiAliasAlphaBits = 0x7F - antiAliasAlphaBits;
					blendFillOnlyWPOTAtantiAliasAlphaByte(pixelIndex, antiAliasAlphaBits);
				}
			}
		}
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(8);
	return null;
}


/*	Blends stroke color and fill color over background.
	Do an appropriate (anti aliased) gradient between stoke color and fill color (or pick just stroke or just fill). Blend this over background.
	Target translucency computed correctly.
	For blending, alphas are in [0 .. 1.0] and R, G, B color components are in [0 .. 255] */

static sqInt blendStrokeAndFillAtredIsInsidegreenIsInsideblueIsInsideantiAliasAlphasWord(sqInt pixelIndex, sqInt isRedInside, sqInt isGreenInside, sqInt isBlueInside, uint32_t antiAliasAlphasWord) {
	float foreB;
	uint32_t resultGBits;
	uint32_t antiAliasGreenAlphaBits;
	float antiAliasGreenAlpha;
	uint32_t antiAliasRedAlphaBits;
	float unAlphaR;
	float clippingAntiAlias;
	uint32_t antiAliasBlueAlphaBits;
	float unAlphaB;
	float resultAlphaG;
	uint32_t clippingAntiAliasBits;
	float resultR;
	float resultB;
	uint32_t resultAlphaBits;
	uint32_t resultRBits;
	float alphaG;
	float foreG;
	float antiAliasBlueAlpha;
	uint32_t morphIdWord;
	float targetAlpha;
	float resultAlphaR;
	uint32_t resultBBits;
	float resultAlphaB;
	uint32_t antiAliasGreenAlphaBitsShifted;
	float unAlphaG;
	uint32_t targetWord;
	float alphaR;
	float antiAliasRedAlpha;
	float resultG;
	float foreR;
	float alphaB;

	antiAliasRedAlphaBits = antiAliasAlphasWord & 0x7F0000;
	antiAliasGreenAlphaBits = antiAliasAlphasWord & 0x7F00;
	antiAliasBlueAlphaBits = antiAliasAlphasWord & 0x7F;
	antiAliasRedAlpha = antiAliasRedAlphaBits * (1.0 / ((127.0 * 256) * 256));
	antiAliasGreenAlpha = antiAliasGreenAlphaBits * (1.0 / (127.0 * 256));
	antiAliasBlueAlpha = antiAliasBlueAlphaBits * (1.0 / 127.0);
	if (isRedInside) {

		/* Do gradient between stroke and fill. Blend the result over background */

		alphaR = (antiAliasRedAlpha * strokeA) + ((1.0 - antiAliasRedAlpha) * fillA);
		foreR = (antiAliasRedAlpha * strokeR) + ((1.0 - antiAliasRedAlpha) * fillR);
	} else {

		/* Blend stroke over background */

		alphaR = antiAliasRedAlpha * strokeA;
		foreR = strokeR;
	}
	if (isGreenInside) {

		/* Do gradient between stroke and fill. Blend the result over background */

		alphaG = (antiAliasGreenAlpha * strokeA) + ((1.0 - antiAliasGreenAlpha) * fillA);
		foreG = (antiAliasGreenAlpha * strokeG) + ((1.0 - antiAliasGreenAlpha) * fillG);
	} else {

		/* Blend stroke over background */

		alphaG = antiAliasGreenAlpha * strokeA;
		foreG = strokeG;
	}
	if (isBlueInside) {

		/* Do gradient between stroke and fill. Blend the result over background */

		alphaB = (antiAliasBlueAlpha * strokeA) + ((1.0 - antiAliasBlueAlpha) * fillA);
		foreB = (antiAliasBlueAlpha * strokeB) + ((1.0 - antiAliasBlueAlpha) * fillB);
	} else {

		/* Blend stroke over background */

		alphaB = antiAliasBlueAlpha * strokeA;
		foreB = strokeB;
	}
	if (currentClipsSubmorphs) {

		/* Don't clip us, but do clip submorphs */

		if (isGreenInside) {
			clippingAntiAliasBits = 0x7F;
		} else {
			morphIdWord = morphIds[pixelIndex];
			clippingAntiAliasBits = morphIdWord & 0x7F;
			
							antiAliasGreenAlphaBitsShifted = antiAliasGreenAlphaBits >> 8;;
			if (antiAliasGreenAlphaBitsShifted > clippingAntiAliasBits) {
				clippingAntiAliasBits = antiAliasGreenAlphaBitsShifted;
			}
		}
	} else {
		if (clipCurrentMorph) {

			/* Clip ourselves to the border anti aliasing of the morph we are clipping at. Keep it for further use. */

			morphIdWord = morphIds[pixelIndex];
			clippingAntiAliasBits = morphIdWord & 0x7F;
			clippingAntiAlias = clippingAntiAliasBits * (1.0 / 127.0);
			alphaR = alphaR * clippingAntiAlias;
			alphaG = alphaG * clippingAntiAlias;
			alphaB = alphaB * clippingAntiAlias;
		} else {

			/* Don't do any additional clipping or preparation for further clipping */

			clippingAntiAliasBits = 0;
		}
	}
	if (!(((alphaR + alphaG) + alphaB) == 0.0)) {
		targetWord = targetBits[pixelIndex];
		resultAlphaBits = targetWord & 0xFF000000U;
		resultRBits = targetWord & 0xFF0000;
		resultGBits = targetWord & 0xFF00;
		resultBBits = targetWord & 0xFF;

		/* These if are not really needed. just ignore them if we use simd instructions. */

		targetAlpha = resultAlphaBits * (1.0 / (((255.0 * 256) * 256) * 256));
		if (!(alphaR == 0.0)) {
			unAlphaR = 1.0 - alphaR;
			resultAlphaR = alphaR + (unAlphaR * targetAlpha);
			
					resultR = (alphaR * foreR) + ((unAlphaR * (resultRBits >> 16)) * targetAlpha);
					resultRBits = (uint32_t)(resultR / resultAlphaR + 0.5) << 16;;
		}
		if (!(alphaG == 0.0)) {
			unAlphaG = 1.0 - alphaG;
			resultAlphaG = alphaG + (unAlphaG * targetAlpha);
			
					resultG = (alphaG * foreG) + ((unAlphaG * (resultGBits >> 8)) * targetAlpha);
					resultGBits = (uint32_t)(resultG / resultAlphaG + 0.5) << 8;
					resultAlphaBits = (uint32_t)(resultAlphaG * 255.0 + 0.5) << 24;;
		}
		if (!(alphaB == 0.0)) {
			unAlphaB = 1.0 - alphaB;
			resultAlphaB = alphaB + (unAlphaB * targetAlpha);
			
					resultB = (alphaB * foreB) + ((unAlphaB * resultBBits) * targetAlpha);
					resultBBits = (uint32_t)(resultB / resultAlphaB + 0.5);;
		}
		targetWord = ((resultAlphaBits | resultRBits) | resultGBits) | resultBBits;
		targetBits[pixelIndex] = targetWord;
		morphIdWord = (currentMorphId << 8) + clippingAntiAliasBits;
		morphIds[pixelIndex] = morphIdWord;
	}
	return null;
}


/*	Inside the shape: Do an appropriate (anti aliased) gradient between stoke color and fill color (or pick just stroke or just fill).
	Blend this over background.
	WP: Whole pixel anti aliasing.
	OT: Target ignored on input and set to opaque on output.
	For blending, alphas are in [0 .. 1.0] and R, G, B color components are in [0 .. 255] */

static sqInt blendStrokeAndFillInsideWPOTAtantiAliasAlphaByte(sqInt pixelIndex, uint8_t antiAliasAlphaBits) {
	float foreB;
	uint32_t resultGBits;
	float unAlpha;
	float clippingAntiAlias;
	uint32_t clippingAntiAliasBits;
	float resultR;
	float resultB;
	uint32_t resultRBits;
	float antiAliasUnAlpha;
	float antiAliasAlpha;
	float foreG;
	uint32_t morphIdWord;
	uint32_t resultBBits;
	float alpha;
	uint32_t targetWord;
	float foreR;
	float resultG;


	/* 1.0/127.0 */

	antiAliasAlpha = antiAliasAlphaBits * 0.007874;

	/* We are inside the shape */

	antiAliasUnAlpha = 1.0 - antiAliasAlpha;
	alpha = (antiAliasAlpha * strokeA) + (antiAliasUnAlpha * fillA);
	foreR = (antiAliasAlpha * strokeR) + (antiAliasUnAlpha * fillR);
	foreG = (antiAliasAlpha * strokeG) + (antiAliasUnAlpha * fillG);
	foreB = (antiAliasAlpha * strokeB) + (antiAliasUnAlpha * fillB);
	if (currentClipsSubmorphs) {

		/* Don't clip us, but do clip submorphs */
		/* We are inside the shape */

		clippingAntiAliasBits = 0x7F;
	} else {
		if (clipCurrentMorph) {

			/* Clip ourselves to the border anti aliasing of the morph we are clipping at. Keep it for further use. */

			morphIdWord = morphIds[pixelIndex];
			clippingAntiAliasBits = morphIdWord & 0x7F;

			/* 1.0/127.0 */

			clippingAntiAlias = clippingAntiAliasBits * 0.007874;
			alpha = alpha * clippingAntiAlias;
		} else {

			/* Don't do any additional clipping or preparation for further clipping */

			clippingAntiAliasBits = 0;
		}
	}
	if (!(alpha == 0.0)) {
		targetWord = targetBits[pixelIndex];
		resultRBits = targetWord & 0xFF0000;
		resultGBits = targetWord & 0xFF00;
		resultBBits = targetWord & 0xFF;
		unAlpha = 1.0 - alpha;
		
				resultR = (alpha * foreR) + (unAlpha * (resultRBits >> 16));
				resultRBits = (uint32_t)(resultR + 0.5) << 16;
				resultG = (alpha * foreG) + (unAlpha * (resultGBits >> 8));
				resultGBits = (uint32_t)(resultG + 0.5) << 8;
				resultB = (alpha * foreB) + (unAlpha * resultBBits);
				resultBBits = (uint32_t)(resultB + 0.5);;
		targetWord = ((0xFF000000U | resultRBits) | resultGBits) | resultBBits;
		targetBits[pixelIndex] = targetWord;
		morphIdWord = (currentMorphId << 8) + clippingAntiAliasBits;
		morphIds[pixelIndex] = morphIdWord;
	}
	return null;
}


/*	Blends stroke color and fill color over background.
	Do an appropriate (anti aliased) gradient between stoke color and fill color (or pick just stroke or just fill). Blend this over background.
	Target translucency computed correctly.
	For blending, alphas are in [0 .. 1.0] and R, G, B color components are in [0 .. 255] */

EXPORT(sqInt) primBlendStrokeAndFill(void) {
	uint8_t edgesUpToThisPixelR;
	uint8_t edgesUpToThisPixelB;
	uint8_t edgesThisPixelG;
	sqInt pixelIndex;
	uint32_t edgesThisPixelWord;
	sqInt isRedInside;
	sqInt isBlueInside;
	uint8_t edgesThisPixelR;
	uint8_t edgesUpToThisPixelG;
	uint8_t edgesThisPixelB;
	sqInt isGreenInside;
	sqInt displayX;
	uint32_t antiAliasAlphasWord;
	sqInt displayY;
	sqInt l;
	sqInt t;
	sqInt r;
	sqInt b;
	unsigned *aBitmap;
	unsigned *aWordArray;
	unsigned *otherWordArray;
	unsigned *anotherWordArray;

	l = interpreterProxy->stackIntegerValue(7);
	t = interpreterProxy->stackIntegerValue(6);
	r = interpreterProxy->stackIntegerValue(5);
	b = interpreterProxy->stackIntegerValue(4);
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(3)));
	aBitmap = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(3))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(2)));
	aWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(1)));
	otherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(0)));
	anotherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	targetBits = aBitmap;
	morphIds = aWordArray;
	edgeCounts = otherWordArray;
	alphaMask = anotherWordArray;
	for (displayY = t; displayY <= b; displayY += 1) {
		edgesUpToThisPixelR = 0;
		edgesUpToThisPixelG = 0;
		edgesUpToThisPixelB = 0;
		pixelIndex = ((displayY * targetWidth) + l) - 1;
		for (displayX = l; displayX <= r; displayX += 1) {
			pixelIndex += 1;
			edgesThisPixelWord = edgeCounts[pixelIndex];
			if (!(edgesThisPixelWord == 0)) {
				edgeCounts[pixelIndex] = 0;
			}
			
					edgesThisPixelR = (uint32_t) (edgesThisPixelWord & 0xFF0000) >> 16;
					edgesThisPixelG = (uint32_t) (edgesThisPixelWord & 0xFF00) >> 8;
					edgesThisPixelB = (uint32_t) (edgesThisPixelWord & 0xFF);;
			edgesUpToThisPixelR += edgesThisPixelR;
			edgesUpToThisPixelG += edgesThisPixelG;

			/* In C, integers already behave like booleans */

			edgesUpToThisPixelB += edgesThisPixelB;
			
					isRedInside = edgesUpToThisPixelR;
					isGreenInside = edgesUpToThisPixelG;
					isBlueInside = edgesUpToThisPixelB;;
			antiAliasAlphasWord = alphaMask[pixelIndex];
			if (antiAliasAlphasWord != 0) {
				alphaMask[pixelIndex] = 0;
			}
			if ((antiAliasAlphasWord != 0) || (isRedInside || (isGreenInside || (isBlueInside)))) {
				blendStrokeAndFillAtredIsInsidegreenIsInsideblueIsInsideantiAliasAlphasWord(pixelIndex, isRedInside, isGreenInside, isBlueInside, antiAliasAlphasWord);
			}
		}
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(8);
	return null;
}


/*	Outside the shape, but still in the stroke: Blend stroke color over background.
	WP: Whole pixel anti aliasing.
	OT: Target ignored on input and set to opaque on output.
	For blending, alphas are in [0 .. 1.0] and R, G, B color components are in [0 .. 255] */

static sqInt blendStrokeAndFillOutsideWPOTAtantiAliasAlphaByte(sqInt pixelIndex, uint8_t antiAliasAlphaBits) {
	float foreB;
	uint32_t resultGBits;
	float unAlpha;
	float clippingAntiAlias;
	uint32_t clippingAntiAliasBits;
	float resultR;
	float resultB;
	uint32_t resultRBits;
	float antiAliasAlpha;
	float foreG;
	uint32_t morphIdWord;
	uint32_t resultBBits;
	float alpha;
	uint32_t targetWord;
	float foreR;
	float resultG;


	/* 1.0/127.0 */
	/* In the stroke, outside the shape */

	antiAliasAlpha = antiAliasAlphaBits * 0.007874;
	alpha = antiAliasAlpha * strokeA;
	foreR = strokeR;
	foreG = strokeG;
	foreB = strokeB;
	if (currentClipsSubmorphs) {

		/* Don't clip us, but do clip submorphs */

		morphIdWord = morphIds[pixelIndex];
		clippingAntiAliasBits = morphIdWord & 0x7F;
		if (antiAliasAlphaBits > clippingAntiAliasBits) {
			clippingAntiAliasBits = antiAliasAlphaBits;
		}
	} else {
		if (clipCurrentMorph) {

			/* Clip ourselves to the border anti aliasing of the morph we are clipping at. Keep it for further use. */

			morphIdWord = morphIds[pixelIndex];
			clippingAntiAliasBits = morphIdWord & 0x7F;

			/* 1.0/127.0 */

			clippingAntiAlias = clippingAntiAliasBits * 0.007874;
			alpha = alpha * clippingAntiAlias;
		} else {

			/* Don't do any additional clipping or preparation for further clipping */

			clippingAntiAliasBits = 0;
		}
	}
	if (!(alpha == 0.0)) {
		targetWord = targetBits[pixelIndex];
		resultRBits = targetWord & 0xFF0000;
		resultGBits = targetWord & 0xFF00;
		resultBBits = targetWord & 0xFF;
		unAlpha = 1.0 - alpha;
		
				resultR = (alpha * foreR) + (unAlpha * (resultRBits >> 16));
				resultRBits = (uint32_t)(resultR + 0.5) << 16;
				resultG = (alpha * foreG) + (unAlpha * (resultGBits >> 8));
				resultGBits = (uint32_t)(resultG + 0.5) << 8;
				resultB = (alpha * foreB) + (unAlpha * resultBBits);
				resultBBits = (uint32_t)(resultB + 0.5);;
		targetWord = ((0xFF000000U | resultRBits) | resultGBits) | resultBBits;
		targetBits[pixelIndex] = targetWord;
		morphIdWord = (currentMorphId << 8) + clippingAntiAliasBits;
		morphIds[pixelIndex] = morphIdWord;
	}
	return null;
}


/*	Blends stroke color and fill color over background.
	Do an appropriate (anti aliased) gradient between stoke color and fill color (or pick just stroke or just fill). Blend this over background.
	WP: Whole pixel anti aliasing.
	OT: Target ignored on input and set to opaque on output.
	For blending, alphas are in [0 .. 1.0] and R, G, B color components are in [0 .. 255] */

EXPORT(sqInt) primBlendStrokeAndFillWPOT(void) {
	uint32_t resultGBits;
	uint8_t antiAliasAlphaBits;
	uint8_t edgesUpToThisPixel;
	sqInt pixelIndex;
	uint32_t optimizedOpaqueTargetWord;
	uint32_t resultRBits;
	sqInt displayX;
	uint8_t edgesThisPixel;
	uint32_t resultBBits;
	uint32_t optimizedOpaqueMorphIdWord;
	sqInt displayY;
	sqInt l;
	sqInt t;
	sqInt r;
	sqInt b;
	unsigned *aBitmap;
	unsigned *aWordArray;
	char *otherByteArray;
	char *anotherByteArray;

	l = interpreterProxy->stackIntegerValue(7);
	t = interpreterProxy->stackIntegerValue(6);
	r = interpreterProxy->stackIntegerValue(5);
	b = interpreterProxy->stackIntegerValue(4);
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(3)));
	aBitmap = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(3))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(2)));
	aWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(1)));
	otherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(0)));
	anotherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	targetBits = aBitmap;
	morphIds = aWordArray;
	edgeCountsWP = otherByteArray;

	/* Optimize most common case: Fully opaque fill color, inside fill, away from stroke (no anti aliasing), no clipping at this point. */

	alphaMaskWP = anotherByteArray;
	optimizedOpaqueTargetWord = 0;
	if (fillA == 1.0) {
		
			resultRBits = (uint32_t)(fillR + 0.5) << 16;
			resultGBits = (uint32_t)(fillG + 0.5) << 8;
			resultBBits = (uint32_t)(fillB + 0.5);;
		optimizedOpaqueTargetWord = ((0xFF000000U | resultRBits) | resultGBits) | resultBBits;
		if (clipCurrentMorph || (currentClipsSubmorphs)) {
			optimizedOpaqueMorphIdWord = (currentMorphId << 8) + 0x7F;
		} else {
			optimizedOpaqueMorphIdWord = currentMorphId << 8;
		}
	}
	for (displayY = t; displayY <= b; displayY += 1) {
		edgesUpToThisPixel = 0;
		pixelIndex = ((displayY * targetWidth) + l) - 1;
		for (displayX = l; displayX <= r; displayX += 1) {
			pixelIndex += 1;
			edgesThisPixel = edgeCountsWP[pixelIndex];
			if (!(edgesThisPixel == 0)) {
				edgeCountsWP[pixelIndex] = 0;
				;
				edgesUpToThisPixel += edgesThisPixel;
			}
			antiAliasAlphaBits = alphaMaskWP[pixelIndex];
			if (edgesUpToThisPixel == 0) {

				/* Still in the stroke, but outside the shape, strictly speaking. */

				if (!(antiAliasAlphaBits == 0)) {
					alphaMaskWP[pixelIndex] = 0;
					if (!(antiAliasAlphaBits == 0)) {
						blendStrokeAndFillOutsideWPOTAtantiAliasAlphaByte(pixelIndex, antiAliasAlphaBits);
					}
				}
			} else {

				/* Inside the shape */

				if ((optimizedOpaqueTargetWord != 0) && ((antiAliasAlphaBits == 0) && ((!clipCurrentMorph) || (((morphIds[pixelIndex]) & 0x7F) == 0x7F)))) {

					/* Optimize most common case: Fully opaque fill color, inside fill, away from stroke (no anti aliasing), no clipping at this point. */

					targetBits[pixelIndex] = optimizedOpaqueTargetWord;
					morphIds[pixelIndex] = optimizedOpaqueMorphIdWord;
				} else {
					if (!(antiAliasAlphaBits == 0)) {
						alphaMaskWP[pixelIndex] = 0;
					}
					blendStrokeAndFillInsideWPOTAtantiAliasAlphaByte(pixelIndex, antiAliasAlphaBits);
				}
			}
		}
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(8);
	return null;
}


/*	Blends stroke color over background. Target translucency computed correctly.
	For blending, alphas are in [0 .. 1.0] and R, G, B color components are in [0 .. 255] */

static sqInt blendStrokeOnlyAtantiAliasAlphasWord(sqInt pixelIndex, uint32_t antiAliasAlphasWord) {
	uint32_t resultGBits;
	uint32_t antiAliasGreenAlphaBits;
	float antiAliasGreenAlpha;
	uint32_t antiAliasRedAlphaBits;
	float unAlphaR;
	float clippingAntiAlias;
	uint32_t antiAliasBlueAlphaBits;
	float unAlphaB;
	float resultAlphaG;
	uint32_t clippingAntiAliasBits;
	float resultR;
	float resultB;
	uint32_t resultAlphaBits;
	uint32_t resultRBits;
	float alphaG;
	float antiAliasBlueAlpha;
	uint32_t morphIdWord;
	float targetAlpha;
	float resultAlphaR;
	uint32_t resultBBits;
	float resultAlphaB;
	uint32_t antiAliasGreenAlphaBitsShifted;
	float unAlphaG;
	uint32_t targetWord;
	float alphaR;
	float antiAliasRedAlpha;
	float resultG;
	float alphaB;

	antiAliasRedAlphaBits = antiAliasAlphasWord & 0x7F0000;
	antiAliasGreenAlphaBits = antiAliasAlphasWord & 0x7F00;
	antiAliasBlueAlphaBits = antiAliasAlphasWord & 0x7F;
	antiAliasRedAlpha = antiAliasRedAlphaBits * (1.0 / ((127.0 * 256) * 256));
	antiAliasGreenAlpha = antiAliasGreenAlphaBits * (1.0 / (127.0 * 256));
	antiAliasBlueAlpha = antiAliasBlueAlphaBits * (1.0 / 127.0);
	alphaR = antiAliasRedAlpha * strokeA;
	alphaG = antiAliasGreenAlpha * strokeA;
	alphaB = antiAliasBlueAlpha * strokeA;
	if (currentClipsSubmorphs) {

		/* Don't clip us, but do clip submorphs */

		morphIdWord = morphIds[pixelIndex];
		clippingAntiAliasBits = morphIdWord & 0x7F;
		
					antiAliasGreenAlphaBitsShifted = antiAliasGreenAlphaBits >> 8;;
		if (antiAliasGreenAlphaBitsShifted > clippingAntiAliasBits) {
			clippingAntiAliasBits = antiAliasGreenAlphaBitsShifted;
		}
	} else {
		if (clipCurrentMorph) {

			/* Clip ourselves to the border anti aliasing of the morph we are clipping at. Keep it for further use. */

			morphIdWord = morphIds[pixelIndex];
			clippingAntiAliasBits = morphIdWord & 0x7F;
			clippingAntiAlias = clippingAntiAliasBits * (1.0 / 127.0);
			alphaR = alphaR * clippingAntiAlias;
			alphaG = alphaG * clippingAntiAlias;
			alphaB = alphaB * clippingAntiAlias;
		} else {

			/* Don't do any additional clipping or preparation for further clipping */

			clippingAntiAliasBits = 0;
		}
	}
	if (!(((alphaR + alphaG) + alphaB) == 0.0)) {
		targetWord = targetBits[pixelIndex];
		resultAlphaBits = targetWord & 0xFF000000U;
		resultRBits = targetWord & 0xFF0000;
		resultGBits = targetWord & 0xFF00;
		resultBBits = targetWord & 0xFF;

		/* These if are not really needed. just ignore them if we use simd instructions. */

		targetAlpha = resultAlphaBits * (1.0 / (((255.0 * 256) * 256) * 256));
		if (!(alphaR == 0.0)) {
			unAlphaR = 1.0 - alphaR;
			resultAlphaR = alphaR + (unAlphaR * targetAlpha);
			
					resultR = (alphaR * strokeR) + ((unAlphaR * (resultRBits >> 16)) * targetAlpha);
					resultRBits = (uint32_t)(resultR / resultAlphaR + 0.5) << 16;;
		}
		if (!(alphaG == 0.0)) {
			unAlphaG = 1.0 - alphaG;
			resultAlphaG = alphaG + (unAlphaG * targetAlpha);
			
					resultG = (alphaG * strokeG) + ((unAlphaG * (resultGBits >> 8)) * targetAlpha);
					resultGBits = (uint32_t)(resultG / resultAlphaG + 0.5) << 8;
					resultAlphaBits = (uint32_t)(resultAlphaG * 255.0 + 0.5) << 24;;
		}
		if (!(alphaB == 0.0)) {
			unAlphaB = 1.0 - alphaB;
			resultAlphaB = alphaB + (unAlphaB * targetAlpha);
			
					resultB = (alphaB * strokeB) + ((unAlphaB * resultBBits) * targetAlpha);
					resultBBits = (uint32_t)(resultB / resultAlphaB + 0.5);;
		}
		targetWord = ((resultAlphaBits | resultRBits) | resultGBits) | resultBBits;
		targetBits[pixelIndex] = targetWord;
		morphIdWord = (currentMorphId << 8) + clippingAntiAliasBits;
		morphIds[pixelIndex] = morphIdWord;
	}
	return null;
}


/*	Blends stroke color over background. Target translucency computed correctly.
	For blending, alphas are in [0 .. 1.0] and R, G, B color components are in [0 .. 255] */

EXPORT(sqInt) primBlendStrokeOnly(void) {
	sqInt pixelIndex;
	sqInt displayX;
	uint32_t antiAliasAlphasWord;
	sqInt displayY;
	sqInt l;
	sqInt t;
	sqInt r;
	sqInt b;
	unsigned *aBitmap;
	unsigned *aWordArray;
	unsigned *anotherWordArray;

	l = interpreterProxy->stackIntegerValue(6);
	t = interpreterProxy->stackIntegerValue(5);
	r = interpreterProxy->stackIntegerValue(4);
	b = interpreterProxy->stackIntegerValue(3);
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(2)));
	aBitmap = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(1)));
	aWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(0)));
	anotherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	targetBits = aBitmap;
	morphIds = aWordArray;
	alphaMask = anotherWordArray;
	for (displayY = t; displayY <= b; displayY += 1) {
		pixelIndex = ((displayY * targetWidth) + l) - 1;
		for (displayX = l; displayX <= r; displayX += 1) {
			pixelIndex += 1;
			antiAliasAlphasWord = alphaMask[pixelIndex];
			if (!(antiAliasAlphasWord == 0)) {
				alphaMask[pixelIndex] = 0;
				blendStrokeOnlyAtantiAliasAlphasWord(pixelIndex, antiAliasAlphasWord);
			}
		}
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(7);
	return null;
}


/*	Blends stroke color over background.
	WP: Whole pixel anti aliasing.
	OT: Target ignored on input and set to opaque on output.
	For blending, alphas are in [0 .. 1.0] and R, G, B color components are in [0 .. 255] */

static sqInt blendStrokeOnlyWPOTAtantiAliasAlphaByte(sqInt pixelIndex, uint8_t antiAliasAlphaBits) {
	uint32_t resultGBits;
	float unAlpha;
	float clippingAntiAlias;
	uint32_t clippingAntiAliasBits;
	float resultR;
	float resultB;
	uint32_t resultRBits;
	float antiAliasAlpha;
	uint32_t morphIdWord;
	uint32_t resultBBits;
	float alpha;
	uint32_t targetWord;
	float resultG;


	/* 1.0/127.0 */

	antiAliasAlpha = antiAliasAlphaBits * 0.007874;
	alpha = antiAliasAlpha * strokeA;
	if (currentClipsSubmorphs) {

		/* Don't clip us, but do clip submorphs */

		morphIdWord = morphIds[pixelIndex];
		clippingAntiAliasBits = morphIdWord & 0x7F;
		if (antiAliasAlphaBits > clippingAntiAliasBits) {
			clippingAntiAliasBits = antiAliasAlphaBits;
		}
	} else {
		if (clipCurrentMorph) {

			/* Clip ourselves to the border anti aliasing of the morph we are clipping at. Keep it for further use. */

			morphIdWord = morphIds[pixelIndex];
			clippingAntiAliasBits = morphIdWord & 0x7F;

			/* 1.0/127.0 */

			clippingAntiAlias = clippingAntiAliasBits * 0.007874;
			alpha = alpha * clippingAntiAlias;
		} else {

			/* Don't do any additional clipping or preparation for further clipping */

			clippingAntiAliasBits = 0;
		}
	}
	if (!(alpha == 0.0)) {
		targetWord = targetBits[pixelIndex];
		resultRBits = targetWord & 0xFF0000;
		resultGBits = targetWord & 0xFF00;
		resultBBits = targetWord & 0xFF;
		unAlpha = 1.0 - alpha;
		
				resultR = (alpha * strokeR) + (unAlpha * (resultRBits >> 16));
				resultRBits = (uint32_t)(resultR + 0.5) << 16;
				resultG = (alpha * strokeG) + (unAlpha * (resultGBits >> 8));
				resultGBits = (uint32_t)(resultG + 0.5) << 8;
				resultB = (alpha * strokeB) + (unAlpha * resultBBits);
				resultBBits = (uint32_t)(resultB + 0.5);;
		targetWord = ((0xFF000000U | resultRBits) | resultGBits) | resultBBits;
		targetBits[pixelIndex] = targetWord;
		morphIdWord = (currentMorphId << 8) + clippingAntiAliasBits;
		morphIds[pixelIndex] = morphIdWord;
	}
	return null;
}


/*	Blends stroke color over background.
	WP: Whole pixel anti aliasing.
	OT: Target ignored on input and set to opaque on output.
	For blending, alphas are in [0 .. 1.0] and R, G, B color components are in [0 .. 255] */

EXPORT(sqInt) primBlendStrokeOnlyWPOT(void) {
	uint32_t resultGBits;
	uint8_t antiAliasAlphaBits;
	sqInt pixelIndex;
	uint32_t optimizedOpaqueTargetWord;
	uint32_t resultRBits;
	sqInt displayX;
	uint32_t resultBBits;
	uint32_t optimizedOpaqueMorphIdWord;
	sqInt displayY;
	sqInt l;
	sqInt t;
	sqInt r;
	sqInt b;
	unsigned *aBitmap;
	unsigned *aWordArray;
	char *anotherByteArray;

	l = interpreterProxy->stackIntegerValue(6);
	t = interpreterProxy->stackIntegerValue(5);
	r = interpreterProxy->stackIntegerValue(4);
	b = interpreterProxy->stackIntegerValue(3);
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(2)));
	aBitmap = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(1)));
	aWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(0)));
	anotherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	targetBits = aBitmap;
	morphIds = aWordArray;

	/* Optimize inner part of a wide stroke: Fully opaque stroke color, inside stroke, away from stroke border (no anti aliasing), no clipping at this point. */

	alphaMaskWP = anotherByteArray;
	optimizedOpaqueTargetWord = 0;
	if (fillA == 1.0) {
		
			resultRBits = (uint32_t)(fillR + 0.5) << 16;
			resultGBits = (uint32_t)(fillG + 0.5) << 8;
			resultBBits = (uint32_t)(fillB + 0.5);;
		optimizedOpaqueTargetWord = ((0xFF000000U | resultRBits) | resultGBits) | resultBBits;
		if (clipCurrentMorph || (currentClipsSubmorphs)) {
			optimizedOpaqueMorphIdWord = (currentMorphId << 8) + 0x7F;
		} else {
			optimizedOpaqueMorphIdWord = currentMorphId << 8;
		}
	}
	for (displayY = t; displayY <= b; displayY += 1) {
		pixelIndex = ((displayY * targetWidth) + l) - 1;
		for (displayX = l; displayX <= r; displayX += 1) {
			pixelIndex += 1;
			antiAliasAlphaBits = alphaMaskWP[pixelIndex];
			if ((optimizedOpaqueTargetWord != 0) && ((antiAliasAlphaBits == 0x7F) && ((!clipCurrentMorph) || (((morphIds[pixelIndex]) & 0x7F) == 0x7F)))) {

				/* Optimize inner part of a wide stroke: Fully opaque stroke color, inside stroke, away from stroke border (no anti aliasing), no clipping at this point. */

				targetBits[pixelIndex] = optimizedOpaqueTargetWord;
				morphIds[pixelIndex] = optimizedOpaqueMorphIdWord;
			} else {
				if (!(antiAliasAlphaBits == 0)) {

					/* In the stroke */

					alphaMaskWP[pixelIndex] = 0;
					blendStrokeOnlyWPOTAtantiAliasAlphaByte(pixelIndex, antiAliasAlphaBits);
				}
			}
		}
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(7);
	return null;
}

EXPORT(sqInt) primClipCurrentMorph(void) {
	sqInt pixelIndex;
	sqInt displayX;
	sqInt displayY;
	sqInt aBoolean;
	unsigned *aWordArray;

	aBoolean = interpreterProxy->booleanValueOf(interpreterProxy->stackValue(1));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(0)));
	aWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	morphIds = aWordArray;
	if (clipCurrentMorph && (!aBoolean)) {
		for (displayY = clipTop; displayY <= clipBottom; displayY += 1) {
			pixelIndex = (displayY * targetWidth) + clipLeft;
			for (displayX = clipLeft; displayX <= clipRight; displayX += 1) {
				morphIds[pixelIndex] = ((morphIds[pixelIndex]) & 0xFFFFFF00U);
				pixelIndex += 1;
			}
		}
	}
	clipCurrentMorph = aBoolean;
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(2);
	return null;
}

EXPORT(sqInt) primClipLeftclipTopclipRightclipBottom(void) {
	sqInt l;
	sqInt t;
	sqInt r;
	sqInt b;

	l = interpreterProxy->stackIntegerValue(3);
	t = interpreterProxy->stackIntegerValue(2);
	r = interpreterProxy->stackIntegerValue(1);
	b = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	clipLeft = l;
	clipTop = t;
	clipRight = r;
	clipBottom = b;
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(4);
	return null;
}

EXPORT(sqInt) primCubicBezier(void) {
	double xFrom;
	double yFrom;
	double xTo;
	double yTo;
	double xControl1;
	double yControl1;
	double xControl2;
	double yControl2;
	unsigned *otherWordArray;
	unsigned *anotherWordArray;
	float *aFloat32Array;

	xFrom = interpreterProxy->stackFloatValue(10);
	yFrom = interpreterProxy->stackFloatValue(9);
	xTo = interpreterProxy->stackFloatValue(8);
	yTo = interpreterProxy->stackFloatValue(7);
	xControl1 = interpreterProxy->stackFloatValue(6);
	yControl1 = interpreterProxy->stackFloatValue(5);
	xControl2 = interpreterProxy->stackFloatValue(4);
	yControl2 = interpreterProxy->stackFloatValue(3);
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(2)));
	otherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(1)));
	anotherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	aFloat32Array = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	edgeCounts = otherWordArray;
	alphaMask = anotherWordArray;
	contour = aFloat32Array;
	pvt_cubicBezierFromXytoXycontrol1Xycontrol2Xy(xFrom, yFrom, xTo, yTo, xControl1, yControl1, xControl2, yControl2);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(11);
	return null;
}

EXPORT(sqInt) primCubicBezierWP(void) {
	double xFrom;
	double yFrom;
	double xTo;
	double yTo;
	double xControl1;
	double yControl1;
	double xControl2;
	double yControl2;
	char *otherByteArray;
	char *anotherByteArray;
	float *aFloat32Array;

	xFrom = interpreterProxy->stackFloatValue(10);
	yFrom = interpreterProxy->stackFloatValue(9);
	xTo = interpreterProxy->stackFloatValue(8);
	yTo = interpreterProxy->stackFloatValue(7);
	xControl1 = interpreterProxy->stackFloatValue(6);
	yControl1 = interpreterProxy->stackFloatValue(5);
	xControl2 = interpreterProxy->stackFloatValue(4);
	yControl2 = interpreterProxy->stackFloatValue(3);
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(2)));
	otherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(1)));
	anotherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	aFloat32Array = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	edgeCountsWP = otherByteArray;
	alphaMaskWP = anotherByteArray;
	contour = aFloat32Array;
	pvt_cubicBezierWPFromXytoXycontrol1Xycontrol2Xy(xFrom, yFrom, xTo, yTo, xControl1, yControl1, xControl2, yControl2);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(11);
	return null;
}


/*	Bound it someway to 31 or 32 bits (SmallInteger in 32 bits, or uint in 32 bits, etc...) */

EXPORT(sqInt) primCurrentMorphIdcurrentClipsSubmorphs(void) {
	sqInt aNumber;
	sqInt aBoolean;

	aNumber = interpreterProxy->stackIntegerValue(1);
	aBoolean = interpreterProxy->booleanValueOf(interpreterProxy->stackValue(0));
	if (interpreterProxy->failed()) {
		return null;
	}
	currentMorphId = aNumber;
	if (currentMorphId == 0) {
		clipCurrentMorph = 0;
	}
	currentClipsSubmorphs = aBoolean;
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(2);
	return null;
}

EXPORT(sqInt) primDisplayString(void) {
	float dx;
	float yMinEnd;
	float startY;
	float advanceWidth;
	float contourStartX;
	float f3;
	float increment;
	float xMaxEnd;
	float ttControlY;
	float ttEndY;
	float controlY;
	float startX;
	float endY;
	float f2;
	float length;
	float oneLessT;
	float ttControlX;
	float ttEndX;
	sqInt numBeziers;
	float controlX;
	float t0;
	sqInt i;
	float ttMoveToY;
	float endX;
	float correction;
	sqInt charIndex;
	float f1;
	float t;
	float xMinEnd;
	float x0;
	double answer;
	sqInt idx;
	float ttMoveToX;
	float y;
	float yMaxEnd;
	float y0;
	float nextGlyphY;
	uint8_t iso8859s15;
	float x;
	float dy;
	sqInt numContours;
	float contourStartY;
	float nextGlyphX;
	sqInt idx2;
	char *aString;
	sqInt startIndex;
	sqInt stopIndex;
	double destX;
	double destY;
	double sx;
	double sy;
	float *contourData;
	int *contourDataIndexes;
	sqInt aBoolean;
	unsigned *otherWordArray;
	unsigned *anotherWordArray;
	sqInt _return_value;

	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(11)));
	aString = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(11))));
	startIndex = interpreterProxy->stackIntegerValue(10);
	stopIndex = interpreterProxy->stackIntegerValue(9);
	destX = interpreterProxy->stackFloatValue(8);
	destY = interpreterProxy->stackFloatValue(7);
	sx = interpreterProxy->stackFloatValue(6);
	sy = interpreterProxy->stackFloatValue(5);
	contourData = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(4))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(3)));
	contourDataIndexes = ((int *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(3))));
	aBoolean = interpreterProxy->booleanValueOf(interpreterProxy->stackValue(2));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(1)));
	otherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(0)));
	anotherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	edgeCounts = otherWordArray;
	alphaMask = anotherWordArray;
	txA11 = txA11 * sx;
	txA12 = txA12 * sy;
	txA21 = txA21 * sx;
	txA22 = txA22 * sy;
	nextGlyphX = destX / sx;
	nextGlyphY = destY / sy;
	for (charIndex = (startIndex - 1); charIndex <= (stopIndex - 1); charIndex += 1) {
		iso8859s15 = aString[charIndex];;
		if (aBoolean) {
			if (iso8859s15 == 95) {
				iso8859s15 = 28;
			}
			if (iso8859s15 == 94) {
				iso8859s15 = 30;
			}
		}
		i = contourDataIndexes[iso8859s15];
		i -= 1;
		advanceWidth = contourData[i];
		i += 5;
		numContours = ((sqInt)(contourData[i]));
		i += 1;
		for (idx = 1; idx <= numContours; idx += 1) {
			numBeziers = ((sqInt)(contourData[i]));
			i += 1;
			ttMoveToX = (contourData[i]) + nextGlyphX;
			i += 1;
			ttMoveToY = (contourData[i]) + nextGlyphY;
			i += 1;
			startX = ((ttMoveToX * txA11) + (ttMoveToY * txA12)) + txA13;
			startY = ((ttMoveToX * txA21) + (ttMoveToY * txA22)) + txA23;
			contourStartX = startX;
			contourStartY = startY;
			/* begin initializeTrajectoryFragment */
			prevYTruncated = 0x7FFFFFFFU;
			for (idx2 = 1; idx2 <= numBeziers; idx2 += 1) {
				ttEndX = contourData[i];
				i += 1;
				ttEndY = contourData[i];
				i += 1;
				ttControlX = contourData[i];
				i += 1;
				ttControlY = contourData[i];
				i += 1;
				endX = ((ttEndX * txA11) + (ttEndY * txA12)) + startX;
				endY = ((ttEndX * txA21) + (ttEndY * txA22)) + startY;
				controlX = ((ttControlX * txA11) + (ttControlY * txA12)) + startX;

				/* This computed span of the Bezier curve is a bit pessimistic (larger than strict bounds), but safe. */

				controlY = ((ttControlX * txA21) + (ttControlY * txA22)) + startY;
				xMinEnd = ((startX < endX) ? startX : endX);
				xMaxEnd = ((startX < endX) ? endX : startX);
				yMinEnd = ((startY < endY) ? startY : endY);
				yMaxEnd = ((startY < endY) ? endY : startY);
				spanLeft = ((spanLeft < (((xMinEnd < ((xMinEnd + controlX) / 2.0)) ? xMinEnd : ((xMinEnd + controlX) / 2.0)))) ? spanLeft : (((xMinEnd < ((xMinEnd + controlX) / 2.0)) ? xMinEnd : ((xMinEnd + controlX) / 2.0))));
				spanRight = ((spanRight < (((xMaxEnd < ((xMaxEnd + controlX) / 2.0)) ? ((xMaxEnd + controlX) / 2.0) : xMaxEnd))) ? (((xMaxEnd < ((xMaxEnd + controlX) / 2.0)) ? ((xMaxEnd + controlX) / 2.0) : xMaxEnd)) : spanRight);
				spanTop = ((spanTop < (((yMinEnd < ((yMinEnd + controlY) / 2.0)) ? yMinEnd : ((yMinEnd + controlY) / 2.0)))) ? spanTop : (((yMinEnd < ((yMinEnd + controlY) / 2.0)) ? yMinEnd : ((yMinEnd + controlY) / 2.0))));

				/* Compute Quadratic Bezier Curve, */
				/* Case t = 0.0 */

				spanBottom = ((spanBottom < (((yMaxEnd < ((yMaxEnd + controlY) / 2.0)) ? ((yMaxEnd + controlY) / 2.0) : yMaxEnd))) ? (((yMaxEnd < ((yMaxEnd + controlY) / 2.0)) ? ((yMaxEnd + controlY) / 2.0) : yMaxEnd)) : spanBottom);
				x = startX;
				y = startY;
				updateAlphasForXy(x, y);
				updateEdgeCountAtXy(x, y);
				dx = fabs(endX-startX); dy = fabs(endY-startY);;
				increment = (((0.5 / (((dx < dy) ? dy : dx))) < 0.5) ? (0.5 / (((dx < dy) ? dy : dx))) : 0.5);
				t = 0.0;
							while (1) {
					t0 = t;
					x0 = x;

					/* Compute next point */

					y0 = y;
					t = t0 + increment;
					oneLessT = 1.0 - t;
					f1 = oneLessT * oneLessT;
					f2 = (2.0 * oneLessT) * t;
					f3 = t * t;
					x = ((f1 * startX) + (f2 * controlX)) + (f3 * endX);

					/* Now adjust the increment to aim at the required hop length, and recompute next point. */

					y = ((f1 * startY) + (f2 * controlY)) + (f3 * endY);
					dx = x - x0;
					dy = y - y0;
					
						length = sqrt(dx*dx + dy*dy);;
					correction = hop / length;
					do {
						increment = (increment / length) * hop;
						t = t0 + increment;
						oneLessT = 1.0 - t;
						f1 = oneLessT * oneLessT;
						f2 = (2.0 * oneLessT) * t;
						f3 = t * t;
						x = ((f1 * startX) + (f2 * controlX)) + (f3 * endX);
						y = ((f1 * startY) + (f2 * controlY)) + (f3 * endY);
						dx = x - x0;
						dy = y - y0;
						
							length = sqrt(dx*dx + dy*dy);;
						correction = hop / length;
					} while(correction < 1.0);
					if (!(t < 1.0)) break;
					updateAlphasForXy(x, y);
					updateEdgeCountAtXy(x, y);
				}
				startX = endX;
				startY = endY;
			}
			updateAlphasForXy(endX, endY);
			updateEdgeCountAtXy(endX, endY);
			updateEdgeCountAtXy(contourStartX, contourStartY);
		}
		nextGlyphX += advanceWidth;
	}
	txA11 = txA11 / sx;
	txA12 = txA12 / sy;
	txA21 = txA21 / sx;
	txA22 = txA22 / sy;
	answer = nextGlyphX * sx;
	_return_value = interpreterProxy->floatObjectOf(answer);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(13, _return_value);
	return null;
}

EXPORT(sqInt) primDisplayStringWP(void) {
	float dx;
	float yMinEnd;
	float startY;
	float advanceWidth;
	float contourStartX;
	float f3;
	float increment;
	float xMaxEnd;
	float ttControlY;
	float ttEndY;
	float controlY;
	float startX;
	float endY;
	float f2;
	float length;
	float oneLessT;
	float ttControlX;
	float ttEndX;
	sqInt numBeziers;
	float controlX;
	float t0;
	sqInt i;
	float correction;
	float ttMoveToY;
	float endX;
	sqInt charIndex;
	float f1;
	float t;
	float xMinEnd;
	float x0;
	double answer;
	sqInt idx;
	float ttMoveToX;
	float y;
	float yMaxEnd;
	float y0;
	float nextGlyphY;
	uint8_t iso8859s15;
	float x;
	float dy;
	sqInt numContours;
	float contourStartY;
	float nextGlyphX;
	sqInt idx2;
	char *aString;
	sqInt startIndex;
	sqInt stopIndex;
	double destX;
	double destY;
	double sx;
	double sy;
	float *contourData;
	int *contourDataIndexes;
	sqInt aBoolean;
	char *otherByteArray;
	char *anotherByteArray;
	sqInt _return_value;

	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(11)));
	aString = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(11))));
	startIndex = interpreterProxy->stackIntegerValue(10);
	stopIndex = interpreterProxy->stackIntegerValue(9);
	destX = interpreterProxy->stackFloatValue(8);
	destY = interpreterProxy->stackFloatValue(7);
	sx = interpreterProxy->stackFloatValue(6);
	sy = interpreterProxy->stackFloatValue(5);
	contourData = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(4))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(3)));
	contourDataIndexes = ((int *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(3))));
	aBoolean = interpreterProxy->booleanValueOf(interpreterProxy->stackValue(2));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(1)));
	otherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(0)));
	anotherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	edgeCountsWP = otherByteArray;
	alphaMaskWP = anotherByteArray;
	txA11 = txA11 * sx;
	txA12 = txA12 * sy;
	txA21 = txA21 * sx;
	txA22 = txA22 * sy;
	nextGlyphX = destX / sx;
	nextGlyphY = destY / sy;
	for (charIndex = (startIndex - 1); charIndex <= (stopIndex - 1); charIndex += 1) {
		iso8859s15 = aString[charIndex];;
		if (aBoolean) {
			if (iso8859s15 == 95) {
				iso8859s15 = 28;
			}
			if (iso8859s15 == 94) {
				iso8859s15 = 30;
			}
		}
		i = contourDataIndexes[iso8859s15];
		i -= 1;
		advanceWidth = contourData[i];
		i += 5;
		numContours = ((sqInt)(contourData[i]));
		i += 1;
		for (idx = 1; idx <= numContours; idx += 1) {
			numBeziers = ((sqInt)(contourData[i]));
			i += 1;
			ttMoveToX = (contourData[i]) + nextGlyphX;
			i += 1;
			ttMoveToY = (contourData[i]) + nextGlyphY;
			i += 1;
			startX = ((ttMoveToX * txA11) + (ttMoveToY * txA12)) + txA13;
			startY = ((ttMoveToX * txA21) + (ttMoveToY * txA22)) + txA23;
			contourStartX = startX;
			contourStartY = startY;
			/* begin initializeTrajectoryFragment */
			prevYTruncated = 0x7FFFFFFFU;
			for (idx2 = 1; idx2 <= numBeziers; idx2 += 1) {
				ttEndX = contourData[i];
				i += 1;
				ttEndY = contourData[i];
				i += 1;
				ttControlX = contourData[i];
				i += 1;
				ttControlY = contourData[i];
				i += 1;
				endX = ((ttEndX * txA11) + (ttEndY * txA12)) + startX;
				endY = ((ttEndX * txA21) + (ttEndY * txA22)) + startY;
				controlX = ((ttControlX * txA11) + (ttControlY * txA12)) + startX;

				/* This computed span of the Bezier curve is a bit pessimistic (larger than strict bounds), but safe. */

				controlY = ((ttControlX * txA21) + (ttControlY * txA22)) + startY;
				xMinEnd = ((startX < endX) ? startX : endX);
				xMaxEnd = ((startX < endX) ? endX : startX);
				yMinEnd = ((startY < endY) ? startY : endY);
				yMaxEnd = ((startY < endY) ? endY : startY);
				spanLeft = ((spanLeft < (((xMinEnd < ((xMinEnd + controlX) / 2.0)) ? xMinEnd : ((xMinEnd + controlX) / 2.0)))) ? spanLeft : (((xMinEnd < ((xMinEnd + controlX) / 2.0)) ? xMinEnd : ((xMinEnd + controlX) / 2.0))));
				spanRight = ((spanRight < (((xMaxEnd < ((xMaxEnd + controlX) / 2.0)) ? ((xMaxEnd + controlX) / 2.0) : xMaxEnd))) ? (((xMaxEnd < ((xMaxEnd + controlX) / 2.0)) ? ((xMaxEnd + controlX) / 2.0) : xMaxEnd)) : spanRight);
				spanTop = ((spanTop < (((yMinEnd < ((yMinEnd + controlY) / 2.0)) ? yMinEnd : ((yMinEnd + controlY) / 2.0)))) ? spanTop : (((yMinEnd < ((yMinEnd + controlY) / 2.0)) ? yMinEnd : ((yMinEnd + controlY) / 2.0))));

				/* Compute Quadratic Bezier Curve, */
				/* Case t = 0.0 */

				spanBottom = ((spanBottom < (((yMaxEnd < ((yMaxEnd + controlY) / 2.0)) ? ((yMaxEnd + controlY) / 2.0) : yMaxEnd))) ? (((yMaxEnd < ((yMaxEnd + controlY) / 2.0)) ? ((yMaxEnd + controlY) / 2.0) : yMaxEnd)) : spanBottom);
				x = startX;
				y = startY;
				updateAlphasWPZeroStrokeForXy(x, y);
				updateEdgeCountWPAtXy(x, y);
				dx = fabs(endX-startX); dy = fabs(endY-startY);;
				increment = (((0.5 / (((dx < dy) ? dy : dx))) < 0.5) ? (0.5 / (((dx < dy) ? dy : dx))) : 0.5);
				t = 0.0;
							while (1) {
					t0 = t;
					x0 = x;

					/* Compute next point */

					y0 = y;
					t = t0 + increment;
					oneLessT = 1.0 - t;
					f1 = oneLessT * oneLessT;
					f2 = (2.0 * oneLessT) * t;
					f3 = t * t;
					x = ((f1 * startX) + (f2 * controlX)) + (f3 * endX);

					/* Now adjust the increment to aim at the required hop length, and recompute next point. */

					y = ((f1 * startY) + (f2 * controlY)) + (f3 * endY);
					dx = x - x0;
					dy = y - y0;
					
						length = sqrt(dx*dx + dy*dy);;
					correction = hop / length;
					do {
						increment = (increment / length) * hop;
						t = t0 + increment;
						oneLessT = 1.0 - t;
						f1 = oneLessT * oneLessT;
						f2 = (2.0 * oneLessT) * t;
						f3 = t * t;
						x = ((f1 * startX) + (f2 * controlX)) + (f3 * endX);
						y = ((f1 * startY) + (f2 * controlY)) + (f3 * endY);
						dx = x - x0;
						dy = y - y0;
						
							length = sqrt(dx*dx + dy*dy);;
						correction = hop / length;
					} while(correction < 1.0);
					if (!(t < 1.0)) break;
					updateAlphasWPZeroStrokeForXy(x, y);
					updateEdgeCountWPAtXy(x, y);
				}
				startX = endX;
				startY = endY;
			}
			updateAlphasWPZeroStrokeForXy(endX, endY);
			updateEdgeCountWPAtXy(endX, endY);
			updateEdgeCountWPAtXy(contourStartX, contourStartY);
		}
		nextGlyphX += advanceWidth;
	}
	txA11 = txA11 / sx;
	txA12 = txA12 / sy;
	txA21 = txA21 / sx;
	txA22 = txA22 / sy;
	answer = nextGlyphX * sx;
	_return_value = interpreterProxy->floatObjectOf(answer);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(13, _return_value);
	return null;
}

EXPORT(sqInt) primDisplayUtf32(void) {
	float dx;
	float yMinEnd;
	float startY;
	float advanceWidth;
	float contourStartX;
	float f3;
	float increment;
	float xMaxEnd;
	float ttControlY;
	float ttEndY;
	float controlY;
	float startX;
	float endY;
	float f2;
	float length;
	float oneLessT;
	float ttControlX;
	float ttEndX;
	sqInt numBeziers;
	float controlX;
	float t0;
	sqInt i;
	float ttMoveToY;
	float endX;
	sqInt utf8Byte;
	float correction;
	float f1;
	float t;
	float xMinEnd;
	float x0;
	double answer;
	sqInt idx;
	float ttMoveToX;
	float y;
	sqInt utf32;
	float yMaxEnd;
	float y0;
	float nextGlyphY;
	float x;
	float dy;
	sqInt numContours;
	float contourStartY;
	float nextGlyphX;
	sqInt idx2;
	sqInt utf32Index;
	unsigned *aWordArray;
	sqInt startIndex;
	sqInt stopIndex;
	double destX;
	double destY;
	double sx;
	double sy;
	float *contourData;
	int *contourDataIndexes;
	sqInt aBoolean;
	unsigned *otherWordArray;
	unsigned *anotherWordArray;
	sqInt _return_value;

	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(11)));
	aWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(11))));
	startIndex = interpreterProxy->stackIntegerValue(10);
	stopIndex = interpreterProxy->stackIntegerValue(9);
	destX = interpreterProxy->stackFloatValue(8);
	destY = interpreterProxy->stackFloatValue(7);
	sx = interpreterProxy->stackFloatValue(6);
	sy = interpreterProxy->stackFloatValue(5);
	contourData = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(4))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(3)));
	contourDataIndexes = ((int *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(3))));
	aBoolean = interpreterProxy->booleanValueOf(interpreterProxy->stackValue(2));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(1)));
	otherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(0)));
	anotherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	edgeCounts = otherWordArray;
	alphaMask = anotherWordArray;
	txA11 = txA11 * sx;
	txA12 = txA12 * sy;
	txA21 = txA21 * sx;
	txA22 = txA22 * sy;
	nextGlyphX = destX / sx;
	nextGlyphY = destY / sy;
	for (utf32Index = (startIndex - 1); utf32Index <= (stopIndex - 1); utf32Index += 1) {
		utf32 = aWordArray[utf32Index];
		if (aBoolean) {
			if (utf32 == 95) {
				utf32 = 8592;
			}
			if (utf32 == 94) {
				utf32 = 8593;
			}
		}
		if (utf32 <= 0x7F) {
			utf8Byte = utf32;
			i = contourDataIndexes[utf8Byte];
		} else {
			if (utf32 <= 0x7FF) {
				utf8Byte = (((usqInt) utf32 >> 6)) | 192;
				i = contourDataIndexes[utf8Byte];
				utf8Byte = (utf32 & 0x3F) | 128;
				i = contourDataIndexes[utf8Byte - i];
			} else {
				if (utf32 <= 0xFFFF) {
					utf8Byte = (((usqInt) utf32 >> 12)) | 224;
					i = contourDataIndexes[utf8Byte];
					utf8Byte = ((((usqInt) utf32 >> 6)) & 0x3F) | 128;
					i = contourDataIndexes[utf8Byte - i];
					utf8Byte = (utf32 & 0x3F) | 128;
					i = contourDataIndexes[utf8Byte - i];
				} else {
					utf8Byte = (((usqInt) utf32 >> 18)) | 240;
					i = contourDataIndexes[utf8Byte];
					utf8Byte = ((((usqInt) utf32 >> 12)) & 0x3F) | 128;
					i = contourDataIndexes[utf8Byte - i];
					utf8Byte = ((((usqInt) utf32 >> 6)) & 0x3F) | 128;
					i = contourDataIndexes[utf8Byte - i];
					utf8Byte = (utf32 & 0x3F) | 128;
					i = contourDataIndexes[utf8Byte - i];
				}
			}
		}
		i -= 1;
		advanceWidth = contourData[i];
		i += 5;
		numContours = ((sqInt)(contourData[i]));
		i += 1;
		for (idx = 1; idx <= numContours; idx += 1) {
			numBeziers = ((sqInt)(contourData[i]));
			i += 1;
			ttMoveToX = (contourData[i]) + nextGlyphX;
			i += 1;
			ttMoveToY = (contourData[i]) + nextGlyphY;
			i += 1;
			startX = ((ttMoveToX * txA11) + (ttMoveToY * txA12)) + txA13;
			startY = ((ttMoveToX * txA21) + (ttMoveToY * txA22)) + txA23;
			contourStartX = startX;
			contourStartY = startY;
			/* begin initializeTrajectoryFragment */
			prevYTruncated = 0x7FFFFFFFU;
			for (idx2 = 1; idx2 <= numBeziers; idx2 += 1) {
				ttEndX = contourData[i];
				i += 1;
				ttEndY = contourData[i];
				i += 1;
				ttControlX = contourData[i];
				i += 1;
				ttControlY = contourData[i];
				i += 1;
				endX = ((ttEndX * txA11) + (ttEndY * txA12)) + startX;
				endY = ((ttEndX * txA21) + (ttEndY * txA22)) + startY;
				controlX = ((ttControlX * txA11) + (ttControlY * txA12)) + startX;

				/* This computed span of the Bezier curve is a bit pessimistic (larger than strict bounds), but safe. */

				controlY = ((ttControlX * txA21) + (ttControlY * txA22)) + startY;
				xMinEnd = ((startX < endX) ? startX : endX);
				xMaxEnd = ((startX < endX) ? endX : startX);
				yMinEnd = ((startY < endY) ? startY : endY);
				yMaxEnd = ((startY < endY) ? endY : startY);
				spanLeft = ((spanLeft < (((xMinEnd < ((xMinEnd + controlX) / 2.0)) ? xMinEnd : ((xMinEnd + controlX) / 2.0)))) ? spanLeft : (((xMinEnd < ((xMinEnd + controlX) / 2.0)) ? xMinEnd : ((xMinEnd + controlX) / 2.0))));
				spanRight = ((spanRight < (((xMaxEnd < ((xMaxEnd + controlX) / 2.0)) ? ((xMaxEnd + controlX) / 2.0) : xMaxEnd))) ? (((xMaxEnd < ((xMaxEnd + controlX) / 2.0)) ? ((xMaxEnd + controlX) / 2.0) : xMaxEnd)) : spanRight);
				spanTop = ((spanTop < (((yMinEnd < ((yMinEnd + controlY) / 2.0)) ? yMinEnd : ((yMinEnd + controlY) / 2.0)))) ? spanTop : (((yMinEnd < ((yMinEnd + controlY) / 2.0)) ? yMinEnd : ((yMinEnd + controlY) / 2.0))));

				/* Compute Quadratic Bezier Curve, */
				/* Case t = 0.0 */

				spanBottom = ((spanBottom < (((yMaxEnd < ((yMaxEnd + controlY) / 2.0)) ? ((yMaxEnd + controlY) / 2.0) : yMaxEnd))) ? (((yMaxEnd < ((yMaxEnd + controlY) / 2.0)) ? ((yMaxEnd + controlY) / 2.0) : yMaxEnd)) : spanBottom);
				x = startX;
				y = startY;
				updateAlphasForXy(x, y);
				updateEdgeCountAtXy(x, y);
				dx = fabs(endX-startX); dy = fabs(endY-startY);;
				increment = (((0.5 / (((dx < dy) ? dy : dx))) < 0.5) ? (0.5 / (((dx < dy) ? dy : dx))) : 0.5);
				t = 0.0;
							while (1) {
					t0 = t;
					x0 = x;

					/* Compute next point. Only C version to avoid hitting a limit in Smalltalk compiler. */

					y0 = y;
					
						t = t0 + increment; oneLessT = 1.0 - t;
						f1 = oneLessT * oneLessT; f2 = 2.0 * oneLessT * t; f3 = t * t;
						x = (f1 * startX) + (f2 * controlX) + (f3 * endX);
						y = (f1 * startY) + (f2 * controlY) + (f3 * endY);
						dx = x-x0; dy = y-y0;
						length = sqrt(dx*dx + dy*dy);;

					/* Now adjust the increment to aim at the required hop length, and recompute next point. */

					correction = hop / length;
					do {
						increment = (increment / length) * hop;
						t = t0 + increment;
						oneLessT = 1.0 - t;
						f1 = oneLessT * oneLessT;
						f2 = (2.0 * oneLessT) * t;
						f3 = t * t;
						x = ((f1 * startX) + (f2 * controlX)) + (f3 * endX);
						y = ((f1 * startY) + (f2 * controlY)) + (f3 * endY);
						dx = x - x0;
						dy = y - y0;
						
							length = sqrt(dx*dx + dy*dy);;
						correction = hop / length;
					} while(correction < 1.0);
					if (!(t < 1.0)) break;
					updateAlphasForXy(x, y);
					updateEdgeCountAtXy(x, y);
				}
				startX = endX;
				startY = endY;
			}
			updateAlphasForXy(endX, endY);
			updateEdgeCountAtXy(endX, endY);
			updateEdgeCountAtXy(contourStartX, contourStartY);
		}
		nextGlyphX += advanceWidth;
	}
	txA11 = txA11 / sx;
	txA12 = txA12 / sy;
	txA21 = txA21 / sx;
	txA22 = txA22 / sy;
	answer = nextGlyphX * sx;
	_return_value = interpreterProxy->floatObjectOf(answer);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(13, _return_value);
	return null;
}

EXPORT(sqInt) primDisplayUtf32WP(void) {
	float dx;
	float yMinEnd;
	float startY;
	float advanceWidth;
	float contourStartX;
	float f3;
	float increment;
	float xMaxEnd;
	float ttControlY;
	float ttEndY;
	float controlY;
	float startX;
	float endY;
	float f2;
	float length;
	float oneLessT;
	float ttControlX;
	float ttEndX;
	sqInt numBeziers;
	float controlX;
	float t0;
	sqInt i;
	float correction;
	float ttMoveToY;
	float endX;
	sqInt utf8Byte;
	float f1;
	float t;
	float xMinEnd;
	float x0;
	double answer;
	sqInt idx;
	float ttMoveToX;
	float y;
	sqInt utf32;
	float yMaxEnd;
	float y0;
	float nextGlyphY;
	float x;
	float dy;
	sqInt numContours;
	float contourStartY;
	float nextGlyphX;
	sqInt idx2;
	sqInt utf32Index;
	unsigned *aWordArray;
	sqInt startIndex;
	sqInt stopIndex;
	double destX;
	double destY;
	double sx;
	double sy;
	float *contourData;
	int *contourDataIndexes;
	sqInt aBoolean;
	char *otherByteArray;
	char *anotherByteArray;
	sqInt _return_value;

	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(11)));
	aWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(11))));
	startIndex = interpreterProxy->stackIntegerValue(10);
	stopIndex = interpreterProxy->stackIntegerValue(9);
	destX = interpreterProxy->stackFloatValue(8);
	destY = interpreterProxy->stackFloatValue(7);
	sx = interpreterProxy->stackFloatValue(6);
	sy = interpreterProxy->stackFloatValue(5);
	contourData = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(4))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(3)));
	contourDataIndexes = ((int *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(3))));
	aBoolean = interpreterProxy->booleanValueOf(interpreterProxy->stackValue(2));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(1)));
	otherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(0)));
	anotherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	edgeCountsWP = otherByteArray;
	alphaMaskWP = anotherByteArray;
	txA11 = txA11 * sx;
	txA12 = txA12 * sy;
	txA21 = txA21 * sx;
	txA22 = txA22 * sy;
	nextGlyphX = destX / sx;
	nextGlyphY = destY / sy;
	for (utf32Index = (startIndex - 1); utf32Index <= (stopIndex - 1); utf32Index += 1) {
		utf32 = aWordArray[utf32Index];
		if (aBoolean) {
			if (utf32 == 95) {
				utf32 = 8592;
			}
			if (utf32 == 94) {
				utf32 = 8593;
			}
		}
		if (utf32 <= 0x7F) {
			utf8Byte = utf32;
			i = contourDataIndexes[utf8Byte];
		} else {
			if (utf32 <= 0x7FF) {
				utf8Byte = (((usqInt) utf32 >> 6)) | 192;
				i = contourDataIndexes[utf8Byte];
				utf8Byte = (utf32 & 0x3F) | 128;
				i = contourDataIndexes[utf8Byte - i];
			} else {
				if (utf32 <= 0xFFFF) {
					utf8Byte = (((usqInt) utf32 >> 12)) | 224;
					i = contourDataIndexes[utf8Byte];
					utf8Byte = ((((usqInt) utf32 >> 6)) & 0x3F) | 128;
					i = contourDataIndexes[utf8Byte - i];
					utf8Byte = (utf32 & 0x3F) | 128;
					i = contourDataIndexes[utf8Byte - i];
				} else {
					utf8Byte = (((usqInt) utf32 >> 18)) | 240;
					i = contourDataIndexes[utf8Byte];
					utf8Byte = ((((usqInt) utf32 >> 12)) & 0x3F) | 128;
					i = contourDataIndexes[utf8Byte - i];
					utf8Byte = ((((usqInt) utf32 >> 6)) & 0x3F) | 128;
					i = contourDataIndexes[utf8Byte - i];
					utf8Byte = (utf32 & 0x3F) | 128;
					i = contourDataIndexes[utf8Byte - i];
				}
			}
		}
		i -= 1;
		advanceWidth = contourData[i];
		i += 5;
		numContours = ((sqInt)(contourData[i]));
		i += 1;
		for (idx = 1; idx <= numContours; idx += 1) {
			numBeziers = ((sqInt)(contourData[i]));
			i += 1;
			ttMoveToX = (contourData[i]) + nextGlyphX;
			i += 1;
			ttMoveToY = (contourData[i]) + nextGlyphY;
			i += 1;
			startX = ((ttMoveToX * txA11) + (ttMoveToY * txA12)) + txA13;
			startY = ((ttMoveToX * txA21) + (ttMoveToY * txA22)) + txA23;
			contourStartX = startX;
			contourStartY = startY;
			/* begin initializeTrajectoryFragment */
			prevYTruncated = 0x7FFFFFFFU;
			for (idx2 = 1; idx2 <= numBeziers; idx2 += 1) {
				ttEndX = contourData[i];
				i += 1;
				ttEndY = contourData[i];
				i += 1;
				ttControlX = contourData[i];
				i += 1;
				ttControlY = contourData[i];
				i += 1;
				endX = ((ttEndX * txA11) + (ttEndY * txA12)) + startX;
				endY = ((ttEndX * txA21) + (ttEndY * txA22)) + startY;
				controlX = ((ttControlX * txA11) + (ttControlY * txA12)) + startX;

				/* This computed span of the Bezier curve is a bit pessimistic (larger than strict bounds), but safe. */

				controlY = ((ttControlX * txA21) + (ttControlY * txA22)) + startY;
				xMinEnd = ((startX < endX) ? startX : endX);
				xMaxEnd = ((startX < endX) ? endX : startX);
				yMinEnd = ((startY < endY) ? startY : endY);
				yMaxEnd = ((startY < endY) ? endY : startY);
				spanLeft = ((spanLeft < (((xMinEnd < ((xMinEnd + controlX) / 2.0)) ? xMinEnd : ((xMinEnd + controlX) / 2.0)))) ? spanLeft : (((xMinEnd < ((xMinEnd + controlX) / 2.0)) ? xMinEnd : ((xMinEnd + controlX) / 2.0))));
				spanRight = ((spanRight < (((xMaxEnd < ((xMaxEnd + controlX) / 2.0)) ? ((xMaxEnd + controlX) / 2.0) : xMaxEnd))) ? (((xMaxEnd < ((xMaxEnd + controlX) / 2.0)) ? ((xMaxEnd + controlX) / 2.0) : xMaxEnd)) : spanRight);
				spanTop = ((spanTop < (((yMinEnd < ((yMinEnd + controlY) / 2.0)) ? yMinEnd : ((yMinEnd + controlY) / 2.0)))) ? spanTop : (((yMinEnd < ((yMinEnd + controlY) / 2.0)) ? yMinEnd : ((yMinEnd + controlY) / 2.0))));

				/* Compute Quadratic Bezier Curve, */
				/* Case t = 0.0 */

				spanBottom = ((spanBottom < (((yMaxEnd < ((yMaxEnd + controlY) / 2.0)) ? ((yMaxEnd + controlY) / 2.0) : yMaxEnd))) ? (((yMaxEnd < ((yMaxEnd + controlY) / 2.0)) ? ((yMaxEnd + controlY) / 2.0) : yMaxEnd)) : spanBottom);
				x = startX;
				y = startY;
				updateAlphasWPZeroStrokeForXy(x, y);
				updateEdgeCountWPAtXy(x, y);
				dx = fabs(endX-startX); dy = fabs(endY-startY);;
				increment = (((0.5 / (((dx < dy) ? dy : dx))) < 0.5) ? (0.5 / (((dx < dy) ? dy : dx))) : 0.5);
				t = 0.0;
							while (1) {
					t0 = t;
					x0 = x;

					/* Compute next point. Only C version to avoid hitting a limit in Smalltalk compiler. */

					y0 = y;
					
						t = t0 + increment; oneLessT = 1.0 - t;
						f1 = oneLessT * oneLessT; f2 = 2.0 * oneLessT * t; f3 = t * t;
						x = (f1 * startX) + (f2 * controlX) + (f3 * endX);
						y = (f1 * startY) + (f2 * controlY) + (f3 * endY);
						dx = x-x0; dy = y-y0;
						length = sqrt(dx*dx + dy*dy);;

					/* Now adjust the increment to aim at the required hop length, and recompute next point. */

					correction = hop / length;
					do {
						increment = (increment / length) * hop;
						t = t0 + increment;
						oneLessT = 1.0 - t;
						f1 = oneLessT * oneLessT;
						f2 = (2.0 * oneLessT) * t;
						f3 = t * t;
						x = ((f1 * startX) + (f2 * controlX)) + (f3 * endX);
						y = ((f1 * startY) + (f2 * controlY)) + (f3 * endY);
						dx = x - x0;
						dy = y - y0;
						
							length = sqrt(dx*dx + dy*dy);;
						correction = hop / length;
					} while(correction < 1.0);
					if (!(t < 1.0)) break;
					updateAlphasWPZeroStrokeForXy(x, y);
					updateEdgeCountWPAtXy(x, y);
				}
				startX = endX;
				startY = endY;
			}
			updateAlphasWPZeroStrokeForXy(endX, endY);
			updateEdgeCountWPAtXy(endX, endY);
			updateEdgeCountWPAtXy(contourStartX, contourStartY);
		}
		nextGlyphX += advanceWidth;
	}
	txA11 = txA11 / sx;
	txA12 = txA12 / sy;
	txA21 = txA21 / sx;
	txA22 = txA22 / sy;
	answer = nextGlyphX * sx;
	_return_value = interpreterProxy->floatObjectOf(answer);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(13, _return_value);
	return null;
}

EXPORT(sqInt) primDisplayUtf8(void) {
	float dx;
	float yMinEnd;
	float startY;
	float advanceWidth;
	float contourStartX;
	uint8_t byte;
	float f3;
	float increment;
	sqInt byteIndex;
	float xMaxEnd;
	float ttControlY;
	float ttEndY;
	float controlY;
	float startX;
	float endY;
	sqInt baseIndex;
	float f2;
	float length;
	float oneLessT;
	float ttControlX;
	float ttEndX;
	sqInt numBeziers;
	float controlX;
	float t0;
	sqInt i;
	float ttMoveToY;
	float endX;
	float correction;
	float f1;
	float t;
	float xMinEnd;
	float x0;
	double answer;
	sqInt idx;
	float ttMoveToX;
	float y;
	float yMaxEnd;
	float y0;
	float nextGlyphY;
	float x;
	float dy;
	sqInt numContours;
	float contourStartY;
	float nextGlyphX;
	sqInt idx2;
	char *aByteArray;
	sqInt byteStartIndex;
	sqInt byteStopIndex;
	double destX;
	double destY;
	double sx;
	double sy;
	float *contourData;
	int *contourDataIndexes;
	sqInt aBoolean;
	unsigned *otherWordArray;
	unsigned *anotherWordArray;
	sqInt _return_value;

	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(11)));
	aByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(11))));
	byteStartIndex = interpreterProxy->stackIntegerValue(10);
	byteStopIndex = interpreterProxy->stackIntegerValue(9);
	destX = interpreterProxy->stackFloatValue(8);
	destY = interpreterProxy->stackFloatValue(7);
	sx = interpreterProxy->stackFloatValue(6);
	sy = interpreterProxy->stackFloatValue(5);
	contourData = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(4))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(3)));
	contourDataIndexes = ((int *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(3))));
	aBoolean = interpreterProxy->booleanValueOf(interpreterProxy->stackValue(2));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(1)));
	otherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(0)));
	anotherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	edgeCounts = otherWordArray;
	alphaMask = anotherWordArray;
	txA11 = txA11 * sx;
	txA12 = txA12 * sy;
	txA21 = txA21 * sx;
	txA22 = txA22 * sy;
	nextGlyphX = destX / sx;
	nextGlyphY = destY / sy;
	baseIndex = 0;
	for (byteIndex = (byteStartIndex - 1); byteIndex <= (byteStopIndex - 1); byteIndex += 1) {
		byte = aByteArray[byteIndex];
		i = contourDataIndexes[baseIndex + byte];
		if (aBoolean) {
			if (byte == 95) {
				i = contourDataIndexes[226];
				i = contourDataIndexes[134 - i];
				i = contourDataIndexes[144 - i];
			}
			if (byte == 94) {
				i = contourDataIndexes[226];
				i = contourDataIndexes[134 - i];
				i = contourDataIndexes[145 - i];
			}
		}
		if (i < 0) {
			baseIndex = 0 - i;
		} else {
			i -= 1;
			advanceWidth = contourData[i];
			i += 5;
			numContours = ((sqInt)(contourData[i]));
			i += 1;
			for (idx = 1; idx <= numContours; idx += 1) {
				numBeziers = ((sqInt)(contourData[i]));
				i += 1;
				ttMoveToX = (contourData[i]) + nextGlyphX;
				i += 1;
				ttMoveToY = (contourData[i]) + nextGlyphY;
				i += 1;
				startX = ((ttMoveToX * txA11) + (ttMoveToY * txA12)) + txA13;
				startY = ((ttMoveToX * txA21) + (ttMoveToY * txA22)) + txA23;
				contourStartX = startX;
				contourStartY = startY;
				/* begin initializeTrajectoryFragment */
				prevYTruncated = 0x7FFFFFFFU;
				for (idx2 = 1; idx2 <= numBeziers; idx2 += 1) {
					ttEndX = contourData[i];
					i += 1;
					ttEndY = contourData[i];
					i += 1;
					ttControlX = contourData[i];
					i += 1;
					ttControlY = contourData[i];
					i += 1;
					endX = ((ttEndX * txA11) + (ttEndY * txA12)) + startX;
					endY = ((ttEndX * txA21) + (ttEndY * txA22)) + startY;
					controlX = ((ttControlX * txA11) + (ttControlY * txA12)) + startX;

					/* This computed span of the Bezier curve is a bit pessimistic (larger than strict bounds), but safe. */

					controlY = ((ttControlX * txA21) + (ttControlY * txA22)) + startY;
					xMinEnd = ((startX < endX) ? startX : endX);
					xMaxEnd = ((startX < endX) ? endX : startX);
					yMinEnd = ((startY < endY) ? startY : endY);
					yMaxEnd = ((startY < endY) ? endY : startY);
					spanLeft = ((spanLeft < (((xMinEnd < ((xMinEnd + controlX) / 2.0)) ? xMinEnd : ((xMinEnd + controlX) / 2.0)))) ? spanLeft : (((xMinEnd < ((xMinEnd + controlX) / 2.0)) ? xMinEnd : ((xMinEnd + controlX) / 2.0))));
					spanRight = ((spanRight < (((xMaxEnd < ((xMaxEnd + controlX) / 2.0)) ? ((xMaxEnd + controlX) / 2.0) : xMaxEnd))) ? (((xMaxEnd < ((xMaxEnd + controlX) / 2.0)) ? ((xMaxEnd + controlX) / 2.0) : xMaxEnd)) : spanRight);
					spanTop = ((spanTop < (((yMinEnd < ((yMinEnd + controlY) / 2.0)) ? yMinEnd : ((yMinEnd + controlY) / 2.0)))) ? spanTop : (((yMinEnd < ((yMinEnd + controlY) / 2.0)) ? yMinEnd : ((yMinEnd + controlY) / 2.0))));

					/* Case t = 0.0 */

					spanBottom = ((spanBottom < (((yMaxEnd < ((yMaxEnd + controlY) / 2.0)) ? ((yMaxEnd + controlY) / 2.0) : yMaxEnd))) ? (((yMaxEnd < ((yMaxEnd + controlY) / 2.0)) ? ((yMaxEnd + controlY) / 2.0) : yMaxEnd)) : spanBottom);
					x = startX;
					y = startY;
					updateAlphasForXy(x, y);
					updateEdgeCountAtXy(x, y);
					dx = fabs(endX-startX); dy = fabs(endY-startY);;

					/* Compute Quadratic Bezier Curve, */

					increment = (((0.5 / (((dx < dy) ? dy : dx))) < 0.5) ? (0.5 / (((dx < dy) ? dy : dx))) : 0.5);
					t = 0.0;
									while (1) {
						t0 = t;
						x0 = x;

						/* Compute next point */

						y0 = y;
						t = t0 + increment;
						oneLessT = 1.0 - t;
						f1 = oneLessT * oneLessT;
						f2 = (2.0 * oneLessT) * t;
						f3 = t * t;
						x = ((f1 * startX) + (f2 * controlX)) + (f3 * endX);

						/* Now adjust the increment to aim at the required hop length, and recompute next point. */

						y = ((f1 * startY) + (f2 * controlY)) + (f3 * endY);
						dx = x - x0;
						dy = y - y0;
						
								length = sqrt(dx*dx + dy*dy);;
						correction = hop / length;
						do {
							increment = (increment / length) * hop;
							t = t0 + increment;
							oneLessT = 1.0 - t;
							f1 = oneLessT * oneLessT;
							f2 = (2.0 * oneLessT) * t;
							f3 = t * t;
							x = ((f1 * startX) + (f2 * controlX)) + (f3 * endX);
							y = ((f1 * startY) + (f2 * controlY)) + (f3 * endY);
							dx = x - x0;
							dy = y - y0;
							
									length = sqrt(dx*dx + dy*dy);;
							correction = hop / length;
						} while(correction < 1.0);
						if (!(t < 1.0)) break;
						updateAlphasForXy(x, y);
						updateEdgeCountAtXy(x, y);
					}
					startX = endX;
					startY = endY;
				}
				updateAlphasForXy(endX, endY);
				updateEdgeCountAtXy(endX, endY);
				updateEdgeCountAtXy(contourStartX, contourStartY);
			}
			nextGlyphX += advanceWidth;
			baseIndex = 0;
		}
	}
	txA11 = txA11 / sx;
	txA12 = txA12 / sy;
	txA21 = txA21 / sx;
	txA22 = txA22 / sy;
	answer = nextGlyphX * sx;
	_return_value = interpreterProxy->floatObjectOf(answer);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(13, _return_value);
	return null;
}

EXPORT(sqInt) primDisplayUtf8WP(void) {
	float dx;
	float yMinEnd;
	float startY;
	float advanceWidth;
	float contourStartX;
	uint8_t byte;
	float f3;
	float increment;
	sqInt byteIndex;
	float xMaxEnd;
	float ttControlY;
	float ttEndY;
	float controlY;
	float startX;
	float endY;
	sqInt baseIndex;
	float f2;
	float length;
	float oneLessT;
	float ttControlX;
	float ttEndX;
	sqInt numBeziers;
	float controlX;
	float t0;
	sqInt i;
	float correction;
	float ttMoveToY;
	float endX;
	float f1;
	float t;
	float xMinEnd;
	float x0;
	double answer;
	sqInt idx;
	float ttMoveToX;
	float y;
	float yMaxEnd;
	float y0;
	float nextGlyphY;
	float x;
	float dy;
	sqInt numContours;
	float contourStartY;
	float nextGlyphX;
	sqInt idx2;
	char *aByteArray;
	sqInt byteStartIndex;
	sqInt byteStopIndex;
	double destX;
	double destY;
	double sx;
	double sy;
	float *contourData;
	int *contourDataIndexes;
	sqInt aBoolean;
	char *otherByteArray;
	char *anotherByteArray;
	sqInt _return_value;

	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(11)));
	aByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(11))));
	byteStartIndex = interpreterProxy->stackIntegerValue(10);
	byteStopIndex = interpreterProxy->stackIntegerValue(9);
	destX = interpreterProxy->stackFloatValue(8);
	destY = interpreterProxy->stackFloatValue(7);
	sx = interpreterProxy->stackFloatValue(6);
	sy = interpreterProxy->stackFloatValue(5);
	contourData = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(4))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(3)));
	contourDataIndexes = ((int *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(3))));
	aBoolean = interpreterProxy->booleanValueOf(interpreterProxy->stackValue(2));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(1)));
	otherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(0)));
	anotherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	edgeCountsWP = otherByteArray;
	alphaMaskWP = anotherByteArray;
	txA11 = txA11 * sx;
	txA12 = txA12 * sy;
	txA21 = txA21 * sx;
	txA22 = txA22 * sy;
	nextGlyphX = destX / sx;
	nextGlyphY = destY / sy;
	baseIndex = 0;
	for (byteIndex = (byteStartIndex - 1); byteIndex <= (byteStopIndex - 1); byteIndex += 1) {
		byte = aByteArray[byteIndex];
		i = contourDataIndexes[baseIndex + byte];
		if (aBoolean) {
			if (byte == 95) {
				i = contourDataIndexes[226];
				i = contourDataIndexes[134 - i];
				i = contourDataIndexes[144 - i];
			}
			if (byte == 94) {
				i = contourDataIndexes[226];
				i = contourDataIndexes[134 - i];
				i = contourDataIndexes[145 - i];
			}
		}
		if (i < 0) {
			baseIndex = 0 - i;
		} else {
			i -= 1;
			advanceWidth = contourData[i];
			i += 5;
			numContours = ((sqInt)(contourData[i]));
			i += 1;
			for (idx = 1; idx <= numContours; idx += 1) {
				numBeziers = ((sqInt)(contourData[i]));
				i += 1;
				ttMoveToX = (contourData[i]) + nextGlyphX;
				i += 1;
				ttMoveToY = (contourData[i]) + nextGlyphY;
				i += 1;
				startX = ((ttMoveToX * txA11) + (ttMoveToY * txA12)) + txA13;
				startY = ((ttMoveToX * txA21) + (ttMoveToY * txA22)) + txA23;
				contourStartX = startX;
				contourStartY = startY;
				/* begin initializeTrajectoryFragment */
				prevYTruncated = 0x7FFFFFFFU;
				for (idx2 = 1; idx2 <= numBeziers; idx2 += 1) {
					ttEndX = contourData[i];
					i += 1;
					ttEndY = contourData[i];
					i += 1;
					ttControlX = contourData[i];
					i += 1;
					ttControlY = contourData[i];
					i += 1;
					endX = ((ttEndX * txA11) + (ttEndY * txA12)) + startX;
					endY = ((ttEndX * txA21) + (ttEndY * txA22)) + startY;
					controlX = ((ttControlX * txA11) + (ttControlY * txA12)) + startX;

					/* This computed span of the Bezier curve is a bit pessimistic (larger than strict bounds), but safe. */

					controlY = ((ttControlX * txA21) + (ttControlY * txA22)) + startY;
					xMinEnd = ((startX < endX) ? startX : endX);
					xMaxEnd = ((startX < endX) ? endX : startX);
					yMinEnd = ((startY < endY) ? startY : endY);
					yMaxEnd = ((startY < endY) ? endY : startY);
					spanLeft = ((spanLeft < (((xMinEnd < ((xMinEnd + controlX) / 2.0)) ? xMinEnd : ((xMinEnd + controlX) / 2.0)))) ? spanLeft : (((xMinEnd < ((xMinEnd + controlX) / 2.0)) ? xMinEnd : ((xMinEnd + controlX) / 2.0))));
					spanRight = ((spanRight < (((xMaxEnd < ((xMaxEnd + controlX) / 2.0)) ? ((xMaxEnd + controlX) / 2.0) : xMaxEnd))) ? (((xMaxEnd < ((xMaxEnd + controlX) / 2.0)) ? ((xMaxEnd + controlX) / 2.0) : xMaxEnd)) : spanRight);
					spanTop = ((spanTop < (((yMinEnd < ((yMinEnd + controlY) / 2.0)) ? yMinEnd : ((yMinEnd + controlY) / 2.0)))) ? spanTop : (((yMinEnd < ((yMinEnd + controlY) / 2.0)) ? yMinEnd : ((yMinEnd + controlY) / 2.0))));

					/* Case t = 0.0 */

					spanBottom = ((spanBottom < (((yMaxEnd < ((yMaxEnd + controlY) / 2.0)) ? ((yMaxEnd + controlY) / 2.0) : yMaxEnd))) ? (((yMaxEnd < ((yMaxEnd + controlY) / 2.0)) ? ((yMaxEnd + controlY) / 2.0) : yMaxEnd)) : spanBottom);
					x = startX;
					y = startY;
					updateAlphasWPZeroStrokeForXy(x, y);
					updateEdgeCountWPAtXy(x, y);
					dx = fabs(endX-startX); dy = fabs(endY-startY);;

					/* Compute Quadratic Bezier Curve, */

					increment = (((0.5 / (((dx < dy) ? dy : dx))) < 0.5) ? (0.5 / (((dx < dy) ? dy : dx))) : 0.5);
					t = 0.0;
									while (1) {
						t0 = t;
						x0 = x;

						/* Compute next point */

						y0 = y;
						t = t0 + increment;
						oneLessT = 1.0 - t;
						f1 = oneLessT * oneLessT;
						f2 = (2.0 * oneLessT) * t;
						f3 = t * t;
						x = ((f1 * startX) + (f2 * controlX)) + (f3 * endX);

						/* Now adjust the increment to aim at the required hop length, and recompute next point. */

						y = ((f1 * startY) + (f2 * controlY)) + (f3 * endY);
						dx = x - x0;
						dy = y - y0;
						
								length = sqrt(dx*dx + dy*dy);;
						correction = hop / length;
						do {
							increment = (increment / length) * hop;
							t = t0 + increment;
							oneLessT = 1.0 - t;
							f1 = oneLessT * oneLessT;
							f2 = (2.0 * oneLessT) * t;
							f3 = t * t;
							x = ((f1 * startX) + (f2 * controlX)) + (f3 * endX);
							y = ((f1 * startY) + (f2 * controlY)) + (f3 * endY);
							dx = x - x0;
							dy = y - y0;
							
									length = sqrt(dx*dx + dy*dy);;
							correction = hop / length;
						} while(correction < 1.0);
						if (!(t < 1.0)) break;
						updateAlphasWPZeroStrokeForXy(x, y);
						updateEdgeCountWPAtXy(x, y);
					}
					startX = endX;
					startY = endY;
				}
				updateAlphasWPZeroStrokeForXy(endX, endY);
				updateEdgeCountWPAtXy(endX, endY);
				updateEdgeCountWPAtXy(contourStartX, contourStartY);
			}
			nextGlyphX += advanceWidth;
			baseIndex = 0;
		}
	}
	txA11 = txA11 / sx;
	txA12 = txA12 / sy;
	txA21 = txA21 / sx;
	txA22 = txA22 / sy;
	answer = nextGlyphX * sx;
	_return_value = interpreterProxy->floatObjectOf(answer);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(13, _return_value);
	return null;
}

EXPORT(sqInt) primFillRGBA(void) {
	double r;
	double g;
	double b;
	double a;

	r = interpreterProxy->stackFloatValue(3);
	g = interpreterProxy->stackFloatValue(2);
	b = interpreterProxy->stackFloatValue(1);
	a = interpreterProxy->stackFloatValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	fillR = r * 255.0;
	fillG = g * 255.0;
	fillB = b * 255.0;
	fillA = a;
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(4);
	return null;
}

EXPORT(sqInt) primGeometryTxSet(void) {
	double a11;
	double a12;
	double a13;
	double a21;
	double a22;
	double a23;

	a11 = interpreterProxy->stackFloatValue(5);
	a12 = interpreterProxy->stackFloatValue(4);
	a13 = interpreterProxy->stackFloatValue(3);
	a21 = interpreterProxy->stackFloatValue(2);
	a22 = interpreterProxy->stackFloatValue(1);
	a23 = interpreterProxy->stackFloatValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	txA11 = a11;
	txA12 = a12;
	txA13 = a13;
	txA21 = a21;
	txA22 = a22;
	txA23 = a23;
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(6);
	return null;
}


/*	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 halt(void) {
	;
	return null;
}

EXPORT(sqInt) primInitializePath(void) {

	/* drawable right. Will later be refined. */

	spanLeft = targetWidth;

	/* drawable bottom. Will later be refined. */

	spanTop = targetHeight;

	/* drawable left. Will later be refined. */

	spanRight = 0;

	/* drawable top. Will later be refined. */

	spanBottom = 0;
	prevYRounded = 0x7FFFFFFFU;
	if (interpreterProxy->failed()) {
		return null;
	}
	return null;
}

EXPORT(sqInt) primLine(void) {
	double xFrom;
	double yFrom;
	double xTo;
	double yTo;
	unsigned *otherWordArray;
	unsigned *anotherWordArray;
	float *aFloat32Array;

	xFrom = interpreterProxy->stackFloatValue(6);
	yFrom = interpreterProxy->stackFloatValue(5);
	xTo = interpreterProxy->stackFloatValue(4);
	yTo = interpreterProxy->stackFloatValue(3);
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(2)));
	otherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(1)));
	anotherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	aFloat32Array = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	edgeCounts = otherWordArray;
	alphaMask = anotherWordArray;
	contour = aFloat32Array;
	pvt_lineFromXytoXy(xFrom, yFrom, xTo, yTo);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(7);
	return null;
}

EXPORT(sqInt) primLineWP(void) {
	double xFrom;
	double yFrom;
	double xTo;
	double yTo;
	char *otherByteArray;
	char *anotherByteArray;
	float *aFloat32Array;

	xFrom = interpreterProxy->stackFloatValue(6);
	yFrom = interpreterProxy->stackFloatValue(5);
	xTo = interpreterProxy->stackFloatValue(4);
	yTo = interpreterProxy->stackFloatValue(3);
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(2)));
	otherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(1)));
	anotherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	aFloat32Array = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	edgeCountsWP = otherByteArray;
	alphaMaskWP = anotherByteArray;
	contour = aFloat32Array;
	pvt_lineWPFromXytoXy(xFrom, yFrom, xTo, yTo);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(7);
	return null;
}

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

	/* begin initializeTrajectoryFragment */
	prevYTruncated = 0x7FFFFFFFU;
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(1, _return_value);
	return null;
}

EXPORT(sqInt) primPathSequence(void) {
	float control1X;
	float endX;
	float control2X;
	float control1Y;
	float endY;
	float startX;
	sqInt i;
	float control2Y;
	sqInt commandType;
	float startY;
	float *aFloat32Array;
	sqInt size;
	unsigned *otherWordArray;
	unsigned *anotherWordArray;
	float *otherFloat32Array;

	aFloat32Array = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(4))));
	size = interpreterProxy->stackIntegerValue(3);
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(2)));
	otherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(1)));
	anotherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	otherFloat32Array = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	edgeCounts = otherWordArray;
	alphaMask = anotherWordArray;
	contour = otherFloat32Array;
	i = 0;
	while (i < size) {
		commandType = ((sqInt)(aFloat32Array[i]));
		i += 1;
		
		switch (commandType) {
		case 0:
						if (!((i + 1) < size)) {
				if (interpreterProxy->failed()) {
					return null;
				}
				interpreterProxy->pop(5);
				return null;
			}
			startX = aFloat32Array[i];
			i += 1;
			startY = aFloat32Array[i];
			i += 1;
			/* begin initializeTrajectoryFragment */
			prevYTruncated = 0x7FFFFFFFU;
			break;
		case 1:
						if (!((i + 1) < size)) {
				if (interpreterProxy->failed()) {
					return null;
				}
				interpreterProxy->pop(5);
				return null;
			}
			endX = aFloat32Array[i];
			i += 1;
			endY = aFloat32Array[i];
			i += 1;
			pvt_lineFromXytoXy(startX, startY, endX, endY);
			startX = endX;
			startY = endY;
			break;
		case 2:
						if (!((i + 3) < size)) {
				if (interpreterProxy->failed()) {
					return null;
				}
				interpreterProxy->pop(5);
				return null;
			}
			endX = aFloat32Array[i];
			i += 1;
			endY = aFloat32Array[i];
			i += 1;
			control1X = aFloat32Array[i];
			i += 1;
			control1Y = aFloat32Array[i];
			i += 1;
			pvt_quadraticBezierFromXytoXycontrolXy(startX, startY, endX, endY, control1X, control1Y);
			startX = endX;
			startY = endY;
			break;
		case 3:
						if (!((i + 5) < size)) {
				if (interpreterProxy->failed()) {
					return null;
				}
				interpreterProxy->pop(5);
				return null;
			}
			endX = aFloat32Array[i];
			i += 1;
			endY = aFloat32Array[i];
			i += 1;
			control1X = aFloat32Array[i];
			i += 1;
			control1Y = aFloat32Array[i];
			i += 1;
			control2X = aFloat32Array[i];
			i += 1;
			control2Y = aFloat32Array[i];
			i += 1;
			pvt_cubicBezierFromXytoXycontrol1Xycontrol2Xy(startX, startY, endX, endY, control1X, control1Y, control2X, control2Y);
			startX = endX;
			startY = endY;
			break;
		default:
						if (interpreterProxy->failed()) {
				return null;
			}
			interpreterProxy->pop(5);
			return null;

		}
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(5);
	return null;
}

EXPORT(sqInt) primPathSequenceWP(void) {
	float control1X;
	float endX;
	float control2X;
	float control1Y;
	float endY;
	float startX;
	sqInt i;
	float control2Y;
	sqInt commandType;
	float startY;
	float *aFloat32Array;
	sqInt size;
	char *otherByteArray;
	char *anotherByteArray;
	float *otherFloat32Array;

	aFloat32Array = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(4))));
	size = interpreterProxy->stackIntegerValue(3);
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(2)));
	otherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(1)));
	anotherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	otherFloat32Array = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	edgeCountsWP = otherByteArray;
	alphaMaskWP = anotherByteArray;
	contour = otherFloat32Array;
	i = 0;
	while (i < size) {
		commandType = ((sqInt)(aFloat32Array[i]));
		i += 1;
		
		switch (commandType) {
		case 0:
						if (!((i + 1) < size)) {
				if (interpreterProxy->failed()) {
					return null;
				}
				interpreterProxy->pop(5);
				return null;
			}
			startX = aFloat32Array[i];
			i += 1;
			startY = aFloat32Array[i];
			i += 1;
			/* begin initializeTrajectoryFragment */
			prevYTruncated = 0x7FFFFFFFU;
			break;
		case 1:
						if (!((i + 1) < size)) {
				if (interpreterProxy->failed()) {
					return null;
				}
				interpreterProxy->pop(5);
				return null;
			}
			endX = aFloat32Array[i];
			i += 1;
			endY = aFloat32Array[i];
			i += 1;
			pvt_lineWPFromXytoXy(startX, startY, endX, endY);
			startX = endX;
			startY = endY;
			break;
		case 2:
						if (!((i + 3) < size)) {
				if (interpreterProxy->failed()) {
					return null;
				}
				interpreterProxy->pop(5);
				return null;
			}
			endX = aFloat32Array[i];
			i += 1;
			endY = aFloat32Array[i];
			i += 1;
			control1X = aFloat32Array[i];
			i += 1;
			control1Y = aFloat32Array[i];
			i += 1;
			pvt_quadraticBezierWPFromXytoXycontrolXy(startX, startY, endX, endY, control1X, control1Y);
			startX = endX;
			startY = endY;
			break;
		case 3:
						if (!((i + 5) < size)) {
				if (interpreterProxy->failed()) {
					return null;
				}
				interpreterProxy->pop(5);
				return null;
			}
			endX = aFloat32Array[i];
			i += 1;
			endY = aFloat32Array[i];
			i += 1;
			control1X = aFloat32Array[i];
			i += 1;
			control1Y = aFloat32Array[i];
			i += 1;
			control2X = aFloat32Array[i];
			i += 1;
			control2Y = aFloat32Array[i];
			i += 1;
			pvt_cubicBezierWPFromXytoXycontrol1Xycontrol2Xy(startX, startY, endX, endY, control1X, control1Y, control2X, control2Y);
			startX = endX;
			startY = endY;
			break;
		default:
						if (interpreterProxy->failed()) {
				return null;
			}
			interpreterProxy->pop(5);
			return null;

		}
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(5);
	return null;
}


/*	
	VectorEngineWithPlugin isPluginAvailable
	API version is a SmallInteger.
	Note: this is Api version, not package version. If no Api change, Api version doesn't change, regardless of changes in the Plugin or Smalltalk code.
	See senders and implementors.
	 */

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

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

static sqInt pvt_cubicBezierFromXytoXycontrol1Xycontrol2Xy(float xFrom, float yFrom, float xTo, float yTo, float xControl1, float yControl1, float xControl2, float yControl2) {
	float txTo;
	float tyControl1;
	float increment;
	float txControl1;
	float yMaxEnd;
	float txFrom;
	float t;
	float dy2;
	float f4;
	float dy3;
	float f1;
	float tyControl2;
	float txControl2;
	float x;
	float dx;
	float f23;
	float tyFrom;
	float tyTo;
	float f2;
	float dx2;
	float oneLessT;
	float y;
	float dy;
	int hops;
	float xMinEnd;
	float f3;
	float xMaxEnd;
	float yMinEnd;
	float dx3;

	txFrom = ((xFrom * txA11) + (yFrom * txA12)) + txA13;
	tyFrom = ((xFrom * txA21) + (yFrom * txA22)) + txA23;
	txTo = ((xTo * txA11) + (yTo * txA12)) + txA13;
	tyTo = ((xTo * txA21) + (yTo * txA22)) + txA23;
	txControl1 = ((xControl1 * txA11) + (yControl1 * txA12)) + txA13;
	tyControl1 = ((xControl1 * txA21) + (yControl1 * txA22)) + txA23;
	txControl2 = ((xControl2 * txA11) + (yControl2 * txA12)) + txA13;
	tyControl2 = ((xControl2 * txA21) + (yControl2 * txA22)) + txA23;
	
		dx = fabs(txControl1-txFrom);
		dx2 = fabs(txTo-txControl2);
		dx3 = fabs(txControl2-txControl1);
		dy = fabs(tyControl1-tyFrom);
		dy2 = fabs(tyTo-tyControl2);
		dy3 = fabs(tyControl2-tyControl1);;
	dx = ((((((dx < dx2) ? dx2 : dx)) * 3) < (dx3 * 1.5)) ? (dx3 * 1.5) : ((((dx < dx2) ? dx2 : dx)) * 3));
	dy = ((((((dy < dy2) ? dy2 : dy)) * 3) < (dy3 * 1.5)) ? (dy3 * 1.5) : ((((dy < dy2) ? dy2 : dy)) * 3));

	/* This computed span of the Bezier curve is a bit pessimistic (larger than strict bounds), but safe. */

	hops = (((sqInt)((((dx < dy) ? dy : dx)) / hop))) + 1;
	xMinEnd = ((txFrom < txTo) ? txFrom : txTo);
	xMaxEnd = ((txFrom < txTo) ? txTo : txFrom);
	yMinEnd = ((tyFrom < tyTo) ? tyFrom : tyTo);
	yMaxEnd = ((tyFrom < tyTo) ? tyTo : tyFrom);
	spanLeft = ((spanLeft < (((xMinEnd < ((xMinEnd * 0.25) + ((((txControl1 < txControl2) ? txControl1 : txControl2)) * 0.75))) ? xMinEnd : ((xMinEnd * 0.25) + ((((txControl1 < txControl2) ? txControl1 : txControl2)) * 0.75))))) ? spanLeft : (((xMinEnd < ((xMinEnd * 0.25) + ((((txControl1 < txControl2) ? txControl1 : txControl2)) * 0.75))) ? xMinEnd : ((xMinEnd * 0.25) + ((((txControl1 < txControl2) ? txControl1 : txControl2)) * 0.75)))));
	spanRight = ((spanRight < (((xMaxEnd < ((xMaxEnd * 0.25) + ((((txControl1 < txControl2) ? txControl2 : txControl1)) * 0.75))) ? ((xMaxEnd * 0.25) + ((((txControl1 < txControl2) ? txControl2 : txControl1)) * 0.75)) : xMaxEnd))) ? (((xMaxEnd < ((xMaxEnd * 0.25) + ((((txControl1 < txControl2) ? txControl2 : txControl1)) * 0.75))) ? ((xMaxEnd * 0.25) + ((((txControl1 < txControl2) ? txControl2 : txControl1)) * 0.75)) : xMaxEnd)) : spanRight);
	spanTop = ((spanTop < (((yMinEnd < ((yMinEnd * 0.25) + ((((tyControl1 < tyControl2) ? tyControl1 : tyControl2)) * 0.75))) ? yMinEnd : ((yMinEnd * 0.25) + ((((tyControl1 < tyControl2) ? tyControl1 : tyControl2)) * 0.75))))) ? spanTop : (((yMinEnd < ((yMinEnd * 0.25) + ((((tyControl1 < tyControl2) ? tyControl1 : tyControl2)) * 0.75))) ? yMinEnd : ((yMinEnd * 0.25) + ((((tyControl1 < tyControl2) ? tyControl1 : tyControl2)) * 0.75)))));
	spanBottom = ((spanBottom < (((yMaxEnd < ((yMaxEnd * 0.25) + ((((tyControl1 < tyControl2) ? tyControl2 : tyControl1)) * 0.75))) ? ((yMaxEnd * 0.25) + ((((tyControl1 < tyControl2) ? tyControl2 : tyControl1)) * 0.75)) : yMaxEnd))) ? (((yMaxEnd < ((yMaxEnd * 0.25) + ((((tyControl1 < tyControl2) ? tyControl2 : tyControl1)) * 0.75))) ? ((yMaxEnd * 0.25) + ((((tyControl1 < tyControl2) ? tyControl2 : tyControl1)) * 0.75)) : yMaxEnd)) : spanBottom);
	t = 0.0;
	increment = 1.0 / hops;
	while (t < 1.0) {
		oneLessT = 1.0 - t;
		f1 = (oneLessT * oneLessT) * oneLessT;
		f23 = (3.0 * oneLessT) * t;
		f2 = f23 * oneLessT;
		f3 = f23 * t;
		f4 = (t * t) * t;
		x = (((f1 * txFrom) + (f2 * txControl1)) + (f3 * txControl2)) + (f4 * txTo);
		y = (((f1 * tyFrom) + (f2 * tyControl1)) + (f3 * tyControl2)) + (f4 * tyTo);
		updateAlphasForXy(x, y);
		if (!(fillA == 0.0)) {
			updateEdgeCountAtXy(x, y);
		}
		updateContourForXy(x, y);
		t += increment;
	}
	updateAlphasForXy(txTo, tyTo);
	if (!(fillA == 0.0)) {
		updateEdgeCountAtXy(txTo, tyTo);
	}
	updateContourForXy(txTo, tyTo);
	return null;
}

static sqInt pvt_cubicBezierWPFromXytoXycontrol1Xycontrol2Xy(float xFrom, float yFrom, float xTo, float yTo, float xControl1, float yControl1, float xControl2, float yControl2) {
	float txTo;
	float tyControl1;
	float increment;
	float txControl1;
	float yMaxEnd;
	float txFrom;
	float t;
	float dy2;
	float f4;
	float dy3;
	float f1;
	float tyControl2;
	float txControl2;
	float x;
	float dx;
	float f23;
	float tyFrom;
	float tyTo;
	float f2;
	float dx2;
	float oneLessT;
	float y;
	float dy;
	int hops;
	float xMinEnd;
	float f3;
	float xMaxEnd;
	float yMinEnd;
	float dx3;

	txFrom = ((xFrom * txA11) + (yFrom * txA12)) + txA13;
	tyFrom = ((xFrom * txA21) + (yFrom * txA22)) + txA23;
	txTo = ((xTo * txA11) + (yTo * txA12)) + txA13;
	tyTo = ((xTo * txA21) + (yTo * txA22)) + txA23;
	txControl1 = ((xControl1 * txA11) + (yControl1 * txA12)) + txA13;
	tyControl1 = ((xControl1 * txA21) + (yControl1 * txA22)) + txA23;
	txControl2 = ((xControl2 * txA11) + (yControl2 * txA12)) + txA13;
	tyControl2 = ((xControl2 * txA21) + (yControl2 * txA22)) + txA23;
	
		dx = fabs(txControl1-txFrom);
		dx2 = fabs(txTo-txControl2);
		dx3 = fabs(txControl2-txControl1);
		dy = fabs(tyControl1-tyFrom);
		dy2 = fabs(tyTo-tyControl2);
		dy3 = fabs(tyControl2-tyControl1);;
	dx = ((((((dx < dx2) ? dx2 : dx)) * 3) < (dx3 * 1.5)) ? (dx3 * 1.5) : ((((dx < dx2) ? dx2 : dx)) * 3));
	dy = ((((((dy < dy2) ? dy2 : dy)) * 3) < (dy3 * 1.5)) ? (dy3 * 1.5) : ((((dy < dy2) ? dy2 : dy)) * 3));

	/* This computed span of the Bezier curve is a bit pessimistic (larger than strict bounds), but safe. */

	hops = (((sqInt)((((dx < dy) ? dy : dx)) / hop))) + 1;
	xMinEnd = ((txFrom < txTo) ? txFrom : txTo);
	xMaxEnd = ((txFrom < txTo) ? txTo : txFrom);
	yMinEnd = ((tyFrom < tyTo) ? tyFrom : tyTo);
	yMaxEnd = ((tyFrom < tyTo) ? tyTo : tyFrom);
	spanLeft = ((spanLeft < (((xMinEnd < ((xMinEnd * 0.25) + ((((txControl1 < txControl2) ? txControl1 : txControl2)) * 0.75))) ? xMinEnd : ((xMinEnd * 0.25) + ((((txControl1 < txControl2) ? txControl1 : txControl2)) * 0.75))))) ? spanLeft : (((xMinEnd < ((xMinEnd * 0.25) + ((((txControl1 < txControl2) ? txControl1 : txControl2)) * 0.75))) ? xMinEnd : ((xMinEnd * 0.25) + ((((txControl1 < txControl2) ? txControl1 : txControl2)) * 0.75)))));
	spanRight = ((spanRight < (((xMaxEnd < ((xMaxEnd * 0.25) + ((((txControl1 < txControl2) ? txControl2 : txControl1)) * 0.75))) ? ((xMaxEnd * 0.25) + ((((txControl1 < txControl2) ? txControl2 : txControl1)) * 0.75)) : xMaxEnd))) ? (((xMaxEnd < ((xMaxEnd * 0.25) + ((((txControl1 < txControl2) ? txControl2 : txControl1)) * 0.75))) ? ((xMaxEnd * 0.25) + ((((txControl1 < txControl2) ? txControl2 : txControl1)) * 0.75)) : xMaxEnd)) : spanRight);
	spanTop = ((spanTop < (((yMinEnd < ((yMinEnd * 0.25) + ((((tyControl1 < tyControl2) ? tyControl1 : tyControl2)) * 0.75))) ? yMinEnd : ((yMinEnd * 0.25) + ((((tyControl1 < tyControl2) ? tyControl1 : tyControl2)) * 0.75))))) ? spanTop : (((yMinEnd < ((yMinEnd * 0.25) + ((((tyControl1 < tyControl2) ? tyControl1 : tyControl2)) * 0.75))) ? yMinEnd : ((yMinEnd * 0.25) + ((((tyControl1 < tyControl2) ? tyControl1 : tyControl2)) * 0.75)))));
	spanBottom = ((spanBottom < (((yMaxEnd < ((yMaxEnd * 0.25) + ((((tyControl1 < tyControl2) ? tyControl2 : tyControl1)) * 0.75))) ? ((yMaxEnd * 0.25) + ((((tyControl1 < tyControl2) ? tyControl2 : tyControl1)) * 0.75)) : yMaxEnd))) ? (((yMaxEnd < ((yMaxEnd * 0.25) + ((((tyControl1 < tyControl2) ? tyControl2 : tyControl1)) * 0.75))) ? ((yMaxEnd * 0.25) + ((((tyControl1 < tyControl2) ? tyControl2 : tyControl1)) * 0.75)) : yMaxEnd)) : spanBottom);
	t = 0.0;
	increment = 1.0 / hops;
	while (t < 1.0) {
		oneLessT = 1.0 - t;
		f1 = (oneLessT * oneLessT) * oneLessT;
		f23 = (3.0 * oneLessT) * t;
		f2 = f23 * oneLessT;
		f3 = f23 * t;
		f4 = (t * t) * t;
		x = (((f1 * txFrom) + (f2 * txControl1)) + (f3 * txControl2)) + (f4 * txTo);
		y = (((f1 * tyFrom) + (f2 * tyControl1)) + (f3 * tyControl2)) + (f4 * tyTo);
		updateAlphasWPForXy(x, y);
		if (!(fillA == 0.0)) {
			updateEdgeCountWPAtXy(x, y);
		}
		updateContourForXy(x, y);
		t += increment;
	}
	updateAlphasWPForXy(txTo, tyTo);
	if (!(fillA == 0.0)) {
		updateEdgeCountWPAtXy(txTo, tyTo);
	}
	updateContourForXy(txTo, tyTo);
	return null;
}

static sqInt pvt_lineFromXytoXy(float xFrom, float yFrom, float xTo, float yTo) {
	float txTo;
	float increment;
	float txFrom;
	float t;
	float x;
	float dx;
	float tyFrom;
	float tyTo;
	float oneLessT;
	float y;
	float dy;
	int hops;

	txFrom = ((xFrom * txA11) + (yFrom * txA12)) + txA13;
	tyFrom = ((xFrom * txA21) + (yFrom * txA22)) + txA23;
	txTo = ((xTo * txA11) + (yTo * txA12)) + txA13;
	tyTo = ((xTo * txA21) + (yTo * txA22)) + txA23;
	dx = txTo - txFrom;
	dy = tyTo - tyFrom;
	
		dx = fabs(dx);
		dy = fabs(dy);;
	hops = (((sqInt)((((dx < dy) ? dy : dx)) / hop))) + 1;
	spanLeft = ((spanLeft < (((txFrom < txTo) ? txFrom : txTo))) ? spanLeft : (((txFrom < txTo) ? txFrom : txTo)));
	spanRight = ((spanRight < (((txFrom < txTo) ? txTo : txFrom))) ? (((txFrom < txTo) ? txTo : txFrom)) : spanRight);
	spanTop = ((spanTop < (((tyFrom < tyTo) ? tyFrom : tyTo))) ? spanTop : (((tyFrom < tyTo) ? tyFrom : tyTo)));
	spanBottom = ((spanBottom < (((tyFrom < tyTo) ? tyTo : tyFrom))) ? (((tyFrom < tyTo) ? tyTo : tyFrom)) : spanBottom);
	t = 0.0;
	increment = 1.0 / hops;
	while (t < 1.0) {
		oneLessT = 1.0 - t;
		x = (oneLessT * txFrom) + (t * txTo);
		y = (oneLessT * tyFrom) + (t * tyTo);
		updateAlphasForXy(x, y);
		if (!(fillA == 0.0)) {
			updateEdgeCountAtXy(x, y);
		}
		updateContourForXy(x, y);
		t += increment;
	}
	updateAlphasForXy(txTo, tyTo);
	if (!(fillA == 0.0)) {
		updateEdgeCountAtXy(txTo, tyTo);
	}
	updateContourForXy(txTo, tyTo);
	return null;
}

static sqInt pvt_lineWPFromXytoXy(float xFrom, float yFrom, float xTo, float yTo) {
	float txTo;
	float increment;
	float txFrom;
	float t;
	float x;
	float dx;
	float tyFrom;
	float tyTo;
	float oneLessT;
	float y;
	float dy;
	int hops;

	txFrom = ((xFrom * txA11) + (yFrom * txA12)) + txA13;
	tyFrom = ((xFrom * txA21) + (yFrom * txA22)) + txA23;
	txTo = ((xTo * txA11) + (yTo * txA12)) + txA13;
	tyTo = ((xTo * txA21) + (yTo * txA22)) + txA23;
	dx = txTo - txFrom;
	dy = tyTo - tyFrom;
	
		dx = fabs(dx);
		dy = fabs(dy);;
	hops = (((sqInt)((((dx < dy) ? dy : dx)) / hop))) + 1;
	spanLeft = ((spanLeft < (((txFrom < txTo) ? txFrom : txTo))) ? spanLeft : (((txFrom < txTo) ? txFrom : txTo)));
	spanRight = ((spanRight < (((txFrom < txTo) ? txTo : txFrom))) ? (((txFrom < txTo) ? txTo : txFrom)) : spanRight);
	spanTop = ((spanTop < (((tyFrom < tyTo) ? tyFrom : tyTo))) ? spanTop : (((tyFrom < tyTo) ? tyFrom : tyTo)));
	spanBottom = ((spanBottom < (((tyFrom < tyTo) ? tyTo : tyFrom))) ? (((tyFrom < tyTo) ? tyTo : tyFrom)) : spanBottom);
	t = 0.0;
	increment = 1.0 / hops;
	while (t < 1.0) {
		oneLessT = 1.0 - t;
		x = (oneLessT * txFrom) + (t * txTo);
		y = (oneLessT * tyFrom) + (t * tyTo);
		updateAlphasWPForXy(x, y);
		if (!(fillA == 0.0)) {
			updateEdgeCountWPAtXy(x, y);
		}
		updateContourForXy(x, y);
		t += increment;
	}
	updateAlphasWPForXy(txTo, tyTo);
	if (!(fillA == 0.0)) {
		updateEdgeCountWPAtXy(txTo, tyTo);
	}
	updateContourForXy(txTo, tyTo);
	return null;
}

static sqInt pvt_quadraticBezierFromXytoXycontrolXy(float xFrom, float yFrom, float xTo, float yTo, float xControl, float yControl) {
	float txTo;
	float increment;
	float yMaxEnd;
	float t0;
	float txFrom;
	float t;
	float dy2;
	float txControl;
	float y0;
	float f1;
	float x;
	float dx;
	float tyFrom;
	float tyTo;
	float f2;
	float dx2;
	float oneLessT;
	float y;
	float dy;
	float length;
	float x0;
	float tyControl;
	float xMinEnd;
	float correction;
	float f3;
	float xMaxEnd;
	float yMinEnd;

	if ((xControl == xTo) && (yControl == yTo)) {
		return pvt_lineFromXytoXy(xFrom, yFrom, xTo, yTo);
	}
	if ((xControl == xFrom) && (yControl == yFrom)) {
		return pvt_lineFromXytoXy(xFrom, yFrom, xTo, yTo);
	}
	txFrom = ((xFrom * txA11) + (yFrom * txA12)) + txA13;
	tyFrom = ((xFrom * txA21) + (yFrom * txA22)) + txA23;
	txTo = ((xTo * txA11) + (yTo * txA12)) + txA13;
	tyTo = ((xTo * txA21) + (yTo * txA22)) + txA23;
	txControl = ((xControl * txA11) + (yControl * txA12)) + txA13;
	tyControl = ((xControl * txA21) + (yControl * txA22)) + txA23;
	
		dx = fabs(txTo-txFrom);
		dx2 = fabs(txControl-txFrom);
		dy = fabs(tyTo-tyFrom);
		dy2 = fabs(tyControl-tyFrom);;
	if ((dx < 1.0) && (dx2 < 1.0)) {
		return pvt_lineFromXytoXy(xFrom, yFrom, xTo, yTo);
	}
	if ((dy < 1.0) && (dy2 < 1.0)) {
		return pvt_lineFromXytoXy(xFrom, yFrom, xTo, yTo);
	}
	xMinEnd = ((txFrom < txTo) ? txFrom : txTo);
	xMaxEnd = ((txFrom < txTo) ? txTo : txFrom);
	yMinEnd = ((tyFrom < tyTo) ? tyFrom : tyTo);
	yMaxEnd = ((tyFrom < tyTo) ? tyTo : tyFrom);
	spanLeft = ((spanLeft < (((xMinEnd < ((xMinEnd + txControl) / 2.0)) ? xMinEnd : ((xMinEnd + txControl) / 2.0)))) ? spanLeft : (((xMinEnd < ((xMinEnd + txControl) / 2.0)) ? xMinEnd : ((xMinEnd + txControl) / 2.0))));
	spanRight = ((spanRight < (((xMaxEnd < ((xMaxEnd + txControl) / 2.0)) ? ((xMaxEnd + txControl) / 2.0) : xMaxEnd))) ? (((xMaxEnd < ((xMaxEnd + txControl) / 2.0)) ? ((xMaxEnd + txControl) / 2.0) : xMaxEnd)) : spanRight);
	spanTop = ((spanTop < (((yMinEnd < ((yMinEnd + tyControl) / 2.0)) ? yMinEnd : ((yMinEnd + tyControl) / 2.0)))) ? spanTop : (((yMinEnd < ((yMinEnd + tyControl) / 2.0)) ? yMinEnd : ((yMinEnd + tyControl) / 2.0))));

	/* Case t = 0.0 */

	spanBottom = ((spanBottom < (((yMaxEnd < ((yMaxEnd + tyControl) / 2.0)) ? ((yMaxEnd + tyControl) / 2.0) : yMaxEnd))) ? (((yMaxEnd < ((yMaxEnd + tyControl) / 2.0)) ? ((yMaxEnd + tyControl) / 2.0) : yMaxEnd)) : spanBottom);
	x = txFrom;
	y = tyFrom;
	updateAlphasForXy(x, y);
	if (!(fillA == 0.0)) {
		updateEdgeCountAtXy(x, y);
	}
	updateContourForXy(x, y);
	increment = (((0.5 / (((dx < dy) ? dy : dx))) < 0.5) ? (0.5 / (((dx < dy) ? dy : dx))) : 0.5);
	t = 0.0;
	while (1) {
		t0 = t;
		x0 = x;

		/* Compute next point */

		y0 = y;
		t = t0 + increment;
		oneLessT = 1.0 - t;
		f1 = oneLessT * oneLessT;
		f2 = (2.0 * oneLessT) * t;
		f3 = t * t;
		x = ((f1 * txFrom) + (f2 * txControl)) + (f3 * txTo);

		/* Now adjust the increment to aim at the required hop length, and recompute next point. */

		y = ((f1 * tyFrom) + (f2 * tyControl)) + (f3 * tyTo);
		dx = x - x0;
		dy = y - y0;
		
			length = sqrt(dx*dx + dy*dy);;
		correction = hop / length;
		do {
			increment = (increment / length) * hop;
			t = t0 + increment;
			oneLessT = 1.0 - t;
			f1 = oneLessT * oneLessT;
			f2 = (2.0 * oneLessT) * t;
			f3 = t * t;
			x = ((f1 * txFrom) + (f2 * txControl)) + (f3 * txTo);
			y = ((f1 * tyFrom) + (f2 * tyControl)) + (f3 * tyTo);
			dx = x - x0;
			dy = y - y0;
			
				length = sqrt(dx*dx + dy*dy);;
			correction = hop / length;
		} while(correction < 1.0);
		if (!(t < 1.0)) break;
		updateAlphasForXy(x, y);
		if (!(fillA == 0.0)) {
			updateEdgeCountAtXy(x, y);
		}
		updateContourForXy(x, y);
	}
	updateAlphasForXy(txTo, tyTo);
	if (!(fillA == 0.0)) {
		updateEdgeCountAtXy(txTo, tyTo);
	}
	updateContourForXy(txTo, tyTo);
	return null;
}

static sqInt pvt_quadraticBezierWPFromXytoXycontrolXy(float xFrom, float yFrom, float xTo, float yTo, float xControl, float yControl) {
	float txTo;
	float increment;
	float yMaxEnd;
	float t0;
	float txFrom;
	float t;
	float dy2;
	float txControl;
	float y0;
	float f1;
	float x;
	float dx;
	float tyFrom;
	float tyTo;
	float f2;
	float dx2;
	float oneLessT;
	float y;
	float dy;
	float length;
	float x0;
	float tyControl;
	float xMinEnd;
	float correction;
	float f3;
	float xMaxEnd;
	float yMinEnd;

	if ((xControl == xTo) && (yControl == yTo)) {
		return pvt_lineWPFromXytoXy(xFrom, yFrom, xTo, yTo);
	}
	if ((xControl == xFrom) && (yControl == yFrom)) {
		return pvt_lineWPFromXytoXy(xFrom, yFrom, xTo, yTo);
	}
	txFrom = ((xFrom * txA11) + (yFrom * txA12)) + txA13;
	tyFrom = ((xFrom * txA21) + (yFrom * txA22)) + txA23;
	txTo = ((xTo * txA11) + (yTo * txA12)) + txA13;
	tyTo = ((xTo * txA21) + (yTo * txA22)) + txA23;
	txControl = ((xControl * txA11) + (yControl * txA12)) + txA13;
	tyControl = ((xControl * txA21) + (yControl * txA22)) + txA23;
	
		dx = fabs(txTo-txFrom);
		dx2 = fabs(txControl-txFrom);
		dy = fabs(tyTo-tyFrom);
		dy2 = fabs(tyControl-tyFrom);;
	if ((dx < 1.0) && (dx2 < 1.0)) {
		return pvt_lineWPFromXytoXy(xFrom, yFrom, xTo, yTo);
	}
	if ((dy < 1.0) && (dy2 < 1.0)) {
		return pvt_lineWPFromXytoXy(xFrom, yFrom, xTo, yTo);
	}
	xMinEnd = ((txFrom < txTo) ? txFrom : txTo);
	xMaxEnd = ((txFrom < txTo) ? txTo : txFrom);
	yMinEnd = ((tyFrom < tyTo) ? tyFrom : tyTo);
	yMaxEnd = ((tyFrom < tyTo) ? tyTo : tyFrom);
	spanLeft = ((spanLeft < (((xMinEnd < ((xMinEnd + txControl) / 2.0)) ? xMinEnd : ((xMinEnd + txControl) / 2.0)))) ? spanLeft : (((xMinEnd < ((xMinEnd + txControl) / 2.0)) ? xMinEnd : ((xMinEnd + txControl) / 2.0))));
	spanRight = ((spanRight < (((xMaxEnd < ((xMaxEnd + txControl) / 2.0)) ? ((xMaxEnd + txControl) / 2.0) : xMaxEnd))) ? (((xMaxEnd < ((xMaxEnd + txControl) / 2.0)) ? ((xMaxEnd + txControl) / 2.0) : xMaxEnd)) : spanRight);
	spanTop = ((spanTop < (((yMinEnd < ((yMinEnd + tyControl) / 2.0)) ? yMinEnd : ((yMinEnd + tyControl) / 2.0)))) ? spanTop : (((yMinEnd < ((yMinEnd + tyControl) / 2.0)) ? yMinEnd : ((yMinEnd + tyControl) / 2.0))));

	/* Case t = 0.0 */

	spanBottom = ((spanBottom < (((yMaxEnd < ((yMaxEnd + tyControl) / 2.0)) ? ((yMaxEnd + tyControl) / 2.0) : yMaxEnd))) ? (((yMaxEnd < ((yMaxEnd + tyControl) / 2.0)) ? ((yMaxEnd + tyControl) / 2.0) : yMaxEnd)) : spanBottom);
	x = txFrom;
	y = tyFrom;
	updateAlphasWPForXy(x, y);
	if (!(fillA == 0.0)) {
		updateEdgeCountWPAtXy(x, y);
	}
	updateContourForXy(x, y);
	increment = (((0.5 / (((dx < dy) ? dy : dx))) < 0.5) ? (0.5 / (((dx < dy) ? dy : dx))) : 0.5);
	t = 0.0;
	while (1) {
		t0 = t;
		x0 = x;

		/* Compute next point */

		y0 = y;
		t = t0 + increment;
		oneLessT = 1.0 - t;
		f1 = oneLessT * oneLessT;
		f2 = (2.0 * oneLessT) * t;
		f3 = t * t;
		x = ((f1 * txFrom) + (f2 * txControl)) + (f3 * txTo);

		/* Now adjust the increment to aim at the required hop length, and recompute next point. */

		y = ((f1 * tyFrom) + (f2 * tyControl)) + (f3 * tyTo);
		dx = x - x0;
		dy = y - y0;
		
			length = sqrt(dx*dx + dy*dy);;
		correction = hop / length;
		do {
			increment = (increment / length) * hop;
			t = t0 + increment;
			oneLessT = 1.0 - t;
			f1 = oneLessT * oneLessT;
			f2 = (2.0 * oneLessT) * t;
			f3 = t * t;
			x = ((f1 * txFrom) + (f2 * txControl)) + (f3 * txTo);
			y = ((f1 * tyFrom) + (f2 * tyControl)) + (f3 * tyTo);
			dx = x - x0;
			dy = y - y0;
			
				length = sqrt(dx*dx + dy*dy);;
			correction = hop / length;
		} while(correction < 1.0);
		if (!(t < 1.0)) break;
		updateAlphasWPForXy(x, y);
		if (!(fillA == 0.0)) {
			updateEdgeCountWPAtXy(x, y);
		}
		updateContourForXy(x, y);
	}
	updateAlphasWPForXy(txTo, tyTo);
	if (!(fillA == 0.0)) {
		updateEdgeCountWPAtXy(txTo, tyTo);
	}
	updateContourForXy(txTo, tyTo);
	return null;
}

EXPORT(sqInt) primQuadraticBezier(void) {
	double xFrom;
	double yFrom;
	double xTo;
	double yTo;
	double xControl;
	double yControl;
	unsigned *otherWordArray;
	unsigned *anotherWordArray;
	float *aFloat32Array;

	xFrom = interpreterProxy->stackFloatValue(8);
	yFrom = interpreterProxy->stackFloatValue(7);
	xTo = interpreterProxy->stackFloatValue(6);
	yTo = interpreterProxy->stackFloatValue(5);
	xControl = interpreterProxy->stackFloatValue(4);
	yControl = interpreterProxy->stackFloatValue(3);
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(2)));
	otherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(1)));
	anotherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	aFloat32Array = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	edgeCounts = otherWordArray;
	alphaMask = anotherWordArray;
	contour = aFloat32Array;
	pvt_quadraticBezierFromXytoXycontrolXy(xFrom, yFrom, xTo, yTo, xControl, yControl);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(9);
	return null;
}

EXPORT(sqInt) primQuadraticBezierWP(void) {
	double xFrom;
	double yFrom;
	double xTo;
	double yTo;
	double xControl;
	double yControl;
	char *otherByteArray;
	char *anotherByteArray;
	float *aFloat32Array;

	xFrom = interpreterProxy->stackFloatValue(8);
	yFrom = interpreterProxy->stackFloatValue(7);
	xTo = interpreterProxy->stackFloatValue(6);
	yTo = interpreterProxy->stackFloatValue(5);
	xControl = interpreterProxy->stackFloatValue(4);
	yControl = interpreterProxy->stackFloatValue(3);
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(2)));
	otherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(1)));
	anotherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	aFloat32Array = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	edgeCountsWP = otherByteArray;
	alphaMaskWP = anotherByteArray;
	contour = aFloat32Array;
	pvt_quadraticBezierWPFromXytoXycontrolXy(xFrom, yFrom, xTo, yTo, xControl, yControl);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(9);
	return null;
}

EXPORT(sqInt) primReset2Contour(void) {
	sqInt y;
	sqInt t;
	sqInt b;
	float *aFloat32Array;

	t = interpreterProxy->stackIntegerValue(2);
	b = interpreterProxy->stackIntegerValue(1);
	aFloat32Array = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	contour = aFloat32Array;
	leftAtThisY = targetWidth;
	rightAtThisY = 0;
	for (y = t; y <= b; y += 1) {
		contour[y * 2] = targetWidth;
		contour[(y * 2) + 1] = 0;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(3);
	return null;
}


/*	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;
}

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

	_return_value = interpreterProxy->integerObjectOf((((sqInt)(spanBottom + auxStrokeWidthDilatedHalf))));
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(1, _return_value);
	return null;
}

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

	_return_value = interpreterProxy->integerObjectOf((((sqInt)(((spanLeft - auxStrokeWidthDilatedHalf) - subPixelDelta) + 1))));
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(1, _return_value);
	return null;
}

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

	_return_value = interpreterProxy->integerObjectOf(((((sqInt)((spanRight + auxStrokeWidthDilatedHalf) + subPixelDelta))) + 1));
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(1, _return_value);
	return null;
}

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

	_return_value = interpreterProxy->integerObjectOf((((sqInt)((spanTop - auxStrokeWidthDilatedHalf) + 1))));
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(1, _return_value);
	return null;
}

EXPORT(sqInt) primStrokeRGBA(void) {
	double r;
	double g;
	double b;
	double a;

	r = interpreterProxy->stackFloatValue(3);
	g = interpreterProxy->stackFloatValue(2);
	b = interpreterProxy->stackFloatValue(1);
	a = interpreterProxy->stackFloatValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	strokeR = r * 255.0;
	strokeG = g * 255.0;
	strokeB = b * 255.0;
	strokeA = a;
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(4);
	return null;
}

EXPORT(sqInt) primStrokeWidth(void) {
	float swErodedHalf;
	double aNumber;

	aNumber = interpreterProxy->stackFloatValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	strokeWidth = aNumber;
	auxStrokeWidthDilatedHalf = (strokeWidth + antiAliasingWidth) * 0.5;
	auxStrokeWidthDilatedHalfSquared = auxStrokeWidthDilatedHalf * auxStrokeWidthDilatedHalf;
	swErodedHalf = (strokeWidth - antiAliasingWidth) * 0.5;
	auxStrokeWidthErodedHalfSquared = swErodedHalf * fabs(swErodedHalf);;
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}


/*	All arrays could be pinned instead of passing them every time! */

EXPORT(sqInt) primSetTarget(void) {
	unsigned *aBitmap;
	unsigned *aWordArray;
	unsigned *otherWordArray;
	unsigned *anotherWordArray;
	float *aFloat32Array;
	sqInt aNumber;
	sqInt otherNumber;

	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(6)));
	aBitmap = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(6))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(5)));
	aWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(5))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(4)));
	otherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(4))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(3)));
	anotherWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(3))));
	aFloat32Array = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(2))));
	aNumber = interpreterProxy->stackIntegerValue(1);
	otherNumber = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	targetBits = aBitmap;
	morphIds = aWordArray;
	edgeCounts = otherWordArray;
	alphaMask = anotherWordArray;
	contour = aFloat32Array;
	targetWidth = aNumber;
	targetHeight = otherNumber;
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(7);
	return null;
}


/*	All arrays could be pinned instead of passing them every time! */

EXPORT(sqInt) primSetTargetWP(void) {
	unsigned *aBitmap;
	unsigned *aWordArray;
	char *otherByteArray;
	char *anotherByteArray;
	float *aFloat32Array;
	sqInt aNumber;
	sqInt otherNumber;

	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(6)));
	aBitmap = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(6))));
	interpreterProxy->success(interpreterProxy->isWords(interpreterProxy->stackValue(5)));
	aWordArray = ((unsigned *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(5))));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(4)));
	otherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(4))));
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(3)));
	anotherByteArray = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(3))));
	aFloat32Array = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(2))));
	aNumber = interpreterProxy->stackIntegerValue(1);
	otherNumber = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	targetBits = aBitmap;
	morphIds = aWordArray;
	edgeCountsWP = otherByteArray;
	alphaMaskWP = anotherByteArray;
	contour = aFloat32Array;
	targetWidth = aNumber;
	targetHeight = otherNumber;
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(7);
	return null;
}

static sqInt updateAlphasForXy(float x, float y) {
	sqInt t;
	uint32_t blueAlpha;
	uint32_t candidateAlpha;
	sqInt doUpdate;
	sqInt pixelIndex;
	float dySquared;
	uint32_t alphaWord;
	float dx;
	sqInt r;
	sqInt displayX;
	sqInt b;
	float distanceToAxisSquared;
	sqInt l;
	uint32_t greenAlpha;
	float dy;
	float dxp;
	uint32_t redAlpha;
	sqInt displayY;


	/* (int(z+1)) works equally well than the more intuitive but slower (int(ceil(z)) */

	t = ((sqInt)((y - auxStrokeWidthDilatedHalf) + 1));
	if (t < clipTop) {
		t = clipTop;
	}
	b = ((sqInt)(y + auxStrokeWidthDilatedHalf));
	if (b > clipBottom) {
		b = clipBottom;
	}

	/* (int(z+1)) works equally well than the more intuitive but slower (int(ceil(z)) */

	l = ((sqInt)(((x - auxStrokeWidthDilatedHalf) - subPixelDelta) + 1));
	if (l < clipLeft) {
		l = clipLeft;
	}
	r = ((sqInt)((x + auxStrokeWidthDilatedHalf) + subPixelDelta));
	if (r > clipRight) {
		r = clipRight;
	}
	for (displayY = t; displayY <= b; displayY += 1) {
		pixelIndex = ((displayY * targetWidth) + l) - 1;
		dy = displayY - y;
		dySquared = dy * dy;
		for (displayX = l; displayX <= r; displayX += 1) {
			pixelIndex += 1;
			alphaWord = alphaMask[pixelIndex];
			if (!(alphaWord == 8355711)) {
				redAlpha = alphaWord & 0x7F0000;
				greenAlpha = alphaWord & 0x7F00;
				blueAlpha = alphaWord & 0x7F;
				doUpdate = 0;

				/* Red */

				dx = displayX - x;
				dxp = dx - subPixelDelta;
				distanceToAxisSquared = (dxp * dxp) + dySquared;
				if (distanceToAxisSquared < auxStrokeWidthDilatedHalfSquared) {
					if (distanceToAxisSquared <= auxStrokeWidthErodedHalfSquared) {
						candidateAlpha = 0x7F0000;
					} else {
						
										candidateAlpha = (uint32_t)((auxStrokeWidthDilatedHalf - (sqrt(distanceToAxisSquared))) * auxAntiAliasingWidthScaledInverse);
										candidateAlpha = candidateAlpha << 16;;
					}
					if (candidateAlpha > redAlpha) {
						doUpdate = 1;
						redAlpha = candidateAlpha;
					}
				}
				distanceToAxisSquared = (dx * dx) + dySquared;
				if (distanceToAxisSquared < auxStrokeWidthDilatedHalfSquared) {
					if (distanceToAxisSquared <= auxStrokeWidthErodedHalfSquared) {
						candidateAlpha = 0x7F00;
					} else {
						
										candidateAlpha = (uint32_t)((auxStrokeWidthDilatedHalf - (sqrt(distanceToAxisSquared))) * auxAntiAliasingWidthScaledInverse);
										candidateAlpha = candidateAlpha << 8;;
					}
					if (candidateAlpha > greenAlpha) {
						doUpdate = 1;
						greenAlpha = candidateAlpha;
					}
				}
				dxp = dx + subPixelDelta;
				distanceToAxisSquared = (dxp * dxp) + dySquared;
				if (distanceToAxisSquared < auxStrokeWidthDilatedHalfSquared) {
					if (distanceToAxisSquared <= auxStrokeWidthErodedHalfSquared) {
						candidateAlpha = 0x7F;
					} else {
						
										candidateAlpha = (uint32_t)((auxStrokeWidthDilatedHalf - (sqrt(distanceToAxisSquared))) * auxAntiAliasingWidthScaledInverse);;
					}
					if (candidateAlpha > blueAlpha) {
						doUpdate = 1;
						blueAlpha = candidateAlpha;
					}
				}
				if (doUpdate) {
					alphaWord = (redAlpha | greenAlpha) | blueAlpha;
					alphaMask[pixelIndex] = alphaWord;
				}
			}
		}
	}
	return null;
}

static sqInt updateAlphasWPForXy(float x, float y) {
	sqInt t;
	uint8_t candidateAlpha;
	sqInt pixelIndex;
	float dySquared;
	float dx;
	sqInt r;
	sqInt displayX;
	sqInt b;
	float distanceToAxisSquared;
	sqInt l;
	float dy;
	float dxSquared;
	sqInt displayY;
	uint8_t alphaByte;


	/* (int(z+1)) works equally well than the more intuitive but slower (int(ceil(z)) */

	t = ((sqInt)((y - auxStrokeWidthDilatedHalf) + 1));
	if (t < clipTop) {
		t = clipTop;
	}
	b = ((sqInt)(y + auxStrokeWidthDilatedHalf));
	if (b > clipBottom) {
		b = clipBottom;
	}

	/* (int(z+1)) works equally well than the more intuitive but slower (int(ceil(z)) */

	l = ((sqInt)((x - auxStrokeWidthDilatedHalf) + 1));
	if (l < clipLeft) {
		l = clipLeft;
	}
	r = ((sqInt)(x + auxStrokeWidthDilatedHalf));
	if (r > clipRight) {
		r = clipRight;
	}
	for (displayY = t; displayY <= b; displayY += 1) {
		pixelIndex = ((displayY * targetWidth) + l) - 1;
		dy = displayY - y;
		dySquared = dy * dy;
		for (displayX = l; displayX <= r; displayX += 1) {
			pixelIndex += 1;
			alphaByte = alphaMaskWP[pixelIndex];
			if (!(alphaByte == 0x7F)) {
				dx = displayX - x;
				dxSquared = dx * dx;
				distanceToAxisSquared = dxSquared + dySquared;
				if (distanceToAxisSquared < auxStrokeWidthDilatedHalfSquared) {
					if (distanceToAxisSquared <= auxStrokeWidthErodedHalfSquared) {
						candidateAlpha = 0x7F;
					} else {
						
										candidateAlpha = (uint8_t)((auxStrokeWidthDilatedHalf - (sqrt(distanceToAxisSquared))) * auxAntiAliasingWidthScaledInverse);;
					}
					if (candidateAlpha > alphaByte) {
						alphaMaskWP[pixelIndex] = candidateAlpha;
					}
				}
			}
		}
	}
	return null;
}


/*	slight optimization possible when we know width = 0:
		- we know candidateAlpha is never 127
		- we know distanceToEdge is always > erodedHalfWidth. */

static sqInt updateAlphasWPZeroStrokeForXy(float x, float y) {
	sqInt t;
	uint8_t candidateAlpha;
	sqInt pixelIndex;
	float dySquared;
	float dx;
	sqInt r;
	sqInt displayX;
	sqInt b;
	float distanceToAxisSquared;
	sqInt l;
	float dy;
	sqInt displayY;
	uint8_t alphaByte;


	/* (int(z+1)) works equally well than the more intuitive but slower (int(ceil(z)) */

	t = ((sqInt)((y - auxStrokeWidthDilatedHalf) + 1));
	if (t < clipTop) {
		t = clipTop;
	}
	b = ((sqInt)(y + auxStrokeWidthDilatedHalf));
	if (b > clipBottom) {
		b = clipBottom;
	}

	/* (int(z+1)) works equally well than the more intuitive but slower (int(ceil(z)) */

	l = ((sqInt)((x - auxStrokeWidthDilatedHalf) + 1));
	if (l < clipLeft) {
		l = clipLeft;
	}
	r = ((sqInt)(x + auxStrokeWidthDilatedHalf));
	if (r > clipRight) {
		r = clipRight;
	}
	for (displayY = t; displayY <= b; displayY += 1) {
		pixelIndex = ((displayY * targetWidth) + l) - 1;
		dy = displayY - y;
		dySquared = dy * dy;
		for (displayX = l; displayX <= r; displayX += 1) {
			pixelIndex += 1;
			alphaByte = alphaMaskWP[pixelIndex];
			if (!(alphaByte == 0x7F)) {
				dx = displayX - x;
				distanceToAxisSquared = (dx * dx) + dySquared;
				if (distanceToAxisSquared < auxStrokeWidthDilatedHalfSquared) {
					
								candidateAlpha = (uint8_t)((auxStrokeWidthDilatedHalf - (sqrt(distanceToAxisSquared))) * auxAntiAliasingWidthScaledInverse);;
					if (candidateAlpha > alphaByte) {
						alphaMaskWP[pixelIndex] = candidateAlpha;
					}
				}
			}
		}
	}
	return null;
}


/*	The Contour of the current morph is the pixel area affected, 	but without holes.
	For each y line where a pixel is affected, record the leftmost and rightmost affected pixels.
	Note: Only includes pen trajectory, but not stroke width. */

static sqInt updateContourForXy(float x, float y) {
	sqInt thisYRounded;

	thisYRounded = ((sqInt)(y + 0.5));
	if (((thisYRounded >= 0) && (thisYRounded <= (targetHeight - 1)))) {
		if (!(thisYRounded == prevYRounded)) {
			if (!(prevYRounded == 0x7FFFFFFFU)) {
				contour[prevYRounded * 2] = leftAtThisY;
				contour[(prevYRounded * 2) + 1] = rightAtThisY;
			}
			leftAtThisY = contour[thisYRounded * 2];
			rightAtThisY = contour[(thisYRounded * 2) + 1];
			prevYRounded = thisYRounded;
		}
		leftAtThisY = ((leftAtThisY < x) ? leftAtThisY : x);
		rightAtThisY = ((rightAtThisY < x) ? x : rightAtThisY);
	}
	return null;
}

EXPORT(sqInt) primUpdate2ContourLastLine(void) {
	float *aFloat32Array;

	aFloat32Array = ((float *) (interpreterProxy->arrayValueOf(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	contour = aFloat32Array;
	if (!(prevYRounded == 0x7FFFFFFFU)) {
		contour[prevYRounded * 2] = leftAtThisY;
		contour[(prevYRounded * 2) + 1] = rightAtThisY;
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}


/*	Compute edges intersecting with this horizontal line, for fills. */

static sqInt updateEdgeCountAtXy(float x, float y) {
	uint32_t redIncrement;
	sqInt thisYTruncated;
	uint32_t blueCount;
	sqInt greenOffset;
	uint32_t greenIncrement;
	sqInt bluePixelIndex;
	sqInt blueOffset;
	uint32_t countWord;
	uint32_t blueIncrement;
	sqInt redOffset;
	sqInt redPixelIndex;
	uint32_t greenCount;
	sqInt rest;
	sqInt pixelY;
	sqInt pixelIndexBase;
	sqInt greenPixelIndex;
	uint32_t redCount;


	/* truncated, both in C and Smalltalk */

	thisYTruncated = ((sqInt)y);
	if (thisYTruncated == prevYTruncated) {
		return 0;
	}
	if (!(((thisYTruncated >= (clipTop - 1)) && (thisYTruncated <= clipBottom)))) {
		return 0;
	}
	if (prevYTruncated == 0x7FFFFFFFU) {
		prevYTruncated = thisYTruncated;
		return 0;
	}
	if (thisYTruncated > prevYTruncated) {
		pixelY = thisYTruncated;
		redIncrement = 65536;
		greenIncrement = 256;
		blueIncrement = 1;
	} else {
		pixelY = prevYTruncated;
		redIncrement = 0xFF0000;
		greenIncrement = 0xFF00;
		blueIncrement = 0xFF;
	}

	/* All edge count at the left of the clipRect are added there (at the left of the clipRect).
	The effect is the same, and we need to clean up less stuff afterwards.
	More important, it avoids trying to acess pixels outside our form, i.e. invalid array acesses. */

	prevYTruncated = thisYTruncated;
	pixelIndexBase = pixelY * targetWidth;

	/* take the next red subpixel center to the right of x */

	redOffset = (((((sqInt)((x + subPixelDelta) + 1))) < clipLeft) ? clipLeft : (((sqInt)((x + subPixelDelta) + 1))));

	/* take the next green subpixel center to the right of x */

	greenOffset = (((((sqInt)(x + 1))) < clipLeft) ? clipLeft : (((sqInt)(x + 1))));

	/* take the next blue subpixel center to the right of x */

	blueOffset = (((((sqInt)((x - subPixelDelta) + 1))) < clipLeft) ? clipLeft : (((sqInt)((x - subPixelDelta) + 1))));
	redPixelIndex = pixelIndexBase + redOffset;
	greenPixelIndex = pixelIndexBase + greenOffset;

	/* Three possible cases here: RGB in one word (pixel); RG in one, and G in another; R in one, GB in another */

	bluePixelIndex = pixelIndexBase + blueOffset;
	if (redPixelIndex == bluePixelIndex) {

		/* First case: RGB in the same word */

		if (redOffset <= clipRight) {
			countWord = edgeCounts[redPixelIndex];
			redCount = (countWord + redIncrement) & 0xFF0000;
			greenCount = (countWord + greenIncrement) & 0xFF00;
			blueCount = (countWord + blueIncrement) & 0xFF;
			countWord = (redCount | greenCount) | blueCount;
			edgeCounts[redPixelIndex] = countWord;
		}
	} else {
		if (redPixelIndex == greenPixelIndex) {

			/* Second case: RG in one word, B in previous */

			if (redOffset <= clipRight) {
				countWord = edgeCounts[redPixelIndex];
				redCount = (countWord + redIncrement) & 0xFF0000;
				greenCount = (countWord + greenIncrement) & 0xFF00;
				rest = countWord & 0xFF;
				countWord = (redCount | greenCount) | rest;
				edgeCounts[redPixelIndex] = countWord;
			}
			if (blueOffset <= clipRight) {
				countWord = edgeCounts[bluePixelIndex];
				rest = countWord & 0xFFFF00;
				blueCount = (countWord + blueIncrement) & 0xFF;
				countWord = rest | blueCount;
				edgeCounts[bluePixelIndex] = countWord;
			}
		} else {

			/* Third case: R in one word, GB in the previous */

			if (redOffset <= clipRight) {
				countWord = edgeCounts[redPixelIndex];
				redCount = (countWord + redIncrement) & 0xFF0000;
				rest = countWord & 0xFFFF;
				countWord = redCount | rest;
				edgeCounts[redPixelIndex] = countWord;
			}
			if (blueOffset <= clipRight) {
				countWord = edgeCounts[bluePixelIndex];
				rest = countWord & 0xFF0000;
				greenCount = (countWord + greenIncrement) & 0xFF00;
				blueCount = (countWord + blueIncrement) & 0xFF;
				countWord = (rest | greenCount) | blueCount;
				edgeCounts[bluePixelIndex] = countWord;
			}
		}
	}
	return null;
}


/*	Compute edges intersecting with this horizontal line, for fills. */

static sqInt updateEdgeCountWPAtXy(float x, float y) {
	uint8_t increment;
	sqInt thisYTruncated;
	sqInt pixelIndex;
	sqInt pixelOffset;
	sqInt pixelY;
	uint8_t count;


	/* truncated, both in C and Smalltalk */

	thisYTruncated = ((sqInt)y);
	if (thisYTruncated == prevYTruncated) {
		return 0;
	}
	if (!(((thisYTruncated >= (clipTop - 1)) && (thisYTruncated <= clipBottom)))) {
		return 0;
	}
	if (prevYTruncated == 0x7FFFFFFFU) {
		prevYTruncated = thisYTruncated;
		return 0;
	}
	if (thisYTruncated > prevYTruncated) {
		pixelY = thisYTruncated;
		increment = 1;
	} else {
		pixelY = prevYTruncated;
		increment = 0xFF;
	}

	/* All edge count at the left of the clipRect are added there (at the left of the clipRect).
	The effect is the same, and we need to clean up less stuff afterwards.
	More important, it avoids trying to acess pixels outside our form, i.e. invalid array acesses. */

	prevYTruncated = thisYTruncated;

	/* take the next pixel center to the right of x */

	pixelOffset = (((((sqInt)(x + 1))) < clipLeft) ? clipLeft : (((sqInt)(x + 1))));
	if (pixelOffset <= clipRight) {
		pixelIndex = (pixelY * targetWidth) + pixelOffset;
		count = edgeCountsWP[pixelIndex];
		count += increment;
		edgeCountsWP[pixelIndex] = count;
	}
	return null;
}


#ifdef SQUEAK_BUILTIN_PLUGIN


void* VectorEnginePlugin_exports[][3] = {
	{"VectorEnginePlugin", "primPathSequenceWP", (void*)primPathSequenceWP},
	{"VectorEnginePlugin", "pluginApiVersion", (void*)pluginApiVersion},
	{"VectorEnginePlugin", "primSetTargetWP", (void*)primSetTargetWP},
	{"VectorEnginePlugin", "primLineWP", (void*)primLineWP},
	{"VectorEnginePlugin", "primDisplayString", (void*)primDisplayString},
	{"VectorEnginePlugin", "primDisplayUtf32WP", (void*)primDisplayUtf32WP},
	{"VectorEnginePlugin", "primBlendStrokeOnly", (void*)primBlendStrokeOnly},
	{"VectorEnginePlugin", "primGeometryTxSet", (void*)primGeometryTxSet},
	{"VectorEnginePlugin", "primAntiAliasingWidthsubPixelDeltaHopLength", (void*)primAntiAliasingWidthsubPixelDeltaHopLength},
	{"VectorEnginePlugin", "primInitializePath", (void*)primInitializePath},
	{"VectorEnginePlugin", "primBlendStrokeAndFill", (void*)primBlendStrokeAndFill},
	{"VectorEnginePlugin", "primBlendStrokeAndFillWPOT", (void*)primBlendStrokeAndFillWPOT},
	{"VectorEnginePlugin", "primStrokeRGBA", (void*)primStrokeRGBA},
	{"VectorEnginePlugin", "primDisplayUtf8", (void*)primDisplayUtf8},
	{"VectorEnginePlugin", "getModuleName", (void*)getModuleName},
	{"VectorEnginePlugin", "primClipLeftclipTopclipRightclipBottom", (void*)primClipLeftclipTopclipRightclipBottom},
	{"VectorEnginePlugin", "primQuadraticBezierWP", (void*)primQuadraticBezierWP},
	{"VectorEnginePlugin", "primStrokeWidth", (void*)primStrokeWidth},
	{"VectorEnginePlugin", "setInterpreter", (void*)setInterpreter},
	{"VectorEnginePlugin", "primSetTarget", (void*)primSetTarget},
	{"VectorEnginePlugin", "primSpanTop", (void*)primSpanTop},
	{"VectorEnginePlugin", "primSpanLeft", (void*)primSpanLeft},
	{"VectorEnginePlugin", "primCubicBezier", (void*)primCubicBezier},
	{"VectorEnginePlugin", "primCubicBezierWP", (void*)primCubicBezierWP},
	{"VectorEnginePlugin", "primCurrentMorphIdcurrentClipsSubmorphs", (void*)primCurrentMorphIdcurrentClipsSubmorphs},
	{"VectorEnginePlugin", "primDisplayUtf8WP", (void*)primDisplayUtf8WP},
	{"VectorEnginePlugin", "primBlendStrokeOnlyWPOT", (void*)primBlendStrokeOnlyWPOT},
	{"VectorEnginePlugin", "primArc", (void*)primArc},
	{"VectorEnginePlugin", "primBlendFillOnlyWPOT", (void*)primBlendFillOnlyWPOT},
	{"VectorEnginePlugin", "primClipCurrentMorph", (void*)primClipCurrentMorph},
	{"VectorEnginePlugin", "primFillRGBA", (void*)primFillRGBA},
	{"VectorEnginePlugin", "primSpanRight", (void*)primSpanRight},
	{"VectorEnginePlugin", "primBlendFillOnly", (void*)primBlendFillOnly},
	{"VectorEnginePlugin", "primNewTrajectoryFragment", (void*)primNewTrajectoryFragment},
	{"VectorEnginePlugin", "primLine", (void*)primLine},
	{"VectorEnginePlugin", "primReset2Contour", (void*)primReset2Contour},
	{"VectorEnginePlugin", "primPathSequence", (void*)primPathSequence},
	{"VectorEnginePlugin", "primDisplayUtf32", (void*)primDisplayUtf32},
	{"VectorEnginePlugin", "primArcWP", (void*)primArcWP},
	{"VectorEnginePlugin", "primDisplayStringWP", (void*)primDisplayStringWP},
	{"VectorEnginePlugin", "primUpdate2ContourLastLine", (void*)primUpdate2ContourLastLine},
	{"VectorEnginePlugin", "primQuadraticBezier", (void*)primQuadraticBezier},
	{"VectorEnginePlugin", "primSpanBottom", (void*)primSpanBottom},
	{NULL, NULL, NULL}
};


#endif /* ifdef SQ_BUILTIN_PLUGIN */

