Spaces:
Running
Running
| /* Smalltalk from Squeak4.5 with VMMaker 4.13.6 translated as JS source on 14 November 2014 12:21:50 am */ | |
| /* Automatically generated by | |
| JSPluginCodeGenerator VMMakerJS-bf.17 uuid: 399be48b-95d8-4722-bdcc-39a94a12c486 | |
| from | |
| BalloonEnginePlugin VMMaker-bf.353 uuid: 8ae25e7e-8d2c-451e-8277-598b30e9c002 | |
| */ | |
| (function B2DPlugin() { | |
| ; | |
| var VM_PROXY_MAJOR = 1; | |
| var VM_PROXY_MINOR = 11; | |
| /*** Functions ***/ | |
| function CLASSOF(obj) { return typeof obj === "number" ? interpreterProxy.classSmallInteger() : obj.sqClass } | |
| function SIZEOF(obj) { return obj.pointers ? obj.pointers.length : obj.words ? obj.words.length : obj.bytes ? obj.bytes.length : 0 } | |
| function BYTESIZEOF(obj) { return obj.bytes ? obj.bytes.length : obj.words ? obj.words.length * 4 : 0 } | |
| function DIV(a, b) { return Math.floor(a / b) | 0; } // integer division | |
| function MOD(a, b) { return a - DIV(a, b) * b | 0; } // signed modulus | |
| function SHL(a, b) { return b > 31 ? 0 : a << b; } // fix JS shift | |
| function SHR(a, b) { return b > 31 ? 0 : a >>> b; } // fix JS shift | |
| function SHIFT(a, b) { return b < 0 ? (b < -31 ? 0 : a >>> (0-b) ) : (b > 31 ? 0 : a << b); } | |
| function PTR_ADD(p, n) { return new Int32Array(p.buffer, p.byteOffset + n * 4); } | |
| function FPTR_ADD(p, n) { return new Float32Array(p.buffer, p.byteOffset + n * 4); } | |
| /*** Constants ***/ | |
| var BEBalloonEngineSize = 12; | |
| var BEBitBltIndex = 2; | |
| var BEFormsIndex = 3; | |
| var BESpanIndex = 1; | |
| var BEWorkBufferIndex = 0; | |
| var ETBalloonEdgeDataSize = 6; | |
| var ETIndexIndex = 0; | |
| var ETLinesIndex = 4; | |
| var ETXValueIndex = 1; | |
| var ETYValueIndex = 2; | |
| var ETZValueIndex = 3; | |
| var FTBalloonFillDataSize = 6; | |
| var FTIndexIndex = 0; | |
| var FTMaxXIndex = 2; | |
| var FTMinXIndex = 1; | |
| var FTYValueIndex = 3; | |
| var GBBaseSize = 16; | |
| var GBBitmapDepth = 12; | |
| var GBBitmapHeight = 11; | |
| var GBBitmapRaster = 14; | |
| var GBBitmapSize = 13; | |
| var GBBitmapWidth = 10; | |
| var GBColormapOffset = 18; | |
| var GBColormapSize = 15; | |
| var GBEndX = 14; | |
| var GBEndY = 15; | |
| var GBFinalX = 21; | |
| var GBMBaseSize = 18; | |
| var GBTileFlag = 16; | |
| var GBUpdateDDX = 4; | |
| var GBUpdateDDY = 5; | |
| var GBUpdateDX = 2; | |
| var GBUpdateDY = 3; | |
| var GBUpdateData = 10; | |
| var GBUpdateX = 0; | |
| var GBUpdateY = 1; | |
| var GBViaX = 12; | |
| var GBViaY = 13; | |
| var GBWideEntry = 18; | |
| var GBWideExit = 19; | |
| var GBWideExtent = 20; | |
| var GBWideFill = 16; | |
| var GBWideSize = 28; | |
| var GBWideUpdateData = 22; | |
| var GBWideWidth = 17; | |
| var GEBaseEdgeSize = 10; | |
| var GEBaseFillSize = 4; | |
| var GEEdgeFillsInvalid = 65536; | |
| var GEFAlreadyFailed = 100; | |
| var GEFBadPoint = 121; | |
| var GEFBitBltLoadFailed = 122; | |
| var GEFClassMismatch = 114; | |
| var GEFEdgeDataTooSmall = 112; | |
| var GEFEngineIsInteger = 101; | |
| var GEFEngineIsWords = 102; | |
| var GEFEngineStopped = 104; | |
| var GEFEngineTooSmall = 103; | |
| var GEFEntityCheckFailed = 120; | |
| var GEFEntityLoadFailed = 119; | |
| var GEFFillDataTooSmall = 113; | |
| var GEFFormLoadFailed = 123; | |
| var GEFSizeMismatch = 115; | |
| var GEFWorkBufferBadMagic = 108; | |
| var GEFWorkBufferIsInteger = 105; | |
| var GEFWorkBufferIsPointers = 106; | |
| var GEFWorkBufferStartWrong = 110; | |
| var GEFWorkBufferTooSmall = 107; | |
| var GEFWorkBufferWrongSize = 109; | |
| var GEFWorkTooBig = 111; | |
| var GEFWrongEdge = 118; | |
| var GEFWrongFill = 117; | |
| var GEFWrongState = 116; | |
| var GEFillIndexLeft = 8; | |
| var GEFillIndexRight = 9; | |
| var GENumLines = 7; | |
| var GEObjectIndex = 2; | |
| var GEObjectLength = 1; | |
| var GEObjectType = 0; | |
| var GEPrimitiveBezier = 6; | |
| var GEPrimitiveClippedBitmapFill = 1024; | |
| var GEPrimitiveEdge = 2; | |
| var GEPrimitiveEdgeMask = 255; | |
| var GEPrimitiveFill = 256; | |
| var GEPrimitiveFillMask = 65280; | |
| var GEPrimitiveLine = 4; | |
| var GEPrimitiveLinearGradientFill = 512; | |
| var GEPrimitiveRadialGradientFill = 768; | |
| var GEPrimitiveTypeMask = 65535; | |
| var GEPrimitiveWide = 1; | |
| var GEPrimitiveWideBezier = 7; | |
| var GEPrimitiveWideLine = 5; | |
| var GEPrimitiveWideMask = 254; | |
| var GEStateAddingFromGET = 1; | |
| var GEStateBlitBuffer = 5; | |
| var GEStateCompleted = 8; | |
| var GEStateScanningAET = 3; | |
| var GEStateUnlocked = 0; | |
| var GEStateUpdateEdges = 6; | |
| var GEStateWaitingChange = 7; | |
| var GEStateWaitingForEdge = 2; | |
| var GEStateWaitingForFill = 4; | |
| var GEXValue = 4; | |
| var GEYValue = 5; | |
| var GEZValue = 6; | |
| var GErrorAETEntry = 6; | |
| var GErrorBadState = 2; | |
| var GErrorFillEntry = 5; | |
| var GErrorGETEntry = 4; | |
| var GErrorNeedFlush = 3; | |
| var GErrorNoMoreSpace = 1; | |
| var GFDirectionX = 6; | |
| var GFDirectionY = 7; | |
| var GFNormalX = 8; | |
| var GFNormalY = 9; | |
| var GFOriginX = 4; | |
| var GFOriginY = 5; | |
| var GFRampLength = 10; | |
| var GFRampOffset = 12; | |
| var GGBaseSize = 12; | |
| var GLBaseSize = 16; | |
| var GLEndX = 14; | |
| var GLEndY = 15; | |
| var GLError = 13; | |
| var GLErrorAdjDown = 15; | |
| var GLErrorAdjUp = 14; | |
| var GLWideEntry = 18; | |
| var GLWideExit = 19; | |
| var GLWideExtent = 20; | |
| var GLWideFill = 16; | |
| var GLWideSize = 21; | |
| var GLWideWidth = 17; | |
| var GLXDirection = 10; | |
| var GLXIncrement = 12; | |
| var GLYDirection = 11; | |
| var GWAAColorMask = 51; | |
| var GWAAColorShift = 50; | |
| var GWAAHalfPixel = 53; | |
| var GWAALevel = 48; | |
| var GWAAScanMask = 52; | |
| var GWAAShift = 49; | |
| var GWAETStart = 13; | |
| var GWAETUsed = 14; | |
| var GWBezierHeightSubdivisions = 109; | |
| var GWBezierLineConversions = 111; | |
| var GWBezierMonotonSubdivisions = 108; | |
| var GWBezierOverflowSubdivisions = 110; | |
| var GWBufferTop = 10; | |
| var GWClearSpanBuffer = 69; | |
| var GWClipMaxX = 43; | |
| var GWClipMaxY = 45; | |
| var GWClipMinX = 42; | |
| var GWClipMinY = 44; | |
| var GWColorTransform = 24; | |
| var GWCountAddAETEntry = 97; | |
| var GWCountChangeAETEntry = 107; | |
| var GWCountDisplaySpan = 103; | |
| var GWCountFinishTest = 93; | |
| var GWCountInitializing = 91; | |
| var GWCountMergeFill = 101; | |
| var GWCountNextAETEntry = 105; | |
| var GWCountNextFillEntry = 99; | |
| var GWCountNextGETEntry = 95; | |
| var GWCurrentY = 88; | |
| var GWCurrentZ = 113; | |
| var GWDestOffsetX = 46; | |
| var GWDestOffsetY = 47; | |
| var GWEdgeTransform = 18; | |
| var GWFillMaxX = 37; | |
| var GWFillMaxY = 39; | |
| var GWFillMinX = 36; | |
| var GWFillMinY = 38; | |
| var GWGETStart = 11; | |
| var GWGETUsed = 12; | |
| var GWHasColorTransform = 17; | |
| var GWHasEdgeTransform = 16; | |
| var GWHeaderSize = 128; | |
| var GWLastExportedEdge = 65; | |
| var GWLastExportedFill = 66; | |
| var GWLastExportedLeftX = 67; | |
| var GWLastExportedRightX = 68; | |
| var GWMagicIndex = 0; | |
| var GWMagicNumber = 1097753705; | |
| var GWMinimalSize = 256; | |
| var GWNeedsFlush = 63; | |
| var GWObjStart = 8; | |
| var GWObjUsed = 9; | |
| var GWPoint1 = 80; | |
| var GWPoint2 = 82; | |
| var GWPoint3 = 84; | |
| var GWPoint4 = 86; | |
| var GWSize = 1; | |
| var GWSpanEnd = 34; | |
| var GWSpanEndAA = 35; | |
| var GWSpanSize = 33; | |
| var GWSpanStart = 32; | |
| var GWState = 2; | |
| var GWStopReason = 64; | |
| var GWTimeAddAETEntry = 96; | |
| var GWTimeChangeAETEntry = 106; | |
| var GWTimeDisplaySpan = 102; | |
| var GWTimeFinishTest = 92; | |
| var GWTimeInitializing = 90; | |
| var GWTimeMergeFill = 100; | |
| var GWTimeNextAETEntry = 104; | |
| var GWTimeNextFillEntry = 98; | |
| var GWTimeNextGETEntry = 94; | |
| var PrimErrBadArgument = 3; | |
| var PrimErrBadNumArgs = 5; | |
| /*** Variables ***/ | |
| var aetBuffer = null; | |
| var bbPluginName = "BitBltPlugin"; | |
| var copyBitsFn = null; | |
| var dispatchReturnValue = 0; | |
| var dispatchedValue = 0; | |
| var doProfileStats = 0; | |
| var engine = 0; | |
| var engineStopped = 0; | |
| var formArray = 0; | |
| var geProfileTime = 0; | |
| var getBuffer = null; | |
| var interpreterProxy = null; | |
| var loadBBFn = null; | |
| var moduleName = "B2DPlugin 14 November 2014 (e)"; | |
| var objBuffer = null; | |
| var objUsed = 0; | |
| var spanBuffer = null; | |
| var workBuffer = null; | |
| function aaColorMaskGet() { | |
| return workBuffer[GWAAColorMask]; | |
| } | |
| function aaColorMaskPut(value) { | |
| return workBuffer[GWAAColorMask] = value; | |
| } | |
| function aaColorShiftGet() { | |
| return workBuffer[GWAAColorShift]; | |
| } | |
| function aaColorShiftPut(value) { | |
| return workBuffer[GWAAColorShift] = value; | |
| } | |
| /* Common function to compute the first full pixel for AA drawing */ | |
| function aaFirstPixelFromto(leftX, rightX) { | |
| var firstPixel; | |
| firstPixel = ((leftX + aaLevelGet()) - 1) & ~(aaLevelGet() - 1); | |
| if (firstPixel > rightX) { | |
| return rightX; | |
| } else { | |
| return firstPixel; | |
| } | |
| } | |
| function aaHalfPixelPut(value) { | |
| return workBuffer[GWAAHalfPixel] = value; | |
| } | |
| /* Common function to compute the last full pixel for AA drawing */ | |
| function aaLastPixelFromto(leftX, rightX) { | |
| return (rightX - 1) & ~(aaLevelGet() - 1); | |
| } | |
| function aaLevelGet() { | |
| return workBuffer[GWAALevel]; | |
| } | |
| function aaLevelPut(value) { | |
| return workBuffer[GWAALevel] = value; | |
| } | |
| function aaScanMaskGet() { | |
| return workBuffer[GWAAScanMask]; | |
| } | |
| function aaScanMaskPut(value) { | |
| return workBuffer[GWAAScanMask] = value; | |
| } | |
| function aaShiftGet() { | |
| return workBuffer[GWAAShift]; | |
| } | |
| function aaShiftPut(value) { | |
| return workBuffer[GWAAShift] = value; | |
| } | |
| /* Compute the squared value of a 8.24 number with 0.0 <= value < 1.0, | |
| e.g., compute (value * value) bitShift: -24 */ | |
| function absoluteSquared8Dot24(value) { | |
| var word1; | |
| var word2; | |
| word1 = value & 65535; | |
| word2 = (value >>> 16) & 255; | |
| return ((((word1 * word1) >>> 16) + ((word1 * word2) * 2)) + ((word2 * word2) << 16)) >>> 8; | |
| } | |
| /* Return the accurate length of the vector described by deltaX and deltaY */ | |
| function accurateLengthOfwith(deltaX, deltaY) { | |
| var length2; | |
| if (deltaX === 0) { | |
| if (deltaY < 0) { | |
| return 0 - deltaY; | |
| } else { | |
| return deltaY; | |
| } | |
| } | |
| if (deltaY === 0) { | |
| if (deltaX < 0) { | |
| return 0 - deltaX; | |
| } else { | |
| return deltaX; | |
| } | |
| } | |
| length2 = (deltaX * deltaX) + (deltaY * deltaY); | |
| return computeSqrt(length2); | |
| } | |
| function addEdgeToGET(edge) { | |
| if (!allocateGETEntry(1)) { | |
| return 0; | |
| } | |
| getBuffer[getUsedGet()] = edge; | |
| getUsedPut(getUsedGet() + 1); | |
| } | |
| /* Adjust the wide bezier curve (dx < 0) to start/end at the right point */ | |
| function adjustWideBezierLeftwidthoffsetendX(bezier, lineWidth, lineOffset, endX) { | |
| var lastX; | |
| var lastY; | |
| bezierUpdateDataOf(bezier)[GBUpdateX] = (bezierUpdateDataOf(bezier)[GBUpdateX] - (lineOffset * 256)); | |
| lastX = wideBezierUpdateDataOf(bezier)[GBUpdateX]; | |
| wideBezierUpdateDataOf(bezier)[GBUpdateX] = (lastX + ((lineWidth - lineOffset) * 256)); | |
| lastY = wideBezierUpdateDataOf(bezier)[GBUpdateY]; | |
| wideBezierUpdateDataOf(bezier)[GBUpdateY] = (lastY + (lineWidth * 256)); | |
| bezierFinalXOfput(bezier, endX - lineOffset); | |
| } | |
| /* Adjust the wide bezier curve (dx >= 0) to start/end at the right point */ | |
| function adjustWideBezierRightwidthoffsetendX(bezier, lineWidth, lineOffset, endX) { | |
| var lastX; | |
| var lastY; | |
| bezierUpdateDataOf(bezier)[GBUpdateX] = (bezierUpdateDataOf(bezier)[GBUpdateX] + (lineOffset * 256)); | |
| lastX = wideBezierUpdateDataOf(bezier)[GBUpdateX]; | |
| wideBezierUpdateDataOf(bezier)[GBUpdateX] = (lastX - ((lineWidth - lineOffset) * 256)); | |
| /* Set lineWidth pixels down */ | |
| lastY = wideBezierUpdateDataOf(bezier)[GBUpdateY]; | |
| wideBezierUpdateDataOf(bezier)[GBUpdateY] = (lastY + (lineWidth * 256)); | |
| bezierFinalXOfput(bezier, (endX - lineOffset) + lineWidth); | |
| } | |
| /* Adjust the wide line after it has been stepped from lastX to nextX. | |
| Special adjustments of line width and start position are made here | |
| to simulate a rectangular brush */ | |
| function adjustWideLineafterSteppingFromto(line, lastX, nextX) { | |
| var baseWidth; | |
| var deltaX; | |
| var lineOffset; | |
| var lineWidth; | |
| var xDir; | |
| var yEntry; | |
| var yExit; | |
| /* Don't inline this */ | |
| /* Fetch the values the adjustment decisions are based on */ | |
| yEntry = wideLineEntryOf(line); | |
| yExit = wideLineExitOf(line); | |
| baseWidth = wideLineExtentOf(line); | |
| lineOffset = offsetFromWidth(baseWidth); | |
| lineWidth = wideLineWidthOf(line); | |
| xDir = lineXDirectionOf(line); | |
| /* Adjust the start of the line to fill an entire rectangle */ | |
| deltaX = nextX - lastX; | |
| if (yEntry < baseWidth) { | |
| if (xDir < 0) { | |
| /* effectively adding */ | |
| lineWidth -= deltaX; | |
| } else { | |
| lineWidth += deltaX; | |
| edgeXValueOfput(line, lastX); | |
| } | |
| } | |
| if ((yExit + lineOffset) === 0) { | |
| if (xDir > 0) { | |
| lineWidth -= lineXIncrementOf(line); | |
| } else { | |
| /* effectively subtracting */ | |
| lineWidth += lineXIncrementOf(line); | |
| edgeXValueOfput(line, lastX); | |
| } | |
| } | |
| if ((yExit + lineOffset) > 0) { | |
| if (xDir < 0) { | |
| /* effectively subtracting */ | |
| lineWidth += deltaX; | |
| edgeXValueOfput(line, lastX); | |
| } else { | |
| lineWidth -= deltaX; | |
| } | |
| } | |
| wideLineWidthOfput(line, lineWidth); | |
| } | |
| function aetStartGet() { | |
| return workBuffer[GWAETStart]; | |
| } | |
| function aetStartPut(value) { | |
| return workBuffer[GWAETStart] = value; | |
| } | |
| function aetUsedGet() { | |
| return workBuffer[GWAETUsed]; | |
| } | |
| function aetUsedPut(value) { | |
| return workBuffer[GWAETUsed] = value; | |
| } | |
| /* Allocate n slots in the active edge table */ | |
| function allocateAETEntry(nSlots) { | |
| return needAvailableSpace(nSlots); | |
| } | |
| function allocateBezier() { | |
| var bezier; | |
| if (!allocateObjEntry(GBBaseSize)) { | |
| return 0; | |
| } | |
| bezier = objUsed; | |
| objUsed = bezier + GBBaseSize; | |
| objectTypeOfput(bezier, GEPrimitiveBezier); | |
| objectIndexOfput(bezier, 0); | |
| objectLengthOfput(bezier, GBBaseSize); | |
| return bezier; | |
| } | |
| function allocateBezierStackEntry() { | |
| wbStackPush(6); | |
| return wbStackSize(); | |
| } | |
| function allocateBitmapFillcolormap(cmSize, cmBits) { | |
| var cm; | |
| var fill; | |
| var fillSize; | |
| var i; | |
| fillSize = GBMBaseSize + cmSize; | |
| if (!allocateObjEntry(fillSize)) { | |
| return 0; | |
| } | |
| fill = objUsed; | |
| objUsed = fill + fillSize; | |
| objectTypeOfput(fill, GEPrimitiveClippedBitmapFill); | |
| objectIndexOfput(fill, 0); | |
| objectLengthOfput(fill, fillSize); | |
| cm = colormapOf(fill); | |
| if (hasColorTransform()) { | |
| for (i = 0; i <= (cmSize - 1); i++) { | |
| cm[i] = transformColor(cmBits[i]); | |
| } | |
| } else { | |
| for (i = 0; i <= (cmSize - 1); i++) { | |
| cm[i] = cmBits[i]; | |
| } | |
| } | |
| bitmapCmSizeOfput(fill, cmSize); | |
| return fill; | |
| } | |
| /* Allocate n slots in the global edge table */ | |
| function allocateGETEntry(nSlots) { | |
| var dstIndex; | |
| var i; | |
| var srcIndex; | |
| var iLimiT; | |
| /* First allocate nSlots in the AET */ | |
| if (!allocateAETEntry(nSlots)) { | |
| return false; | |
| } | |
| if (aetUsedGet() !== 0) { | |
| /* Then move the AET upwards */ | |
| srcIndex = aetUsedGet(); | |
| dstIndex = aetUsedGet() + nSlots; | |
| for (i = 1, iLimiT = aetUsedGet(); i <= iLimiT; i++) { | |
| aetBuffer[(--dstIndex)] = aetBuffer[(--srcIndex)]; | |
| } | |
| } | |
| aetBuffer = PTR_ADD(aetBuffer, nSlots); | |
| return true; | |
| } | |
| function allocateGradientFillrampWidthisRadial(ramp, rampWidth, isRadial) { | |
| var fill; | |
| var fillSize; | |
| var i; | |
| var rampPtr; | |
| fillSize = GGBaseSize + rampWidth; | |
| if (!allocateObjEntry(fillSize)) { | |
| return 0; | |
| } | |
| fill = objUsed; | |
| objUsed = fill + fillSize; | |
| if (isRadial) { | |
| objectTypeOfput(fill, GEPrimitiveRadialGradientFill); | |
| } else { | |
| objectTypeOfput(fill, GEPrimitiveLinearGradientFill); | |
| } | |
| objectIndexOfput(fill, 0); | |
| objectLengthOfput(fill, fillSize); | |
| rampPtr = gradientRampOf(fill); | |
| if (hasColorTransform()) { | |
| for (i = 0; i <= (rampWidth - 1); i++) { | |
| rampPtr[i] = transformColor(ramp[i]); | |
| } | |
| } else { | |
| for (i = 0; i <= (rampWidth - 1); i++) { | |
| rampPtr[i] = ramp[i]; | |
| } | |
| } | |
| gradientRampLengthOfput(fill, rampWidth); | |
| return fill; | |
| } | |
| function allocateLine() { | |
| var line; | |
| if (!allocateObjEntry(GLBaseSize)) { | |
| return 0; | |
| } | |
| line = objUsed; | |
| objUsed = line + GLBaseSize; | |
| objectTypeOfput(line, GEPrimitiveLine); | |
| objectIndexOfput(line, 0); | |
| objectLengthOfput(line, GLBaseSize); | |
| return line; | |
| } | |
| /* Allocate n slots in the object buffer */ | |
| function allocateObjEntry(nSlots) { | |
| var dstIndex; | |
| var i; | |
| var srcIndex; | |
| var iLimiT; | |
| /* First allocate nSlots in the GET */ | |
| if (!allocateGETEntry(nSlots)) { | |
| return false; | |
| } | |
| if (getUsedGet() !== 0) { | |
| /* Then move the GET upwards */ | |
| srcIndex = getUsedGet(); | |
| dstIndex = getUsedGet() + nSlots; | |
| for (i = 1, iLimiT = getUsedGet(); i <= iLimiT; i++) { | |
| getBuffer[(--dstIndex)] = getBuffer[(--srcIndex)]; | |
| } | |
| } | |
| getBuffer = PTR_ADD(getBuffer, nSlots); | |
| return true; | |
| } | |
| /* AET and Stack allocation are symmetric */ | |
| function allocateStackEntry(nSlots) { | |
| return needAvailableSpace(nSlots); | |
| } | |
| function allocateStackFillEntry() { | |
| return wbStackPush(stackFillEntryLength()); | |
| } | |
| function allocateWideBezier() { | |
| var bezier; | |
| if (!allocateObjEntry(GBWideSize)) { | |
| return 0; | |
| } | |
| bezier = objUsed; | |
| objUsed = bezier + GBWideSize; | |
| objectTypeOfput(bezier, GEPrimitiveWideBezier); | |
| objectIndexOfput(bezier, 0); | |
| objectLengthOfput(bezier, GBWideSize); | |
| return bezier; | |
| } | |
| function allocateWideLine() { | |
| var line; | |
| if (!allocateObjEntry(GLWideSize)) { | |
| return 0; | |
| } | |
| line = objUsed; | |
| objUsed = line + GLWideSize; | |
| objectTypeOfput(line, GEPrimitiveWideLine); | |
| objectIndexOfput(line, 0); | |
| objectLengthOfput(line, GLWideSize); | |
| return line; | |
| } | |
| function areEdgeFillsValid(edge) { | |
| return (objectHeaderOf(edge) & GEEdgeFillsInvalid) === 0; | |
| } | |
| /* Make sure that val1 is between val2 and val3. */ | |
| function assureValuebetweenand(val1, val2, val3) { | |
| if (val2 > val3) { | |
| if (val1 > val2) { | |
| return val2; | |
| } | |
| if (val1 < val3) { | |
| return val3; | |
| } | |
| } else { | |
| if (val1 < val2) { | |
| return val2; | |
| } | |
| if (val1 > val3) { | |
| return val3; | |
| } | |
| } | |
| return val1; | |
| } | |
| function bezierEndXOf(bezier) { | |
| return objat(bezier, GBEndX); | |
| } | |
| function bezierEndXOfput(bezier, value) { | |
| return objatput(bezier, GBEndX, value); | |
| } | |
| function bezierEndYOf(bezier) { | |
| return objat(bezier, GBEndY); | |
| } | |
| function bezierEndYOfput(bezier, value) { | |
| return objatput(bezier, GBEndY, value); | |
| } | |
| function bezierFinalXOf(bezier) { | |
| return objat(bezier, GBFinalX); | |
| } | |
| function bezierFinalXOfput(bezier, value) { | |
| return objatput(bezier, GBFinalX, value); | |
| } | |
| function bezierUpdateDataOf(bezier) { | |
| return PTR_ADD(objBuffer, bezier + GBUpdateData); | |
| } | |
| function bezierViaXOf(bezier) { | |
| return objat(bezier, GBViaX); | |
| } | |
| function bezierViaXOfput(bezier, value) { | |
| return objatput(bezier, GBViaX, value); | |
| } | |
| function bezierViaYOf(bezier) { | |
| return objat(bezier, GBViaY); | |
| } | |
| function bezierViaYOfput(bezier, value) { | |
| return objatput(bezier, GBViaY, value); | |
| } | |
| function bitmapCmSizeOf(bmFill) { | |
| return objat(bmFill, GBColormapSize); | |
| } | |
| function bitmapCmSizeOfput(bmFill, value) { | |
| return objatput(bmFill, GBColormapSize, value); | |
| } | |
| function bitmapDepthOf(bmFill) { | |
| return objat(bmFill, GBBitmapDepth); | |
| } | |
| function bitmapDepthOfput(bmFill, value) { | |
| return objatput(bmFill, GBBitmapDepth, value); | |
| } | |
| function bitmapHeightOf(bmFill) { | |
| return objat(bmFill, GBBitmapHeight); | |
| } | |
| function bitmapHeightOfput(bmFill, value) { | |
| return objatput(bmFill, GBBitmapHeight, value); | |
| } | |
| function bitmapRasterOf(bmFill) { | |
| return objat(bmFill, GBBitmapRaster); | |
| } | |
| function bitmapRasterOfput(bmFill, value) { | |
| return objatput(bmFill, GBBitmapRaster, value); | |
| } | |
| function bitmapSizeOf(bmFill) { | |
| return objat(bmFill, GBBitmapSize); | |
| } | |
| function bitmapSizeOfput(bmFill, value) { | |
| return objatput(bmFill, GBBitmapSize, value); | |
| } | |
| function bitmapTileFlagOf(bmFill) { | |
| return objat(bmFill, GBTileFlag); | |
| } | |
| function bitmapTileFlagOfput(bmFill, value) { | |
| return objatput(bmFill, GBTileFlag, value); | |
| } | |
| function bitmapValuebitsatXy(bmFill, bits, xp, yp) { | |
| var a; | |
| var b; | |
| var bmDepth; | |
| var bmRaster; | |
| var cMask; | |
| var g; | |
| var r; | |
| var rShift; | |
| var value; | |
| bmDepth = bitmapDepthOf(bmFill); | |
| bmRaster = bitmapRasterOf(bmFill); | |
| if (bmDepth === 32) { | |
| value = (bits[(bmRaster * yp) + xp]|0); | |
| if ((value !== 0) && ((value & 4278190080) === 0)) { | |
| value = value | 4278190080; | |
| } | |
| return uncheckedTransformColor(value); | |
| } | |
| rShift = rShiftTable()[bmDepth]; | |
| /* cMask - mask out the pixel from the word */ | |
| value = bits[(bmRaster * yp) + (SHR(xp, rShift))]; | |
| /* rShift - shift value to move the pixel in the word to the lowest bit position */ | |
| cMask = (SHL(1, bmDepth)) - 1; | |
| rShift = (32 - bmDepth) - ((xp & ((SHL(1, rShift)) - 1)) * bmDepth); | |
| value = (SHR(value, rShift)) & cMask; | |
| if (bmDepth === 16) { | |
| /* Must convert by expanding bits */ | |
| if (value !== 0) { | |
| b = (value & 31) << 3; | |
| b += b >>> 5; | |
| g = ((value >>> 5) & 31) << 3; | |
| g += g >>> 5; | |
| r = ((value >>> 10) & 31) << 3; | |
| r += r >>> 5; | |
| a = 255; | |
| value = ((b + (g << 8)) + (r << 16)) + (a << 24); | |
| } | |
| } else { | |
| /* Must convert by using color map */ | |
| if (bitmapCmSizeOf(bmFill) === 0) { | |
| value = 0; | |
| } else { | |
| value = colormapOf(bmFill)[value]; | |
| } | |
| } | |
| return uncheckedTransformColor(value); | |
| } | |
| function bitmapWidthOf(bmFill) { | |
| return objat(bmFill, GBBitmapWidth); | |
| } | |
| function bitmapWidthOfput(bmFill, value) { | |
| return objatput(bmFill, GBBitmapWidth, value); | |
| } | |
| function bzEndX(index) { | |
| return wbStackValue((wbStackSize() - index) + 4); | |
| } | |
| function bzEndXput(index, value) { | |
| return wbStackValueput((wbStackSize() - index) + 4, value); | |
| } | |
| function bzEndY(index) { | |
| return wbStackValue((wbStackSize() - index) + 5); | |
| } | |
| function bzEndYput(index, value) { | |
| return wbStackValueput((wbStackSize() - index) + 5, value); | |
| } | |
| function bzStartX(index) { | |
| return wbStackValue((wbStackSize() - index) + 0); | |
| } | |
| function bzStartXput(index, value) { | |
| return wbStackValueput((wbStackSize() - index) + 0, value); | |
| } | |
| function bzStartY(index) { | |
| return wbStackValue((wbStackSize() - index) + 1); | |
| } | |
| function bzStartYput(index, value) { | |
| return wbStackValueput((wbStackSize() - index) + 1, value); | |
| } | |
| function bzViaX(index) { | |
| return wbStackValue((wbStackSize() - index) + 2); | |
| } | |
| function bzViaXput(index, value) { | |
| return wbStackValueput((wbStackSize() - index) + 2, value); | |
| } | |
| function bzViaY(index) { | |
| return wbStackValue((wbStackSize() - index) + 3); | |
| } | |
| function bzViaYput(index, value) { | |
| return wbStackValueput((wbStackSize() - index) + 3, value); | |
| } | |
| /* Check the fill indexes in the run-length encoded fillList */ | |
| function checkCompressedFillIndexListmaxsegments(fillList, maxIndex, nSegs) { | |
| var fillPtr; | |
| var i; | |
| var length; | |
| var nFills; | |
| var runLength; | |
| var runValue; | |
| length = SIZEOF(fillList); | |
| fillPtr = fillList.wordsAsInt32Array(); | |
| nFills = 0; | |
| for (i = 0; i <= (length - 1); i++) { | |
| runLength = shortRunLengthAtfrom(i, fillPtr); | |
| runValue = shortRunValueAtfrom(i, fillPtr); | |
| if (!((runValue >= 0) && (runValue <= maxIndex))) { | |
| return false; | |
| } | |
| nFills += runLength; | |
| } | |
| return nFills === nSegs; | |
| } | |
| /* Check if the indexList (containing fill handles) is okay. */ | |
| function checkCompressedFills(indexList) { | |
| var fillIndex; | |
| var fillPtr; | |
| var i; | |
| var length; | |
| /* First check if the oops have the right format */ | |
| if (!interpreterProxy.isWords(indexList)) { | |
| return false; | |
| } | |
| length = SIZEOF(indexList); | |
| fillPtr = indexList.wordsAsInt32Array(); | |
| for (i = 0; i <= (length - 1); i++) { | |
| /* Make sure the fill is okay */ | |
| fillIndex = fillPtr[i]; | |
| if (!isFillOkay(fillIndex)) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| /* Check the run-length encoded lineWidthList matches nSegments */ | |
| function checkCompressedLineWidthssegments(lineWidthList, nSegments) { | |
| var i; | |
| var length; | |
| var nItems; | |
| var ptr; | |
| var runLength; | |
| length = SIZEOF(lineWidthList); | |
| ptr = lineWidthList.wordsAsInt32Array(); | |
| nItems = 0; | |
| for (i = 0; i <= (length - 1); i++) { | |
| runLength = shortRunLengthAtfrom(i, ptr); | |
| nItems += runLength; | |
| } | |
| return nItems === nSegments; | |
| } | |
| /* Check if the given point array can be handled by the engine. */ | |
| function checkCompressedPointssegments(points, nSegments) { | |
| var pSize; | |
| if (!interpreterProxy.isWords(points)) { | |
| return false; | |
| } | |
| /* The points must be either in PointArray format or ShortPointArray format. | |
| Also, we currently handle only quadratic segments (e.g., 3 points each) and thus either | |
| pSize = nSegments * 3, for ShortPointArrays or, | |
| pSize = nSegments * 6, for PointArrays */ | |
| pSize = SIZEOF(points); | |
| if (!((pSize === (nSegments * 3)) || (pSize === (nSegments * 6)))) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| /* Check if the given shape can be handled by the engine. | |
| Since there are a number of requirements this is an extra method. */ | |
| function checkCompressedShapesegmentsleftFillsrightFillslineWidthslineFillsfillIndexList(points, nSegments, leftFills, rightFills, lineWidths, lineFills, fillIndexList) { | |
| var maxFillIndex; | |
| if (!checkCompressedPointssegments(points, nSegments)) { | |
| return false; | |
| } | |
| if (!checkCompressedFills(fillIndexList)) { | |
| return false; | |
| } | |
| maxFillIndex = SIZEOF(fillIndexList); | |
| if (!checkCompressedFillIndexListmaxsegments(leftFills, maxFillIndex, nSegments)) { | |
| return false; | |
| } | |
| if (!checkCompressedFillIndexListmaxsegments(rightFills, maxFillIndex, nSegments)) { | |
| return false; | |
| } | |
| if (!checkCompressedFillIndexListmaxsegments(lineFills, maxFillIndex, nSegments)) { | |
| return false; | |
| } | |
| if (!checkCompressedLineWidthssegments(lineWidths, nSegments)) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| /* Add the bezier to the global edge table if it intersects the clipping region */ | |
| function checkedAddBezierToGET(bezier) { | |
| var lineWidth; | |
| if (isWide(bezier)) { | |
| lineWidth = wideBezierExtentOf(bezier); | |
| } else { | |
| lineWidth = 0; | |
| } | |
| if ((bezierEndYOf(bezier) + lineWidth) < fillMinYGet()) { | |
| return 0; | |
| } | |
| if (((edgeXValueOf(bezier) - lineWidth) >= fillMaxXGet()) && ((bezierEndXOf(bezier) - lineWidth) >= fillMaxXGet())) { | |
| return 0; | |
| } | |
| addEdgeToGET(bezier); | |
| } | |
| /* Add the edge to the global edge table. | |
| For known edge types, check if the edge intersects the visible region */ | |
| function checkedAddEdgeToGET(edge) { | |
| if (isLine(edge)) { | |
| return checkedAddLineToGET(edge); | |
| } | |
| if (isBezier(edge)) { | |
| return checkedAddBezierToGET(edge); | |
| } | |
| addEdgeToGET(edge); | |
| } | |
| /* Add the line to the global edge table if it intersects the clipping region */ | |
| function checkedAddLineToGET(line) { | |
| var lineWidth; | |
| if (isWide(line)) { | |
| lineWidth = wideLineExtentOf(line); | |
| } else { | |
| lineWidth = 0; | |
| } | |
| if ((lineEndYOf(line) + lineWidth) < fillMinYGet()) { | |
| return 0; | |
| } | |
| if (((edgeXValueOf(line) - lineWidth) >= fillMaxXGet()) && ((lineEndXOf(line) - lineWidth) >= fillMaxXGet())) { | |
| return 0; | |
| } | |
| addEdgeToGET(line); | |
| } | |
| function circleCosTable() { | |
| var theTable = | |
| [1.0, 0.98078528040323, 0.923879532511287, 0.831469612302545, | |
| 0.7071067811865475, 0.555570233019602, 0.38268343236509, 0.1950903220161286, | |
| 0.0, -0.1950903220161283, -0.3826834323650896, -0.555570233019602, | |
| -0.707106781186547, -0.831469612302545, -0.9238795325112865, -0.98078528040323, | |
| -1.0, -0.98078528040323, -0.923879532511287, -0.831469612302545, | |
| -0.707106781186548, -0.555570233019602, -0.3826834323650903, -0.1950903220161287, | |
| 0.0, 0.1950903220161282, 0.38268343236509, 0.555570233019602, | |
| 0.707106781186547, 0.831469612302545, 0.9238795325112865, 0.98078528040323, | |
| 1.0 ]; | |
| return theTable; | |
| } | |
| function circleSinTable() { | |
| var theTable = | |
| [0.0, 0.1950903220161282, 0.3826834323650897, 0.555570233019602, | |
| 0.707106781186547, 0.831469612302545, 0.923879532511287, 0.98078528040323, | |
| 1.0, 0.98078528040323, 0.923879532511287, 0.831469612302545, | |
| 0.7071067811865475, 0.555570233019602, 0.38268343236509, 0.1950903220161286, | |
| 0.0, -0.1950903220161283, -0.3826834323650896, -0.555570233019602, | |
| -0.707106781186547, -0.831469612302545, -0.9238795325112865, -0.98078528040323, | |
| -1.0, -0.98078528040323, -0.923879532511287, -0.831469612302545, | |
| -0.707106781186548, -0.555570233019602, -0.3826834323650903, -0.1950903220161287, | |
| 0.0 ]; | |
| return theTable; | |
| } | |
| function clampValuemax(value, maxValue) { | |
| if (value < 0) { | |
| return 0; | |
| } else { | |
| if (value >= maxValue) { | |
| return maxValue - 1; | |
| } else { | |
| return value; | |
| } | |
| } | |
| } | |
| /* Clear the current span buffer. | |
| The span buffer is only cleared in the area that has been used by the previous scan line. */ | |
| function clearSpanBuffer() { | |
| var x0; | |
| var x1; | |
| x0 = SHR(spanStartGet(), aaShiftGet()); | |
| x1 = (SHR(spanEndGet(), aaShiftGet())) + 1; | |
| if (x0 < 0) { | |
| x0 = 0; | |
| } | |
| if (x1 > spanSizeGet()) { | |
| x1 = spanSizeGet(); | |
| } | |
| while (x0 < x1) { | |
| spanBuffer[x0] = 0; | |
| ++x0; | |
| } | |
| spanStartPut(spanSizeGet()); | |
| spanEndPut(0); | |
| } | |
| function clearSpanBufferGet() { | |
| return workBuffer[GWClearSpanBuffer]; | |
| } | |
| function clearSpanBufferPut(value) { | |
| return workBuffer[GWClearSpanBuffer] = value; | |
| } | |
| function clipMaxXGet() { | |
| return workBuffer[GWClipMaxX]; | |
| } | |
| function clipMaxXPut(value) { | |
| return workBuffer[GWClipMaxX] = value; | |
| } | |
| function clipMaxYGet() { | |
| return workBuffer[GWClipMaxY]; | |
| } | |
| function clipMaxYPut(value) { | |
| return workBuffer[GWClipMaxY] = value; | |
| } | |
| function clipMinXGet() { | |
| return workBuffer[GWClipMinX]; | |
| } | |
| function clipMinXPut(value) { | |
| return workBuffer[GWClipMinX] = value; | |
| } | |
| function clipMinYGet() { | |
| return workBuffer[GWClipMinY]; | |
| } | |
| function clipMinYPut(value) { | |
| return workBuffer[GWClipMinY] = value; | |
| } | |
| function colorTransform() { | |
| return FPTR_ADD(workBuffer, GWColorTransform); | |
| } | |
| function colormapOf(bmFill) { | |
| return PTR_ADD(objBuffer, bmFill + GBColormapOffset); | |
| } | |
| /* Split the bezier curve at the given parametric value. | |
| Note: Since this method is only invoked to make non-monoton | |
| beziers monoton we must check for the resulting y values | |
| to be *really* between the start and end value. */ | |
| function computeBeziersplitAt(index, param) { | |
| var endX; | |
| var endY; | |
| var leftViaX; | |
| var leftViaY; | |
| var newIndex; | |
| var rightViaX; | |
| var rightViaY; | |
| var sharedX; | |
| var sharedY; | |
| var startX; | |
| var startY; | |
| var viaX; | |
| var viaY; | |
| leftViaX = (startX = bzStartX(index)); | |
| leftViaY = (startY = bzStartY(index)); | |
| rightViaX = (viaX = bzViaX(index)); | |
| rightViaY = (viaY = bzViaY(index)); | |
| endX = bzEndX(index); | |
| /* Compute intermediate points */ | |
| endY = bzEndY(index); | |
| sharedX = (leftViaX += (((viaX - startX) * param)|0)); | |
| sharedY = (leftViaY += (((viaY - startY) * param)|0)); | |
| rightViaX += (((endX - viaX) * param)|0); | |
| /* Compute new shared point */ | |
| rightViaY += (((endY - viaY) * param)|0); | |
| sharedX += (((rightViaX - leftViaX) * param)|0); | |
| /* Check the new via points */ | |
| sharedY += (((rightViaY - leftViaY) * param)|0); | |
| leftViaY = assureValuebetweenand(leftViaY, startY, sharedY); | |
| rightViaY = assureValuebetweenand(rightViaY, sharedY, endY); | |
| newIndex = allocateBezierStackEntry(); | |
| if (engineStopped) { | |
| return 0; | |
| } | |
| bzViaXput(index, leftViaX); | |
| bzViaYput(index, leftViaY); | |
| bzEndXput(index, sharedX); | |
| bzEndYput(index, sharedY); | |
| bzStartXput(newIndex, sharedX); | |
| bzStartYput(newIndex, sharedY); | |
| bzViaXput(newIndex, rightViaX); | |
| bzViaYput(newIndex, rightViaY); | |
| bzEndXput(newIndex, endX); | |
| bzEndYput(newIndex, endY); | |
| return newIndex; | |
| } | |
| /* Split the bezier curve at 0.5. */ | |
| function computeBezierSplitAtHalf(index) { | |
| var endX; | |
| var endY; | |
| var leftViaX; | |
| var leftViaY; | |
| var newIndex; | |
| var rightViaX; | |
| var rightViaY; | |
| var sharedX; | |
| var sharedY; | |
| var startX; | |
| var startY; | |
| var viaX; | |
| var viaY; | |
| newIndex = allocateBezierStackEntry(); | |
| if (engineStopped) { | |
| return 0; | |
| } | |
| leftViaX = (startX = bzStartX(index)); | |
| leftViaY = (startY = bzStartY(index)); | |
| rightViaX = (viaX = bzViaX(index)); | |
| rightViaY = (viaY = bzViaY(index)); | |
| endX = bzEndX(index); | |
| /* Compute intermediate points */ | |
| endY = bzEndY(index); | |
| leftViaX += (viaX - startX) >> 1; | |
| leftViaY += (viaY - startY) >> 1; | |
| sharedX = (rightViaX += (endX - viaX) >> 1); | |
| /* Compute new shared point */ | |
| sharedY = (rightViaY += (endY - viaY) >> 1); | |
| sharedX += (leftViaX - rightViaX) >> 1; | |
| /* Store the first part back */ | |
| sharedY += (leftViaY - rightViaY) >> 1; | |
| bzViaXput(index, leftViaX); | |
| bzViaYput(index, leftViaY); | |
| bzEndXput(index, sharedX); | |
| bzEndYput(index, sharedY); | |
| bzStartXput(newIndex, sharedX); | |
| bzStartYput(newIndex, sharedY); | |
| bzViaXput(newIndex, rightViaX); | |
| bzViaYput(newIndex, rightViaY); | |
| bzEndXput(newIndex, endX); | |
| bzEndYput(newIndex, endY); | |
| return newIndex; | |
| } | |
| /* Get both values from the two boundaries of the given bezier | |
| and compute the actual position/width of the line */ | |
| function computeFinalWideBezierValueswidth(bezier, lineWidth) { | |
| var leftX; | |
| var rightX; | |
| var temp; | |
| leftX = bezierUpdateDataOf(bezier)[GBUpdateX] >> 8; | |
| rightX = wideBezierUpdateDataOf(bezier)[GBUpdateX] >> 8; | |
| if (leftX > rightX) { | |
| temp = leftX; | |
| leftX = rightX; | |
| rightX = temp; | |
| } | |
| edgeXValueOfput(bezier, leftX); | |
| if ((rightX - leftX) > lineWidth) { | |
| wideBezierWidthOfput(bezier, rightX - leftX); | |
| } else { | |
| wideBezierWidthOfput(bezier, lineWidth); | |
| } | |
| } | |
| function computeSqrt(length2) { | |
| if (length2 < 32) { | |
| return smallSqrtTable()[length2]; | |
| } else { | |
| return ((Math.sqrt(length2) + 0.5)|0); | |
| } | |
| } | |
| function copyBitsFromtoat(x0, x1, yValue) { | |
| if (!copyBitsFn) { | |
| /* We need copyBits here so try to load it implicitly */ | |
| if (!initialiseModule()) { | |
| return false; | |
| } | |
| } | |
| return copyBitsFn(x0, x1, yValue); | |
| } | |
| /* Create the global edge table */ | |
| function createGlobalEdgeTable() { | |
| var end; | |
| var object; | |
| object = 0; | |
| end = objUsed; | |
| while (object < end) { | |
| /* Note: addEdgeToGET: may fail on insufficient space but that's not a problem here */ | |
| if (isEdge(object)) { | |
| /* Check if the edge starts below fillMaxY. */ | |
| if (!(edgeYValueOf(object) >= fillMaxYGet())) { | |
| checkedAddEdgeToGET(object); | |
| } | |
| } | |
| object += objectLengthOf(object); | |
| } | |
| } | |
| function currentYGet() { | |
| return workBuffer[GWCurrentY]; | |
| } | |
| function currentYPut(value) { | |
| return workBuffer[GWCurrentY] = value; | |
| } | |
| function currentZGet() { | |
| return workBuffer[GWCurrentZ]; | |
| } | |
| function currentZPut(value) { | |
| return workBuffer[GWCurrentZ] = value; | |
| } | |
| function destOffsetXGet() { | |
| return workBuffer[GWDestOffsetX]; | |
| } | |
| function destOffsetXPut(value) { | |
| return workBuffer[GWDestOffsetX] = value; | |
| } | |
| function destOffsetYGet() { | |
| return workBuffer[GWDestOffsetY]; | |
| } | |
| function destOffsetYPut(value) { | |
| return workBuffer[GWDestOffsetY] = value; | |
| } | |
| /* Display the span buffer at the current scan line. */ | |
| function displaySpanBufferAt(y) { | |
| var targetX0; | |
| var targetX1; | |
| var targetY; | |
| /* self aaLevelGet > 1 ifTrue:[self adjustAALevel]. */ | |
| targetX0 = SHR(spanStartGet(), aaShiftGet()); | |
| if (targetX0 < clipMinXGet()) { | |
| targetX0 = clipMinXGet(); | |
| } | |
| targetX1 = SHR(((spanEndGet() + aaLevelGet()) - 1), aaShiftGet()); | |
| if (targetX1 > clipMaxXGet()) { | |
| targetX1 = clipMaxXGet(); | |
| } | |
| targetY = SHR(y, aaShiftGet()); | |
| if ((targetY < clipMinYGet()) || ((targetY >= clipMaxYGet()) || ((targetX1 < clipMinXGet()) || (targetX0 >= clipMaxXGet())))) { | |
| return 0; | |
| } | |
| copyBitsFromtoat(targetX0, targetX1, targetY); | |
| } | |
| function edgeFillsInvalidate(edge) { | |
| return objectTypeOfput(edge, objectTypeOf(edge) | GEEdgeFillsInvalid); | |
| } | |
| function edgeFillsValidate(edge) { | |
| return objectTypeOfput(edge, objectTypeOf(edge) & ~GEEdgeFillsInvalid); | |
| } | |
| function edgeLeftFillOf(edge) { | |
| return objat(edge, GEFillIndexLeft); | |
| } | |
| function edgeLeftFillOfput(edge, value) { | |
| return objatput(edge, GEFillIndexLeft, value); | |
| } | |
| function edgeNumLinesOf(edge) { | |
| return objat(edge, GENumLines); | |
| } | |
| function edgeNumLinesOfput(edge, value) { | |
| return objatput(edge, GENumLines, value); | |
| } | |
| function edgeRightFillOf(edge) { | |
| return objat(edge, GEFillIndexRight); | |
| } | |
| function edgeRightFillOfput(edge, value) { | |
| return objatput(edge, GEFillIndexRight, value); | |
| } | |
| function edgeTransform() { | |
| return FPTR_ADD(workBuffer, GWEdgeTransform); | |
| } | |
| /* Return the edge type (e.g., witout the wide edge flag) */ | |
| function edgeTypeOf(edge) { | |
| return objectTypeOf(edge) >>> 1; | |
| } | |
| function edgeXValueOf(edge) { | |
| return objat(edge, GEXValue); | |
| } | |
| function edgeXValueOfput(edge, value) { | |
| return objatput(edge, GEXValue, value); | |
| } | |
| function edgeYValueOf(edge) { | |
| return objat(edge, GEYValue); | |
| } | |
| function edgeYValueOfput(edge, value) { | |
| return objatput(edge, GEYValue, value); | |
| } | |
| function edgeZValueOf(edge) { | |
| return objat(edge, GEZValue); | |
| } | |
| function edgeZValueOfput(edge, value) { | |
| return objatput(edge, GEZValue, value); | |
| } | |
| /* Ignore dispatch errors when translating to C | |
| (since we have no entry point for #error in the VM proxy) */ | |
| function errorWrongIndex() { | |
| ; | |
| } | |
| /* Fill the span buffer from leftX to rightX with the given fill. */ | |
| function fillAllFromto(leftX, rightX) { | |
| var fill; | |
| var startX; | |
| var stopX; | |
| fill = topFill(); | |
| startX = leftX; | |
| stopX = topRightX(); | |
| while (stopX < rightX) { | |
| fill = topFill(); | |
| if (fill !== 0) { | |
| if (fillSpanfromto(fill, startX, stopX)) { | |
| return true; | |
| } | |
| } | |
| quickRemoveInvalidFillsAt(stopX); | |
| startX = stopX; | |
| stopX = topRightX(); | |
| } | |
| fill = topFill(); | |
| if (fill !== 0) { | |
| return fillSpanfromto(fill, startX, rightX); | |
| } | |
| return false; | |
| } | |
| function fillBitmapSpan() { | |
| return fillBitmapSpanfromtoat(lastExportedFillGet(), lastExportedLeftXGet(), lastExportedRightXGet(), currentYGet()); | |
| } | |
| /* Fill the span buffer between leftEdge and rightEdge using the given bits. | |
| Note: We always start from zero - this avoids using huge bitmap buffers if the bitmap is to be displayed at the very far right hand side and also gives us a chance of using certain bitmaps (e.g., those with depth 32) directly. */ | |
| function fillBitmapSpanfromto(bits, leftX, rightX) { | |
| var baseShift; | |
| var bitX; | |
| var colorMask; | |
| var colorShift; | |
| var fillValue; | |
| var x; | |
| var x0; | |
| var x1; | |
| x0 = leftX; | |
| x1 = rightX; | |
| /* Hack for pre-increment */ | |
| bitX = -1; | |
| if (aaLevelGet() === 1) { | |
| /* Speedy version for no anti-aliasing */ | |
| while (x0 < x1) { | |
| fillValue = (bits[(++bitX)]|0); | |
| spanBuffer[x0] = fillValue; | |
| ++x0; | |
| } | |
| } else { | |
| /* Generic version with anti-aliasing */ | |
| colorMask = aaColorMaskGet(); | |
| colorShift = aaColorShiftGet(); | |
| baseShift = aaShiftGet(); | |
| while (x0 < x1) { | |
| x = SHR(x0, baseShift); | |
| fillValue = (bits[(++bitX)]|0); | |
| fillValue = SHR((fillValue & colorMask), colorShift); | |
| spanBuffer[x] = (spanBuffer[x] + fillValue); | |
| ++x0; | |
| } | |
| } | |
| if (x1 > spanEndGet()) { | |
| spanEndPut(x1); | |
| } | |
| if (x1 > spanEndAAGet()) { | |
| spanEndAAPut(x1); | |
| } | |
| } | |
| function fillBitmapSpanfromtoat(bmFill, leftX, rightX, yValue) { | |
| var bits; | |
| var bmHeight; | |
| var bmWidth; | |
| var deltaX; | |
| var deltaY; | |
| var ds; | |
| var dsX; | |
| var dt; | |
| var dtX; | |
| var fillValue; | |
| var tileFlag; | |
| var x; | |
| var x1; | |
| var xp; | |
| var yp; | |
| if (aaLevelGet() !== 1) { | |
| return fillBitmapSpanAAfromtoat(bmFill, leftX, rightX, yValue); | |
| } | |
| bits = loadBitsFrom(bmFill); | |
| if (!bits) { | |
| return null; | |
| } | |
| bmWidth = bitmapWidthOf(bmFill); | |
| bmHeight = bitmapHeightOf(bmFill); | |
| tileFlag = bitmapTileFlagOf(bmFill) === 1; | |
| deltaX = leftX - fillOriginXOf(bmFill); | |
| deltaY = yValue - fillOriginYOf(bmFill); | |
| dsX = fillDirectionXOf(bmFill); | |
| dtX = fillNormalXOf(bmFill); | |
| ds = (deltaX * dsX) + (deltaY * fillDirectionYOf(bmFill)); | |
| dt = (deltaX * dtX) + (deltaY * fillNormalYOf(bmFill)); | |
| x = leftX; | |
| x1 = rightX; | |
| while (x < x1) { | |
| if (tileFlag) { | |
| ds = repeatValuemax(ds, bmWidth << 16); | |
| dt = repeatValuemax(dt, bmHeight << 16); | |
| } | |
| xp = ds >> 16; | |
| yp = dt >> 16; | |
| if (!tileFlag) { | |
| xp = clampValuemax(xp, bmWidth); | |
| yp = clampValuemax(yp, bmHeight); | |
| } | |
| if ((xp >= 0) && ((yp >= 0) && ((xp < bmWidth) && (yp < bmHeight)))) { | |
| fillValue = bitmapValuebitsatXy(bmFill, bits, xp, yp); | |
| spanBuffer[x] = fillValue; | |
| } | |
| ds += dsX; | |
| dt += dtX; | |
| ++x; | |
| } | |
| } | |
| function fillBitmapSpanAAfromtoat(bmFill, leftX, rightX, yValue) { | |
| var aaLevel; | |
| var baseShift; | |
| var bits; | |
| var bmHeight; | |
| var bmWidth; | |
| var cMask; | |
| var cShift; | |
| var deltaX; | |
| var deltaY; | |
| var ds; | |
| var dsX; | |
| var dt; | |
| var dtX; | |
| var fillValue; | |
| var firstPixel; | |
| var idx; | |
| var lastPixel; | |
| var tileFlag; | |
| var x; | |
| var xp; | |
| var yp; | |
| bits = loadBitsFrom(bmFill); | |
| if (!bits) { | |
| return null; | |
| } | |
| bmWidth = bitmapWidthOf(bmFill); | |
| bmHeight = bitmapHeightOf(bmFill); | |
| tileFlag = bitmapTileFlagOf(bmFill) === 1; | |
| deltaX = leftX - fillOriginXOf(bmFill); | |
| deltaY = yValue - fillOriginYOf(bmFill); | |
| dsX = fillDirectionXOf(bmFill); | |
| dtX = fillNormalXOf(bmFill); | |
| ds = (deltaX * dsX) + (deltaY * fillDirectionYOf(bmFill)); | |
| dt = (deltaX * dtX) + (deltaY * fillNormalYOf(bmFill)); | |
| aaLevel = aaLevelGet(); | |
| firstPixel = aaFirstPixelFromto(leftX, rightX); | |
| lastPixel = aaLastPixelFromto(leftX, rightX); | |
| baseShift = aaShiftGet(); | |
| cMask = aaColorMaskGet(); | |
| cShift = aaColorShiftGet(); | |
| x = leftX; | |
| while (x < firstPixel) { | |
| if (tileFlag) { | |
| ds = repeatValuemax(ds, bmWidth << 16); | |
| dt = repeatValuemax(dt, bmHeight << 16); | |
| } | |
| xp = ds >> 16; | |
| yp = dt >> 16; | |
| if (!tileFlag) { | |
| xp = clampValuemax(xp, bmWidth); | |
| yp = clampValuemax(yp, bmHeight); | |
| } | |
| if ((xp >= 0) && ((yp >= 0) && ((xp < bmWidth) && (yp < bmHeight)))) { | |
| fillValue = bitmapValuebitsatXy(bmFill, bits, xp, yp); | |
| fillValue = SHR((fillValue & cMask), cShift); | |
| idx = SHR(x, baseShift); | |
| spanBuffer[idx] = (spanBuffer[idx] + fillValue); | |
| } | |
| ds += dsX; | |
| dt += dtX; | |
| ++x; | |
| } | |
| cMask = (SHR(aaColorMaskGet(), aaShiftGet())) | 4042322160; | |
| cShift = aaShiftGet(); | |
| while (x < lastPixel) { | |
| if (tileFlag) { | |
| ds = repeatValuemax(ds, bmWidth << 16); | |
| dt = repeatValuemax(dt, bmHeight << 16); | |
| } | |
| xp = ds >> 16; | |
| yp = dt >> 16; | |
| if (!tileFlag) { | |
| xp = clampValuemax(xp, bmWidth); | |
| yp = clampValuemax(yp, bmHeight); | |
| } | |
| if ((xp >= 0) && ((yp >= 0) && ((xp < bmWidth) && (yp < bmHeight)))) { | |
| fillValue = bitmapValuebitsatXy(bmFill, bits, xp, yp); | |
| fillValue = SHR((fillValue & cMask), cShift); | |
| idx = SHR(x, baseShift); | |
| spanBuffer[idx] = (spanBuffer[idx] + fillValue); | |
| } | |
| ds += SHL(dsX, cShift); | |
| dt += SHL(dtX, cShift); | |
| x += aaLevel; | |
| } | |
| cMask = aaColorMaskGet(); | |
| cShift = aaColorShiftGet(); | |
| while (x < rightX) { | |
| if (tileFlag) { | |
| ds = repeatValuemax(ds, bmWidth << 16); | |
| dt = repeatValuemax(dt, bmHeight << 16); | |
| } | |
| xp = ds >> 16; | |
| yp = dt >> 16; | |
| if (!tileFlag) { | |
| xp = clampValuemax(xp, bmWidth); | |
| yp = clampValuemax(yp, bmHeight); | |
| } | |
| if ((xp >= 0) && ((yp >= 0) && ((xp < bmWidth) && (yp < bmHeight)))) { | |
| fillValue = bitmapValuebitsatXy(bmFill, bits, xp, yp); | |
| fillValue = SHR((fillValue & cMask), cShift); | |
| idx = SHR(x, baseShift); | |
| spanBuffer[idx] = (spanBuffer[idx] + fillValue); | |
| } | |
| ds += dsX; | |
| dt += dtX; | |
| ++x; | |
| } | |
| } | |
| /* Fill the span buffer between leftEdge and rightEdge with the given pixel value. */ | |
| function fillColorSpanfromto(pixelValue32, leftX, rightX) { | |
| var x0; | |
| var x1; | |
| /* Use a unrolled version for anti-aliased fills... */ | |
| if (aaLevelGet() !== 1) { | |
| return fillColorSpanAAx0x1(pixelValue32, leftX, rightX); | |
| } | |
| x0 = leftX; | |
| /* Unroll the inner loop four times, since we're only storing data. */ | |
| x1 = rightX; | |
| while ((x0 + 4) < x1) { | |
| spanBuffer[x0] = pixelValue32; | |
| spanBuffer[x0 + 1] = pixelValue32; | |
| spanBuffer[x0 + 2] = pixelValue32; | |
| spanBuffer[x0 + 3] = pixelValue32; | |
| x0 += 4; | |
| } | |
| while (x0 < x1) { | |
| spanBuffer[x0] = pixelValue32; | |
| ++x0; | |
| } | |
| } | |
| /* This is the inner loop for solid color fills with anti-aliasing. | |
| This loop has been unrolled for speed and quality into three parts: | |
| a) copy all pixels that fall into the first full pixel. | |
| b) copy aaLevel pixels between the first and the last full pixel | |
| c) copy all pixels that fall in the last full pixel */ | |
| function fillColorSpanAAx0x1(pixelValue32, leftX, rightX) { | |
| var aaLevel; | |
| var baseShift; | |
| var colorMask; | |
| var firstPixel; | |
| var idx; | |
| var lastPixel; | |
| var pv32; | |
| var x; | |
| /* Not now -- maybe later */ | |
| /* Compute the pixel boundaries. */ | |
| firstPixel = aaFirstPixelFromto(leftX, rightX); | |
| lastPixel = aaLastPixelFromto(leftX, rightX); | |
| aaLevel = aaLevelGet(); | |
| baseShift = aaShiftGet(); | |
| /* Part a: Deal with the first n sub-pixels */ | |
| x = leftX; | |
| if (x < firstPixel) { | |
| pv32 = SHR((pixelValue32 & aaColorMaskGet()), aaColorShiftGet()); | |
| while (x < firstPixel) { | |
| idx = SHR(x, baseShift); | |
| spanBuffer[idx] = (spanBuffer[idx] + pv32); | |
| ++x; | |
| } | |
| } | |
| if (x < lastPixel) { | |
| colorMask = (SHR(aaColorMaskGet(), aaShiftGet())) | 4042322160; | |
| pv32 = SHR((pixelValue32 & colorMask), aaShiftGet()); | |
| while (x < lastPixel) { | |
| idx = SHR(x, baseShift); | |
| spanBuffer[idx] = (spanBuffer[idx] + pv32); | |
| x += aaLevel; | |
| } | |
| } | |
| if (x < rightX) { | |
| pv32 = SHR((pixelValue32 & aaColorMaskGet()), aaColorShiftGet()); | |
| while (x < rightX) { | |
| idx = SHR(x, baseShift); | |
| spanBuffer[idx] = (spanBuffer[idx] + pv32); | |
| ++x; | |
| } | |
| } | |
| } | |
| function fillDirectionXOf(fill) { | |
| return objat(fill, GFDirectionX); | |
| } | |
| function fillDirectionXOfput(fill, value) { | |
| return objatput(fill, GFDirectionX, value); | |
| } | |
| function fillDirectionYOf(fill) { | |
| return objat(fill, GFDirectionY); | |
| } | |
| function fillDirectionYOfput(fill, value) { | |
| return objatput(fill, GFDirectionY, value); | |
| } | |
| function fillLinearGradient() { | |
| return fillLinearGradientfromtoat(lastExportedFillGet(), lastExportedLeftXGet(), lastExportedRightXGet(), currentYGet()); | |
| } | |
| /* Draw a linear gradient fill. */ | |
| function fillLinearGradientfromtoat(fill, leftX, rightX, yValue) { | |
| var ds; | |
| var dsX; | |
| var ramp; | |
| var rampIndex; | |
| var rampSize; | |
| var x; | |
| var x0; | |
| var x1; | |
| ramp = gradientRampOf(fill); | |
| rampSize = gradientRampLengthOf(fill); | |
| dsX = fillDirectionXOf(fill); | |
| ds = ((leftX - fillOriginXOf(fill)) * dsX) + ((yValue - fillOriginYOf(fill)) * fillDirectionYOf(fill)); | |
| x = (x0 = leftX); | |
| /* Note: The inner loop has been divided into three parts for speed */ | |
| /* Part one: Fill everything outside the left boundary */ | |
| x1 = rightX; | |
| while (((((rampIndex = ds >> 16)) < 0) || (rampIndex >= rampSize)) && (x < x1)) { | |
| ++x; | |
| ds += dsX; | |
| } | |
| if (x > x0) { | |
| if (rampIndex < 0) { | |
| rampIndex = 0; | |
| } | |
| if (rampIndex >= rampSize) { | |
| rampIndex = rampSize - 1; | |
| } | |
| fillColorSpanfromto(ramp[rampIndex], x0, x); | |
| } | |
| if (aaLevelGet() === 1) { | |
| /* Fast version w/o anti-aliasing */ | |
| while (((((rampIndex = ds >> 16)) < rampSize) && (rampIndex >= 0)) && (x < x1)) { | |
| spanBuffer[x] = ramp[rampIndex]; | |
| ++x; | |
| ds += dsX; | |
| } | |
| } else { | |
| x = fillLinearGradientAArampdsdsXfromto(fill, ramp, ds, dsX, x, rightX); | |
| } | |
| if (x < x1) { | |
| if (rampIndex < 0) { | |
| rampIndex = 0; | |
| } | |
| if (rampIndex >= rampSize) { | |
| rampIndex = rampSize - 1; | |
| } | |
| fillColorSpanfromto(ramp[rampIndex], x, x1); | |
| } | |
| } | |
| /* This is the AA version of linear gradient filling. */ | |
| function fillLinearGradientAArampdsdsXfromto(fill, ramp, deltaS, dsX, leftX, rightX) { | |
| var aaLevel; | |
| var baseShift; | |
| var colorMask; | |
| var colorShift; | |
| var ds; | |
| var firstPixel; | |
| var idx; | |
| var lastPixel; | |
| var rampIndex; | |
| var rampSize; | |
| var rampValue; | |
| var x; | |
| aaLevel = aaLevelGet(); | |
| baseShift = aaShiftGet(); | |
| rampSize = gradientRampLengthOf(fill); | |
| ds = deltaS; | |
| x = leftX; | |
| rampIndex = ds >> 16; | |
| firstPixel = aaFirstPixelFromto(leftX, rightX); | |
| /* Deal with the first n sub-pixels */ | |
| lastPixel = aaLastPixelFromto(leftX, rightX); | |
| colorMask = aaColorMaskGet(); | |
| colorShift = aaColorShiftGet(); | |
| while ((x < firstPixel) && ((rampIndex < rampSize) && (rampIndex >= 0))) { | |
| rampValue = ramp[rampIndex]; | |
| /* Copy as many pixels as possible */ | |
| rampValue = SHR((rampValue & colorMask), colorShift); | |
| while ((x < firstPixel) && ((ds >> 16) === rampIndex)) { | |
| idx = SHR(x, baseShift); | |
| spanBuffer[idx] = (spanBuffer[idx] + rampValue); | |
| ++x; | |
| ds += dsX; | |
| } | |
| rampIndex = ds >> 16; | |
| } | |
| colorMask = (SHR(aaColorMaskGet(), aaShiftGet())) | 4042322160; | |
| colorShift = aaShiftGet(); | |
| while ((x < lastPixel) && ((rampIndex < rampSize) && (rampIndex >= 0))) { | |
| rampValue = ramp[rampIndex]; | |
| /* Copy as many pixels as possible */ | |
| rampValue = SHR((rampValue & colorMask), colorShift); | |
| while ((x < lastPixel) && ((ds >> 16) === rampIndex)) { | |
| idx = SHR(x, baseShift); | |
| spanBuffer[idx] = (spanBuffer[idx] + rampValue); | |
| x += aaLevel; | |
| ds += SHL(dsX, colorShift); | |
| } | |
| rampIndex = ds >> 16; | |
| } | |
| colorMask = aaColorMaskGet(); | |
| colorShift = aaColorShiftGet(); | |
| while ((x < rightX) && ((rampIndex < rampSize) && (rampIndex >= 0))) { | |
| rampValue = ramp[rampIndex]; | |
| /* Copy as many pixels as possible */ | |
| rampValue = SHR((rampValue & colorMask), colorShift); | |
| while ((x < rightX) && ((ds >> 16) === rampIndex)) { | |
| idx = SHR(x, baseShift); | |
| spanBuffer[idx] = (spanBuffer[idx] + rampValue); | |
| ++x; | |
| ds += dsX; | |
| } | |
| rampIndex = ds >> 16; | |
| } | |
| return x; | |
| } | |
| function fillMaxXGet() { | |
| return workBuffer[GWFillMaxX]; | |
| } | |
| function fillMaxXPut(value) { | |
| return workBuffer[GWFillMaxX] = value; | |
| } | |
| function fillMaxYGet() { | |
| return workBuffer[GWFillMaxY]; | |
| } | |
| function fillMaxYPut(value) { | |
| return workBuffer[GWFillMaxY] = value; | |
| } | |
| function fillMinXGet() { | |
| return workBuffer[GWFillMinX]; | |
| } | |
| function fillMinXPut(value) { | |
| return workBuffer[GWFillMinX] = value; | |
| } | |
| function fillMinYGet() { | |
| return workBuffer[GWFillMinY]; | |
| } | |
| function fillMinYPut(value) { | |
| return workBuffer[GWFillMinY] = value; | |
| } | |
| function fillNormalXOf(fill) { | |
| return objat(fill, GFNormalX); | |
| } | |
| function fillNormalXOfput(fill, value) { | |
| return objatput(fill, GFNormalX, value); | |
| } | |
| function fillNormalYOf(fill) { | |
| return objat(fill, GFNormalY); | |
| } | |
| function fillNormalYOfput(fill, value) { | |
| return objatput(fill, GFNormalY, value); | |
| } | |
| function fillOriginXOf(fill) { | |
| return objat(fill, GFOriginX); | |
| } | |
| function fillOriginXOfput(fill, value) { | |
| return objatput(fill, GFOriginX, value); | |
| } | |
| function fillOriginYOf(fill) { | |
| return objat(fill, GFOriginY); | |
| } | |
| function fillOriginYOfput(fill, value) { | |
| return objatput(fill, GFOriginY, value); | |
| } | |
| /* Part 2a) Compute the decreasing part of the ramp */ | |
| function fillRadialDecreasingrampdeltaSTdsXdtXfromto(fill, ramp, deltaST, dsX, dtX, leftX, rightX) { | |
| var ds; | |
| var dt; | |
| var length2; | |
| var nextLength; | |
| var rampIndex; | |
| var rampValue; | |
| var x; | |
| var x1; | |
| ds = (deltaST[0]|0); | |
| dt = (deltaST[1]|0); | |
| rampIndex = accurateLengthOfwith(ds >> 16, dt >> 16); | |
| rampValue = ramp[rampIndex]; | |
| length2 = (rampIndex - 1) * (rampIndex - 1); | |
| x = leftX; | |
| x1 = rightX; | |
| if (x1 > fillOriginXOf(fill)) { | |
| x1 = fillOriginXOf(fill); | |
| } | |
| while (x < x1) { | |
| /* Try to copy the current value more than just once */ | |
| while ((x < x1) && (squaredLengthOfwith(ds >> 16, dt >> 16) >= length2)) { | |
| spanBuffer[x] = rampValue; | |
| ++x; | |
| ds += dsX; | |
| dt += dtX; | |
| } | |
| nextLength = squaredLengthOfwith(ds >> 16, dt >> 16); | |
| while (nextLength < length2) { | |
| --rampIndex; | |
| rampValue = ramp[rampIndex]; | |
| length2 = (rampIndex - 1) * (rampIndex - 1); | |
| } | |
| } | |
| deltaST[0] = ds; | |
| deltaST[1] = dt; | |
| return x; | |
| } | |
| /* Part 2a) Compute the decreasing part of the ramp */ | |
| function fillRadialDecreasingAArampdeltaSTdsXdtXfromto(fill, ramp, deltaST, dsX, dtX, leftX, rightX) { | |
| var aaLevel; | |
| var baseShift; | |
| var colorMask; | |
| var colorShift; | |
| var ds; | |
| var dt; | |
| var firstPixel; | |
| var index; | |
| var lastPixel; | |
| var length2; | |
| var nextLength; | |
| var rampIndex; | |
| var rampValue; | |
| var x; | |
| var x1; | |
| ds = (deltaST[0]|0); | |
| dt = (deltaST[1]|0); | |
| aaLevel = aaLevelGet(); | |
| baseShift = aaShiftGet(); | |
| rampIndex = accurateLengthOfwith(ds >> 16, dt >> 16); | |
| length2 = (rampIndex - 1) * (rampIndex - 1); | |
| x = leftX; | |
| x1 = fillOriginXOf(fill); | |
| if (x1 > rightX) { | |
| x1 = rightX; | |
| } | |
| firstPixel = aaFirstPixelFromto(leftX, x1); | |
| /* Deal with the first n sub-pixels */ | |
| lastPixel = aaLastPixelFromto(leftX, x1); | |
| if (x < firstPixel) { | |
| colorMask = aaColorMaskGet(); | |
| colorShift = aaColorShiftGet(); | |
| rampValue = ramp[rampIndex]; | |
| rampValue = SHR((rampValue & colorMask), colorShift); | |
| while (x < firstPixel) { | |
| /* Try to copy the current value more than just once */ | |
| while ((x < firstPixel) && (squaredLengthOfwith(ds >> 16, dt >> 16) >= length2)) { | |
| index = SHR(x, baseShift); | |
| spanBuffer[index] = (spanBuffer[index] + rampValue); | |
| ++x; | |
| ds += dsX; | |
| dt += dtX; | |
| } | |
| nextLength = squaredLengthOfwith(ds >> 16, dt >> 16); | |
| while (nextLength < length2) { | |
| --rampIndex; | |
| rampValue = ramp[rampIndex]; | |
| rampValue = SHR((rampValue & colorMask), colorShift); | |
| length2 = (rampIndex - 1) * (rampIndex - 1); | |
| } | |
| } | |
| } | |
| if (x < lastPixel) { | |
| colorMask = (SHR(aaColorMaskGet(), aaShiftGet())) | 4042322160; | |
| colorShift = aaShiftGet(); | |
| rampValue = ramp[rampIndex]; | |
| rampValue = SHR((rampValue & colorMask), colorShift); | |
| while (x < lastPixel) { | |
| /* Try to copy the current value more than just once */ | |
| while ((x < lastPixel) && (squaredLengthOfwith(ds >> 16, dt >> 16) >= length2)) { | |
| index = SHR(x, baseShift); | |
| spanBuffer[index] = (spanBuffer[index] + rampValue); | |
| x += aaLevel; | |
| ds += SHL(dsX, colorShift); | |
| dt += SHL(dtX, colorShift); | |
| } | |
| nextLength = squaredLengthOfwith(ds >> 16, dt >> 16); | |
| while (nextLength < length2) { | |
| --rampIndex; | |
| rampValue = ramp[rampIndex]; | |
| rampValue = SHR((rampValue & colorMask), colorShift); | |
| length2 = (rampIndex - 1) * (rampIndex - 1); | |
| } | |
| } | |
| } | |
| if (x < x1) { | |
| colorMask = aaColorMaskGet(); | |
| colorShift = aaColorShiftGet(); | |
| rampValue = ramp[rampIndex]; | |
| rampValue = SHR((rampValue & colorMask), colorShift); | |
| while (x < x1) { | |
| /* Try to copy the current value more than just once */ | |
| while ((x < x1) && (squaredLengthOfwith(ds >> 16, dt >> 16) >= length2)) { | |
| index = SHR(x, baseShift); | |
| spanBuffer[index] = (spanBuffer[index] + rampValue); | |
| ++x; | |
| ds += dsX; | |
| dt += dtX; | |
| } | |
| nextLength = squaredLengthOfwith(ds >> 16, dt >> 16); | |
| while (nextLength < length2) { | |
| --rampIndex; | |
| rampValue = ramp[rampIndex]; | |
| rampValue = SHR((rampValue & colorMask), colorShift); | |
| length2 = (rampIndex - 1) * (rampIndex - 1); | |
| } | |
| } | |
| } | |
| deltaST[0] = ds; | |
| deltaST[1] = dt; | |
| return x; | |
| } | |
| function fillRadialGradient() { | |
| return fillRadialGradientfromtoat(lastExportedFillGet(), lastExportedLeftXGet(), lastExportedRightXGet(), currentYGet()); | |
| } | |
| /* Draw a radial gradient fill. */ | |
| function fillRadialGradientfromtoat(fill, leftX, rightX, yValue) { | |
| var deltaST; | |
| var deltaX; | |
| var deltaY; | |
| var ds; | |
| var dsX; | |
| var dt; | |
| var dtX; | |
| var length2; | |
| var ramp; | |
| var rampSize; | |
| var x; | |
| var x1; | |
| ramp = gradientRampOf(fill); | |
| rampSize = gradientRampLengthOf(fill); | |
| deltaX = leftX - fillOriginXOf(fill); | |
| deltaY = yValue - fillOriginYOf(fill); | |
| dsX = fillDirectionXOf(fill); | |
| dtX = fillNormalXOf(fill); | |
| ds = (deltaX * dsX) + (deltaY * fillDirectionYOf(fill)); | |
| dt = (deltaX * dtX) + (deltaY * fillNormalYOf(fill)); | |
| x = leftX; | |
| /* Note: The inner loop has been divided into three parts for speed */ | |
| /* Part one: Fill everything outside the left boundary */ | |
| x1 = rightX; | |
| /* This is the upper bound */ | |
| length2 = (rampSize - 1) * (rampSize - 1); | |
| while ((squaredLengthOfwith(ds >> 16, dt >> 16) >= length2) && (x < x1)) { | |
| ++x; | |
| ds += dsX; | |
| dt += dtX; | |
| } | |
| if (x > leftX) { | |
| fillColorSpanfromto(ramp[rampSize - 1], leftX, x); | |
| } | |
| deltaST = point1Get(); | |
| deltaST[0] = ds; | |
| deltaST[1] = dt; | |
| if (x < fillOriginXOf(fill)) { | |
| /* Draw the decreasing part */ | |
| if (aaLevelGet() === 1) { | |
| x = fillRadialDecreasingrampdeltaSTdsXdtXfromto(fill, ramp, deltaST, dsX, dtX, x, x1); | |
| } else { | |
| x = fillRadialDecreasingAArampdeltaSTdsXdtXfromto(fill, ramp, deltaST, dsX, dtX, x, x1); | |
| } | |
| } | |
| if (x < x1) { | |
| /* Draw the increasing part */ | |
| if (aaLevelGet() === 1) { | |
| x = fillRadialIncreasingrampdeltaSTdsXdtXfromto(fill, ramp, deltaST, dsX, dtX, x, x1); | |
| } else { | |
| x = fillRadialIncreasingAArampdeltaSTdsXdtXfromto(fill, ramp, deltaST, dsX, dtX, x, x1); | |
| } | |
| } | |
| if (x < rightX) { | |
| fillColorSpanfromto(ramp[rampSize - 1], x, rightX); | |
| } | |
| } | |
| /* Part 2b) Compute the increasing part of the ramp */ | |
| function fillRadialIncreasingrampdeltaSTdsXdtXfromto(fill, ramp, deltaST, dsX, dtX, leftX, rightX) { | |
| var ds; | |
| var dt; | |
| var lastLength; | |
| var length2; | |
| var nextLength; | |
| var rampIndex; | |
| var rampSize; | |
| var rampValue; | |
| var x; | |
| var x1; | |
| ds = (deltaST[0]|0); | |
| dt = (deltaST[1]|0); | |
| rampIndex = accurateLengthOfwith(ds >> 16, dt >> 16); | |
| rampValue = ramp[rampIndex]; | |
| rampSize = gradientRampLengthOf(fill); | |
| /* This is the upper bound */ | |
| length2 = (rampSize - 1) * (rampSize - 1); | |
| nextLength = (rampIndex + 1) * (rampIndex + 1); | |
| lastLength = squaredLengthOfwith(ds >> 16, dt >> 16); | |
| x = leftX; | |
| x1 = rightX; | |
| while ((x < x1) && (lastLength < length2)) { | |
| /* Try to copy the current value more than once */ | |
| while ((x < x1) && (squaredLengthOfwith(ds >> 16, dt >> 16) <= nextLength)) { | |
| spanBuffer[x] = rampValue; | |
| ++x; | |
| ds += dsX; | |
| dt += dtX; | |
| } | |
| lastLength = squaredLengthOfwith(ds >> 16, dt >> 16); | |
| while (lastLength > nextLength) { | |
| ++rampIndex; | |
| rampValue = ramp[rampIndex]; | |
| nextLength = (rampIndex + 1) * (rampIndex + 1); | |
| } | |
| } | |
| deltaST[0] = ds; | |
| deltaST[1] = dt; | |
| return x; | |
| } | |
| /* Part 2b) Compute the increasing part of the ramp */ | |
| function fillRadialIncreasingAArampdeltaSTdsXdtXfromto(fill, ramp, deltaST, dsX, dtX, leftX, rightX) { | |
| var aaLevel; | |
| var baseShift; | |
| var colorMask; | |
| var colorShift; | |
| var ds; | |
| var dt; | |
| var firstPixel; | |
| var index; | |
| var lastLength; | |
| var lastPixel; | |
| var length2; | |
| var nextLength; | |
| var rampIndex; | |
| var rampSize; | |
| var rampValue; | |
| var x; | |
| ds = (deltaST[0]|0); | |
| dt = (deltaST[1]|0); | |
| aaLevel = aaLevelGet(); | |
| baseShift = aaShiftGet(); | |
| rampIndex = accurateLengthOfwith(ds >> 16, dt >> 16); | |
| rampSize = gradientRampLengthOf(fill); | |
| /* This is the upper bound */ | |
| length2 = (rampSize - 1) * (rampSize - 1); | |
| nextLength = (rampIndex + 1) * (rampIndex + 1); | |
| lastLength = squaredLengthOfwith(ds >> 16, dt >> 16); | |
| x = leftX; | |
| firstPixel = aaFirstPixelFromto(leftX, rightX); | |
| /* Deal with the first n subPixels */ | |
| lastPixel = aaLastPixelFromto(leftX, rightX); | |
| if ((x < firstPixel) && (lastLength < length2)) { | |
| colorMask = aaColorMaskGet(); | |
| colorShift = aaColorShiftGet(); | |
| rampValue = ramp[rampIndex]; | |
| rampValue = SHR((rampValue & colorMask), colorShift); | |
| while ((x < firstPixel) && (lastLength < length2)) { | |
| /* Try to copy the current value more than once */ | |
| while ((x < firstPixel) && (squaredLengthOfwith(ds >> 16, dt >> 16) <= nextLength)) { | |
| index = SHR(x, baseShift); | |
| spanBuffer[index] = (spanBuffer[index] + rampValue); | |
| ++x; | |
| ds += dsX; | |
| dt += dtX; | |
| } | |
| lastLength = squaredLengthOfwith(ds >> 16, dt >> 16); | |
| while (lastLength > nextLength) { | |
| ++rampIndex; | |
| rampValue = ramp[rampIndex]; | |
| rampValue = SHR((rampValue & colorMask), colorShift); | |
| nextLength = (rampIndex + 1) * (rampIndex + 1); | |
| } | |
| } | |
| } | |
| if ((x < lastPixel) && (lastLength < length2)) { | |
| colorMask = (SHR(aaColorMaskGet(), aaShiftGet())) | 4042322160; | |
| colorShift = aaShiftGet(); | |
| rampValue = ramp[rampIndex]; | |
| rampValue = SHR((rampValue & colorMask), colorShift); | |
| while ((x < lastPixel) && (lastLength < length2)) { | |
| /* Try to copy the current value more than once */ | |
| while ((x < lastPixel) && (squaredLengthOfwith(ds >> 16, dt >> 16) <= nextLength)) { | |
| index = SHR(x, baseShift); | |
| spanBuffer[index] = (spanBuffer[index] + rampValue); | |
| x += aaLevel; | |
| ds += SHL(dsX, colorShift); | |
| dt += SHL(dtX, colorShift); | |
| } | |
| lastLength = squaredLengthOfwith(ds >> 16, dt >> 16); | |
| while (lastLength > nextLength) { | |
| ++rampIndex; | |
| rampValue = ramp[rampIndex]; | |
| rampValue = SHR((rampValue & colorMask), colorShift); | |
| nextLength = (rampIndex + 1) * (rampIndex + 1); | |
| } | |
| } | |
| } | |
| if ((x < rightX) && (lastLength < length2)) { | |
| colorMask = aaColorMaskGet(); | |
| colorShift = aaColorShiftGet(); | |
| rampValue = ramp[rampIndex]; | |
| rampValue = SHR((rampValue & colorMask), colorShift); | |
| while ((x < rightX) && (lastLength < length2)) { | |
| /* Try to copy the current value more than once */ | |
| while ((x < rightX) && (squaredLengthOfwith(ds >> 16, dt >> 16) <= nextLength)) { | |
| index = SHR(x, baseShift); | |
| spanBuffer[index] = (spanBuffer[index] + rampValue); | |
| ++x; | |
| ds += dsX; | |
| dt += dtX; | |
| } | |
| lastLength = squaredLengthOfwith(ds >> 16, dt >> 16); | |
| while (lastLength > nextLength) { | |
| ++rampIndex; | |
| rampValue = ramp[rampIndex]; | |
| rampValue = SHR((rampValue & colorMask), colorShift); | |
| nextLength = (rampIndex + 1) * (rampIndex + 1); | |
| } | |
| } | |
| } | |
| deltaST[0] = ds; | |
| deltaST[1] = dt; | |
| return x; | |
| } | |
| /* Return true if fillEntry1 should be drawn before fillEntry2 */ | |
| function fillSortsbefore(fillEntry1, fillEntry2) { | |
| var diff; | |
| /* First check the depth value */ | |
| diff = stackFillDepth(fillEntry1) - stackFillDepth(fillEntry2); | |
| if (diff !== 0) { | |
| return diff > 0; | |
| } | |
| return (stackFillValue(fillEntry1)>>>0) < (stackFillValue(fillEntry2)>>>0); | |
| } | |
| /* Fill the span buffer from leftX to rightX with the given fill. | |
| Clip before performing any operations. Return true if the fill must | |
| be handled by some Smalltalk code. */ | |
| function fillSpanfromto(fill, leftX, rightX) { | |
| var type; | |
| var x0; | |
| var x1; | |
| if (fill === 0) { | |
| return false; | |
| } | |
| if (leftX < spanEndAAGet()) { | |
| x0 = spanEndAAGet(); | |
| } else { | |
| x0 = leftX; | |
| } | |
| if (rightX > (SHL(spanSizeGet(), aaShiftGet()))) { | |
| x1 = SHL(spanSizeGet(), aaShiftGet()); | |
| } else { | |
| x1 = rightX; | |
| } | |
| if (x0 < fillMinXGet()) { | |
| x0 = fillMinXGet(); | |
| } | |
| if (x1 > fillMaxXGet()) { | |
| x1 = fillMaxXGet(); | |
| } | |
| if (x0 < spanStartGet()) { | |
| spanStartPut(x0); | |
| } | |
| if (x1 > spanEndGet()) { | |
| spanEndPut(x1); | |
| } | |
| if (x1 > spanEndAAGet()) { | |
| spanEndAAPut(x1); | |
| } | |
| if (x0 >= x1) { | |
| return false; | |
| } | |
| if (isFillColor(fill)) { | |
| fillColorSpanfromto(fill, x0, x1); | |
| } else { | |
| /* Store the values for the dispatch */ | |
| lastExportedFillPut(fill); | |
| lastExportedLeftXPut(x0); | |
| lastExportedRightXPut(x1); | |
| type = fillTypeOf(fill); | |
| if (type <= 1) { | |
| return true; | |
| } | |
| switch (type) { | |
| case 0: | |
| case 1: | |
| errorWrongIndex(); | |
| break; | |
| case 2: | |
| fillLinearGradient(); | |
| break; | |
| case 3: | |
| fillRadialGradient(); | |
| break; | |
| case 4: | |
| case 5: | |
| fillBitmapSpan(); | |
| break; | |
| } | |
| } | |
| return false; | |
| } | |
| function fillTypeOf(fill) { | |
| return (objectTypeOf(fill) & GEPrimitiveFillMask) >>> 8; | |
| } | |
| /* Check the global edge table for any entries that cannot be handled by the engine itself. | |
| If there are any, return true. Otherwise, initialize the the edge and add it to the AET */ | |
| function findNextExternalEntryFromGET() { | |
| var edge; | |
| var type; | |
| var yValue; | |
| /* As long as we have entries in the GET */ | |
| yValue = currentYGet(); | |
| while (getStartGet() < getUsedGet()) { | |
| edge = getBuffer[getStartGet()]; | |
| if (edgeYValueOf(edge) > yValue) { | |
| return false; | |
| } | |
| type = objectTypeOf(edge); | |
| if ((type & GEPrimitiveWideMask) === GEPrimitiveEdge) { | |
| return true; | |
| } | |
| if (!needAvailableSpace(1)) { | |
| return false; | |
| } | |
| switch (type) { | |
| case 0: | |
| case 1: | |
| case 2: | |
| case 3: | |
| errorWrongIndex(); | |
| break; | |
| case 4: | |
| stepToFirstLine(); | |
| break; | |
| case 5: | |
| stepToFirstWideLine(); | |
| break; | |
| case 6: | |
| stepToFirstBezier(); | |
| break; | |
| case 7: | |
| stepToFirstWideBezier(); | |
| break; | |
| } | |
| insertEdgeIntoAET(edge); | |
| getStartPut(getStartGet() + 1); | |
| } | |
| return false; | |
| } | |
| /* Scan the active edge table. If there is any fill that cannot be handled by the engine itself, return true. Otherwise handle the fills and return false. */ | |
| /* self currentYGet >= 680 ifTrue:[ | |
| self printAET. | |
| self halt. | |
| ]. */ | |
| function findNextExternalFillFromAET() { | |
| var leftEdge; | |
| var leftX; | |
| var rightEdge; | |
| var rightX; | |
| leftX = (rightX = fillMaxXGet()); | |
| while (aetStartGet() < aetUsedGet()) { | |
| /* TODO: We should check if leftX from last operation | |
| is greater than leftX from next edge. | |
| Currently, we rely here on spanEndAA | |
| from the span buffer fill. */ | |
| leftEdge = (rightEdge = aetBuffer[aetStartGet()]); | |
| leftX = (rightX = edgeXValueOf(leftEdge)); | |
| if (leftX >= fillMaxXGet()) { | |
| return false; | |
| } | |
| quickRemoveInvalidFillsAt(leftX); | |
| if (isWide(leftEdge)) { | |
| toggleWideFillOf(leftEdge); | |
| } | |
| if (areEdgeFillsValid(leftEdge)) { | |
| toggleFillsOf(leftEdge); | |
| if (engineStopped) { | |
| return false; | |
| } | |
| } | |
| aetStartPut(aetStartGet() + 1); | |
| if (aetStartGet() < aetUsedGet()) { | |
| rightEdge = aetBuffer[aetStartGet()]; | |
| rightX = edgeXValueOf(rightEdge); | |
| if (rightX >= fillMinXGet()) { | |
| /* This is the visible portion */ | |
| fillAllFromto(leftX, rightX); | |
| } | |
| } | |
| } | |
| if (rightX < fillMaxXGet()) { | |
| fillAllFromto(rightX, fillMaxXGet()); | |
| } | |
| return false; | |
| } | |
| /* Check the active edge table for any entries that cannot be handled by the engine itself. | |
| If there are any, return true. Otherwise, step the the edge to the next y value. */ | |
| function findNextExternalUpdateFromAET() { | |
| var count; | |
| var edge; | |
| var type; | |
| while (aetStartGet() < aetUsedGet()) { | |
| edge = aetBuffer[aetStartGet()]; | |
| count = edgeNumLinesOf(edge) - 1; | |
| if (count === 0) { | |
| /* Edge at end -- remove it */ | |
| removeFirstAETEntry(); | |
| } else { | |
| /* Store remaining lines back */ | |
| edgeNumLinesOfput(edge, count); | |
| type = objectTypeOf(edge); | |
| if ((type & GEPrimitiveWideMask) === GEPrimitiveEdge) { | |
| return true; | |
| } | |
| switch (type) { | |
| case 0: | |
| case 1: | |
| case 2: | |
| case 3: | |
| errorWrongIndex(); | |
| break; | |
| case 4: | |
| stepToNextLine(); | |
| break; | |
| case 5: | |
| stepToNextWideLine(); | |
| break; | |
| case 6: | |
| stepToNextBezier(); | |
| break; | |
| case 7: | |
| stepToNextWideBezier(); | |
| break; | |
| } | |
| resortFirstAETEntry(); | |
| aetStartPut(aetStartGet() + 1); | |
| } | |
| } | |
| return false; | |
| } | |
| function findStackFilldepth(fillIndex, depth) { | |
| var index; | |
| index = 0; | |
| while ((index < stackFillSize()) && ((stackFillValue(index) !== fillIndex) || (stackFillDepth(index) !== depth))) { | |
| index += stackFillEntryLength(); | |
| } | |
| if (index >= stackFillSize()) { | |
| return -1; | |
| } else { | |
| return index; | |
| } | |
| } | |
| /* Return true if processing is finished */ | |
| function finishedProcessing() { | |
| return stateGet() === GEStateCompleted; | |
| } | |
| function freeStackFillEntry() { | |
| wbStackPop(stackFillEntryLength()); | |
| } | |
| /* 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! */ | |
| function getModuleName() { | |
| return moduleName; | |
| } | |
| /* Return true if the edge at index i should sort before the edge at index j. */ | |
| function getSortsbefore(edge1, edge2) { | |
| var diff; | |
| if (edge1 === edge2) { | |
| return true; | |
| } | |
| diff = edgeYValueOf(edge1) - edgeYValueOf(edge2); | |
| if (diff !== 0) { | |
| return diff < 0; | |
| } | |
| diff = edgeXValueOf(edge1) - edgeXValueOf(edge2); | |
| return diff < 0; | |
| } | |
| function getStartGet() { | |
| return workBuffer[GWGETStart]; | |
| } | |
| function getStartPut(value) { | |
| return workBuffer[GWGETStart] = value; | |
| } | |
| function getUsedGet() { | |
| return workBuffer[GWGETUsed]; | |
| } | |
| function getUsedPut(value) { | |
| return workBuffer[GWGETUsed] = value; | |
| } | |
| function gradientRampLengthOf(fill) { | |
| return objat(fill, GFRampLength); | |
| } | |
| function gradientRampLengthOfput(fill, value) { | |
| return objatput(fill, GFRampLength, value); | |
| } | |
| function gradientRampOf(fill) { | |
| return PTR_ADD(objBuffer, fill + GFRampOffset); | |
| } | |
| function halt() { | |
| ; | |
| } | |
| function hasColorTransform() { | |
| return hasColorTransformGet() !== 0; | |
| } | |
| function hasColorTransformGet() { | |
| return workBuffer[GWHasColorTransform]; | |
| } | |
| function hasColorTransformPut(value) { | |
| return workBuffer[GWHasColorTransform] = value; | |
| } | |
| function hasEdgeTransform() { | |
| return hasEdgeTransformGet() !== 0; | |
| } | |
| function hasEdgeTransformGet() { | |
| return workBuffer[GWHasEdgeTransform]; | |
| } | |
| function hasEdgeTransformPut(value) { | |
| return workBuffer[GWHasEdgeTransform] = value; | |
| } | |
| /* Make the fill style with the given index invisible */ | |
| function hideFilldepth(fillIndex, depth) { | |
| var index; | |
| var newDepth; | |
| var newRightX; | |
| var newTop; | |
| var newTopIndex; | |
| index = findStackFilldepth(fillIndex, depth); | |
| if (index === -1) { | |
| return false; | |
| } | |
| if (index === 0) { | |
| freeStackFillEntry(); | |
| return true; | |
| } | |
| stackFillValueput(index, stackFillValue(0)); | |
| stackFillDepthput(index, stackFillDepth(0)); | |
| stackFillRightXput(index, stackFillRightX(0)); | |
| freeStackFillEntry(); | |
| if (stackFillSize() <= stackFillEntryLength()) { | |
| return true; | |
| } | |
| newTopIndex = 0; | |
| index = stackFillEntryLength(); | |
| while (index < stackFillSize()) { | |
| if (fillSortsbefore(index, newTopIndex)) { | |
| newTopIndex = index; | |
| } | |
| index += stackFillEntryLength(); | |
| } | |
| if ((newTopIndex + stackFillEntryLength()) === stackFillSize()) { | |
| return true; | |
| } | |
| newTop = stackFillValue(newTopIndex); | |
| stackFillValueput(newTopIndex, topFillValue()); | |
| topFillValuePut(newTop); | |
| newDepth = stackFillDepth(newTopIndex); | |
| stackFillDepthput(newTopIndex, topFillDepth()); | |
| topFillDepthPut(newDepth); | |
| newRightX = stackFillRightX(newTopIndex); | |
| stackFillRightXput(newTopIndex, topFillRightX()); | |
| topFillRightXPut(newRightX); | |
| return true; | |
| } | |
| function incrementStatby(statIndex, value) { | |
| return workBuffer[statIndex] = (workBuffer[statIndex] + value); | |
| } | |
| /* Find insertion point for the given edge in the AET */ | |
| function indexForInsertingIntoAET(edge) { | |
| var index; | |
| var initialX; | |
| initialX = edgeXValueOf(edge); | |
| index = 0; | |
| while ((index < aetUsedGet()) && (edgeXValueOf(aetBuffer[index]) < initialX)) { | |
| ++index; | |
| } | |
| while ((index < aetUsedGet()) && ((edgeXValueOf(aetBuffer[index]) === initialX) && (getSortsbefore(aetBuffer[index], edge)))) { | |
| ++index; | |
| } | |
| return index; | |
| } | |
| function initColorTransform() { | |
| var transform; | |
| transform = colorTransform(); | |
| transform[0] = 1.0; | |
| transform[1] = 0.0; | |
| transform[2] = 1.0; | |
| transform[3] = 0.0; | |
| transform[4] = 1.0; | |
| transform[5] = 0.0; | |
| transform[6] = 1.0; | |
| transform[7] = 0.0; | |
| hasColorTransformPut(0); | |
| } | |
| function initEdgeTransform() { | |
| var transform; | |
| transform = edgeTransform(); | |
| transform[0] = 1.0; | |
| transform[1] = 0.0; | |
| transform[2] = 0.0; | |
| transform[3] = 0.0; | |
| transform[4] = 1.0; | |
| transform[5] = 0.0; | |
| hasEdgeTransformPut(0); | |
| } | |
| function initialiseModule() { | |
| loadBBFn = interpreterProxy.ioLoadFunctionFrom("loadBitBltFrom", bbPluginName); | |
| copyBitsFn = interpreterProxy.ioLoadFunctionFrom("copyBitsFromtoat", bbPluginName); | |
| return (!!loadBBFn) && (!!copyBitsFn); | |
| } | |
| /* Initialization stuff that needs to be done before any processing can take place. */ | |
| /* Make sure aaLevel is initialized */ | |
| function initializeGETProcessing() { | |
| setAALevel(aaLevelGet()); | |
| if (clipMinXGet() < 0) { | |
| clipMinXPut(0); | |
| } | |
| if (clipMaxXGet() > spanSizeGet()) { | |
| clipMaxXPut(spanSizeGet()); | |
| } | |
| fillMinXPut(SHL(clipMinXGet(), aaShiftGet())); | |
| fillMinYPut(SHL(clipMinYGet(), aaShiftGet())); | |
| fillMaxXPut(SHL(clipMaxXGet(), aaShiftGet())); | |
| fillMaxYPut(SHL(clipMaxYGet(), aaShiftGet())); | |
| getUsedPut(0); | |
| aetUsedPut(0); | |
| getBuffer = PTR_ADD(objBuffer, objUsed); | |
| /* Create the global edge table */ | |
| aetBuffer = PTR_ADD(objBuffer, objUsed); | |
| createGlobalEdgeTable(); | |
| if (engineStopped) { | |
| return null; | |
| } | |
| if (getUsedGet() === 0) { | |
| /* Nothing to do */ | |
| currentYPut(fillMaxYGet()); | |
| return 0; | |
| } | |
| sortGlobalEdgeTable(); | |
| currentYPut(edgeYValueOf(getBuffer[0])); | |
| if (currentYGet() < fillMinYGet()) { | |
| currentYPut(fillMinYGet()); | |
| } | |
| spanStartPut(0); | |
| spanEndPut((SHL(spanSizeGet(), aaShiftGet())) - 1); | |
| clearSpanBuffer(); | |
| } | |
| /* Insert the edge with the given index from the global edge table into the active edge table. | |
| The edge has already been stepped to the initial yValue -- thus remainingLines and rasterX | |
| are both set. */ | |
| function insertEdgeIntoAET(edge) { | |
| var index; | |
| /* Check for the number of lines remaining */ | |
| if (edgeNumLinesOf(edge) <= 0) { | |
| return null; | |
| } | |
| /* And insert edge */ | |
| index = indexForInsertingIntoAET(edge); | |
| insertToAETbeforeIndex(edge, index); | |
| } | |
| /* Insert the given edge into the AET. */ | |
| function insertToAETbeforeIndex(edge, index) { | |
| var i; | |
| /* Make sure we have space in the AET */ | |
| if (!allocateAETEntry(1)) { | |
| return null; | |
| } | |
| i = aetUsedGet() - 1; | |
| while (!(i < index)) { | |
| aetBuffer[i + 1] = aetBuffer[i]; | |
| --i; | |
| } | |
| aetBuffer[index] = edge; | |
| aetUsedPut(aetUsedGet() + 1); | |
| } | |
| function isBezier(bezier) { | |
| return (objectTypeOf(bezier) & GEPrimitiveWideMask) === GEPrimitiveBezier; | |
| } | |
| function isEdge(edge) { | |
| var type; | |
| type = objectTypeOf(edge); | |
| if (type > GEPrimitiveEdgeMask) { | |
| return false; | |
| } | |
| return (objectTypeOf(edge) & GEPrimitiveEdgeMask) !== 0; | |
| } | |
| function isFill(fill) { | |
| return isFillColor(fill) || (isRealFill(fill)); | |
| } | |
| function isFillColor(fill) { | |
| return (fill & 4278190080) !== 0; | |
| } | |
| function isFillOkay(fill) { | |
| return (fill === 0) || (isFillColor(fill) || (isObject(fill) && (isFill(fill)))); | |
| } | |
| function isLine(line) { | |
| return (objectTypeOf(line) & GEPrimitiveWideMask) === GEPrimitiveLine; | |
| } | |
| function isObject(obj) { | |
| return (obj >= 0) && (obj < objUsed); | |
| } | |
| function isRealFill(fill) { | |
| return (objectTypeOf(fill) & GEPrimitiveFillMask) !== 0; | |
| } | |
| function isWide(object) { | |
| return (objectTypeOf(object) & GEPrimitiveWide) !== 0; | |
| } | |
| function lastExportedEdgeGet() { | |
| return workBuffer[GWLastExportedEdge]; | |
| } | |
| function lastExportedEdgePut(value) { | |
| return workBuffer[GWLastExportedEdge] = value; | |
| } | |
| function lastExportedFillGet() { | |
| return workBuffer[GWLastExportedFill]; | |
| } | |
| function lastExportedFillPut(value) { | |
| return workBuffer[GWLastExportedFill] = value; | |
| } | |
| function lastExportedLeftXGet() { | |
| return workBuffer[GWLastExportedLeftX]; | |
| } | |
| function lastExportedLeftXPut(value) { | |
| return workBuffer[GWLastExportedLeftX] = value; | |
| } | |
| function lastExportedRightXGet() { | |
| return workBuffer[GWLastExportedRightX]; | |
| } | |
| function lastExportedRightXPut(value) { | |
| return workBuffer[GWLastExportedRightX] = value; | |
| } | |
| function lineEndXOf(line) { | |
| return objat(line, GLEndX); | |
| } | |
| function lineEndXOfput(line, value) { | |
| return objatput(line, GLEndX, value); | |
| } | |
| function lineEndYOf(line) { | |
| return objat(line, GLEndY); | |
| } | |
| function lineEndYOfput(line, value) { | |
| return objatput(line, GLEndY, value); | |
| } | |
| function lineErrorAdjDownOf(line) { | |
| return objat(line, GLErrorAdjDown); | |
| } | |
| function lineErrorAdjDownOfput(line, value) { | |
| return objatput(line, GLErrorAdjDown, value); | |
| } | |
| function lineErrorAdjUpOf(line) { | |
| return objat(line, GLErrorAdjUp); | |
| } | |
| function lineErrorAdjUpOfput(line, value) { | |
| return objatput(line, GLErrorAdjUp, value); | |
| } | |
| function lineErrorOf(line) { | |
| return objat(line, GLError); | |
| } | |
| function lineErrorOfput(line, value) { | |
| return objatput(line, GLError, value); | |
| } | |
| function lineXDirectionOf(line) { | |
| return objat(line, GLXDirection); | |
| } | |
| function lineXDirectionOfput(line, value) { | |
| return objatput(line, GLXDirection, value); | |
| } | |
| function lineXIncrementOf(line) { | |
| return objat(line, GLXIncrement); | |
| } | |
| function lineXIncrementOfput(line, value) { | |
| return objatput(line, GLXIncrement, value); | |
| } | |
| function lineYDirectionOfput(line, value) { | |
| return objatput(line, GLYDirection, value); | |
| } | |
| /* Load and subdivide the bezier curve from point1/point2/point3. | |
| If wideFlag is set then make sure the curve is monoton in X. */ | |
| function loadAndSubdivideBezierFromviatoisWide(point1, point2, point3, wideFlag) { | |
| var bz1; | |
| var bz2; | |
| var index; | |
| var index1; | |
| var index2; | |
| bz1 = allocateBezierStackEntry(); | |
| if (engineStopped) { | |
| return 0; | |
| } | |
| bzStartXput(bz1, point1[0]); | |
| bzStartYput(bz1, point1[1]); | |
| bzViaXput(bz1, point2[0]); | |
| bzViaYput(bz1, point2[1]); | |
| bzEndXput(bz1, point3[0]); | |
| bzEndYput(bz1, point3[1]); | |
| index2 = (bz2 = subdivideToBeMonotoninX(bz1, wideFlag)); | |
| for (index = bz1; index <= bz2; index += 6) { | |
| index1 = subdivideBezierFrom(index); | |
| if (index1 > index2) { | |
| index2 = index1; | |
| } | |
| if (engineStopped) { | |
| return 0; | |
| } | |
| } | |
| return DIV(index2, 6); | |
| } | |
| function loadArrayPolygonnPointsfilllineWidthlineFill(points, nPoints, fillIndex, lineWidth, lineFill) { | |
| var i; | |
| var x0; | |
| var x1; | |
| var y0; | |
| var y1; | |
| loadPointfrom(point1Get(), interpreterProxy.fetchPointerofObject(0, points)); | |
| if (interpreterProxy.failed()) { | |
| return null; | |
| } | |
| x0 = point1Get()[0]; | |
| y0 = point1Get()[1]; | |
| for (i = 1; i <= (nPoints - 1); i++) { | |
| loadPointfrom(point1Get(), interpreterProxy.fetchPointerofObject(i, points)); | |
| if (interpreterProxy.failed()) { | |
| return null; | |
| } | |
| x1 = point1Get()[0]; | |
| y1 = point1Get()[1]; | |
| point1Get()[0] = x0; | |
| point1Get()[1] = y0; | |
| point2Get()[0] = x1; | |
| point2Get()[1] = y1; | |
| transformPoints(2); | |
| loadWideLinefromtolineFillleftFillrightFill(lineWidth, point1Get(), point2Get(), lineFill, fillIndex, 0); | |
| if (engineStopped) { | |
| return null; | |
| } | |
| x0 = x1; | |
| y0 = y1; | |
| } | |
| } | |
| function loadArrayShapenSegmentsfilllineWidthlineFill(points, nSegments, fillIndex, lineWidth, lineFill) { | |
| var i; | |
| var pointOop; | |
| var segs; | |
| var x0; | |
| var x1; | |
| var x2; | |
| var y0; | |
| var y1; | |
| var y2; | |
| for (i = 0; i <= (nSegments - 1); i++) { | |
| pointOop = interpreterProxy.fetchPointerofObject(i * 3, points); | |
| loadPointfrom(point1Get(), pointOop); | |
| pointOop = interpreterProxy.fetchPointerofObject((i * 3) + 1, points); | |
| loadPointfrom(point2Get(), pointOop); | |
| pointOop = interpreterProxy.fetchPointerofObject((i * 3) + 2, points); | |
| loadPointfrom(point3Get(), pointOop); | |
| if (interpreterProxy.failed()) { | |
| return null; | |
| } | |
| transformPoints(3); | |
| x0 = point1Get()[0]; | |
| y0 = point1Get()[1]; | |
| x1 = point2Get()[0]; | |
| y1 = point2Get()[1]; | |
| x2 = point3Get()[0]; | |
| /* Check if we can use a line */ | |
| y2 = point3Get()[1]; | |
| if (((x0 === y0) && (x1 === y1)) || ((x1 === x2) && (y1 === y2))) { | |
| loadWideLinefromtolineFillleftFillrightFill(lineWidth, point1Get(), point3Get(), lineFill, fillIndex, 0); | |
| } else { | |
| /* Need bezier */ | |
| segs = loadAndSubdivideBezierFromviatoisWide(point1Get(), point2Get(), point3Get(), (lineWidth !== 0) && (lineFill !== 0)); | |
| if (engineStopped) { | |
| return null; | |
| } | |
| loadWideBezierlineFillleftFillrightFilln(lineWidth, lineFill, fillIndex, 0, segs); | |
| } | |
| if (engineStopped) { | |
| return null; | |
| } | |
| } | |
| } | |
| /* Load a transformation from the given array. */ | |
| function loadArrayTransformFromintolength(transformOop, destPtr, n) { | |
| var i; | |
| var value; | |
| for (i = 0; i <= (n - 1); i++) { | |
| value = interpreterProxy.fetchPointerofObject(i, transformOop); | |
| if (!(typeof value === "number" || (value.isFloat))) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| if (typeof value === "number") { | |
| destPtr[i] = value; | |
| } else { | |
| destPtr[i] = interpreterProxy.floatValueOf(value); | |
| } | |
| } | |
| } | |
| /* Initialize the bezier segment stored on the stack */ | |
| function loadBeziersegmentleftFillrightFilloffset(bezier, index, leftFillIndex, rightFillIndex, yOffset) { | |
| if (bzEndY(index) >= bzStartY(index)) { | |
| /* Top to bottom */ | |
| edgeXValueOfput(bezier, bzStartX(index)); | |
| edgeYValueOfput(bezier, bzStartY(index) - yOffset); | |
| bezierViaXOfput(bezier, bzViaX(index)); | |
| bezierViaYOfput(bezier, bzViaY(index) - yOffset); | |
| bezierEndXOfput(bezier, bzEndX(index)); | |
| bezierEndYOfput(bezier, bzEndY(index) - yOffset); | |
| } else { | |
| edgeXValueOfput(bezier, bzEndX(index)); | |
| edgeYValueOfput(bezier, bzEndY(index) - yOffset); | |
| bezierViaXOfput(bezier, bzViaX(index)); | |
| bezierViaYOfput(bezier, bzViaY(index) - yOffset); | |
| bezierEndXOfput(bezier, bzStartX(index)); | |
| bezierEndYOfput(bezier, bzStartY(index) - yOffset); | |
| } | |
| edgeZValueOfput(bezier, currentZGet()); | |
| edgeLeftFillOfput(bezier, leftFillIndex); | |
| edgeRightFillOfput(bezier, rightFillIndex); | |
| } | |
| function loadBitBltFrom(bbObj) { | |
| if (!loadBBFn) { | |
| /* We need copyBits here so try to load it implicitly */ | |
| if (!initialiseModule()) { | |
| return false; | |
| } | |
| } | |
| return loadBBFn(bbObj); | |
| } | |
| /* Load the bitmap fill. */ | |
| function loadBitmapFillcolormaptilefromalongnormalxIndex(formOop, cmOop, tileFlag, point1, point2, point3, xIndex) { | |
| var bmBits; | |
| var bmBitsSize; | |
| var bmDepth; | |
| var bmFill; | |
| var bmHeight; | |
| var bmRaster; | |
| var bmWidth; | |
| var cmBits; | |
| var cmSize; | |
| var ppw; | |
| if (cmOop.isNil) { | |
| cmSize = 0; | |
| cmBits = null; | |
| } else { | |
| if (CLASSOF(cmOop) !== interpreterProxy.classBitmap()) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| cmSize = SIZEOF(cmOop); | |
| cmBits = cmOop.wordsAsInt32Array(); | |
| } | |
| if (typeof formOop === "number") { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| if (!interpreterProxy.isPointers(formOop)) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| if (SIZEOF(formOop) < 5) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| bmBits = interpreterProxy.fetchPointerofObject(0, formOop); | |
| if (CLASSOF(bmBits) !== interpreterProxy.classBitmap()) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| bmBitsSize = SIZEOF(bmBits); | |
| bmWidth = interpreterProxy.fetchIntegerofObject(1, formOop); | |
| bmHeight = interpreterProxy.fetchIntegerofObject(2, formOop); | |
| bmDepth = interpreterProxy.fetchIntegerofObject(3, formOop); | |
| if (interpreterProxy.failed()) { | |
| return null; | |
| } | |
| if (!((bmWidth >= 0) && (bmHeight >= 0))) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| if (!((((((bmDepth === 32) || (bmDepth === 8)) || (bmDepth === 16)) || (bmDepth === 1)) || (bmDepth === 2)) || (bmDepth === 4))) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| if (!((cmSize === 0) || (cmSize === (SHL(1, bmDepth))))) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| ppw = DIV(32, bmDepth); | |
| bmRaster = DIV((bmWidth + (ppw - 1)), ppw); | |
| if (bmBitsSize !== (bmRaster * bmHeight)) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| bmFill = allocateBitmapFillcolormap(cmSize, cmBits); | |
| if (engineStopped) { | |
| return null; | |
| } | |
| bitmapWidthOfput(bmFill, bmWidth); | |
| bitmapHeightOfput(bmFill, bmHeight); | |
| bitmapDepthOfput(bmFill, bmDepth); | |
| bitmapRasterOfput(bmFill, bmRaster); | |
| bitmapSizeOfput(bmFill, bmBitsSize); | |
| bitmapTileFlagOfput(bmFill, tileFlag); | |
| objectIndexOfput(bmFill, xIndex); | |
| loadFillOrientationfromalongnormalwidthheight(bmFill, point1, point2, point3, bmWidth, bmHeight); | |
| return bmFill; | |
| } | |
| /* Note: Assumes that the contents of formArray has been checked before */ | |
| function loadBitsFrom(bmFill) { | |
| var bitsLen; | |
| var bitsOop; | |
| var formOop; | |
| var xIndex; | |
| xIndex = objectIndexOf(bmFill); | |
| if (xIndex > SIZEOF(formArray)) { | |
| return null; | |
| } | |
| formOop = interpreterProxy.fetchPointerofObject(xIndex, formArray); | |
| bitsOop = interpreterProxy.fetchPointerofObject(0, formOop); | |
| bitsLen = SIZEOF(bitsOop); | |
| if (bitsLen !== bitmapSizeOf(bmFill)) { | |
| return null; | |
| } | |
| return bitsOop.wordsAsInt32Array(); | |
| } | |
| /* Load a 2x3 transformation matrix from the given oop. | |
| Return true if the matrix is not nil, false otherwise */ | |
| function loadColorTransformFrom(transformOop) { | |
| var okay; | |
| var transform; | |
| transform = colorTransform(); | |
| hasColorTransformPut(0); | |
| okay = loadTransformFromintolength(transformOop, transform, 8); | |
| if (!okay) { | |
| return false; | |
| } | |
| hasColorTransformPut(1); | |
| transform[1] = (transform[1] * 256.0); | |
| transform[3] = (transform[3] * 256.0); | |
| transform[5] = (transform[5] * 256.0); | |
| transform[7] = (transform[7] * 256.0); | |
| return okay; | |
| } | |
| /* Load the compressed segment identified by segment index */ | |
| function loadCompressedSegmentfromshortleftFillrightFilllineWidthlineColor(segmentIndex, points, pointsShort, leftFill, rightFill, lineWidth, lineFill) { | |
| var index; | |
| var segs; | |
| var x0; | |
| var x1; | |
| var x2; | |
| var y0; | |
| var y1; | |
| var y2; | |
| /* Check if have anything to do at all */ | |
| if ((leftFill === rightFill) && ((lineWidth === 0) || (lineFill === 0))) { | |
| return null; | |
| } | |
| /* 3 points with x/y each */ | |
| index = segmentIndex * 6; | |
| if (pointsShort) { | |
| /* Load short points */ | |
| x0 = (points.int16Array || (points.int16Array = new Int16Array(points.buffer, points.byteOffset)))[index + 0]; | |
| y0 = (points.int16Array || (points.int16Array = new Int16Array(points.buffer, points.byteOffset)))[index + 1]; | |
| x1 = (points.int16Array || (points.int16Array = new Int16Array(points.buffer, points.byteOffset)))[index + 2]; | |
| y1 = (points.int16Array || (points.int16Array = new Int16Array(points.buffer, points.byteOffset)))[index + 3]; | |
| x2 = (points.int16Array || (points.int16Array = new Int16Array(points.buffer, points.byteOffset)))[index + 4]; | |
| y2 = (points.int16Array || (points.int16Array = new Int16Array(points.buffer, points.byteOffset)))[index + 5]; | |
| } else { | |
| x0 = (points[(index + 0)]|0); | |
| y0 = (points[(index + 1)]|0); | |
| x1 = (points[(index + 2)]|0); | |
| y1 = (points[(index + 3)]|0); | |
| x2 = (points[(index + 4)]|0); | |
| y2 = (points[(index + 5)]|0); | |
| } | |
| if (((x0 === x1) && (y0 === y1)) || ((x1 === x2) && (y1 === y2))) { | |
| /* We can use a line from x0/y0 to x2/y2 */ | |
| if ((x0 === x2) && (y0 === y2)) { | |
| return null; | |
| } | |
| point1Get()[0] = x0; | |
| point1Get()[1] = y0; | |
| point2Get()[0] = x2; | |
| point2Get()[1] = y2; | |
| transformPoints(2); | |
| return loadWideLinefromtolineFillleftFillrightFill(lineWidth, point1Get(), point2Get(), lineFill, leftFill, rightFill); | |
| } | |
| point1Get()[0] = x0; | |
| point1Get()[1] = y0; | |
| point2Get()[0] = x1; | |
| point2Get()[1] = y1; | |
| point3Get()[0] = x2; | |
| point3Get()[1] = y2; | |
| transformPoints(3); | |
| segs = loadAndSubdivideBezierFromviatoisWide(point1Get(), point2Get(), point3Get(), (lineWidth !== 0) && (lineFill !== 0)); | |
| if (engineStopped) { | |
| return null; | |
| } | |
| loadWideBezierlineFillleftFillrightFilln(lineWidth, lineFill, leftFill, rightFill, segs); | |
| } | |
| /* Load a compressed shape into the engine. | |
| WARNING: THIS METHOD NEEDS THE FULL FRAME SIZE!!!! | |
| */ | |
| function loadCompressedShapesegmentsleftFillsrightFillslineWidthslineFillsfillIndexListpointShort(points, nSegments, leftFills, rightFills, lineWidths, lineFills, fillIndexList, pointsShort) { | |
| var i; | |
| var leftLength; | |
| var leftRun; | |
| var leftValue; | |
| var lineFillLength; | |
| var lineFillRun; | |
| var lineFillValue; | |
| var rightLength; | |
| var rightRun; | |
| var rightValue; | |
| var widthLength; | |
| var widthRun; | |
| var widthValue; | |
| if (nSegments === 0) { | |
| return 0; | |
| } | |
| leftRun = (rightRun = (widthRun = (lineFillRun = -1))); | |
| leftLength = (rightLength = (widthLength = (lineFillLength = 1))); | |
| leftValue = (rightValue = (widthValue = (lineFillValue = 0))); | |
| for (i = 1; i <= nSegments; i++) { | |
| /* Decrement current run length and load new stuff */ | |
| if (((--leftLength)) <= 0) { | |
| ++leftRun; | |
| leftLength = shortRunLengthAtfrom(leftRun, leftFills); | |
| leftValue = shortRunValueAtfrom(leftRun, leftFills); | |
| if (leftValue !== 0) { | |
| leftValue = fillIndexList[leftValue - 1]; | |
| leftValue = transformColor(leftValue); | |
| if (engineStopped) { | |
| return null; | |
| } | |
| } | |
| } | |
| if (((--rightLength)) <= 0) { | |
| ++rightRun; | |
| rightLength = shortRunLengthAtfrom(rightRun, rightFills); | |
| rightValue = shortRunValueAtfrom(rightRun, rightFills); | |
| if (rightValue !== 0) { | |
| rightValue = fillIndexList[rightValue - 1]; | |
| rightValue = transformColor(rightValue); | |
| } | |
| } | |
| if (((--widthLength)) <= 0) { | |
| ++widthRun; | |
| widthLength = shortRunLengthAtfrom(widthRun, lineWidths); | |
| widthValue = shortRunValueAtfrom(widthRun, lineWidths); | |
| if (widthValue !== 0) { | |
| widthValue = transformWidth(widthValue); | |
| } | |
| } | |
| if (((--lineFillLength)) <= 0) { | |
| ++lineFillRun; | |
| lineFillLength = shortRunLengthAtfrom(lineFillRun, lineFills); | |
| lineFillValue = shortRunValueAtfrom(lineFillRun, lineFills); | |
| if (lineFillValue !== 0) { | |
| lineFillValue = fillIndexList[lineFillValue - 1]; | |
| } | |
| } | |
| loadCompressedSegmentfromshortleftFillrightFilllineWidthlineColor(i - 1, points, pointsShort, leftValue, rightValue, widthValue, lineFillValue); | |
| if (engineStopped) { | |
| return null; | |
| } | |
| } | |
| } | |
| function loadEdgeStateFrom(edgeOop) { | |
| var edge; | |
| edge = lastExportedEdgeGet(); | |
| if (SIZEOF(edgeOop) < ETBalloonEdgeDataSize) { | |
| return null; | |
| } | |
| edgeXValueOfput(edge, interpreterProxy.fetchIntegerofObject(ETXValueIndex, edgeOop)); | |
| edgeYValueOfput(edge, interpreterProxy.fetchIntegerofObject(ETYValueIndex, edgeOop)); | |
| edgeZValueOfput(edge, interpreterProxy.fetchIntegerofObject(ETZValueIndex, edgeOop)); | |
| edgeNumLinesOfput(edge, interpreterProxy.fetchIntegerofObject(ETLinesIndex, edgeOop)); | |
| return edge; | |
| } | |
| /* Load a 2x3 transformation matrix from the given oop. | |
| Return true if the matrix is not nil, false otherwise */ | |
| function loadEdgeTransformFrom(transformOop) { | |
| var okay; | |
| var transform; | |
| hasEdgeTransformPut(0); | |
| transform = edgeTransform(); | |
| okay = loadTransformFromintolength(transformOop, transform, 6); | |
| if (interpreterProxy.failed()) { | |
| return null; | |
| } | |
| if (!okay) { | |
| return false; | |
| } | |
| hasEdgeTransformPut(1); | |
| transform[2] = (transform[2] + destOffsetXGet()); | |
| transform[5] = (transform[5] + destOffsetYGet()); | |
| return true; | |
| } | |
| /* Transform the points */ | |
| function loadFillOrientationfromalongnormalwidthheight(fill, point1, point2, point3, fillWidth, fillHeight) { | |
| var dirX; | |
| var dirY; | |
| var dsLength2; | |
| var dsX; | |
| var dsY; | |
| var dtLength2; | |
| var dtX; | |
| var dtY; | |
| var nrmX; | |
| var nrmY; | |
| point2[0] = (point2[0] + point1[0]); | |
| point2[1] = (point2[1] + point1[1]); | |
| point3[0] = (point3[0] + point1[0]); | |
| point3[1] = (point3[1] + point1[1]); | |
| transformPoint(point1); | |
| transformPoint(point2); | |
| transformPoint(point3); | |
| dirX = point2[0] - point1[0]; | |
| dirY = point2[1] - point1[1]; | |
| nrmX = point3[0] - point1[0]; | |
| /* Compute the scale from direction/normal into ramp size */ | |
| nrmY = point3[1] - point1[1]; | |
| dsLength2 = (dirX * dirX) + (dirY * dirY); | |
| if (dsLength2 > 0) { | |
| dsX = ((((dirX * fillWidth) * 65536.0) / dsLength2)|0); | |
| dsY = ((((dirY * fillWidth) * 65536.0) / dsLength2)|0); | |
| } else { | |
| dsX = 0; | |
| dsY = 0; | |
| } | |
| dtLength2 = (nrmX * nrmX) + (nrmY * nrmY); | |
| if (dtLength2 > 0) { | |
| dtX = ((((nrmX * fillHeight) * 65536.0) / dtLength2)|0); | |
| dtY = ((((nrmY * fillHeight) * 65536.0) / dtLength2)|0); | |
| } else { | |
| dtX = 0; | |
| dtY = 0; | |
| } | |
| fillOriginXOfput(fill, point1[0]); | |
| fillOriginYOfput(fill, point1[1]); | |
| fillDirectionXOfput(fill, dsX); | |
| fillDirectionYOfput(fill, dsY); | |
| fillNormalXOfput(fill, dtX); | |
| fillNormalYOfput(fill, dtY); | |
| } | |
| /* Check all the forms from arrayOop. */ | |
| function loadFormsFrom(arrayOop) { | |
| var bmBits; | |
| var bmBitsSize; | |
| var bmDepth; | |
| var bmHeight; | |
| var bmRaster; | |
| var bmWidth; | |
| var formOop; | |
| var i; | |
| var ppw; | |
| if (!interpreterProxy.isArray(arrayOop)) { | |
| return false; | |
| } | |
| formArray = arrayOop; | |
| for (i = 0; i <= (SIZEOF(formArray) - 1); i++) { | |
| formOop = interpreterProxy.fetchPointerofObject(i, formArray); | |
| if (typeof formOop === "number") { | |
| return false; | |
| } | |
| if (!interpreterProxy.isPointers(formOop)) { | |
| return false; | |
| } | |
| if (SIZEOF(formOop) < 5) { | |
| return false; | |
| } | |
| bmBits = interpreterProxy.fetchPointerofObject(0, formOop); | |
| if (CLASSOF(bmBits) !== interpreterProxy.classBitmap()) { | |
| return false; | |
| } | |
| bmBitsSize = SIZEOF(bmBits); | |
| bmWidth = interpreterProxy.fetchIntegerofObject(1, formOop); | |
| bmHeight = interpreterProxy.fetchIntegerofObject(2, formOop); | |
| bmDepth = interpreterProxy.fetchIntegerofObject(3, formOop); | |
| if (interpreterProxy.failed()) { | |
| return false; | |
| } | |
| if (!((bmWidth >= 0) && (bmHeight >= 0))) { | |
| return false; | |
| } | |
| ppw = DIV(32, bmDepth); | |
| bmRaster = DIV((bmWidth + (ppw - 1)), ppw); | |
| if (bmBitsSize !== (bmRaster * bmHeight)) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| /* Load the gradient fill as defined by the color ramp. */ | |
| function loadGradientFillfromalongnormalisRadial(rampOop, point1, point2, point3, isRadial) { | |
| var fill; | |
| var rampWidth; | |
| if (CLASSOF(rampOop) !== interpreterProxy.classBitmap()) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| rampWidth = SIZEOF(rampOop); | |
| fill = allocateGradientFillrampWidthisRadial(rampOop.wordsAsInt32Array(), rampWidth, isRadial); | |
| if (engineStopped) { | |
| return null; | |
| } | |
| loadFillOrientationfromalongnormalwidthheight(fill, point1, point2, point3, rampWidth, rampWidth); | |
| return fill; | |
| } | |
| /* Load the line defined by point1 and point2. */ | |
| function loadLinefromtooffsetleftFillrightFill(line, point1, point2, yOffset, leftFill, rightFill) { | |
| var p1; | |
| var p2; | |
| var yDir; | |
| if (point1[1] <= point2[1]) { | |
| p1 = point1; | |
| p2 = point2; | |
| yDir = 1; | |
| } else { | |
| p1 = point2; | |
| p2 = point1; | |
| yDir = -1; | |
| } | |
| edgeXValueOfput(line, p1[0]); | |
| edgeYValueOfput(line, p1[1] - yOffset); | |
| edgeZValueOfput(line, currentZGet()); | |
| edgeLeftFillOfput(line, leftFill); | |
| edgeRightFillOfput(line, rightFill); | |
| lineEndXOfput(line, p2[0]); | |
| lineEndYOfput(line, p2[1] - yOffset); | |
| lineYDirectionOfput(line, yDir); | |
| } | |
| /* Load a rectangular oval currently defined by point1/point2 */ | |
| function loadOvallineFillleftFillrightFill(lineWidth, lineFill, leftFill, rightFill) { | |
| var cx; | |
| var cy; | |
| var h; | |
| var i; | |
| var nSegments; | |
| var w; | |
| w = (point2Get()[0] - point1Get()[0]) >> 1; | |
| h = (point2Get()[1] - point1Get()[1]) >> 1; | |
| cx = (point2Get()[0] + point1Get()[0]) >> 1; | |
| cy = (point2Get()[1] + point1Get()[1]) >> 1; | |
| for (i = 0; i <= 15; i++) { | |
| loadOvalSegmentwhcxcy(i, w, h, cx, cy); | |
| transformPoints(3); | |
| nSegments = loadAndSubdivideBezierFromviatoisWide(point1Get(), point2Get(), point3Get(), (lineWidth !== 0) && (lineFill !== 0)); | |
| if (engineStopped) { | |
| return null; | |
| } | |
| loadWideBezierlineFillleftFillrightFilln(lineWidth, lineFill, leftFill, rightFill, nSegments); | |
| if (engineStopped) { | |
| return null; | |
| } | |
| } | |
| } | |
| function loadOvalSegmentwhcxcy(seg, w, h, cx, cy) { | |
| var x0; | |
| var x1; | |
| var x2; | |
| var y0; | |
| var y1; | |
| var y2; | |
| /* Load start point of segment */ | |
| x0 = (((circleCosTable()[(seg * 2) + 0] * w) + cx)|0); | |
| y0 = (((circleSinTable()[(seg * 2) + 0] * h) + cy)|0); | |
| point1Get()[0] = x0; | |
| point1Get()[1] = y0; | |
| x2 = (((circleCosTable()[(seg * 2) + 2] * w) + cx)|0); | |
| y2 = (((circleSinTable()[(seg * 2) + 2] * h) + cy)|0); | |
| point3Get()[0] = x2; | |
| point3Get()[1] = y2; | |
| x1 = (((circleCosTable()[(seg * 2) + 1] * w) + cx)|0); | |
| /* NOTE: The intermediate point is the point ON the curve | |
| and not yet the control point (which is OFF the curve) */ | |
| y1 = (((circleSinTable()[(seg * 2) + 1] * h) + cy)|0); | |
| x1 = (x1 * 2) - ((x0 + x2) >> 1); | |
| y1 = (y1 * 2) - ((y0 + y2) >> 1); | |
| point2Get()[0] = x1; | |
| point2Get()[1] = y1; | |
| } | |
| /* Load the contents of pointOop into pointArray */ | |
| function loadPointfrom(pointArray, pointOop) { | |
| var value; | |
| if (CLASSOF(pointOop) !== interpreterProxy.classPoint()) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| value = interpreterProxy.fetchPointerofObject(0, pointOop); | |
| if (!(typeof value === "number" || (value.isFloat))) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| if (typeof value === "number") { | |
| pointArray[0] = value; | |
| } else { | |
| pointArray[0] = (interpreterProxy.floatValueOf(value)|0); | |
| } | |
| value = interpreterProxy.fetchPointerofObject(1, pointOop); | |
| if (!(typeof value === "number" || (value.isFloat))) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| if (typeof value === "number") { | |
| pointArray[1] = value; | |
| } else { | |
| pointArray[1] = (interpreterProxy.floatValueOf(value)|0); | |
| } | |
| } | |
| function loadPolygonnPointsfilllineWidthlineFillpointsShort(points, nPoints, fillIndex, lineWidth, lineFill, isShort) { | |
| var i; | |
| var x0; | |
| var x1; | |
| var y0; | |
| var y1; | |
| if (isShort) { | |
| x0 = (points.int16Array || (points.int16Array = new Int16Array(points.buffer, points.byteOffset)))[0]; | |
| y0 = (points.int16Array || (points.int16Array = new Int16Array(points.buffer, points.byteOffset)))[1]; | |
| } else { | |
| x0 = (points[0]|0); | |
| y0 = (points[1]|0); | |
| } | |
| for (i = 1; i <= (nPoints - 1); i++) { | |
| if (isShort) { | |
| x1 = (points.int16Array || (points.int16Array = new Int16Array(points.buffer, points.byteOffset)))[i * 2]; | |
| y1 = (points.int16Array || (points.int16Array = new Int16Array(points.buffer, points.byteOffset)))[(i * 2) + 1]; | |
| } else { | |
| x1 = (points[(i * 2)]|0); | |
| y1 = (points[((i * 2) + 1)]|0); | |
| } | |
| point1Get()[0] = x0; | |
| point1Get()[1] = y0; | |
| point2Get()[0] = x1; | |
| point2Get()[1] = y1; | |
| transformPoints(2); | |
| loadWideLinefromtolineFillleftFillrightFill(lineWidth, point1Get(), point2Get(), lineFill, fillIndex, 0); | |
| if (engineStopped) { | |
| return null; | |
| } | |
| x0 = x1; | |
| y0 = y1; | |
| } | |
| } | |
| /* Load a rectangle currently defined by point1-point4 */ | |
| function loadRectanglelineFillleftFillrightFill(lineWidth, lineFill, leftFill, rightFill) { | |
| loadWideLinefromtolineFillleftFillrightFill(lineWidth, point1Get(), point2Get(), lineFill, leftFill, rightFill); | |
| loadWideLinefromtolineFillleftFillrightFill(lineWidth, point2Get(), point3Get(), lineFill, leftFill, rightFill); | |
| loadWideLinefromtolineFillleftFillrightFill(lineWidth, point3Get(), point4Get(), lineFill, leftFill, rightFill); | |
| loadWideLinefromtolineFillleftFillrightFill(lineWidth, point4Get(), point1Get(), lineFill, leftFill, rightFill); | |
| } | |
| /* Load the entire state from the interpreter for the rendering primitives. | |
| Answer 0 on success or a non-zero failure code on failure. */ | |
| function loadRenderingState() { | |
| var edgeOop; | |
| var failCode; | |
| var fillOop; | |
| var state; | |
| if (interpreterProxy.methodArgumentCount() !== 2) { | |
| return PrimErrBadNumArgs; | |
| } | |
| if (((failCode = quickLoadEngineFrom(interpreterProxy.stackValue(2)))) !== 0) { | |
| return failCode; | |
| } | |
| fillOop = interpreterProxy.stackObjectValue(0); | |
| edgeOop = interpreterProxy.stackObjectValue(1); | |
| if (interpreterProxy.failed()) { | |
| return PrimErrBadArgument; | |
| } | |
| if (((failCode = loadSpanBufferFrom(interpreterProxy.fetchPointerofObject(BESpanIndex, engine)))) !== 0) { | |
| return failCode; | |
| } | |
| if (!loadBitBltFrom(interpreterProxy.fetchPointerofObject(BEBitBltIndex, engine))) { | |
| return GEFBitBltLoadFailed; | |
| } | |
| if (!loadFormsFrom(interpreterProxy.fetchPointerofObject(BEFormsIndex, engine))) { | |
| return GEFFormLoadFailed; | |
| } | |
| if (SIZEOF(edgeOop) < ETBalloonEdgeDataSize) { | |
| return GEFEdgeDataTooSmall; | |
| } | |
| if (SIZEOF(fillOop) < FTBalloonFillDataSize) { | |
| return GEFFillDataTooSmall; | |
| } | |
| state = stateGet(); | |
| if ((state === GEStateWaitingForEdge) || ((state === GEStateWaitingForFill) || (state === GEStateWaitingChange))) { | |
| return GEFWrongState; | |
| } | |
| return 0; | |
| } | |
| function loadShapenSegmentsfilllineWidthlineFillpointsShort(points, nSegments, fillIndex, lineWidth, lineFill, pointsShort) { | |
| var i; | |
| for (i = 1; i <= nSegments; i++) { | |
| loadCompressedSegmentfromshortleftFillrightFilllineWidthlineColor(i - 1, points, pointsShort, fillIndex, 0, lineWidth, lineFill); | |
| if (engineStopped) { | |
| return null; | |
| } | |
| } | |
| } | |
| /* Load the span buffer from the given oop. | |
| Answer 0 on success or a non-zero failure code on failure. */ | |
| function loadSpanBufferFrom(spanOop) { | |
| if (CLASSOF(spanOop) !== interpreterProxy.classBitmap()) { | |
| return GEFClassMismatch; | |
| } | |
| /* Leave last entry unused to avoid complications */ | |
| spanBuffer = spanOop.words; | |
| spanSizePut(SIZEOF(spanOop) - 1); | |
| return 0; | |
| } | |
| /* Load a transformation from transformOop into the float array | |
| defined by destPtr. The transformation is assumed to be either | |
| an array or a FloatArray of length n. */ | |
| function loadTransformFromintolength(transformOop, destPtr, n) { | |
| if (transformOop.isNil) { | |
| return false; | |
| } | |
| if (typeof transformOop === "number") { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| if (SIZEOF(transformOop) !== n) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| if (interpreterProxy.isWords(transformOop)) { | |
| loadWordTransformFromintolength(transformOop, destPtr, n); | |
| } else { | |
| loadArrayTransformFromintolength(transformOop, destPtr, n); | |
| } | |
| return true; | |
| } | |
| /* Load the (possibly wide) bezier from the segments currently on the bezier stack. */ | |
| function loadWideBezierlineFillleftFillrightFilln(lineWidth, lineFill, leftFill, rightFill, nSegments) { | |
| var bezier; | |
| var index; | |
| var offset; | |
| var wide; | |
| if ((lineWidth === 0) || (lineFill === 0)) { | |
| wide = false; | |
| offset = 0; | |
| } else { | |
| wide = true; | |
| offset = offsetFromWidth(lineWidth); | |
| } | |
| index = nSegments * 6; | |
| while (index > 0) { | |
| if (wide) { | |
| bezier = allocateWideBezier(); | |
| } else { | |
| bezier = allocateBezier(); | |
| } | |
| if (engineStopped) { | |
| return 0; | |
| } | |
| loadBeziersegmentleftFillrightFilloffset(bezier, index, leftFill, rightFill, offset); | |
| if (wide) { | |
| wideBezierFillOfput(bezier, lineFill); | |
| wideBezierWidthOfput(bezier, lineWidth); | |
| wideBezierExtentOfput(bezier, lineWidth); | |
| } | |
| index -= 6; | |
| } | |
| wbStackClear(); | |
| } | |
| /* Load a (possibly wide) line defined by the points p1 and p2 */ | |
| function loadWideLinefromtolineFillleftFillrightFill(lineWidth, p1, p2, lineFill, leftFill, rightFill) { | |
| var line; | |
| var offset; | |
| if ((lineWidth === 0) || (lineFill === 0)) { | |
| line = allocateLine(); | |
| offset = 0; | |
| } else { | |
| line = allocateWideLine(); | |
| offset = offsetFromWidth(lineWidth); | |
| } | |
| if (engineStopped) { | |
| return 0; | |
| } | |
| loadLinefromtooffsetleftFillrightFill(line, p1, p2, offset, leftFill, rightFill); | |
| if (isWide(line)) { | |
| wideLineFillOfput(line, lineFill); | |
| wideLineWidthOfput(line, lineWidth); | |
| wideLineExtentOfput(line, lineWidth); | |
| } | |
| } | |
| /* Load a float array transformation from the given oop */ | |
| function loadWordTransformFromintolength(transformOop, destPtr, n) { | |
| var i; | |
| var srcPtr; | |
| srcPtr = transformOop.wordsAsFloat32Array(); | |
| for (i = 0; i <= (n - 1); i++) { | |
| destPtr[i] = srcPtr[i]; | |
| } | |
| } | |
| /* Load the working buffer from the given oop */ | |
| function loadWorkBufferFrom(wbOop) { | |
| if (typeof wbOop === "number") { | |
| return GEFWorkBufferIsInteger; | |
| } | |
| if (!interpreterProxy.isWords(wbOop)) { | |
| return GEFWorkBufferIsPointers; | |
| } | |
| if (SIZEOF(wbOop) < GWMinimalSize) { | |
| return GEFWorkBufferTooSmall; | |
| } | |
| workBufferPut(wbOop); | |
| if (magicNumberGet() !== GWMagicNumber) { | |
| return GEFWorkBufferBadMagic; | |
| } | |
| if (wbSizeGet() !== SIZEOF(wbOop)) { | |
| return GEFWorkBufferWrongSize; | |
| } | |
| if (objStartGet() !== GWHeaderSize) { | |
| return GEFWorkBufferStartWrong; | |
| } | |
| objBuffer = PTR_ADD(workBuffer, objStartGet()); | |
| getBuffer = PTR_ADD(objBuffer, objUsedGet()); | |
| /* Make sure we don't exceed the work buffer */ | |
| aetBuffer = PTR_ADD(getBuffer, getUsedGet()); | |
| if ((((GWHeaderSize + objUsedGet()) + getUsedGet()) + aetUsedGet()) > wbSizeGet()) { | |
| return GEFWorkTooBig; | |
| } | |
| return 0; | |
| } | |
| function magicNumberGet() { | |
| return workBuffer[GWMagicIndex]; | |
| } | |
| function magicNumberPut(value) { | |
| return workBuffer[GWMagicIndex] = value; | |
| } | |
| /* The module with the given name was just unloaded. | |
| Make sure we have no dangling references. */ | |
| function moduleUnloaded(aModuleName) { | |
| if (strcmp(aModuleName, bbPluginName) === 0) { | |
| /* BitBlt just shut down. How nasty. */ | |
| loadBBFn = 0; | |
| copyBitsFn = 0; | |
| } | |
| } | |
| /* The entry at index is not in the right position of the AET. | |
| Move it to the left until the position is okay. */ | |
| function moveAETEntryFromedgex(index, edge, xValue) { | |
| var newIndex; | |
| newIndex = index; | |
| while ((newIndex > 0) && (edgeXValueOf(aetBuffer[newIndex - 1]) > xValue)) { | |
| aetBuffer[newIndex] = aetBuffer[newIndex - 1]; | |
| --newIndex; | |
| } | |
| aetBuffer[newIndex] = edge; | |
| } | |
| /* Check if we have n slots available */ | |
| function needAvailableSpace(nSlots) { | |
| if (((((GWHeaderSize + objUsed) + getUsedGet()) + aetUsedGet()) + nSlots) > wbTopGet()) { | |
| stopBecauseOf(GErrorNoMoreSpace); | |
| return false; | |
| } | |
| return true; | |
| } | |
| function needsFlush() { | |
| return needsFlushGet() !== 0; | |
| } | |
| function needsFlushGet() { | |
| return workBuffer[GWNeedsFlush]; | |
| } | |
| function needsFlushPut(value) { | |
| return workBuffer[GWNeedsFlush] = value; | |
| } | |
| function objat(object, index) { | |
| return objBuffer[object + index]; | |
| } | |
| function objatput(object, index, value) { | |
| return objBuffer[object + index] = value; | |
| } | |
| function objStartGet() { | |
| return workBuffer[GWObjStart]; | |
| } | |
| function objStartPut(value) { | |
| return workBuffer[GWObjStart] = value; | |
| } | |
| function objUsedGet() { | |
| return workBuffer[GWObjUsed]; | |
| } | |
| function objUsedPut(value) { | |
| return workBuffer[GWObjUsed] = value; | |
| } | |
| function objectHeaderOf(obj) { | |
| return objat(obj, GEObjectType); | |
| } | |
| function objectIndexOf(obj) { | |
| return objat(obj, GEObjectIndex); | |
| } | |
| function objectIndexOfput(obj, value) { | |
| return objatput(obj, GEObjectIndex, value); | |
| } | |
| function objectLengthOf(obj) { | |
| return objat(obj, GEObjectLength); | |
| } | |
| function objectLengthOfput(obj, value) { | |
| return objatput(obj, GEObjectLength, value); | |
| } | |
| function objectTypeOf(obj) { | |
| return objat(obj, GEObjectType) & GEPrimitiveTypeMask; | |
| } | |
| function objectTypeOfput(obj, value) { | |
| return objatput(obj, GEObjectType, value); | |
| } | |
| /* Common function so that we don't compute that wrong in any place | |
| and can easily find all the places where we deal with one-pixel offsets. */ | |
| function offsetFromWidth(lineWidth) { | |
| return lineWidth >> 1; | |
| } | |
| function point1Get() { | |
| return PTR_ADD(workBuffer, GWPoint1); | |
| } | |
| function point2Get() { | |
| return PTR_ADD(workBuffer, GWPoint2); | |
| } | |
| function point3Get() { | |
| return PTR_ADD(workBuffer, GWPoint3); | |
| } | |
| function point4Get() { | |
| return PTR_ADD(workBuffer, GWPoint4); | |
| } | |
| /* We have just blitted a scan line to the screen. | |
| Do whatever seems to be a good idea here. */ | |
| /* Note: In the future we may check the time needed for this scan line and interrupt processing to give the Smalltalk code a chance to run at a certain time. */ | |
| /* Check if there is any more work to do. */ | |
| function postDisplayAction() { | |
| if ((getStartGet() >= getUsedGet()) && (aetUsedGet() === 0)) { | |
| /* No more entries to process */ | |
| statePut(GEStateCompleted); | |
| } | |
| if (currentYGet() >= fillMaxYGet()) { | |
| /* Out of clipping range */ | |
| statePut(GEStateCompleted); | |
| } | |
| } | |
| function primitiveAbortProcessing() { | |
| var failureCode; | |
| if (interpreterProxy.methodArgumentCount() !== 0) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFrom(interpreterProxy.stackValue(0)))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| statePut(GEStateCompleted); | |
| storeEngineStateInto(engine); | |
| } | |
| /* Note: No need to load either bitBlt or spanBuffer */ | |
| function primitiveAddActiveEdgeEntry() { | |
| var edge; | |
| var edgeOop; | |
| var failureCode; | |
| if (doProfileStats) { | |
| geProfileTime = interpreterProxy.ioMicroMSecs(); | |
| } | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(1), GEStateWaitingForEdge))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| edgeOop = interpreterProxy.stackObjectValue(0); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| edge = loadEdgeStateFrom(edgeOop); | |
| if (!edge) { | |
| return interpreterProxy.primitiveFailFor(GEFEdgeDataTooSmall); | |
| } | |
| if (!needAvailableSpace(1)) { | |
| return interpreterProxy.primitiveFailFor(GEFWorkTooBig); | |
| } | |
| if (edgeNumLinesOf(edge) > 0) { | |
| insertEdgeIntoAET(edge); | |
| } | |
| if (engineStopped) { | |
| return interpreterProxy.primitiveFailFor(GEFEngineStopped); | |
| } | |
| statePut(GEStateAddingFromGET); | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(1); | |
| if (doProfileStats) { | |
| incrementStatby(GWCountAddAETEntry, 1); | |
| incrementStatby(GWTimeAddAETEntry, interpreterProxy.ioMicroMSecs() - geProfileTime); | |
| } | |
| } | |
| function primitiveAddBezier() { | |
| var endOop; | |
| var failureCode; | |
| var leftFill; | |
| var nSegments; | |
| var rightFill; | |
| var startOop; | |
| var viaOop; | |
| /* Fail if we have the wrong number of arguments */ | |
| if (interpreterProxy.methodArgumentCount() !== 5) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| rightFill = interpreterProxy.positive32BitValueOf(interpreterProxy.stackValue(0)); | |
| leftFill = interpreterProxy.positive32BitValueOf(interpreterProxy.stackValue(1)); | |
| viaOop = interpreterProxy.stackObjectValue(2); | |
| endOop = interpreterProxy.stackObjectValue(3); | |
| startOop = interpreterProxy.stackObjectValue(4); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(5), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| if (!(isFillOkay(leftFill) && (isFillOkay(rightFill)))) { | |
| return interpreterProxy.primitiveFailFor(GEFWrongFill); | |
| } | |
| if ((leftFill === rightFill) && false) { | |
| return interpreterProxy.pop(6); | |
| } | |
| loadPointfrom(point1Get(), startOop); | |
| loadPointfrom(point2Get(), viaOop); | |
| loadPointfrom(point3Get(), endOop); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| transformPoints(3); | |
| nSegments = loadAndSubdivideBezierFromviatoisWide(point1Get(), point2Get(), point3Get(), false); | |
| needAvailableSpace(nSegments * GBBaseSize); | |
| if (!engineStopped) { | |
| leftFill = transformColor(leftFill); | |
| rightFill = transformColor(rightFill); | |
| } | |
| if (!engineStopped) { | |
| loadWideBezierlineFillleftFillrightFilln(0, 0, leftFill, rightFill, nSegments); | |
| } | |
| if (engineStopped) { | |
| /* Make sure the stack is okay */ | |
| wbStackClear(); | |
| return interpreterProxy.primitiveFailFor(GEFEngineStopped); | |
| } | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(GEFEntityLoadFailed); | |
| } | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(5); | |
| } | |
| function primitiveAddBezierShape() { | |
| var failureCode; | |
| var fillIndex; | |
| var length; | |
| var lineFill; | |
| var lineWidth; | |
| var nSegments; | |
| var points; | |
| var pointsIsArray; | |
| var segSize; | |
| /* Fail if we have the wrong number of arguments */ | |
| if (interpreterProxy.methodArgumentCount() !== 5) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| lineFill = interpreterProxy.positive32BitValueOf(interpreterProxy.stackValue(0)); | |
| lineWidth = interpreterProxy.stackIntegerValue(1); | |
| fillIndex = interpreterProxy.positive32BitValueOf(interpreterProxy.stackValue(2)); | |
| nSegments = interpreterProxy.stackIntegerValue(3); | |
| points = interpreterProxy.stackObjectValue(4); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(5), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| length = SIZEOF(points); | |
| if (interpreterProxy.isWords(points)) { | |
| /* Either PointArray or ShortPointArray */ | |
| pointsIsArray = false; | |
| if (!((length === (nSegments * 3)) || (length === (nSegments * 6)))) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| } else { | |
| /* Must be Array of points */ | |
| if (!interpreterProxy.isArray(points)) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| if (length !== (nSegments * 3)) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| pointsIsArray = true; | |
| } | |
| if ((lineWidth === 0) || (lineFill === 0)) { | |
| segSize = GLBaseSize; | |
| } else { | |
| segSize = GLWideSize; | |
| } | |
| if (!needAvailableSpace(segSize * nSegments)) { | |
| return interpreterProxy.primitiveFailFor(GEFWorkTooBig); | |
| } | |
| if (!(isFillOkay(lineFill) && (isFillOkay(fillIndex)))) { | |
| return interpreterProxy.primitiveFailFor(GEFWrongFill); | |
| } | |
| lineFill = transformColor(lineFill); | |
| fillIndex = transformColor(fillIndex); | |
| if (engineStopped) { | |
| return interpreterProxy.primitiveFailFor(GEFEngineStopped); | |
| } | |
| if (((lineFill === 0) || (lineWidth === 0)) && (fillIndex === 0)) { | |
| return interpreterProxy.pop(5); | |
| } | |
| if (lineWidth !== 0) { | |
| lineWidth = transformWidth(lineWidth); | |
| if (lineWidth < 1) { | |
| lineWidth = 1; | |
| } | |
| } | |
| if (pointsIsArray) { | |
| loadArrayShapenSegmentsfilllineWidthlineFill(points, nSegments, fillIndex, lineWidth, lineFill); | |
| } else { | |
| loadShapenSegmentsfilllineWidthlineFillpointsShort(points.wordsAsInt32Array(), nSegments, fillIndex, lineWidth, lineFill, (nSegments * 3) === length); | |
| } | |
| if (engineStopped) { | |
| return interpreterProxy.primitiveFailFor(GEFEngineStopped); | |
| } | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(GEFEntityLoadFailed); | |
| } | |
| needsFlushPut(1); | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(5); | |
| } | |
| function primitiveAddBitmapFill() { | |
| var cmOop; | |
| var dirOop; | |
| var failureCode; | |
| var fill; | |
| var formOop; | |
| var nrmOop; | |
| var originOop; | |
| var tileFlag; | |
| var xIndex; | |
| /* Fail if we have the wrong number of arguments */ | |
| if (interpreterProxy.methodArgumentCount() !== 7) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| xIndex = interpreterProxy.stackIntegerValue(0); | |
| if (xIndex <= 0) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| nrmOop = interpreterProxy.stackObjectValue(1); | |
| dirOop = interpreterProxy.stackObjectValue(2); | |
| originOop = interpreterProxy.stackObjectValue(3); | |
| tileFlag = interpreterProxy.booleanValueOf(interpreterProxy.stackValue(4)); | |
| cmOop = interpreterProxy.stackObjectValue(5); | |
| formOop = interpreterProxy.stackObjectValue(6); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(7), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| loadPointfrom(point1Get(), originOop); | |
| loadPointfrom(point2Get(), dirOop); | |
| loadPointfrom(point3Get(), nrmOop); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(GEFBadPoint); | |
| } | |
| fill = loadBitmapFillcolormaptilefromalongnormalxIndex(formOop, cmOop, (tileFlag | |
| ? 1 | |
| : 0), point1Get(), point2Get(), point3Get(), xIndex - 1); | |
| if (engineStopped) { | |
| /* Make sure the stack is okay */ | |
| return interpreterProxy.primitiveFailFor(GEFEngineStopped); | |
| } | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(GEFEntityLoadFailed); | |
| } | |
| storeEngineStateInto(engine); | |
| interpreterProxy.popthenPush(8, interpreterProxy.positive32BitIntegerFor(fill)); | |
| } | |
| function primitiveAddCompressedShape() { | |
| var failureCode; | |
| var fillIndexList; | |
| var leftFills; | |
| var lineFills; | |
| var lineWidths; | |
| var nSegments; | |
| var points; | |
| var pointsShort; | |
| var rightFills; | |
| /* Fail if we have the wrong number of arguments */ | |
| if (interpreterProxy.methodArgumentCount() !== 7) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| fillIndexList = interpreterProxy.stackObjectValue(0); | |
| lineFills = interpreterProxy.stackObjectValue(1); | |
| lineWidths = interpreterProxy.stackObjectValue(2); | |
| rightFills = interpreterProxy.stackObjectValue(3); | |
| leftFills = interpreterProxy.stackObjectValue(4); | |
| nSegments = interpreterProxy.stackIntegerValue(5); | |
| points = interpreterProxy.stackObjectValue(6); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(7), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| if (!checkCompressedShapesegmentsleftFillsrightFillslineWidthslineFillsfillIndexList(points, nSegments, leftFills, rightFills, lineWidths, lineFills, fillIndexList)) { | |
| return interpreterProxy.primitiveFailFor(GEFEntityCheckFailed); | |
| } | |
| if (!needAvailableSpace(Math.max(GBBaseSize, GLBaseSize) * nSegments)) { | |
| return interpreterProxy.primitiveFailFor(GEFWorkTooBig); | |
| } | |
| /* Then actually load the compressed shape */ | |
| pointsShort = SIZEOF(points) === (nSegments * 3); | |
| loadCompressedShapesegmentsleftFillsrightFillslineWidthslineFillsfillIndexListpointShort(points.wordsAsInt32Array(), nSegments, leftFills.wordsAsInt32Array(), rightFills.wordsAsInt32Array(), lineWidths.wordsAsInt32Array(), lineFills.wordsAsInt32Array(), fillIndexList.wordsAsInt32Array(), pointsShort); | |
| if (engineStopped) { | |
| return interpreterProxy.primitiveFailFor(GEFEngineStopped); | |
| } | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(GEFEntityLoadFailed); | |
| } | |
| needsFlushPut(1); | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(7); | |
| } | |
| function primitiveAddGradientFill() { | |
| var dirOop; | |
| var failureCode; | |
| var fill; | |
| var isRadial; | |
| var nrmOop; | |
| var originOop; | |
| var rampOop; | |
| /* Fail if we have the wrong number of arguments */ | |
| if (interpreterProxy.methodArgumentCount() !== 5) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| isRadial = interpreterProxy.booleanValueOf(interpreterProxy.stackValue(0)); | |
| nrmOop = interpreterProxy.stackValue(1); | |
| dirOop = interpreterProxy.stackValue(2); | |
| originOop = interpreterProxy.stackValue(3); | |
| rampOop = interpreterProxy.stackValue(4); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(5), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| loadPointfrom(point1Get(), originOop); | |
| loadPointfrom(point2Get(), dirOop); | |
| loadPointfrom(point3Get(), nrmOop); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(GEFBadPoint); | |
| } | |
| fill = loadGradientFillfromalongnormalisRadial(rampOop, point1Get(), point2Get(), point3Get(), isRadial); | |
| if (engineStopped) { | |
| /* Make sure the stack is okay */ | |
| return interpreterProxy.primitiveFailFor(GEFEngineStopped); | |
| } | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(GEFEntityLoadFailed); | |
| } | |
| storeEngineStateInto(engine); | |
| interpreterProxy.popthenPush(6, interpreterProxy.positive32BitIntegerFor(fill)); | |
| } | |
| function primitiveAddLine() { | |
| var endOop; | |
| var failureCode; | |
| var leftFill; | |
| var rightFill; | |
| var startOop; | |
| /* Fail if we have the wrong number of arguments */ | |
| if (interpreterProxy.methodArgumentCount() !== 4) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| rightFill = interpreterProxy.positive32BitValueOf(interpreterProxy.stackValue(0)); | |
| leftFill = interpreterProxy.positive32BitValueOf(interpreterProxy.stackValue(1)); | |
| endOop = interpreterProxy.stackObjectValue(2); | |
| startOop = interpreterProxy.stackObjectValue(3); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(4), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| if (!(isFillOkay(leftFill) && (isFillOkay(rightFill)))) { | |
| return interpreterProxy.primitiveFailFor(GEFWrongFill); | |
| } | |
| loadPointfrom(point1Get(), startOop); | |
| loadPointfrom(point2Get(), endOop); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(GEFBadPoint); | |
| } | |
| transformPoints(2); | |
| leftFill = transformColor(leftFill); | |
| rightFill = transformColor(rightFill); | |
| if (engineStopped) { | |
| return interpreterProxy.primitiveFailFor(GEFEngineStopped); | |
| } | |
| loadWideLinefromtolineFillleftFillrightFill(0, point1Get(), point2Get(), 0, leftFill, rightFill); | |
| if (engineStopped) { | |
| return interpreterProxy.primitiveFailFor(GEFEngineStopped); | |
| } | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(GEFEntityLoadFailed); | |
| } | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(4); | |
| } | |
| function primitiveAddOval() { | |
| var borderIndex; | |
| var borderWidth; | |
| var endOop; | |
| var failureCode; | |
| var fillIndex; | |
| var startOop; | |
| /* Fail if we have the wrong number of arguments */ | |
| if (interpreterProxy.methodArgumentCount() !== 5) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| borderIndex = interpreterProxy.positive32BitValueOf(interpreterProxy.stackValue(0)); | |
| borderWidth = interpreterProxy.stackIntegerValue(1); | |
| fillIndex = interpreterProxy.positive32BitValueOf(interpreterProxy.stackValue(2)); | |
| endOop = interpreterProxy.stackObjectValue(3); | |
| startOop = interpreterProxy.stackObjectValue(4); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(5), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| if (!(isFillOkay(borderIndex) && (isFillOkay(fillIndex)))) { | |
| return interpreterProxy.primitiveFailFor(GEFWrongFill); | |
| } | |
| fillIndex = transformColor(fillIndex); | |
| borderIndex = transformColor(borderIndex); | |
| if (engineStopped) { | |
| return interpreterProxy.primitiveFailFor(GEFEngineStopped); | |
| } | |
| if ((fillIndex === 0) && ((borderIndex === 0) || (borderWidth <= 0))) { | |
| return interpreterProxy.pop(5); | |
| } | |
| if (!needAvailableSpace(16 * GBBaseSize)) { | |
| return interpreterProxy.primitiveFailFor(GEFWorkTooBig); | |
| } | |
| if ((borderWidth > 0) && (borderIndex !== 0)) { | |
| borderWidth = transformWidth(borderWidth); | |
| } else { | |
| borderWidth = 0; | |
| } | |
| loadPointfrom(point1Get(), startOop); | |
| loadPointfrom(point2Get(), endOop); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(GEFBadPoint); | |
| } | |
| loadOvallineFillleftFillrightFill(borderWidth, borderIndex, 0, fillIndex); | |
| if (engineStopped) { | |
| wbStackClear(); | |
| return interpreterProxy.primitiveFailFor(GEFEngineStopped); | |
| } | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(GEFEntityLoadFailed); | |
| } | |
| needsFlushPut(1); | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(5); | |
| } | |
| function primitiveAddPolygon() { | |
| var failureCode; | |
| var fillIndex; | |
| var length; | |
| var lineFill; | |
| var lineWidth; | |
| var nPoints; | |
| var points; | |
| var pointsIsArray; | |
| var segSize; | |
| /* Fail if we have the wrong number of arguments */ | |
| if (interpreterProxy.methodArgumentCount() !== 5) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| lineFill = interpreterProxy.positive32BitValueOf(interpreterProxy.stackValue(0)); | |
| lineWidth = interpreterProxy.stackIntegerValue(1); | |
| fillIndex = interpreterProxy.positive32BitValueOf(interpreterProxy.stackValue(2)); | |
| nPoints = interpreterProxy.stackIntegerValue(3); | |
| points = interpreterProxy.stackObjectValue(4); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(5), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| length = SIZEOF(points); | |
| if (interpreterProxy.isWords(points)) { | |
| /* Either PointArray or ShortPointArray */ | |
| pointsIsArray = false; | |
| if (!((length === nPoints) || ((nPoints * 2) === length))) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| } else { | |
| /* Must be Array of points */ | |
| if (!interpreterProxy.isArray(points)) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| if (length !== nPoints) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| pointsIsArray = true; | |
| } | |
| if ((lineWidth === 0) || (lineFill === 0)) { | |
| segSize = GLBaseSize; | |
| } else { | |
| segSize = GLWideSize; | |
| } | |
| if (!needAvailableSpace(segSize * nPoints)) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| if (!(isFillOkay(lineFill) && (isFillOkay(fillIndex)))) { | |
| return interpreterProxy.primitiveFailFor(GEFWrongFill); | |
| } | |
| lineFill = transformColor(lineFill); | |
| fillIndex = transformColor(fillIndex); | |
| if (engineStopped) { | |
| return interpreterProxy.primitiveFailFor(GEFEngineStopped); | |
| } | |
| if (((lineFill === 0) || (lineWidth === 0)) && (fillIndex === 0)) { | |
| return interpreterProxy.pop(5); | |
| } | |
| if (lineWidth !== 0) { | |
| lineWidth = transformWidth(lineWidth); | |
| } | |
| if (pointsIsArray) { | |
| loadArrayPolygonnPointsfilllineWidthlineFill(points, nPoints, fillIndex, lineWidth, lineFill); | |
| } else { | |
| loadPolygonnPointsfilllineWidthlineFillpointsShort(points.wordsAsInt32Array(), nPoints, fillIndex, lineWidth, lineFill, nPoints === length); | |
| } | |
| if (engineStopped) { | |
| return interpreterProxy.primitiveFailFor(GEFEngineStopped); | |
| } | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(GEFEntityLoadFailed); | |
| } | |
| needsFlushPut(1); | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(5); | |
| } | |
| function primitiveAddRect() { | |
| var borderIndex; | |
| var borderWidth; | |
| var endOop; | |
| var failureCode; | |
| var fillIndex; | |
| var startOop; | |
| /* Fail if we have the wrong number of arguments */ | |
| if (interpreterProxy.methodArgumentCount() !== 5) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| borderIndex = interpreterProxy.positive32BitValueOf(interpreterProxy.stackValue(0)); | |
| borderWidth = interpreterProxy.stackIntegerValue(1); | |
| fillIndex = interpreterProxy.positive32BitValueOf(interpreterProxy.stackValue(2)); | |
| endOop = interpreterProxy.stackObjectValue(3); | |
| startOop = interpreterProxy.stackObjectValue(4); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(5), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| if (!(isFillOkay(borderIndex) && (isFillOkay(fillIndex)))) { | |
| return interpreterProxy.primitiveFailFor(GEFWrongFill); | |
| } | |
| borderIndex = transformColor(borderIndex); | |
| fillIndex = transformColor(fillIndex); | |
| if (engineStopped) { | |
| return interpreterProxy.primitiveFailFor(GEFEngineStopped); | |
| } | |
| if ((fillIndex === 0) && ((borderIndex === 0) || (borderWidth === 0))) { | |
| return interpreterProxy.pop(5); | |
| } | |
| if (!needAvailableSpace(4 * GLBaseSize)) { | |
| return interpreterProxy.primitiveFailFor(GEFWorkTooBig); | |
| } | |
| if ((borderWidth > 0) && (borderIndex !== 0)) { | |
| borderWidth = transformWidth(borderWidth); | |
| } else { | |
| borderWidth = 0; | |
| } | |
| loadPointfrom(point1Get(), startOop); | |
| loadPointfrom(point3Get(), endOop); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(GEFBadPoint); | |
| } | |
| point2Get()[0] = point3Get()[0]; | |
| point2Get()[1] = point1Get()[1]; | |
| point4Get()[0] = point1Get()[0]; | |
| point4Get()[1] = point3Get()[1]; | |
| transformPoints(4); | |
| loadRectanglelineFillleftFillrightFill(borderWidth, borderIndex, 0, fillIndex); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(GEFEntityLoadFailed); | |
| } | |
| needsFlushPut(1); | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(5); | |
| } | |
| /* Note: No need to load either bitBlt or spanBuffer */ | |
| function primitiveChangedActiveEdgeEntry() { | |
| var edge; | |
| var edgeOop; | |
| var failureCode; | |
| if (doProfileStats) { | |
| geProfileTime = interpreterProxy.ioMicroMSecs(); | |
| } | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(1), GEStateWaitingChange))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| edgeOop = interpreterProxy.stackObjectValue(0); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| edge = loadEdgeStateFrom(edgeOop); | |
| if (!edge) { | |
| return interpreterProxy.primitiveFailFor(GEFEdgeDataTooSmall); | |
| } | |
| if (edgeNumLinesOf(edge) === 0) { | |
| removeFirstAETEntry(); | |
| } else { | |
| resortFirstAETEntry(); | |
| aetStartPut(aetStartGet() + 1); | |
| } | |
| statePut(GEStateUpdateEdges); | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(1); | |
| if (doProfileStats) { | |
| incrementStatby(GWCountChangeAETEntry, 1); | |
| incrementStatby(GWTimeChangeAETEntry, interpreterProxy.ioMicroMSecs() - geProfileTime); | |
| } | |
| } | |
| function primitiveCopyBuffer() { | |
| var buf1; | |
| var buf2; | |
| var diff; | |
| var dst; | |
| var failCode; | |
| var i; | |
| var src; | |
| var iLimiT; | |
| if (interpreterProxy.methodArgumentCount() !== 2) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| buf2 = interpreterProxy.stackValue(0); | |
| /* Make sure the old buffer is properly initialized */ | |
| buf1 = interpreterProxy.stackValue(1); | |
| if (((failCode = loadWorkBufferFrom(buf1))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failCode); | |
| } | |
| if (CLASSOF(buf1) !== CLASSOF(buf2)) { | |
| return interpreterProxy.primitiveFailFor(GEFClassMismatch); | |
| } | |
| diff = SIZEOF(buf2) - SIZEOF(buf1); | |
| if (diff < 0) { | |
| return interpreterProxy.primitiveFailFor(GEFSizeMismatch); | |
| } | |
| src = workBuffer; | |
| dst = buf2.wordsAsInt32Array(); | |
| for (i = 0, iLimiT = (wbTopGet() - 1); i <= iLimiT; i++) { | |
| dst[i] = src[i]; | |
| } | |
| dst[GWBufferTop] = (wbTopGet() + diff); | |
| dst[GWSize] = (wbSizeGet() + diff); | |
| src = PTR_ADD(src, wbTopGet()); | |
| dst = PTR_ADD(dst, wbTopGet() + diff); | |
| for (i = 0, iLimiT = ((wbSizeGet() - wbTopGet()) - 1); i <= iLimiT; i++) { | |
| dst[i] = src[i]; | |
| } | |
| if (((failCode = loadWorkBufferFrom(buf2))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failCode); | |
| } | |
| interpreterProxy.pop(2); | |
| } | |
| /* Note: Must load bitBlt and spanBuffer */ | |
| function primitiveDisplaySpanBuffer() { | |
| var failureCode; | |
| if (doProfileStats) { | |
| geProfileTime = interpreterProxy.ioMicroMSecs(); | |
| } | |
| if (interpreterProxy.methodArgumentCount() !== 0) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(0), GEStateBlitBuffer))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| if (((failureCode = loadSpanBufferFrom(interpreterProxy.fetchPointerofObject(BESpanIndex, engine)))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| if (!loadBitBltFrom(interpreterProxy.fetchPointerofObject(BEBitBltIndex, engine))) { | |
| return interpreterProxy.primitiveFailFor(GEFBitBltLoadFailed); | |
| } | |
| if ((currentYGet() & aaScanMaskGet()) === aaScanMaskGet()) { | |
| displaySpanBufferAt(currentYGet()); | |
| postDisplayAction(); | |
| } | |
| if (!finishedProcessing()) { | |
| aetStartPut(0); | |
| currentYPut(currentYGet() + 1); | |
| statePut(GEStateUpdateEdges); | |
| } | |
| storeEngineStateInto(engine); | |
| if (doProfileStats) { | |
| incrementStatby(GWCountDisplaySpan, 1); | |
| incrementStatby(GWTimeDisplaySpan, interpreterProxy.ioMicroMSecs() - geProfileTime); | |
| } | |
| } | |
| /* Turn on/off profiling. Return the old value of the flag. */ | |
| function primitiveDoProfileStats() { | |
| var newValue; | |
| var oldValue; | |
| oldValue = doProfileStats; | |
| newValue = interpreterProxy.stackObjectValue(0); | |
| newValue = interpreterProxy.booleanValueOf(newValue); | |
| if (!interpreterProxy.failed()) { | |
| doProfileStats = newValue; | |
| interpreterProxy.pop(2); | |
| interpreterProxy.pushBool(oldValue); | |
| } | |
| } | |
| function primitiveFinishedProcessing() { | |
| var failureCode; | |
| var finished; | |
| if (doProfileStats) { | |
| geProfileTime = interpreterProxy.ioMicroMSecs(); | |
| } | |
| if (interpreterProxy.methodArgumentCount() !== 0) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFrom(interpreterProxy.stackValue(0)))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| finished = finishedProcessing(); | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(1); | |
| interpreterProxy.pushBool(finished); | |
| if (doProfileStats) { | |
| incrementStatby(GWCountFinishTest, 1); | |
| incrementStatby(GWTimeFinishTest, interpreterProxy.ioMicroMSecs() - geProfileTime); | |
| } | |
| } | |
| function primitiveGetAALevel() { | |
| var failureCode; | |
| if (interpreterProxy.methodArgumentCount() !== 0) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFrom(interpreterProxy.stackValue(0)))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| interpreterProxy.pop(1); | |
| interpreterProxy.pushInteger(aaLevelGet()); | |
| } | |
| function primitiveGetBezierStats() { | |
| var failureCode; | |
| var statOop; | |
| var stats; | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFrom(interpreterProxy.stackValue(1)))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| statOop = interpreterProxy.stackObjectValue(0); | |
| if (!(!interpreterProxy.failed() && (interpreterProxy.isWords(statOop) && (SIZEOF(statOop) >= 4)))) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| stats = statOop.wordsAsInt32Array(); | |
| stats[0] = (stats[0] + workBuffer[GWBezierMonotonSubdivisions]); | |
| stats[1] = (stats[1] + workBuffer[GWBezierHeightSubdivisions]); | |
| stats[2] = (stats[2] + workBuffer[GWBezierOverflowSubdivisions]); | |
| stats[3] = (stats[3] + workBuffer[GWBezierLineConversions]); | |
| interpreterProxy.pop(1); | |
| } | |
| function primitiveGetClipRect() { | |
| var failureCode; | |
| var pointOop; | |
| var rectOop; | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFrom(interpreterProxy.stackValue(1)))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| rectOop = interpreterProxy.stackObjectValue(0); | |
| if (!(!interpreterProxy.failed() && (interpreterProxy.isPointers(rectOop) && (SIZEOF(rectOop) >= 2)))) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| interpreterProxy.pushRemappableOop(rectOop); | |
| pointOop = interpreterProxy.makePointwithxValueyValue(clipMinXGet(), clipMinYGet()); | |
| interpreterProxy.storePointerofObjectwithValue(0, interpreterProxy.topRemappableOop(), pointOop); | |
| pointOop = interpreterProxy.makePointwithxValueyValue(clipMaxXGet(), clipMaxYGet()); | |
| rectOop = interpreterProxy.popRemappableOop(); | |
| interpreterProxy.storePointerofObjectwithValue(1, rectOop, pointOop); | |
| interpreterProxy.popthenPush(2, rectOop); | |
| } | |
| function primitiveGetCounts() { | |
| var failureCode; | |
| var statOop; | |
| var stats; | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFrom(interpreterProxy.stackValue(1)))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| statOop = interpreterProxy.stackObjectValue(0); | |
| if (!(!interpreterProxy.failed() && (interpreterProxy.isWords(statOop) && (SIZEOF(statOop) >= 9)))) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| stats = statOop.wordsAsInt32Array(); | |
| stats[0] = (stats[0] + workBuffer[GWCountInitializing]); | |
| stats[1] = (stats[1] + workBuffer[GWCountFinishTest]); | |
| stats[2] = (stats[2] + workBuffer[GWCountNextGETEntry]); | |
| stats[3] = (stats[3] + workBuffer[GWCountAddAETEntry]); | |
| stats[4] = (stats[4] + workBuffer[GWCountNextFillEntry]); | |
| stats[5] = (stats[5] + workBuffer[GWCountMergeFill]); | |
| stats[6] = (stats[6] + workBuffer[GWCountDisplaySpan]); | |
| stats[7] = (stats[7] + workBuffer[GWCountNextAETEntry]); | |
| stats[8] = (stats[8] + workBuffer[GWCountChangeAETEntry]); | |
| interpreterProxy.pop(1); | |
| } | |
| function primitiveGetDepth() { | |
| var failureCode; | |
| if (interpreterProxy.methodArgumentCount() !== 0) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFrom(interpreterProxy.stackValue(0)))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| interpreterProxy.pop(1); | |
| interpreterProxy.pushInteger(currentZGet()); | |
| } | |
| /* Return the reason why the last operation failed. */ | |
| function primitiveGetFailureReason() { | |
| var failCode; | |
| if (interpreterProxy.methodArgumentCount() !== 0) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| /* Note -- don't call loadEngineFrom here because this will override the stopReason with Zero */ | |
| engine = interpreterProxy.stackValue(0); | |
| if (typeof engine === "number") { | |
| return interpreterProxy.primitiveFailFor(GEFEngineIsInteger); | |
| } | |
| if (!interpreterProxy.isPointers(engine)) { | |
| return interpreterProxy.primitiveFailFor(GEFEngineIsWords); | |
| } | |
| if (SIZEOF(engine) < BEBalloonEngineSize) { | |
| return interpreterProxy.primitiveFailFor(GEFEngineTooSmall); | |
| } | |
| if (((failCode = loadWorkBufferFrom(interpreterProxy.fetchPointerofObject(BEWorkBufferIndex, engine)))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failCode); | |
| } | |
| interpreterProxy.pop(1); | |
| interpreterProxy.pushInteger(stopReasonGet()); | |
| } | |
| function primitiveGetOffset() { | |
| var failureCode; | |
| var pointOop; | |
| if (interpreterProxy.methodArgumentCount() !== 0) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFrom(interpreterProxy.stackValue(0)))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| pointOop = interpreterProxy.makePointwithxValueyValue(destOffsetXGet(), destOffsetYGet()); | |
| interpreterProxy.popthenPush(1, pointOop); | |
| } | |
| function primitiveGetTimes() { | |
| var failureCode; | |
| var statOop; | |
| var stats; | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFrom(interpreterProxy.stackValue(1)))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| statOop = interpreterProxy.stackObjectValue(0); | |
| if (!(!interpreterProxy.failed() && (interpreterProxy.isWords(statOop) && (SIZEOF(statOop) >= 9)))) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| stats = statOop.wordsAsInt32Array(); | |
| stats[0] = (stats[0] + workBuffer[GWTimeInitializing]); | |
| stats[1] = (stats[1] + workBuffer[GWTimeFinishTest]); | |
| stats[2] = (stats[2] + workBuffer[GWTimeNextGETEntry]); | |
| stats[3] = (stats[3] + workBuffer[GWTimeAddAETEntry]); | |
| stats[4] = (stats[4] + workBuffer[GWTimeNextFillEntry]); | |
| stats[5] = (stats[5] + workBuffer[GWTimeMergeFill]); | |
| stats[6] = (stats[6] + workBuffer[GWTimeDisplaySpan]); | |
| stats[7] = (stats[7] + workBuffer[GWTimeNextAETEntry]); | |
| stats[8] = (stats[8] + workBuffer[GWTimeChangeAETEntry]); | |
| interpreterProxy.pop(1); | |
| } | |
| function primitiveInitializeBuffer() { | |
| var size; | |
| var wbOop; | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| wbOop = interpreterProxy.stackObjectValue(0); | |
| if (interpreterProxy.failed()) { | |
| return null; | |
| } | |
| if (!interpreterProxy.isWords(wbOop)) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| if (((size = SIZEOF(wbOop))) < GWMinimalSize) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| workBufferPut(wbOop); | |
| objBuffer = PTR_ADD(workBuffer, GWHeaderSize); | |
| magicNumberPut(GWMagicNumber); | |
| wbSizePut(size); | |
| wbTopPut(size); | |
| statePut(GEStateUnlocked); | |
| objStartPut(GWHeaderSize); | |
| objUsedPut(4); | |
| objectTypeOfput(0, GEPrimitiveFill); | |
| objectLengthOfput(0, 4); | |
| objectIndexOfput(0, 0); | |
| getStartPut(0); | |
| getUsedPut(0); | |
| aetStartPut(0); | |
| aetUsedPut(0); | |
| stopReasonPut(0); | |
| needsFlushPut(0); | |
| clipMinXPut(0); | |
| clipMaxXPut(0); | |
| clipMinYPut(0); | |
| clipMaxYPut(0); | |
| currentZPut(0); | |
| resetGraphicsEngineStats(); | |
| initEdgeTransform(); | |
| initColorTransform(); | |
| interpreterProxy.pop(2); | |
| interpreterProxy.push(wbOop); | |
| } | |
| /* Note: No need to load bitBlt but must load spanBuffer */ | |
| function primitiveInitializeProcessing() { | |
| var failureCode; | |
| if (doProfileStats) { | |
| geProfileTime = interpreterProxy.ioMicroMSecs(); | |
| } | |
| if (interpreterProxy.methodArgumentCount() !== 0) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(0), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| if (((failureCode = loadSpanBufferFrom(interpreterProxy.fetchPointerofObject(BESpanIndex, engine)))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| initializeGETProcessing(); | |
| if (engineStopped) { | |
| return interpreterProxy.primitiveFailFor(GEFEngineStopped); | |
| } | |
| statePut(GEStateAddingFromGET); | |
| if (!interpreterProxy.failed()) { | |
| storeEngineStateInto(engine); | |
| } | |
| if (doProfileStats) { | |
| incrementStatby(GWCountInitializing, 1); | |
| incrementStatby(GWTimeInitializing, interpreterProxy.ioMicroMSecs() - geProfileTime); | |
| } | |
| } | |
| /* Note: No need to load bitBlt but must load spanBuffer */ | |
| function primitiveMergeFillFrom() { | |
| var bitsOop; | |
| var failureCode; | |
| var fillOop; | |
| var value; | |
| if (doProfileStats) { | |
| geProfileTime = interpreterProxy.ioMicroMSecs(); | |
| } | |
| if (interpreterProxy.methodArgumentCount() !== 2) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(2), GEStateWaitingForFill))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| if (((failureCode = loadSpanBufferFrom(interpreterProxy.fetchPointerofObject(BESpanIndex, engine)))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| fillOop = interpreterProxy.stackObjectValue(0); | |
| /* Check bitmap */ | |
| bitsOop = interpreterProxy.stackObjectValue(1); | |
| if (!(!interpreterProxy.failed() && (CLASSOF(bitsOop) === interpreterProxy.classBitmap()))) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| if (SIZEOF(fillOop) < FTBalloonFillDataSize) { | |
| return interpreterProxy.primitiveFailFor(GEFFillDataTooSmall); | |
| } | |
| value = interpreterProxy.fetchIntegerofObject(FTIndexIndex, fillOop); | |
| if (objectIndexOf(lastExportedFillGet()) !== value) { | |
| return interpreterProxy.primitiveFailFor(GEFWrongFill); | |
| } | |
| value = interpreterProxy.fetchIntegerofObject(FTMinXIndex, fillOop); | |
| if (lastExportedLeftXGet() !== value) { | |
| return interpreterProxy.primitiveFailFor(GEFWrongFill); | |
| } | |
| value = interpreterProxy.fetchIntegerofObject(FTMaxXIndex, fillOop); | |
| if (lastExportedRightXGet() !== value) { | |
| return interpreterProxy.primitiveFailFor(GEFWrongFill); | |
| } | |
| if (SIZEOF(bitsOop) < (lastExportedRightXGet() - lastExportedLeftXGet())) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| if (interpreterProxy.failed()) { | |
| return null; | |
| } | |
| fillBitmapSpanfromto(bitsOop.wordsAsInt32Array(), lastExportedLeftXGet(), lastExportedRightXGet()); | |
| statePut(GEStateScanningAET); | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(2); | |
| if (doProfileStats) { | |
| incrementStatby(GWCountMergeFill, 1); | |
| incrementStatby(GWTimeMergeFill, interpreterProxy.ioMicroMSecs() - geProfileTime); | |
| } | |
| } | |
| function primitiveNeedsFlush() { | |
| var failureCode; | |
| var needFlush; | |
| if (interpreterProxy.methodArgumentCount() !== 0) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFrom(interpreterProxy.stackValue(0)))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| needFlush = needsFlush(); | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(1); | |
| interpreterProxy.pushBool(needFlush); | |
| } | |
| function primitiveNeedsFlushPut() { | |
| var failureCode; | |
| var needFlush; | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFrom(interpreterProxy.stackValue(1)))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| needFlush = interpreterProxy.booleanValueOf(interpreterProxy.stackValue(0)); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| if (needFlush === true) { | |
| needsFlushPut(1); | |
| } else { | |
| needsFlushPut(0); | |
| } | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(1); | |
| } | |
| /* Note: No need to load either bitBlt or spanBuffer */ | |
| function primitiveNextActiveEdgeEntry() { | |
| var edge; | |
| var edgeOop; | |
| var failureCode; | |
| var hasEdge; | |
| if (doProfileStats) { | |
| geProfileTime = interpreterProxy.ioMicroMSecs(); | |
| } | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredStateor(interpreterProxy.stackValue(1), GEStateUpdateEdges, GEStateCompleted))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| edgeOop = interpreterProxy.stackObjectValue(0); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| hasEdge = false; | |
| if (stateGet() !== GEStateCompleted) { | |
| hasEdge = findNextExternalUpdateFromAET(); | |
| if (hasEdge) { | |
| edge = aetBuffer[aetStartGet()]; | |
| storeEdgeStateFrominto(edge, edgeOop); | |
| statePut(GEStateWaitingChange); | |
| } else { | |
| statePut(GEStateAddingFromGET); | |
| } | |
| } | |
| if (interpreterProxy.failed()) { | |
| return null; | |
| } | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(2); | |
| interpreterProxy.pushBool(!hasEdge); | |
| if (doProfileStats) { | |
| incrementStatby(GWCountNextAETEntry, 1); | |
| incrementStatby(GWTimeNextAETEntry, interpreterProxy.ioMicroMSecs() - geProfileTime); | |
| } | |
| } | |
| /* Note: No need to load bitBlt but must load spanBuffer */ | |
| function primitiveNextFillEntry() { | |
| var failureCode; | |
| var fillOop; | |
| var hasFill; | |
| if (doProfileStats) { | |
| geProfileTime = interpreterProxy.ioMicroMSecs(); | |
| } | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(1), GEStateScanningAET))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| if (((failureCode = loadSpanBufferFrom(interpreterProxy.fetchPointerofObject(BESpanIndex, engine)))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| if (!loadFormsFrom(interpreterProxy.fetchPointerofObject(BEFormsIndex, engine))) { | |
| return interpreterProxy.primitiveFailFor(GEFFormLoadFailed); | |
| } | |
| if (clearSpanBufferGet() !== 0) { | |
| if ((currentYGet() & aaScanMaskGet()) === 0) { | |
| clearSpanBuffer(); | |
| } | |
| clearSpanBufferPut(0); | |
| } | |
| fillOop = interpreterProxy.stackObjectValue(0); | |
| hasFill = findNextExternalFillFromAET(); | |
| if (engineStopped) { | |
| return interpreterProxy.primitiveFailFor(GEFEngineStopped); | |
| } | |
| if (hasFill) { | |
| storeFillStateInto(fillOop); | |
| } | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(GEFWrongFill); | |
| } | |
| if (hasFill) { | |
| statePut(GEStateWaitingForFill); | |
| } else { | |
| wbStackClear(); | |
| spanEndAAPut(0); | |
| statePut(GEStateBlitBuffer); | |
| } | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(2); | |
| interpreterProxy.pushBool(!hasFill); | |
| if (doProfileStats) { | |
| incrementStatby(GWCountNextFillEntry, 1); | |
| incrementStatby(GWTimeNextFillEntry, interpreterProxy.ioMicroMSecs() - geProfileTime); | |
| } | |
| } | |
| /* Note: No need to load either bitBlt or spanBuffer */ | |
| function primitiveNextGlobalEdgeEntry() { | |
| var edge; | |
| var edgeOop; | |
| var failureCode; | |
| var hasEdge; | |
| if (doProfileStats) { | |
| geProfileTime = interpreterProxy.ioMicroMSecs(); | |
| } | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(1), GEStateAddingFromGET))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| edgeOop = interpreterProxy.stackObjectValue(0); | |
| hasEdge = findNextExternalEntryFromGET(); | |
| if (hasEdge) { | |
| edge = getBuffer[getStartGet()]; | |
| storeEdgeStateFrominto(edge, edgeOop); | |
| getStartPut(getStartGet() + 1); | |
| } | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(GEFWrongEdge); | |
| } | |
| if (hasEdge) { | |
| statePut(GEStateWaitingForEdge); | |
| } else { | |
| /* Start scanning the AET */ | |
| statePut(GEStateScanningAET); | |
| clearSpanBufferPut(1); | |
| aetStartPut(0); | |
| wbStackClear(); | |
| } | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(2); | |
| interpreterProxy.pushBool(!hasEdge); | |
| if (doProfileStats) { | |
| incrementStatby(GWCountNextGETEntry, 1); | |
| incrementStatby(GWTimeNextGETEntry, interpreterProxy.ioMicroMSecs() - geProfileTime); | |
| } | |
| } | |
| function primitiveRegisterExternalEdge() { | |
| var edge; | |
| var failureCode; | |
| var index; | |
| var initialX; | |
| var initialY; | |
| var initialZ; | |
| var leftFillIndex; | |
| var rightFillIndex; | |
| if (interpreterProxy.methodArgumentCount() !== 6) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(6), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| rightFillIndex = interpreterProxy.positive32BitValueOf(interpreterProxy.stackValue(0)); | |
| leftFillIndex = interpreterProxy.positive32BitValueOf(interpreterProxy.stackValue(1)); | |
| initialZ = interpreterProxy.stackIntegerValue(2); | |
| initialY = interpreterProxy.stackIntegerValue(3); | |
| initialX = interpreterProxy.stackIntegerValue(4); | |
| index = interpreterProxy.stackIntegerValue(5); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| if (!allocateObjEntry(GEBaseEdgeSize)) { | |
| return interpreterProxy.primitiveFailFor(GEFWorkTooBig); | |
| } | |
| if (!(isFillOkay(leftFillIndex) && (isFillOkay(rightFillIndex)))) { | |
| return interpreterProxy.primitiveFailFor(GEFWrongFill); | |
| } | |
| edge = objUsed; | |
| /* Install type and length */ | |
| objUsed = edge + GEBaseEdgeSize; | |
| objectTypeOfput(edge, GEPrimitiveEdge); | |
| objectLengthOfput(edge, GEBaseEdgeSize); | |
| objectIndexOfput(edge, index); | |
| edgeXValueOfput(edge, initialX); | |
| edgeYValueOfput(edge, initialY); | |
| edgeZValueOfput(edge, initialZ); | |
| edgeLeftFillOfput(edge, transformColor(leftFillIndex)); | |
| edgeRightFillOfput(edge, transformColor(rightFillIndex)); | |
| if (engineStopped) { | |
| return interpreterProxy.primitiveFailFor(GEFEngineStopped); | |
| } | |
| if (!interpreterProxy.failed()) { | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(6); | |
| } | |
| } | |
| function primitiveRegisterExternalFill() { | |
| var failureCode; | |
| var fill; | |
| var index; | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(1), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| index = interpreterProxy.stackIntegerValue(0); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| fill = 0; | |
| while (fill === 0) { | |
| if (!allocateObjEntry(GEBaseEdgeSize)) { | |
| return interpreterProxy.primitiveFailFor(GEFWorkTooBig); | |
| } | |
| fill = objUsed; | |
| /* Install type and length */ | |
| objUsed = fill + GEBaseFillSize; | |
| objectTypeOfput(fill, GEPrimitiveFill); | |
| objectLengthOfput(fill, GEBaseFillSize); | |
| objectIndexOfput(fill, index); | |
| } | |
| if (!interpreterProxy.failed()) { | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(2); | |
| interpreterProxy.pushInteger(fill); | |
| } | |
| } | |
| /* Start/Proceed rendering the entire image */ | |
| function primitiveRenderImage() { | |
| var failCode; | |
| if (((failCode = loadRenderingState())) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failCode); | |
| } | |
| proceedRenderingScanline(); | |
| if (engineStopped) { | |
| return storeRenderingState(); | |
| } | |
| proceedRenderingImage(); | |
| storeRenderingState(); | |
| } | |
| /* Start rendering the entire image */ | |
| function primitiveRenderScanline() { | |
| var failCode; | |
| if (((failCode = loadRenderingState())) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failCode); | |
| } | |
| proceedRenderingScanline(); | |
| storeRenderingState(); | |
| } | |
| function primitiveSetAALevel() { | |
| var failureCode; | |
| var level; | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(1), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| level = interpreterProxy.stackIntegerValue(0); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| setAALevel(level); | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(1); | |
| } | |
| /* Primitive. Set the BitBlt plugin to use. */ | |
| function primitiveSetBitBltPlugin() { | |
| var i; | |
| var length; | |
| var needReload; | |
| var pluginName; | |
| var ptr; | |
| /* Must be string to work */ | |
| pluginName = interpreterProxy.stackValue(0); | |
| if (!interpreterProxy.isBytes(pluginName)) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| length = BYTESIZEOF(pluginName); | |
| if (length >= 256) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| ptr = pluginName.bytes; | |
| needReload = false; | |
| // JS hack: can't copy bytes as in the C version | |
| var newPluginName = pluginName.bytesAsString(); | |
| if (newPluginName !== bbPluginName) { | |
| bbPluginName = newPluginName; | |
| needReload = true; | |
| } | |
| if (needReload) { | |
| if (!initialiseModule()) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| } | |
| interpreterProxy.pop(1); | |
| } | |
| function primitiveSetClipRect() { | |
| var failureCode; | |
| var rectOop; | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(1), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| rectOop = interpreterProxy.stackObjectValue(0); | |
| if (!(!interpreterProxy.failed() && (interpreterProxy.isPointers(rectOop) && (SIZEOF(rectOop) >= 2)))) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| loadPointfrom(point1Get(), interpreterProxy.fetchPointerofObject(0, rectOop)); | |
| loadPointfrom(point2Get(), interpreterProxy.fetchPointerofObject(1, rectOop)); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| clipMinXPut(point1Get()[0]); | |
| clipMinYPut(point1Get()[1]); | |
| clipMaxXPut(point2Get()[0]); | |
| clipMaxYPut(point2Get()[1]); | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(1); | |
| } | |
| function primitiveSetColorTransform() { | |
| var failureCode; | |
| var transformOop; | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(1), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| transformOop = interpreterProxy.stackObjectValue(0); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| loadColorTransformFrom(transformOop); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(GEFEntityLoadFailed); | |
| } | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(1); | |
| } | |
| function primitiveSetDepth() { | |
| var depth; | |
| var failureCode; | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(1), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| depth = interpreterProxy.stackIntegerValue(0); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| currentZPut(depth); | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(1); | |
| } | |
| function primitiveSetEdgeTransform() { | |
| var failureCode; | |
| var transformOop; | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(1), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| transformOop = interpreterProxy.stackObjectValue(0); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| loadEdgeTransformFrom(transformOop); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(1); | |
| } | |
| function primitiveSetOffset() { | |
| var failureCode; | |
| var pointOop; | |
| if (interpreterProxy.methodArgumentCount() !== 1) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadNumArgs); | |
| } | |
| if (((failureCode = quickLoadEngineFromrequiredState(interpreterProxy.stackValue(1), GEStateUnlocked))) !== 0) { | |
| return interpreterProxy.primitiveFailFor(failureCode); | |
| } | |
| pointOop = interpreterProxy.stackValue(0); | |
| if (CLASSOF(pointOop) !== interpreterProxy.classPoint()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| loadPointfrom(point1Get(), pointOop); | |
| if (interpreterProxy.failed()) { | |
| return interpreterProxy.primitiveFailFor(PrimErrBadArgument); | |
| } | |
| destOffsetXPut(point1Get()[0]); | |
| destOffsetYPut(point1Get()[1]); | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(1); | |
| } | |
| /* This is the main rendering entry */ | |
| function proceedRenderingImage() { | |
| var external; | |
| while (!(finishedProcessing())) { | |
| if (doProfileStats) { | |
| geProfileTime = interpreterProxy.ioMicroMSecs(); | |
| } | |
| external = findNextExternalEntryFromGET(); | |
| if (doProfileStats) { | |
| incrementStatby(GWCountNextGETEntry, 1); | |
| incrementStatby(GWTimeNextGETEntry, interpreterProxy.ioMicroMSecs() - geProfileTime); | |
| } | |
| if (engineStopped) { | |
| return statePut(GEStateAddingFromGET); | |
| } | |
| if (external) { | |
| statePut(GEStateWaitingForEdge); | |
| return stopBecauseOf(GErrorGETEntry); | |
| } | |
| aetStartPut(0); | |
| wbStackClear(); | |
| clearSpanBufferPut(1); | |
| if (doProfileStats) { | |
| geProfileTime = interpreterProxy.ioMicroMSecs(); | |
| } | |
| if ((clearSpanBufferGet() !== 0) && ((currentYGet() & aaScanMaskGet()) === 0)) { | |
| clearSpanBuffer(); | |
| } | |
| clearSpanBufferPut(0); | |
| external = findNextExternalFillFromAET(); | |
| if (doProfileStats) { | |
| incrementStatby(GWCountNextFillEntry, 1); | |
| incrementStatby(GWTimeNextFillEntry, interpreterProxy.ioMicroMSecs() - geProfileTime); | |
| } | |
| if (engineStopped) { | |
| return statePut(GEStateScanningAET); | |
| } | |
| if (external) { | |
| statePut(GEStateWaitingForFill); | |
| return stopBecauseOf(GErrorFillEntry); | |
| } | |
| wbStackClear(); | |
| spanEndAAPut(0); | |
| if (doProfileStats) { | |
| geProfileTime = interpreterProxy.ioMicroMSecs(); | |
| } | |
| if ((currentYGet() & aaScanMaskGet()) === aaScanMaskGet()) { | |
| displaySpanBufferAt(currentYGet()); | |
| postDisplayAction(); | |
| } | |
| if (doProfileStats) { | |
| incrementStatby(GWCountDisplaySpan, 1); | |
| incrementStatby(GWTimeDisplaySpan, interpreterProxy.ioMicroMSecs() - geProfileTime); | |
| } | |
| if (engineStopped) { | |
| return statePut(GEStateBlitBuffer); | |
| } | |
| if (finishedProcessing()) { | |
| return 0; | |
| } | |
| aetStartPut(0); | |
| currentYPut(currentYGet() + 1); | |
| if (doProfileStats) { | |
| geProfileTime = interpreterProxy.ioMicroMSecs(); | |
| } | |
| external = findNextExternalUpdateFromAET(); | |
| if (doProfileStats) { | |
| incrementStatby(GWCountNextAETEntry, 1); | |
| incrementStatby(GWTimeNextAETEntry, interpreterProxy.ioMicroMSecs() - geProfileTime); | |
| } | |
| if (engineStopped) { | |
| return statePut(GEStateUpdateEdges); | |
| } | |
| if (external) { | |
| statePut(GEStateWaitingChange); | |
| return stopBecauseOf(GErrorAETEntry); | |
| } | |
| } | |
| } | |
| /* Proceed rendering the current scan line. | |
| This method may be called after some Smalltalk code has been executed inbetween. */ | |
| /* This is the main rendering entry */ | |
| function proceedRenderingScanline() { | |
| var external; | |
| var state; | |
| state = stateGet(); | |
| if (state === GEStateUnlocked) { | |
| initializeGETProcessing(); | |
| if (engineStopped) { | |
| return 0; | |
| } | |
| state = GEStateAddingFromGET; | |
| } | |
| if (state === GEStateAddingFromGET) { | |
| if (doProfileStats) { | |
| geProfileTime = interpreterProxy.ioMicroMSecs(); | |
| } | |
| external = findNextExternalEntryFromGET(); | |
| if (doProfileStats) { | |
| incrementStatby(GWCountNextGETEntry, 1); | |
| incrementStatby(GWTimeNextGETEntry, interpreterProxy.ioMicroMSecs() - geProfileTime); | |
| } | |
| if (engineStopped) { | |
| return statePut(GEStateAddingFromGET); | |
| } | |
| if (external) { | |
| statePut(GEStateWaitingForEdge); | |
| return stopBecauseOf(GErrorGETEntry); | |
| } | |
| aetStartPut(0); | |
| wbStackClear(); | |
| clearSpanBufferPut(1); | |
| state = GEStateScanningAET; | |
| } | |
| if (state === GEStateScanningAET) { | |
| if (doProfileStats) { | |
| geProfileTime = interpreterProxy.ioMicroMSecs(); | |
| } | |
| if ((clearSpanBufferGet() !== 0) && ((currentYGet() & aaScanMaskGet()) === 0)) { | |
| clearSpanBuffer(); | |
| } | |
| clearSpanBufferPut(0); | |
| external = findNextExternalFillFromAET(); | |
| if (doProfileStats) { | |
| incrementStatby(GWCountNextFillEntry, 1); | |
| incrementStatby(GWTimeNextFillEntry, interpreterProxy.ioMicroMSecs() - geProfileTime); | |
| } | |
| if (engineStopped) { | |
| return statePut(GEStateScanningAET); | |
| } | |
| if (external) { | |
| statePut(GEStateWaitingForFill); | |
| return stopBecauseOf(GErrorFillEntry); | |
| } | |
| state = GEStateBlitBuffer; | |
| wbStackClear(); | |
| spanEndAAPut(0); | |
| } | |
| if (state === GEStateBlitBuffer) { | |
| if (doProfileStats) { | |
| geProfileTime = interpreterProxy.ioMicroMSecs(); | |
| } | |
| if ((currentYGet() & aaScanMaskGet()) === aaScanMaskGet()) { | |
| displaySpanBufferAt(currentYGet()); | |
| postDisplayAction(); | |
| } | |
| if (doProfileStats) { | |
| incrementStatby(GWCountDisplaySpan, 1); | |
| incrementStatby(GWTimeDisplaySpan, interpreterProxy.ioMicroMSecs() - geProfileTime); | |
| } | |
| if (engineStopped) { | |
| return statePut(GEStateBlitBuffer); | |
| } | |
| if (finishedProcessing()) { | |
| return 0; | |
| } | |
| state = GEStateUpdateEdges; | |
| aetStartPut(0); | |
| currentYPut(currentYGet() + 1); | |
| } | |
| if (state === GEStateUpdateEdges) { | |
| if (doProfileStats) { | |
| geProfileTime = interpreterProxy.ioMicroMSecs(); | |
| } | |
| external = findNextExternalUpdateFromAET(); | |
| if (doProfileStats) { | |
| incrementStatby(GWCountNextAETEntry, 1); | |
| incrementStatby(GWTimeNextAETEntry, interpreterProxy.ioMicroMSecs() - geProfileTime); | |
| } | |
| if (engineStopped) { | |
| return statePut(GEStateUpdateEdges); | |
| } | |
| if (external) { | |
| statePut(GEStateWaitingChange); | |
| return stopBecauseOf(GErrorAETEntry); | |
| } | |
| statePut(GEStateAddingFromGET); | |
| } | |
| } | |
| /* Load the minimal required state from the engineOop, e.g., just the work buffer. | |
| Answer 0 on success or non-zero a failure code on failure */ | |
| function quickLoadEngineFrom(engineOop) { | |
| var failCode; | |
| if (interpreterProxy.failed()) { | |
| return GEFAlreadyFailed; | |
| } | |
| if (typeof engineOop === "number") { | |
| return GEFEngineIsInteger; | |
| } | |
| if (!interpreterProxy.isPointers(engineOop)) { | |
| return GEFEngineIsWords; | |
| } | |
| if (SIZEOF(engineOop) < BEBalloonEngineSize) { | |
| return GEFEngineTooSmall; | |
| } | |
| engine = engineOop; | |
| if (((failCode = loadWorkBufferFrom(interpreterProxy.fetchPointerofObject(BEWorkBufferIndex, engineOop)))) !== 0) { | |
| return failCode; | |
| } | |
| stopReasonPut(0); | |
| objUsed = objUsedGet(); | |
| engineStopped = false; | |
| return 0; | |
| } | |
| function quickLoadEngineFromrequiredState(oop, requiredState) { | |
| var failureCode; | |
| if (((failureCode = quickLoadEngineFrom(oop))) !== 0) { | |
| return failureCode; | |
| } | |
| if (stateGet() === requiredState) { | |
| return 0; | |
| } | |
| stopReasonPut(GErrorBadState); | |
| return GEFWrongState; | |
| } | |
| function quickLoadEngineFromrequiredStateor(oop, requiredState, alternativeState) { | |
| var failureCode; | |
| if (((failureCode = quickLoadEngineFrom(oop))) !== 0) { | |
| return failureCode; | |
| } | |
| if (stateGet() === requiredState) { | |
| return 0; | |
| } | |
| if (stateGet() === alternativeState) { | |
| return 0; | |
| } | |
| stopReasonPut(GErrorBadState); | |
| return GEFWrongState; | |
| } | |
| /* Remove any top fills if they have become invalid. */ | |
| function quickRemoveInvalidFillsAt(leftX) { | |
| if (stackFillSize() === 0) { | |
| return null; | |
| } | |
| while (topRightX() <= leftX) { | |
| hideFilldepth(topFill(), topDepth()); | |
| if (stackFillSize() === 0) { | |
| return null; | |
| } | |
| } | |
| } | |
| /* Sort elements i through j of self to be nondescending according to | |
| sortBlock. */ | |
| /* Note: The original loop has been heavily re-written for C translation */ | |
| function quickSortGlobalEdgeTablefromto(array, i, j) { | |
| var again; | |
| var before; | |
| var di; | |
| var dij; | |
| var dj; | |
| var ij; | |
| var k; | |
| var l; | |
| var n; | |
| var tmp; | |
| var tt; | |
| /* The prefix d means the data at that index. */ | |
| if (((n = (j + 1) - i)) <= 1) { | |
| return 0; | |
| } | |
| di = array[i]; | |
| dj = array[j]; | |
| /* i.e., should di precede dj? */ | |
| before = getSortsbefore(di, dj); | |
| if (!before) { | |
| tmp = array[i]; | |
| array[i] = array[j]; | |
| array[j] = tmp; | |
| tt = di; | |
| di = dj; | |
| dj = tt; | |
| } | |
| if (n <= 2) { | |
| return 0; | |
| } | |
| /* ij is the midpoint of i and j. */ | |
| ij = (i + j) >> 1; | |
| /* Sort di,dij,dj. Make dij be their median. */ | |
| dij = array[ij]; | |
| /* i.e. should di precede dij? */ | |
| before = getSortsbefore(di, dij); | |
| if (before) { | |
| /* i.e., should dij precede dj? */ | |
| before = getSortsbefore(dij, dj); | |
| if (!before) { | |
| /* i.e., should dij precede dj? */ | |
| tmp = array[j]; | |
| array[j] = array[ij]; | |
| array[ij] = tmp; | |
| dij = dj; | |
| } | |
| } else { | |
| /* i.e. di should come after dij */ | |
| tmp = array[i]; | |
| array[i] = array[ij]; | |
| array[ij] = tmp; | |
| dij = di; | |
| } | |
| if (n <= 3) { | |
| return 0; | |
| } | |
| k = i; | |
| l = j; | |
| again = true; | |
| while (again) { | |
| before = true; | |
| while (before) { | |
| if (k <= ((--l))) { | |
| tmp = array[l]; | |
| before = getSortsbefore(dij, tmp); | |
| } else { | |
| before = false; | |
| } | |
| } | |
| before = true; | |
| while (before) { | |
| if (((++k)) <= l) { | |
| tmp = array[k]; | |
| before = getSortsbefore(tmp, dij); | |
| } else { | |
| before = false; | |
| } | |
| } | |
| again = k <= l; | |
| if (again) { | |
| tmp = array[k]; | |
| array[k] = array[l]; | |
| array[l] = tmp; | |
| } | |
| } | |
| quickSortGlobalEdgeTablefromto(array, i, l); | |
| quickSortGlobalEdgeTablefromto(array, k, j); | |
| } | |
| function rShiftTable() { | |
| var theTable = | |
| [0, 5, 4, 0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1]; | |
| return theTable; | |
| } | |
| function removeFirstAETEntry() { | |
| var index; | |
| index = aetStartGet(); | |
| aetUsedPut(aetUsedGet() - 1); | |
| while (index < aetUsedGet()) { | |
| aetBuffer[index] = aetBuffer[index + 1]; | |
| ++index; | |
| } | |
| } | |
| function repeatValuemax(delta, maxValue) { | |
| var newDelta; | |
| newDelta = delta; | |
| while (newDelta < 0) { | |
| newDelta += maxValue; | |
| } | |
| while (newDelta >= maxValue) { | |
| newDelta -= maxValue; | |
| } | |
| return newDelta; | |
| } | |
| function resetGraphicsEngineStats() { | |
| workBuffer[GWTimeInitializing] = 0; | |
| workBuffer[GWTimeFinishTest] = 0; | |
| workBuffer[GWTimeNextGETEntry] = 0; | |
| workBuffer[GWTimeAddAETEntry] = 0; | |
| workBuffer[GWTimeNextFillEntry] = 0; | |
| workBuffer[GWTimeMergeFill] = 0; | |
| workBuffer[GWTimeDisplaySpan] = 0; | |
| workBuffer[GWTimeNextAETEntry] = 0; | |
| workBuffer[GWTimeChangeAETEntry] = 0; | |
| workBuffer[GWCountInitializing] = 0; | |
| workBuffer[GWCountFinishTest] = 0; | |
| workBuffer[GWCountNextGETEntry] = 0; | |
| workBuffer[GWCountAddAETEntry] = 0; | |
| workBuffer[GWCountNextFillEntry] = 0; | |
| workBuffer[GWCountMergeFill] = 0; | |
| workBuffer[GWCountDisplaySpan] = 0; | |
| workBuffer[GWCountNextAETEntry] = 0; | |
| workBuffer[GWCountChangeAETEntry] = 0; | |
| workBuffer[GWBezierMonotonSubdivisions] = 0; | |
| workBuffer[GWBezierHeightSubdivisions] = 0; | |
| workBuffer[GWBezierOverflowSubdivisions] = 0; | |
| workBuffer[GWBezierLineConversions] = 0; | |
| } | |
| function resortFirstAETEntry() { | |
| var edge; | |
| var leftEdge; | |
| var xValue; | |
| if (aetStartGet() === 0) { | |
| return null; | |
| } | |
| edge = aetBuffer[aetStartGet()]; | |
| xValue = edgeXValueOf(edge); | |
| leftEdge = aetBuffer[aetStartGet() - 1]; | |
| if (edgeXValueOf(leftEdge) <= xValue) { | |
| return null; | |
| } | |
| moveAETEntryFromedgex(aetStartGet(), edge, xValue); | |
| } | |
| function returnWideBezierFill() { | |
| return (dispatchReturnValue = wideBezierFillOf(dispatchedValue)); | |
| } | |
| function returnWideBezierWidth() { | |
| return (dispatchReturnValue = wideBezierWidthOf(dispatchedValue)); | |
| } | |
| /* Return the fill of the (wide) line - this method is called from a case. */ | |
| function returnWideLineFill() { | |
| return (dispatchReturnValue = wideLineFillOf(dispatchedValue)); | |
| } | |
| /* Return the width of the (wide) line - this method is called from a case. */ | |
| function returnWideLineWidth() { | |
| return (dispatchReturnValue = wideLineWidthOf(dispatchedValue)); | |
| } | |
| /* Set the anti-aliasing level. Three levels are supported: | |
| 1 - No antialiasing | |
| 2 - 2x2 unweighted anti-aliasing | |
| 4 - 4x4 unweighted anti-aliasing. | |
| */ | |
| function setAALevel(level) { | |
| var aaLevel; | |
| if (level >= 4) { | |
| aaLevel = 4; | |
| } | |
| if ((level >= 2) && (level < 4)) { | |
| aaLevel = 2; | |
| } | |
| if (level < 2) { | |
| aaLevel = 1; | |
| } | |
| aaLevelPut(aaLevel); | |
| if (aaLevel === 1) { | |
| aaShiftPut(0); | |
| aaColorMaskPut(4294967295); | |
| aaScanMaskPut(0); | |
| } | |
| if (aaLevel === 2) { | |
| aaShiftPut(1); | |
| aaColorMaskPut(4244438268); | |
| aaScanMaskPut(1); | |
| } | |
| if (aaLevel === 4) { | |
| aaShiftPut(2); | |
| aaColorMaskPut(4042322160); | |
| aaScanMaskPut(3); | |
| } | |
| aaColorShiftPut(aaShiftGet() * 2); | |
| aaHalfPixelPut(aaShiftGet()); | |
| } | |
| /* Note: This is coded so that is can be run from Squeak. */ | |
| function setInterpreter(anInterpreter) { | |
| var ok; | |
| interpreterProxy = anInterpreter; | |
| ok = interpreterProxy.majorVersion() == VM_PROXY_MAJOR; | |
| if (ok === false) { | |
| return false; | |
| } | |
| ok = interpreterProxy.minorVersion() >= VM_PROXY_MINOR; | |
| return ok; | |
| } | |
| /* Return the run-length value from the given ShortRunArray. */ | |
| function shortRunLengthAtfrom(i, runArray) { | |
| return (runArray[i]|0) >>> 16; | |
| } | |
| /* Return the run-length value from the given ShortRunArray. | |
| Note: We don't need any coercion to short/int here, since | |
| we deal basically only with unsigned values. */ | |
| function shortRunValueAtfrom(i, runArray) { | |
| return (runArray[i]|0) & 65535; | |
| } | |
| function showFilldepthrightX(fillIndex, depth, rightX) { | |
| if (!allocateStackFillEntry()) { | |
| return null; | |
| } | |
| stackFillValueput(0, fillIndex); | |
| stackFillDepthput(0, depth); | |
| stackFillRightXput(0, rightX); | |
| if (stackFillSize() === stackFillEntryLength()) { | |
| return null; | |
| } | |
| if (fillSortsbefore(0, stackFillSize() - stackFillEntryLength())) { | |
| /* New top fill */ | |
| stackFillValueput(0, topFillValue()); | |
| stackFillDepthput(0, topFillDepth()); | |
| stackFillRightXput(0, topFillRightX()); | |
| topFillValuePut(fillIndex); | |
| topFillDepthPut(depth); | |
| topFillRightXPut(rightX); | |
| } | |
| } | |
| function smallSqrtTable() { | |
| var theTable = | |
| [0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6]; | |
| return theTable; | |
| } | |
| /* Sort the entire global edge table */ | |
| function sortGlobalEdgeTable() { | |
| quickSortGlobalEdgeTablefromto(getBuffer, 0, getUsedGet() - 1); | |
| } | |
| function spanEndAAGet() { | |
| return workBuffer[GWSpanEndAA]; | |
| } | |
| function spanEndAAPut(value) { | |
| return workBuffer[GWSpanEndAA] = value; | |
| } | |
| function spanEndGet() { | |
| return workBuffer[GWSpanEnd]; | |
| } | |
| function spanEndPut(value) { | |
| return workBuffer[GWSpanEnd] = value; | |
| } | |
| function spanSizeGet() { | |
| return workBuffer[GWSpanSize]; | |
| } | |
| function spanSizePut(value) { | |
| return workBuffer[GWSpanSize] = value; | |
| } | |
| function spanStartGet() { | |
| return workBuffer[GWSpanStart]; | |
| } | |
| function spanStartPut(value) { | |
| return workBuffer[GWSpanStart] = value; | |
| } | |
| function squaredLengthOfwith(deltaX, deltaY) { | |
| return (deltaX * deltaX) + (deltaY * deltaY); | |
| } | |
| function stackFillDepth(index) { | |
| return wbStackValue(index + 1); | |
| } | |
| function stackFillDepthput(index, value) { | |
| return wbStackValueput(index + 1, value); | |
| } | |
| function stackFillEntryLength() { | |
| return 3; | |
| } | |
| function stackFillRightX(index) { | |
| return wbStackValue(index + 2); | |
| } | |
| function stackFillRightXput(index, value) { | |
| return wbStackValueput(index + 2, value); | |
| } | |
| function stackFillSize() { | |
| return wbStackSize(); | |
| } | |
| function stackFillValue(index) { | |
| return wbStackValue(index); | |
| } | |
| function stackFillValueput(index, value) { | |
| return wbStackValueput(index, value); | |
| } | |
| function stateGet() { | |
| return workBuffer[GWState]; | |
| } | |
| function statePut(value) { | |
| return workBuffer[GWState] = value; | |
| } | |
| /* Initialize the current entry in the GET by stepping to the current scan line */ | |
| function stepToFirstBezier() { | |
| return stepToFirstBezierInat(getBuffer[getStartGet()], currentYGet()); | |
| } | |
| /* Initialize the bezier at yValue. | |
| TODO: Check if reducing maxSteps from 2*deltaY to deltaY | |
| brings a *significant* performance improvement. | |
| In theory this should make for double step performance | |
| but will cost in quality. Might be that the AA stuff will | |
| compensate for this - but I'm not really sure. */ | |
| function stepToFirstBezierInat(bezier, yValue) { | |
| var deltaY; | |
| var endX; | |
| var endY; | |
| var fwDDx; | |
| var fwDDy; | |
| var fwDx; | |
| var fwDy; | |
| var fwX1; | |
| var fwX2; | |
| var fwY1; | |
| var fwY2; | |
| var maxSteps; | |
| var scaledStepSize; | |
| var squaredStepSize; | |
| var startX; | |
| var startY; | |
| var updateData; | |
| var viaX; | |
| var viaY; | |
| /* Do a quick check if there is anything at all to do */ | |
| if (!isWide(bezier) && (yValue >= bezierEndYOf(bezier))) { | |
| return edgeNumLinesOfput(bezier, 0); | |
| } | |
| startX = edgeXValueOf(bezier); | |
| startY = edgeYValueOf(bezier); | |
| viaX = bezierViaXOf(bezier); | |
| viaY = bezierViaYOf(bezier); | |
| endX = bezierEndXOf(bezier); | |
| endY = bezierEndYOf(bezier); | |
| /* Initialize integer forward differencing */ | |
| deltaY = endY - startY; | |
| fwX1 = (viaX - startX) * 2; | |
| fwX2 = (startX + endX) - (viaX * 2); | |
| fwY1 = (viaY - startY) * 2; | |
| fwY2 = (startY + endY) - (viaY * 2); | |
| maxSteps = deltaY * 2; | |
| if (maxSteps < 2) { | |
| maxSteps = 2; | |
| } | |
| scaledStepSize = DIV(16777216, maxSteps); | |
| squaredStepSize = absoluteSquared8Dot24(scaledStepSize); | |
| fwDx = fwX1 * scaledStepSize; | |
| fwDDx = (fwX2 * squaredStepSize) * 2; | |
| fwDx += fwDDx >> 1; | |
| fwDy = fwY1 * scaledStepSize; | |
| fwDDy = (fwY2 * squaredStepSize) * 2; | |
| /* Store the values */ | |
| fwDy += fwDDy >> 1; | |
| edgeNumLinesOfput(bezier, deltaY); | |
| updateData = bezierUpdateDataOf(bezier); | |
| updateData[GBUpdateX] = (startX * 256); | |
| updateData[GBUpdateY] = (startY * 256); | |
| updateData[GBUpdateDX] = fwDx; | |
| updateData[GBUpdateDY] = fwDy; | |
| updateData[GBUpdateDDX] = fwDDx; | |
| updateData[GBUpdateDDY] = fwDDy; | |
| if (((startY = edgeYValueOf(bezier))) !== yValue) { | |
| stepToNextBezierInat(bezier, yValue); | |
| edgeNumLinesOfput(bezier, deltaY - (yValue - startY)); | |
| } | |
| } | |
| /* Initialize the current entry in the GET by stepping to the current scan line */ | |
| function stepToFirstLine() { | |
| return stepToFirstLineInat(getBuffer[getStartGet()], currentYGet()); | |
| } | |
| /* Initialize the line at yValue */ | |
| function stepToFirstLineInat(line, yValue) { | |
| var deltaX; | |
| var deltaY; | |
| var error; | |
| var errorAdjUp; | |
| var i; | |
| var startY; | |
| var widthX; | |
| var xDir; | |
| var xInc; | |
| /* Do a quick check if there is anything at all to do */ | |
| if (!isWide(line) && (yValue >= lineEndYOf(line))) { | |
| return edgeNumLinesOfput(line, 0); | |
| } | |
| deltaX = lineEndXOf(line) - edgeXValueOf(line); | |
| /* Check if edge goes left to right */ | |
| deltaY = lineEndYOf(line) - edgeYValueOf(line); | |
| if (deltaX >= 0) { | |
| xDir = 1; | |
| widthX = deltaX; | |
| error = 0; | |
| } else { | |
| xDir = -1; | |
| widthX = 0 - deltaX; | |
| error = 1 - deltaY; | |
| } | |
| if (deltaY === 0) { | |
| /* No error for horizontal edges */ | |
| error = 0; | |
| /* Encodes width and direction */ | |
| xInc = deltaX; | |
| errorAdjUp = 0; | |
| } else { | |
| /* Check if edge is y-major */ | |
| if (deltaY > widthX) { | |
| /* Note: The '>' instead of '>=' could be important here... */ | |
| xInc = 0; | |
| errorAdjUp = widthX; | |
| } else { | |
| xInc = (DIV(widthX, deltaY)) * xDir; | |
| errorAdjUp = MOD(widthX, deltaY); | |
| } | |
| } | |
| edgeNumLinesOfput(line, deltaY); | |
| lineXDirectionOfput(line, xDir); | |
| lineXIncrementOfput(line, xInc); | |
| lineErrorOfput(line, error); | |
| lineErrorAdjUpOfput(line, errorAdjUp); | |
| lineErrorAdjDownOfput(line, deltaY); | |
| if (((startY = edgeYValueOf(line))) !== yValue) { | |
| for (i = startY; i <= (yValue - 1); i++) { | |
| stepToNextLineInat(line, i); | |
| } | |
| edgeNumLinesOfput(line, deltaY - (yValue - startY)); | |
| } | |
| } | |
| /* Initialize the current entry in the GET by stepping to the current scan line */ | |
| function stepToFirstWideBezier() { | |
| return stepToFirstWideBezierInat(getBuffer[getStartGet()], currentYGet()); | |
| } | |
| /* Initialize the bezier at yValue */ | |
| function stepToFirstWideBezierInat(bezier, yValue) { | |
| var endX; | |
| var i; | |
| var lineOffset; | |
| var lineWidth; | |
| var nLines; | |
| var startY; | |
| var xDir; | |
| var yEntry; | |
| var yExit; | |
| /* Get some values */ | |
| lineWidth = wideBezierExtentOf(bezier); | |
| /* Compute the incremental values of the bezier */ | |
| lineOffset = offsetFromWidth(lineWidth); | |
| endX = bezierEndXOf(bezier); | |
| startY = edgeYValueOf(bezier); | |
| stepToFirstBezierInat(bezier, startY); | |
| /* Copy the incremental update data */ | |
| nLines = edgeNumLinesOf(bezier); | |
| for (i = 0; i <= 5; i++) { | |
| wideBezierUpdateDataOf(bezier)[i] = bezierUpdateDataOf(bezier)[i]; | |
| } | |
| xDir = bezierUpdateDataOf(bezier)[GBUpdateDX]; | |
| if (xDir === 0) { | |
| bezierUpdateDataOf(bezier)[GBUpdateDDX]; | |
| } | |
| if (xDir >= 0) { | |
| xDir = 1; | |
| } else { | |
| xDir = -1; | |
| } | |
| if (xDir < 0) { | |
| adjustWideBezierLeftwidthoffsetendX(bezier, lineWidth, lineOffset, endX); | |
| } else { | |
| adjustWideBezierRightwidthoffsetendX(bezier, lineWidth, lineOffset, endX); | |
| } | |
| if (nLines === 0) { | |
| bezierUpdateDataOf(bezier)[GBUpdateX] = (bezierFinalXOf(bezier) * 256); | |
| } | |
| edgeNumLinesOfput(bezier, nLines + lineWidth); | |
| /* turned on at lineOffset */ | |
| yEntry = 0; | |
| /* turned off at zero */ | |
| yExit = (0 - nLines) - lineOffset; | |
| wideBezierEntryOfput(bezier, yEntry); | |
| wideBezierExitOfput(bezier, yExit); | |
| if ((yEntry >= lineOffset) && (yExit < 0)) { | |
| edgeFillsValidate(bezier); | |
| } else { | |
| edgeFillsInvalidate(bezier); | |
| } | |
| computeFinalWideBezierValueswidth(bezier, lineWidth); | |
| if (startY !== yValue) { | |
| /* Note: Must single step here so that entry/exit works */ | |
| for (i = startY; i <= (yValue - 1); i++) { | |
| stepToNextWideBezierInat(bezier, i); | |
| } | |
| edgeNumLinesOfput(bezier, edgeNumLinesOf(bezier) - (yValue - startY)); | |
| } | |
| } | |
| /* Initialize the current entry in the GET by stepping to the current scan line */ | |
| function stepToFirstWideLine() { | |
| return stepToFirstWideLineInat(getBuffer[getStartGet()], currentYGet()); | |
| } | |
| /* Initialize the wide line at yValue. */ | |
| function stepToFirstWideLineInat(line, yValue) { | |
| var i; | |
| var lineOffset; | |
| var lineWidth; | |
| var nLines; | |
| var startX; | |
| var startY; | |
| var xDir; | |
| var yEntry; | |
| var yExit; | |
| /* Get some values */ | |
| lineWidth = wideLineExtentOf(line); | |
| /* Compute the incremental values of the line */ | |
| lineOffset = offsetFromWidth(lineWidth); | |
| startX = edgeXValueOf(line); | |
| startY = edgeYValueOf(line); | |
| stepToFirstLineInat(line, startY); | |
| nLines = edgeNumLinesOf(line); | |
| /* Adjust the line to start at the correct X position */ | |
| xDir = lineXDirectionOf(line); | |
| edgeXValueOfput(line, startX - lineOffset); | |
| edgeNumLinesOfput(line, nLines + lineWidth); | |
| if (xDir > 0) { | |
| wideLineWidthOfput(line, lineXIncrementOf(line) + lineWidth); | |
| } else { | |
| wideLineWidthOfput(line, lineWidth - lineXIncrementOf(line)); | |
| edgeXValueOfput(line, edgeXValueOf(line) + lineXIncrementOf(line)); | |
| } | |
| /* turned on at lineOffset */ | |
| yEntry = 0; | |
| /* turned off at zero */ | |
| yExit = (0 - nLines) - lineOffset; | |
| wideLineEntryOfput(line, yEntry); | |
| wideLineExitOfput(line, yExit); | |
| if ((yEntry >= lineOffset) && (yExit < 0)) { | |
| edgeFillsValidate(line); | |
| } else { | |
| edgeFillsInvalidate(line); | |
| } | |
| if (startY !== yValue) { | |
| for (i = startY; i <= (yValue - 1); i++) { | |
| stepToNextWideLineInat(line, i); | |
| } | |
| edgeNumLinesOfput(line, edgeNumLinesOf(line) - (yValue - startY)); | |
| } | |
| } | |
| /* Process the current entry in the AET by stepping to the next scan line */ | |
| function stepToNextBezier() { | |
| return stepToNextBezierInat(aetBuffer[aetStartGet()], currentYGet()); | |
| } | |
| /* Incrementally step to the next scan line in the given bezier update data. */ | |
| function stepToNextBezierForwardat(updateData, yValue) { | |
| var fwDx; | |
| var fwDy; | |
| var lastX; | |
| var lastY; | |
| var minY; | |
| lastX = updateData[GBUpdateX]; | |
| lastY = updateData[GBUpdateY]; | |
| fwDx = updateData[GBUpdateDX]; | |
| fwDy = updateData[GBUpdateDY]; | |
| /* Step as long as we haven't yet reached minY and also | |
| as long as fwDy is greater than zero thus stepping down. | |
| Note: The test for fwDy should not be necessary in theory | |
| but is a good insurance in practice. */ | |
| minY = yValue * 256; | |
| while ((minY > lastY) && (fwDy >= 0)) { | |
| lastX += (fwDx + 32768) >> 16; | |
| lastY += (fwDy + 32768) >> 16; | |
| fwDx += updateData[GBUpdateDDX]; | |
| fwDy += updateData[GBUpdateDDY]; | |
| } | |
| updateData[GBUpdateX] = lastX; | |
| updateData[GBUpdateY] = lastY; | |
| updateData[GBUpdateDX] = fwDx; | |
| updateData[GBUpdateDY] = fwDy; | |
| return lastX >> 8; | |
| } | |
| /* Incrementally step to the next scan line in the given bezier */ | |
| function stepToNextBezierInat(bezier, yValue) { | |
| var xValue; | |
| xValue = stepToNextBezierForwardat(bezierUpdateDataOf(bezier), yValue); | |
| edgeXValueOfput(bezier, xValue); | |
| } | |
| /* Process the current entry in the AET by stepping to the next scan line */ | |
| function stepToNextLine() { | |
| return stepToNextLineInat(aetBuffer[aetStartGet()], currentYGet()); | |
| } | |
| /* Incrementally step to the next scan line in the given line */ | |
| function stepToNextLineInat(line, yValue) { | |
| var err; | |
| var x; | |
| x = edgeXValueOf(line) + lineXIncrementOf(line); | |
| err = lineErrorOf(line) + lineErrorAdjUpOf(line); | |
| if (err > 0) { | |
| x += lineXDirectionOf(line); | |
| err -= lineErrorAdjDownOf(line); | |
| } | |
| lineErrorOfput(line, err); | |
| edgeXValueOfput(line, x); | |
| } | |
| /* Initialize the current entry in the GET by stepping to the current scan line */ | |
| function stepToNextWideBezier() { | |
| stepToNextWideBezierInat(aetBuffer[aetStartGet()], currentYGet()); | |
| } | |
| /* Incrementally step to the next scan line in the given wide bezier */ | |
| function stepToNextWideBezierInat(bezier, yValue) { | |
| var lineOffset; | |
| var lineWidth; | |
| var yEntry; | |
| var yExit; | |
| /* Don't inline this */ | |
| lineWidth = wideBezierExtentOf(bezier); | |
| lineOffset = offsetFromWidth(lineWidth); | |
| yEntry = wideBezierEntryOf(bezier) + 1; | |
| yExit = wideBezierExitOf(bezier) + 1; | |
| wideBezierEntryOfput(bezier, yEntry); | |
| wideBezierExitOfput(bezier, yExit); | |
| if (yEntry >= lineOffset) { | |
| edgeFillsValidate(bezier); | |
| } | |
| if (yExit >= 0) { | |
| edgeFillsInvalidate(bezier); | |
| } | |
| if ((yExit + lineOffset) < 0) { | |
| stepToNextBezierForwardat(bezierUpdateDataOf(bezier), yValue); | |
| } else { | |
| /* Adjust the last x value to the final x recorded previously */ | |
| bezierUpdateDataOf(bezier)[GBUpdateX] = (bezierFinalXOf(bezier) * 256); | |
| } | |
| stepToNextBezierForwardat(wideBezierUpdateDataOf(bezier), yValue); | |
| computeFinalWideBezierValueswidth(bezier, lineWidth); | |
| } | |
| /* Process the current entry in the AET by stepping to the next scan line */ | |
| function stepToNextWideLine() { | |
| return stepToNextWideLineInat(aetBuffer[aetStartGet()], currentYGet()); | |
| } | |
| /* Incrementally step to the next scan line in the given wide line */ | |
| function stepToNextWideLineInat(line, yValue) { | |
| var lastX; | |
| var lineOffset; | |
| var lineWidth; | |
| var nextX; | |
| var yEntry; | |
| var yExit; | |
| /* Adjust entry/exit values */ | |
| yEntry = wideLineEntryOf(line) + 1; | |
| yExit = wideLineExitOf(line) + 1; | |
| wideLineEntryOfput(line, yEntry); | |
| wideLineExitOfput(line, yExit); | |
| lineWidth = wideLineExtentOf(line); | |
| lineOffset = offsetFromWidth(lineWidth); | |
| if (yEntry >= lineOffset) { | |
| edgeFillsValidate(line); | |
| } | |
| if (yExit >= 0) { | |
| edgeFillsInvalidate(line); | |
| } | |
| lastX = edgeXValueOf(line); | |
| stepToNextLineInat(line, yValue); | |
| /* Check for special start/end adjustments */ | |
| nextX = edgeXValueOf(line); | |
| if ((yEntry <= lineWidth) || ((yExit + lineOffset) >= 0)) { | |
| /* Yes, need an update */ | |
| adjustWideLineafterSteppingFromto(line, lastX, nextX); | |
| } | |
| } | |
| function stopBecauseOf(stopReason) { | |
| stopReasonPut(stopReason); | |
| engineStopped = true; | |
| } | |
| function stopReasonGet() { | |
| return workBuffer[GWStopReason]; | |
| } | |
| function stopReasonPut(value) { | |
| return workBuffer[GWStopReason] = value; | |
| } | |
| function storeEdgeStateFrominto(edge, edgeOop) { | |
| if (SIZEOF(edgeOop) < ETBalloonEdgeDataSize) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| interpreterProxy.storeIntegerofObjectwithValue(ETIndexIndex, edgeOop, objectIndexOf(edge)); | |
| interpreterProxy.storeIntegerofObjectwithValue(ETXValueIndex, edgeOop, edgeXValueOf(edge)); | |
| interpreterProxy.storeIntegerofObjectwithValue(ETYValueIndex, edgeOop, currentYGet()); | |
| interpreterProxy.storeIntegerofObjectwithValue(ETZValueIndex, edgeOop, edgeZValueOf(edge)); | |
| interpreterProxy.storeIntegerofObjectwithValue(ETLinesIndex, edgeOop, edgeNumLinesOf(edge)); | |
| lastExportedEdgePut(edge); | |
| } | |
| function storeEngineStateInto(oop) { | |
| objUsedPut(objUsed); | |
| } | |
| function storeFillStateInto(fillOop) { | |
| var fillIndex; | |
| var leftX; | |
| var rightX; | |
| fillIndex = lastExportedFillGet(); | |
| leftX = lastExportedLeftXGet(); | |
| rightX = lastExportedRightXGet(); | |
| if (SIZEOF(fillOop) < FTBalloonFillDataSize) { | |
| return interpreterProxy.primitiveFail(); | |
| } | |
| interpreterProxy.storeIntegerofObjectwithValue(FTIndexIndex, fillOop, objectIndexOf(fillIndex)); | |
| interpreterProxy.storeIntegerofObjectwithValue(FTMinXIndex, fillOop, leftX); | |
| interpreterProxy.storeIntegerofObjectwithValue(FTMaxXIndex, fillOop, rightX); | |
| interpreterProxy.storeIntegerofObjectwithValue(FTYValueIndex, fillOop, currentYGet()); | |
| } | |
| function storeRenderingState() { | |
| if (interpreterProxy.failed()) { | |
| return null; | |
| } | |
| if (engineStopped) { | |
| /* Check the stop reason and store the required information */ | |
| storeStopStateIntoEdgefill(interpreterProxy.stackObjectValue(1), interpreterProxy.stackObjectValue(0)); | |
| } | |
| storeEngineStateInto(engine); | |
| interpreterProxy.pop(3); | |
| interpreterProxy.pushInteger(stopReasonGet()); | |
| } | |
| function storeStopStateIntoEdgefill(edgeOop, fillOop) { | |
| var edge; | |
| var reason; | |
| reason = stopReasonGet(); | |
| if (reason === GErrorGETEntry) { | |
| edge = getBuffer[getStartGet()]; | |
| storeEdgeStateFrominto(edge, edgeOop); | |
| getStartPut(getStartGet() + 1); | |
| } | |
| if (reason === GErrorFillEntry) { | |
| storeFillStateInto(fillOop); | |
| } | |
| if (reason === GErrorAETEntry) { | |
| edge = aetBuffer[aetStartGet()]; | |
| storeEdgeStateFrominto(edge, edgeOop); | |
| } | |
| } | |
| /* Subdivide the given bezier curve if necessary */ | |
| function subdivideBezier(index) { | |
| var deltaX; | |
| var deltaY; | |
| var endX; | |
| var endY; | |
| var startX; | |
| var startY; | |
| startY = bzStartY(index); | |
| /* If the receiver is horizontal, don't do anything */ | |
| endY = bzEndY(index); | |
| if (endY === startY) { | |
| return index; | |
| } | |
| deltaY = endY - startY; | |
| if (deltaY < 0) { | |
| deltaY = 0 - deltaY; | |
| } | |
| if (deltaY > 255) { | |
| incrementStatby(GWBezierHeightSubdivisions, 1); | |
| return computeBezierSplitAtHalf(index); | |
| } | |
| startX = bzStartX(index); | |
| endX = bzEndX(index); | |
| deltaX = endX - startX; | |
| if (deltaX < 0) { | |
| deltaX = 0 - deltaX; | |
| } | |
| if ((deltaY * 32) < deltaX) { | |
| incrementStatby(GWBezierOverflowSubdivisions, 1); | |
| return computeBezierSplitAtHalf(index); | |
| } | |
| return index; | |
| } | |
| /* Recursively subdivide the curve on the bezier stack. */ | |
| function subdivideBezierFrom(index) { | |
| var index1; | |
| var index2; | |
| var otherIndex; | |
| otherIndex = subdivideBezier(index); | |
| if (otherIndex !== index) { | |
| index1 = subdivideBezierFrom(index); | |
| if (engineStopped) { | |
| return 0; | |
| } | |
| index2 = subdivideBezierFrom(otherIndex); | |
| if (engineStopped) { | |
| return 0; | |
| } | |
| if (index1 >= index2) { | |
| return index1; | |
| } else { | |
| return index2; | |
| } | |
| } | |
| return index; | |
| } | |
| /* Check if the given bezier curve is monoton in Y, and, if desired in X. | |
| If not, subdivide it */ | |
| function subdivideToBeMonotoninX(base, doTestX) { | |
| var base2; | |
| var index1; | |
| var index2; | |
| base2 = (index1 = (index2 = subdivideToBeMonotonInY(base))); | |
| if (doTestX) { | |
| index1 = subdivideToBeMonotonInX(base); | |
| } | |
| if (index1 > index2) { | |
| index2 = index1; | |
| } | |
| if ((base !== base2) && (doTestX)) { | |
| index1 = subdivideToBeMonotonInX(base2); | |
| } | |
| if (index1 > index2) { | |
| index2 = index1; | |
| } | |
| return index2; | |
| } | |
| /* Check if the given bezier curve is monoton in X. If not, subdivide it */ | |
| function subdivideToBeMonotonInX(index) { | |
| var denom; | |
| var dx1; | |
| var dx2; | |
| var endX; | |
| var num; | |
| var startX; | |
| var viaX; | |
| startX = bzStartX(index); | |
| viaX = bzViaX(index); | |
| endX = bzEndX(index); | |
| dx1 = viaX - startX; | |
| dx2 = endX - viaX; | |
| if ((dx1 * dx2) >= 0) { | |
| return index; | |
| } | |
| incrementStatby(GWBezierMonotonSubdivisions, 1); | |
| denom = dx2 - dx1; | |
| num = dx1; | |
| if (num < 0) { | |
| num = 0 - num; | |
| } | |
| if (denom < 0) { | |
| denom = 0 - denom; | |
| } | |
| return computeBeziersplitAt(index, num / denom); | |
| } | |
| /* Check if the given bezier curve is monoton in Y. If not, subdivide it */ | |
| function subdivideToBeMonotonInY(index) { | |
| var denom; | |
| var dy1; | |
| var dy2; | |
| var endY; | |
| var num; | |
| var startY; | |
| var viaY; | |
| startY = bzStartY(index); | |
| viaY = bzViaY(index); | |
| endY = bzEndY(index); | |
| dy1 = viaY - startY; | |
| dy2 = endY - viaY; | |
| if ((dy1 * dy2) >= 0) { | |
| return index; | |
| } | |
| incrementStatby(GWBezierMonotonSubdivisions, 1); | |
| denom = dy2 - dy1; | |
| num = dy1; | |
| if (num < 0) { | |
| num = 0 - num; | |
| } | |
| if (denom < 0) { | |
| denom = 0 - denom; | |
| } | |
| return computeBeziersplitAt(index, num / denom); | |
| } | |
| /* Make the fill style with the given index either visible or invisible */ | |
| function toggleFilldepthrightX(fillIndex, depth, rightX) { | |
| var hidden; | |
| if (stackFillSize() === 0) { | |
| if (allocateStackFillEntry()) { | |
| topFillValuePut(fillIndex); | |
| topFillDepthPut(depth); | |
| topFillRightXPut(rightX); | |
| } | |
| } else { | |
| hidden = hideFilldepth(fillIndex, depth); | |
| if (!hidden) { | |
| showFilldepthrightX(fillIndex, depth, rightX); | |
| } | |
| } | |
| } | |
| function toggleFillsOf(edge) { | |
| var depth; | |
| var fillIndex; | |
| if (!needAvailableSpace(stackFillEntryLength() * 2)) { | |
| return null; | |
| } | |
| depth = edgeZValueOf(edge) << 1; | |
| fillIndex = edgeLeftFillOf(edge); | |
| if (fillIndex !== 0) { | |
| toggleFilldepthrightX(fillIndex, depth, 999999999); | |
| } | |
| fillIndex = edgeRightFillOf(edge); | |
| if (fillIndex !== 0) { | |
| toggleFilldepthrightX(fillIndex, depth, 999999999); | |
| } | |
| quickRemoveInvalidFillsAt(edgeXValueOf(edge)); | |
| } | |
| function toggleWideFillOf(edge) { | |
| var depth; | |
| var fill; | |
| var index; | |
| var lineWidth; | |
| var rightX; | |
| var type; | |
| type = edgeTypeOf(edge); | |
| dispatchedValue = edge; | |
| switch (type) { | |
| case 0: | |
| case 1: | |
| errorWrongIndex(); | |
| break; | |
| case 2: | |
| returnWideLineWidth(); | |
| break; | |
| case 3: | |
| returnWideBezierWidth(); | |
| break; | |
| } | |
| lineWidth = dispatchReturnValue; | |
| switch (type) { | |
| case 0: | |
| case 1: | |
| errorWrongIndex(); | |
| break; | |
| case 2: | |
| returnWideLineFill(); | |
| break; | |
| case 3: | |
| returnWideBezierFill(); | |
| break; | |
| } | |
| fill = dispatchReturnValue; | |
| if (fill === 0) { | |
| return null; | |
| } | |
| if (!needAvailableSpace(stackFillEntryLength())) { | |
| return null; | |
| } | |
| /* So lines sort before interior fills */ | |
| depth = (edgeZValueOf(edge) << 1) + 1; | |
| rightX = edgeXValueOf(edge) + lineWidth; | |
| index = findStackFilldepth(fill, depth); | |
| if (index === -1) { | |
| showFilldepthrightX(fill, depth, rightX); | |
| } else { | |
| if (stackFillRightX(index) < rightX) { | |
| stackFillRightXput(index, rightX); | |
| } | |
| } | |
| quickRemoveInvalidFillsAt(edgeXValueOf(edge)); | |
| } | |
| function topDepth() { | |
| if (stackFillSize() === 0) { | |
| return -1; | |
| } else { | |
| return topFillDepth(); | |
| } | |
| } | |
| function topFill() { | |
| if (stackFillSize() === 0) { | |
| return 0; | |
| } else { | |
| return topFillValue(); | |
| } | |
| } | |
| function topFillDepth() { | |
| return stackFillDepth(stackFillSize() - stackFillEntryLength()); | |
| } | |
| function topFillDepthPut(value) { | |
| return stackFillDepthput(stackFillSize() - stackFillEntryLength(), value); | |
| } | |
| function topFillRightX() { | |
| return stackFillRightX(stackFillSize() - stackFillEntryLength()); | |
| } | |
| function topFillRightXPut(value) { | |
| return stackFillRightXput(stackFillSize() - stackFillEntryLength(), value); | |
| } | |
| function topFillValue() { | |
| return stackFillValue(stackFillSize() - stackFillEntryLength()); | |
| } | |
| function topFillValuePut(value) { | |
| return stackFillValueput(stackFillSize() - stackFillEntryLength(), value); | |
| } | |
| function topRightX() { | |
| if (stackFillSize() === 0) { | |
| return 999999999; | |
| } else { | |
| return topFillRightX(); | |
| } | |
| } | |
| function transformColor(fillIndex) { | |
| var a; | |
| var alphaScale; | |
| var b; | |
| var g; | |
| var r; | |
| var transform; | |
| if (!((fillIndex === 0) || (isFillColor(fillIndex)))) { | |
| return fillIndex; | |
| } | |
| b = fillIndex & 255; | |
| g = (fillIndex >>> 8) & 255; | |
| r = (fillIndex >>> 16) & 255; | |
| a = (fillIndex >>> 24) & 255; | |
| if (hasColorTransform()) { | |
| transform = colorTransform(); | |
| alphaScale = ((a * transform[6]) + transform[7]) / a; | |
| r = ((((r * transform[0]) + transform[1]) * alphaScale)|0); | |
| g = ((((g * transform[2]) + transform[3]) * alphaScale)|0); | |
| b = ((((b * transform[4]) + transform[5]) * alphaScale)|0); | |
| a = a * alphaScale|0; | |
| r = Math.max(r, 0); | |
| r = Math.min(r, 255); | |
| g = Math.max(g, 0); | |
| g = Math.min(g, 255); | |
| b = Math.max(b, 0); | |
| b = Math.min(b, 255); | |
| a = Math.max(a, 0); | |
| a = Math.min(a, 255); | |
| } | |
| if (a < 1) { | |
| return 0; | |
| } | |
| if ((a < 255) && (needsFlush())) { | |
| stopBecauseOf(GErrorNeedFlush); | |
| } | |
| return ((b + (g << 8)) + (r << 16)) + (a << 24); | |
| } | |
| /* Transform the given point. If haveMatrix is true then use the current transformation. */ | |
| function transformPoint(point) { | |
| if (hasEdgeTransform()) { | |
| /* Note: AA adjustment is done in #transformPoint: for higher accuracy */ | |
| transformPointinto(point, point); | |
| } else { | |
| /* Multiply each component by aaLevel and add a half pixel */ | |
| point[0] = ((point[0] + destOffsetXGet()) * aaLevelGet()); | |
| point[1] = ((point[1] + destOffsetYGet()) * aaLevelGet()); | |
| } | |
| } | |
| /* Transform srcPoint into dstPoint by using the currently loaded matrix */ | |
| /* Note: This method has been rewritten so that inlining works (e.g., removing | |
| the declarations and adding argument coercions at the appropriate points) */ | |
| function transformPointinto(srcPoint, dstPoint) { | |
| transformPointXyinto((srcPoint[0]|0), (srcPoint[1]|0), dstPoint); | |
| } | |
| /* Transform srcPoint into dstPoint by using the currently loaded matrix */ | |
| /* Note: This should be rewritten so that inlining works (e.g., removing | |
| the declarations and adding argument coercions at the appropriate points) */ | |
| function transformPointXyinto(xValue, yValue, dstPoint) { | |
| var transform; | |
| var x; | |
| var y; | |
| transform = edgeTransform(); | |
| x = (((((transform[0] * xValue) + (transform[1] * yValue)) + transform[2]) * aaLevelGet())|0); | |
| y = (((((transform[3] * xValue) + (transform[4] * yValue)) + transform[5]) * aaLevelGet())|0); | |
| dstPoint[0] = x; | |
| dstPoint[1] = y; | |
| } | |
| /* Transform n (n=1,2,3) points. | |
| If haveMatrix is true then the matrix contains the actual transformation. */ | |
| function transformPoints(n) { | |
| if (n > 0) { | |
| transformPoint(point1Get()); | |
| } | |
| if (n > 1) { | |
| transformPoint(point2Get()); | |
| } | |
| if (n > 2) { | |
| transformPoint(point3Get()); | |
| } | |
| if (n > 3) { | |
| transformPoint(point4Get()); | |
| } | |
| } | |
| /* Transform the given width */ | |
| function transformWidth(w) { | |
| var deltaX; | |
| var deltaY; | |
| var dstWidth; | |
| var dstWidth2; | |
| if (w === 0) { | |
| return 0; | |
| } | |
| point1Get()[0] = 0; | |
| point1Get()[1] = 0; | |
| point2Get()[0] = (w * 256); | |
| point2Get()[1] = 0; | |
| point3Get()[0] = 0; | |
| point3Get()[1] = (w * 256); | |
| transformPoints(3); | |
| deltaX = (point2Get()[0] - point1Get()[0]); | |
| deltaY = (point2Get()[1] - point1Get()[1]); | |
| dstWidth = ((Math.sqrt((deltaX * deltaX) + (deltaY * deltaY))|0) + 128) >> 8; | |
| deltaX = (point3Get()[0] - point1Get()[0]); | |
| deltaY = (point3Get()[1] - point1Get()[1]); | |
| dstWidth2 = ((Math.sqrt((deltaX * deltaX) + (deltaY * deltaY))|0) + 128) >> 8; | |
| if (dstWidth2 < dstWidth) { | |
| dstWidth = dstWidth2; | |
| } | |
| if (dstWidth === 0) { | |
| return 1; | |
| } else { | |
| return dstWidth; | |
| } | |
| } | |
| function uncheckedTransformColor(fillIndex) { | |
| var a; | |
| var b; | |
| var g; | |
| var r; | |
| var transform; | |
| if (!hasColorTransform()) { | |
| return fillIndex; | |
| } | |
| b = fillIndex & 255; | |
| g = (fillIndex >>> 8) & 255; | |
| r = (fillIndex >>> 16) & 255; | |
| a = (fillIndex >>> 24) & 255; | |
| transform = colorTransform(); | |
| r = (((r * transform[0]) + transform[1])|0); | |
| g = (((g * transform[2]) + transform[3])|0); | |
| b = (((b * transform[4]) + transform[5])|0); | |
| a = (((a * transform[6]) + transform[7])|0); | |
| r = Math.max(r, 0); | |
| r = Math.min(r, 255); | |
| g = Math.max(g, 0); | |
| g = Math.min(g, 255); | |
| b = Math.max(b, 0); | |
| b = Math.min(b, 255); | |
| a = Math.max(a, 0); | |
| a = Math.min(a, 255); | |
| if (a < 16) { | |
| return 0; | |
| } | |
| return ((b + (g << 8)) + (r << 16)) + (a << 24); | |
| } | |
| function wbSizeGet() { | |
| return workBuffer[GWSize]; | |
| } | |
| function wbSizePut(value) { | |
| return workBuffer[GWSize] = value; | |
| } | |
| function wbStackClear() { | |
| wbTopPut(wbSizeGet()); | |
| } | |
| function wbStackPop(nItems) { | |
| wbTopPut(wbTopGet() + nItems); | |
| } | |
| function wbStackPush(nItems) { | |
| if (!allocateStackEntry(nItems)) { | |
| return false; | |
| } | |
| wbTopPut(wbTopGet() - nItems); | |
| return true; | |
| } | |
| function wbStackSize() { | |
| return wbSizeGet() - wbTopGet(); | |
| } | |
| function wbStackValue(index) { | |
| return workBuffer[wbTopGet() + index]; | |
| } | |
| function wbStackValueput(index, value) { | |
| return workBuffer[wbTopGet() + index] = value; | |
| } | |
| function wbTopGet() { | |
| return workBuffer[GWBufferTop]; | |
| } | |
| function wbTopPut(value) { | |
| return workBuffer[GWBufferTop] = value; | |
| } | |
| function wideBezierEntryOf(line) { | |
| return objat(line, GBWideEntry); | |
| } | |
| function wideBezierEntryOfput(line, value) { | |
| return objatput(line, GBWideEntry, value); | |
| } | |
| function wideBezierExitOf(line) { | |
| return objat(line, GBWideExit); | |
| } | |
| function wideBezierExitOfput(line, value) { | |
| return objatput(line, GBWideExit, value); | |
| } | |
| function wideBezierExtentOf(bezier) { | |
| return objat(bezier, GBWideExtent); | |
| } | |
| function wideBezierExtentOfput(bezier, value) { | |
| return objatput(bezier, GBWideExtent, value); | |
| } | |
| function wideBezierFillOf(bezier) { | |
| return objat(bezier, GBWideFill); | |
| } | |
| function wideBezierFillOfput(bezier, value) { | |
| return objatput(bezier, GBWideFill, value); | |
| } | |
| function wideBezierUpdateDataOf(bezier) { | |
| return PTR_ADD(objBuffer, bezier + GBWideUpdateData); | |
| } | |
| function wideBezierWidthOf(line) { | |
| return objat(line, GBWideWidth); | |
| } | |
| function wideBezierWidthOfput(line, value) { | |
| return objatput(line, GBWideWidth, value); | |
| } | |
| function wideLineEntryOf(line) { | |
| return objat(line, GLWideEntry); | |
| } | |
| function wideLineEntryOfput(line, value) { | |
| return objatput(line, GLWideEntry, value); | |
| } | |
| function wideLineExitOf(line) { | |
| return objat(line, GLWideExit); | |
| } | |
| function wideLineExitOfput(line, value) { | |
| return objatput(line, GLWideExit, value); | |
| } | |
| function wideLineExtentOf(line) { | |
| return objat(line, GLWideExtent); | |
| } | |
| function wideLineExtentOfput(line, value) { | |
| return objatput(line, GLWideExtent, value); | |
| } | |
| function wideLineFillOf(line) { | |
| return objat(line, GLWideFill); | |
| } | |
| function wideLineFillOfput(line, value) { | |
| return objatput(line, GLWideFill, value); | |
| } | |
| function wideLineWidthOf(line) { | |
| return objat(line, GLWideWidth); | |
| } | |
| function wideLineWidthOfput(line, value) { | |
| return objatput(line, GLWideWidth, value); | |
| } | |
| function workBufferPut(wbOop) { | |
| workBuffer = wbOop.wordsAsInt32Array(); | |
| } | |
| function registerPlugin() { | |
| if (typeof Squeak === "object" && Squeak.registerExternalModule) { | |
| Squeak.registerExternalModule("B2DPlugin", { | |
| primitiveMergeFillFrom: primitiveMergeFillFrom, | |
| primitiveCopyBuffer: primitiveCopyBuffer, | |
| primitiveAddRect: primitiveAddRect, | |
| primitiveAddGradientFill: primitiveAddGradientFill, | |
| primitiveSetClipRect: primitiveSetClipRect, | |
| initialiseModule: initialiseModule, | |
| primitiveSetBitBltPlugin: primitiveSetBitBltPlugin, | |
| primitiveRegisterExternalEdge: primitiveRegisterExternalEdge, | |
| primitiveGetClipRect: primitiveGetClipRect, | |
| primitiveAddBezier: primitiveAddBezier, | |
| primitiveInitializeProcessing: primitiveInitializeProcessing, | |
| primitiveRenderImage: primitiveRenderImage, | |
| primitiveGetOffset: primitiveGetOffset, | |
| primitiveSetDepth: primitiveSetDepth, | |
| primitiveAddBezierShape: primitiveAddBezierShape, | |
| primitiveSetEdgeTransform: primitiveSetEdgeTransform, | |
| getModuleName: getModuleName, | |
| primitiveGetTimes: primitiveGetTimes, | |
| primitiveNextActiveEdgeEntry: primitiveNextActiveEdgeEntry, | |
| primitiveAddBitmapFill: primitiveAddBitmapFill, | |
| primitiveGetDepth: primitiveGetDepth, | |
| primitiveAbortProcessing: primitiveAbortProcessing, | |
| primitiveNextGlobalEdgeEntry: primitiveNextGlobalEdgeEntry, | |
| primitiveGetFailureReason: primitiveGetFailureReason, | |
| primitiveDisplaySpanBuffer: primitiveDisplaySpanBuffer, | |
| moduleUnloaded: moduleUnloaded, | |
| primitiveGetCounts: primitiveGetCounts, | |
| primitiveChangedActiveEdgeEntry: primitiveChangedActiveEdgeEntry, | |
| primitiveRenderScanline: primitiveRenderScanline, | |
| primitiveGetBezierStats: primitiveGetBezierStats, | |
| primitiveFinishedProcessing: primitiveFinishedProcessing, | |
| setInterpreter: setInterpreter, | |
| primitiveNeedsFlush: primitiveNeedsFlush, | |
| primitiveAddLine: primitiveAddLine, | |
| primitiveSetOffset: primitiveSetOffset, | |
| primitiveNextFillEntry: primitiveNextFillEntry, | |
| primitiveInitializeBuffer: primitiveInitializeBuffer, | |
| primitiveDoProfileStats: primitiveDoProfileStats, | |
| primitiveAddActiveEdgeEntry: primitiveAddActiveEdgeEntry, | |
| primitiveSetAALevel: primitiveSetAALevel, | |
| primitiveNeedsFlushPut: primitiveNeedsFlushPut, | |
| primitiveAddCompressedShape: primitiveAddCompressedShape, | |
| primitiveSetColorTransform: primitiveSetColorTransform, | |
| primitiveAddOval: primitiveAddOval, | |
| primitiveRegisterExternalFill: primitiveRegisterExternalFill, | |
| primitiveAddPolygon: primitiveAddPolygon, | |
| primitiveGetAALevel: primitiveGetAALevel, | |
| }); | |
| } else self.setTimeout(registerPlugin, 100); | |
| } | |
| registerPlugin(); | |
| })(); // Register module/plugin | |