Initial checkin of skia source in google codebase.
authorcroachrose <croachrose@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 20 Sep 2006 15:47:42 +0000 (15:47 +0000)
committercroachrose <croachrose@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 20 Sep 2006 15:47:42 +0000 (15:47 +0000)
* reviewed by me!

git-svn-id: http://skia.googlecode.com/svn/trunk@2 2bbb7eff-a529-9590-31e7-b0007b416f81

488 files changed:
include/corecg/Sk64.h [new file with mode: 0644]
include/corecg/SkBuffer.h [new file with mode: 0644]
include/corecg/SkChunkAlloc.h [new file with mode: 0644]
include/corecg/SkEndian.h [new file with mode: 0644]
include/corecg/SkFDot6.h [new file with mode: 0644]
include/corecg/SkFixed.h [new file with mode: 0644]
include/corecg/SkFloatingPoint.h [new file with mode: 0644]
include/corecg/SkMath.h [new file with mode: 0644]
include/corecg/SkMatrix.h [new file with mode: 0644]
include/corecg/SkPoint.h [new file with mode: 0644]
include/corecg/SkPostConfig.h [new file with mode: 0644]
include/corecg/SkPreConfig.h [new file with mode: 0644]
include/corecg/SkRandom.h [new file with mode: 0644]
include/corecg/SkRect.h [new file with mode: 0644]
include/corecg/SkRegion.h [new file with mode: 0644]
include/corecg/SkScalar.h [new file with mode: 0644]
include/corecg/SkTemplates.h [new file with mode: 0644]
include/corecg/SkThread.h [new file with mode: 0644]
include/corecg/SkThread_platform.h [new file with mode: 0644]
include/corecg/SkTypes.h [new file with mode: 0644]
include/corecg/SkUserConfig.h [new file with mode: 0644]
include/graphics/DoxygenMain.dox [new file with mode: 0644]
include/graphics/Sk1DPathEffect.h [new file with mode: 0644]
include/graphics/Sk2DPathEffect.h [new file with mode: 0644]
include/graphics/SkAnimator.h [new file with mode: 0644]
include/graphics/SkAnimatorView.h [new file with mode: 0644]
include/graphics/SkApplication.h [new file with mode: 0644]
include/graphics/SkAvoidXfermode.h [new file with mode: 0644]
include/graphics/SkBGViewArtist.h [new file with mode: 0644]
include/graphics/SkBML_WXMLParser.h [new file with mode: 0644]
include/graphics/SkBML_XMLParser.h [new file with mode: 0644]
include/graphics/SkBitmap.h [new file with mode: 0644]
include/graphics/SkBitmapRef.h [new file with mode: 0644]
include/graphics/SkBlurMaskFilter.h [new file with mode: 0644]
include/graphics/SkBorderView.h [new file with mode: 0644]
include/graphics/SkBounder.h [new file with mode: 0644]
include/graphics/SkCamera.h [new file with mode: 0644]
include/graphics/SkCanvas.h [new file with mode: 0644]
include/graphics/SkColor.h [new file with mode: 0644]
include/graphics/SkColorFilter.h [new file with mode: 0644]
include/graphics/SkColorPriv.h [new file with mode: 0644]
include/graphics/SkCornerPathEffect.h [new file with mode: 0644]
include/graphics/SkCullPoints.h [new file with mode: 0644]
include/graphics/SkDOM.h [new file with mode: 0644]
include/graphics/SkDashPathEffect.h [new file with mode: 0644]
include/graphics/SkDeque.h [new file with mode: 0644]
include/graphics/SkDescriptor.h [new file with mode: 0644]
include/graphics/SkDiscretePathEffect.h [new file with mode: 0644]
include/graphics/SkDrawExtraPathEffect.h [new file with mode: 0755]
include/graphics/SkEmbossMaskFilter.h [new file with mode: 0644]
include/graphics/SkEvent.h [new file with mode: 0644]
include/graphics/SkEventSink.h [new file with mode: 0644]
include/graphics/SkFlattenable.h [new file with mode: 0644]
include/graphics/SkFontCodec.h [new file with mode: 0644]
include/graphics/SkFontHost.h [new file with mode: 0644]
include/graphics/SkGlobals.h [new file with mode: 0644]
include/graphics/SkGradientShader.h [new file with mode: 0644]
include/graphics/SkGraphics.h [new file with mode: 0644]
include/graphics/SkImageDecoder.h [new file with mode: 0644]
include/graphics/SkImageView.h [new file with mode: 0644]
include/graphics/SkInterpolator.h [new file with mode: 0644]
include/graphics/SkJS.h [new file with mode: 0644]
include/graphics/SkKey.h [new file with mode: 0644]
include/graphics/SkLayerRasterizer.h [new file with mode: 0644]
include/graphics/SkMask.h [new file with mode: 0644]
include/graphics/SkMaskFilter.h [new file with mode: 0644]
include/graphics/SkMetaData.h [new file with mode: 0644]
include/graphics/SkNinePatch.h [new file with mode: 0644]
include/graphics/SkOSFile.h [new file with mode: 0644]
include/graphics/SkOSMenu.h [new file with mode: 0644]
include/graphics/SkOSSound.h [new file with mode: 0644]
include/graphics/SkOSWindow_Mac.h [new file with mode: 0644]
include/graphics/SkOSWindow_Unix.h [new file with mode: 0644]
include/graphics/SkOSWindow_Win.h [new file with mode: 0644]
include/graphics/SkOSWindow_wxwidgets.h [new file with mode: 0644]
include/graphics/SkPaint.h [new file with mode: 0644]
include/graphics/SkParse.h [new file with mode: 0644]
include/graphics/SkParsePaint.h [new file with mode: 0644]
include/graphics/SkPath.h [new file with mode: 0644]
include/graphics/SkPathEffect.h [new file with mode: 0644]
include/graphics/SkPathMeasure.h [new file with mode: 0644]
include/graphics/SkPorterDuff.h [new file with mode: 0644]
include/graphics/SkPrefix_Debug_Fixed.h [new file with mode: 0644]
include/graphics/SkPrefix_Release_Fixed.h [new file with mode: 0644]
include/graphics/SkProgressBarView.h [new file with mode: 0644]
include/graphics/SkRasterizer.h [new file with mode: 0644]
include/graphics/SkRefCnt.h [new file with mode: 0644]
include/graphics/SkSVGAttribute.h [new file with mode: 0644]
include/graphics/SkSVGBase.h [new file with mode: 0644]
include/graphics/SkSVGPaintState.h [new file with mode: 0644]
include/graphics/SkSVGParser.h [new file with mode: 0644]
include/graphics/SkSVGTypes.h [new file with mode: 0644]
include/graphics/SkScalerContext.h [new file with mode: 0644]
include/graphics/SkScrollBarView.h [new file with mode: 0644]
include/graphics/SkShader.h [new file with mode: 0644]
include/graphics/SkShaderExtras.h [new file with mode: 0644]
include/graphics/SkStackViewLayout.h [new file with mode: 0644]
include/graphics/SkStdLib_Redirect.h [new file with mode: 0644]
include/graphics/SkStream.h [new file with mode: 0644]
include/graphics/SkStream_Win.h [new file with mode: 0644]
include/graphics/SkString.h [new file with mode: 0644]
include/graphics/SkStroke.h [new file with mode: 0644]
include/graphics/SkSystemEventTypes.h [new file with mode: 0644]
include/graphics/SkTDArray.h [new file with mode: 0644]
include/graphics/SkTDStack.h [new file with mode: 0644]
include/graphics/SkTDict.h [new file with mode: 0644]
include/graphics/SkTSearch.h [new file with mode: 0644]
include/graphics/SkTextBox.h [new file with mode: 0644]
include/graphics/SkTextLayout.h [new file with mode: 0644]
include/graphics/SkTime.h [new file with mode: 0644]
include/graphics/SkTransparentShader.h [new file with mode: 0644]
include/graphics/SkTypeface.h [new file with mode: 0644]
include/graphics/SkUnitMapper.h [new file with mode: 0644]
include/graphics/SkUtils.h [new file with mode: 0644]
include/graphics/SkView.h [new file with mode: 0644]
include/graphics/SkViewInflate.h [new file with mode: 0644]
include/graphics/SkWidget.h [new file with mode: 0644]
include/graphics/SkWidgetViews.h [new file with mode: 0644]
include/graphics/SkWindow.h [new file with mode: 0644]
include/graphics/SkXMLParser.h [new file with mode: 0644]
include/graphics/SkXMLWriter.h [new file with mode: 0644]
include/graphics/SkXfermode.h [new file with mode: 0644]
libs/corecg/Makefile [new file with mode: 0644]
libs/corecg/Sk64.cpp [new file with mode: 0644]
libs/corecg/SkBuffer.cpp [new file with mode: 0644]
libs/corecg/SkChunkAlloc.cpp [new file with mode: 0644]
libs/corecg/SkCordic.cpp [new file with mode: 0644]
libs/corecg/SkCordic.h [new file with mode: 0644]
libs/corecg/SkDebug.cpp [new file with mode: 0644]
libs/corecg/SkDebug_stdio.cpp [new file with mode: 0644]
libs/corecg/SkFP.h [new file with mode: 0644]
libs/corecg/SkFloat.cpp [new file with mode: 0644]
libs/corecg/SkFloat.h [new file with mode: 0644]
libs/corecg/SkMath.cpp [new file with mode: 0644]
libs/corecg/SkMatrix.cpp [new file with mode: 0644]
libs/corecg/SkMemory_stdlib.cpp [new file with mode: 0644]
libs/corecg/SkPoint.cpp [new file with mode: 0644]
libs/corecg/SkRect.cpp [new file with mode: 0644]
libs/corecg/SkRegion.cpp [new file with mode: 0644]
libs/corecg/SkRegionPriv.h [new file with mode: 0644]
libs/corecg/SkSinTable.h [new file with mode: 0644]
libs/corecg/SkTSort.h [new file with mode: 0644]
libs/graphics/Makefile [new file with mode: 0644]
libs/graphics/animator/SkAnimate.h [new file with mode: 0644]
libs/graphics/animator/SkAnimate3DSchema.xsd [new file with mode: 0644]
libs/graphics/animator/SkAnimate3DSchema.xsx [new file with mode: 0644]
libs/graphics/animator/SkAnimateActive.cpp [new file with mode: 0644]
libs/graphics/animator/SkAnimateActive.h [new file with mode: 0644]
libs/graphics/animator/SkAnimateBase.cpp [new file with mode: 0644]
libs/graphics/animator/SkAnimateBase.h [new file with mode: 0644]
libs/graphics/animator/SkAnimateField.cpp [new file with mode: 0644]
libs/graphics/animator/SkAnimateMaker.cpp [new file with mode: 0644]
libs/graphics/animator/SkAnimateMaker.h [new file with mode: 0644]
libs/graphics/animator/SkAnimateProperties.h [new file with mode: 0644]
libs/graphics/animator/SkAnimateSchema.xsd [new file with mode: 0644]
libs/graphics/animator/SkAnimateSchema.xsx [new file with mode: 0644]
libs/graphics/animator/SkAnimateSet.cpp [new file with mode: 0644]
libs/graphics/animator/SkAnimateSet.h [new file with mode: 0644]
libs/graphics/animator/SkAnimator.cpp [new file with mode: 0644]
libs/graphics/animator/SkAnimatorScript.cpp [new file with mode: 0644]
libs/graphics/animator/SkAnimatorScript.h [new file with mode: 0644]
libs/graphics/animator/SkAnimatorScript2.cpp [new file with mode: 0755]
libs/graphics/animator/SkAnimatorScript2.h [new file with mode: 0755]
libs/graphics/animator/SkBase64.cpp [new file with mode: 0644]
libs/graphics/animator/SkBase64.h [new file with mode: 0644]
libs/graphics/animator/SkBoundable.cpp [new file with mode: 0644]
libs/graphics/animator/SkBoundable.h [new file with mode: 0644]
libs/graphics/animator/SkBuildCondensedInfo.cpp [new file with mode: 0644]
libs/graphics/animator/SkCondensedDebug.cpp [new file with mode: 0644]
libs/graphics/animator/SkCondensedRelease.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayAdd.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayAdd.h [new file with mode: 0644]
libs/graphics/animator/SkDisplayApply.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayApply.h [new file with mode: 0644]
libs/graphics/animator/SkDisplayBounds.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayBounds.h [new file with mode: 0644]
libs/graphics/animator/SkDisplayEvent.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayEvent.h [new file with mode: 0644]
libs/graphics/animator/SkDisplayEvents.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayEvents.h [new file with mode: 0644]
libs/graphics/animator/SkDisplayInclude.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayInclude.h [new file with mode: 0644]
libs/graphics/animator/SkDisplayInput.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayInput.h [new file with mode: 0644]
libs/graphics/animator/SkDisplayList.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayList.h [new file with mode: 0644]
libs/graphics/animator/SkDisplayMath.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayMath.h [new file with mode: 0644]
libs/graphics/animator/SkDisplayMovie.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayMovie.h [new file with mode: 0644]
libs/graphics/animator/SkDisplayNumber.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayNumber.h [new file with mode: 0644]
libs/graphics/animator/SkDisplayPost.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayPost.h [new file with mode: 0644]
libs/graphics/animator/SkDisplayRandom.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayRandom.h [new file with mode: 0644]
libs/graphics/animator/SkDisplayScreenplay.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayScreenplay.h [new file with mode: 0644]
libs/graphics/animator/SkDisplayType.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayType.h [new file with mode: 0644]
libs/graphics/animator/SkDisplayTypes.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayTypes.h [new file with mode: 0644]
libs/graphics/animator/SkDisplayXMLParser.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayXMLParser.h [new file with mode: 0644]
libs/graphics/animator/SkDisplayable.cpp [new file with mode: 0644]
libs/graphics/animator/SkDisplayable.h [new file with mode: 0644]
libs/graphics/animator/SkDraw3D.cpp [new file with mode: 0644]
libs/graphics/animator/SkDraw3D.h [new file with mode: 0644]
libs/graphics/animator/SkDrawBitmap.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawBitmap.h [new file with mode: 0644]
libs/graphics/animator/SkDrawBlur.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawBlur.h [new file with mode: 0644]
libs/graphics/animator/SkDrawClip.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawClip.h [new file with mode: 0644]
libs/graphics/animator/SkDrawColor.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawColor.h [new file with mode: 0644]
libs/graphics/animator/SkDrawDash.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawDash.h [new file with mode: 0644]
libs/graphics/animator/SkDrawDiscrete.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawDiscrete.h [new file with mode: 0644]
libs/graphics/animator/SkDrawEmboss.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawEmboss.h [new file with mode: 0644]
libs/graphics/animator/SkDrawExtraPathEffect.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawFull.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawFull.h [new file with mode: 0644]
libs/graphics/animator/SkDrawGradient.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawGradient.h [new file with mode: 0644]
libs/graphics/animator/SkDrawGroup.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawGroup.h [new file with mode: 0644]
libs/graphics/animator/SkDrawLine.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawLine.h [new file with mode: 0644]
libs/graphics/animator/SkDrawMatrix.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawMatrix.h [new file with mode: 0644]
libs/graphics/animator/SkDrawOval.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawOval.h [new file with mode: 0644]
libs/graphics/animator/SkDrawPaint.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawPaint.h [new file with mode: 0644]
libs/graphics/animator/SkDrawPath.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawPath.h [new file with mode: 0644]
libs/graphics/animator/SkDrawPoint.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawPoint.h [new file with mode: 0644]
libs/graphics/animator/SkDrawRectangle.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawRectangle.h [new file with mode: 0644]
libs/graphics/animator/SkDrawSaveLayer.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawSaveLayer.h [new file with mode: 0644]
libs/graphics/animator/SkDrawShader.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawShader.h [new file with mode: 0644]
libs/graphics/animator/SkDrawText.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawText.h [new file with mode: 0644]
libs/graphics/animator/SkDrawTextBox.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawTextBox.h [new file with mode: 0644]
libs/graphics/animator/SkDrawTo.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawTo.h [new file with mode: 0644]
libs/graphics/animator/SkDrawTransparentShader.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawTransparentShader.h [new file with mode: 0644]
libs/graphics/animator/SkDrawable.cpp [new file with mode: 0644]
libs/graphics/animator/SkDrawable.h [new file with mode: 0644]
libs/graphics/animator/SkDump.cpp [new file with mode: 0644]
libs/graphics/animator/SkDump.h [new file with mode: 0644]
libs/graphics/animator/SkExtraPathEffects.xsd [new file with mode: 0644]
libs/graphics/animator/SkExtras.h [new file with mode: 0644]
libs/graphics/animator/SkGetCondensedInfo.cpp [new file with mode: 0644]
libs/graphics/animator/SkHitClear.cpp [new file with mode: 0644]
libs/graphics/animator/SkHitClear.h [new file with mode: 0644]
libs/graphics/animator/SkHitTest.cpp [new file with mode: 0644]
libs/graphics/animator/SkHitTest.h [new file with mode: 0644]
libs/graphics/animator/SkIntArray.h [new file with mode: 0644]
libs/graphics/animator/SkInterpolator.cpp [new file with mode: 0644]
libs/graphics/animator/SkMatrixParts.cpp [new file with mode: 0644]
libs/graphics/animator/SkMatrixParts.h [new file with mode: 0644]
libs/graphics/animator/SkMemberInfo.cpp [new file with mode: 0644]
libs/graphics/animator/SkMemberInfo.h [new file with mode: 0644]
libs/graphics/animator/SkOpArray.cpp [new file with mode: 0755]
libs/graphics/animator/SkOpArray.h [new file with mode: 0755]
libs/graphics/animator/SkOperand.h [new file with mode: 0644]
libs/graphics/animator/SkOperand2.h [new file with mode: 0755]
libs/graphics/animator/SkOperandInterpolator.h [new file with mode: 0644]
libs/graphics/animator/SkOperandIterpolator.cpp [new file with mode: 0644]
libs/graphics/animator/SkPaintParts.cpp [new file with mode: 0644]
libs/graphics/animator/SkPaintParts.h [new file with mode: 0644]
libs/graphics/animator/SkPathParts.cpp [new file with mode: 0644]
libs/graphics/animator/SkPathParts.h [new file with mode: 0644]
libs/graphics/animator/SkPostParts.cpp [new file with mode: 0644]
libs/graphics/animator/SkPostParts.h [new file with mode: 0644]
libs/graphics/animator/SkSVGPath.cpp [new file with mode: 0644]
libs/graphics/animator/SkScript.cpp [new file with mode: 0644]
libs/graphics/animator/SkScript.h [new file with mode: 0644]
libs/graphics/animator/SkScript2.h [new file with mode: 0755]
libs/graphics/animator/SkScriptCallBack.h [new file with mode: 0755]
libs/graphics/animator/SkScriptDecompile.cpp [new file with mode: 0644]
libs/graphics/animator/SkScriptRuntime.cpp [new file with mode: 0755]
libs/graphics/animator/SkScriptRuntime.h [new file with mode: 0755]
libs/graphics/animator/SkScriptTokenizer.cpp [new file with mode: 0755]
libs/graphics/animator/SkSnapshot.cpp [new file with mode: 0644]
libs/graphics/animator/SkSnapshot.h [new file with mode: 0644]
libs/graphics/animator/SkTDArray_Experimental.h [new file with mode: 0644]
libs/graphics/animator/SkTextOnPath.cpp [new file with mode: 0644]
libs/graphics/animator/SkTextOnPath.h [new file with mode: 0644]
libs/graphics/animator/SkTextToPath.cpp [new file with mode: 0644]
libs/graphics/animator/SkTextToPath.h [new file with mode: 0644]
libs/graphics/animator/SkTime.cpp [new file with mode: 0644]
libs/graphics/animator/SkTypedArray.cpp [new file with mode: 0644]
libs/graphics/animator/SkTypedArray.h [new file with mode: 0644]
libs/graphics/animator/SkXMLAnimatorWriter.cpp [new file with mode: 0644]
libs/graphics/animator/SkXMLAnimatorWriter.h [new file with mode: 0644]
libs/graphics/animator/thingstodo.txt [new file with mode: 0644]
libs/graphics/effects/Sk1DPathEffect.cpp [new file with mode: 0644]
libs/graphics/effects/Sk2DPathEffect.cpp [new file with mode: 0644]
libs/graphics/effects/SkAvoidXfermode.cpp [new file with mode: 0644]
libs/graphics/effects/SkBlurMask.cpp [new file with mode: 0644]
libs/graphics/effects/SkBlurMask.h [new file with mode: 0644]
libs/graphics/effects/SkBlurMaskFilter.cpp [new file with mode: 0644]
libs/graphics/effects/SkCamera.cpp [new file with mode: 0644]
libs/graphics/effects/SkColorFilters.cpp [new file with mode: 0644]
libs/graphics/effects/SkCornerPathEffect.cpp [new file with mode: 0644]
libs/graphics/effects/SkCullPoints.cpp [new file with mode: 0644]
libs/graphics/effects/SkDashPathEffect.cpp [new file with mode: 0644]
libs/graphics/effects/SkDiscretePathEffect.cpp [new file with mode: 0644]
libs/graphics/effects/SkEmbossMask.cpp [new file with mode: 0644]
libs/graphics/effects/SkEmbossMask.h [new file with mode: 0644]
libs/graphics/effects/SkEmbossMaskFilter.cpp [new file with mode: 0644]
libs/graphics/effects/SkEmbossMask_Table.h [new file with mode: 0644]
libs/graphics/effects/SkGradientShader.cpp [new file with mode: 0644]
libs/graphics/effects/SkLayerRasterizer.cpp [new file with mode: 0644]
libs/graphics/effects/SkNinePatch.cpp [new file with mode: 0644]
libs/graphics/effects/SkRadialGradient_Table.h [new file with mode: 0644]
libs/graphics/effects/SkShaderExtras.cpp [new file with mode: 0644]
libs/graphics/effects/SkTransparentShader.cpp [new file with mode: 0644]
libs/graphics/images/SkBitmapRef.cpp [new file with mode: 0644]
libs/graphics/images/SkBitmapRefPriv.h [new file with mode: 0644]
libs/graphics/images/SkImageDecoder.cpp [new file with mode: 0644]
libs/graphics/images/SkImageDecoder_libgif.cpp [new file with mode: 0644]
libs/graphics/images/SkImageDecoder_libjpeg.cpp [new file with mode: 0644]
libs/graphics/images/SkImageDecoder_libpng.cpp [new file with mode: 0644]
libs/graphics/images/SkStream.cpp [new file with mode: 0644]
libs/graphics/ports/SkFontHost.cpp [new file with mode: 0644]
libs/graphics/ports/SkFontHost_FONTPATH.cpp [new file with mode: 0644]
libs/graphics/ports/SkFontHost_FreeType.cpp [new file with mode: 0644]
libs/graphics/ports/SkFontHost_none.cpp [new file with mode: 0644]
libs/graphics/ports/SkGlobals_global.cpp [new file with mode: 0644]
libs/graphics/ports/SkImageDecoder_Factory.cpp [new file with mode: 0644]
libs/graphics/ports/SkOSEvent_android.cpp [new file with mode: 0644]
libs/graphics/ports/SkOSEvent_dummy.cpp [new file with mode: 0644]
libs/graphics/ports/SkOSFile_stdio.cpp [new file with mode: 0644]
libs/graphics/ports/SkThread_none.cpp [new file with mode: 0644]
libs/graphics/ports/SkTime_Unix.cpp [new file with mode: 0644]
libs/graphics/ports/SkXMLParser_empty.cpp [new file with mode: 0644]
libs/graphics/ports/SkXMLParser_expat.cpp [new file with mode: 0644]
libs/graphics/ports/SkXMLParser_tinyxml.cpp [new file with mode: 0644]
libs/graphics/sgl/SkAlphaRuns.cpp [new file with mode: 0644]
libs/graphics/sgl/SkAntiRun.h [new file with mode: 0644]
libs/graphics/sgl/SkBitmap.cpp [new file with mode: 0644]
libs/graphics/sgl/SkBitmapSampler.cpp [new file with mode: 0644]
libs/graphics/sgl/SkBitmapSampler.h [new file with mode: 0644]
libs/graphics/sgl/SkBitmapSamplerTemplate.h [new file with mode: 0644]
libs/graphics/sgl/SkBitmapShader.cpp [new file with mode: 0644]
libs/graphics/sgl/SkBitmapShader.h [new file with mode: 0644]
libs/graphics/sgl/SkBitmapShader16BilerpTemplate.h [new file with mode: 0644]
libs/graphics/sgl/SkBitmapShaderTemplate.h [new file with mode: 0644]
libs/graphics/sgl/SkBlitBWMaskTemplate.h [new file with mode: 0644]
libs/graphics/sgl/SkBlitter.cpp [new file with mode: 0644]
libs/graphics/sgl/SkBlitter.h [new file with mode: 0644]
libs/graphics/sgl/SkBlitter_A1.cpp [new file with mode: 0644]
libs/graphics/sgl/SkBlitter_A8.cpp [new file with mode: 0644]
libs/graphics/sgl/SkBlitter_ARGB32.cpp [new file with mode: 0644]
libs/graphics/sgl/SkBlitter_RGB16.cpp [new file with mode: 0644]
libs/graphics/sgl/SkBlitter_Sprite.cpp [new file with mode: 0644]
libs/graphics/sgl/SkCanvas.cpp [new file with mode: 0644]
libs/graphics/sgl/SkColor.cpp [new file with mode: 0644]
libs/graphics/sgl/SkColorFilter.cpp [new file with mode: 0644]
libs/graphics/sgl/SkColorTable.cpp [new file with mode: 0644]
libs/graphics/sgl/SkCoreBlitters.h [new file with mode: 0644]
libs/graphics/sgl/SkDeque.cpp [new file with mode: 0644]
libs/graphics/sgl/SkDraw.cpp [new file with mode: 0644]
libs/graphics/sgl/SkDraw.h [new file with mode: 0644]
libs/graphics/sgl/SkEdge.cpp [new file with mode: 0644]
libs/graphics/sgl/SkEdge.h [new file with mode: 0644]
libs/graphics/sgl/SkFP.h [new file with mode: 0644]
libs/graphics/sgl/SkFilterProc.cpp [new file with mode: 0644]
libs/graphics/sgl/SkFilterProc.h [new file with mode: 0644]
libs/graphics/sgl/SkGeometry.cpp [new file with mode: 0644]
libs/graphics/sgl/SkGeometry.h [new file with mode: 0644]
libs/graphics/sgl/SkGlobals.cpp [new file with mode: 0644]
libs/graphics/sgl/SkGlyphCache.cpp [new file with mode: 0644]
libs/graphics/sgl/SkGlyphCache.h [new file with mode: 0644]
libs/graphics/sgl/SkGraphics.cpp [new file with mode: 0644]
libs/graphics/sgl/SkMaskFilter.cpp [new file with mode: 0644]
libs/graphics/sgl/SkPaint.cpp [new file with mode: 0644]
libs/graphics/sgl/SkPath.cpp [new file with mode: 0644]
libs/graphics/sgl/SkPathEffect.cpp [new file with mode: 0644]
libs/graphics/sgl/SkPathMeasure.cpp [new file with mode: 0644]
libs/graphics/sgl/SkProcSpriteBlitter.cpp [new file with mode: 0644]
libs/graphics/sgl/SkRasterizer.cpp [new file with mode: 0644]
libs/graphics/sgl/SkRefCnt.cpp [new file with mode: 0644]
libs/graphics/sgl/SkRegion_path.cpp [new file with mode: 0644]
libs/graphics/sgl/SkScalerContext.cpp [new file with mode: 0644]
libs/graphics/sgl/SkScan.cpp [new file with mode: 0644]
libs/graphics/sgl/SkScan.h [new file with mode: 0644]
libs/graphics/sgl/SkScanPriv.h [new file with mode: 0644]
libs/graphics/sgl/SkScan_AntiPath.cpp [new file with mode: 0644]
libs/graphics/sgl/SkScan_Antihair.cpp [new file with mode: 0644]
libs/graphics/sgl/SkScan_Hairline.cpp [new file with mode: 0644]
libs/graphics/sgl/SkScan_Path.cpp [new file with mode: 0644]
libs/graphics/sgl/SkShader.cpp [new file with mode: 0644]
libs/graphics/sgl/SkSinTable.h [new file with mode: 0644]
libs/graphics/sgl/SkSpriteBlitter.h [new file with mode: 0644]
libs/graphics/sgl/SkSpriteBlitterTemplate.h [new file with mode: 0644]
libs/graphics/sgl/SkSpriteBlitter_ARGB32.cpp [new file with mode: 0644]
libs/graphics/sgl/SkSpriteBlitter_RGB16.cpp [new file with mode: 0644]
libs/graphics/sgl/SkString.cpp [new file with mode: 0644]
libs/graphics/sgl/SkStroke.cpp [new file with mode: 0644]
libs/graphics/sgl/SkStrokerPriv.cpp [new file with mode: 0644]
libs/graphics/sgl/SkStrokerPriv.h [new file with mode: 0644]
libs/graphics/sgl/SkTSearch.cpp [new file with mode: 0644]
libs/graphics/sgl/SkTSort.h [new file with mode: 0644]
libs/graphics/sgl/SkTemplatesPriv.h [new file with mode: 0644]
libs/graphics/sgl/SkTextLayout.cpp [new file with mode: 0644]
libs/graphics/sgl/SkUtils.cpp [new file with mode: 0644]
libs/graphics/sgl/SkXfermode.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVG.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGCircle.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGCircle.h [new file with mode: 0644]
libs/graphics/svg/SkSVGClipPath.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGClipPath.h [new file with mode: 0644]
libs/graphics/svg/SkSVGDefs.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGDefs.h [new file with mode: 0644]
libs/graphics/svg/SkSVGElements.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGElements.h [new file with mode: 0644]
libs/graphics/svg/SkSVGEllipse.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGEllipse.h [new file with mode: 0644]
libs/graphics/svg/SkSVGFeColorMatrix.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGFeColorMatrix.h [new file with mode: 0644]
libs/graphics/svg/SkSVGFilter.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGFilter.h [new file with mode: 0644]
libs/graphics/svg/SkSVGG.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGG.h [new file with mode: 0644]
libs/graphics/svg/SkSVGGradient.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGGradient.h [new file with mode: 0644]
libs/graphics/svg/SkSVGGroup.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGGroup.h [new file with mode: 0644]
libs/graphics/svg/SkSVGImage.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGImage.h [new file with mode: 0644]
libs/graphics/svg/SkSVGLine.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGLine.h [new file with mode: 0644]
libs/graphics/svg/SkSVGLinearGradient.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGLinearGradient.h [new file with mode: 0644]
libs/graphics/svg/SkSVGMask.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGMask.h [new file with mode: 0644]
libs/graphics/svg/SkSVGMetadata.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGMetadata.h [new file with mode: 0644]
libs/graphics/svg/SkSVGPaintState.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGParser.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGPath.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGPath.h [new file with mode: 0644]
libs/graphics/svg/SkSVGPolygon.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGPolygon.h [new file with mode: 0644]
libs/graphics/svg/SkSVGPolyline.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGPolyline.h [new file with mode: 0644]
libs/graphics/svg/SkSVGRadialGradient.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGRadialGradient.h [new file with mode: 0644]
libs/graphics/svg/SkSVGRect.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGRect.h [new file with mode: 0644]
libs/graphics/svg/SkSVGSVG.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGSVG.h [new file with mode: 0644]
libs/graphics/svg/SkSVGStop.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGStop.h [new file with mode: 0644]
libs/graphics/svg/SkSVGSymbol.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGSymbol.h [new file with mode: 0644]
libs/graphics/svg/SkSVGText.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGText.h [new file with mode: 0644]
libs/graphics/svg/SkSVGUse.cpp [new file with mode: 0644]
libs/graphics/svg/SkSVGUse.h [new file with mode: 0644]
libs/graphics/text/ATextEntry.h [new file with mode: 0644]
libs/graphics/views/SkEvent.cpp [new file with mode: 0644]
libs/graphics/views/SkEventSink.cpp [new file with mode: 0644]
libs/graphics/views/SkMetaData.cpp [new file with mode: 0644]
libs/graphics/views/SkTagList.cpp [new file with mode: 0644]
libs/graphics/views/SkTagList.h [new file with mode: 0644]
libs/graphics/views/SkTextBox.cpp [new file with mode: 0644]
libs/graphics/xml/SkBML_Verbs.h [new file with mode: 0644]
libs/graphics/xml/SkBML_XMLParser.cpp [new file with mode: 0644]
libs/graphics/xml/SkDOM.cpp [new file with mode: 0644]
libs/graphics/xml/SkJS.cpp [new file with mode: 0644]
libs/graphics/xml/SkJSDisplayable.cpp [new file with mode: 0644]
libs/graphics/xml/SkParse.cpp [new file with mode: 0644]
libs/graphics/xml/SkParseColor.cpp [new file with mode: 0644]
libs/graphics/xml/SkXMLParser.cpp [new file with mode: 0644]
libs/graphics/xml/SkXMLWriter.cpp [new file with mode: 0644]

diff --git a/include/corecg/Sk64.h b/include/corecg/Sk64.h
new file mode 100644 (file)
index 0000000..ed67b1f
--- /dev/null
@@ -0,0 +1,219 @@
+#ifndef Sk64_DEFINED
+#define Sk64_DEFINED
+
+#include "SkMath.h"
+
+/**    \class Sk64
+
+       Sk64 is a 64-bit math package that does not require long long support from the compiler.
+*/
+struct Sk64 {
+       int32_t  fHi;   //!< the high 32 bits of the number (including sign)
+       uint32_t fLo;   //!< the low 32 bits of the number
+
+       /**     Returns non-zero if the Sk64 can be represented as a signed 32 bit integer
+       */
+       SkBool  is32() const { return fHi == ((int32_t)fLo >> 31); }
+       /**     Returns non-zero if the Sk64 cannot be represented as a signed 32 bit integer
+       */
+       SkBool  is64() const { return fHi != ((int32_t)fLo >> 31); }
+       /**     Returns non-zero if the Sk64 can be represented as a signed 48 bit integer. Used to know
+               if we can shift the value down by 16 to treat it as a SkFixed.
+       */
+       SkBool  isFixed() const;
+
+       /**     Return the signed 32 bit integer equivalent. Asserts that is32() returns non-zero.
+       */
+       int32_t get32() const { SkASSERT(this->is32()); return (int32_t)fLo; }
+       /**     Return the number >> 16. Asserts that this does not loose any significant high bits.
+       */
+       SkFixed getFixed() const
+       {
+               SkASSERT(this->isFixed());
+
+               uint32_t sum = fLo + (1 << 15);
+               int32_t  hi = fHi;
+               if (sum < fLo)
+                       hi += 1;
+
+               return (hi << 16) | (sum >> 16);
+       }
+       /**     Return the number >> 30. Asserts that this does not loose any significant high bits.
+       */
+       SkFract getFract() const;
+
+       /**     Returns the square-root of the number as a signed 32 bit value.
+       */
+       int32_t getSqrt() const;
+
+       /**     Returns the number of leading zeros of the absolute value of this.
+               Will return in the range [0..64]
+       */
+       int     getClzAbs() const;
+
+       /**     Returns non-zero if the number is zero
+       */
+       SkBool  isZero() const { return (fHi | fLo) == 0; }
+       /**     Returns non-zero if the number is non-zero
+       */
+       SkBool  nonZero() const { return fHi | fLo; }
+       /**     Returns non-zero if the number is negative (number < 0)
+       */
+       SkBool  isNeg() const { return (uint32_t)fHi >> 31; }
+       /**     Returns non-zero if the number is positive (number > 0)
+       */
+       SkBool  isPos() const { return ~(fHi >> 31) & (fHi | fLo); }
+       /**     Returns -1,0,+1 based on the sign of the number
+       */
+       int             sign() const { return (fHi >> 31) | Sk32ToBool(fHi | fLo); }
+       /**     Negate the number
+       */
+       void    negate();
+
+       /**     If the number < 0, negate the number
+       */
+       void    abs();
+
+       /**     Returns the number of bits needed to shift the Sk64 to the right
+               in order to make it fit in a signed 32 bit integer.
+       */
+       int             shiftToMake32() const;
+
+       /**     Set the number to zero
+       */
+       void    setZero() { fHi = fLo = 0; }
+       /**     Set the high and low 32 bit values of the number
+       */
+       void    set(int32_t hi, uint32_t lo) { fHi = hi; fLo = lo; }
+       /**     Set the number to the specified 32 bit integer
+       */
+       void    set(int32_t a) { fHi = a >> 31; fLo = a; }
+       /**     Set the number to the product of the two 32 bit integers
+       */
+       void    setMul(int32_t a, int32_t b);
+
+       /** extract 32bits after shifting right by bitCount.
+               Note: itCount must be [0..63].
+               Asserts that no significant high bits were lost.
+       */
+       int32_t getShiftRight(unsigned bitCount) const;
+       /**     Shift the number left by the specified number of bits.
+               @param bits     How far to shift left, must be [0..63]
+       */
+       void    shiftLeft(unsigned bits);
+       /**     Shift the number right by the specified number of bits.
+               @param bits     How far to shift right, must be [0..63]. This
+               performs an arithmetic right-shift (sign extending).
+       */
+       void    shiftRight(unsigned bits);
+       /**     Shift the number right by the specified number of bits, but
+               round the result.
+               @param bits     How far to shift right, must be [0..63]. This
+               performs an arithmetic right-shift (sign extending).
+       */
+       void    roundRight(unsigned bits);
+
+       /**     Add the specified 32 bit integer to the number
+       */
+       void    add(int32_t lo)
+       {
+               int32_t  hi = lo >> 31; // 0 or -1
+               uint32_t sum = fLo + (uint32_t)lo;
+
+               fHi = fHi + hi + (sum < fLo);
+               fLo = sum;
+       }
+       /**     Add the specified Sk64 to the number
+       */
+       void    add(int32_t hi, uint32_t lo)
+       {
+               uint32_t sum = fLo + lo;
+
+               fHi = fHi + hi + (sum < fLo);
+               fLo = sum;
+       }
+       /**     Add the specified Sk64 to the number
+       */
+       void    add(const Sk64& other) { this->add(other.fHi, other.fLo); }
+       /**     Subtract the specified Sk64 from the number. (*this) = (*this) - num
+       */
+       void    sub(const Sk64& num);
+       /**     Subtract the number from the specified Sk64. (*this) = num - (*this)
+       */
+       void    rsub(const Sk64& num);
+       /**     Multiply the number by the specified 32 bit integer
+       */
+       void    mul(int32_t);
+
+       enum DivOptions {
+               kTrunc_DivOption,       //!< truncate the result when calling div()
+               kRound_DivOption        //!< round the result when calling div()
+       };
+       /**     Divide the number by the specified 32 bit integer, using the specified
+               divide option (either truncate or round).
+       */
+       void    div(int32_t, DivOptions);
+
+       SkFixed addGetFixed(const Sk64& other) const
+       {
+               return this->addGetFixed(other.fHi, other.fLo);
+       }
+       SkFixed addGetFixed(int32_t hi, uint32_t lo) const
+       {
+#ifdef SK_DEBUG
+               Sk64    tmp(*this);
+               tmp.add(hi, lo);
+#endif
+               uint32_t sum = fLo + lo + (1 << 15);
+
+               hi = fHi + hi + (sum < fLo);
+               hi = (hi << 16) | (sum >> 16);
+
+               SkASSERT(hi == tmp.getFixed());
+               return hi;
+       }
+
+       /**     Return the result of dividing the number by denom, treating the answer
+               as a SkFixed. (*this) << 16 / denom. It is an error for denom to be 0.
+       */
+       SkFixed getFixedDiv(const Sk64& denom) const;
+
+       friend bool operator==(const Sk64& a, const Sk64& b)
+       {
+               return a.fHi == b.fHi && a.fLo == b.fLo;
+       }
+       friend bool operator!=(const Sk64& a, const Sk64& b)
+       {
+               return a.fHi != b.fHi || a.fLo != b.fLo;
+       }
+       friend bool operator<(const Sk64& a, const Sk64& b)
+       {
+               return a.fHi < b.fHi || a.fHi == b.fHi && a.fLo < b.fLo;
+       }
+       friend bool operator<=(const Sk64& a, const Sk64& b)
+       {
+               return a.fHi < b.fHi || a.fHi == b.fHi && a.fLo <= b.fLo;
+       }
+       friend bool operator>(const Sk64& a, const Sk64& b)
+       {
+               return a.fHi > b.fHi || a.fHi == b.fHi && a.fLo > b.fLo;
+       }
+       friend bool operator>=(const Sk64& a, const Sk64& b)
+       {
+               return a.fHi > b.fHi || a.fHi == b.fHi && a.fLo >= b.fLo;
+       }
+
+#ifdef SK_CAN_USE_LONGLONG
+       SkLONGLONG getLongLong() const;
+#endif
+
+#ifdef SK_DEBUG
+  /** @cond UNIT_TEST */
+       static void UnitTest();
+  /** @endcond */
+#endif
+};
+
+#endif
+
+
diff --git a/include/corecg/SkBuffer.h b/include/corecg/SkBuffer.h
new file mode 100644 (file)
index 0000000..cd670fc
--- /dev/null
@@ -0,0 +1,135 @@
+#ifndef SkBuffer_DEFINED
+#define SkBuffer_DEFINED
+
+#include "SkScalar.h"
+
+/** \class SkRBuffer
+
+    Light weight class for reading data from a memory block.
+    The RBuffer is given the buffer to read from, with either a specified size
+    or no size (in which case no range checking is performed). It is iillegal
+    to attempt to read a value from an empty RBuffer (data == null). 
+*/
+class SkRBuffer {
+public:
+    SkRBuffer() : fData(0), fPos(0), fStop(0) {}
+    /** Initialize RBuffer with a data pointer, but no specified length.
+        This signals the RBuffer to not perform range checks during reading.
+    */
+    SkRBuffer(const void* data)
+    {
+        fData = (const char*)data;
+        fPos = (const char*)data;
+        fStop = 0;  // no bounds checking
+    }
+    /** Initialize RBuffer with a data point and length.
+    */
+    SkRBuffer(const void* data, size_t size)
+    {
+        SkASSERT(data != 0 || size == 0);
+        fData = (const char*)data;
+        fPos = (const char*)data;
+        fStop = (const char*)data + size;
+    }
+    
+    /** Return the number of bytes that have been read from the beginning
+        of the data pointer.
+    */
+    size_t  pos() const { return fPos - fData; }
+    /** Return the total size of the data pointer. Only defined if the length was
+        specified in the constructor or in a call to reset().
+    */
+    size_t  size() const { return fStop - fData; }
+    /** Return true if the buffer has read to the end of the data pointer.
+        Only defined if the length was specified in the constructor or in a call
+        to reset(). Always returns true if the length was not specified.
+    */
+    bool    eof() const { return fPos >= fStop; }
+
+    /** Read the specified number of bytes from the data pointer. If buffer is not
+        null, copy those bytes into buffer.
+    */
+    void    read(void* buffer, size_t size) { if (size) this->readNoSizeCheck(buffer, size); }
+    size_t  skipToAlign4();
+
+    void*       readPtr() { void* ptr; read(&ptr, sizeof(ptr)); return ptr; }
+    SkScalar    readScalar() { SkScalar x; read(&x, 4); return x; }
+    uint32_t    readU32() { uint32_t x; read(&x, 4); return x; }
+    int32_t     readS32() { int32_t x; read(&x, 4); return x; }
+    uint16_t    readU16() { uint16_t x; read(&x, 2); return x; }
+    int16_t     readS16() { int16_t x; read(&x, 2); return x; }
+    uint8_t     readU8() { uint8_t x; read(&x, 1); return x; }
+    bool        readBool() { return this->readU8() != 0; }
+
+private:
+    void    readNoSizeCheck(void* buffer, size_t size);
+
+    const char* fData;
+    const char* fPos;
+    const char* fStop;
+};
+
+/** \class SkWBuffer
+
+    Light weight class for writing data to a memory block.
+    The WBuffer is given the buffer to write into, with either a specified size
+    or no size, in which case no range checking is performed. An empty WBuffer
+    is legal, in which case no data is ever written, but the relative pos()
+    is updated.
+*/
+class SkWBuffer {
+public:
+    SkWBuffer() : fData(0), fPos(0), fStop(0) {}
+    SkWBuffer(void* data)
+    {
+        fData = (char*)data;
+        fPos = (char*)data;
+        fStop = 0;  // no bounds checking
+    }
+    SkWBuffer(void* data, size_t size)
+    {
+        SkASSERT(data != 0 || size == 0);
+        fData = (char*)data;
+        fPos = (char*)data;
+        fStop = (char*)data + size;
+    }
+
+    void reset(void* data)
+    {
+        fData = (char*)data;
+        fPos = (char*)data;
+        fStop = 0;  // no bounds checking
+    }
+    void reset(void* data, size_t size)
+    {
+        SkASSERT(data != 0 || size == 0);
+        fData = (char*)data;
+        fPos = (char*)data;
+        fStop = (char*)data + size;
+    }
+    
+    void*   data() const { return fData; }
+    size_t  pos() const { return fPos - fData; }
+    size_t  size() const { return fStop - fData; }
+    bool    eof() const { return fPos >= fStop; }
+
+    void    write(const void* buffer, size_t size) { if (size) this->writeNoSizeCheck(buffer, size); }
+    size_t  padToAlign4();
+
+    void    writePtr(const void* x) { this->writeNoSizeCheck(&x, sizeof(x)); }
+    void    writeScalar(SkScalar x) { this->writeNoSizeCheck(&x, 4); }
+    void    write32(int32_t x) { this->writeNoSizeCheck(&x, 4); }
+    void    write16(int16_t x) { this->writeNoSizeCheck(&x, 2); }
+    void    write8(int8_t x) { this->writeNoSizeCheck(&x, 1); }
+    void    writeBool(bool x) { this->write8(x); }
+
+private:
+    void    writeNoSizeCheck(const void* buffer, size_t size);
+
+    char* fData;
+    char* fPos;
+    char* fStop;
+};
+
+#endif
+
diff --git a/include/corecg/SkChunkAlloc.h b/include/corecg/SkChunkAlloc.h
new file mode 100644 (file)
index 0000000..3070af8
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef SkChunkAlloc_DEFINED
+#define SkChunkAlloc_DEFINED
+
+#include "SkTypes.h"
+
+class SkChunkAlloc {
+public:
+       SkChunkAlloc(size_t minSize) : fBlock(nil), fMinSize(SkAlign4(minSize)) {}
+       ~SkChunkAlloc();
+
+       void    reset();
+
+       enum AllocFailType {
+               kReturnNil_AllocFailType,
+               kThrow_AllocFailType
+       };
+       void*   alloc(size_t bytes, AllocFailType);
+       
+private:
+       struct Block {
+               Block*  fNext;
+               size_t  fFreeSize;
+               char*   fFreePtr;
+               // data[] follows
+       };
+       Block*  fBlock;
+       size_t  fMinSize;
+};
+
+#endif
diff --git a/include/corecg/SkEndian.h b/include/corecg/SkEndian.h
new file mode 100644 (file)
index 0000000..845037c
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef SkEndian_DEFINED
+#define SkEndian_DEFINED
+
+#include "SkTypes.h"
+
+/**    \file SkEndian.h
+
+       Macros and helper functions for handling 16 and 32 bit values in
+       big and little endian formats.
+*/
+
+#if defined(SK_CPU_LENDIAN) && defined(SK_CPU_BENDIAN)
+       #error "can't have both LENDIAN and BENDIAN defined"
+#endif
+
+#if !defined(SK_CPU_LENDIAN) && !defined(SK_CPU_BENDIAN)
+       #error "need either LENDIAN or BENDIAN defined"
+#endif
+
+/**    Swap the two bytes in the low 16bits of the parameters.
+       e.g. 0x1234 -> 0x3412
+*/
+inline uint16_t SkEndianSwap16(U16CPU value)
+{
+       SkASSERT(value == (uint16_t)value);
+       return (uint16_t)((value >> 8) | (value << 8));
+}
+
+/**    Vector version of SkEndianSwap16(), which swaps the
+       low two bytes of each value in the array.
+*/
+inline void SkEndianSwap16s(uint16_t array[], int count)
+{
+       SkASSERT(count == 0 || array != nil);
+
+       while (--count >= 0)
+       {
+               *array = SkEndianSwap16(*array);
+               array += 1;
+       }
+}
+
+/**    Reverse all 4 bytes in a 32bit value.
+       e.g. 0x12345678 -> 0x78563412
+*/
+inline uint32_t SkEndianSwap32(uint32_t value)
+{
+       return  ((value & 0xFF) << 24) |
+                       ((value & 0xFF00) << 8) |
+                       ((value & 0xFF0000) >> 8) |
+                       (value >> 24);
+}
+
+/**    Vector version of SkEndianSwap16(), which swaps the
+       bytes of each value in the array.
+*/
+inline void SkEndianSwap32s(uint32_t array[], int count)
+{
+       SkASSERT(count == 0 || array != nil);
+
+       while (--count >= 0)
+       {
+               *array = SkEndianSwap32(*array);
+               array += 1;
+       }
+}
+
+#ifdef SK_CPU_LENDIAN
+       #define SkEndian_SwapBE16(n)    SkEndianSwap16(n)
+       #define SkEndian_SwapBE32(n)    SkEndianSwap32(n)
+       #define SkEndian_SwapLE16(n)    (n)
+       #define SkEndian_SwapLE32(n)    (n)
+#else  // SK_CPU_BENDIAN
+       #define SkEndian_SwapBE16(n)    (n)
+       #define SkEndian_SwapBE32(n)    (n)
+       #define SkEndian_SwapLE16(n)    SkEndianSwap16(n)
+       #define SkEndian_SwapLE32(n)    SkEndianSwap32(n)
+#endif
+
+
+#endif
+
diff --git a/include/corecg/SkFDot6.h b/include/corecg/SkFDot6.h
new file mode 100644 (file)
index 0000000..838c3ba
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef SkFDot6_DEFINED
+#define SkFDot6_DEFINED
+
+#include "SkMath.h"
+
+typedef int32_t        SkFDot6;
+
+#define SK_FDot61                      (64)
+#define SK_FDot6Half           (32)
+
+#ifdef SK_DEBUG
+       inline SkFDot6 SkIntToFDot6(S16CPU x)
+       {
+               SkASSERT(SkToS16(x) == x);
+               return x << 6;
+       }
+#else
+       #define SkIntToFDot6(x) ((x) << 6)
+#endif
+
+#define SkFDot6Floor(x)                ((x) >> 6)
+#define SkFDot6Ceil(x)         (((x) + 63) >> 6)
+#define SkFDot6Round(x)                (((x) + 32) >> 6)
+
+#define SkFixedToFDot6(x)      ((x) >> 10)
+
+inline SkFixed SkFDot6ToFixed(SkFDot6 x)
+{
+       SkASSERT((x << 10 >> 10) == x);
+
+       return x << 10;
+}
+
+#ifdef SK_SCALAR_IS_FLOAT
+       #define SkScalarToFDot6(x)      (SkFDot6)((x) * 64)
+#else
+       #define SkScalarToFDot6(x)      ((x) >> 10)
+#endif
+
+inline SkFixed SkFDot6Div(SkFDot6 a, SkFDot6 b)
+{
+       SkASSERT(b != 0);
+
+       if (a == (int16_t)a)
+               return (a << 16) / b;
+       else
+               return SkFixedDiv(a, b);
+}
+
+#endif
+
diff --git a/include/corecg/SkFixed.h b/include/corecg/SkFixed.h
new file mode 100644 (file)
index 0000000..ddb4a6f
--- /dev/null
@@ -0,0 +1,159 @@
+#ifndef SkFixed_DEFINED
+#define SkFixed_DEFINED
+
+/**    \file SkFixed.h
+
+       Types and macros for 16.16 fixed point
+*/
+
+/**    32 bit signed integer used to represent fractions values with 16 bits to the right of the decimal point
+*/
+typedef int32_t                                SkFixed;
+#define SK_Fixed1                      (1 << 16)
+#define SK_FixedHalf           (1 << 15)
+#define SK_FixedMax                    (0x7FFFFFFF)
+#define SK_FixedMin                    (0x1)
+#define SK_FixedNaN                    ((int) 0x80000000)
+#define SK_FixedPI                     (0x3243F)
+#define SK_FixedSqrt2          (92682)
+#define SK_FixedTanPIOver8     (0x6A0A)
+#define SK_FixedRoot2Over2     (0xB505)
+
+#ifdef SK_CAN_USE_FLOAT
+       #define SkFixedToFloat(x)       ((x) * 1.5258789e-5f)
+       #define SkFloatToFixed(x)       ((SkFixed)((x) * SK_Fixed1))
+#endif
+
+/**    32 bit signed integer used to represent fractions values with 30 bits to the right of the decimal point
+*/
+typedef int32_t             SkFract;
+#define SK_Fract1                      (1 << 30)
+#define Sk_FracHalf                    (1 << 29)
+#define SK_FractPIOver180      (0x11DF46A)
+
+#ifdef SK_CAN_USE_FLOAT
+       #define SkFractToFloat(x)       ((float)(x) * 0.00000000093132257f)
+       #define SkFloatToFract(x)       ((SkFract)((x) * SK_Fract1))
+#endif
+
+/**    Converts an integer to a SkFixed, asserting that the result does not overflow
+       a 32 bit signed integer
+*/
+#ifdef SK_DEBUG
+       inline SkFixed SkIntToFixed(int n)
+       {
+               SkASSERT(n >= -32768 && n <= 32767);
+               return n << 16;
+       }
+#else
+       //      force the cast to SkFixed to ensure that the answer is signed (like the debug version)
+       #define SkIntToFixed(n)         (SkFixed)((n) << 16)
+#endif
+
+/**    Converts a SkFixed to a SkFract, asserting that the result does not overflow
+       a 32 bit signed integer
+*/
+#ifdef SK_DEBUG
+       inline SkFract SkFixedToFract(SkFixed x)
+       {
+               SkASSERT(x >= (-2 << 16) && x <= (2 << 16) - 1);
+               return x << 14;
+       }
+#else
+       #define SkFixedToFract(x)       ((x) << 14)
+#endif
+
+/**    Returns the signed fraction of a SkFixed
+*/
+inline SkFixed SkFixedFraction(SkFixed x)
+{
+       SkFixed mask = x >> 31 << 16;
+       return x & 0xFFFF | mask;
+}
+
+/**    Converts a SkFract to a SkFixed
+*/
+#define SkFractToFixed(x)      ((x) >> 14)
+/**    Round a SkFixed to an integer
+*/
+#define SkFixedRound(x)                (((x) + SK_FixedHalf) >> 16)
+#define SkFixedCeil(x)         (((x) + SK_Fixed1 - 1) >> 16)
+#define SkFixedFloor(x)                ((x) >> 16)
+#define SkFixedAbs(x)          SkAbs32(x)
+#define SkFixedAve(a, b)       (((a) + (b)) >> 1)
+
+#if defined(SK_BUILD_FOR_BREW) && !defined(AEE_SIMULATOR)
+       inline SkFixed SkFixedSquare(SkFixed a)
+       {
+               SkFixed answer;
+               asm volatile ( "SMULL r6, r7, %0, %0" : : "r"(a) : "r6", "r7" );
+               asm volatile ( "MOV      r6, r6, LSR #16" );
+               asm volatile ( "ORR      r6, r6, r7, LSL #16" );
+               asm volatile ( "STR      r6, %0" : "=m"(answer) );
+               return answer;
+       }
+       inline SkFixed SkFixedMul(SkFixed a, SkFixed b)
+       {
+               SkFixed answer;
+               asm volatile ( "SMULL r6, r7, %0, %1" : : "r"(a), "r"(b) : "r6", "r7" );
+               asm volatile ( "MOV      r6, r6, LSR #16" );
+               asm volatile ( "ORR      r6, r6, r7, LSL #16" );
+               asm volatile ( "STR      r6, %0" : "=m"(answer) );
+               return answer;
+       }
+       inline SkFract SkFractMul(SkFract a, SkFract b)
+       {
+               SkFract answer;
+               asm volatile ( "SMULL r6, r7, %0, %1" : : "r"(a), "r"(b) : "r6", "r7" );
+               asm volatile ( "MOV      r6, r6, LSR #30" );
+               asm volatile ( "ORR      r6, r6, r7, LSL #2" );
+               asm volatile ( "STR      r6, %0" : "=m"(answer) );
+               return answer;
+       }
+#else
+       inline SkFixed SkFixedSquare(SkFixed value)
+       {
+               uint32_t a = SkAbs32(value);
+               uint32_t ah = a >> 16;
+               uint32_t al = a & 0xFFFF;
+               return ah * a + al * ah + (al * al >> 16);
+       }
+       SkFixed SkFixedMul(SkFixed, SkFixed);
+       SkFract SkFractMul(SkFract, SkFract);
+#endif
+#define SkFixedDiv(numer, denom)       SkDivBits(numer, denom, 16)
+SkFixed SkFixedDivInt(int32_t numer, int32_t denom);
+SkFixed SkFixedMod(SkFixed numer, SkFixed denom);
+#define SkFixedInvert(n)                       SkDivBits(SK_Fixed1, n, 16)
+#define SkFixedSqrt(n)                         SkSqrtBits(n, 23)
+SkFixed SkFixedMean(SkFixed a, SkFixed b);  //*< returns sqrt(x*y)
+int SkFixedMulCommon(SkFixed, int , int bias); // internal used by SkFixedMulFloor, SkFixedMulCeil, SkFixedMulRound
+
+#define SkFractDiv(numer, denom)       SkDivBits(numer, denom, 30)
+#define SkFractSqrt(n)                         SkSqrtBits(n, 30)
+
+SkFixed SkFixedSinCos(SkFixed radians, SkFixed* cosValueOrNil);
+#define SkFixedSin(radians)                    SkFixedSinCos(radians, nil)
+inline SkFixed SkFixedCos(SkFixed radians)
+{
+       SkFixed cosValue;
+       (void)SkFixedSinCos(radians, &cosValue);
+       return cosValue;
+}
+SkFixed SkFixedTan(SkFixed radians);
+SkFixed SkFixedASin(SkFixed);
+SkFixed SkFixedACos(SkFixed);
+SkFixed SkFixedATan2(SkFixed y, SkFixed x);
+SkFixed SkFixedExp(SkFixed);
+SkFixed SkFixedLog(SkFixed);
+
+#define SK_FixedNearlyZero                     (SK_Fixed1 >> 12)
+
+inline bool SkFixedNearlyZero(SkFixed x, SkFixed tolerance = SK_FixedNearlyZero)
+{
+       SkASSERT(tolerance > 0);
+       return SkAbs32(x) < tolerance;
+}
+
+#endif
+
diff --git a/include/corecg/SkFloatingPoint.h b/include/corecg/SkFloatingPoint.h
new file mode 100644 (file)
index 0000000..9841086
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef SkFloatingPoint_DEFINED
+#define SkFloatingPoint_DEFINED
+
+#include "SkTypes.h"
+
+#ifdef SK_CAN_USE_FLOAT
+
+#include <math.h>
+#include <float.h>
+
+#ifdef SK_BUILD_FOR_WINCE
+       #define sk_float_sqrt(x)                (float)::sqrt(x)
+       #define sk_float_sin(x)                 (float)::sin(x)
+       #define sk_float_cos(x)                 (float)::cos(x)
+       #define sk_float_tan(x)                 (float)::tan(x)
+       #define sk_float_acos(x)                (float)::acos(x)
+       #define sk_float_asin(x)                (float)::asin(x)
+       #define sk_float_atan2(y,x)             (float)::atan2(y,x)
+       #define sk_float_abs(x)                 (float)::fabs(x)
+       #define sk_float_mod(x,y)               (float)::fmod(x,y)
+       #define sk_float_exp(x)         (float)::exp(x)
+       #define sk_float_log(x)         (float)::log(x)
+#else
+       #define sk_float_sqrt(x)                sqrtf(x)
+       #define sk_float_sin(x)                 sinf(x)
+       #define sk_float_cos(x)                 cosf(x)
+       #define sk_float_tan(x)                 tanf(x)
+#ifdef SK_BUILD_FOR_MAC
+       #define sk_float_acos(x)                acos(x)
+       #define sk_float_asin(x)                asin(x)
+#else
+       #define sk_float_acos(x)                acosf(x)
+       #define sk_float_asin(x)                asinf(x)
+#endif
+       #define sk_float_atan2(y,x)     atan2f(y,x)
+       #define sk_float_abs(x)                 fabsf(x)
+       #define sk_float_mod(x,y)               fmodf(x,y)
+       #define sk_float_exp(x)                 expf(x)
+       #define sk_float_log(x)                 logf(x)
+       #define sk_float_isNaN(x)               _isnan(x)
+#endif
+
+#endif
+#endif
diff --git a/include/corecg/SkMath.h b/include/corecg/SkMath.h
new file mode 100644 (file)
index 0000000..9657f71
--- /dev/null
@@ -0,0 +1,132 @@
+#ifndef SkMath_DEFINED
+#define SkMath_DEFINED
+
+#include "SkTypes.h"
+
+/** \file SkMath.h
+
+       This file defines various math types and functions. It also introduces
+       SkScalar, the type used to describe fractional values and coordinates.
+       SkScalar is defined at compile time to be either an IEEE float, or a
+       16.16 fixed point integer. Various macros and functions in SkMath.h
+       allow arithmetic operations to be performed on SkScalars without known
+       which representation is being used. e.g. SkScalarMul(a, b) multiplies
+       two SkScalar values, and returns a SkScalar, and this works with either
+       float or fixed implementations.
+*/
+
+//#if defined(SK_BUILD_FOR_BREW) && !defined(AEE_SIMULATOR)
+#if 0
+       inline int SkCLZ(uint32_t value)
+       {
+               int     answer;
+               asm volatile ( "CLZ r6, %0" : : "r"(value) : "r6" );
+               asm volatile ( "STR r6, %0" : "=m"(answer) );
+               return answer;
+       }
+#else
+       int     SkCLZ(uint32_t);        //<! Returns the number of leading zero bits (0...32)
+#endif
+
+/**    Computes the 64bit product of a * b, and then shifts the answer down by
+       shift bits, returning the low 32bits. shift must be [0..63]
+       e.g. to perform a fixedmul, call SkMulShift(a, b, 16)
+*/
+int32_t SkMulShift(int32_t a, int32_t b, unsigned shift);
+/**    Computes numer1 * numer2 / denom in full 64 intermediate precision.
+       It is an error for denom to be 0. There is no special handling if
+       the result overflows 32bits.
+*/
+int32_t SkMulDiv(int32_t numer1, int32_t numer2, int32_t denom);
+/**    Computes (numer1 << shift) / denom in full 64 intermediate precision.
+       It is an error for denom to be 0. There is no special handling if
+       the result overflows 32bits.
+*/
+int32_t SkDivBits(int32_t numer, int32_t denom, int shift);
+int32_t SkSqrtBits(int32_t value, int bits);
+#define SkSqrt32(n)                    SkSqrtBits(n, 15)
+int32_t SkCubeRootBits(int32_t value, int bits);
+
+/**    Returns -1 if n < 0, else returns 0
+*/
+#define SkExtractSign(n)       ((int32_t)(n) >> 31)
+
+/**    If sign == -1, returns -n, else sign must be 0, and returns n.
+       Typically used in conjunction with SkExtractSign().
+*/
+inline int32_t SkApplySign(int32_t n, int32_t sign)
+{
+       SkASSERT(sign == 0 || sign == -1);
+       return (n ^ sign) - sign;
+}
+
+/**    Returns max(value, 0)
+*/
+inline int SkClampPos(int value)
+{
+       return value & ~(value >> 31);
+}
+
+/**    Given an integer and a positive (max) integer, return the value
+       pinned against 0 and max, inclusive.
+       Note: only works as long as max - value doesn't wrap around
+       @param value    The value we want returned pinned between [0...max]
+       @param max              The positive max value
+       @return 0 if value < 0, max if value > max, else value
+*/
+inline int SkClampMax(int value, int max)
+{
+       // ensure that max is positive
+       SkASSERT(max >= 0);
+       // ensure that if value is negative, max - value doesn't wrap around
+       SkASSERT(value >= 0 || max - value > 0);
+
+#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
+       if (value < 0)
+               value = 0;
+       if (value > max)
+               value = max;
+       return value;
+#else
+
+       int     diff = max - value;
+       // clear diff if diff is positive
+       diff &= diff >> 31;
+
+       // clear the result if value < 0
+       return (value + diff) & ~(value >> 31);
+#endif
+}
+
+/**    Given a positive value and a positive max, return the value
+       pinned against max.
+       Note: only works as long as max - value doesn't wrap around
+       @return max if value >= max, else value
+*/
+inline unsigned SkClampUMax(unsigned value, unsigned max)
+{
+#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
+       if (value > max)
+               value = max;
+       return value;
+#else
+       int     diff = max - value;
+       // clear diff if diff is positive
+       diff &= diff >> 31;
+
+       return value + diff;
+#endif
+}
+
+#include "SkFixed.h"
+#include "SkScalar.h"
+
+#ifdef SK_DEBUG
+       class SkMath {
+       public:
+               static void UnitTest();
+       };
+#endif
+
+#endif
+
diff --git a/include/corecg/SkMatrix.h b/include/corecg/SkMatrix.h
new file mode 100644 (file)
index 0000000..26fdb29
--- /dev/null
@@ -0,0 +1,298 @@
+#ifndef SkMatrix_DEFINED
+#define SkMatrix_DEFINED
+
+#include "SkRect.h"
+
+/**    \class SkMatrix
+
+       The SkMatrix class holds a 3x3 matrix for transforming coordinates.
+       SkMatrix does not have a constructor, so it must be explicitly initialized
+       using either reset() - to construct an identity matrix, or one of the set...()
+       functions (e.g. setTranslate, setRotate, etc.).
+*/
+class SkMatrix {
+public:
+       /**     Bit fields used to identify the characteristics of the matrix.
+               See TypeMask for the corresponding mask values.
+       */
+       enum TypeShift {
+               kTranslate_Shift,
+               kScale_Shift,
+               kAffine_Shift,
+               kPerspective_Shift,
+
+               kShiftCount
+       };
+
+       /**     Enum of bit fields for the mask return by getType().
+               Use this to identify the complexity of the matrix.
+       */
+       enum TypeMask {
+               kIdentity_Mask          = 0,                                            //!< type is 0 iff the matrix is the identiy
+               kTranslate_Mask         = 1 << kTranslate_Shift,        //!< set if the matrix has non-zero translation
+               kScale_Mask                     = 1 << kScale_Shift,            //!< set if the matrix has X or Y scale different from 1.0
+               kAffine_Mask            = 1 << kAffine_Shift,           //!< set if the matrix skews or rotates
+               kPerspective_Mask       = 1 << kPerspective_Shift       //!< set if the matrix is in perspective
+       };
+
+       /**     Returns true if the mask represents a matrix that will only scale
+               or translate (i.e., will map a rectangle into another rectangle).
+       */
+       static bool RectStaysRect(TypeMask mask)
+       {
+               return (mask & (kAffine_Mask | kPerspective_Mask)) == 0;
+       }
+
+       /**     Returns a mask bitfield describing the types of transformations
+               that the matrix will perform. This information is used by routines
+               like mapPoints, to optimize its inner loops to only perform as much
+               arithmetic as is necessary.
+       */
+       TypeMask getType() const;
+
+       /**     Returns true if the matrix is identity.
+               This is faster than testing if (getType() == kIdentity_Mask)
+       */
+       bool isIdentity() const;
+
+       /**     Returns true if the matrix that will only scale
+               or translate (i.e., will map a rectangle into another rectangle).
+       */
+       bool rectStaysRect() const { return RectStaysRect(this->getType()); }
+
+       SkScalar        getScaleX() const { return fMat[0]; }
+       SkScalar        getScaleY() const { return fMat[4]; }
+       SkScalar        getSkewY() const { return fMat[3]; }
+       SkScalar        getSkewX() const { return fMat[1]; }
+       SkScalar        getTranslateX() const { return fMat[2]; }
+       SkScalar        getTranslateY() const { return fMat[5]; }
+       SkScalar        getPerspX() const { return fMat[6]; }
+       SkScalar        getPerspY() const { return fMat[7]; }
+
+       void    setScaleX(SkScalar v) { fMat[0] = v; }
+       void    setScaleY(SkScalar v) { fMat[4] = v; }
+       void    setSkewY(SkScalar v) { fMat[3] = v; }
+       void    setSkewX(SkScalar v) { fMat[1] = v; }
+       void    setTranslateX(SkScalar v) { fMat[2] = v; }
+       void    setTranslateY(SkScalar v) { fMat[5] = v; }
+#ifdef SK_SCALAR_IS_FIXED
+       void    setPerspX(SkFract v) { fMat[6] = v; }
+       void    setPerspY(SkFract v) { fMat[7] = v; }
+#else
+       void    setPerspX(SkScalar v) { fMat[6] = v; }
+       void    setPerspY(SkScalar v) { fMat[7] = v; }
+#endif
+       /**     Set the matrix to identity
+       */
+       void    reset();
+    
+    void    set(const SkMatrix& other) { *this = other; }
+    
+       /**     Set the matrix to translate by (dx, dy).
+       */
+       void    setTranslate(SkScalar dx, SkScalar dy);
+       /**     Set the matrix to scale by sx and sy, with a pivot point at (px, py).
+               The pivot point is the coordinate that should remain unchanged by the
+               specified transformation.
+       */
+       void    setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
+       /**     Set the matrix to rotate by the specified number of degrees, with a pivot point at (px, py).
+               The pivot point is the coordinate that should remain unchanged by the
+               specified transformation.
+       */
+       void    setRotate(SkScalar degrees, SkScalar px, SkScalar py);
+       /**     Set the matrix to rotate by the specified sine and cosine values, with a pivot point at (px, py).
+               The pivot point is the coordinate that should remain unchanged by the
+               specified transformation.
+       */
+       void    setSinCos(SkScalar sinValue, SkScalar cosValue, SkScalar px, SkScalar py);
+       /**     Set the matrix to skew by sx and sy, with a pivot point at (px, py).
+               The pivot point is the coordinate that should remain unchanged by the
+               specified transformation.
+       */
+       void    setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
+       /**     Set the matrix to the concatenation of the two specified matrices, returning
+               true if the the result can be represented. Either of the two matrices may
+               also be the target matrix. *this = a * b;
+       */
+       bool    setConcat(const SkMatrix& a, const SkMatrix& b);
+
+       /**     Preconcats the matrix with the specified translation.
+               M' = M * T(dx, dy)
+       */
+       bool    preTranslate(SkScalar dx, SkScalar dy);
+       /**     Preconcats the matrix with the specified scale.
+               M' = M * S(sx, sy, px, py)
+       */
+       bool    preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
+       /**     Preconcats the matrix with the specified rotation.
+               M' = M * R(degrees, px, py)
+       */
+       bool    preRotate(SkScalar degrees, SkScalar px, SkScalar py);
+       /**     Preconcats the matrix with the specified skew.
+               M' = M * K(kx, ky, px, py)
+       */
+       bool    preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
+       /**     Preconcats the matrix with the specified matrix.
+               M' = M * other
+       */
+       bool    preConcat(const SkMatrix& other);
+
+       /**     Postconcats the matrix with the specified translation.
+               M' = T(dx, dy) * M
+       */
+       bool    postTranslate(SkScalar dx, SkScalar dy);
+       /**     Postconcats the matrix with the specified scale.
+               M' = S(sx, sy, px, py) * M
+       */
+       bool    postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
+       /**     Postconcats the matrix with the specified rotation.
+               M' = R(degrees, px, py) * M
+       */
+       bool    postRotate(SkScalar degrees, SkScalar px, SkScalar py);
+       /**     Postconcats the matrix with the specified skew.
+               M' = K(kx, ky, px, py) * M
+       */
+       bool    postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
+       /**     Postconcats the matrix with the specified matrix.
+               M' = other * M
+       */
+       bool    postConcat(const SkMatrix& other);
+
+       enum ScaleToFit {
+               kFill_ScaleToFit,               //!< scale in X and Y independently
+               kStart_ScaleToFit,              //!< uniform scale in X/Y, align along left/top
+               kCenter_ScaleToFit,             //!< uniform scale in X/Y, align along center
+               kEnd_ScaleToFit                 //!< uniform scale in X/Y, align along right/bottom
+       };
+       /**     Set the matrix to the scale and translate values that map the source rectangle
+               to the destination rectangle, returning true if the the result can be represented.
+               @param src the source rectangle to map from.
+               @param dst the destination rectangle to map to.
+               @param stf the ScaleToFit option
+               @return true if the matrix can be represented by the rectangle mapping.
+       */
+       bool    setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf = kFill_ScaleToFit);
+       /**     Set the matrix such that the specified src points would map to the
+               specified dst points. count must be withing [0..4].
+       */
+       bool    setPolyToPoly(const SkPoint dst[], const SkPoint src[], int count);
+
+
+       /**     If this matrix can be inverted, return true and if inverse is not nil, set inverse
+               to be the inverse of this matrix. If this matrix cannot be inverted, ignore inverse
+               and return false
+       */
+       bool    invert(SkMatrix* inverse) const;
+
+       /**     Apply this matrix to the array of points specified by src, and write the transformed
+               points into the array of points specified by dst.
+               dst[] = M * src[]
+               @param dst      Where the transformed coordinates are written. It must contain at least count entries
+               @param src      The original coordinates that are to be transformed. It must contain at least count entries
+               @param count The number of points in src to read, and then transform into dst.
+               @param typeMask The mask bits returned by getType() for this matrix.
+       */
+       bool    mapPoints(SkPoint dst[], const SkPoint src[], int count, TypeMask typeMask) const;
+       /**     Apply this matrix to the array of vectors specified by src, and write the transformed
+               vectors into the array of points specified by dst. This is similar to mapPoints, but
+               ignores any translation in the matrix.
+               @param dst      Where the transformed coordinates are written. It must contain at least count entries
+               @param src      The original coordinates that are to be transformed. It must contain at least count entries
+               @param count The number of vectors in src to read, and then transform into dst.
+               @param typeMask The mask bits returned by getType() for this matrix.
+       */
+       bool    mapVectors(SkVector dst[], const SkVector src[], int count, TypeMask typeMask) const;
+       /**     Apply this matrix to the src rectangle, and write the transformed rectangle into
+               dst. This is accomplished by transforming the 4 corners of src, and then setting
+               dst to the bounds of those points.
+               @param dst      Where the transformed rectangle is written.
+               @param src      The original rectangle to be transformed.
+               @param typeMask The mask bits returned by getType() for this matrix.
+       */
+       bool    mapRect(SkRect* dst, const SkRect& src, TypeMask typeMask) const;
+
+       /**     Helper method for mapPoints() where the TypeMask needs to be computed.
+       */
+       bool mapPoints(SkPoint dst[], const SkPoint src[], int count) const
+       {
+               return this->mapPoints(dst, src, count, this->getType());
+       }
+       /**     Helper method for mapPoints() where the src and dst arrays are the
+               same, and the TypeMask needs to be computed.
+       */
+       bool mapPoints(SkPoint pts[], int count) const
+       {
+               return this->mapPoints(pts, pts, count, this->getType());
+       }
+       /**     Helper method for mapVectors() where the TypeMask needs to be computed.
+       */
+       bool mapVectors(SkVector dst[], const SkVector src[], int count) const
+       {
+               return this->mapVectors(dst, src, count, this->getType());
+       }
+       /**     Helper method for mapVectors() where the src and dst arrays are the
+               same, and the TypeMask needs to be computed.
+       */
+       bool mapVectors(SkVector vecs[], int count) const
+       {
+               return this->mapVectors(vecs, vecs, count, this->getType());
+       }
+       /**     Helper method for mapRect() where the TypeMask needs to be computed.
+       */
+       bool mapRect(SkRect* dst, const SkRect& src) const
+       {
+               return this->mapRect(dst, src, this->getType());
+       }
+       /**     Helper method for mapRect() where the TypeMask needs to be computed
+               and the src and dst rects are the same (i.e. map in place)
+       */
+       bool mapRect(SkRect* rect) const
+       {
+               return this->mapRect(rect, *rect, this->getType());
+       }
+
+       /**     Return the mean radius of a circle after it has been mapped by
+               this matrix. NOTE: in perspective this value assumes the circle
+               has its center at the origin.
+       */
+       SkScalar mapRadius(SkScalar radius) const;
+
+       typedef void (*MapPtProc)(const SkMatrix& mat, SkScalar x, SkScalar y, SkPoint* result);
+       MapPtProc       getMapPtProc() const;
+
+       /**     If the matrix can be stepped in X (not complex perspective)
+               then return true and if step[XY] is not nil, return the step[XY] value.
+               If it cannot, return false and ignore step.
+       */
+       bool fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const;
+
+       friend bool operator==(const SkMatrix& a, const SkMatrix& b)
+       {
+               return memcmp(a.fMat, b.fMat, sizeof(a)) == 0;
+       }
+
+#ifdef SK_DEBUG
+  /** @cond UNIT_TEST */
+  void dump() const;
+
+       static void UnitTest();
+  /** @endcond */
+#endif
+
+private:
+       SkScalar fMat[9];
+
+       static void Map2Pt(const SkPoint srcPt[], SkMatrix* dst, SkScalar scale);
+       static void Map3Pt(const SkPoint srcPt[], SkMatrix* dst, SkScalar scaleX, SkScalar scaleY);
+       static void Map4Pt(const SkPoint srcPt[], SkMatrix* dst, SkScalar scaleX, SkScalar scaleY);
+
+       static void Perspective_ptProc(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
+       static void Affine_ptProc(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
+       static void Scale_ptProc(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
+       static void Translate_ptProc(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
+       static void Identity_ptProc(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
+};
+
+#endif
+
diff --git a/include/corecg/SkPoint.h b/include/corecg/SkPoint.h
new file mode 100644 (file)
index 0000000..5c9e165
--- /dev/null
@@ -0,0 +1,244 @@
+#ifndef SkPoint_DEFINED
+#define SkPoint_DEFINED
+
+#include "SkMath.h"
+
+/**    \struct SkPoint16
+
+       SkPoint16 holds two 16 bit integer coordinates
+*/
+struct SkPoint16 {
+       int16_t fX, fY;
+
+       void set(S16CPU x, S16CPU y) { fX = SkToS16(x); fY = SkToS16(y); }
+
+       /**     Rotate the point clockwise, writing the new point into dst
+               It is legal for dst == this
+       */
+       void rotateCW(SkPoint16* dst) const;
+       /**     Rotate the point clockwise, writing the new point back into the point
+       */
+       void rotateCW() { this->rotateCW(this); }
+       /**     Rotate the point counter-clockwise, writing the new point into dst.
+               It is legal for dst == this
+       */
+       void rotateCCW(SkPoint16* dst) const;
+       /**     Rotate the point counter-clockwise, writing the new point back into the point
+       */
+       void rotateCCW() { this->rotateCCW(this); }
+       /**     Negate the X and Y coordinates of the point.
+       */
+       void negate() { fX = -fX; fY = -fY; }
+       /**     Return a new point whose X and Y coordinates are the negative of the original point's
+       */
+       SkPoint16 operator-() const
+       {
+               SkPoint16 neg;
+               neg.fX = -fX;
+               neg.fY = -fY;
+               return neg;
+       }
+       /**     Add v's coordinates to this point's
+       */
+       void operator+=(const SkPoint16& v)
+       {
+               fX = SkToS16(fX + v.fX);
+               fY = SkToS16(fY + v.fY);
+       }
+       /**     Subtract v's coordinates from this point's
+       */
+       void operator-=(const SkPoint16& v)
+       {
+               fX = SkToS16(fX - v.fX);
+               fY = SkToS16(fY - v.fY);
+       }
+       /**     Returns true if the point's coordinates equal (x,y)
+       */
+       bool equals(S16CPU x, S16CPU y) const { return fX == x && fY == y; }
+       friend bool operator==(const SkPoint16& a, const SkPoint16& b)
+       {
+               return a.fX == b.fX && a.fY == b.fY;
+       }
+       friend bool operator!=(const SkPoint16& a, const SkPoint16& b)
+       {
+               return a.fX != b.fX || a.fY != b.fY;
+       }
+       /**     Returns a new point whose coordinates are the difference between a and b (a - b)
+       */
+       friend SkPoint16 operator-(const SkPoint16& a, const SkPoint16& b)
+       {
+               SkPoint16 v;
+               v.set(a.fX - b.fX, a.fY - b.fY);
+               return v;
+       }
+       /**     Returns a new point whose coordinates are the sum of a and b (a + b)
+       */
+       friend SkPoint16 operator+(const SkPoint16& a, const SkPoint16& b)
+       {
+               SkPoint16 v;
+               v.set(a.fX + b.fX, a.fY + b.fY);
+               return v;
+       }
+       /**     Returns the dot product of a and b, treating them as 2D vectors
+       */
+       static int32_t DotProduct(const SkPoint16& a, const SkPoint16& b)
+       {
+               return a.fX * b.fX + a.fY * b.fY;
+       }
+       /**     Returns the cross product of a and b, treating them as 2D vectors
+       */
+       static int32_t CrossProduct(const SkPoint16& a, const SkPoint16& b)
+       {
+               return a.fX * b.fY - a.fY * b.fX;
+       }
+};
+
+struct SkPoint32 {
+       int32_t fX, fY;
+
+       void set(int x, int y) { fX = x; fY = y; }
+};
+
+struct SkPoint {
+       SkScalar        fX, fY;
+
+       /**     Set the point's X and Y coordinates
+       */
+       void set(SkScalar x, SkScalar y) { fX = x; fY = y; }
+       /**     Set the point's X and Y coordinates by automatically promoting (x,y) to SkScalar values.
+       */
+       void iset(S16CPU x, S16CPU y) { fX = SkIntToScalar(x); fY = SkIntToScalar(y); }
+       /**     Set the point's X and Y coordinates by automatically promoting p's coordinates to SkScalar values.
+       */
+       void iset(const SkPoint16& p) { fX = SkIntToScalar(p.fX); fY = SkIntToScalar(p.fY); }
+
+       /**     Return the euclidian distance from (0,0) to the point
+       */
+       SkScalar length() const { return SkPoint::Length(fX, fY); }
+
+       /**     Set the point (vector) to be unit-length in the same direction as it
+               currently is, and return its old length. If the old length is
+               degenerately small (nearly zero), do nothing and return 0.
+       */
+       bool normalize();
+       /**     Set the point (vector) to be unit-length in the same direction as the
+               x,y params, and return their old length. If the old length is
+               degenerately small (nearly zero), do nothing and return 0.
+       */
+       bool setUnit(SkScalar x, SkScalar y);
+       /**     Scale the point to have the specified length, and return that
+               length. If the original length is
+               degenerately small (nearly zero), do nothing and return 0.
+       */
+       bool setLength(SkScalar length);
+       /**     Set the point to have the specified length in the same direction as (x,y),
+               and return the old length of (x,y). If that old length is
+               degenerately small (nearly zero), do nothing and return 0.
+       */
+       bool setLength(SkScalar x, SkScalar y, SkScalar length);
+
+       /**     Scale the point's coordinates by scale, writing the answer into dst.
+               It is legal for dst == this.
+       */
+       void scale(SkScalar scale, SkPoint* dst) const;
+       /**     Scale the point's coordinates by scale, writing the answer back into the point.
+       */
+       void scale(SkScalar scale) { this->scale(scale, this); }
+
+       /**     Rotate the point clockwise by 90 degrees, writing the answer into dst.
+               It is legal for dst == this.
+       */
+       void rotateCW(SkPoint* dst) const;
+       /**     Rotate the point clockwise by 90 degrees, writing the answer back into the point.
+       */
+       void rotateCW() { this->rotateCW(this); }
+       /**     Rotate the point counter-clockwise by 90 degrees, writing the answer into dst.
+               It is legal for dst == this.
+       */
+       void rotateCCW(SkPoint* dst) const;
+       /**     Rotate the point counter-clockwise by 90 degrees, writing the answer back into the point.
+       */
+       void rotateCCW() { this->rotateCCW(this); }
+       /**     Negate the point's coordinates
+       */
+       void negate() { fX = -fX; fY = -fY; }
+       /**     Returns a new point whose coordinates are the negative of the point's
+       */
+       SkPoint operator-() const
+       {
+               SkPoint neg;
+               neg.fX = -fX;
+               neg.fY = -fY;
+               return neg;
+       }
+
+       /**     Add v's coordinates to the point's
+       */
+       void operator+=(const SkPoint& v)
+       {
+               fX += v.fX;
+               fY += v.fY;
+       }
+       /**     Subtract v's coordinates from the point's
+       */
+       void operator-=(const SkPoint& v)
+       {
+               fX -= v.fX;
+               fY -= v.fY;
+       }
+
+       /**     Returns true if the point's coordinates equal (x,y)
+       */
+       bool equals(SkScalar x, SkScalar y) const { return fX == x && fY == y; }
+       friend bool operator==(const SkPoint& a, const SkPoint& b)
+       {
+               return a.fX == b.fX && a.fY == b.fY;
+       }
+       friend bool operator!=(const SkPoint& a, const SkPoint& b)
+       {
+               return a.fX != b.fX || a.fY != b.fY;
+       }
+
+       /**     Returns a new point whose coordinates are the difference between a's and b's (a - b)
+       */
+       friend SkPoint operator-(const SkPoint& a, const SkPoint& b)
+       {
+               SkPoint v;
+               v.set(a.fX - b.fX, a.fY - b.fY);
+               return v;
+       }
+       /**     Returns a new point whose coordinates are the sum of a's and b's (a + b)
+       */
+       friend SkPoint operator+(const SkPoint& a, const SkPoint& b)
+       {
+               SkPoint v;
+               v.set(a.fX + b.fX, a.fY + b.fY);
+               return v;
+       }
+       /**     Returns the euclidian distance from (0,0) to (x,y)
+       */
+       static SkScalar Length(SkScalar x, SkScalar y);
+       /**     Returns the euclidian distance between a and b
+       */
+       static SkScalar Distance(const SkPoint& a, const SkPoint& b)
+       {
+               return Length(a.fX - b.fX, a.fY - b.fY);
+       }
+       /**     Returns the dot product of a and b, treating them as 2D vectors
+       */
+       static SkScalar DotProduct(const SkPoint& a, const SkPoint& b)
+       {
+               return SkScalarMul(a.fX, b.fX) + SkScalarMul(a.fY, b.fY);
+       }
+       /**     Returns the cross product of a and b, treating them as 2D vectors
+       */
+       static SkScalar CrossProduct(const SkPoint& a, const SkPoint& b)
+       {
+               return SkScalarMul(a.fX, b.fY) - SkScalarMul(a.fY, b.fX);
+       }
+};
+
+typedef SkPoint SkVector;
+
+#endif
+
diff --git a/include/corecg/SkPostConfig.h b/include/corecg/SkPostConfig.h
new file mode 100644 (file)
index 0000000..18f1517
--- /dev/null
@@ -0,0 +1,169 @@
+#ifndef SkPostConfig_DEFINED
+#define SkPostConfig_DEFINED
+
+#if defined(SK_BUILD_FOR_WIN32) || defined(SK_BUILD_FOR_WINCE)
+       #define SK_BUILD_FOR_WIN
+#endif
+
+#if defined(SK_DEBUG) && defined(SK_RELEASE)
+       #error "cannot define both SK_DEBUG and SK_RELEASE"
+#elif !defined(SK_DEBUG) && !defined(SK_RELEASE)
+       #error "must define either SK_DEBUG or SK_RELEASE"
+#endif
+
+#if defined SK_SUPPORT_UNITTEST && !defined(SK_DEBUG)
+       #error "can't have unittests without debug"
+#endif
+
+#if defined(SK_SCALAR_IS_FIXED) && defined(SK_SCALAR_IS_FLOAT)
+       #error "cannot define both SK_SCALAR_IS_FIXED and SK_SCALAR_IS_FLOAT"
+#elif !defined(SK_SCALAR_IS_FIXED) && !defined(SK_SCALAR_IS_FLOAT)
+    #ifdef SK_CAN_USE_FLOAT
+        #define SK_SCALAR_IS_FLOAT
+    #else
+        #define SK_SCALAR_IS_FIXED
+    #endif
+#endif
+
+#if defined(SK_SCALAR_IS_FLOAT) && !defined(SK_CAN_USE_FLOAT)
+       #define SK_CAN_USE_FLOAT
+       // we do nothing in the else case: fixed-scalars can have floats or not
+#endif
+
+#if defined(SK_CPU_LENDIAN) && defined(SK_CPU_BENDIAN)
+       #error "cannot define both SK_CPU_LENDIAN and SK_CPU_BENDIAN"
+#elif !defined(SK_CPU_LENDIAN) && !defined(SK_CPU_BENDIAN)
+       #error "must define either SK_CPU_LENDIAN or SK_CPU_BENDIAN"
+#endif
+
+#ifndef SkNEW
+       #define SkNEW(type_name)                                new type_name
+       #define SkNEW_ARGS(type_name, args)             new type_name args
+       #define SkDELETE(obj)                                   delete obj
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_BUILD_FOR_WIN
+       #define WIN32_LEAN_AND_MEAN
+       #include <windows.h>
+       #undef WIN32_LEAN_AND_MEAN
+
+       #ifndef SK_DEBUGBREAK
+               #define SK_DEBUGBREAK(cond)             do { if (!(cond)) DebugBreak(); } while (false)
+       #endif
+
+       #ifdef SK_BUILD_FOR_WIN32
+               #define strcasecmp(a, b)                stricmp(a, b)
+               #define strncasecmp(a, b, c)    strnicmp(a, b, c)
+       #elif defined(SK_BUILD_FOR_WINCE)
+               #define strcasecmp(a, b)                _stricmp(a, b)
+               #define strncasecmp(a, b, c)    _strnicmp(a, b, c)
+       #endif
+#elif defined(SK_BUILD_FOR_MAC)
+       #include <carbon/carbon.h>
+       #ifndef SK_DEBUGBREAK
+               #define SK_DEBUGBREAK(cond)         do { if (!(cond)) sk_throw(); } while (false)
+       #endif
+#else
+    #ifdef SK_DEBUG
+        #include <assert.h>
+        #ifndef SK_DEBUGBREAK
+            #define SK_DEBUGBREAK(cond)        assert(cond)
+        #endif
+    #endif
+#endif
+
+//     stdlib macros
+
+#if 0
+#if !defined(strlen) && defined(SK_DEBUG)
+       extern size_t sk_strlen(const char*);
+       #define strlen(s)       sk_strlen(s)
+#endif
+#ifndef sk_strcpy
+       #define sk_strcpy(dst, src)             strcpy(dst, src)
+#endif
+#ifndef sk_strchr
+       #define sk_strchr(s, c)                 strchr(s, c)
+#endif
+#ifndef sk_strrchr
+       #define sk_strrchr(s, c)                strrchr(s, c)
+#endif
+#ifndef sk_strcmp
+       #define sk_strcmp(s, t)                 strcmp(s, t)
+#endif
+#ifndef sk_strncmp
+       #define sk_strncmp(s, t, n)             strncmp(s, t, n)
+#endif
+#ifndef sk_memcpy
+       #define sk_memcpy(dst, src, n)  memcpy(dst, src, n)
+#endif
+#ifndef memmove
+       #define memmove(dst, src, n)    memmove(dst, src, n)
+#endif
+#ifndef sk_memset
+       #define sk_memset(dst, val, n)  memset(dst, val, n)
+#endif
+#ifndef sk_memcmp
+       #define sk_memcmp(s, t, n)              memcmp(s, t, n)
+#endif
+
+#define sk_strequal(s, t)                      (!sk_strcmp(s, t))
+#define sk_strnequal(s, t, n)          (!sk_strncmp(s, t, n))
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+#ifndef SK_BUILD_FOR_WINCE
+#include <string.h>
+#include <stdlib.h>
+#else
+#define _CMNINTRIN_DECLARE_ONLY
+#include "cmnintrin.h"
+#endif
+
+#if defined SK_DEBUG && defined SK_BUILD_FOR_WIN32
+//#define _CRTDBG_MAP_ALLOC
+#ifdef free
+#undef free
+#endif
+#include <crtdbg.h>
+#undef free
+
+#ifdef SK_DEBUG
+#if defined(SK_SIMULATE_FAILED_MALLOC) && defined(__cplusplus)
+       void * operator new(
+        size_t cb,
+        int nBlockUse,
+        const char * szFileName,
+        int nLine,
+               int foo
+        );
+       void * operator new[](
+        size_t cb,
+        int nBlockUse,
+        const char * szFileName,
+        int nLine,
+               int foo
+        );
+       void operator delete(
+        void *pUserData,
+               int, const char*, int, int
+        );
+       void operator delete(
+        void *pUserData
+        );
+       void operator delete[]( void * p );
+       #define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__, 0)
+#else
+       #define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
+#endif
+       #define new DEBUG_CLIENTBLOCK
+#else
+#define DEBUG_CLIENTBLOCK
+#endif // _DEBUG
+
+#endif
+
+#endif
+
diff --git a/include/corecg/SkPreConfig.h b/include/corecg/SkPreConfig.h
new file mode 100644 (file)
index 0000000..7e14287
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef SkPreConfig_DEFINED
+#define SkPreConfig_DEFINED
+
+#ifdef ANDROID
+    #define SK_BUILD_FOR_UNIX
+    #define SK_SCALAR_IS_FIXED
+    #define SK_CAN_USE_FLOAT
+#endif
+
+#if !defined(SK_CPU_BENDIAN) && !defined(SK_CPU_LENDIAN)
+    #if defined(__APPLE__) || defined(__MC68K__)
+        #define SK_CPU_BENDIAN
+    #else
+        #define SK_CPU_LENDIAN
+    #endif
+#endif
+
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(SK_BUILD_FOR_PALM) && !defined(SK_BUILD_FOR_WINCE) && !defined(SK_BUILD_FOR_WIN32) && !defined(SK_BUILD_FOR_SYMBIAN) && !defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUILD_FOR_MAC)
+
+    #if defined(PALMOS_SDK_VERSION)
+        #define SK_BUILD_FOR_PALM
+    #elif defined(UNDER_CE)
+        #define SK_BUILD_FOR_WINCE
+    #elif defined(WIN32)
+        #define SK_BUILD_FOR_WIN32
+    #elif defined(__SYMBIAN32__)
+        #define SK_BUILD_FOR_WIN32
+    #elif defined(linux)
+        #define SK_BUILD_FOR_UNIX
+    #else
+        #define SK_BUILD_FOR_MAC
+    #endif
+
+#endif
+
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(SK_DEBUG) && !defined(SK_RELEASE)
+       #ifdef NDEBUG
+               #define SK_RELEASE
+       #else
+               #define SK_DEBUG
+       #endif
+#endif
+
+//////////////////////////////////////////////////////////////////////
+
+#ifdef SK_BUILD_FOR_WIN32
+       #define SK_SCALAR_IS_FLOAT
+#endif
+
+#if defined(SK_BUILD_FOR_WIN32) || defined(SK_BUILD_FOR_MAC)
+       #define SK_CAN_USE_FLOAT
+    #define SK_SCALAR_IS_FIXED
+       #define SK_CAN_USE_LONGLONG
+#endif
+
+//////////////////////////////////////////////////////////////////////
+
+#ifdef SK_CAN_USE_LONGLONG
+       #ifdef SK_BUILD_FOR_WIN32
+               #define SkLONGLONG      __int64
+       #else
+               #define SkLONGLONG      long long
+       #endif
+#endif
+
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(SK_CPU_BENDIAN) && !defined(SK_CPU_LENDIAN)
+
+#ifdef SK_BUILD_FOR_MAC
+       #define SK_CPU_BENDIAN
+#else
+       #define SK_CPU_LENDIAN
+#endif
+
+#endif
+
+#if defined(SK_BUILD_FOR_BREW) || defined(SK_BUILD_FOR_WINCE) || (defined(SK_BUILD_FOR_SYMBIAN) && !defined(__MARM_THUMB__))
+       /* e.g. the ARM instructions have conditional execution, making tiny branches cheap */
+       #define SK_CPU_HAS_CONDITIONAL_INSTR
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Conditional features based on build target
+
+#if defined(SK_BUILD_FOR_WIN32) || defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
+    #ifndef SK_BUILD_NO_IMAGE_ENCODE
+        #define SK_SUPPORT_IMAGE_ENCODE
+    #endif
+#endif
+
+#ifdef SK_BUILD_FOR_SYMBIAN
+    #define SK_USE_RUNTIME_GLOBALS
+#endif
+
+#endif
+
diff --git a/include/corecg/SkRandom.h b/include/corecg/SkRandom.h
new file mode 100644 (file)
index 0000000..362117e
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef SkRandom_DEFINED
+#define SkRandom_DEFINED
+
+#include "Sk64.h"
+
+/**    \class SkRandom
+
+       Utility class that implements pseudo random 32bit numbers using a fast
+       linear equation. Unlike rand(), this class holds its own seed (initially
+       set to 0), so that multiple instances can be used with no side-effects.
+*/
+class SkRandom {
+public:
+       SkRandom() : fSeed(0) {}
+       SkRandom(uint32_t seed) : fSeed(seed) {}
+
+       /**     Return the next pseudo random number as an unsigned 32bit value.
+       */
+       uint32_t        nextU() { uint32_t r = fSeed * kMul + kAdd; fSeed = r; return r; }
+       /**     Return the next pseudo random number as a signed 32bit value.
+       */
+       int32_t nextS() { return (int32_t)this->nextU(); }
+       /**     Return the next pseudo random number as an unsigned 16bit value.
+       */
+       U16CPU nextU16() { return this->nextU() >> 16; }
+       /**     Return the next pseudo random number as a signed 16bit value.
+       */
+       S16CPU nextS16() { return this->nextS() >> 16; }
+
+       /**     Return the next pseudo random number, as an unsigned value of
+               at most bitCount bits.
+               @param bitCount The maximum number of bits to be returned
+       */
+       uint32_t nextBits(unsigned bitCount)
+       {
+               SkASSERT(bitCount > 0 && bitCount <= 32);
+               return this->nextU() >> (32 - bitCount);
+       }
+       /**     Return the next pseudo random unsigned number, mapped to lie within
+               [min, max] inclusive.
+       */
+       uint32_t nextRangeU(uint32_t min, uint32_t max)
+       {
+               SkASSERT(min <= max);
+               return min + this->nextU() % (max - min + 1);
+       }
+
+       /**     Return the next pseudo random number expressed as an unsigned SkFixed
+               in the range [0..SK_Fixed1).
+       */
+       SkFixed nextUFixed1() { return this->nextU() >> 16; }
+       /**     Return the next pseudo random number expressed as a signed SkFixed
+               in the range (-SK_Fixed1..SK_Fixed1).
+       */
+       SkFixed nextSFixed1() { return this->nextS() >> 15; }
+
+       /**     Return the next pseudo random number expressed as a SkScalar
+               in the range [0..SK_Scalar1).
+       */
+       SkScalar nextUScalar1() { return SkFixedToScalar(this->nextUFixed1()); }
+       /**     Return the next pseudo random number expressed as a SkScalar
+               in the range (-SK_Scalar1..SK_Scalar1).
+       */
+       SkScalar nextSScalar1() { return SkFixedToScalar(this->nextSFixed1()); }
+
+       /**     Return the next pseudo random number as a signed 64bit value.
+       */
+       void next64(Sk64* a) { SkASSERT(a); a->set(this->nextS(), this->nextU()); }
+       /**     Set the seed of the random object. The seed is initialized to 0 when the
+               object is first created, and is updated each time the next pseudo random
+               number is requested.
+       */
+       void setSeed(int32_t seed) { fSeed = (uint32_t)seed; }
+
+private:
+       //      "Numerical Recipes in C", 1992 page 284
+       enum {
+               kMul = 1664525,
+               kAdd = 1013904223
+       };
+       uint32_t fSeed;
+};
+
+#endif
+
diff --git a/include/corecg/SkRect.h b/include/corecg/SkRect.h
new file mode 100644 (file)
index 0000000..ec48e38
--- /dev/null
@@ -0,0 +1,266 @@
+#ifndef SkRect_DEFINED
+#define SkRect_DEFINED
+
+#include "SkPoint.h"
+
+/**    \struct SkRect16
+
+       SkRect16 holds four 16 bit integer coordinates for a rectangle
+*/
+struct SkRect16 {
+       S16     fLeft, fTop, fRight, fBottom;
+
+       /**     Returns true if the rectangle is empty (e.g. left >= right or top >= bottom)
+       */
+       bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
+       /**     Returns the rectangle's width. This does not check for a valid rectangle (i.e. left <= right)
+               so the result may be negative.
+       */
+       int     width() const { return fRight - fLeft; }
+       /**     Returns the rectangle's height. This does not check for a valid rectangle (i.e. top <= bottom)
+               so the result may be negative.
+       */
+       int     height() const { return fBottom - fTop; }
+
+       friend int operator==(const SkRect16& a, const SkRect16& b)
+       {
+               return !memcmp(&a, &b, sizeof(a));
+       }
+       friend int operator!=(const SkRect16& a, const SkRect16& b)
+       {
+               return memcmp(&a, &b, sizeof(a));
+       }
+
+       /**     Set the rectangle to (0,0,0,0)
+       */
+       void setEmpty() { memset(this, 0, sizeof(*this)); }
+
+       void set(S16CPU left, S16CPU top, S16CPU right, S16CPU bottom)
+       {
+               fLeft   = SkToS16(left);
+               fTop    = SkToS16(top);
+               fRight  = SkToS16(right);
+               fBottom = SkToS16(bottom);
+       }
+       /**     Offset set the rectangle by adding dx to its left and right,
+               and adding dy to its top and bottom.
+       */
+       void offset(S16CPU dx, S16CPU dy)
+       {
+               fLeft   = SkToS16(fLeft + dx);
+               fTop    = SkToS16(fTop + dy);
+               fRight  = SkToS16(fRight + dx);
+               fBottom = SkToS16(fBottom + dy);
+       }
+       /**     Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards,
+               making the rectangle narrower. If dx is negative, then the sides are moved outwards,
+               making the rectangle wider. The same hods true for dy and the top and bottom.
+       */
+       void inset(S16CPU dx, S16CPU dy)
+       {
+               fLeft   = SkToS16(fLeft + dx);
+               fTop    = SkToS16(fTop + dy);
+               fRight  = SkToS16(fRight - dx);
+               fBottom = SkToS16(fBottom - dy);
+       }
+       /**     Returns true if (x,y) is inside the rectangle. The left and top are considered to be
+               inside, while the right and bottom are not. Thus for the rectangle (0, 0, 5, 10), the
+               points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not.
+       */
+       bool contains(S16CPU x, S16CPU y) const
+       {
+               return  (unsigned)(x - fLeft) < (unsigned)(fRight - fLeft) &&
+                               (unsigned)(y - fTop) < (unsigned)(fBottom - fTop);
+       }
+       /**     Returns true if the 4 specified sides of a rectangle are inside or equal to this rectangle.
+       */
+       bool contains(S16CPU left, S16CPU top, S16CPU right, S16CPU bottom) const
+       {
+               return  fLeft <= left && fTop <= top &&
+                               fRight >= right && fBottom >= bottom;
+       }
+       /**     Returns true if the specified rectangle r is inside or equal to this rectangle.
+       */
+       bool contains(const SkRect16& r) const
+       {
+               return  fLeft <= r.fLeft && fTop <= r.fTop &&
+                               fRight >= r.fRight && fBottom >= r.fBottom;
+       }
+       /**     If r intersects this rectangle, return true and set this rectangle to that
+               intersection, otherwise return false and do not change this rectangle.
+       */
+       bool intersect(const SkRect16& r);
+       /**     If rectangles a and b intersect, return true and set this rectangle to that
+               intersection, otherwise return false and do not change this rectangle.
+       */
+       bool intersect(const SkRect16& a, const SkRect16& b);
+       /**     If the rectangle specified by left,top,right,bottom intersects this rectangle,
+               return true and set this rectangle to that intersection,
+               otherwise return false and do not change this rectangle.
+       */
+       bool intersect(S16CPU left, S16CPU top, S16CPU right, S16CPU bottom);
+       /**     Returns true if a and b intersect
+       */
+       static bool Intersects(const SkRect16& a, const SkRect16& b)
+       {
+               return  a.fLeft < b.fRight && b.fLeft < a.fRight &&
+                               a.fTop < b.fBottom && b.fTop < a.fBottom;
+       }
+       void join(const SkRect16& r)
+       {
+               fLeft = SkToS16(SkMin32(fLeft, r.fLeft));
+               fTop = SkToS16(SkMin32(fTop, r.fTop));
+               fRight = SkToS16(SkMax32(fRight, r.fRight));
+               fBottom = SkToS16(SkMax32(fBottom, r.fBottom));
+       }
+
+       /** Swap top/bottom or left/right if there are flipped.
+               This can be called if the edges are computed separately,
+               and may have crossed over each other.
+               When this returns, left <= right && top <= bottom
+       */
+       void sort();
+};
+
+/**    \struct SkRect
+*/
+struct SkRect {
+       SkScalar        fLeft, fTop, fRight, fBottom;
+
+       bool            isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
+       SkScalar        width() const { return fRight - fLeft; }
+       SkScalar        height() const { return fBottom - fTop; }
+       SkScalar        centerX() const { return SkScalarHalf(fLeft + fRight); }
+       SkScalar        centerY() const { return SkScalarHalf(fTop + fBottom); }
+
+       friend int operator==(const SkRect& a, const SkRect& b)
+       {
+               return !memcmp(&a, &b, sizeof(a));
+       }
+       friend int operator!=(const SkRect& a, const SkRect& b)
+       {
+               return memcmp(&a, &b, sizeof(a));
+       }
+
+       /** return the 4 points that enclose the rectangle
+       */
+       void toQuad(SkPoint quad[4]) const;
+
+       /**     Set this rectangle to the empty rectangle (0,0,0,0)
+       */
+       void setEmpty() { memset(this, 0, sizeof(*this)); }
+
+       void set(const SkRect16& src)
+       {
+               fLeft   = SkIntToScalar(src.fLeft);
+               fTop    = SkIntToScalar(src.fTop);
+               fRight  = SkIntToScalar(src.fRight);
+               fBottom = SkIntToScalar(src.fBottom);
+       }
+
+       void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom)
+       {
+               fLeft   = left;
+               fTop    = top;
+               fRight  = right;
+               fBottom = bottom;
+       }
+       /**     Set this rectangle to be the bounds of the array of points.
+               If the array is empty (count == 0), then set this rectangle
+               to the empty rectangle (0,0,0,0)
+       */
+       void set(const SkPoint pts[], int count);
+
+       /**     Offset set the rectangle by adding dx to its left and right,
+               and adding dy to its top and bottom.
+       */
+       void offset(SkScalar dx, SkScalar dy)
+       {
+               fLeft   += dx;
+               fTop    += dy;
+               fRight  += dx;
+               fBottom += dy;
+       }       
+       /**     Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards,
+               making the rectangle narrower. If dx is negative, then the sides are moved outwards,
+               making the rectangle wider. The same hods true for dy and the top and bottom.
+       */
+       void inset(SkScalar dx, SkScalar dy)
+       {
+               fLeft   += dx;
+               fTop    += dy;
+               fRight  -= dx;
+               fBottom -= dy;
+       }
+
+       /**     If this rectangle intersects r, return true and set this rectangle to that
+               intersection, otherwise return false and do not change this rectangle.
+       */
+       bool intersect(const SkRect& r);
+       /**     If this rectangle intersects the rectangle specified by left, top, right, bottom,
+               return true and set this rectangle to that
+               intersection, otherwise return false and do not change this rectangle.
+       */
+       bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
+       /**     Return true if rectangles a and b intersect.
+       */
+       static bool Intersects(const SkRect& a, const SkRect& b)
+       {
+               return  a.fLeft < b.fRight && b.fLeft < a.fRight &&
+                               a.fTop < b.fBottom && b.fTop < a.fBottom;
+       }
+
+       /**     Returns true if (p.fX,p.fY) is inside the rectangle. The left and top coordinates of
+               the rectangle are considered to be inside, while the right and bottom coordinates
+               are not. Thus for the rectangle (0, 0, 5, 10), the points (0,0) and (0,9) are inside,
+               while (-1,0) and (5,9) are not.
+       */
+       bool contains(const SkPoint& p) const
+       {
+               return  fLeft <= p.fX && p.fX < fRight &&
+                               fTop <= p.fY && p.fY < fBottom;
+       }
+       /**     Returns true if (x,y) is inside the rectangle. The left and top coordinates of
+               the rectangle are considered to be inside, while the right and bottom coordinates
+               are not. Thus for the rectangle (0, 0, 5, 10), the points (0,0) and (0,9) are inside,
+               while (-1,0) and (5,9) are not.
+       */
+       bool contains(SkScalar x, SkScalar y) const
+       {
+               return  fLeft <= x && x < fRight &&
+                               fTop <= y && y < fBottom;
+       }
+       /**     Return true if this rectangle contains r
+       */
+       bool contains(const SkRect& r) const
+       {
+               return  fLeft <= r.fLeft && fTop <= r.fTop &&
+                               fRight >= r.fRight && fBottom >= r.fBottom;
+       }
+       /**     Set the dst integer rectangle by rounding this rectangle's coordinates
+               to their nearest integer values.
+       */
+       void round(SkRect16* dst) const
+       {
+               SkASSERT(dst);
+               dst->set(SkScalarRound(fLeft), SkScalarRound(fTop), SkScalarRound(fRight), SkScalarRound(fBottom));
+       }
+       /**     Set the dst integer rectangle by rounding "out" this rectangle, choosing the floor of top and left,
+               and the ceiling of right and bototm.
+       */
+       void roundOut(SkRect16* dst) const
+       {
+               SkASSERT(dst);
+               dst->set(SkScalarFloor(fLeft), SkScalarFloor(fTop), SkScalarCeil(fRight), SkScalarCeil(fBottom));
+       }
+
+       /** Swap top/bottom or left/right if there are flipped.
+               This can be called if the edges are computed separately,
+               and may have crossed over each other.
+               When this returns, left <= right && top <= bottom
+       */
+       void sort();
+};
+
+#endif
+
diff --git a/include/corecg/SkRegion.h b/include/corecg/SkRegion.h
new file mode 100644 (file)
index 0000000..73daa9c
--- /dev/null
@@ -0,0 +1,249 @@
+#ifndef SkRegion_DEFINED
+#define SkRegion_DEFINED
+
+#include "SkRect.h"
+
+class SkPath;
+class SkRgnBuilder;
+
+namespace android {
+    class Region;
+}
+
+#define SkRegion_gEmptyRunHeadPtr ((SkRegion::RunHead*)-1)
+#define SkRegion_gRectRunHeadPtr 0
+
+/**    \class SkRegion
+
+       The SkRegion class encapsulates the geometric region used to specify
+       clipping areas for drawing.
+*/
+class SkRegion {
+public:
+       typedef int16_t RunType;
+
+       SkRegion();
+       explicit SkRegion(const SkRegion&);
+       explicit SkRegion(const SkRect16&);
+       ~SkRegion();
+
+       SkRegion& operator=(const SkRegion&);
+    
+    friend int operator==(const SkRegion& a, const SkRegion& b);
+    friend int operator!=(const SkRegion& a, const SkRegion& b)
+    {
+        return !(a == b);
+    }
+       
+       // provide explicitly, so we'll have a java equivalent
+       void set(const SkRegion& src)
+       {
+               SkASSERT(&src);
+               *this = src;
+       }
+       /**     Swap the contents of this and the specified region. This operation
+               is gauarenteed to never fail.
+       */
+       void    swap(SkRegion&);
+
+       /**     Return true if this region is empty */
+       bool    isEmpty() const { return fRunHead == SkRegion_gEmptyRunHeadPtr; }
+       /**     Return true if this region is a single, non-empty rectangle */
+       bool    isRect() const { return fRunHead == SkRegion_gRectRunHeadPtr; }
+       /**     Return true if this region consists of more than 1 rectangular area */
+       bool    isComplex() const { return !this->isEmpty() && !this->isRect(); }
+       /**     Return the bounds of this region. If the region is empty, returns an
+               empty rectangle.
+       */
+       const SkRect16& getBounds() const { return fBounds; }
+
+    /** Returns true if the region is non-empty, and if so, sets the specified path to the
+        boundary(s) of the region.
+    */
+    bool getBoundaryPath(SkPath* path) const;
+
+       /**     Set the region to be empty, and return false */
+       bool    setEmpty();
+       /**     If rect is non-empty, set this region to that rectangle and return true,
+               otherwise set this region to empty and return false.
+       */
+       bool    setRect(const SkRect16&);
+       /**     If left < right and top < bottom, set this region to that rectangle and
+               return true, otherwise set this region to empty and return false.
+       */
+       bool    setRect(S16CPU left, S16CPU top, S16CPU right, S16CPU bottom);
+       /**     Set this region to the specified region, and return true if it is non-empty. */
+       bool    setRegion(const SkRegion&);
+       /**     Set this region to the area described by the path, optionally clipped (if clip is
+               not nil). Return true if the resulting region is non-empty. This produces a region
+               that is identical to the pixels that would be drawn by the path (with no antialiasing).
+       */
+       bool    setPath(const SkPath&, const SkRegion* clip = nil);
+       /**     Return true if the specified x,y coordinate is inside the region.
+       */
+       bool    contains(S16CPU x, S16CPU y) const;
+       /**     Return true if this region is a single rectangle (not complex) and the specified rectangle
+               is contained by this region. Returning false is not a guarantee that the rectangle is not contained
+               by this region, but return true is a guarantee that the rectangle is contained by this region.
+       */
+       bool quickContains(const SkRect16& r) const
+       {
+               return this->isRect() && fBounds.contains(r);
+       }
+       /**     Return true if this region is a single rectangle (not complex) and the specified rectangle
+               is contained by this region. Returning false is not a guarantee that the rectangle is not contained
+               by this region, but return true is a guarantee that the rectangle is contained by this region.
+       */
+       bool quickContains(S16CPU left, S16CPU top, S16CPU right, S16CPU bottom) const
+       {
+               return this->isRect() && fBounds.contains(left, top, right, bottom);
+       }
+       /**     Return true if this region is empty, or if the specified rectangle does not intersect
+               the region. Returning false is not a guarantee that they intersect, but returning
+               true is a guarantee that they do not.
+       */
+       bool quickReject(const SkRect16& rect) const
+       {
+               return this->isEmpty() || !SkRect16::Intersects(fBounds, rect);
+       }
+       /**     Return true if this region, or rgn, is empty, or if their bounds do not intersect.
+               Returning false is not a guarantee that they intersect, but returning true is a guarantee
+               that they do not.
+       */
+       bool quickReject(const SkRegion& rgn) const
+       {
+               return this->isEmpty() || rgn.isEmpty() || !SkRect16::Intersects(fBounds, rgn.fBounds);
+       }
+    
+    void translate(int dx, int dy)
+    {
+        this->translate(dx, dy, this);
+    }
+    void translate(int dx, int dy, SkRegion* dst) const;
+
+       enum Op {
+               kDifference_Op,
+               kIntersect_Op,
+               kUnion_Op,
+               kXOR_Op,
+
+               kOpCount
+       };
+       /**     Set this region to the result of applying the Opereation to this region and the specified
+               rectangle. Return true if the resulting region is non-empty.
+       */
+       bool    op(const SkRect16&, Op);
+       // helper for java, so it doesn't have to create a Rect object
+       bool    op(S16CPU left, S16CPU top, S16CPU right, S16CPU bottom, Op op)
+       {
+               SkRect16 r;
+               r.set(left, top, right, bottom);
+               return this->op(r, op);
+       }
+       /**     Set this region to the result of applying the Opereation to this region and the specified
+               region. Return true if the resulting region is non-empty.
+       */
+       bool    op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); }
+       /**     Set this region to the result of applying the Opereation to the specified rectangle and region.
+               Return true if the resulting region is non-empty.
+       */
+       bool    op(const SkRect16&, const SkRegion&, Op);
+       /**     Set this region to the result of applying the Opereation to the specified regions.
+               Return true if the resulting region is non-empty.
+       */
+       bool    op(const SkRegion&, const SkRegion&, Op);
+
+       /**     Helper class that returns the sequence of rectangles that make up this region.
+       */
+       class Iterator {
+       public:
+               Iterator();
+               Iterator(const SkRegion&);
+               void                    reset(const SkRegion&);
+               bool                    done() { return fDone; }
+               void                    next();
+               const SkRect16& rect() const { return fRect; }
+
+       private:
+               const RunType*  fRuns;
+               SkRect16                fRect;
+               bool                    fDone;
+       };
+
+       /**     Helper class that returns the sequence of rectangles that make up this region,
+               intersected with the clip rectangle.
+       */
+       class Cliperator {
+       public:
+               Cliperator(const SkRegion&, const SkRect16& clip);
+               bool                    done() { return fDone; }
+               void                    next();
+               const SkRect16& rect() const { return fRect; }
+
+       private:
+               Iterator        fIter;
+               SkRect16        fClip;
+               SkRect16        fRect;
+               bool            fDone;
+       };
+
+       /**     Helper class that returns the sequence of scanline runs that make up this region.
+       */
+       class Spanerator {
+       public:
+               Spanerator(const SkRegion&, int y, int left, int right);
+               bool    next(int* left, int* right);
+
+       private:
+               const SkRegion::RunType* fRuns;
+               int     fLeft, fRight;
+               bool    fDone;
+       };
+
+    /** Return the number of bytes need to write this region to a buffer.
+    */
+    size_t  computeBufferSize() const;
+    /** Write the region to the buffer, and return the number of bytes written.
+    */
+    size_t  writeToBuffer(void* buffer) const;
+    /** Initialized the region from the buffer, returning the number
+        of bytes actually read.
+    */
+    size_t  readFromBuffer(const void* buffer);
+       
+    SkDEBUGCODE(void dump() const;)
+       SkDEBUGCODE(void validate() const;)
+    SkDEBUGCODE(static void UnitTest();)
+
+private:
+    enum {
+        kRectRegionRuns = 6,           // need to store a region of a rect [T B L R S S]        
+        kRunTypeSentinel = 0x7FFF
+    };
+
+    friend class android::Region;    // needed for marshalling efficiently
+    void allocateRuns(int count); // allocate space for count runs
+
+    struct RunHead;
+
+       SkRect16        fBounds;
+       RunHead*        fRunHead;
+
+       void                    freeRuns();
+       const RunType*  getRuns(RunType tmpStorage[], int* count) const;
+       bool                    setRuns(RunType runs[], int count);
+
+       int count_runtype_values(int* itop, int* ibot) const;
+    
+    static void build_rect_runs(const SkRect16& bounds, RunType runs[kRectRegionRuns]);
+    static bool compute_run_bounds(const RunType runs[], int count, SkRect16* bounds);
+
+    friend struct RunHead;
+       friend class Iterator;
+       friend class Spanerator;
+    friend class SkRgnBuilder;
+};
+
+
+#endif
+
diff --git a/include/corecg/SkScalar.h b/include/corecg/SkScalar.h
new file mode 100644 (file)
index 0000000..271f1d3
--- /dev/null
@@ -0,0 +1,235 @@
+#ifndef SkScalar_DEFINED
+#define SkScalar_DEFINED
+
+#include "SkTypes.h"
+
+/**    \file SkScalar.h
+
+       Types and macros for the data type SkScalar. This is the fractional numeric type
+       that, depending on the compile-time flag SK_SCALAR_IS_FLOAT, may be implemented
+       either as an IEEE float, or as a 16.16 SkFixed. The macros in this file are written
+       to allow the calling code to manipulate SkScalar values without knowing which representation
+       is in effect.
+*/
+
+#ifdef SK_SCALAR_IS_FLOAT
+       #include "SkFloatingPoint.h"
+
+       /**     SkScalar is our type for fractional values and coordinates. Depending on
+               compile configurations, it is either represented as an IEEE float, or
+               as a 16.16 fixed point integer.
+       */
+       typedef float   SkScalar;
+       extern const uint32_t gIEEENotANumber;
+       extern const uint32_t gIEEEInfinity;
+
+       /**     SK_Scalar1 is defined to be 1.0 represented as an SkScalar
+       */
+       #define SK_Scalar1                              (1.0f)
+       /**     SK_Scalar1 is defined to be 1/2 represented as an SkScalar
+       */
+       #define SK_ScalarHalf                   (0.5f)
+       /**     SK_ScalarInfinity is defined to be infinity as an SkScalar
+       */
+       #define SK_ScalarInfinity                       (*(const float*)&gIEEEInfinity)
+       /**     SK_ScalarMax is defined to be the largest value representable as an SkScalar
+       */
+       #define SK_ScalarMax                    (3.4028235e+38f)
+       /**     SK_ScalarMin is defined to be the smallest value representable as an SkScalar
+       */
+       #define SK_ScalarMin                    (1.1754944e-38f)
+       /**     SK_ScalarNaN is defined to be 'Not a Number' as an SkScalar
+       */
+       #define SK_ScalarNaN                    (*(const float*)&gIEEENotANumber)
+       /**     SkScalarIsNaN(n) returns true if argument is not a number
+       */
+       static inline bool SkScalarIsNaN(float x) { return x != x; }
+       /**     SkIntToScalar(n) returns its integer argument as an SkScalar
+       */
+       #define SkIntToScalar(n)                ((float)(n))
+       /**     SkFixedToScalar(n) returns its SkFixed argument as an SkScalar
+       */
+       #define SkFixedToScalar(x)              SkFixedToFloat(x)
+       /**     SkFixedToScalar(n) returns its SkScalar argument as an SkFixed
+       */
+       #define SkScalarToFixed(x)              (SkFixed)((x) * SK_Fixed1)
+
+       #define SkScalarToFloat(n)              (n)
+       #define SkFloatToScalar(n)              (n)
+
+       /**     SkScalarFraction(x) returns the signed fractional part of the argument
+       */
+       #define SkScalarFraction(x)             sk_float_mod(x, 1.0f)
+       /**     Rounds the SkScalar to the nearest integer value
+       */
+       inline int SkScalarRound(SkScalar x)
+       {
+               if (x < 0)
+                       x -= SK_ScalarHalf;
+               else
+                       x += SK_ScalarHalf;
+               return (int)x;
+       }
+       /**     Returns the smallest integer that is >= the specified SkScalar
+       */
+       #define SkScalarCeil(x)                 (int)ceil(x)
+       /**     Returns the largest integer that is <= the specified SkScalar
+       */
+       #define SkScalarFloor(x)                (int)floor(x)
+       /**     Returns the absolute value of the specified SkScalar
+       */
+       #define SkScalarAbs(x)                  sk_float_abs(x)
+       /**     Returns the value pinned between 0 and max inclusive
+       */
+       inline SkScalar SkScalarClampMax(SkScalar x, SkScalar max) {
+               return x < 0 ? 0 : x > max ? max : x;
+       }
+       /**     Returns the value pinned between min and max inclusive
+       */
+       inline SkScalar SkScalarPin(SkScalar x, SkScalar min, SkScalar max) {
+               return x < min ? min : x > max ? max : x;
+       }
+       /**     Returns the specified SkScalar squared (x*x)
+       */
+       inline SkScalar SkScalarSquare(SkScalar x) { return x * x; }
+       /**     Returns the product of two SkScalars
+       */
+       #define SkScalarMul(a, b)               ((a) * (b))
+       /**     Returns the product of a SkScalar and an int rounded to the nearest integer value
+       */
+       #define SkScalarMulRound(a, b) SkScalarRound((a) * (b))
+       /**     Returns the product of a SkScalar and an int promoted to the next larger int
+       */
+       #define SkScalarMulCeil(a, b) SkScalarCeil((a) * (b))
+       /**     Returns the product of a SkScalar and an int truncated to the next smaller int
+       */
+       #define SkScalarMulFloor(a, b) SkScalarFloor((a) * (b))
+       /**     Returns the quotient of two SkScalars (a/b)
+       */
+       #define SkScalarDiv(a, b)               ((a) / (b))
+       /**     Returns the mod of two SkScalars (a mod b)
+       */
+       #define SkScalarMod(x,y)                sk_float_mod(x,y)
+       /**     Returns the product of the first two arguments, divided by the third argument
+       */
+       #define SkScalarMulDiv(a, b, c) ((a) * (b) / (c))
+       /**     Returns the multiplicative inverse of the SkScalar (1/x)
+       */
+       #define SkScalarInvert(x)               (SK_Scalar1 / (x))
+       /**     Returns the square root of the SkScalar
+       */
+       #define SkScalarSqrt(x)                 sk_float_sqrt(x)
+       /**     Returns the average of two SkScalars (a+b)/2
+       */
+       #define SkScalarAve(a, b)               (((a) + (b)) * 0.5f)
+       /**     Returns the geometric mean of two SkScalars
+       */
+       #define SkScalarMean(a, b)              sk_float_sqrt((a) * (b))
+       /**     Returns one half of the specified SkScalar
+       */
+       #define SkScalarHalf(a)                 ((a) * 0.5f)
+
+       #define SK_ScalarSqrt2                  1.41421356f
+       #define SK_ScalarPI                             3.14159265f
+       #define SK_ScalarTanPIOver8             0.414213562f
+       #define SK_ScalarRoot2Over2             0.707106781f
+
+       #define SkDegreesToRadians(degrees)     ((degrees) * (SK_ScalarPI / 180))
+       float SkScalarSinCos(SkScalar radians, SkScalar* cosValue);
+       #define SkScalarSin(radians)    (float)sk_float_sin(radians)
+       #define SkScalarCos(radians)    (float)sk_float_cos(radians)
+       #define SkScalarTan(radians)    (float)sk_float_tan(radians)
+       #define SkScalarASin(val)       (float)sk_float_asin(val)
+       #define SkScalarACos(val)       (float)sk_float_acos(val)
+       #define SkScalarATan2(y, x)     (float)sk_float_atan2(y,x)
+       #define SkScalarExp(x)  (float)sk_float_exp(x)
+       #define SkScalarLog(x)  (float)sk_float_log(x)
+
+       inline SkScalar SkMaxScalar(SkScalar a, SkScalar b) { return a > b ? a : b; }
+       inline SkScalar SkMinScalar(SkScalar a, SkScalar b) { return a < b ? a : b; }
+
+#else
+       #include "SkFixed.h"
+
+       typedef SkFixed SkScalar;
+
+       #define SK_Scalar1                              SK_Fixed1
+       #define SK_ScalarHalf                   SK_FixedHalf
+       #define SK_ScalarInfinity       SK_FixedMax
+       #define SK_ScalarMax                    SK_FixedMax
+       #define SK_ScalarMin                    SK_FixedMin
+       #define SK_ScalarNaN                    SK_FixedNaN
+       #define SkScalarIsNaN(x)                ((x) == SK_FixedNaN)
+       #define SkIntToScalar(n)                SkIntToFixed(n)
+       #define SkFixedToScalar(x)              (x)
+       #define SkScalarToFixed(x)              (x)
+       #ifdef SK_CAN_USE_FLOAT
+               #define SkScalarToFloat(n)      SkFixedToFloat(n)
+               #define SkFloatToScalar(n)      SkFloatToFixed(n)
+       #endif
+       #define SkScalarFraction(x)             SkFixedFraction(x)
+       #define SkScalarRound(x)                SkFixedRound(x)
+       #define SkScalarCeil(x)                 SkFixedCeil(x)
+       #define SkScalarFloor(x)                SkFixedFloor(x)
+       #define SkScalarAbs(x)                  SkFixedAbs(x)
+       #define SkScalarClampMax(x, max) SkClampMax(x, max)
+       #define SkScalarPin(x, min, max) SkPin32(x, min, max)
+       #define SkScalarSquare(x)               SkFixedSquare(x)
+       #define SkScalarMul(a, b)               SkFixedMul(a, b)
+       #define SkScalarMulRound(a, b)          SkFixedMulCommon(a, b, SK_FixedHalf)
+       #define SkScalarMulCeil(a, b)           SkFixedMulCommon(a, b, SK_Fixed1 - 1)
+       #define SkScalarMulFloor(a, b)          SkFixedMulCommon(a, b, 0)
+       #define SkScalarDiv(a, b)               SkFixedDiv(a, b)
+       #define SkScalarMod(a, b)               SkFixedMod(a, b)
+       #define SkScalarMulDiv(a, b, c) SkMulDiv(a, b, c)
+       #define SkScalarInvert(x)               SkFixedInvert(x)
+       #define SkScalarSqrt(x)                 SkFixedSqrt(x)
+       #define SkScalarAve(a, b)               SkFixedAve(a, b)
+       #define SkScalarMean(a, b)              SkFixedMean(a, b)
+       #define SkScalarHalf(a)                 ((a) >> 1)
+
+       #define SK_ScalarSqrt2                  SK_FixedSqrt2
+       #define SK_ScalarPI                             SK_FixedPI
+       #define SK_ScalarTanPIOver8             SK_FixedTanPIOver8
+       #define SK_ScalarRoot2Over2             SK_FixedRoot2Over2
+
+       #define SkDegreesToRadians(degrees)             SkFractMul(degrees, SK_FractPIOver180)
+       #define SkScalarSinCos(radians, cosPtr) SkFixedSinCos(radians, cosPtr)
+       #define SkScalarSin(radians)    SkFixedSin(radians)
+       #define SkScalarCos(radians)    SkFixedCos(radians)
+       #define SkScalarTan(val)                SkFixedTan(val)
+       #define SkScalarASin(val)               SkFixedASin(val)
+       #define SkScalarACos(val)               SkFixedACos(val)
+       #define SkScalarATan2(y, x)             SkFixedATan2(y,x)
+       #define SkScalarExp(x)                  SkFixedExp(x)
+       #define SkScalarLog(x)                  SkFixedLog(x)
+
+       #define SkMaxScalar(a, b)               SkMax32(a, b)
+       #define SkMinScalar(a, b)               SkMin32(a, b)
+#endif
+
+#define SK_ScalarNearlyZero                    (SK_Scalar1 / (1 << 12))
+
+/*     <= is slower than < for floats, so we use < for our tolerance test
+*/
+
+inline bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance = SK_ScalarNearlyZero)
+{
+       SkASSERT(tolerance > 0);
+       return SkScalarAbs(x) < tolerance;
+}
+
+/**    Linearly interpolate between A and B, based on t.
+       If t is 0, return A
+       If t is 1, return B
+       else interpolate.
+       t must be [0..SK_Scalar1]
+*/
+inline SkScalar SkScalarInterp(SkScalar A, SkScalar B, SkScalar t)
+{
+       SkASSERT(t >= 0 && t <= SK_Scalar1);
+       return A + SkScalarMul(B - A, t);
+}
+
+#endif
+
diff --git a/include/corecg/SkTemplates.h b/include/corecg/SkTemplates.h
new file mode 100644 (file)
index 0000000..448638d
--- /dev/null
@@ -0,0 +1,161 @@
+#ifndef SkTemplates_DEFINED
+#define SkTemplates_DEFINED
+
+#include "SkTypes.h"
+
+/**    \file SkTemplates.h
+
+       This file contains light-weight template classes for type-safe and exception-safe
+       resource management.
+*/
+
+/** \class SkAutoTCallProc
+
+       Similar to SkAutoTDelete, this class is used to auto delete an object
+       when leaving the scope of the object. This is mostly useful when
+       errors occur and objects need to be cleaned up. The template uses two
+       parameters, the object, and a function that is to be called in the destructor.
+       If detach() is called then the function is not called when SkAutoTCallProc goes out
+       of scope. This also happens is the passed in object is nil.
+
+*/
+template <typename T, void (*P)(T*)> class SkAutoTCallProc {
+public:
+       SkAutoTCallProc(T* obj): fObj(obj) {}
+       ~SkAutoTCallProc()
+       {
+               if (fObj)
+                       P(fObj);
+       }
+       T* detach() { T* obj = fObj; fObj = nil; return obj; }
+private:
+       T* fObj;
+};
+
+template <typename T> class SkAutoTDelete {
+public:
+       SkAutoTDelete(T* obj) : fObj(obj) {}
+       ~SkAutoTDelete() { delete fObj; }
+
+       void    free() { delete fObj; fObj = nil; }
+       T*              detach() { T* obj = fObj; fObj = nil; return obj; }
+
+private:
+       T*      fObj;
+};
+
+template <typename T> class SkAutoTDeleteArray {
+public:
+       SkAutoTDeleteArray(T array[]) : fArray(array) {}
+       ~SkAutoTDeleteArray() { delete[] fArray; }
+
+       void    free() { delete[] fArray; fArray = nil; }
+       T*              detach() { T* array = fArray; fArray = nil; return array; }
+
+private:
+       T*      fArray;
+};
+
+template <typename T> class SkAutoTArray {
+public:
+       SkAutoTArray(size_t count)
+       {
+               fArray = nil;   // init first in case we throw
+               if (count)
+                       fArray = new T[count];
+#ifdef SK_DEBUG
+               fCount = count;
+#endif
+       }
+       ~SkAutoTArray()
+       {
+               delete[] fArray;
+       }
+
+       T* get() const { return fArray; }
+       T&      operator[](int index) const { SkASSERT((unsigned)index < fCount); return fArray[index]; }
+
+       void reset()
+       {
+               if (fArray)
+               {
+                       delete[] fArray;
+                       fArray = nil;
+               }
+       }
+
+       void replace(T* array)
+       {
+               if (fArray != array)
+               {
+                       delete[] fArray;
+                       fArray = array;
+               }
+       }
+
+       /**     Call swap to exchange your pointer to an array of T with the SkAutoTArray object.
+               After this call, the SkAutoTArray object will be responsible for deleting your
+               array, and you will be responsible for deleting its.
+       */
+       void swap(T*& other)
+       {
+               T*      tmp = fArray;
+               fArray = other;
+               other = tmp;
+       }
+
+private:
+#ifdef SK_DEBUG
+       size_t fCount;
+#endif
+       T*      fArray;
+};
+
+/** Allocate a temp array on the stack/heap.
+    Does NOT call any constructors/destructors on T (i.e. T must be POD)
+*/
+template <typename T> class SkAutoTMalloc {
+public:
+    SkAutoTMalloc(size_t count)
+    {
+        fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
+       }
+       ~SkAutoTMalloc()
+       {
+        sk_free(fPtr);
+       }
+       T* get() const { return fPtr; }
+
+private:
+       T*  fPtr;
+       // illegal
+       SkAutoTMalloc(const SkAutoTMalloc&);
+       SkAutoTMalloc& operator=(const SkAutoTMalloc&);        
+};
+
+template <size_t N, typename T> class SkAutoSTMalloc {
+public:
+    SkAutoSTMalloc(size_t count)
+    {
+               if (count <= N)
+                       fPtr = (T*)fStorage;
+               else
+                       fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
+       }
+       ~SkAutoSTMalloc()
+       {
+               if (fPtr != (T*)fStorage)
+                       sk_free(fPtr);
+       }
+       T* get() const { return fPtr; }
+
+private:
+       T*          fPtr;
+       uint32_t        fStorage[(N*sizeof(T) + 3) >> 2];
+       // illegal
+       SkAutoSTMalloc(const SkAutoSTMalloc&);
+       SkAutoSTMalloc& operator=(const SkAutoSTMalloc&);        
+};
+
+#endif
+
diff --git a/include/corecg/SkThread.h b/include/corecg/SkThread.h
new file mode 100644 (file)
index 0000000..ac548c4
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef SkThread_DEFINED
+#define SkThread_DEFINED
+
+#include "SkTypes.h"
+#include "SkThread_platform.h"
+
+/****** SkThread_platform needs to define the following...
+
+int32_t sk_atomic_inc(int32_t*);
+int32_t sk_atomic_dec(int32_t*);
+
+class SkMutex {
+public:
+       SkMutex();
+       ~SkMutex();
+
+       void    acquire();
+       void    release();
+};
+
+****************/
+
+class SkAutoMutexAcquire {
+public:
+       explicit SkAutoMutexAcquire(SkMutex& mutex) : fMutex(mutex)
+       {
+               mutex.acquire();
+       }
+       ~SkAutoMutexAcquire()
+       {
+               fMutex.release();
+       }
+private:
+       SkMutex&        fMutex;
+
+       // illegal
+       SkAutoMutexAcquire& operator=(SkAutoMutexAcquire&);
+};
+
+#endif
diff --git a/include/corecg/SkThread_platform.h b/include/corecg/SkThread_platform.h
new file mode 100644 (file)
index 0000000..bfa3899
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef SkThread_platform_DEFINED
+#define SkThread_platform_DEFINED
+
+#ifdef ANDROID
+
+#include <utils/threads.h>
+#include <utils/Atomic.h>
+
+#define sk_atomic_inc(addr)     android_atomic_inc(addr)
+#define sk_atomic_dec(addr)     android_atomic_dec(addr)
+
+class SkMutex : android::Mutex {
+public:
+       SkMutex() {}
+       ~SkMutex() {}
+
+       void    acquire() { this->lock(); }
+       void    release() { this->unlock(); }
+};
+
+#else   /* SkThread_empty.cpp */
+
+int32_t sk_atomic_inc(int32_t* addr);
+int32_t sk_atomic_dec(int32_t* addr);
+
+class SkMutex {
+public:
+       SkMutex();
+       ~SkMutex();
+
+       void    acquire();
+       void    release();
+};
+
+#endif
+
+#endif
diff --git a/include/corecg/SkTypes.h b/include/corecg/SkTypes.h
new file mode 100644 (file)
index 0000000..fe0cc38
--- /dev/null
@@ -0,0 +1,299 @@
+#ifndef SkTypes_DEFINED
+#define SkTypes_DEFINED
+
+#include "SkPreConfig.h"
+#include "SkUserConfig.h"
+#include "SkPostConfig.h"
+
+#include <stdint.h>
+#include <stdio.h>
+
+/**    \file SkTypes.h
+*/
+
+/*
+    memory wrappers
+*/
+
+extern void  sk_out_of_memory(void);    // platform specific, does not return
+extern void  sk_throw(void);            // platform specific, does not return
+enum {
+       SK_MALLOC_TEMP  = 0x01, //!< hint to sk_malloc that the requested memory will be freed in the scope of the stack frame
+       SK_MALLOC_THROW = 0x02  //!< instructs sk_malloc to call sk_throw if the memory cannot be allocated.
+};
+/**    Return a block of memory (at least 4-byte aligned) of at least the
+       specified size. If the requested memory cannot be returned, either
+       return nil (if SK_MALLOC_TEMP bit is clear) or call sk_throw()
+       (if SK_MALLOC_TEMP bit is set). To free the memory, call sk_free().
+*/
+extern void* sk_malloc_flags(size_t size, unsigned flags);
+/**    Same as sk_malloc(), but hard coded to pass SK_MALLOC_THROW as the flag
+*/
+extern void* sk_malloc_throw(size_t size);
+/**    Same as standard realloc(), but this one never returns nil on failure. It will throw
+       an exception if it fails.
+*/
+extern void* sk_realloc_throw(void* buffer, size_t size);
+/**    Free memory returned by sk_malloc(). It is safe to pass nil.
+*/
+extern void  sk_free(void*);
+
+///////////////////////////////////////////////////////////////////////
+
+#define SK_INIT_TO_AVOID_WARNING       = 0
+
+#ifdef SK_DEBUG
+    #define SkASSERT(cond)              SK_DEBUGBREAK(cond)
+       #define SkDEBUGCODE(code)                       code
+       #define SkDECLAREPARAM(type, var)       , type var
+       #define SkPARAM(var)                            , var
+//     #define SkDEBUGF(args           )               SkDebugf##args
+       #define SkDEBUGF(args           )               SkDebugf args
+       void SkDebugf(const char format[], ...);
+
+       #define SkAssertResult(cond)            SkASSERT(cond)
+#else
+       #define SkASSERT(cond)
+       #define SkDEBUGCODE(code)
+       #define SkDEBUGF(args)
+       #define SkDECLAREPARAM(type, var)
+       #define SkPARAM(var)
+
+       // unlike SkASSERT, this guy executes its condition in the non-debug build
+       #define SkAssertResult(cond)            cond
+#endif
+
+///////////////////////////////////////////////////////////////////////
+
+#ifndef nil
+       #define nil                     0
+#endif
+
+// legacy defines. will be removed before shipping
+typedef int8_t      S8;
+typedef uint8_t     U8;
+typedef int16_t     S16;
+typedef uint16_t    U16;
+typedef int32_t     S32;
+typedef uint32_t    U32;
+
+/** Fast type for signed 8 bits. Use for parameter passing and local variables, not for storage
+*/
+typedef int                    S8CPU;
+/** Fast type for unsigned 8 bits. Use for parameter passing and local variables, not for storage
+*/
+typedef int                    S16CPU;
+/** Fast type for signed 16 bits. Use for parameter passing and local variables, not for storage
+*/
+typedef unsigned       U8CPU;
+/** Fast type for unsigned 16 bits. Use for parameter passing and local variables, not for storage
+*/
+typedef unsigned       U16CPU;
+
+/** Meant to be faster than bool (doesn't promise to be 0 or 1, just 0 or non-zero
+*/
+typedef int                    SkBool;
+/**    Meant to be a small version of bool, for storage purposes. Will be 0 or 1
+*/
+typedef uint8_t                SkBool8;
+
+#ifdef SK_DEBUG
+       int8_t      SkToS8(long);
+       uint8_t     SkToU8(size_t);
+       int16_t     SkToS16(long);
+       uint16_t        SkToU16(size_t);
+       int32_t     SkToS32(long);
+       uint32_t        SkToU32(size_t);
+#else
+       #define SkToS8(x)       ((int8_t)(x))
+       #define SkToU8(x)       ((uint8_t)(x))
+       #define SkToS16(x)      ((int16_t)(x))
+       #define SkToU16(x)      ((uint16_t)(x))
+       #define SkToS32(x)      ((int32_t)(x))
+       #define SkToU32(x)      ((uint32_t)(x))
+#endif
+
+/**    Returns 0 or 1 based on the condition
+*/
+#define SkToBool(cond) ((cond) != 0)
+
+#define SK_MaxS16      32767
+#define SK_MinS16      -32767
+#define SK_MaxU16      0xFFFF
+#define SK_MinU16      0
+#define SK_MaxS32      0x7FFFFFFF
+#define SK_MinS32      0x80000001
+#define SK_MaxU32      0xFFFFFFFF
+#define SK_MinU32      0
+#define SK_NaN32       0x80000000
+
+#ifndef SK_OFFSETOF
+       #define SK_OFFSETOF(type, field)        ((char*)&(((type*)1)->field) - (char*)1)
+#endif
+
+/**    Returns the number of entries in an array (not a pointer)
+*/
+#define SK_ARRAY_COUNT(array)          (sizeof(array) / sizeof(array[0]))
+
+/**    Returns x rounded up to a multiple of 2
+*/
+#define SkAlign2(x)            (((x) + 1) >> 1 << 1)
+/** Returns x rounded up to a multiple of 4
+*/
+#define SkAlign4(x)            (((x) + 3) >> 2 << 2)
+
+typedef uint32_t SkFourByteTag;
+#define SkSetFourByteTag(a, b, c, d)   (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
+
+/**    32 bit integer to hold a unicode value
+*/
+typedef int32_t        SkUnichar;
+/**    32 bit value to hold a millisecond count
+*/
+typedef uint32_t SkMSec;
+/**    1 second measured in milliseconds
+*/
+#define SK_MSec1 1000
+/**    maximum representable milliseconds
+*/
+#define SK_MSecMax 0x7FFFFFFF
+/**    Returns a < b for milliseconds, correctly handling wrap-around from 0xFFFFFFFF to 0
+*/
+#define SkMSec_LT(a, b)                ((int32_t)(a) - (int32_t)(b) < 0)
+/**    Returns a <= b for milliseconds, correctly handling wrap-around from 0xFFFFFFFF to 0
+*/
+#define SkMSec_LE(a, b)                ((int32_t)(a) - (int32_t)(b) <= 0)
+
+
+/****************************************************************************
+       The rest of these only build with C++
+*/
+#ifdef __cplusplus
+
+/**    Faster than SkToBool for integral conditions. Returns 0 or 1
+*/
+inline int Sk32ToBool(uint32_t n)
+{
+       return (n | (0-n)) >> 31;
+}
+
+template <typename T> inline void SkTSwap(T& a, T& b)
+{
+       T c(a);
+       a = b;
+       b = c;
+}
+
+inline int32_t SkAbs32(int32_t value)
+{
+#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
+       if (value < 0)
+               value = -value;
+       return value;
+#else
+       int32_t mask = value >> 31;
+       return (value ^ mask) - mask;
+#endif
+}
+
+inline int32_t SkMax32(int32_t a, int32_t b)
+{
+       if (a < b)
+               a = b;
+       return a;
+}
+
+inline int32_t SkMin32(int32_t a, int32_t b)
+{
+       if (a > b)
+               a = b;
+       return a;
+}
+
+inline int32_t SkSign32(int32_t a)
+{
+       return (a >> 31) | ((unsigned) -a >> 31);
+}
+
+inline int32_t SkFastMin32(int32_t value, int32_t max)
+{
+#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
+       if (value > max)
+               value = max;
+       return value;
+#else
+       int diff = max - value;
+       // clear diff if it is negative (clear if value > max)
+       diff &= (diff >> 31);
+       return value + diff;
+#endif
+}
+
+/**    Returns signed 32 bit value pinned between min and max, inclusively
+*/
+inline int32_t SkPin32(int32_t value, int32_t min, int32_t max)
+{
+#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
+       if (value < min)
+               value = min;
+       if (value > max)
+               value = max;
+#else
+       if (value < min)
+               value = min;
+       else if (value > max)
+               value = max;
+#endif
+       return value;
+}
+
+inline uint32_t SkSetClear32(uint32_t flags, bool cond, unsigned shift)
+{
+       return flags & ~(1 << shift) | ((int)cond << shift);
+}
+
+class SkAutoMalloc {
+public:
+       SkAutoMalloc(size_t size)
+       {
+               fPtr = sk_malloc_flags(size, SK_MALLOC_THROW | SK_MALLOC_TEMP);
+       }
+       ~SkAutoMalloc()
+       {
+               sk_free(fPtr);
+       }
+       void* get() const { return fPtr; }
+private:
+       void* fPtr;
+       // illegal
+       SkAutoMalloc(const SkAutoMalloc&);
+       SkAutoMalloc& operator=(const SkAutoMalloc&);
+};
+
+template <size_t kSize> class SkAutoSMalloc {
+public:
+       SkAutoSMalloc(size_t size)
+       {
+               if (size <= kSize)
+                       fPtr = fStorage;
+               else
+                       fPtr = sk_malloc_flags(size, SK_MALLOC_THROW | SK_MALLOC_TEMP);
+       }
+       ~SkAutoSMalloc()
+       {
+               if (fPtr != (void*)fStorage)
+                       sk_free(fPtr);
+       }
+       void* get() const { return fPtr; }
+private:
+       void*       fPtr;
+       uint32_t        fStorage[(kSize + 3) >> 2];
+       // illegal
+       SkAutoSMalloc(const SkAutoSMalloc&);
+       SkAutoSMalloc& operator=(const SkAutoSMalloc&);
+};
+
+#endif /* C++ */
+
+#endif
+
diff --git a/include/corecg/SkUserConfig.h b/include/corecg/SkUserConfig.h
new file mode 100644 (file)
index 0000000..21f1604
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef SkUserConfig_DEFINED
+#define SkUserConfig_DEFINED
+
+/*     This file is included before all other headers, except for SkPreConfig.h.
+       That file uses various heuristics to make a "best guess" at settings for
+       the following build defines.
+
+       However, in this file you can override any of those decisions by either
+       defining new symbols, or #undef symbols that were already set.
+*/
+
+// experimental for now
+#define SK_SUPPORT_MIPMAP
+
+// android specific defines and tests
+
+#ifdef SK_FORCE_SCALARFIXED
+       #define SK_SCALAR_IS_FIXED
+       #undef SK_SCALAR_IS_FLOAT
+       #undef SK_CAN_USE_FLOAT
+#endif
+
+#ifdef SK_FORCE_SCALARFLOAT
+       #define SK_SCALAR_IS_FLOAT
+       #define SK_CAN_USE_FLOAT
+       #undef SK_SCALAR_IS_FIXED
+#endif
+
+#ifdef ANDROID
+    #include <utils/misc.h>
+
+    #if __BYTE_ORDER == __BIG_ENDIAN
+        #define SK_CPU_BENDIAN
+        #undef  SK_CPU_LENDIAN
+    #else
+        #define SK_CPU_LENDIAN
+        #undef  SK_CPU_BENDIAN
+    #endif
+#endif
+
+#ifdef SK_DEBUG
+       #define SK_SUPPORT_UNITTEST
+       /* Define SK_SIMULATE_FAILED_MALLOC to have
+        * sk_malloc throw an exception. Use this to
+        * detect unhandled memory leaks. */
+       //#define SK_SIMULATE_FAILED_MALLOC
+       //#define SK_FIND_MEMORY_LEAKS
+#endif
+
+#ifdef SK_BUILD_FOR_BREW
+       #include "SkBrewUserConfig.h"
+#endif
+
+#ifdef SK_BUILD_FOR_MAC
+    #define SK_CAN_USE_FLOAT
+#endif
+
+#endif
+
diff --git a/include/graphics/DoxygenMain.dox b/include/graphics/DoxygenMain.dox
new file mode 100644 (file)
index 0000000..9751862
--- /dev/null
@@ -0,0 +1,3 @@
+/** \mainpage notitle\r
+*   \htmlinclude "SGL Spec. rev 9.htm"\r
+*/
\ No newline at end of file
diff --git a/include/graphics/Sk1DPathEffect.h b/include/graphics/Sk1DPathEffect.h
new file mode 100644 (file)
index 0000000..3fd2885
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef Sk1DPathEffect_DEFINED
+#define Sk1DPathEffect_DEFINED
+
+#include "SkPathEffect.h"
+#include "SkPath.h"
+
+class SkPathMeasure;
+
+//  This class is not exported to java.
+class Sk1DPathEffect : public SkPathEffect {
+public:
+       Sk1DPathEffect() {}
+
+       virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
+
+protected:
+       /**     Called at the start of each contour, returns the initial offset
+               into that contour.
+       */
+       virtual SkScalar begin(SkScalar contourLength);
+       /**     Called with the current distance along the path, with the current matrix
+               for the point/tangent at the specified distance.
+               Return the distance to travel for the next call. If return <= 0, then that
+               contour is done.
+       */
+       virtual SkScalar next(SkPath* dst, SkScalar distance, SkPathMeasure&);
+
+       Sk1DPathEffect(SkRBuffer& buffer) : SkPathEffect(buffer) {}
+
+private:
+       // illegal
+       Sk1DPathEffect(const Sk1DPathEffect&);
+       Sk1DPathEffect& operator=(const Sk1DPathEffect&);
+
+       typedef SkPathEffect INHERITED;
+};
+
+class SkPath1DPathEffect : public Sk1DPathEffect {
+public:
+    enum Style {
+        kTranslate_Style,   // translate the shape to each position
+        kRotate_Style,      // rotate the shape about its center
+        kMorph_Style,       // transform each point, and turn lines into curves
+        
+        kStyleCount
+    };
+    SkPath1DPathEffect(const SkPath& path, SkScalar advance, SkScalar phase, Style);
+
+    // This method is not exported to java.
+       virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
+
+protected:
+    virtual SkScalar begin(SkScalar contourLength);
+    virtual SkScalar next(SkPath* dst, SkScalar distance, SkPathMeasure&);
+    
+private:
+    SkPath      fPath;
+    SkScalar    fAdvance, fPhase;
+    Style       fStyle;
+    
+    typedef Sk1DPathEffect INHERITED;
+};
+
+
+#endif
diff --git a/include/graphics/Sk2DPathEffect.h b/include/graphics/Sk2DPathEffect.h
new file mode 100644 (file)
index 0000000..502d4a3
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef Sk2DPathEffect_DEFINED
+#define Sk2DPathEffect_DEFINED
+
+#include "SkPathEffect.h"
+#include "SkMatrix.h"
+
+//  This class is not exported to java.
+class Sk2DPathEffect : public SkPathEffect {
+public:
+       Sk2DPathEffect(const SkMatrix& mat);
+
+       // overrides
+       virtual bool    filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
+
+    // overrides from SkFlattenable
+       virtual void    flatten(SkWBuffer&);
+    virtual Factory getFactory();
+
+protected:
+       /**     New virtual, to be overridden by subclasses.
+               This is called once from filterPath, and provides the
+               uv parameter bounds for the path. Subsequent calls to
+               next() will receive u and v values within these bounds,
+               and then a call to end() will signal the end of processing.
+       */
+       virtual void begin(const SkRect16& uvBounds, SkPath* dst);
+       virtual void next(const SkPoint& loc, int u, int v, SkPath* dst);
+       virtual void end(SkPath* dst);
+
+       /**     Low-level virtual called per span of locations in the u-direction.
+               The default implementation calls next() repeatedly with each
+               location.
+       */
+       virtual void nextSpan(int u, int v, int ucount, SkPath* dst);
+
+       const SkMatrix& getMatrix() const { return fMatrix; }
+
+       // protected so that subclasses can call this during unflattening
+       Sk2DPathEffect(SkRBuffer&);
+
+private:
+       SkMatrix        fMatrix, fInverse;
+       // illegal
+       Sk2DPathEffect(const Sk2DPathEffect&);
+       Sk2DPathEffect& operator=(const Sk2DPathEffect&);
+
+    static SkFlattenable* CreateProc(SkRBuffer&);
+
+       friend class Sk2DPathEffectBlitter;
+       typedef SkPathEffect INHERITED;
+};
+
+#endif
diff --git a/include/graphics/SkAnimator.h b/include/graphics/SkAnimator.h
new file mode 100644 (file)
index 0000000..7a70c10
--- /dev/null
@@ -0,0 +1,492 @@
+#ifndef SkAnimator_DEFINED
+#define SkAnimator_DEFINED
+
+#include "SkScalar.h"
+#include "SkKey.h"
+#include "SkEventSink.h"
+
+class SkAnimateMaker;
+class SkCanvas;
+class SkDisplayable;
+class SkEvent;
+class SkExtras;
+struct SkMemberInfo;
+class SkPaint;
+struct SkRect;
+class SkStream;
+class SkTypedArray;
+class SkXMLParserError;
+class SkDOM;
+struct SkDOMNode;
+
+/** SkElementType is the type of element: a rectangle, a color, an animator, and so on.
+       This enum is incomplete and will be fleshed out in a future release */
+enum SkElementType {
+       kElementDummyType
+};
+/** SkFieldType is the type of field: a scalar, a string, an integer, a boolean, and so on.
+       This enum is incomplete and will be fleshed out in a future release */
+enum SkFieldType {
+       kFieldDummyType
+};
+
+/** \class SkAnimator
+
+       The SkAnimator class decodes an XML stream into a display list. The
+       display list can be drawn statically as a picture, or can drawn 
+       different elements at different times to form a moving animation.
+
+       SkAnimator does not read the system time on its own; it relies on the
+       caller to pass the current time. The caller can pause, speed up, or
+       reverse the animation by varying the time passed in.
+
+       The XML describing the display list must conform to the schema 
+       described by SkAnimateSchema.xsd. 
+
+       The XML must contain an <event> element to draw. Usually, it contains
+       an <event kind="onload" /> block to add some drawing elements to the
+       display list when the document is first decoded.
+
+       Here's an "Hello World" XML sample:
+
+       <screenplay>
+               <event kind="onload" >
+                       <text text="Hello World" y="20" />
+               </event>
+       </screenplay>
+
+       To read and draw this sample:
+
+               // choose one of these two
+               SkAnimator animator; // declare an animator instance on the stack
+       //      SkAnimator* animator = new SkAnimator() // or one could instantiate the class
+
+               // choose one of these three
+               animator.decodeMemory(buffer, size); // to read from RAM
+               animator.decodeStream(stream); // to read from a user-defined stream (e.g., a zip file)
+               animator.decodeURI(filename); // to read from a web location, or from a local text file
+
+               // to draw to the current window:
+               SkCanvas canvas(getBitmap()); // create a canvas
+               animator.draw(canvas, &paint, 0); // draw the scene
+*/
+class SkAnimator : public SkEventSink {
+public:
+       SkAnimator();
+       virtual ~SkAnimator();
+
+       /** Add a drawable extension to the graphics engine. Experimental. 
+               @param extras A derived class that implements methods that identify and instantiate the class
+       */
+       void addExtras(SkExtras* extras);
+
+       /** Read in XML from a stream, and append it to the current
+               animator. Returns false if an error was encountered.
+               Error diagnostics are stored in fErrorCode and fLineNumber.
+               @param stream  The stream to append.
+               @return true if the XML was parsed successfully.
+       */
+       bool appendStream(SkStream* stream);
+
+       /** Read in XML from memory. Returns true if the file can be 
+               read without error. Returns false if an error was encountered.
+               Error diagnostics are stored in fErrorCode and fLineNumber.
+               @param buffer  The XML text as UTF-8 characters.
+               @param size  The XML text length in bytes.
+               @return true if the XML was parsed successfully.
+       */
+       bool decodeMemory(const void* buffer, size_t size);
+
+       /** Read in XML from a stream. Returns true if the file can be 
+               read without error. Returns false if an error was encountered.
+               Error diagnostics are stored in fErrorCode and fLineNumber.
+               @param stream  The stream containg the XML text as UTF-8 characters.
+               @return true if the XML was parsed successfully.
+       */
+       virtual bool decodeStream(SkStream* stream);
+
+       /** Parse the DOM tree starting at the specified node. Returns true if it can be 
+               parsed without error. Returns false if an error was encountered.
+               Error diagnostics are stored in fErrorCode and fLineNumber.
+               @return true if the DOM was parsed successfully.
+       */
+       virtual bool decodeDOM(const SkDOM&, const SkDOMNode*);
+
+       /** Read in XML from a URI. Returns true if the file can be 
+               read without error. Returns false if an error was encountered.
+               Error diagnostics are stored in fErrorCode and fLineNumber.
+               @param uri The complete url path to be read (either ftp, http or https).
+               @return true if the XML was parsed successfully.
+       */
+       bool decodeURI(const char uri[]);
+
+       /** Pass a char event, usually a keyboard symbol, to the animator.
+               This triggers events of the form <event kind="keyChar" key="... />
+               @param ch  The character to match against <event> element "key" 
+                       attributes.
+               @return true if the event was dispatched successfully.
+       */
+       bool doCharEvent(SkUnichar ch);
+
+       /** Experimental:
+               Pass a mouse click event along with the mouse coordinates to 
+               the animator. This triggers events of the form <event kind="mouseDown" ... />
+               and other mouse events.
+               @param state The mouse state, described by SkView::Click::State : values are
+               down == 0, moved == 1, up == 2
+               @param x        The x-position of the mouse
+               @param y The y-position of the mouse
+               @return true if the event was dispatched successfully.
+       */
+       bool doClickEvent(int state, SkScalar x, SkScalar y);
+
+       /** Pass a meta-key event, such as an arrow , to the animator.
+               This triggers events of the form <event kind="keyPress" code="... />
+               @param code  The key to match against <event> element "code" 
+                       attributes.
+               @return true if the event was dispatched successfully.
+       */
+       bool doKeyEvent(SkKey code);
+    bool doKeyUpEvent(SkKey code);
+       
+       /** Send an event to the animator. The animator's clock is set 
+               relative to the current time.
+               @return true if the event was dispatched successfully.
+       */
+       bool doUserEvent(const SkEvent& evt);
+
+       /** The possible results from the draw function. 
+       */
+       enum DifferenceType {
+               kNotDifferent,
+               kDifferent,
+               kPartiallyDifferent
+       };
+       /** Draws one frame of the animation. The first call to draw always 
+               draws the initial frame of the animation. Subsequent calls draw 
+               the offset into the animation by 
+               subtracting the initial time from the current time.
+               @param canvas  The canvas to draw into.
+               @param paint     The paint to draw with.
+               @param time  The offset into the current animation.
+               @return kNotDifferent if there are no active animations; kDifferent if there are active animations; and
+               kPartiallyDifferent if the document contains an active <bounds> element that specifies a minimal 
+               redraw area.
+       */
+       DifferenceType draw(SkCanvas* canvas, SkPaint* paint, SkMSec time);
+
+       /** Draws one frame of the animation, using a new Paint each time.
+               The first call to draw always 
+               draws the initial frame of the animation. Subsequent calls draw 
+               the offset into the animation by 
+               subtracting the initial time from the current time.
+               @param canvas  The canvas to draw into.
+               @param time  The offset into the current animation.
+               @return kNotDifferent if there are no active animations; kDifferent if there are active animations; and
+               kPartiallyDifferent if the document contains an active <bounds> element that specifies a minimal 
+               redraw area.
+       */
+       DifferenceType draw(SkCanvas* canvas, SkMSec time);
+
+       /** Experimental:
+               Helper to choose whether to return a SkView::Click handler.
+               @param x ignored
+               @param y ignored
+               @return true if a mouseDown event handler is enabled.
+       */
+       bool findClickEvent(SkScalar x, SkScalar y); 
+
+
+       /** Get the nested animator associated with this element, if any.
+               Use this to access a movie's event sink, to send events to movies.
+               @param element the value returned by getElement
+               @return the internal animator.
+       */
+       const SkAnimator* getAnimator(const SkDisplayable* element) const;
+
+       /** Returns the scalar value of the specified element's attribute[index]
+               @param element the value returned by getElement
+               @param field the value returned by getField
+               @param index the array entry
+               @return the integer value to retrieve, or SK_NaN32 if unsuccessful
+       */
+       int32_t getArrayInt(const SkDisplayable* element, const SkMemberInfo* field, int index);
+
+       /** Returns the scalar value of the specified element's attribute[index]
+               @param elementID is the value of the id attribute in the XML of this element
+               @param fieldName specifies the name of the attribute  
+               @param index the array entry
+               @return the integer value to retrieve, or SK_NaN32 if unsuccessful
+       */
+       int32_t getArrayInt(const char* elementID, const char* fieldName, int index);
+
+       /** Returns the scalar value of the specified element's attribute[index]
+               @param element the value returned by getElement
+               @param field the value returned by getField
+               @param index the array entry
+               @return the scalar value to retrieve, or SK_ScalarNaN if unsuccessful
+       */
+       SkScalar getArrayScalar(const SkDisplayable* element, const SkMemberInfo* field, int index);
+
+       /** Returns the scalar value of the specified element's attribute[index]
+               @param elementID is the value of the id attribute in the XML of this element
+               @param fieldName specifies the name of the attribute  
+               @param index the array entry
+               @return the scalar value to retrieve, or SK_ScalarNaN if unsuccessful
+       */
+       SkScalar getArrayScalar(const char* elementID, const char* fieldName, int index);
+
+       /** Returns the string value of the specified element's attribute[index]
+               @param element is a value returned by getElement
+               @param field is a value returned by getField  
+               @param index the array entry
+               @return the string value to retrieve, or null if unsuccessful
+       */
+       const char* getArrayString(const SkDisplayable* element, const SkMemberInfo* field, int index);
+
+       /** Returns the string value of the specified element's attribute[index]
+               @param elementID is the value of the id attribute in the XML of this element
+               @param fieldName specifies the name of the attribute  
+               @param index the array entry
+               @return the string value to retrieve, or null if unsuccessful
+       */
+       const char* getArrayString(const char* elementID, const char* fieldName, int index);
+
+       /** Returns the XML element corresponding to the given ID.
+               @param elementID is the value of the id attribute in the XML of this element 
+               @return the element matching the ID, or nil if the element can't be found
+       */
+       const SkDisplayable* getElement(const char* elementID);
+
+       /** Returns the element type corresponding to the XML element.
+               The element type matches the element name; for instance, <line> returns kElement_LineType
+               @param element is a value returned by getElement  
+               @return element type, or 0 if the element can't be found
+       */
+       SkElementType getElementType(const SkDisplayable* element);
+
+       /** Returns the element type corresponding to the given ID.
+               @param elementID is the value of the id attribute in the XML of this element 
+               @return element type, or 0 if the element can't be found
+       */
+       SkElementType getElementType(const char* elementID);
+
+       /** Returns the XML field of the named attribute in the XML element.
+               @param element is a value returned by getElement
+               @param fieldName is the attribute to return  
+               @return the attribute matching the fieldName, or nil if the element can't be found
+       */
+       const SkMemberInfo* getField(const SkDisplayable* element, const char* fieldName);
+
+       /** Returns the XML field of the named attribute in the XML element matching the elementID.
+               @param elementID is the value of the id attribute in the XML of this element
+               @param fieldName is the attribute to return  
+               @return the attribute matching the fieldName, or nil if the element can't be found
+       */
+       const SkMemberInfo* getField(const char* elementID, const char* fieldName);
+
+       /** Returns the value type coresponding to the element's attribute.
+               The value type matches the XML schema: and may be kField_BooleanType, kField_ScalarType, etc.
+               @param field is a value returned by getField  
+               @return the attribute type, or 0 if the element can't be found
+       */
+       SkFieldType getFieldType(const SkMemberInfo* field);
+
+       /** Returns the value type coresponding to the element's attribute.
+               @param elementID is the value of the id attribute in the XML of this element
+               @param fieldName specifies the name of the attribute  
+               @return the attribute type, or 0 if the element can't be found
+       */
+       SkFieldType getFieldType(const char* elementID, const char* fieldName);
+
+       /** Returns the recommended animation interval. Returns zero if no
+               interval is specified.
+       */
+       SkMSec getInterval();
+
+       /** Returns the partial rectangle to invalidate after drawing. Call after draw() returns
+       kIsPartiallyDifferent to do a mimimal inval(). */
+       void getInvalBounds(SkRect* inval); 
+
+       /** Returns the details of any error encountered while parsing the XML. 
+       */
+       const SkXMLParserError* getParserError();
+       
+       /** Returns the details of any error encountered while parsing the XML as string. 
+       */
+       const char* getParserErrorString();
+       
+       /** Returns the scalar value of the specified element's attribute
+               @param element is a value returned by getElement
+               @param field is a value returned by getField  
+               @return the integer value to retrieve, or SK_NaN32 if not found
+       */
+       int32_t getInt(const SkDisplayable* element, const SkMemberInfo* field);
+
+       /** Returns the scalar value of the specified element's attribute
+               @param elementID is the value of the id attribute in the XML of this element
+               @param fieldName specifies the name of the attribute  
+               @return the integer value to retrieve, or SK_NaN32 if not found
+       */
+       int32_t getInt(const char* elementID, const char* fieldName);
+
+       /** Returns the scalar value of the specified element's attribute
+               @param element is a value returned by getElement
+               @param field is a value returned by getField  
+               @return the scalar value to retrieve, or SK_ScalarNaN if not found
+       */
+       SkScalar getScalar(const SkDisplayable* element, const SkMemberInfo* field);
+
+       /** Returns the scalar value of the specified element's attribute
+               @param elementID is the value of the id attribute in the XML of this element
+               @param fieldName specifies the name of the attribute  
+               @return the scalar value to retrieve, or SK_ScalarNaN if not found
+       */
+       SkScalar getScalar(const char* elementID, const char* fieldName);
+
+       /** Returns the string value of the specified element's attribute
+               @param element is a value returned by getElement
+               @param field is a value returned by getField  
+               @return the string value to retrieve, or null if not found
+       */
+       const char* getString(const SkDisplayable* element, const SkMemberInfo* field);
+
+       /** Returns the string value of the specified element's attribute
+               @param elementID is the value of the id attribute in the XML of this element
+               @param fieldName specifies the name of the attribute  
+               @return the string value to retrieve, or null if not found
+       */
+       const char* getString(const char* elementID, const char* fieldName);
+
+       /** Gets the file default directory of the URL base path set explicitly or by reading the last URL. */
+       const char* getURIBase();
+
+       /** Resets the animator to a newly created state with no animation data. */
+       void initialize();
+
+       /** Experimental. Resets any active animations so that the next time passed is treated as 
+               time zero. */
+       void reset();
+    
+    /** Sets the scalar value of the specified element's attribute
+               @param elementID is the value of the id attribute in the XML of this element
+               @param fieldName specifies the name of the attribute  
+               @param array is the c-style array of integers
+        @param count is the length of the array
+               @return true if the value was set successfully
+       */
+    bool setArrayInt(const char* elementID, const char* fieldName, const int* array, int count);
+    
+    /** Sets the scalar value of the specified element's attribute
+               @param elementID is the value of the id attribute in the XML of this element
+               @param fieldName specifies the name of the attribute  
+               @param array is the c-style array of strings
+        @param count is the length of the array
+               @return true if the value was set successfully
+       */
+    bool setArrayString(const char* elementID, const char* fieldName, const char** array, int count);
+    
+       /** Sets the scalar value of the specified element's attribute
+               @param elementID is the value of the id attribute in the XML of this element
+               @param fieldName specifies the name of the attribute  
+               @param data the integer value to set
+               @return true if the value was set successfully
+       */
+       bool setInt(const char* elementID, const char* fieldName, int32_t data);
+
+       /** Sets the scalar value of the specified element's attribute
+               @param elementID is the value of the id attribute in the XML of this element
+               @param fieldName specifies the name of the attribute  
+               @param data the scalar value to set
+               @return true if the value was set successfully
+       */
+       bool setScalar(const char* elementID, const char* fieldName, SkScalar data);
+
+       /** Sets the string value of the specified element's attribute
+               @param elementID is the value of the id attribute in the XML of this element
+               @param fieldName specifies the name of the attribute  
+               @param data the string value to set
+               @return true if the value was set successfully
+       */
+       bool setString(const char* elementID, const char* fieldName, const char* data);
+
+       /** Sets the file default directory of the URL base path 
+               @param path the directory path 
+       */
+       void setURIBase(const char* path);
+
+       typedef void* Handler;
+    // This guy needs to be exported to java, so don't make it virtual
+       void setHostHandler(Handler handler) {
+        this->onSetHostHandler(handler);
+    }
+
+       /** \class Timeline
+       Returns current time to animator. To return a custom timeline, create a child
+       class and override the getMSecs method.
+       */
+       class Timeline {
+       public:
+        virtual ~Timeline() {}
+
+               /** Returns the current time in milliseconds */
+               virtual SkMSec getMSecs() const = 0;
+       };
+
+       /** Sets a user class to return the current time to the animator. 
+               Optional; if not called, the system clock will be used by calling SkTime::GetMSecs instead.
+               @param callBack the time function
+       */
+       void setTimeline(const Timeline& );
+
+       static void Init(bool runUnitTests);
+       static void Term();
+       
+       /** The event sink events generated by the animation are posted to. 
+               Screenplay also posts an inval event to this event sink after processing an
+               event to force a redraw.
+               @param target the event sink id
+       */
+       void setHostEventSinkID(SkEventSinkID hostID);
+    SkEventSinkID getHostEventSinkID() const;
+       
+       // helper
+       void setHostEventSink(SkEventSink* sink) {
+               this->setHostEventSinkID(sink ? sink->getSinkID() : 0);
+       }
+       
+       virtual void setJavaOwner(Handler owner);
+       
+#ifdef SK_DEBUG
+       virtual void eventDone(const SkEvent& evt);
+       virtual bool isTrackingEvents();
+       static bool NoLeaks();
+#endif 
+    
+protected:
+    virtual void onSetHostHandler(Handler handler);
+    virtual void onEventPost(SkEvent*, SkEventSinkID);
+    virtual void onEventPostTime(SkEvent*, SkEventSinkID, SkMSec time);
+
+private:
+// helper functions for setters
+    bool setArray(SkDisplayable* element, const SkMemberInfo* field, SkTypedArray array);
+    bool setArray(const char* elementID, const char* fieldName, SkTypedArray array);
+       bool setInt(SkDisplayable* element, const SkMemberInfo* field, int32_t data);
+       bool setScalar(SkDisplayable* element, const SkMemberInfo* field, SkScalar data);
+       bool setString(SkDisplayable* element, const SkMemberInfo* field, const char* data);
+    
+       virtual bool onEvent(const SkEvent&);
+       SkAnimateMaker* fMaker;
+       friend class SkAnimateMaker;
+       friend class SkAnimatorScript;
+       friend class SkAnimatorScript2;
+       friend class SkApply;
+       friend class SkDisplayMovie;
+       friend class SkDisplayType;
+       friend class SkPost;
+       friend class SkXMLAnimatorWriter;
+};
+
+#endif
+
diff --git a/include/graphics/SkAnimatorView.h b/include/graphics/SkAnimatorView.h
new file mode 100644 (file)
index 0000000..2fa7657
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef SkAnimatorView_DEFINED
+#define SkAnimatorView_DEFINED
+
+#include "SkView.h"
+#include "SkAnimator.h"
+
+class SkAnimatorView : public SkView {
+public:
+                       SkAnimatorView();
+       virtual ~SkAnimatorView();
+
+       SkAnimator*     getAnimator() const { return fAnimator; }
+
+       bool    decodeFile(const char path[]);
+       bool    decodeMemory(const void* buffer, size_t size);
+       bool    decodeStream(SkStream* stream);
+
+protected:
+       // overrides
+       virtual bool onEvent(const SkEvent&);
+       virtual void onDraw(SkCanvas*);
+       virtual void onInflate(const SkDOM&, const SkDOM::Node*);
+
+private:
+       SkAnimator*     fAnimator;
+
+       typedef SkView INHERITED;
+};
+
+#endif
+
diff --git a/include/graphics/SkApplication.h b/include/graphics/SkApplication.h
new file mode 100644 (file)
index 0000000..fbeea47
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef SkApplication_DEFINED
+#define SkApplication_DEFINED
+
+class SkOSWindow;
+
+extern SkOSWindow* create_sk_window(void* hwnd);
+extern void application_init();
+extern void application_term();
+
+#endif // SkApplication_DEFINED
diff --git a/include/graphics/SkAvoidXfermode.h b/include/graphics/SkAvoidXfermode.h
new file mode 100644 (file)
index 0000000..574568b
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef SkAvoidXfermode_DEFINED
+#define SkAvoidXfermode_DEFINED
+
+#include "SkXfermode.h"
+
+/** \class SkAvoidXfermode
+
+    This xfermode will draw the src everywhere except on top of the specified
+    color.
+*/
+class SkAvoidXfermode : public SkXfermode {
+public:
+    /** This xfermode will draw the src everywhere except on top of the specified
+        color.
+        @param opColor  the color to avoid (or to target if reverse is true);
+        @param tolerance    How closely we compare a pixel to the opColor.
+                            0 - we only avoid on an exact match
+                            255 - maximum gradation (blending) based on how similar
+                            the pixel is to our opColor.
+        @param reverse      true means we target the opColor rather than avoid it.
+    */
+    SkAvoidXfermode(SkColor opColor, U8CPU tolerance, bool reverse);
+
+    virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count, const SkAlpha aa[]);
+    virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count, const SkAlpha aa[]);
+    virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count, const SkAlpha aa[]);
+
+private:
+    SkColor     fOpColor;
+    uint32_t    fDistMul;   // x.14
+    bool        fReverse;
+};
+
+#endif
diff --git a/include/graphics/SkBGViewArtist.h b/include/graphics/SkBGViewArtist.h
new file mode 100644 (file)
index 0000000..dd6e263
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef SkBGViewArtist_DEFINED
+#define SkBGViewArtist_DEFINED
+
+#include "SkView.h"
+#include "SkPaint.h"
+
+class SkBGViewArtist : public SkView::Artist {
+public:
+                       SkBGViewArtist(SkColor c = SK_ColorWHITE);
+       virtual ~SkBGViewArtist();
+
+       const SkPaint&  paint() const { return fPaint; }
+       SkPaint&                paint() { return fPaint; }
+
+protected:
+       // overrides
+       virtual void onDraw(SkView*, SkCanvas*);
+       virtual void onInflate(const SkDOM&, const SkDOM::Node*);
+
+private:
+       SkPaint fPaint;
+};
+
+#endif
+
diff --git a/include/graphics/SkBML_WXMLParser.h b/include/graphics/SkBML_WXMLParser.h
new file mode 100644 (file)
index 0000000..706b6b1
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef SkBML_WXMLParser_DEFINED
+#define SkBML_WXMLParser_DEFINED
+
+#include "SkString.h"
+#include "SkXMLParser.h"
+
+class SkStream;
+class SkWStream;
+
+class BML_WXMLParser : public SkXMLParser {
+public:
+       BML_WXMLParser(SkWStream& writer);
+       virtual ~BML_WXMLParser();
+       static void Write(SkStream& s, const char filename[]);
+  
+  /** @cond UNIT_TEST */
+  SkDEBUGCODE(static void UnitTest();)
+  /** @endcond */  
+private:
+       virtual bool onAddAttribute(const char name[], const char value[]);
+       virtual bool onEndElement(const char name[]);
+       virtual bool onStartElement(const char name[]);
+       BML_WXMLParser& operator=(const BML_WXMLParser& src);
+#ifdef SK_DEBUG
+       int     fElemsCount, fElemsReused;
+       int     fAttrsCount, fNamesReused, fValuesReused;
+#endif
+       SkWStream&      fWriter;
+       char*           fElems[256];
+       char*           fAttrNames[256];
+       char*           fAttrValues[256];
+
+       // important that these are U8, so we get automatic wrap-around
+       U8      fNextElem, fNextAttrName, fNextAttrValue;
+};
+
+#endif // SkBML_WXMLParser_DEFINED
+
diff --git a/include/graphics/SkBML_XMLParser.h b/include/graphics/SkBML_XMLParser.h
new file mode 100644 (file)
index 0000000..29e7f4e
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef SkBML_XMLParser_DEFINED
+#define SkBML_XMLParser_DEFINED
+
+class SkStream;
+class SkWStream;
+class SkXMLParser;
+class SkXMLWriter;
+
+class BML_XMLParser {
+public:
+       /**     Read the byte XML stream and write the decompressed XML.
+       */
+       static void Read(SkStream& s, SkXMLWriter& writer);
+       /**     Read the byte XML stream and write the decompressed XML into a writable stream.
+       */
+       static void Read(SkStream& s, SkWStream& output);
+       /**     Read the byte XML stream and write the decompressed XML into an XML parser.
+       */
+       static void Read(SkStream& s, SkXMLParser& output);
+};
+
+#endif // SkBML_XMLParser_DEFINED
+
diff --git a/include/graphics/SkBitmap.h b/include/graphics/SkBitmap.h
new file mode 100644 (file)
index 0000000..a7de542
--- /dev/null
@@ -0,0 +1,374 @@
+#ifndef SkBitmap_DEFINED
+#define SkBitmap_DEFINED
+
+#include "SkColor.h"
+#include "SkRefCnt.h"
+
+// Android - we need to run as an embedded product, not X11
+//#ifdef SK_BUILD_FOR_UNIX
+//#include <X11/Xlib.h>
+//#endif
+
+
+class SkColorTable;
+
+/**    \class SkBitmap
+
+       The SkBitmap class specifies a raster bitmap. A bitmap has an integer width
+       and height, and a format (config), and a pointer to the actual pixels.
+       Bitmaps can be drawn into a SkCanvas, but they are also used to specify the target
+       of a SkCanvas' drawing operations.
+*/
+class SkBitmap {
+public:
+       enum Config {
+               kNo_Config,         //!< bitmap has not been configured
+               kA1_Config,         //!< 1-bit per pixel, (0 is transparent, 1 is opaque)
+               kA8_Config,         //!< 8-bits per pixel, with only alpha specified (0 is transparent, 0xFF is opaque)
+               kIndex8_Config,     //!< 8-bits per pixel, using SkColorTable to specify the colors
+               kRGB_565_Config,        //!< 16-bits per pixel, (see SkColorPriv.h for packing)
+               kARGB_8888_Config,      //!< 32-bits per pixel, (see SkColorPriv.h for packing)
+
+               kConfigCount
+       };
+
+       /**     Default construct creates a bitmap with zero width and height, and no pixels.
+               Its config is set to kNo_Config.
+       */
+       SkBitmap();
+       /**     Constructor initializes the new bitmap by copying the src bitmap. All fields are copied,
+               but ownership of the pixels remains with the src bitmap.
+       */
+    //  This method is not exported to java.
+       SkBitmap(const SkBitmap& src);
+       /**     Destructor that, if getOwnsPixels() returns true, will delete the pixel's memory.
+       */
+       ~SkBitmap();
+
+       /**     Copies the src bitmap into this bitmap. Ownership of the src bitmap's pixels remains
+               with the src bitmap.
+       */
+       SkBitmap& operator=(const SkBitmap& src);
+       /**     Swap the fields of the two bitmaps. This routine is guaranteed to never fail or throw.
+       */
+    //  This method is not exported to java.
+       void    swap(SkBitmap& other);
+
+       /**     Return the config for the bitmap.
+       */
+       Config  getConfig() const { return (Config)fConfig; }
+       /**     Return the bitmap's width, in pixels.
+       */
+       unsigned width() const { return fWidth; }
+       /**     Return the bitmap's height, in pixels.
+       */
+       unsigned height() const { return fHeight; }
+       /**     Return the number of bytes between subsequent rows of the bitmap.
+       */
+       unsigned rowBytes() const { return fRowBytes; }
+       /**     Return the address of the pixels for this SkBitmap. This can be set either with
+               setPixels(), where the caller owns the buffer, or with allocPixels() or resizeAlloc(),
+               which marks the pixel memory to be owned by the SkBitmap (e.g. will be freed automatically
+               when the bitmap is destroyed).
+       */
+       void*   getPixels() const { return fPixels; }
+       /**     Return the byte size of the pixels, based on the height and rowBytes
+       */
+       size_t  getSize() const { return fHeight * fRowBytes; }
+    
+    /** Returns true if the bitmap is opaque (has no translucent/transparent pixels).
+    */
+    bool    isOpaque() const;
+    /** Specify if this bitmap's pixels are all opaque or not. Is only meaningful for configs
+        that support per-pixel alpha (RGB32, A1, A8).
+    */
+    void    setIsOpaque(bool);
+
+       /**     Reset the bitmap to its initial state (see default constructor). If getOwnsPixels() returned
+               true, then the memory for the pixels is freed.
+       */
+       void    reset();
+       /**     Set the bitmap's config and dimensions. If rowBytes is 0, then an appropriate value
+               is computed based on the bitmap's config and width. If getOwnsPixels() returned true,
+               then the pixel's memory is freed.
+       */
+       void    setConfig(Config, U16CPU width, U16CPU height, U16CPU rowBytes = 0);
+       /**     Use this to assign a new pixel address for an existing bitmap. If getOwnsPixels() returned
+               true, then the previous pixel's memory is freed. The new address is "owned" by the called,
+               and getOwnsPixels() will now return false. This method is not exported to java.
+       */
+       void    setPixels(void* p);
+       /**     If this is called, then the bitmap will dynamically allocate memory for its pixels
+               based on rowBytes and height. The SkBitmap will remember that it allocated
+               this, and will automatically free it as needed, thus getOwnsPixels() will now return true.
+       */
+       void    allocPixels();
+       /**     Realloc the memory for the pixels based on the specified width and height. This
+               keeps the old value for config, and computes a rowBytes based on the config and the width.
+               This is similar, but more efficient than calling setConfig() followed by allocPixels().
+       */
+// not implemented
+//     void    resizeAlloc(U16CPU width, U16CPU height);
+
+       /**     Returns true if the current pixels have been allocated via allocPixels()
+               or resizeAlloc(). This method is not exported to java.
+       */
+       bool    getOwnsPixels() const;
+       /**     Call this to explicitly change the ownership rule for the pixels. This may be called
+               after one bitmap is copied into another, to specify which bitmap should handle freeing
+               the memory. This method is not exported to java.
+       */
+       void    setOwnsPixels(bool ownsPixels);
+
+       /**     Get the bitmap's colortable object.
+       
+       Return the bitmap's colortable (if any). Does not affect the colortable's
+               reference count.
+       */
+       SkColorTable* getColorTable() const { return fColorTable; }
+       /**     Assign ctable to be the colortable for the bitmap, replacing any existing reference.
+               The reference count of ctable (if it is not nil) is incremented, and any existing
+               reference has its reference count decremented. NOTE: colortable's may be assigned
+               to any bitmap, but are only interpreted for kIndex8_Config bitmaps, where they
+               are required.
+               @return the ctable argument
+       */
+       SkColorTable* setColorTable(SkColorTable* ctable);
+
+       /**     Initialize the bitmap's pixels with the specified color+alpha, automatically converting into the correct format
+               for the bitmap's config. If the config is kRGB_565_Config, then the alpha value is ignored.
+               If the config is kA8_Config, then the r,g,b parameters are ignored.
+       */
+       void eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
+       /**     Initialize the bitmap's pixels with the specified color+alpha, automatically converting into the correct format
+               for the bitmap's config. If the config is kRGB_565_Config, then the alpha value is presumed
+               to be 0xFF. If the config is kA8_Config, then the r,g,b parameters are ignored and the
+               pixels are all set to 0xFF.
+       */
+       void eraseRGB(U8CPU r, U8CPU g, U8CPU b)
+       {
+               this->eraseARGB(0xFF, r, g, b);
+       }
+       /**     Initialize the bitmap's pixels with the specified color, automatically converting into the correct format
+               for the bitmap's config. If the config is kRGB_565_Config, then the color's alpha value is presumed
+               to be 0xFF. If the config is kA8_Config, then only the color's alpha value is used.
+       */
+       void eraseColor(SkColor c)
+       {
+               this->eraseARGB(SkColorGetA(c), SkColorGetR(c), SkColorGetG(c), SkColorGetB(c));
+       }
+
+       /**     Returns the address of the pixel specified by x,y.
+               Asserts that x,y are in range, and that the bitmap's config is either kARGB_8888_Config.
+       */
+    //  This method is not exported to java.
+       inline uint32_t* getAddr32(int x, int y) const;
+       /**     Returns the address of the pixel specified by x,y.
+               Asserts that x,y are in range, and that the bitmap's config is kRGB_565_Config.
+       */
+    //  This method is not exported to java.
+       inline uint16_t* getAddr16(int x, int y) const;
+       /**     Returns the address of the pixel specified by x,y.
+               Asserts that x,y are in range, and that the bitmap's config is either kA8_Config or kIndex8_Config.
+       */
+    //  This method is not exported to java.
+       inline uint8_t* getAddr8(int x, int y) const;
+       /**     Returns the color corresponding to the pixel specified by x,y.
+               Asserts that x,y are in range, and that the bitmap's config is kIndex8_Config.
+       */
+    //  This method is not exported to java.
+       inline SkPMColor getIndex8Color(int x, int y) const;
+       /**     Returns the address of the byte containing the pixel specified by x,y.
+               Asserts that x,y are in range, and that the bitmap's config is kA1_Config.
+       */
+    //  This method is not exported to java.
+       inline uint8_t* getAddr1(int x, int y) const;
+
+       //      OS-specific helpers
+#ifndef SK_USE_WXWIDGETS
+#ifdef SK_BUILD_FOR_WIN
+       /**     On Windows and PocketPC builds, this will draw the SkBitmap onto the
+               specified HDC
+       */
+       void    drawToHDC(HDC, int left, int top) const;
+#elif defined(SK_BUILD_FOR_MAC)
+       /**     On Mac OS X and Carbon builds, this will draw the SkBitmap onto the
+               specified WindowRef
+       */
+       void    drawToPort(WindowRef) const;
+#endif
+#endif
+
+       void            buildMipMap(bool forceRebuild);
+       unsigned        countMipLevels() const;
+
+private:
+       SkColorTable*   fColorTable;    // only meaningful for kIndex8
+
+#ifdef SK_SUPPORT_MIPMAP
+       struct MipLevel {
+               void*       fPixels;
+               uint16_t        fWidth, fHeight, fRowBytes;
+               uint8_t         fConfig, fShift;
+       };
+       enum {
+               kMaxMipLevels = 5
+       };
+       struct MipMap {
+               MipLevel        fLevel[kMaxMipLevels];
+       };
+       MipMap* fMipMap;
+#endif
+
+       enum Flags {
+               kWeOwnThePixels_Flag = 0x01,
+               kWeOwnTheMipMap_Flag = 0x02,
+        kImageIsOpaque_Flag  = 0x04
+       };
+
+       void*           fPixels;
+       uint16_t        fWidth, fHeight, fRowBytes;
+       uint8_t         fConfig;
+       uint8_t         fFlags;
+
+       const MipLevel* getMipLevel(unsigned level) const;
+
+       void freePixels();
+
+    friend class SkBitmapShader;
+};
+
+/**    \class SkColorTable
+
+       SkColorTable holds an array SkPMColors (premultiplied 32-bit colors) used by
+       8-bit bitmaps, where the bitmap bytes are interpreted as indices into the colortable.
+*/
+class SkColorTable : public SkRefCnt {
+public:
+       /**     Constructs an empty color table (zero colors).
+       */
+                       SkColorTable();
+       virtual ~SkColorTable();
+
+       enum Flags {
+               kColorsAreOpaque_Flag   = 0x01  //!< if set, all of the colors in the table are opaque (alpha==0xFF)
+       };
+       /**     Returns the flag bits for the color table. These can be changed with setFlags().
+       */
+       unsigned getFlags() const { return fFlags; }
+       /**     Set the flags for the color table. See the Flags enum for possible values.
+       */
+       void    setFlags(unsigned flags);
+
+       /**     Returns the number of colors in the table.
+       */
+       int     count() const { return fCount; }
+
+       /**     Returns the specified color from the table. In the debug build, this asserts that
+               the index is in range (0 <= index < count).
+       */
+       SkPMColor operator[](int index) const
+       {
+               SkASSERT(fColors != nil && (unsigned)index < fCount);
+               return fColors[index];
+       }
+
+       /**     Specify the number of colors in the color table. This does not initialize the colors
+               to any value, just allocates memory for them. To initialize the values, either call
+               setColors(array, count), or follow setCount(count) with a call to
+               lockColors()/{set the values}/unlockColors(true).
+       */
+       void    setColors(int count) { this->setColors(nil, count); }
+       void    setColors(const SkPMColor[], int count);
+
+       /**     Return the array of colors for reading and/or writing. This must be
+               balanced by a call to unlockColors(changed?), telling the colortable if
+               the colors were changed during the lock.
+       */
+       SkPMColor* lockColors()
+       {
+               SkDEBUGCODE(fColorLockCount += 1;)
+               return fColors;
+       }
+       /**     Balancing call to lockColors(). If the colors have been changed, pass true.
+       */
+       void unlockColors(bool changed)
+       {
+               SkASSERT(fColorLockCount != 0);
+               SkDEBUGCODE(fColorLockCount -= 1;)
+       }
+
+       /** Similar to lockColors(), lock16BitCache() returns the array of
+               RGB16 colors that mirror the 32bit colors. However, this function
+               will return nil if kColorsAreOpaque_Flag is not set.
+               Also, unlike lockColors(), the returned array here cannot be modified.
+       */
+       const uint16_t* lock16BitCache();
+       /** Balancing call to lock16BitCache().
+       */
+       void            unlock16BitCache()
+       {
+               SkASSERT(f16BitCacheLockCount > 0);
+               SkDEBUGCODE(f16BitCacheLockCount -= 1);
+       }
+
+private:
+       SkPMColor*      fColors;
+       uint16_t*       f16BitCache;
+       uint16_t        fCount;
+       uint8_t     fFlags;
+       SkDEBUGCODE(int fColorLockCount;)
+       SkDEBUGCODE(int f16BitCacheLockCount;)
+
+       void inval16BitCache();
+};
+
+//////////////////////////////////////////////////////////////////////////////////
+
+inline uint32_t* SkBitmap::getAddr32(int x, int y) const
+{
+       SkASSERT(fPixels);
+       SkASSERT(fConfig == kARGB_8888_Config);
+       SkASSERT((unsigned)x < fWidth && (unsigned)y < fHeight);
+
+       return (uint32_t*)((char*)fPixels + y * fRowBytes + (x << 2));
+}
+
+inline uint16_t* SkBitmap::getAddr16(int x, int y) const
+{
+       SkASSERT(fPixels);
+       SkASSERT(fConfig == kRGB_565_Config);
+       SkASSERT((unsigned)x < fWidth && (unsigned)y < fHeight);
+
+       return (uint16_t*)((char*)fPixels + y * fRowBytes + (x << 1));
+}
+
+inline uint8_t* SkBitmap::getAddr8(int x, int y) const
+{
+       SkASSERT(fPixels);
+       SkASSERT(fConfig == kA8_Config || fConfig == kIndex8_Config);
+       SkASSERT((unsigned)x < fWidth && (unsigned)y < fHeight);
+       return (uint8_t*)fPixels + y * fRowBytes + x;
+}
+
+inline SkPMColor SkBitmap::getIndex8Color(int x, int y) const
+{
+       SkASSERT(fPixels);
+       SkASSERT(fConfig == kIndex8_Config);
+       SkASSERT((unsigned)x < fWidth && (unsigned)y < fHeight);
+       SkASSERT(fColorTable);
+       return (*fColorTable)[*((const uint8_t*)fPixels + y * fRowBytes + x)];
+}
+
+// returns the address of the byte that contains the x coordinate
+inline uint8_t* SkBitmap::getAddr1(int x, int y) const
+{
+       SkASSERT(fPixels);
+       SkASSERT(fConfig == kA1_Config);
+       SkASSERT((unsigned)x < fWidth && (unsigned)y < fHeight);
+       return (uint8_t*)fPixels + y * fRowBytes + (x >> 3);
+}
+
+
+#endif
+
diff --git a/include/graphics/SkBitmapRef.h b/include/graphics/SkBitmapRef.h
new file mode 100644 (file)
index 0000000..ffecfb6
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef SkBitmapRef_DEFINED
+#define SkBitmapRef_DEFINED 
+
+#include "SkBitmap.h"
+
+class SkStream;
+
+/**    Helper class to manage a cache of decoded images from the file system
+*/
+class SkBitmapRef : public SkRefCnt {
+public:
+    /** Create a non-cached bitmap, trasfering ownership of pixels if needed
+     */
+    SkBitmapRef(const SkBitmap& src, bool transferOwnsPixels);
+    virtual ~SkBitmapRef();
+
+       const SkBitmap& bitmap();
+
+    static SkBitmapRef* create(const SkBitmap& src, bool transferOwnsPixels);
+    static SkBitmapRef* DecodeFile(const char file[], bool forceDecode);
+    static SkBitmapRef* DecodeMemory(const void* bytes, size_t len);
+    static SkBitmapRef* DecodeStream(SkStream* stream); 
+    
+    /**        Frees all cached images, asserting that all references have been removed
+       */
+    static void PurgeCacheAll();
+
+       /** frees one cached image, returning true, or returns false if none could be freed
+       */
+       static bool PurgeCacheOne();
+
+private:
+       struct Rec;
+       Rec*    fRec;
+
+       SkBitmapRef(Rec*);
+
+       friend class SkBitmapRef_Globals;
+};
+
+class SkAutoBitmapRef {
+public:
+       SkAutoBitmapRef(const char file[], bool forceDecode)
+       {
+               fRef = SkBitmapRef::DecodeFile(file, forceDecode);
+       }
+       ~SkAutoBitmapRef() { delete fRef; }
+
+       const SkBitmap* bitmap() const
+       {
+               return fRef ? &fRef->bitmap() : nil;
+       }
+private:
+       SkBitmapRef*    fRef;
+};
+
+
+#endif
diff --git a/include/graphics/SkBlurMaskFilter.h b/include/graphics/SkBlurMaskFilter.h
new file mode 100644 (file)
index 0000000..9bbba18
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef SkBlurMaskFilter_DEFINED
+#define SkBlurMaskFilter_DEFINED
+
+#include "SkMaskFilter.h"
+
+class SkBlurMaskFilter : public SkMaskFilter {
+public:
+       enum BlurStyle {
+               kNormal_BlurStyle,      //!< fuzzy inside and outside
+               kSolid_BlurStyle,       //!< solid inside, fuzzy outside
+               kOuter_BlurStyle,       //!< nothing inside, fuzzy outside
+               kInner_BlurStyle,       //!< fuzzy inside, nothing outside
+
+               kBlurStyleCount
+       };
+
+    /** Create a blur maskfilter.
+        @param radius   The radius to extend the blur from the original mask. Must be > 0.
+        @param style    The BlurStyle to use
+        @return The new blur maskfilter
+    */
+    static SkMaskFilter* Create(SkScalar radius, BlurStyle style);
+
+    /** Create an emboss maskfilter
+        @param direction    array of 3 scalars [x, y, z] specifying the direction of the light source
+        @param ambient      0...1 amount of ambient light
+        @param specular     coefficient for specular highlights (e.g. 8)
+        @param blurRadius   amount to blur before applying lighting (e.g. 3)
+        @return the emboss maskfilter
+    */
+    static SkMaskFilter* CreateEmboss(  const SkScalar direction[3],
+                                        SkScalar ambient, SkScalar specular,
+                                        SkScalar blurRadius);
+};
+
+#endif
+
diff --git a/include/graphics/SkBorderView.h b/include/graphics/SkBorderView.h
new file mode 100644 (file)
index 0000000..307a91d
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef SkBorderView_DEFINED
+#define SkBorderView_DEFINED
+
+#include "SkView.h"
+#include "SkWidgetViews.h"
+#include "SkAnimator.h"
+
+class SkBorderView : public SkWidgetView {
+public:
+       SkBorderView();
+       ~SkBorderView();
+       void setSkin(const char skin[]);
+       SkScalar getLeft() const { return fLeft; }
+       SkScalar getRight() const { return fRight; }
+       SkScalar getTop() const { return fTop; }
+       SkScalar getBottom() const { return fBottom; }
+protected:
+       //overrides
+       virtual void onInflate(const SkDOM& dom,  const SkDOM::Node* node);
+       virtual void onSizeChange();
+       virtual void onDraw(SkCanvas* canvas);
+       virtual bool onEvent(const SkEvent& evt);
+private:
+       SkAnimator fAnim;
+       SkScalar fLeft, fRight, fTop, fBottom;  //margin on each side
+       SkRect fMargin;
+
+       typedef SkWidgetView INHERITED;
+};
+
+#endif
\ No newline at end of file
diff --git a/include/graphics/SkBounder.h b/include/graphics/SkBounder.h
new file mode 100644 (file)
index 0000000..8bf9dfa
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef SkBounder_DEFINED
+#define SkBounder_DEFINED
+
+#include "SkTypes.h"
+#include "SkRefCnt.h"
+
+struct SkRect16;
+struct SkPoint;
+struct SkRect;
+class SkPaint;
+class SkPath;
+class SkRegion;
+
+/**    \class SkBounder
+
+       Base class for intercepting the device bounds of shapes before they are drawn.
+       Install a subclass of this in your canvas.
+*/
+class SkBounder : public SkRefCnt {
+public:
+       bool doIRect(const SkRect16&, const SkRegion&);
+       bool doHairline(const SkPoint&, const SkPoint&, const SkPaint&, const SkRegion&);
+       bool doRect(const SkRect&, const SkPaint&, const SkRegion&);
+       bool doPath(const SkPath&, const SkPaint&, const SkRegion&, bool doFill);
+
+protected:
+       /**     Override in your subclass. This is called with the device bounds of an
+               object (text, geometry, image) just before it is drawn. If your method
+               returns false, the drawing for that shape is aborted. If your method
+               returns true, drawing continues. The bounds your method receives have already
+               been transformed in to device coordinates, and clipped to the current clip.
+       */
+       virtual bool onIRect(const SkRect16&) = 0;
+
+       /**     Called after each shape has been drawn. The default implementation does
+               nothing, but your override could use this notification to signal itself
+               that the offscreen being rendered into needs to be updated to the screen.
+       */
+       virtual void commit();
+
+       friend class SkAutoBounderCommit;
+};
+
+#endif
+
diff --git a/include/graphics/SkCamera.h b/include/graphics/SkCamera.h
new file mode 100644 (file)
index 0000000..d39fa89
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef SkCamera_DEFINED
+#define SkCamera_DEFINED
+
+#include "SkMatrix.h"
+#include "Sk64.h"
+
+#ifdef SK_SCALAR_IS_FIXED
+       typedef SkFract SkUnitScalar;
+       #define SK_UnitScalar1                  SK_Fract1
+       #define SkUnitScalarMul(a, b)   SkFractMul(a, b)
+       #define SkUnitScalarDiv(a, b)   SkFractDiv(a, b)
+#else
+       typedef float   SkUnitScalar;
+       #define SK_UnitScalar1                  SK_Scalar1
+       #define SkUnitScalarMul(a, b)   SkScalarMul(a, b)
+       #define SkUnitScalarDiv(a, b)   SkScalarDiv(a, b)
+#endif
+
+//     Taken from Rob Johnson's most excellent QuickDraw GX library
+
+struct SkUnit3D {
+       SkUnitScalar    fX, fY, fZ;
+
+       void set(SkUnitScalar x, SkUnitScalar y, SkUnitScalar z)
+       {
+               fX = x; fY = y; fZ = z;
+       }
+       static SkUnitScalar Dot(const SkUnit3D&, const SkUnit3D&);
+       static void Cross(const SkUnit3D&, const SkUnit3D&, SkUnit3D* cross);
+};
+
+struct SkPoint3D {
+       SkScalar        fX, fY, fZ;
+
+       void set(SkScalar x, SkScalar y, SkScalar z)
+       {
+               fX = x; fY = y; fZ = z;
+       }
+       SkScalar        normalize(SkUnit3D*) const;
+};
+
+class SkPatch3D {
+public:
+       SkPatch3D();
+
+       void    reset();
+       void    rotate(SkScalar radX, SkScalar radY, SkScalar radZ);
+       void    rotateDegrees(SkScalar degX, SkScalar degY, SkScalar degZ)
+       {
+               this->rotate(SkDegreesToRadians(degX),
+                                        SkDegreesToRadians(degY),
+                                        SkDegreesToRadians(degZ));
+       }
+
+       // dot a unit vector with the patch's normal
+       SkScalar        dotWith(SkScalar dx, SkScalar dy, SkScalar dz) const;
+
+       SkPoint3D       fU, fV, fOrigin;
+private:
+       friend class SkCamera3D;
+};
+
+class SkCamera3D {
+public:
+       SkCamera3D();
+
+       void update();
+       void computeMatrix(const SkPatch3D&, SkMatrix* matrix) const;
+
+       SkPoint3D       fLocation;
+       SkPoint3D       fAxis;
+       SkPoint3D       fZenith;
+       SkPoint3D       fObserver;
+
+private:
+       SkMatrix        fOrientation;
+};
+
+#endif
+
diff --git a/include/graphics/SkCanvas.h b/include/graphics/SkCanvas.h
new file mode 100644 (file)
index 0000000..11dfb99
--- /dev/null
@@ -0,0 +1,470 @@
+#ifndef SkCanvas_DEFINED
+#define SkCanvas_DEFINED
+
+#include "SkBitmap.h"
+#include "SkDeque.h"
+#include "SkPaint.h"
+#include "SkPorterDuff.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+
+class SkBounder;
+
+/**    \class SkCanvas
+
+       The SkCanvas class holds the "draw" calls. To draw something, you need
+       4 basic components: A SkBitmap to hold the pixels, a SkCanvas to host
+       the draw calls (writing into the bitmap), a drawing primitive (e.g. SkRect, SkPath,
+       text, SkBitmap), and a paint (to describe the colors and styles for the drawing).
+*/
+class SkCanvas {
+public:
+    /** Construct an empty canvas. Use setPixels() to specify a bitmap to draw into.
+    */
+       SkCanvas();
+    /** Construct a canvas with the specified bitmap to draw into.
+        @param bitmap   Specifies a bitmap for the canvas to draw into. Its contents are copied to the canvas.
+    */
+       SkCanvas(const SkBitmap& bitmap);
+       ~SkCanvas();
+
+       /**     Return a copy of the bitmap that the canvas draws into. This does not make a copy
+               of the bitmap's pixels, but just returns the pixel's address.
+        @param bitmap   The bitmap, allocated by the caller, that receives a copy of the canvas' bitmap
+                        (the one specified in the setPixels() call, or in the constructor).
+       */
+       void    getPixels(SkBitmap* bitmap) const;
+       /**     Specify a bitmap for the canvas to draw into. This routine makes a copy of the bitmap,
+               but does not copy the actual pixels. Ownership of the bitmap's pixels stays with the caller's
+               bitmap.
+        @param bitmap   Specifies a new bitmap for the canvas to draw into. Its contents are copied to the canvas.
+       */
+       void    setPixels(const SkBitmap& bitmap);
+    
+    /** Return true if the bitmap that the current layer draws into is always opaque
+        (i.e. does not support per-pixel alpha). e.g. kARGB_8888_Config returns false,
+        kARGB_565_Config returns true.
+        @return true if the bitmap that the current layer draws into is always opaque
+    */
+    bool    isBitmapOpaque() const;
+    
+    /** Return the width of the bitmap that the current layer draws into
+        @return the width of the bitmap that the current layer draws into
+    */
+    int getBitmapWidth() const { return this->getCurrBitmap().width(); }
+    /** Return the height of the bitmap that the current layer draws into
+        @return the height of the bitmap that the current layer draws into
+    */
+    int getBitmapHeight() const { return this->getCurrBitmap().height(); }
+
+       /**     This call saves the current matrix and clip information, and pushes a copy onto a
+               private stack. Subsequent calls to translate,scale,rotate,skew,concat or clipRect,clipPath
+               all operate on this copy. When the balancing call to restore() is made, this copy is deleted
+               and the previous matrix/clip state is restored.
+        @return The value to pass to restoreToCount() to balance this save()
+       */
+       int     save();
+       /**     This behaves the same as save(), but in addition it allocates an offscreen bitmap.
+        All drawing calls are directed there, and only when the balancing call to restore() is made
+        is that offscreen transfered to the canvas (or the previous layer).
+        Subsequent calls to translate,scale,rotate,skew,concat or clipRect,clipPath
+               all operate on this copy. When the balancing call to restore() is made, this copy is deleted
+               and the previous matrix/clip state is restored.
+        @param bounds The maximum size the offscreen bitmap needs to be (in local coordinates)
+        @param paint This is copied, and is applied to the offscreen when restore() is called.
+        @return The value to pass to restoreToCount() to balance this save()
+       */
+       int     saveLayer(const SkRect& bounds, const SkPaint& paint);
+       /**     This call balances a previous call to save(), and is used to remove all modifications to
+               the matrix/clip state since the last save call. It is an error to call restore() more times
+               than save() was called.
+       */
+       void    restore();
+       /**     Returns the number of matrix/clip states on the SkCanvas' private stack. This will equal
+               # save() calls - # restore() calls.
+       */
+       int             getSaveCount() const;
+       /**     Efficient way to pop any calls to save() that happened after the save count reached saveCount.
+        It is an error for saveCount to be less than getSaveCount()
+        @param saveCount    The number of save() levels to restore from
+       */
+       void    restoreToCount(int saveCount);
+
+       /**     Preconcat the current matrix with the specified translation
+               @param dx       The distance to translate in X
+               @param dy       The distance to translate in Y
+               returns true if the operation succeeded (e.g. did not overflow)
+       */
+       bool    translate(SkScalar dx, SkScalar dy);
+       /**     Preconcat the current matrix with the specified scale and pivot point.
+               The pivot is the point that will remain unchanged after the scale is applied.
+               @param sx       The amount to scale in X, about the pivot point (px,py)
+               @param sy       The amount to scale in Y, about the pivot point (px,py)
+               @param px       The pivot's X coordinate
+               @param py       The pivot's Y coordinate
+               returns true if the operation succeeded (e.g. did not overflow)
+       */
+       bool    scale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
+       /**     Preconcat the current matrix with the specified rotation and pivot point.
+               The pivot is the point that will remain unchanged after the rotation is applied.
+               @param degrees  The amount to rotate, in degrees
+               @param px       The pivot's X coordinate
+               @param py       The pivot's Y coordinate
+               returns true if the operation succeeded (e.g. did not overflow)
+       */
+       bool    rotate(SkScalar degrees, SkScalar px, SkScalar py);
+       /**     Preconcat the current matrix with the specified skew and pivot point.
+               The pivot is the point that will remain unchanged after the skew is applied.
+               @param sx       The amount to skew in X, about the pivot point (px,py)
+               @param sy       The amount to skew in Y, about the pivot point (px,py)
+               @param px       The pivot's X coordinate
+               @param py       The pivot's Y coordinate
+               returns true if the operation succeeded (e.g. did not overflow)
+       */
+       bool    skew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
+       /**     Preconcat the current matrix with the specified matrix.
+        @param matrix   The matrix to preconcatenate with the current matrix
+        @return true if the operation succeeded (e.g. did not overflow)
+       */
+       bool    concat(const SkMatrix& matrix);
+
+       /**     Intersect the current clip with the specified rectangle.
+        @param rect The rect to intersect with the current clip
+    */
+       void    clipRect(const SkRect& rect);
+       /**     Intersect the current clip with the specified rectangle.
+        @param left     The left side of the rectangle to intersect with the current clip
+        @param top      The top side of the rectangle to intersect with the current clip
+        @param right    The right side of the rectangle to intersect with the current clip
+        @param bottom   The bottom side of the rectangle to intersect with the current clip
+    */
+       void    clipRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
+       /**     Intersect the current clip with the specified path.
+        @param path The path to intersect with the current clip
+       */
+       void    clipPath(const SkPath& path);
+       /**     Intersect the current clip with the specified region. Note that unlike clipRect()
+        and clipPath() which transform their arguments by the current matrix, clipDeviceRgn()
+        assumes its argument is already in the coordinate system of the current layer's bitmap,
+        and so not transformation is performed.
+        @param deviceRgn    The region to intersect with the current clip
+    */
+       void    clipDeviceRgn(const SkRegion& deviceRgn);
+
+       /**     Return true if the specified rectangle, after being transformed by the current
+               matrix, would lie completely outside of the current clip. Call this to check
+               if an area you intend to draw into is clipped out (and therefore you can skip
+               making the draw calls).
+        @param rect the rect to compare with the current clip
+        @param antialiased  true if the rect should be considered antialiased, since that means it may
+                            affect a larger area (more pixels) than non-antialiased.
+        @return true if the rect (transformed by the canvas' matrix) does not intersect with the canvas' clip
+       */
+       bool    quickReject(const SkRect& rect, bool antialiased = false) const;
+       /**     Return true if the specified path, after being transformed by the current
+               matrix, would lie completely outside of the current clip. Call this to check
+               if an area you intend to draw into is clipped out (and therefore you can skip
+               making the draw calls).
+        Note, for speed it may return false even if the path itself might not intersect
+        the clip (i.e. the bounds of the path intersects, but the path doesnot).
+        @param path The path to compare with the current clip
+        @param antialiased  true if the path should be considered antialiased, since that means it may
+                            affect a larger area (more pixels) than non-antialiased.
+        @return true if the path (transformed by the canvas' matrix) does not intersect with the canvas' clip
+       */
+       bool    quickReject(const SkPath& path, bool antialiased = false) const;
+       /**     Return true if the specified rectangle, after being transformed by the current
+               matrix, would lie completely outside of the current clip. Call this to check
+               if an area you intend to draw into is clipped out (and therefore you can skip
+               making the draw calls).
+        @param left     The left side of the rectangle to compare with the current clip
+        @param top      The top side of the rectangle to compare with the current clip
+        @param right    The right side of the rectangle to compare with the current clip
+        @param bottom   The bottom side of the rectangle to compare with the current clip
+        @param antialiased  true if the rect should be considered antialiased, since that means it may
+                            affect a larger area (more pixels) than non-antialiased.
+        @return true if the rect (transformed by the canvas' matrix) does not intersect with the canvas' clip
+       */
+       bool    quickReject(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, bool antialiased = false) const
+    {
+        SkRect r;
+        r.set(left, top, right, bottom);
+        return this->quickReject(r, antialiased);
+    }
+
+       /**     Fill the entire canvas' bitmap (restricted to the current clip) with the
+               specified RGB color, using srcover porterduff mode.
+        @param r    the red component (0..255) of the color used to draw onto the canvas
+        @param g    the green component (0..255) of the color used to draw onto the canvas
+        @param b    the blue component (0..255) of the color used to draw onto the canvas
+       */
+       void    drawRGB(U8CPU r, U8CPU g, U8CPU b);
+       /**     Fill the entire canvas' bitmap (restricted to the current clip) with the
+               specified ARGB color, using srcover porterduff mode.
+        @param a    the alpha component (0..255) of the color used to draw onto the canvas
+        @param r    the red component (0..255) of the color used to draw onto the canvas
+        @param g    the green component (0..255) of the color used to draw onto the canvas
+        @param b    the blue component (0..255) of the color used to draw onto the canvas
+       */
+       void    drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
+       /**     Fill the entire canvas' bitmap (restricted to the current clip) with the
+               specified color, using srcover porterduff mode.
+        @param color    the color to draw onto the canvas
+       */
+       void    drawColor(SkColor color)
+    {
+        this->drawColor(color, SkPorterDuff::kSrcOver_Mode);
+    }
+       /**     Fill the entire canvas' bitmap (restricted to the current clip) with the
+               specified color and porter-duff xfermode.
+        @param color    the color to draw with
+        @param mode     the porter-duff mode to apply to the color
+       */
+       void    drawColor(SkColor color, SkPorterDuff::Mode mode);
+
+       /**     Fill the entire canvas' bitmap (restricted to the current clip) with the
+               specified paint. This is equivalent (but faster) to drawing an infinitely
+               large rectangle with the specified paint.
+        @param paint    The paint used to draw onto the canvas
+       */
+       void    drawPaint(const SkPaint& paint);
+       /**     Draw a line segment with the specified start and stop points, using the specified
+               paint. NOTE: since a line is always "framed", the Style is ignored in
+               the paint.
+        @param start    The start point of the line
+        @param stop     The stop point of the line
+        @param paint    The paint used to draw the line
+       */
+       void    drawLine(const SkPoint& start, const SkPoint& stop, const SkPaint& paint);
+       /**     Draw a line segment with the specified start and stop x,y coordinates, using the specified
+               paint. NOTE: since a line is always "framed", the Style is ignored in
+               the paint.
+        @param startX   The x-coordinate of the start point of the line
+        @param startY   The y-coordinate of the start point of the line
+        @param endX     The x-coordinate of the end point of the line
+        @param endY     The y-coordinate of the end point of the line
+        @param paint    The paint used to draw the line
+       */
+       void    drawLine(SkScalar startX, SkScalar startY, SkScalar stopX, SkScalar stopY, const SkPaint& paint);
+       /**     Draw the specified SkRect using the specified paint. The rectangle will be filled
+               or framed based on the Style in the paint.
+        @param rect     The rect to be drawn
+        @param paint    The paint used to draw the rect
+       */
+       void    drawRect(const SkRect& rect, const SkPaint& paint);
+       /**     Draw the specified SkRect using the specified paint. The rectangle will be filled
+               or framed based on the Style in the paint.
+        @param left     The left side of the rectangle to be drawn
+        @param top      The top side of the rectangle to be drawn
+        @param right    The right side of the rectangle to be drawn
+        @param bottom   The bottom side of the rectangle to be drawn
+        @param paint    The paint used to draw the rect
+       */
+       void    drawRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, const SkPaint& paint);
+       /**     Draw the specified oval using the specified paint. The oval will be filled
+               or framed based on the Style in the paint.
+        @param oval     The rectangle bounds of the oval to be drawn
+        @param paint    The paint used to draw the oval
+       */
+       void    drawOval(const SkRect& oval, const SkPaint&);
+       /**     Draw the specified circle using the specified paint. If radius is <= 0, then
+               nothing will be drawn. The circle will be filled
+               or framed based on the Style in the paint.
+        @param cx       The x-coordinate of the center of the cirle to be drawn
+        @param cy       The y-coordinate of the center of the cirle to be drawn
+        @param radius   The radius of the cirle to be drawn
+        @param paint    The paint used to draw the circle
+       */
+       void    drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint);
+       /**     Draw the specified round-rect using the specified paint. The round-rect will be filled
+               or framed based on the Style in the paint.
+        @param rect     The rectangular bounds of the roundRect to be drawn
+               @param rx       The x-radius of the oval used to round the corners
+               @param ry       The y-radius of the oval used to round the corners
+        @param paint    The paint used to draw the roundRect
+       */
+       void    drawRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, const SkPaint& paint);
+       /**     Draw the specified path using the specified paint. The path will be filled
+               or framed based on the Style in the paint.
+        @param path     The path to be drawn
+        @param paint    The paint used to draw the path
+       */
+       void    drawPath(const SkPath& path, const SkPaint& paint);
+       /**     Draw the specified bitmap, with its top/left corner at (x,y), using the specified paint,
+        transformed by the current matrix.
+        @param bitmap   The bitmap to be drawn
+        @param left     The position of the left side of the bitmap being drawn
+        @param top      The position of the top side of the bitmap being drawn
+        @param paint    The paint used to draw the bitmap
+       */
+       void    drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint& paint);
+       /**     Draw the specified bitmap, with its top/left corner at (x,y), transformed
+        by the current matrix. Since no paint is specified, the bitmap is drawn with no overriding
+        alpha or colorfilter, and in srcover porterduff mode.
+        @param bitmap   The bitmap to be drawn
+        @param left     The position of the left side of the bitmap being drawn
+        @param top      The position of the top side of the bitmap being drawn
+       */
+       void    drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top);
+       /**     Draw the specified bitmap, with its top/left corner at (x,y), NOT transformed
+        by the current matrix. This method is not exported to java.
+        @param bitmap   The bitmap to be drawn
+        @param left     The position of the left side of the bitmap being drawn
+        @param top      The position of the top side of the bitmap being drawn
+        @param paint    The paint used to draw the bitmap
+       */
+    void    drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint& paint);
+       /**     Draw the utf8-text, with origin at (x,y), using the specified paint. The origin is interpreted
+               based on the Align setting in the paint.
+               @param text     The UTF8 text to be drawn
+               @param byteLength       The number of bytes to read from the text parameter
+        @param x        The x-coordinate of the origin of the text being drawn
+        @param y        The y-coordinate of the origin of the text being drawn
+               @param paint    The paint used for the text (e.g. color, size, style)
+       */
+       void    drawText(const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint);
+       /**     Draw the utf8-text, with origin at (x,y), using the specified paint. The origin is interpreted
+               based on the Align setting in the paint.
+               @param text     The UTF16 text to be drawn
+               @param numberOf16BitValues      The number of 16bit values to read from the text parameter
+        @param x        The x-coordinate of the origin of the text being drawn
+        @param y        The y-coordinate of the origin of the text being drawn
+               @param paint    The paint used for the text (e.g. color, size, style)
+       */
+       void    drawText16(const uint16_t text[], size_t numberOf16BitValues, SkScalar x, SkScalar y, const SkPaint& paint);
+       /**     Draw the utf8-text, with origin at (x,y), using the specified paint. The origin is interpreted
+               based on the Align setting in the paint.
+               @param text     The UTF8 text to be drawn
+               @param byteLength       The number of bytes to read from the text parameter
+        @param pos      Array of positions, used to position each character
+               @param paint    The paint used for the text (e.g. color, size, style)
+       */
+       void    drawPosText(const char text[], size_t byteLength, const SkPoint pos[], const SkPaint& paint);
+       /**     Draw the utf8-text, with origin at (x,y), using the specified paint. The origin is interpreted
+               based on the Align setting in the paint.
+               @param text     The UTF16 text to be drawn
+               @param numberOf16BitValues      The number of 16bit values to read from the text parameter
+        @param pos      Array of positions, used to position each character
+               @param paint    The paint used for the text (e.g. color, size, style)
+       */
+       void    drawPosText16(const uint16_t text[], size_t numberOf16BitValues, const SkPoint pos[], const SkPaint& paint);
+       /**     Draw the utf8-text, with origin at (x,y), using the specified paint, along the specified path.
+               The paint's Align setting determins where along the path to start the text.
+               @param text     The UTF8 text to be drawn
+               @param byteLength       The number of bytes to read from the text parameter
+               @param path         The path the text should follow for its baseline
+               @param distance     The distance along the path to add to the text's starting position
+               @param paint        The paint used for the text (e.g. color, size, style)
+       */
+       void    drawTextOnPath(const char text[], size_t byteLength, const SkPath& path, SkScalar distance, const SkPaint& paint);
+       /**     Draw the utf8-text, with origin at (x,y), using the specified paint, along the specified path.
+               The paint's Align setting determins where along the path to start the text.
+               @param text     The UTF16 text to be drawn
+               @param numberOf16BitValues      The number of 16bit values to read from the text parameter
+               @param path     The path the text should follow for its baseline
+               @param offset   The distance along the path to add to the text's starting position
+               @param paint    The paint used for the text (e.g. color, size, style)
+       */
+       void    drawText16OnPath(const uint16_t text[], size_t numberOf16BitValues, const SkPath& path, SkScalar distance, const SkPaint& paint);
+
+       /**     Return the current set mask, used to temporarily modify the paint's flags
+               when something is being drawin.
+        This method is not exported to java.
+       */
+       uint32_t        getPaintSetBits() const;
+       /**     Return the current clear mask, used to temporarily modify the paint's flags
+               when something is being drawin.
+        This method is not exported to java.
+       */
+       uint32_t        getPaintClearBits() const;
+       /**     Set the current set and clear masks, used to temporarily modify the paint's flags
+               when something is being drawin. The setBits are applied before the clrBits.
+        This method is not exported to java.
+               @param setBits  A mask of bits to be OR'd into the paint's flag bits
+               @param clrBits  A mask of bits to be cleared from the paint's flag bits
+       */
+       void    setPaintSetClearBits(uint32_t setBits, uint32_t clrBits);
+       /**     Helper for getPaintSetClearBits/setPaintSetClearBits. The parameters are OR'd into
+               the current values, rather than replacing them as with setPaintSetClearBits.
+        This method is not exported to java.
+        @param setBits  A mask of bits to be OR'd with the existing setBits on the canvas
+        @param clearBits  A mask of bits to be OR'd with the existing clearBits on the canvas
+       */
+       void    orPaintSetClearBits(uint32_t setBits, uint32_t clearBits);
+
+       /**     Get the current bounder object. 
+               <p />
+         The bounder's reference count is not affected.
+               @return the canva's bounder (or NULL).
+       */
+       SkBounder*      getBounder() const { return fBounder; }
+       /**     Set a new bounder (or NULL).
+               <p />
+               Pass NULL to clear any previous bounder.
+               As a convenience, the parameter passed is also returned.
+               If a previous bounder exists, its reference count is decremented.
+               If bounder is not NULL, its reference count is incremented.
+               @param bounder the new bounder (or NULL) to be installed in the canvas
+               @return the set bounder object
+       */
+       SkBounder*      setBounder(SkBounder*);
+
+    /** Return a reference to the bitmap that the current layer draws into.
+        This method is not exported to java.
+        @return The a reference to the bitmap that the current layer draws into.
+    */
+    const SkBitmap& getCurrBitmap() const;
+    /** Return the MapPtProc for the current matrix on the canvas.
+        This method is not exported to java.
+        @return the MapPtProc for the current matrix on the canvas.
+    */
+    SkMatrix::MapPtProc getCurrMapPtProc() const;
+    /** Return the current matrix on the canvas.
+        This method is not exported to java.
+        @return The current matrix on the canvas.
+    */
+    const SkMatrix& getTotalMatrix() const;
+    /** Return the current device clip (concatenation of all clip calls).
+        This method is not exported to java.
+        @return the current device clip (concatenation of all clip calls).
+    */
+    const SkRegion& getTotalClip() const;
+
+private:
+    struct MCRec;
+
+    SkDeque     fMCStack;
+    MCRec*      fMCRec;             // points to top of stack
+    uint32_t    fMCRecStorage[32];  // the first N recs that can fit here mean we won't call malloc
+
+       SkBitmap        fBitmap;
+       SkBounder*      fBounder;
+
+       friend class SkDraw;
+};
+
+/**    Stack helper class to automatically call restoreToCount() on the canvas
+       when this object goes out of scope. Use this to guarantee that the canvas
+       is restored to a known state.
+*/
+class SkAutoCanvasRestore {
+public:
+       SkAutoCanvasRestore(SkCanvas* canvas, bool doSave) : fCanvas(canvas)
+       {
+               SkASSERT(canvas);
+               fSaveCount = canvas->getSaveCount();
+               if (doSave)
+                       canvas->save();
+       }
+       ~SkAutoCanvasRestore()
+       {
+               fCanvas->restoreToCount(fSaveCount);
+       }
+
+private:
+       SkCanvas*       fCanvas;
+       int                     fSaveCount;
+};
+
+#endif
+
diff --git a/include/graphics/SkColor.h b/include/graphics/SkColor.h
new file mode 100644 (file)
index 0000000..6df71ea
--- /dev/null
@@ -0,0 +1,126 @@
+#ifndef SkColor_DEFINED
+#define SkColor_DEFINED
+
+#include "SkScalar.h"
+
+/**    \file SkColor.h
+
+       Types and macros for colors
+*/
+
+/**    8-bit type for an alpha value. 0xFF is 100% opaque, 0x00 is 100% transparent.
+*/
+typedef uint8_t        SkAlpha;
+/** 32 bit ARGB color value, not premultiplied. The color components are always in
+       a known order. This is different from SkPMColor, which has its bytes in a configuration
+       dependent order, to match the format of kARGB32 bitmaps. SkColor is the type used to
+       specify colors in SkPaint and in gradients.
+*/
+typedef uint32_t SkColor;
+
+/**    Return a SkColor value from 8 bit component values
+*/
+static inline SkColor SkColorSetARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
+{
+       SkASSERT(a <= 255 && r <= 255 && g <= 255 && b <= 255);
+
+       return (a << 24) | (r << 16) | (g << 8) | (b << 0);
+}
+
+/**    Return a SkColor value from 8 bit component values, with an implied value
+       of 0xFF for alpha (fully opaque)
+*/
+#define SkColorSetRGB(r, g, b) SkColorSetARGB(0xFF, r, g, b)
+
+#define SkColorGetA(color)             ((color) >> 24)                 //!< return the alpha byte from a SkColor value
+#define SkColorGetR(color)             ((color) << 8 >> 24)    //!< return the red byte from a SkColor value
+#define SkColorGetG(color)             ((color) << 16 >> 24)   //!< return the green byte from a SkColor value
+#define SkColorGetB(color)             ((color) << 24 >> 24)   //!< return the blue byte from a SkColor value
+
+// common colors
+
+#define SK_ColorBLACK  0xFF000000      //!< black SkColor value
+#define SK_ColorDKGRAY 0xFF444444      //!< dark gray SkColor value
+#define SK_ColorGRAY   0xFF888888      //!< gray SkColor value
+#define SK_ColorLTGRAY 0xFFCCCCCC      //!< light gray SkColor value
+#define SK_ColorWHITE  0xFFFFFFFF      //!< white SkColor value
+
+#define SK_ColorRED            0xFFFF0000      //!< red SkColor value
+#define SK_ColorGREEN  0xFF00FF00      //!< green SkColor value
+#define SK_ColorBLUE   0xFF0000FF      //!< blue SkColor value
+#define SK_ColorYELLOW 0xFFFFFF00      //!< yellow SkColor value
+#define SK_ColorCYAN   0xFF00FFFF      //!< cyan SkColor value
+#define SK_ColorMAGENTA        0xFFFF00FF      //!< magenta SkColor value
+
+////////////////////////////////////////////////////////////////////////
+
+/** Convert RGB components to HSV.
+        hsv[0] is Hue [0 .. 360)
+        hsv[1] is Saturation [0...1]
+        hsv[2] is Value [0...1]
+    @param red  red component value [0..255]
+    @param green  green component value [0..255]
+    @param blue  blue component value [0..255]
+    @param hsv  3 element array which holds the resulting HSV components.
+*/
+void SkRGBToHSV(U8CPU red, U8CPU green, U8CPU blue, SkScalar hsv[3]);
+
+/** Convert the argb color to its HSV components.
+        hsv[0] is Hue [0 .. 360)
+        hsv[1] is Saturation [0...1]
+        hsv[2] is Value [0...1]
+    @param color the argb color to convert. Note: the alpha component is ignored.
+    @param hsv  3 element array which holds the resulting HSV components.
+*/
+static inline void SkColorToHSV(SkColor color, SkScalar hsv[3])
+{
+    SkRGBToHSV(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color), hsv);
+}
+
+/** Convert HSV components to an ARGB color. The alpha component is passed through unchanged.
+        hsv[0] is Hue [0 .. 360)
+        hsv[1] is Saturation [0...1]
+        hsv[2] is Value [0...1]
+    If hsv values are out of range, they are pinned.
+    @param alpha the alpha component of the returned argb color.
+    @param hsv  3 element array which holds the input HSV components.
+    @return the resulting argb color
+*/
+SkColor SkHSVToColor(U8CPU alpha, const SkScalar hsv[3]);
+
+/** Convert HSV components to an ARGB color. The alpha component set to 0xFF.
+        hsv[0] is Hue [0 .. 360)
+        hsv[1] is Saturation [0...1]
+        hsv[2] is Value [0...1]
+    If hsv values are out of range, they are pinned.
+    @param hsv  3 element array which holds the input HSV components.
+    @return the resulting argb color
+*/
+static inline SkColor SkHSVToColor(const SkScalar hsv[3])
+{
+    return SkHSVToColor(0xFF, hsv);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+/** 32 bit ARGB color value, premultiplied. The byte order for this value is
+       configuration dependent, matching the format of kARGB32 bitmaps. This is different
+       from SkColor, which is nonpremultiplied, and is always in the same byte order.
+*/
+typedef uint32_t SkPMColor;
+
+/**    Return a SkPMColor value from unpremultiplied 8 bit component values
+*/
+SkPMColor SkPreMultiplyARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
+/**    Return a SkPMColor value from a SkColor value. This is done by multiplying the color
+       components by the color's alpha, and by arranging the bytes in a configuration
+       dependent order, to match the format of kARGB32 bitmaps.
+*/
+SkPMColor SkPreMultiplyColor(SkColor c);
+
+/** Define a function pointer type for combining two premultiplied colors
+*/
+typedef SkPMColor (*SkXfermodeProc)(SkPMColor src, SkPMColor dst);
+
+#endif
+
diff --git a/include/graphics/SkColorFilter.h b/include/graphics/SkColorFilter.h
new file mode 100644 (file)
index 0000000..91879ae
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef SkColorFilter_DEFINED
+#define SkColorFilter_DEFINED
+
+#include "SkRefCnt.h"
+#include "SkColor.h"
+#include "SkPorterDuff.h"
+
+class SkColorFilter : public SkRefCnt {
+public:
+    /** Called with a scanline of colors, as if there was a shader installed.
+        The implementation writes out its filtered version into result[].
+        @param shader   array of colors, possibly generated by a shader
+        @param count    the number of entries in the shader[] and result[] arrays
+        @param result   written by the filter, these are the colors that are used to draw
+    */
+    virtual void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]);
+    
+    /** Create a colorfilter that uses the specified color and xfermode proc.
+        @param srcColor    The source color passed to the xfermode proc
+        @param proc     The xfermode proc that is applied to each color in the colorfilter's filterSpan method
+        @return colorfilter object that applies the src color and xfermode proc, or NULL if proc is NULL
+    */
+    static SkColorFilter* CreatXfermodeFilter(SkColor srcColor, SkXfermodeProc proc);
+    /** Create a colorfilter that uses the specified color and porter-duff mode.
+        @param srcColor    The source color used with the specified porter-duff mode
+        @param porterDuffMode     The porter-duff mode that is applied to each color in the colorfilter's filterSpan method
+        @return colorfilter object that applies the src color and porter-duff mode, or NULL is mode is out of range
+    */
+    static SkColorFilter* CreatePorterDuffFilter(SkColor srcColor, SkPorterDuff::Mode porterDuffMode);
+    
+    /** Create a colorfilter that multiplies the RGB channels by one color, and then adds a second color,
+        pinning the result for each component to [0..255]. The alpha components of the mul and add arguments
+        are ignored.
+    */
+    static SkColorFilter* CreateLightingFilter(SkColor mul, SkColor add);
+};
+
+#include "SkShader.h"
+
+class SkFilterShader : public SkShader {
+public:
+    SkFilterShader(SkShader* shader, SkColorFilter* filter);
+    virtual ~SkFilterShader();
+
+    // override
+    virtual bool setContext(const SkBitmap& device, const SkPaint& paint, const SkMatrix& matrix);
+    virtual void shadeSpan(int x, int y, SkPMColor result[], int count);
+    
+private:
+    SkShader*       fShader;
+    SkColorFilter*  fFilter;
+    
+    typedef SkShader INHERITED;
+};
+
+#endif
diff --git a/include/graphics/SkColorPriv.h b/include/graphics/SkColorPriv.h
new file mode 100644 (file)
index 0000000..65b5851
--- /dev/null
@@ -0,0 +1,218 @@
+#ifndef SkColorPriv_DEFINED
+#define SkColorPriv_DEFINED
+
+#include "SkColor.h"
+
+inline unsigned SkAlpha255To256(U8CPU alpha)
+{
+       SkASSERT(SkToU8(alpha) == alpha);
+       return alpha + (alpha >> 7);
+}
+
+#define SkAlphaMul(value, alpha256)            ((value) * (alpha256) >> 8)
+
+//     The caller may want negative values, so keep all params signed (int)
+//     so we don't accidentally slip into unsigned math and lose the sign
+//     extension when we shift (in SkAlphaMul)
+inline int SkAlphaBlend(int src, int dst, int scale256)
+{
+       SkASSERT((unsigned)scale256 <= 256);
+       return dst + SkAlphaMul(src - dst, scale256);
+}
+
+#define SK_R16_BITS            5
+#define SK_G16_BITS            6
+#define SK_B16_BITS            5
+
+#define SK_R16_SHIFT   (SK_B16_BITS + SK_G16_BITS)
+#define SK_G16_SHIFT   (SK_B16_BITS)
+#define SK_B16_SHIFT   0
+
+#define SK_R16_MASK            ((1 << SK_R16_BITS) - 1)
+#define SK_G16_MASK            ((1 << SK_G16_BITS) - 1)
+#define SK_B16_MASK            ((1 << SK_B16_BITS) - 1)
+
+#define SkGetPackedR16(color)  (((unsigned)(color) >> SK_R16_SHIFT) & SK_R16_MASK)
+#define SkGetPackedG16(color)  (((unsigned)(color) >> SK_G16_SHIFT) & SK_G16_MASK)
+#define SkGetPackedB16(color)  (((unsigned)(color) >> SK_B16_SHIFT) & SK_B16_MASK)
+
+inline uint16_t SkPackRGB16(unsigned r, unsigned g, unsigned b)
+{
+       SkASSERT(r <= SK_R16_MASK);
+       SkASSERT(g <= SK_G16_MASK);
+       SkASSERT(b <= SK_B16_MASK);
+
+       return SkToU16((r << SK_R16_SHIFT) | (g << SK_G16_SHIFT) | (b << SK_B16_SHIFT));
+}
+
+inline int SkShouldDitherXY(int x, int y)
+{
+    return (x ^ y) & 1;
+}
+
+inline uint16_t SkDitherPack888ToRGB16(U8CPU r, U8CPU g, U8CPU b)
+{
+    r = ((r << 1) - ((r >> (8 - SK_R16_BITS) << (8 - SK_R16_BITS)) | (r >> SK_R16_BITS))) >> (8 - SK_R16_BITS);
+    g = ((g << 1) - ((g >> (8 - SK_G16_BITS) << (8 - SK_G16_BITS)) | (g >> SK_G16_BITS))) >> (8 - SK_G16_BITS);
+    b = ((b << 1) - ((b >> (8 - SK_B16_BITS) << (8 - SK_B16_BITS)) | (b >> SK_B16_BITS))) >> (8 - SK_B16_BITS);
+
+   return SkPackRGB16(r, g, b);
+}
+
+#define SK_R16_MASK_IN_PLACE           (SK_R16_MASK << SK_R16_SHIFT)
+#define SK_G16_MASK_IN_PLACE           (SK_G16_MASK << SK_G16_SHIFT)
+#define SK_B16_MASK_IN_PLACE           (SK_B16_MASK << SK_B16_SHIFT)
+
+#define SK_R16B16_MASK_IN_PLACE                (SK_R16_MASK_IN_PLACE | SK_B16_MASK_IN_PLACE)
+
+inline U16CPU SkAlphaMulRGB16(U16CPU c, unsigned scale)
+{
+#if SK_G16_MASK_IN_PLACE != 0x07E0
+       return SkPackRGB16(     SkAlphaMul(SkGetPackedR16(c), scale),
+                                               SkAlphaMul(SkGetPackedG16(c), scale),
+                                               SkAlphaMul(SkGetPackedB16(c), scale));
+#else
+       scale >>= (8 - SK_G16_BITS);
+       uint32_t rb = (c & SK_R16B16_MASK_IN_PLACE) * scale >> SK_G16_BITS;
+       uint32_t  g = (c & SK_G16_MASK_IN_PLACE) * scale >> SK_G16_BITS;
+       return (g & SK_G16_MASK_IN_PLACE) | (rb & SK_R16B16_MASK_IN_PLACE);
+#endif
+}
+
+inline U16CPU SkBlendRGB16(U16CPU src, U16CPU dst, unsigned scale)
+{
+       SkASSERT(scale <= 256);
+
+       return SkPackRGB16(     SkAlphaBlend(SkGetPackedR16(src), SkGetPackedR16(dst), scale),
+                                               SkAlphaBlend(SkGetPackedG16(src), SkGetPackedG16(dst), scale),
+                                               SkAlphaBlend(SkGetPackedB16(src), SkGetPackedB16(dst), scale));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+
+#define SK_A32_BITS            8
+#define SK_R32_BITS            8
+#define SK_G32_BITS            8
+#define SK_B32_BITS            8
+
+#ifdef TEST_INTEL_MAC
+
+#define SK_A32_SHIFT   0
+#define SK_R32_SHIFT   8
+#define SK_G32_SHIFT   16
+#define SK_B32_SHIFT   24
+
+#else
+
+#define SK_A32_SHIFT   24
+#define SK_R32_SHIFT   16
+#define SK_G32_SHIFT   8
+#define SK_B32_SHIFT   0
+
+#endif
+
+#define SK_A32_MASK            ((1 << SK_A32_BITS) - 1)
+#define SK_R32_MASK            ((1 << SK_R32_BITS) - 1)
+#define SK_G32_MASK            ((1 << SK_G32_BITS) - 1)
+#define SK_B32_MASK            ((1 << SK_B32_BITS) - 1)
+
+#define SkGetPackedA32(packed)         ((uint32_t)((packed) << (24 - SK_A32_SHIFT)) >> 24)
+#define SkGetPackedR32(packed)         ((uint32_t)((packed) << (24 - SK_R32_SHIFT)) >> 24)
+#define SkGetPackedG32(packed)         ((uint32_t)((packed) << (24 - SK_G32_SHIFT)) >> 24)
+#define SkGetPackedB32(packed)         ((uint32_t)((packed) << (24 - SK_B32_SHIFT)) >> 24)
+
+inline SkPMColor SkPackARGB32(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
+{
+       SkASSERT(a <= SK_A32_MASK);
+       SkASSERT(r <= a);
+       SkASSERT(g <= a);
+       SkASSERT(b <= a);
+
+       return (a << SK_A32_SHIFT) | (r << SK_R32_SHIFT) | (g << SK_G32_SHIFT) | (b << SK_B32_SHIFT);
+}
+
+inline uint32_t SkAlphaMulQ(uint32_t c, unsigned scale)
+{
+       uint32_t rb = ((c & 0xFF00FF) * scale) >> 8;
+       uint32_t ag = ((c >> 8) & 0xFF00FF) * scale;
+       return (rb & 0xFF00FF) | (ag & ~0xFF00FF);
+}
+
+inline SkPMColor SkPMSrcOver(SkPMColor src, SkPMColor dst)
+{
+       return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
+}
+
+inline SkPMColor SkBlendARGB32(SkPMColor src, SkPMColor dst, U8CPU aa)
+{
+       SkASSERT((unsigned)aa <= 255);
+
+       unsigned src_scale = SkAlpha255To256(aa);
+       unsigned dst_scale = SkAlpha255To256(255 - SkAlphaMul(SkGetPackedA32(src), src_scale));
+
+       return SkAlphaMulQ(src, src_scale) + SkAlphaMulQ(dst, dst_scale);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+// Convert a 32bit pixel to a 16bit pixel (no dither)
+
+#define SkR32ToR16(r)  ((unsigned)(r) >> (SK_R32_BITS - SK_R16_BITS))
+#define SkG32ToG16(g)  ((unsigned)(g) >> (SK_G32_BITS - SK_G16_BITS))
+#define SkB32ToB16(b)  ((unsigned)(b) >> (SK_B32_BITS - SK_B16_BITS))
+
+#define SkPacked32ToR16(c)     (((unsigned)(c) >> (SK_R32_SHIFT + SK_R32_BITS - SK_R16_BITS)) & SK_R16_MASK)
+#define SkPacked32ToG16(c)     (((unsigned)(c) >> (SK_G32_SHIFT + SK_G32_BITS - SK_G16_BITS)) & SK_G16_MASK)
+#define SkPacked32ToB16(c)     (((unsigned)(c) >> (SK_B32_SHIFT + SK_B32_BITS - SK_B16_BITS)) & SK_B16_MASK)
+
+inline U16CPU SkPixel32ToPixel16(SkPMColor src)
+{
+#if 0
+       return  (SkPacked32ToR16(src) << SK_R16_SHIFT) |
+                       (SkPacked32ToG16(src) << SK_G16_SHIFT) |
+                       (SkPacked32ToB16(src) << SK_B16_SHIFT);
+#else  // only works if the components are in the same order in both formats (i.e. foo32_shift >= foo16_shift)
+       return  ((src >> (SK_R32_SHIFT + SK_R32_BITS - SK_R16_BITS - SK_R16_SHIFT)) & (SK_R16_MASK << SK_R16_SHIFT)) |
+                       ((src >> (SK_G32_SHIFT + SK_G32_BITS - SK_G16_BITS - SK_G16_SHIFT)) & (SK_G16_MASK << SK_G16_SHIFT)) |
+                       ((src >> (SK_B32_SHIFT + SK_B32_BITS - SK_B16_BITS - SK_B16_SHIFT)) & (SK_B16_MASK << SK_B16_SHIFT));
+#endif
+}
+
+#define SkPixel32ToPixel16_ToU16(src)  SkToU16(SkPixel32ToPixel16(src))
+
+////////////////////////////////////////////////////////////////////////////////////////////
+// Convert a 16bit pixel to a 32bit pixel
+
+inline unsigned SkR16ToR32(unsigned r)
+{
+       return (r << (8 - SK_R16_BITS)) | (r >> (2 * SK_R16_BITS - 8));
+}
+inline unsigned SkG16ToG32(unsigned g)
+{
+       return (g << (8 - SK_G16_BITS)) | (g >> (2 * SK_G16_BITS - 8));
+}
+inline unsigned SkB16ToB32(unsigned b)
+{
+       return (b << (8 - SK_B16_BITS)) | (b >> (2 * SK_B16_BITS - 8));
+}
+
+#define SkPacked16ToR32(c)             SkR16ToR32(SkGetPackedR16(c))
+#define SkPacked16ToG32(c)             SkG16ToG32(SkGetPackedG16(c))
+#define SkPacked16ToB32(c)             SkB16ToB32(SkGetPackedB16(c))
+
+inline SkPMColor SkPixel16ToPixel32(U16CPU src)
+{
+       SkASSERT(src == SkToU16(src));
+
+       unsigned        r = SkPacked16ToR32(src);
+       unsigned        g = SkPacked16ToG32(src);
+       unsigned        b = SkPacked16ToB32(src);
+
+       SkASSERT((r >> (8 - SK_R16_BITS)) == SkGetPackedR16(src));
+       SkASSERT((g >> (8 - SK_G16_BITS)) == SkGetPackedG16(src));
+       SkASSERT((b >> (8 - SK_B16_BITS)) == SkGetPackedB16(src));
+
+       return SkPackARGB32(0xFF, r, g, b);
+}
+
+#endif
+
diff --git a/include/graphics/SkCornerPathEffect.h b/include/graphics/SkCornerPathEffect.h
new file mode 100644 (file)
index 0000000..4307c70
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef SkCornerPathEffect_DEFINED
+#define SkCornerPathEffect_DEFINED
+
+#include "SkPathEffect.h"
+
+/**    \class SkCornerPathEffect
+
+       SkCornerPathEffect is a subclass of SkPathEffect that can turn sharp corners
+    into various treatments (e.g. rounded corners)
+*/
+class SkCornerPathEffect : public SkPathEffect {
+public:
+       /**     radius must be > 0 to have an effect. It specifies the distance from each corner
+        that should be "rounded".
+       */
+       SkCornerPathEffect(SkScalar radius);
+       virtual ~SkCornerPathEffect();
+
+       // overrides for SkPathEffect
+    //  This method is not exported to java.
+       virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
+
+       // overrides for SkFlattenable
+    //  This method is not exported to java.
+       virtual Factory getFactory();
+    //  This method is not exported to java.
+       virtual void flatten(SkWBuffer&);
+
+protected:
+       SkCornerPathEffect(SkRBuffer&);
+
+private:
+    SkScalar    fRadius;
+
+       static SkFlattenable* CreateProc(SkRBuffer&);
+    
+    // illegal
+    SkCornerPathEffect(const SkCornerPathEffect&);
+    SkCornerPathEffect& operator=(const SkCornerPathEffect&);
+    
+    typedef SkPathEffect INHERITED;
+};
+
+#endif
+
diff --git a/include/graphics/SkCullPoints.h b/include/graphics/SkCullPoints.h
new file mode 100644 (file)
index 0000000..def938d
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef SkCullPoints_DEFINED
+#define SkCullPoints_DEFINED
+
+#include "SkRect.h"
+
+class SkCullPoints {
+public:
+    SkCullPoints();
+    SkCullPoints(const SkRect16& r);
+    
+    void    reset(const SkRect16& r);
+    
+    /** Start a contour at (x,y). Follow this with call(s) to lineTo(...)
+    */
+    void    moveTo(int x, int y);
+    
+    enum LineToResult {
+        kNo_Result,             //!< line segment was completely clipped out
+        kLineTo_Result,         //!< path.lineTo(pts[1]);
+        kMoveToLineTo_Result    //!< path.moveTo(pts[0]); path.lineTo(pts[1]);
+    };
+    /** Connect a line to the previous call to lineTo (or moveTo).
+    */
+    LineToResult lineTo(int x, int y, SkPoint16 pts[2]);
+
+private:
+    SkRect16    fR;
+    SkPoint16   fAsQuad[4];
+    SkPoint32   fPrevPt;    // local state
+    
+    bool sect_test(int x0, int y0, int x1, int y1) const;
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+
+class SkPath;
+
+/** \class SkCullPointsPath
+
+    Similar to SkCullPoints, but this class handles the return values
+    from lineTo, and automatically builds a SkPath with the result(s).
+*/
+class SkCullPointsPath {
+public:
+    SkCullPointsPath();
+    SkCullPointsPath(const SkRect16& r, SkPath* dst);
+
+    void reset(const SkRect16& r, SkPath* dst);
+    
+    void    moveTo(int x, int y);
+    void    lineTo(int x, int y);
+
+private:
+    SkCullPoints    fCP;
+    SkPath*         fPath;
+};
+
+#endif
diff --git a/include/graphics/SkDOM.h b/include/graphics/SkDOM.h
new file mode 100644 (file)
index 0000000..6567a89
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef SkDOM_DEFINED
+#define SkDOM_DEFINED
+
+#include "SkChunkAlloc.h"
+#include "SkMath.h"
+#include "SkTemplates.h"
+
+struct SkDOMNode;
+struct SkDOMAttr;
+
+class SkDOM {
+public:
+       SkDOM();
+       ~SkDOM();
+
+       typedef SkDOMNode Node;
+    typedef SkDOMAttr Attr;
+
+       /** Returns nil on failure
+       */
+       const Node* build(const char doc[], size_t len);
+       const Node* copy(const SkDOM& dom, const Node* node);
+
+       const Node*     getRootNode() const;
+
+       enum Type {
+               kElement_Type,
+               kText_Type
+       };
+       Type    getType(const Node*) const;
+
+       const char*     getName(const Node*) const;
+       const Node*     getFirstChild(const Node*, const char elem[] = nil) const;
+       const Node*     getNextSibling(const Node*, const char elem[] = nil) const;
+
+       const char* findAttr(const Node*, const char attrName[]) const;
+    const Attr* getFirstAttr(const Node*) const;
+    const Attr* getNextAttr(const Node*, const Attr*) const;
+    const char* getAttrName(const Node*, const Attr*) const;
+    const char* getAttrValue(const Node*, const Attr*) const;
+       
+       // helpers for walking children
+       int countChildren(const Node* node, const char elem[] = nil) const;
+
+       // helpers for calling SkParse
+       bool findS32(const Node*, const char name[], int32_t* value) const;
+       bool findScalars(const Node*, const char name[], SkScalar value[], int count) const;
+       bool findHex(const Node*, const char name[], uint32_t* value) const;
+       bool findBool(const Node*, const char name[], bool*) const;
+       int  findList(const Node*, const char name[], const char list[]) const;
+
+       bool findScalar(const Node* node, const char name[], SkScalar value[]) const
+       {
+               return this->findScalars(node, name, value, 1);
+       }
+
+       bool hasAttr(const Node*, const char name[], const char value[]) const;
+       bool hasS32(const Node*, const char name[], int32_t value) const;
+       bool hasScalar(const Node*, const char name[], SkScalar value) const;
+       bool hasHex(const Node*, const char name[], uint32_t value) const;
+       bool hasBool(const Node*, const char name[], bool value) const;
+
+       class AttrIter {
+       public:
+               AttrIter(const class SkDOM&, const Node*);
+               const char* next(const char** value);
+       private:
+               const Attr*     fAttr;
+               const Attr*     fStop;
+       };
+
+       SkDEBUGCODE(void dump(const Node* node = nil, int tabLevel = 0) const;)
+       SkDEBUGCODE(static void UnitTest();)
+
+private:
+       SkChunkAlloc    fAlloc;
+       Node*                   fRoot;
+       friend class AttrIter;
+       friend class SkDOMParser;
+};
+
+#endif
+
diff --git a/include/graphics/SkDashPathEffect.h b/include/graphics/SkDashPathEffect.h
new file mode 100644 (file)
index 0000000..0e567ef
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef SkDashPathEffect_DEFINED
+#define SkDashPathEffect_DEFINED
+
+#include "SkPathEffect.h"
+
+/**    \class SkDashPathEffect
+
+       SkDashPathEffect is a subclass of SkPathEffect that implements dashing
+*/
+class SkDashPathEffect : public SkPathEffect {
+public:
+       /**     The intervals array must contain an even number of entries (>=2), with the even
+               indices specifying the "on" intervals, and the odd indices specifying the "off"
+               intervals. phase is an offset into the intervals array (mod the sum of all of the
+               intervals).
+               Note: only affects framed paths
+       */
+       SkDashPathEffect(const SkScalar intervals[], int count, SkScalar phase, bool scaleToFit = false);
+       virtual ~SkDashPathEffect();
+
+       // overrides for SkPathEffect
+    //  This method is not exported to java.
+       virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
+
+       // overrides for SkFlattenable
+    //  This method is not exported to java.
+       virtual Factory getFactory();
+    //  This method is not exported to java.
+       virtual void flatten(SkWBuffer&);
+
+protected:
+       SkDashPathEffect(SkRBuffer&);
+    
+private:
+       SkScalar*       fIntervals;
+       int32_t         fCount;
+       // computed from phase
+       SkScalar        fInitialDashLength;
+       int32_t         fInitialDashIndex;
+       SkScalar        fIntervalLength;
+       bool            fScaleToFit;
+
+       static SkFlattenable* CreateProc(SkRBuffer&);
+
+    typedef SkPathEffect INHERITED;
+};
+
+#endif
+
diff --git a/include/graphics/SkDeque.h b/include/graphics/SkDeque.h
new file mode 100644 (file)
index 0000000..0967702
--- /dev/null
@@ -0,0 +1,191 @@
+#ifndef SkTDeque_DEFINED
+#define SkTDeque_DEFINED
+
+#include "SkTypes.h"
+
+template <typename T> struct sk_trait_trivial_constructor  { enum { value = false }; };
+template <typename T> struct sk_trait_trivial_destructor   { enum { value = false }; };
+template <typename T> struct sk_trait_trivial_copy         { enum { value = false }; };
+template <typename T> struct sk_trait_trivial_assign       { enum { value = false }; };
+
+template <typename T> struct sk_traits {
+    enum {
+        has_trivial_constructor = sk_trait_trivial_constructor<T>::value,
+        has_trivial_destructor  = sk_trait_trivial_destructor<T>::value,
+        has_trivial_copy        = sk_trait_trivial_copy<T>::value,
+        has_trivial_assign      = sk_trait_trivial_assign<T>::value
+    };
+};
+
+#define SK_SET_BASIC_TRAITS(T)                                                  \
+    template <> struct sk_trait_trivial_constructor<T> { enum { value = true }; };     \
+    template <> struct sk_trait_trivial_destructor<T>  { enum { value = true }; };     \
+    template <> struct sk_trait_trivial_copy<T>        { enum { value = true }; };     \
+    template <> struct sk_trait_trivial_assign<T>      { enum { value = true }; }
+
+#define SK_SET_TYPE_TRAITS(T, ctor, dtor, copy, asgn)                           \
+    template <> struct sk_trait_trivial_constructor<T> { enum { value = ctor }; };     \
+    template <> struct sk_trait_trivial_destructor<T>  { enum { value = dtor }; };     \
+    template <> struct sk_trait_trivial_copy<T>        { enum { value = copy }; };     \
+    template <> struct sk_trait_trivial_assign<T>      { enum { value = asgn }; }
+
+#include <new>
+
+class SkDeque {
+public:
+    SkDeque(size_t elemSize);
+    SkDeque(size_t elemSize, void* storage, size_t storageSize);
+    ~SkDeque();
+
+    bool    empty() const { return fCount == 0; }
+    int     count() const { return fCount; }
+
+    const void* front() const;
+    const void* back() const;
+
+    void* front()
+    {
+        return (void*)((const SkDeque*)this)->front();
+    }
+    void* back()
+    {
+        return (void*)((const SkDeque*)this)->back();
+    }
+
+    void*   push_front();
+    void*   push_back();
+    
+    void    pop_front();
+    void    pop_back();
+    
+    SkDEBUGCODE(static void UnitTest();)
+
+private:
+    struct Head;
+
+public:
+    class Iter {
+    public:
+        Iter(const SkDeque& d);
+        void* next();
+
+    private:
+        SkDeque::Head*  fHead;
+        char*           fPos;
+        size_t          fElemSize;
+    };
+
+private:
+    Head*   fFront;
+    Head*   fBack;
+    size_t  fElemSize;
+    void*   fInitialStorage;
+    int     fCount;
+    
+    friend class Iter;
+};
+
+template <typename T> class SkTDeque {
+public:
+    SkTDeque() : fD(sizeof(T)) {}
+    SkTDeque(T storage[], int count) : fD(sizeof(T), storage, count * sizeof(T)) {}
+    inline ~SkTDeque();
+
+    bool empty() const { return fD.empty(); }
+    int count() const { return fD.count(); }
+
+    T*          front() { return (T*)fD.front(); }
+    const T*    front() const { return (const T*)fD.front(); }
+    T*          back() { return (T*)fD.back(); }
+    const T*    back() const { return (const T*)fD.back(); }
+    
+    T* push_front()
+    {
+        T* front = (T*)fD.push_front();
+        if (!sk_traits<T>::has_trivial_constructor) {
+            new(front) T();
+        }
+        return front;
+    }
+    T* push_back()
+    {
+        T* back = (T*)fD.push_back();
+        if (!sk_traits<T>::has_trivial_constructor) {
+            new(back) T();
+        }
+        return back;
+    }
+
+    T* push_front(const T& value)
+    {
+        T* front = (T*)fD.push_front();
+        if (sk_traits<T>::has_trivial_copy) {
+            *front = value;
+        }
+        else {
+            new(front) T(value);
+        }
+        return front;
+    }
+    T* push_back(const T& value)
+    {
+        T* back = (T*)fD.push_back();
+        if (sk_traits<T>::has_trivial_copy) {
+            *back = value;
+        }
+        else {
+            new(back) T(value);
+        }
+        return back;
+    }
+    
+    void pop_front()
+    {
+        if (!sk_traits<T>::has_trivial_destructor) {
+            this->front()->~T();
+        }
+        fD.pop_front();
+    }
+    void pop_back()
+    {
+        if (!sk_traits<T>::has_trivial_destructor) {
+            this->back()->~T();
+        }
+        fD.pop_back();
+    }
+    
+    class Iter : private SkDeque::Iter {
+    public:
+        Iter(const SkTDeque<T>& d) : SkDeque::Iter(d.fD) {}
+        T* next() { return (T*)SkDeque::Iter::next(); }
+    };
+
+private:
+    SkDeque fD;
+    
+    friend class Iter;
+};
+
+template <size_t COUNT, typename T> class SkSTDeque : public SkTDeque<T> {
+public:
+    SkSTDeque() : SkTDeque<T>((T*)fStorage, COUNT) {}
+    
+private:
+    uint32_t fStorage[SkAlign4(COUNT * sizeof(T))];
+};
+
+////////////////////////////////////////////////////////////////////////////////////
+
+template <typename T> inline SkTDeque<T>::~SkTDeque()
+{
+    if (!sk_traits<T>::has_trivial_destructor)
+    {
+        Iter   iter(*this);
+        T*     t;
+        while ((t = iter.next()) != nil) {
+            t->~T();
+        }
+    }
+}
+
+#endif
diff --git a/include/graphics/SkDescriptor.h b/include/graphics/SkDescriptor.h
new file mode 100644 (file)
index 0000000..b431144
--- /dev/null
@@ -0,0 +1,158 @@
+#ifndef SkDescriptor_DEFINED
+#define SkDescriptor_DEFINED
+
+#include "SkTypes.h"
+
+class SkDescriptor {
+public:
+       static size_t ComputeOverhead(int entryCount)
+       {
+               SkASSERT(entryCount >= 0);
+               return sizeof(SkDescriptor) + entryCount * sizeof(Entry);
+       }
+
+       static SkDescriptor* Alloc(size_t length)
+       {
+               SkASSERT(SkAlign4(length) == length);
+               SkDescriptor* desc = (SkDescriptor*)sk_malloc_throw(length);
+               return desc;
+       }
+
+       static void Free(SkDescriptor* desc)
+       {
+               sk_free(desc);
+       }
+
+       void init()
+       {
+               fLength = sizeof(SkDescriptor);
+               fCount  = 0;
+       }
+
+       U32 getLength() const { return fLength; }
+
+       void* addEntry(U32 tag, U32 length, const void* data = nil)
+       {
+               SkASSERT(tag);
+               SkASSERT(SkAlign4(length) == length);
+               SkASSERT(this->findEntry(tag, nil) == nil);
+
+               Entry*  entry = (Entry*)((char*)this + fLength);
+               entry->fTag = tag;
+               entry->fLen = length;
+               if (data)
+                       memcpy(entry + 1, data, length);
+
+               fCount += 1;
+               fLength += sizeof(Entry) + length;
+               return (entry + 1);     // return its data
+       }
+
+       void computeChecksum()
+       {
+               fChecksum = SkDescriptor::ComputeChecksum(this);
+       }
+
+#ifdef SK_DEBUG
+       void assertChecksum() const
+       {
+               SkASSERT(fChecksum == SkDescriptor::ComputeChecksum(this));
+       }
+#endif
+
+       const void* findEntry(U32 tag, U32* length) const
+       {
+               const Entry* entry = (const Entry*)(this + 1);
+               int                      count = fCount;
+
+               while (--count >= 0)
+               {
+                       if (entry->fTag == tag)
+                       {
+                               if (length)
+                                       *length = entry->fLen;
+                               return entry + 1;
+                       }
+                       entry = (const Entry*)((const char*)(entry + 1) + entry->fLen);
+               }
+               return nil;
+       }
+
+       SkDescriptor* copy() const
+       {
+               SkDescriptor* desc = SkDescriptor::Alloc(fLength);
+               memcpy(desc, this, fLength);
+               return desc;
+       }
+
+       friend bool operator==(const SkDescriptor& a, const SkDescriptor& b)
+       {
+               return  a.fChecksum == b.fChecksum &&
+                               a.fLength == b.fLength &&
+                               // this assumes that fCount is the beginning of the rest of the descriptor
+                               // (after fCheckSum and fLength)
+                               memcmp(&a.fCount, &b.fCount, a.fLength - 2*sizeof(U32)) == 0;
+       }
+
+       struct Entry {
+               U32     fTag;
+               U32     fLen;
+       };
+
+#ifdef SK_DEBUG
+       U32 getChecksum() const { return fChecksum; }
+       U32 getCount() const { return fCount; }
+#endif
+
+private:
+       U32     fChecksum;      // must be first
+       U32     fLength;        // must be second
+       U32     fCount;
+
+       static U32 ComputeChecksum(const SkDescriptor* desc)
+       {
+               const U32*      ptr = (const U32*)desc + 1;     // skip the checksum field
+               const U32*      stop = (const U32*)((const char*)desc + desc->fLength);
+               U32                     sum = 0;
+
+               SkASSERT(ptr < stop);
+               do {
+                       sum = (sum << 1) | (sum >> 31);
+                       sum += *ptr++;
+               } while (ptr < stop);
+
+               return sum;
+       }
+};
+
+#include "SkScalerContext.h"
+
+class SkAutoDescriptor {
+public:
+       SkAutoDescriptor(size_t size)
+       {
+               if (size <= kStorageSize)
+                       fDesc = (SkDescriptor*)fStorage;
+               else
+                       fDesc = SkDescriptor::Alloc(size);
+       }
+       ~SkAutoDescriptor()
+       {
+               if (fDesc != (SkDescriptor*)fStorage)
+                       SkDescriptor::Free(fDesc);
+       }
+       SkDescriptor* getDesc() const { return fDesc; }
+private:
+       enum {
+               kStorageSize =  sizeof(SkDescriptor)
+                        + sizeof(SkDescriptor::Entry) + sizeof(SkScalerContext::Rec)    // for rec
+                        + sizeof(SkDescriptor::Entry) + sizeof(void*)                   // for typeface
+                        + 32   // slop for occational small extras
+       };
+       SkDescriptor*   fDesc;
+       U32                             fStorage[kStorageSize >> 2];
+};
+
+
+#endif
+
diff --git a/include/graphics/SkDiscretePathEffect.h b/include/graphics/SkDiscretePathEffect.h
new file mode 100644 (file)
index 0000000..d358624
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef SkDiscretePathEffect_DEFINED
+#define SkDiscretePathEffect_DEFINED
+
+#include "SkPathEffect.h"
+
+/** \class SkDiscretePathEffect
+
+    This path effect chops a path into discrete segments, and randomly displaces them.
+*/
+class SkDiscretePathEffect : public SkPathEffect {
+public:
+       /**     Break the path into segments of segLength length, and randomly move the endpoints
+               away from the original path by a maximum of deviation.
+               Note: works on filled or framed paths
+       */
+       SkDiscretePathEffect(SkScalar segLength, SkScalar deviation);
+
+       // overrides for SkPathEffect
+    //  This method is not exported to java.
+       virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
+
+       // overrides for SkFlattenable
+    //  This method is not exported to java.
+       virtual Factory getFactory();
+    //  This method is not exported to java.
+       virtual void flatten(SkWBuffer&);
+
+protected:
+    SkDiscretePathEffect(SkRBuffer&);
+
+private:
+       SkScalar fSegLength, fPerterb;
+
+       static SkFlattenable* CreateProc(SkRBuffer&);
+    
+    typedef SkPathEffect INHERITED;
+};
+
+#endif
+
diff --git a/include/graphics/SkDrawExtraPathEffect.h b/include/graphics/SkDrawExtraPathEffect.h
new file mode 100755 (executable)
index 0000000..50a43c6
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef SK_DRAW_EXTRA_PATH_EFFECT_H
+#define SK_DRAW_EXTRA_PATH_EFFECT_H
+class SkAnimator;
+void InitializeSkExtraPathEffects(SkAnimator* animator);
+#endif
+
diff --git a/include/graphics/SkEmbossMaskFilter.h b/include/graphics/SkEmbossMaskFilter.h
new file mode 100644 (file)
index 0000000..5cfa145
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef SkEmbossMaskFilter_DEFINED
+#define SkEmbossMaskFilter_DEFINED
+
+#include "SkMaskFilter.h"
+
+/** \class SkEmbossMaskFilter
+
+    This mask filter creates a 3D emboss look, by specifying a light and blur amount.
+*/
+class SkEmbossMaskFilter : public SkMaskFilter {
+public:
+       struct Light {
+               SkScalar        fDirection[3];  // x,y,z
+               U16                     fPad;
+               U8                      fAmbient;
+               U8                      fSpecular;              // exponent, 4.4 right now
+       };
+
+       SkEmbossMaskFilter(const Light& light, SkScalar blurRadius);
+
+       // overrides from SkMaskFilter
+    //  This method is not exported to java.
+       virtual SkMask::Format getFormat();
+    //  This method is not exported to java.
+       virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkPoint16* margin);
+
+       // overrides from SkFlattenable
+
+    //  This method is not exported to java.
+       virtual Factory getFactory();
+    //  This method is not exported to java.
+       virtual void flatten(SkWBuffer&);
+
+protected:
+    SkEmbossMaskFilter(SkRBuffer&);
+
+private:
+       Light           fLight;
+       SkScalar        fBlurRadius;
+
+       static SkFlattenable* CreateProc(SkRBuffer&);
+    
+    typedef SkMaskFilter INHERITED;
+};
+
+#endif
+
diff --git a/include/graphics/SkEvent.h b/include/graphics/SkEvent.h
new file mode 100644 (file)
index 0000000..d171015
--- /dev/null
@@ -0,0 +1,228 @@
+#ifndef SkEvent_DEFINED
+#define SkEvent_DEFINED
+
+#include "SkDOM.h"
+#include "SkMetaData.h"
+#include "SkString.h"
+
+//class SkOSWindow;
+
+/**    Unique 32bit id used to identify an instance of SkEventSink. When events are
+       posted, they are posted to a specific sinkID. When it is time to dispatch the
+       event, the sinkID is used to find the specific SkEventSink object. If it is found,
+       its doEvent() method is called with the event.
+*/
+typedef U32 SkEventSinkID;
+
+/** \class SkEvent
+
+       SkEvents are used to communicate type-safe information to SkEventSinks.
+       SkEventSinks (including SkViews) each have a unique ID, which is stored
+       in an event. This ID is used to target the event once it has been "posted".
+*/
+class SkEvent {
+public:
+       /**     Default construct, creating an empty event.
+       */
+       SkEvent();
+       /**     Construct a new event with the specified type.
+       */
+       explicit SkEvent(const SkString& type);
+       /**     Construct a new event with the specified type.
+       */
+       explicit SkEvent(const char type[]);
+       /**     Construct a new event by copying the fields from the src event.
+       */
+       SkEvent(const SkEvent& src);
+       ~SkEvent();
+
+//     /**     Return the event's type (will never be nil) */
+//     const char*     getType() const;
+       /** Copy the event's type into the specified SkString parameter */
+       void    getType(SkString* str) const;
+       /**     Returns true if the event's type matches exactly the specified type (case sensitive) */
+       bool    isType(const SkString& str) const;
+       /**     Returns true if the event's type matches exactly the specified type (case sensitive) */
+       bool    isType(const char type[], size_t len = 0) const;
+       /**     Set the event's type to the specified string.
+               In XML, use the "type" attribute.
+       */
+       void    setType(const SkString&);
+       /**     Set the event's type to the specified string.
+               In XML, use the "type" attribute.
+       */
+       void    setType(const char type[], size_t len = 0);
+
+       /**     Return the event's unnamed 32bit field. Default value is 0 */
+       U32             getFast32() const { return f32; }
+       /**     Set the event's unnamed 32bit field. In XML, use
+               the subelement <data fast32=... />
+       */
+       void    setFast32(uint32_t x) { f32 = x; }
+
+       /**     Return true if the event contains the named 32bit field, and return the field
+               in value (if value is non-nil). If there is no matching named field, return false
+               and ignore the value parameter.
+       */
+       bool    findS32(const char name[], int32_t* value = nil) const { return fMeta.findS32(name, value); }
+       /**     Return true if the event contains the named SkScalar field, and return the field
+               in value (if value is non-nil). If there is no matching named field, return false
+               and ignore the value parameter.
+       */
+       bool    findScalar(const char name[], SkScalar* value = nil) const { return fMeta.findScalar(name, value); }
+       /**     Return true if the event contains the named SkScalar field, and return the fields
+               in value[] (if value is non-nil), and return the number of SkScalars in count (if count is non-nil).
+               If there is no matching named field, return false and ignore the value and count parameters.
+       */
+       const SkScalar* findScalars(const char name[], int* count, SkScalar values[] = nil) const { return fMeta.findScalars(name, count, values); }
+       /**     Return the value of the named string field, or if no matching named field exists, return nil.
+       */
+       const char*     findString(const char name[]) const { return fMeta.findString(name); }
+       /**     Return true if the event contains the named pointer field, and return the field
+               in value (if value is non-nil). If there is no matching named field, return false
+               and ignore the value parameter.
+       */
+       bool    findPtr(const char name[], void** value) const { return fMeta.findPtr(name, value); }
+       bool    findBool(const char name[], bool* value) const { return fMeta.findBool(name, value); }
+
+       /**     Returns true if ethe event contains the named 32bit field, and if it equals the specified value */
+       bool    hasS32(const char name[], int32_t value) const { return fMeta.hasS32(name, value); }
+       /**     Returns true if ethe event contains the named SkScalar field, and if it equals the specified value */
+       bool    hasScalar(const char name[], SkScalar value) const { return fMeta.hasScalar(name, value); }
+       /**     Returns true if ethe event contains the named string field, and if it equals (using strcmp) the specified value */
+       bool    hasString(const char name[], const char value[]) const { return fMeta.hasString(name, value); }
+       /**     Returns true if ethe event contains the named pointer field, and if it equals the specified value */
+       bool    hasPtr(const char name[], void* value) const { return fMeta.hasPtr(name, value); }
+       bool    hasBool(const char name[], bool value) const { return fMeta.hasBool(name, value); }
+
+       /**     Add/replace the named 32bit field to the event. In XML use the subelement <data name=... s32=... /> */
+       void    setS32(const char name[], int32_t value) { fMeta.setS32(name, value); }
+       /**     Add/replace the named SkScalar field to the event. In XML use the subelement <data name=... scalar=... /> */
+       void    setScalar(const char name[], SkScalar value) { fMeta.setScalar(name, value); }
+       /**     Add/replace the named SkScalar[] field to the event. */
+       SkScalar* setScalars(const char name[], int count, const SkScalar values[] = nil) { return fMeta.setScalars(name, count, values); }
+       /**     Add/replace the named string field to the event. In XML use the subelement <data name=... string=... */
+       void    setString(const char name[], const SkString& value) { fMeta.setString(name, value.c_str()); }
+       /**     Add/replace the named string field to the event. In XML use the subelement <data name=... string=... */
+       void    setString(const char name[], const char value[]) { fMeta.setString(name, value); }
+       /**     Add/replace the named pointer field to the event. There is no XML equivalent for this call */
+       void    setPtr(const char name[], void* value) { fMeta.setPtr(name, value); }
+       void    setBool(const char name[], bool value) { fMeta.setBool(name, value); }
+
+       /**     Return the underlying metadata object */
+       SkMetaData&                     getMetaData() { return fMeta; }
+       /**     Return the underlying metadata object */
+       const SkMetaData&       getMetaData() const { return fMeta; }
+
+       void tron() { SkDEBUGCODE(fDebugTrace = true;) }
+       void troff() { SkDEBUGCODE(fDebugTrace = false;) }
+       bool isDebugTrace() const
+       {
+#ifdef SK_DEBUG
+               return fDebugTrace;
+#else
+               return false;
+#endif
+       }
+
+       /**     Call this to initialize the event from the specified XML node */
+       void    inflate(const SkDOM&, const SkDOM::Node*);
+
+       SkDEBUGCODE(void dump(const char title[] = nil);)
+
+       /**     Post the specified event to the event queue, targeting the specified eventsink, with an optional
+               delay. The event must be dynamically allocated for this. It cannot be a global or on the stack.
+               After this call, ownership is transfered to the system, so the caller must not retain
+               the event's ptr. Returns false if the event could not be posted (which means it will have been deleted).
+       */
+       static bool     Post(SkEvent* evt, SkEventSinkID targetID, SkMSec delay = 0);
+       /**     Post the specified event to the event queue, targeting the specified eventsink, to be delivered on/after the
+               specified millisecond time. The event must be dynamically allocated for this. It cannot be a global or on the stack.
+               After this call, ownership is transfered to the system, so the caller must not retain
+               the event's ptr. Returns false if the event could not be posted (which means it will have been deleted).
+       */
+       static bool     PostTime(SkEvent* evt, SkEventSinkID targetID, SkMSec time);
+
+       /**     Helper method for calling SkEvent::PostTime(this, ...), where the caller specifies a delay.
+               The real "time" will be computed automatically by sampling the clock and adding its value
+               to delay.
+       */
+       bool post(SkEventSinkID sinkID, SkMSec delay = 0)
+       {
+               return SkEvent::Post(this, sinkID, delay);
+       }
+
+       void postTime(SkEventSinkID sinkID, SkMSec time)
+       {
+               SkEvent::PostTime(this, sinkID, time);
+       }
+
+       ///////////////////////////////////////////////
+       /**     Porting layer must call these functions **/
+       ///////////////////////////////////////////////
+
+       /**     Global initialization function for the SkEvent system. Should be called exactly
+               once before any other event method is called, and should be called after the
+               call to SkGraphics::Init().
+       */
+       static void             Init();
+       /**     Global cleanup function for the SkEvent system. Should be called exactly once after
+               all event methods have been called, and should be called before calling SkGraphics::Term().
+       */
+       static void             Term();
+
+       /**     Call this to process one event from the queue. If it returns true, there are more events
+               to process.
+       */
+       static bool             ProcessEvent();
+       /**     Call this whenever the requested timer has expired (requested by a call to SetQueueTimer).
+               It will post any delayed events whose time as "expired" onto the event queue.
+               It may also call SignalQueueTimer() and SignalNonEmptyQueue().
+       */
+       static void             ServiceQueueTimer();
+
+       ////////////////////////////////////////////////////
+       /**     Porting layer must implement these functions **/
+       ////////////////////////////////////////////////////
+
+       /**     Called whenever an SkEvent is posted to an empty queue, so that the OS
+               can be told to later call Dequeue().
+       */
+       static void     SignalNonEmptyQueue();
+       /**     Called whenever the delay until the next delayed event changes. If zero is
+               passed, then there are no more queued delay events.
+       */
+       static void SignalQueueTimer(SkMSec delay);
+
+#ifndef SK_USE_WXWIDGETS
+#ifdef SK_BUILD_FOR_WIN
+       static bool WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+#elif defined(SK_BUILD_FOR_UNIXx)
+  static U32 HandleTimer(U32, void*);
+  static bool WndProc(Display*, Window, XEvent&);
+#endif
+#else
+       // Don't know yet what this will be
+       //static bool CustomEvent();
+#endif
+
+private:
+       SkMetaData              fMeta;
+       mutable char*   fType;  // may be characters with low bit set to know that it is not a pointer
+       U32                             f32;
+       SkDEBUGCODE(bool fDebugTrace;)
+
+       // these are for our implementation of the event queue
+       SkEventSinkID   fTargetID;
+       SkMSec                  fTime;
+       SkEvent*                fNextEvent;     // either in the delay or normal event queue
+       void initialize(const char* type, size_t typeLen);
+
+       static bool Enqueue(SkEvent* evt);
+       static SkMSec EnqueueTime(SkEvent* evt, SkMSec time);
+       static SkEvent* Dequeue(SkEventSinkID* targetID);
+       static bool             QHasEvents();
+};
+
+#endif
+
diff --git a/include/graphics/SkEventSink.h b/include/graphics/SkEventSink.h
new file mode 100644 (file)
index 0000000..6772f03
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef SkEventSink_DEFINED
+#define SkEventSink_DEFINED
+
+#include "SkRefCnt.h"
+#include "SkEvent.h"
+
+struct SkTagList;
+
+/**    \class SkEventSink
+
+       SkEventSink is the base class for all objects that receive SkEvents.
+*/
+class SkEventSink : public SkRefCnt {
+public:
+                       SkEventSink();
+       virtual ~SkEventSink();
+
+       /**     Returns this eventsink's unique ID. Use this to post SkEvents to
+               this eventsink.
+       */
+       SkEventSinkID getSinkID() const { return fID; }
+
+       /**     Call this to pass an event to this object for processing. Returns true if the
+               event was handled.
+       */
+       bool doEvent(const SkEvent&);
+       /**     Returns true if the sink (or one of its subclasses) understands the event as a query.
+               If so, the sink may modify the event to communicate its "answer".
+       */
+       bool doQuery(SkEvent* query);
+
+       /**     Add sinkID to the list of listeners, to receive events from calls to sendToListeners()
+               and postToListeners(). If sinkID already exists in the listener list, no change is made.
+       */
+       void    addListenerID(SkEventSinkID sinkID);
+       /**     Copy listeners from one event sink to another, typically from parent to child.
+               @param from the event sink to copy the listeners from
+       */
+       void copyListeners(const SkEventSink& from);
+       /**     Remove sinkID from the list of listeners. If sinkID does not appear in the list,
+               no change is made.
+       */
+       void    removeListenerID(SkEventSinkID);
+       /**     Returns true if there are 1 or more listeners attached to this eventsink
+       */
+       bool    hasListeners() const;
+       /**     Posts a copy of evt to each of the eventsinks in the lisener list.
+       */
+       void    postToListeners(const SkEvent& evt, SkMSec delay = 0);
+
+       enum EventResult {
+               kHandled_EventResult,           //!< the eventsink returned true from its doEvent method
+               kNotHandled_EventResult,        //!< the eventsink returned false from its doEvent method
+               kSinkNotFound_EventResult       //!< no matching eventsink was found for the event's getSink().
+       };
+       /**     DoEvent handles searching for an eventsink object that matches the targetID.
+               If one is found, it calls the sink's doEvent method, returning
+               either kHandled_EventResult or kNotHandled_EventResult. If no matching
+               eventsink is found, kSinkNotFound_EventResult is returned.
+       */
+       static EventResult DoEvent(const SkEvent&, SkEventSinkID targetID);
+
+       /** Returns the matching eventsink, or nil if not found
+       */
+       static SkEventSink*     FindSink(SkEventSinkID);
+
+protected:
+       /**     Override this to handle events in your subclass. Be sure to call the inherited version
+               for events that you don't handle.
+       */
+       virtual bool onEvent(const SkEvent&);
+       virtual bool onQuery(SkEvent*);
+
+       SkTagList*      findTagList(U8CPU tag) const;
+       void            addTagList(SkTagList*);
+       void            removeTagList(U8CPU tag);
+
+private:
+       SkEventSinkID   fID;
+       SkTagList*              fTagHead;
+
+       // for our private link-list
+       SkEventSink*    fNextSink;
+};
+
+#endif
+
diff --git a/include/graphics/SkFlattenable.h b/include/graphics/SkFlattenable.h
new file mode 100644 (file)
index 0000000..b68a361
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef SkFlattenable_DEFINED
+#define SkFlattenable_DEFINED
+
+#include "SkRefCnt.h"
+#include "SkBuffer.h"
+
+/**    \class SkFlattenable
+
+       SkFlattenable is the base class for objects that need to be flattened
+       into a data stream for either transport or as part of the key to the
+       font cache.
+*/
+//  This class is not exported to java.
+class SkFlattenable : public SkRefCnt {
+public:
+       typedef SkFlattenable* (*Factory)(SkRBuffer&);
+
+       virtual Factory getFactory();
+       virtual void    flatten(SkWBuffer&);
+};
+
+#endif
+
diff --git a/include/graphics/SkFontCodec.h b/include/graphics/SkFontCodec.h
new file mode 100644 (file)
index 0000000..5dc8738
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef SkFontCodec_DEFINED
+#define SkFontCodec_DEFINED
+
+#include "SkSFNT.h"
+
+class SkFontCodec {
+public:
+       static void Compress(SkSFNT& font, const char fileName[]);
+
+       /*      Format is [count] + [instruction, bitcount] * count
+               Allocated with sk_malloc()
+       */
+       static U8* BuildInstrHuffmanTable(SkSFNT&);
+       static U8* BuildOutlineHuffmanTable(SkSFNT& font);
+
+       SkDEBUGCODE(static void UnitTest();)
+};
+
+#endif
+
diff --git a/include/graphics/SkFontHost.h b/include/graphics/SkFontHost.h
new file mode 100644 (file)
index 0000000..3b3eacd
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef SkFontHost_DEFINED
+#define SkFontHost_DEFINED
+
+#include "SkScalerContext.h"
+#include "SkTypeface.h"
+
+class SkDescriptor;
+
+/** \class SkFontHost
+
+       This class is ported to each environment. It is responsible for bridging the gap
+    between SkTypeface and the resulting platform-specific instance of SkScalerContext.
+*/
+class SkFontHost {
+public:
+       /**     Return a subclass of SkTypeface, one that can be used by your scalaracontext
+               (returned by SkFontHost::CreateScalarContext).
+        1) If family is nil, use name.
+        2) If name is nil, use family.
+        3) If both are nil, use default family.
+       */
+       static SkTypeface* CreateTypeface(const SkTypeface* family, const char name[], SkTypeface::Style);
+       /** Given a typeface (or nil), return the number of bytes needed to flatten it
+        into a buffer, for the purpose of communicating information to the
+        scalercontext. If buffer is nil, then ignore it but still return the number
+        of bytes that would be written.
+    */
+       static uint32_t FlattenTypeface(const SkTypeface* face, void* buffer);
+       /**     Return a subclass of SkScalarContext
+       */
+       static SkScalerContext* CreateScalerContext(const SkDescriptor* desc);
+    
+    enum ScalerContextID {
+        kMissing_ScalerContextID = SK_UnknownAuxScalerContextID,
+        kMax_ScalerContextID = SK_MaxAuxScalerContextID
+    };
+    static ScalerContextID FindScalerContextIDForUnichar(int32_t unichar);
+
+    static SkScalerContext* CreateScalerContextFromID(ScalerContextID, const SkScalerContext::Rec&);
+};
+
+#endif
+
diff --git a/include/graphics/SkGlobals.h b/include/graphics/SkGlobals.h
new file mode 100644 (file)
index 0000000..8ac0d31
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef SkGlobals_DEFINED
+#define SkGlobals_DEFINED
+
+#include "SkThread.h"
+
+class SkGlobals {
+public:
+       class Rec {
+       public:
+               virtual ~Rec();
+       private:
+               Rec*    fNext;
+               U32             fTag;
+
+               friend class SkGlobals;
+       };
+
+       /**     Look for a matching Rec for the specified tag. If one is found, return it.
+               If one is not found, if create_proc is nil, return nil, else
+               call the proc, and if it returns a Rec, add it to the global list
+               and return it.
+
+               create_proc can NOT call back into SkGlobals::Find (it would deadlock)
+       */
+       static Rec*     Find(U32 tag, Rec* (*create_proc)());
+       /**     Helper for Find, when you want to assert that the Rec is already in the list
+       */
+       static Rec* Get(U32 tag)
+       {
+               Rec* rec = SkGlobals::Find(tag, nil);
+               SkASSERT(rec);
+               return rec;
+       }
+
+       // used by porting layer
+       struct BootStrap {
+               SkMutex fMutex;
+               Rec*    fHead;
+       };
+
+private:
+       static void     Init();
+       static void Term();
+       friend class SkGraphics;
+
+       //      This last function is implemented in the porting layer
+       static BootStrap& GetBootStrap();
+};
+
+#endif
+
diff --git a/include/graphics/SkGradientShader.h b/include/graphics/SkGradientShader.h
new file mode 100644 (file)
index 0000000..7e5a722
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef SkGradientShader_DEFINED
+#define SkGradientShader_DEFINED
+
+#include "SkShader.h"
+
+class SkUnitMapper;
+
+/**    \class SkGradientShader
+
+       SkGradientShader hosts factories for creating subclasses of SkShader that
+       render linear and radial gradients.
+*/
+class SkGradientShader : public SkShader {
+public:
+       /**     Returns a shader that generates a linear gradient between the two
+               specified points.
+               <p />
+               CreateLinear returns a shader with a reference count of 1.
+               The caller should decrement the shader's reference count when done with the shader.
+               It is an error for count to be < 2.
+        @param  pts The start and end points for the gradient.
+        @param  colors  The array[count] of colors, to be distributed between the two points
+        @param  pos     May be NULL. array[count] of SkScalars, or NULL, of the relative position of
+                        each corresponding color in the colors array. If this is NULL,
+                        the the colors are distributed evenly between the start and end point.
+        @param  count   Must be >=2. The number of colors (and pos if not NULL) entries. 
+        @param  mode    The tiling mode
+        @param  mapper  May be NULL. Callback to modify the spread of the colors.
+       */
+       static SkShader* CreateLinear(  const SkPoint pts[2],
+                                                                       const SkColor colors[], const SkScalar pos[], int count,
+                                                                       TileMode mode,
+                                                                       SkUnitMapper* mapper = NULL);
+
+       /**     Returns a shader that generates a radial gradient given the center and radius.
+               <p />
+               CreateRadial returns a shader with a reference count of 1.
+               The caller should decrement the shader's reference count when done with the shader.
+               It is an error for colorCount to be < 2, or for radius to be <= 0.
+        @param  center  The center of the circle for this gradient
+        @param  radius  Must be positive. The radius of the circle for this gradient
+        @param  colors  The array[count] of colors, to be distributed between the center and edge of the circle
+        @param  pos     May be NULL. The array[count] of SkScalars, or NULL, of the relative position of
+                        each corresponding color in the colors array. If this is NULL,
+                        the the colors are distributed evenly between the center and edge of the circle.
+        @param  count   Must be >= 2. The number of colors (and pos if not NULL) entries
+        @param  mode    The tiling mode
+        @param  mapper  May be NULL. Callback to modify the spread of the colors.
+       */
+       static SkShader* CreateRadial(  const SkPoint& center, SkScalar radius,
+                                                                       const SkColor colors[], const SkScalar pos[], int count,
+                                                                       TileMode mode,
+                                                                       SkUnitMapper* mapper = NULL);
+};
+
+#endif
+
diff --git a/include/graphics/SkGraphics.h b/include/graphics/SkGraphics.h
new file mode 100644 (file)
index 0000000..96c3f11
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef SkGraphics_DEFINED
+#define SkGraphics_DEFINED
+
+#include "SkTypes.h"
+
+class SkGraphics {
+public:
+       static void Init(bool runUnitTests);
+       static void Term();
+
+       /**     Call this if the heap that the graphics engine uses is low on memory.
+               It will attempt to free some of its caches. Returns true if it was
+               able to, or false if it could do nothing.
+
+               This may be called from any thread, and guarantees not to call
+               new or sk_malloc (though it will hopefully call delete and/or sk_free).
+               It also will never throw an exception.
+       */
+       static bool FreeCaches(size_t bytesNeeded);
+
+private:
+       /**     This is automatically called by SkGraphics::Init(), and must be
+               implemented by the host OS. This allows the host OS to register a callback
+               with the C++ runtime to call SkGraphics::FreeCaches()
+       */
+       static void InstallNewHandler();
+};
+
+#endif
+
diff --git a/include/graphics/SkImageDecoder.h b/include/graphics/SkImageDecoder.h
new file mode 100644 (file)
index 0000000..e5c7f3c
--- /dev/null
@@ -0,0 +1,130 @@
+#ifndef SkImageDecoder_DEFINED
+#define SkImageDecoder_DEFINED
+
+#include "SkBitmap.h"
+#include "SkBitmapRef.h"
+
+class SkStream;
+
+/**    \class SkImageDecoder
+
+       Base class for decoding compressed images into a SkBitmap
+*/
+class SkImageDecoder {
+public:
+       virtual ~SkImageDecoder();
+
+       /**     Decode the image stored in the specified file, and store the result
+               in bitmap. Return true for success or false on failure.
+
+               If pref is kNo_Config, then the decoder is free to choose the most natural
+        config given the image data. If pref something other than kNo_Config,
+               the decoder will attempt to decode the image into that format, unless
+               there is a conflict (e.g. the image has per-pixel alpha and the bitmap's
+               config does not support that), in which case the decoder will choose a
+               closest match configuration.
+       */
+       static bool DecodeFile(const char file[], SkBitmap* bitmap,
+                           SkBitmap::Config pref = SkBitmap::kNo_Config);
+       /**     Decode the image stored in the specified memory buffer, and store the result
+               in bitmap. Return true for success or false on failure.
+
+               If pref is kNo_Config, then the decoder is free to choose the most natural
+        config given the image data. If pref something other than kNo_Config,
+               the decoder will attempt to decode the image into that format, unless
+               there is a conflict (e.g. the image has per-pixel alpha and the bitmap's
+               config does not support that), in which case the decoder will choose a
+               closest match configuration.
+       */
+       static bool DecodeMemory(const void* buffer, size_t size, SkBitmap* bitmap,
+                             SkBitmap::Config pref = SkBitmap::kNo_Config);
+       /**     Decode the image stored in the specified SkStream, and store the result
+               in bitmap. Return true for success or false on failure.
+
+               If pref is kNo_Config, then the decoder is free to choose the most natural
+        config given the image data. If pref something other than kNo_Config,
+               the decoder will attempt to decode the image into that format, unless
+               there is a conflict (e.g. the image has per-pixel alpha and the bitmap's
+               config does not support that), in which case the decoder will choose a
+               closest match configuration.
+       */
+       static bool DecodeStream(SkStream*, SkBitmap* bitmap,
+                             SkBitmap::Config pref = SkBitmap::kNo_Config);
+
+       /**     Decode the image stored at the specified URL, and store the result
+               in bitmap. Return true for success or false on failure. The URL restrictions
+               are device dependent. On Win32 and WinCE, the URL may be ftp, http or
+               https.
+
+               If pref is kNo_Config, then the decoder is free to choose the most natural
+        config given the image data. If pref something other than kNo_Config,
+               the decoder will attempt to decode the image into that format, unless
+               there is a conflict (e.g. the image has per-pixel alpha and the bitmap's
+               config does not support that), in which case the decoder will choose a
+               closest match configuration.
+       */
+       static bool DecodeURL(const char url[], SkBitmap* bitmap,
+                          SkBitmap::Config pref = SkBitmap::kNo_Config);
+
+       /**     Return the default config for the running device.
+               Currently this used as a suggestion to image decoders that need to guess
+               what config they should decode into.
+               Default is kNo_Config, but this can be changed with SetDeviceConfig()
+       */
+       static SkBitmap::Config GetDeviceConfig();
+       /**     Set the default config for the running device.
+               Currently this used as a suggestion to image decoders that need to guess
+               what config they should decode into.
+               Default is kNo_Config.
+               This can be queried with GetDeviceConfig()
+       */
+       static void     SetDeviceConfig(SkBitmap::Config);
+
+  /** @cond UNIT_TEST */
+       SkDEBUGCODE(static void UnitTest();)
+  /** @endcond */
+
+protected:
+       SkImageDecoder();
+
+       /**     Given a stream, decode it into the specified bitmap.
+               If the decoder can decompress the image, it should call setConfig() on the bitmap,
+        and then call allocPixels(), which will allocated offscreen memory for the pixels.
+        It can then set the pixels with the decompressed image. If the image cannot be
+        decompressed, return false and leave the bitmap unchanged.
+       */
+       virtual bool onDecode(SkStream*, SkBitmap* bitmap, SkBitmap::Config pref) = 0;
+
+private:
+       static SkImageDecoder* Factory(SkStream*);
+};
+
+#ifdef SK_SUPPORT_IMAGE_ENCODE
+
+class SkWStream;
+
+class SkImageEncoder {
+public:
+       enum Type {
+               kJPEG_Type,
+               kPNG_Type
+       };
+       static SkImageEncoder* Create(Type);
+
+       virtual ~SkImageEncoder();
+
+       /*      Quality ranges from 0..100 */
+
+       bool encodeFile(const char file[], const SkBitmap&, int quality = 80);
+       bool encodeStream(SkWStream*, const SkBitmap&, int quality = 80);
+
+protected:
+       virtual bool onEncode(SkWStream*, const SkBitmap&, int quality) = 0;
+};
+
+#endif /* SK_SUPPORT_IMAGE_ENCODE */
+
+///////////////////////////////////////////////////////////////////////
+
+#endif
+
diff --git a/include/graphics/SkImageView.h b/include/graphics/SkImageView.h
new file mode 100644 (file)
index 0000000..78ee5b7
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef SkImageView_DEFINED
+#define SkImageView_DEFINED
+
+#include "SkView.h"
+#include "SkString.h"
+
+class SkAnimator;
+class SkBitmap;
+struct SkMatrix;
+
+class SkImageView : public SkView {
+public:
+                       SkImageView();
+       virtual ~SkImageView();
+
+       void    getUri(SkString*) const;
+       void    setUri(const char []);
+       void    setUri(const SkString&);
+       
+
+       enum ScaleType {
+               kMatrix_ScaleType,
+               kFitXY_ScaleType,
+               kFitStart_ScaleType,
+               kFitCenter_ScaleType,
+               kFitEnd_ScaleType
+       };
+       ScaleType       getScaleType() const { return (ScaleType)fScaleType; }
+       void            setScaleType(ScaleType);
+       
+       bool    getImageMatrix(SkMatrix*) const;
+       void    setImageMatrix(const SkMatrix*);
+
+protected:
+       // overrides
+       virtual bool    onEvent(const SkEvent&);
+       virtual void    onDraw(SkCanvas*);
+       virtual void    onInflate(const SkDOM&, const SkDOMNode*);
+       
+private:
+       SkString        fUri;
+       SkMatrix*       fMatrix;        // nil or copy of caller's matrix ,,,,,
+       union {
+               SkAnimator*     fAnim;
+               SkBitmap* fBitmap;
+       } fData;
+       U8                      fScaleType;
+       SkBool8         fDataIsAnim;    // as opposed to bitmap
+       SkBool8         fUriIsValid;
+       
+       void    onUriChange();
+       bool    getDataBounds(SkRect* bounds);
+       bool    freeData();
+       bool    ensureUriIsLoaded();
+
+       typedef SkView INHERITED;
+};
+
+#endif
diff --git a/include/graphics/SkInterpolator.h b/include/graphics/SkInterpolator.h
new file mode 100644 (file)
index 0000000..c224c8c
--- /dev/null
@@ -0,0 +1,98 @@
+#ifndef SkInterpolator_DEFINED
+#define SkInterpolator_DEFINED
+
+#include "SkMath.h"
+
+class SkInterpolatorBase {
+public:
+       enum Result {
+               kNormal_Result,
+               kFreezeStart_Result,
+               kFreezeEnd_Result
+       };
+       static SkScalar Blend(SkScalar t, SkScalar blend);
+protected:
+       SkInterpolatorBase();
+       ~SkInterpolatorBase();
+public:
+       void    reset(int elemCount, int frameCount);
+
+       /**     Return the start and end time for this interpolator.
+               If there are no key frames, return false.
+               @param  startTime       If no nil, returns the time (in milliseconds) of the
+                                                       first keyframe. If there are no keyframes, this parameter
+                                                       is ignored (left unchanged).
+               @param  endTime         If no nil, returns the time (in milliseconds) of the
+                                                       last keyframe. If there are no keyframes, this parameter
+                                                       is ignored (left unchanged).
+               @return True if there are key frames, or false if there are none.
+       */
+       bool    getDuration(SkMSec* startTime, SkMSec* endTime) const;
+
+
+       /**     Set the whether the repeat is mirrored.
+               @param If true, the odd repeats interpolate from the last key frame and the first.
+       */
+       void    setMirror(bool mirror) { fFlags = SkToU8(fFlags & ~kMirror | (int) mirror); }
+
+       /**     Set the repeat count. The repeat count may be fractional.
+               @param repeatCount Multiplies the total time by this scalar.
+       */
+       void    setRepeatCount(SkScalar repeatCount) { fRepeat = repeatCount; }
+
+       /**     Set the whether the repeat is mirrored.
+               @param If true, the odd repeats interpolate from the last key frame and the first.
+       */
+       void    setReset(bool reset) { fFlags = SkToU8(fFlags & ~kReset | (int) reset); }
+
+       Result  timeToT(SkMSec time, SkScalar* T, int* index, SkBool* exact) const;
+protected:
+       enum Flags {
+               kMirror = 1,
+               kReset = 2
+       };
+       static SkScalar ComputeRelativeT(SkMSec time, SkMSec prevTime, SkMSec nextTime, SkScalar blend);
+       S16 fFrameCount;
+       U8 fElemCount;
+       U8 fFlags;
+       SkScalar fRepeat;
+       struct SkTimeCode {
+               SkMSec fTime;
+               SkScalar fBlend;
+       };
+       SkTimeCode* fTimes;             // pointer into fStorage
+       void* fStorage;
+#ifdef SK_DEBUG
+       SkTimeCode(* fTimesArray)[10];
+#endif
+};
+
+class SkInterpolator : public SkInterpolatorBase {
+public:
+       SkInterpolator();
+       SkInterpolator(int elemCount, int frameCount);
+       void    reset(int elemCount, int frameCount);
+
+       /**     Add or replace a key frame, copying the values[] data into the interpolator.
+               @param index    The index of this frame (frames must be ordered by time)
+               @param time     The millisecond time for this frame
+               @param values   The array of values [elemCount] for this frame. The data is copied
+                                               into the interpolator.
+               @param blend    A positive scalar specifying how to blend between this and the next key frame.
+                                               [0...1) is a cubic lag/log/lag blend (slow to change at the beginning and end)
+                                               1 is a linear blend (default)
+       */
+       bool    setKeyFrame(int index, SkMSec time, const SkScalar values[], SkScalar blend = SK_Scalar1);
+       Result timeToValues(SkMSec time, SkScalar values[]) const;
+       SkDEBUGCODE(static void UnitTest();)
+private:
+       SkScalar* fValues;      // pointer into fStorage
+#ifdef SK_DEBUG
+       SkScalar(* fScalarsArray)[10];
+#endif
+       typedef SkInterpolatorBase INHERITED;
+};
+
+
+#endif
+
diff --git a/include/graphics/SkJS.h b/include/graphics/SkJS.h
new file mode 100644 (file)
index 0000000..89fa4d7
--- /dev/null
@@ -0,0 +1,31 @@
+#include "SkTypes.h"
+#include "SkWindow.h"
+
+extern "C" {
+       typedef long JSWord;
+       typedef JSWord jsword;
+       typedef jsword  jsval;
+       typedef struct JSRuntime JSRuntime;
+       typedef struct JSContext JSContext;
+       typedef struct JSObject JSObject;
+}
+
+class SkString;
+
+class SkJS : public SkOSWindow {
+public:
+       SkJS(void* hwnd);
+       ~SkJS();
+       SkBool EvaluateScript(const char* script, jsval* rVal);
+       SkBool ValueToString(jsval value, SkString* string);
+#ifdef SK_DEBUG
+       static void Test(void* hwnd);
+#endif
+protected:
+       void InitializeDisplayables(const SkBitmap& , JSContext *, JSObject *, JSObject *);
+       void DisposeDisplayables();
+       JSRuntime *fRuntime;
+    JSContext *fContext;
+       JSObject *fGlobal;
+};
+
diff --git a/include/graphics/SkKey.h b/include/graphics/SkKey.h
new file mode 100644 (file)
index 0000000..4a1297c
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef SkKey_DEFINED
+#define SkKey_DEFINED
+
+#include "SkTypes.h"
+
+enum SkKey {
+    //reordering these to match android.app.KeyEvent 
+       kNONE_SkKey,    //corresponds to android's UNKNOWN
+    
+       kLeftSoftKey_SkKey,
+       kRightSoftKey_SkKey,
+
+    kHome_SkKey,    //!< the home key - added to match android
+    kBack_SkKey,       //!< (CLR)
+       kSend_SkKey,    //!< the green (talk) key
+       kEnd_SkKey,             //!< the red key
+    
+       k0_SkKey,
+       k1_SkKey,
+       k2_SkKey,
+       k3_SkKey,
+       k4_SkKey,
+       k5_SkKey,
+       k6_SkKey,
+       k7_SkKey,
+       k8_SkKey,
+       k9_SkKey,
+       kStar_SkKey,    //!< the * key
+       kHash_SkKey,    //!< the # key
+
+       kUp_SkKey,
+       kDown_SkKey,
+       kLeft_SkKey,
+       kRight_SkKey,
+
+       kOK_SkKey,              //!< the center key
+
+    kVolUp_SkKey,   //!< volume up - match android
+    kVolDown_SkKey, //!< volume down - same
+    kPower_SkKey,   //!< power button - same
+    kCamera_SkKey,  //!< camera         - same
+
+       kSkKeyCount
+};
+
+#endif
+
diff --git a/include/graphics/SkLayerRasterizer.h b/include/graphics/SkLayerRasterizer.h
new file mode 100644 (file)
index 0000000..548968a
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef SkLayerRasterizer_DEFINED
+#define SkLayerRasterizer_DEFINED
+
+#include "SkRasterizer.h"
+#include "SkDeque.h"
+#include "SkScalar.h"
+
+class SkPaint;
+
+class SkLayerRasterizer : public SkRasterizer {
+public:
+            SkLayerRasterizer();
+    virtual ~SkLayerRasterizer();
+    
+    void addLayer(const SkPaint& paint)
+    {
+        this->addLayer(paint, 0, 0);
+    }
+    void addLayer(const SkPaint& paint, SkScalar dx, SkScalar dy);
+
+    // overrides from SkFlattenable
+       virtual Factory getFactory();
+       virtual void    flatten(SkWBuffer&);
+
+protected:
+    SkLayerRasterizer(SkRBuffer&);
+
+    // override from SkRasterizer
+    virtual bool onRasterize(const SkPath& path, const SkMatrix& matrix,
+                             const SkRect16* clipBounds,
+                             SkMask* mask, SkMask::CreateMode mode);
+
+private:
+    SkDeque fLayers;
+    
+    static SkFlattenable* CreateProc(SkRBuffer&);
+
+    typedef SkRasterizer INHERITED;
+};
+
+#endif
diff --git a/include/graphics/SkMask.h b/include/graphics/SkMask.h
new file mode 100644 (file)
index 0000000..8fdf461
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef SkMask_DEFINED
+#define SkMask_DEFINED
+
+#include "SkRect.h"
+
+/**    \class SkMask
+       SkMask is used to describe alpha bitmaps, either 1bit, 8bit, or
+       the 3-channel 3D format. These are passed to SkMaskFilter objects.
+*/
+struct SkMask {
+       enum Format {
+               kBW_Format,     //!< 1bit per pixel mask (e.g. monochrome)
+               kA8_Format,     //!< 8bits per pixel mask (e.g. antialiasing)
+               k3D_Format      //!< 3 8bit per pixl planes: alpha, mul, add
+       };
+
+       uint8_t*        fImage;
+       SkRect16        fBounds;
+       uint16_t        fRowBytes;
+       uint8_t         fFormat;        // Format
+
+       /**     Return the byte size of the mask, assuming only 1 plane.
+               Does not account for k3D_Format. For that, use computeFormatImageSize()
+       */
+       size_t computeImageSize() const;
+       /**     Return the byte size of the mask, taking into account
+               any extra planes (e.g. k3D_Format).
+       */
+       size_t computeTotalImageSize() const;
+
+       /**     Returns the address of the byte that holds the specified bit.
+               Asserts that the mask is kBW_Format, and that x,y are in range.
+               x,y are in the same coordiate space as fBounds.
+       */
+       uint8_t* getAddr1(int x, int y) const
+       {
+               SkASSERT(fFormat == kBW_Format);
+               SkASSERT(fBounds.contains(x, y));
+               SkASSERT(fImage != nil);
+               return fImage + ((x - fBounds.fLeft) >> 3) + (y - fBounds.fTop) * fRowBytes;
+       }
+       /**     Returns the address of the specified byte.
+               Asserts that the mask is kA8_Format, and that x,y are in range.
+               x,y are in the same coordiate space as fBounds.
+       */
+       uint8_t* getAddr(int x, int y) const
+       {
+               SkASSERT(fFormat != kBW_Format);
+               SkASSERT(fBounds.contains(x, y));
+               SkASSERT(fImage != nil);
+               return fImage + x - fBounds.fLeft + (y - fBounds.fTop) * fRowBytes;
+       }
+
+       static uint8_t* AllocImage(size_t bytes);
+       static void     FreeImage(uint8_t* image);
+    
+    enum CreateMode {
+        kJustComputeBounds_CreateMode,      //!< compute bounds and return
+        kJustRenderImage_CreateMode,        //!< render into preallocate mask
+        kComputeBoundsAndRenderImage_CreateMode  //!< compute bounds, alloc image and render into it
+    };
+};
+
+#endif
+
diff --git a/include/graphics/SkMaskFilter.h b/include/graphics/SkMaskFilter.h
new file mode 100644 (file)
index 0000000..f844e36
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef SkMaskFilter_DEFINED
+#define SkMaskFilter_DEFINED
+
+#include "SkFlattenable.h"
+#include "SkMask.h"
+
+class SkBlitter;
+class SkBounder;
+class SkMatrix;
+class SkPath;
+class SkRegion;
+
+/**    \class SkMaskFilter
+
+       SkMaskFilter is the base class for object that perform transformations on
+       an alpha-channel mask before drawing it. A subclass of SkMaskFilter may be
+       installed into a SkPaint. Once there, each time a primitive is drawn, it
+       is first scan converted into a SkMask::kA8_Format mask, and handed to the
+       filter, calling its filterMask() method. If this returns true, then the
+       new mask is used to render into the device.
+
+       Blur and emboss are implemented as subclasses of SkMaskFilter.
+*/
+class SkMaskFilter : public SkFlattenable {
+public:
+    SkMaskFilter() {}
+
+       /**     Returns the format of the resulting mask that this subclass will return
+               when its filterMask() method is called.
+       */
+       virtual SkMask::Format  getFormat() = 0;
+
+       /**     Create a new mask by filter the src mask.
+               If src.fImage == nil, then do not allocate or create the dst image
+               but do fill out the other fields in dstMask.
+               If you do allocate a dst image, use SkMask::AllocImage()
+               If this returns false, dst mask is ignored.
+               @param  dst     the result of the filter. If src.fImage == nil, dst should not allocate its image
+               @param src the original image to be filtered.
+               @param matrix the CTM
+               @param margin   if not nil, return the buffer dx/dy need when calculating the effect. Used when
+                                               drawing a clipped object to know how much larger to allocate the src before
+                                               applying the filter.
+               @return true if the dst mask was correctly created.
+       */
+       virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, SkPoint16* margin);
+
+       /**     Helper method that, given a path in device space, will rasterize it into a kA8_Format mask
+               and then call filterMask(). If this returns true, the specified blitter will be called
+               to render that mask. Returns false if filterMask() returned false.
+        This method is not exported to java.
+       */
+       bool filterPath(const SkPath& devPath, const SkMatrix& devMatrix,
+                                       const SkRegion& devClip, SkBounder*, SkBlitter* blitter);
+
+protected:
+    // empty for now, but lets get our subclass to remember to init us for the future
+    SkMaskFilter(SkRBuffer&) {}
+};
+
+/**    \class SkAutoMaskImage
+
+       Stack class used to manage the fImage buffer in a SkMask.
+       When this object loses scope, the buffer is freed with SkMask::FreeImage().
+*/
+class SkAutoMaskImage {
+public:
+       SkAutoMaskImage(SkMask* mask, bool alloc)
+       {
+               if (alloc)
+                       mask->fImage = SkMask::AllocImage(mask->computeImageSize());
+               fImage = mask->fImage;
+       }
+       ~SkAutoMaskImage()
+       {
+               SkMask::FreeImage(fImage);
+       }
+private:
+       uint8_t*    fImage;
+};
+
+#endif
+
diff --git a/include/graphics/SkMetaData.h b/include/graphics/SkMetaData.h
new file mode 100644 (file)
index 0000000..b3b80eb
--- /dev/null
@@ -0,0 +1,138 @@
+#ifndef SkMetaData_DEFINED
+#define SkMetaData_DEFINED
+
+#include "SkMath.h"
+
+class SkMetaData {
+public:
+       SkMetaData();
+       SkMetaData(const SkMetaData& src);
+       ~SkMetaData();
+
+       SkMetaData&     operator=(const SkMetaData& src);
+
+       void    reset();
+
+       bool    findS32(const char name[], int32_t* value = nil) const;
+       bool    findScalar(const char name[], SkScalar* value = nil) const;
+       const SkScalar* findScalars(const char name[], int* count, SkScalar values[] = nil) const;
+       const char*     findString(const char name[]) const;
+       bool    findPtr(const char name[], void** value = nil) const;
+       bool    findBool(const char name[], bool* value = nil) const;
+
+       bool    hasS32(const char name[], int32_t value) const
+       {
+               int32_t v;
+               return this->findS32(name, &v) && v == value;
+       }
+       bool    hasScalar(const char name[], SkScalar value) const
+       {
+               SkScalar        v;
+               return this->findScalar(name, &v) && v == value;
+       }
+       bool    hasString(const char name[], const char value[]) const
+       {
+               const char* v = this->findString(name);
+               return  v == nil && value == nil ||
+                               v != nil && value != nil && !strcmp(v, value);
+       }
+       bool    hasPtr(const char name[], void* value) const
+       {
+               void*   v;
+               return this->findPtr(name, &v) && v == value;
+       }
+       bool    hasBool(const char name[], bool value) const
+       {
+               bool    v;
+               return this->findBool(name, &v) && v == value;
+       }
+
+       void    setS32(const char name[], int32_t value);
+       void    setScalar(const char name[], SkScalar value);
+       SkScalar* setScalars(const char name[], int count, const SkScalar values[] = nil);
+       void    setString(const char name[], const char value[]);
+       void    setPtr(const char name[], void* value);
+       void    setBool(const char name[], bool value);
+
+       bool    removeS32(const char name[]);
+       bool    removeScalar(const char name[]);
+       bool    removeString(const char name[]);
+       bool    removePtr(const char name[]);
+       bool    removeBool(const char name[]);
+
+       SkDEBUGCODE(static void UnitTest();)
+
+       enum Type {
+               kS32_Type,
+               kScalar_Type,
+               kString_Type,
+               kPtr_Type,
+               kBool_Type,
+
+               kTypeCount
+       };
+
+       struct Rec;
+       class Iter;
+       friend class Iter;
+
+       class Iter {
+       public:
+               Iter() : fRec(nil) {}
+               Iter(const SkMetaData&);
+
+               /**     Reset the iterator, so that calling next() will return the first
+                       data element. This is done implicitly in the constructor.
+               */
+               void    reset(const SkMetaData&);
+
+               /**     Each time next is called, it returns the name of the next data element,
+                       or nil when there are no more elements. If non-nil is returned, then the
+                       element's type is returned (if not nil), and the number of data values
+                       is returned in count (if not nil).
+               */
+               const char*     next(Type*, int* count);
+
+       private:
+               Rec* fRec;
+       };
+
+public:
+       struct Rec {
+               Rec*        fNext;
+               uint16_t        fDataCount;     // number of elements
+               uint8_t         fDataLen;       // sizeof a single element
+#ifdef SK_DEBUG
+               Type            fType;
+#else
+               uint8_t         fType;
+#endif
+
+#ifdef SK_DEBUG
+               const char* fName;
+               union {
+                       int32_t     fS32;
+                       SkScalar        fScalar;
+                       const char*     fString;
+                       void*           fPtr;
+                       bool            fBool;
+               } fData;
+#endif
+
+               const void*     data() const { return (this + 1); }
+               void*           data() { return (this + 1); }
+               const char*     name() const { return (const char*)this->data() + fDataLen * fDataCount; }
+               char*           name() { return (char*)this->data() + fDataLen * fDataCount; }
+
+               static Rec* Alloc(size_t);
+               static void Free(Rec*);
+       };
+       Rec*    fRec;
+
+       const Rec* find(const char name[], Type) const;
+       void* set(const char name[], const void* data, size_t len, Type, int count);
+       bool remove(const char name[], Type);
+};
+
+#endif
+
diff --git a/include/graphics/SkNinePatch.h b/include/graphics/SkNinePatch.h
new file mode 100644 (file)
index 0000000..5cc48c1
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef SkNinePatch_DEFINED
+#define SkNinePatch_DEFINED
+
+#include "SkRect.h"
+
+class SkBitmap;
+class SkCanvas;
+class SkPaint;
+
+class SkNinePatch {
+public:
+    static void Draw(SkCanvas* canvas, const SkRect& dst,
+                     const SkBitmap& bitmap, const SkRect16& margin,
+                     const SkPaint* paint = NULL);
+
+    static void Draw(SkCanvas* canvas, const SkRect& dst,
+                     const SkBitmap& bitmap, int cx, int cy,
+                     const SkPaint* paint = NULL);
+};
+
+#endif
diff --git a/include/graphics/SkOSFile.h b/include/graphics/SkOSFile.h
new file mode 100644 (file)
index 0000000..6baef7d
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright Skia Inc. 2004 - 2005
+// 
+#ifndef SkOSFile_DEFINED
+#define SkOSFile_DEFINED
+
+#include "SkString.h"
+
+#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
+       #include <dirent.h>
+#endif
+
+struct SkFILE;
+
+enum SkFILE_Flags {
+       kRead_SkFILE_Flag       = 0x01,
+       kWrite_SkFILE_Flag      = 0x02
+};
+
+SkFILE*        sk_fopen(const char path[], SkFILE_Flags);
+void   sk_fclose(SkFILE*);
+
+size_t sk_fgetsize(SkFILE*);
+/**    Return true if the file could seek back to the beginning
+*/
+bool   sk_frewind(SkFILE*);
+
+size_t sk_fread(void* buffer, size_t byteCount, SkFILE*);
+size_t sk_fwrite(const void* buffer, size_t byteCount, SkFILE*);
+void   sk_fflush(SkFILE*);
+
+int            sk_fseek( SkFILE*, size_t, int );
+size_t sk_ftell( SkFILE* );
+
+class SkOSFile {
+public:
+       class Iter {
+       public:
+               Iter();
+               Iter(const char path[], const char suffix[] = nil);
+               ~Iter();
+
+               void reset(const char path[], const char suffix[] = nil);
+               bool next(SkString* name, bool getDir = false);
+
+       private:
+#ifdef SK_BUILD_FOR_WIN
+               HANDLE          fHandle;
+               U16*            fPath16;
+#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
+               DIR*            fDIR;
+               SkString        fPath, fSuffix;
+#endif
+       };
+};
+
+class SkUTF16_Str {
+public:
+       SkUTF16_Str(const char src[]);
+       ~SkUTF16_Str()
+       {
+               sk_free(fStr);
+       }
+       const U16* get() const { return fStr; }
+
+private:
+       U16*    fStr;
+};
+
+#endif
+
diff --git a/include/graphics/SkOSMenu.h b/include/graphics/SkOSMenu.h
new file mode 100644 (file)
index 0000000..4cf52e7
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef SkOSMenu_DEFINED
+#define SkOSMenu_DEFINED
+
+#include "SkEvent.h"
+#include "SkTDArray.h"
+
+class SkOSMenu {
+public:
+       explicit SkOSMenu(const char title[]);
+       ~SkOSMenu();
+
+       const char*     getTitle() const { return fTitle; }
+
+       void    appendItem(const char title[], const char eventType[], S32 eventData);
+
+       // called by SkOSWindow when it receives an OS menu event
+       int             countItems() const;
+       const char*     getItem(int index, U32* cmdID) const;
+
+       SkEvent* createEvent(U32 os_cmd);
+
+private:
+       const char*     fTitle;
+
+       struct Item {
+               const char*     fTitle;
+               const char*     fEventType;
+               U32                     fEventData;
+               U32                     fOSCmd; // internal
+       };
+       SkTDArray<Item> fItems;
+
+       // illegal
+       SkOSMenu(const SkOSMenu&);
+       SkOSMenu& operator=(const SkOSMenu&);
+};
+
+#endif
+
diff --git a/include/graphics/SkOSSound.h b/include/graphics/SkOSSound.h
new file mode 100644 (file)
index 0000000..2e4262b
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef SkOSSound_DEFINED
+#define SkOSSound_DEFINED
+
+#include "SkTypes.h"
+
+class SkOSSound {
+public:
+       static void Play(const char path[]);
+       static void Pause();
+       static void Resume();
+       static bool TogglePause();      // returns true if we are now playing, or false if we're now paused
+       static void Stop();
+
+       //      volume runs from 0 (silent) to 0xFF (max-volume)
+       static U8       GetVolume();
+       static void SetVolume(U8CPU volume);
+};
+
+#endif
+
diff --git a/include/graphics/SkOSWindow_Mac.h b/include/graphics/SkOSWindow_Mac.h
new file mode 100644 (file)
index 0000000..b37b652
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef SkOSWindow_Mac_DEFINED
+#define SkOSWindow_Mac_DEFINED
+
+#include "SkWindow.h"
+
+class SkOSWindow : public SkWindow {
+public:
+       SkOSWindow(void* hwnd);
+
+       void*   getHWND() const { return fHWND; }
+       void    updateSize();
+
+       static bool PostEvent(SkEvent* evt, SkEventSinkID, SkMSec delay);
+
+       static pascal OSStatus SkOSWindow::EventHandler( EventHandlerCallRef inHandler, EventRef inEvent, void* userData );
+
+protected:
+       // overrides from SkWindow
+       virtual void onHandleInval(const SkRect16&);
+       // overrides from SkView
+       virtual void onAddMenu(const SkOSMenu*);
+
+private:
+       void*   fHWND;
+
+       void    doPaint(void* ctx);
+
+       typedef SkWindow INHERITED;
+};
+
+#endif
+
diff --git a/include/graphics/SkOSWindow_Unix.h b/include/graphics/SkOSWindow_Unix.h
new file mode 100644 (file)
index 0000000..5c1b1eb
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef SkOSWindow_Unix_DEFINED
+#define SkOSWindow_Unix_DEFINED
+
+#include "SkWindow.h"
+#include <X11/Xlib.h>
+
+struct SkUnixWindow {
+  Display* fDisplay;
+  Window fWin;
+  size_t fOSWin;
+};
+
+class SkOSWindow : public SkWindow {
+public:
+       SkOSWindow(Display* display, Window win);
+
+       void*   getHWND() const { return (void*)fUnixWindow.fWin; }
+  void* getDisplay() const { return (void*)fUnixWindow.fDisplay; }
+  void* getUnixWindow() const { return (void*)&fUnixWindow; }
+  void setSize(int width, int height);
+       void    updateSize();
+
+       static bool PostEvent(SkEvent* evt, SkEventSinkID, SkMSec delay);
+
+       static bool WndProc(SkUnixWindow* w,  XEvent &e);
+
+protected:
+       // overrides from SkWindow
+       virtual void onHandleInval(const SkRect16&);
+       // overrides from SkView
+       virtual void onAddMenu(const SkOSMenu*);
+
+private:
+       SkUnixWindow  fUnixWindow;
+
+       void    doPaint();
+
+       void*   fMBar;
+
+       typedef SkWindow INHERITED;
+};
+
+#endif
+
diff --git a/include/graphics/SkOSWindow_Win.h b/include/graphics/SkOSWindow_Win.h
new file mode 100644 (file)
index 0000000..b213a05
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef SkOSWindow_Win_DEFINED
+#define SkOSWindow_Win_DEFINED
+
+#include "SkWindow.h"
+
+class SkOSWindow : public SkWindow {
+public:
+       SkOSWindow(void* hwnd);
+
+       void*   getHWND() const { return fHWND; }
+       void    setSize(int width, int height);
+       void    updateSize();
+
+       static bool PostEvent(SkEvent* evt, SkEventSinkID, SkMSec delay);
+
+       static bool WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+       static bool SkOSWindow::QuitOnDeactivate(HWND hWnd);
+
+       enum {
+               SK_WM_SkEvent = WM_APP + 1000,
+               SK_WM_SkTimerID = 0xFFFF        // just need a non-zero value
+       };
+
+protected:
+       virtual bool quitOnDeactivate() { return true; }
+
+       // overrides from SkWindow
+       virtual void onHandleInval(const SkRect16&);
+       // overrides from SkView
+       virtual void onAddMenu(const SkOSMenu*);
+
+private:
+       void*   fHWND;
+
+       void    doPaint(void* ctx);
+
+       HMENU   fMBar;
+
+       typedef SkWindow INHERITED;
+};
+
+#endif
+
diff --git a/include/graphics/SkOSWindow_wxwidgets.h b/include/graphics/SkOSWindow_wxwidgets.h
new file mode 100644 (file)
index 0000000..1f526c0
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *  SkOSWindow_wxwidgets.h
+ *  wxwidgets
+ *
+ *  Created by phanna on 12/14/05.
+ *  Copyright 2005 __MyCompanyName__. All rights reserved.
+ *
+ */
+
+#ifndef SkOSWindow_wxwidgets_DEFINED
+#define SkOSWindow_wxwidgets_DEFINED
+
+#include "SkWindow.h"
+#include "wx/frame.h"
+
+class SkOSWindow: public SkWindow
+{
+public:
+       SkOSWindow();
+    SkOSWindow(const wxString& title, int x, int y, int width, int height);
+    ~SkOSWindow();
+       
+       wxFrame* getWXFrame() const { return fFrame; }
+       
+       void updateSize();
+       
+protected:
+    virtual void onHandleInval(const SkRect16&);
+    virtual void onAddMenu(const SkOSMenu*);
+    
+private:
+    wxFrame* fFrame;
+    typedef SkWindow INHERITED;
+    
+};
+
+#endif
\ No newline at end of file
diff --git a/include/graphics/SkPaint.h b/include/graphics/SkPaint.h
new file mode 100644 (file)
index 0000000..5c1a036
--- /dev/null
@@ -0,0 +1,630 @@
+#ifndef SkPaint_DEFINED
+#define SkPaint_DEFINED
+
+#include "SkColor.h"
+#include "SkMath.h"
+#include "SkPorterDuff.h"
+
+class SkColorFilter;
+class SkGlyphCache;
+class SkMaskFilter;
+class SkMatrix;
+class SkPath;
+class SkPathEffect;
+class SkRasterizer;
+class SkShader;
+class SkTextLayout;
+class SkTypeface;
+class SkXfermode;
+
+typedef SkUnichar (*SkUnicodeWalkerProc)(const char** text);
+
+/**    \class SkPaint
+
+       The SkPaint class holds the style and color information about how to draw geometries, text and bitmaps.
+*/
+class SkPaint {
+public:
+       SkPaint();
+       SkPaint(const SkPaint& paint);
+       ~SkPaint();
+
+       SkPaint& operator=(const SkPaint&);
+
+       friend int operator==(const SkPaint& a, const SkPaint& b);
+       friend int operator!=(const SkPaint& a, const SkPaint& b) { return !(a == b); }
+
+       /**     Restores the paint to its initial settings.
+       */
+       void    reset();
+
+    /** FlagShift enum specifies the amount to bit-shift for a given flag setting.
+        Can be used to slide a boolean value into the correct position (e.g.
+        flags |= isAntiAlias << kAntiAlias_Shift;
+    */
+       enum FlagShift {
+               kAntiAlias_Shift,               //!< bit position for the flag enabling antialiasing
+               kLinearText_Shift       ,       //!< bit position for the flag enabling linear-text (no gridding)
+               kUnderlineText_Shift,   //!< bit position for the flag enabling underline text
+               kStrikeThruText_Shift,  //!< bit position for the flag enabling strike-thru text
+        kFakeBoldText_Shift,    //!< bit position for the flag enabling fake-bold text
+
+               kFlagShiftCount
+       };
+    
+    /** FlagMask enum specifies the bit values that are stored in the paint's flags.
+    */
+       enum FlagMask {
+               kAntiAlias_Mask         = 1 << kAntiAlias_Shift,                //!< bit mask for the flag enabling antialiasing
+               kLinearText_Mask        = 1 << kLinearText_Shift,               //!< bit mask for the flag enabling linear-text (no gridding)
+               kUnderlineText_Mask     = 1 << kUnderlineText_Shift,    //!< bit mask for the flag enabling underline text
+               kStrikeThruText_Mask= 1 << kStrikeThruText_Shift,       //!< bit mask for the flag enabling strike-thru text
+               kFakeBoldText_Mask  = 1 << kFakeBoldText_Shift,     //!< bit mask for the flag enabling fake-bold text
+
+               kAllFlagMasks = (1 << kFlagShiftCount) - 1
+       };
+
+    /** Return the paint's flags. Use the FlagMask enum to test flag values.
+        @return the paint's flags (see enums ending in _Mask for bit masks)
+    */
+       uint32_t    getFlags() const { return fFlags; }
+    /** Set the paint's flags. Use the FlagMask enum to specific flag values.
+        @param flags    The new flag bits for the paint (see enums ending in _Mask for bit masks)
+    */
+       void    setFlags(uint32_t flags);
+
+       /**     Helper for getFlags(), returning true if kAntiAlias_Mask bit is set
+        @return true if the antialias bit is set in the paint's flags.
+       */
+       bool    isAntiAliasOn() const { return SkToBool(this->getFlags() & kAntiAlias_Mask); }
+       /**     Helper for setFlags(), setting or clearing the kAntiAlias_Mask bit
+        @param aa   true to set the antialias bit in the flags, false to clear it
+       */
+       void    setAntiAliasOn(bool aa);
+       /**     Helper for getFlags(), returning true if kLinearText_Mask bit is set
+        @return true if the lineartext bit is set in the paint's flags
+       */
+       bool    isLinearTextOn() const { return SkToBool(this->getFlags() & kLinearText_Mask); }
+       /**     Helper for setFlags(), setting or clearing the kLinearText_Mask bit
+        @param linearText true to set the linearText bit in the paint's flags, false to clear it.
+       */
+       void    setLinearTextOn(bool linearText);
+       /**     Helper for getFlags(), returning true if kUnderlineText_Mask bit is set
+        @return true if the underlineText bit is set in the paint's flags.
+       */
+       bool    isUnderlineTextOn() const { return SkToBool(this->getFlags() & kUnderlineText_Mask); }
+       /**     Helper for setFlags(), setting or clearing the kUnderlineText_Mask bit
+        @param underlineText true to set the underlineText bit in the paint's flags, false to clear it.
+       */
+       void    setUnderlineTextOn(bool underlineText);
+       /**     Helper for getFlags(), returning true if kStrikeThruText_Mask bit is set
+        @return true if the strikeThruText bit is set in the paint's flags.
+       */
+       bool    isStrikeThruTextOn() const { return SkToBool(this->getFlags() & kStrikeThruText_Mask); }
+       /**     Helper for setFlags(), setting or clearing the kStrikeThruText_Mask bit
+        @param strikeThruText   true to set the strikeThruText bit in the paint's flags, false to clear it.
+       */
+       void    setStrikeThruTextOn(bool strikeThruText);
+       /**     Helper for getFlags(), returning true if kFakeBoldText_Mask bit is set
+        @return true if the fakeBoldText bit is set in the paint's flags.
+       */
+       bool    isFakeBoldTextOn() const { return SkToBool(this->getFlags() & kFakeBoldText_Mask); }
+       /**     Helper for setFlags(), setting or clearing the kStrikeThruText_Mask bit
+        @param fakeBoldText true to set the fakeBoldText bit in the paint's flags, false to clear it.
+       */
+       void    setFakeBoldTextOn(bool fakeBoldText);
+
+       /**     Styles apply to rect, oval, path, and text.
+               Bitmaps are always drawn in "fill", and lines are always drawn in "stroke"
+       */
+       enum Style {
+               kFill_Style,                    //!< fill with the paint's color
+               kStroke_Style,                  //!< stroke with the paint's color
+               kStrokeAndFill_Style,   //!< fill and stroke with the paint's color
+
+               kStyleCount,
+        kDefault_Style = kFill_Style,   //!< the default style setting in the paint
+       };
+       /**     Return the paint's style, used for controlling how primitives'
+               geometries are interpreted (except for drawBitmap, which always assumes
+               kFill_Style).
+        @return the paint's style setting (Fill, Stroke, StrokeAndFill)
+       */
+       Style   getStyle() const { return (Style)fStyle; }
+       /**     Set the paint's style, used for controlling how primitives'
+               geometries are interpreted (except for drawBitmap, which always assumes
+               Fill).
+        @param style    The new style to set in the paint (Fill, Stroke, StrokeAndFill)
+       */
+       void    setStyle(Style style);
+
+       /**     Return the paint's color. Note that the color is a 32bit value containing alpha
+               as well as r,g,b. This 32bit value is not premultiplied, meaning that
+               its alpha can be any value, regardless of the values of r,g,b.
+        @return the paint's color (and alpha).
+       */
+       SkColor getColor() const { return fColor; }
+       /**     Helper to getColor() that just returns the color's alpha value.
+        @return the alpha component of the paint's color.
+       */
+       uint8_t getAlpha() const { return SkToU8(SkColorGetA(fColor)); }
+       /**     Set the paint's color. Note that the color is a 32bit value containing alpha
+               as well as r,g,b. This 32bit value is not premultiplied, meaning that
+               its alpha can be any value, regardless of the values of r,g,b.
+        @param color    The new color (including alpha) to set in the paint.
+       */
+       void    setColor(SkColor color);
+       /**     Helper to setColor(), that only assigns the color's alpha value, leaving its
+               r,g,b values unchanged.
+        @param a    set the alpha component (0..255) of the paint's color.
+       */
+       void    setAlpha(U8CPU a);
+       /**     Helper to setColor(), that takes a,r,g,b and constructs the color value using SkColorSetARGB()
+        @param a    The new alpha component (0..255) of the paint's color.
+        @param r    The new red component (0..255) of the paint's color.
+        @param g    The new green component (0..255) of the paint's color.
+        @param b    The new blue component (0..255) of the paint's color.
+       */
+       void    setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
+
+       /**     Return the width for stroking. 
+               <p />
+               A value of 0 strokes in hairline mode.
+               Hairlines always draws a single pixel independent of the canva's matrix.
+        @return the paint's stroke width, used whenever the paint's style is Stroke or StrokeAndFill.
+       */
+       SkScalar        getStrokeWidth() const { return fWidth; }
+       /**     Set the width for stroking. 
+               Pass 0 to stroke in hairline mode.
+               Hairlines always draws a single pixel independent of the canva's matrix.
+               @param width set the paint's stroke width, used whenever the paint's style is Stroke or StrokeAndFill.
+       */
+       void            setStrokeWidth(SkScalar width);
+
+       /**     Return the paint's stroke miter value. This is used to control the behavior
+               of miter joins when the joins angle is sharp.
+        @return the paint's miter limit, used whenever the paint's style is Stroke or StrokeAndFill.
+       */
+       SkScalar        getStrokeMiter() const { return fMiterLimit; }
+       /**     Set the paint's stroke miter value. This is used to control the behavior
+               of miter joins when the joins angle is sharp. This value must be >= 0.
+        @param miter    set the miter limit on the paint, used whenever the paint's style is Stroke or StrokeAndFill.
+       */
+       void            setStrokeMiter(SkScalar miter);
+
+    /** Cap enum specifies the settings for the paint's strokecap. This is the treatment
+        that is applied to the beginning and end of each non-closed contour (e.g. lines).
+    */
+       enum Cap {
+               kButt_Cap,              //!< begin and end a contour with no extension
+               kRound_Cap,             //!< begin and end a contour with a semi-circle extension
+               kSquare_Cap,    //!< begin and end a contour with a half square extension
+
+               kCapCount,
+               kDefault_Cap = kButt_Cap
+       };
+
+    /** Join enum specifies the settings for the paint's strokejoin. This is the treatment
+        that is applied to corners in paths and rectangles.
+    */
+       enum Join {
+               kMiter_Join,    //!< connect path segments with a sharp join (respects miter-limit)
+               kRound_Join,    //!< connect path segments with a round join
+               kBevel_Join,    //!< connect path segments with a flat bevel join
+
+               kJoinCount,
+               kDefault_Join = kMiter_Join
+       };
+
+       /**     Return the paint's stroke cap type, controlling how the start and end of stroked lines and paths
+        are treated.
+        @return the line cap style for the paint, used whenever the paint's style is Stroke or StrokeAndFill.
+       */
+       Cap             getStrokeCap() const { return (Cap)fCapType; }
+       /**     Set the paint's stroke cap type.
+        @param cap  set the paint's line cap style, used whenever the paint's style is Stroke or StrokeAndFill.
+       */
+       void    setStrokeCap(Cap cap);
+
+       /**     Return the paint's stroke join type.
+        @return the paint's line join style, used whenever the paint's style is Stroke or StrokeAndFill.
+       */
+       Join    getStrokeJoin() const { return (Join)fJoinType; }
+       /**     Set the paint's stroke join type.
+        @param join set the paint's line join style, used whenever the paint's style is Stroke or StrokeAndFill.
+       */
+       void    setStrokeJoin(Join join);
+
+       enum FilterType {
+               kNo_FilterType,                 //!< draw bitmaps using nearest-neighbor sampling
+               kBilinear_FilterType,   //!< draw bitmaps using bilinear sampling
+
+               kFilterTypeCount
+       };
+       /**     Return the paint's bitmap filter type. This setting affects drawBitmap() and bitmaps
+               that appear inside a bitmap shader.
+        @return the paint's filter type, used when drawing bitmaps.
+       */
+       FilterType      getFilterType() const { return (FilterType)fFilterType; }
+       /**     Set the paint's bitmap filter type. This setting affects drawBitmap() and bitmaps
+               that appear inside a bitmap shader.
+        @param filterType   set the new filter type on the paint, used when drawing a bitmap
+       */
+       void            setFilterType(FilterType filterType);
+
+       /**     Get the paint's shader object.
+               <p />
+         The shader's reference count is not affected.
+               @return the paint's shader (or NULL)
+       */
+       SkShader*       getShader() const { return fShader; }
+       /**     Set or clear the shader object.
+               <p />
+               Pass NULL to clear any previous shader.
+               As a convenience, the parameter passed is also returned.
+               If a previous shader exists, its reference count is decremented.
+               If shader is not NULL, its reference count is incremented.
+               @param shader   May be NULL. the new shader to be installed in the paint
+               @return         shader
+       */
+       SkShader*       setShader(SkShader* shader);
+    
+    /** Get the paint's colorfilter (or NULL). If there is a colorfilter, its reference
+        count is not changed.
+        @return the paint's colorfilter (or NULL)
+    */
+    SkColorFilter*  getColorFilter() const { return fColorFilter; }
+       /**     Set or clear the paint's colorfilter, returning the parameter.
+               <p />
+               If the paint already has a filter, its reference count is decremented.
+               If filter is not NULL, its reference count is incremented.
+               @param filter   May be NULL. The new filter to be installed in the paint
+               @return         filter
+       */
+    SkColorFilter*  setColorFilter(SkColorFilter* filter);
+
+       /**     Get the paint's xfermode object.
+               <p />
+         The xfermode's reference count is not affected.
+               @return the paint's xfermode (or NULL)
+       */
+       SkXfermode*     getXfermode() const { return fXfermode; }
+       /**     Set or clear the xfermode object.
+               <p />
+               Pass NULL to clear any previous xfermode.
+               As a convenience, the parameter passed is also returned.
+               If a previous xfermode exists, its reference count is decremented.
+               If xfermode is not NULL, its reference count is incremented.
+               @param xfermode May be NULL. The new xfermode to be installed in the paint
+               @return         xfermode
+       */
+       SkXfermode*     setXfermode(SkXfermode* xfermode);
+    
+    /** Helper for setXfermode, passing the corresponding xfermode object returned from the
+        PorterDuff factory.
+        @param mode The porter-duff mode used to create an xfermode for the paint.
+        @return the resulting xfermode object (or NULL if the mode is SrcOver)
+    */
+       SkXfermode* setPorterDuffXfermode(SkPorterDuff::Mode mode);
+
+       /**     Get the paint's patheffect object.
+               <p />
+         The patheffect reference count is not affected.
+               @return the paint's patheffect (or NULL)
+       */
+       SkPathEffect*   getPathEffect() const { return fPathEffect; }
+       /**     Set or clear the patheffect object.
+               <p />
+               Pass NULL to clear any previous patheffect.
+               As a convenience, the parameter passed is also returned.
+               If a previous patheffect exists, its reference count is decremented.
+               If patheffect is not NULL, its reference count is incremented.
+               @param effect   May be NULL. The new patheffect to be installed in the paint
+               @return         effect
+       */
+       SkPathEffect*   setPathEffect(SkPathEffect* effect);
+
+       /**     Get the paint's maskfilter object.
+               <p />
+         The maskfilter reference count is not affected.
+               @return the paint's maskfilter (or NULL)
+       */
+       SkMaskFilter*   getMaskFilter() const { return fMaskFilter; }
+       /**     Set or clear the maskfilter object.
+               <p />
+               Pass NULL to clear any previous maskfilter.
+               As a convenience, the parameter passed is also returned.
+               If a previous maskfilter exists, its reference count is decremented.
+               If maskfilter is not NULL, its reference count is incremented.
+               @param maskfilter   May be NULL. The new maskfilter to be installed in the paint
+               @return             maskfilter
+       */
+       SkMaskFilter*   setMaskFilter(SkMaskFilter* maskfilter);
+
+       // These attributes are for text/fonts
+
+       /**     Get the paint's typeface object.
+               <p />
+               The typeface object identifies which font to use when drawing or measuring text.
+        The typeface reference count is not affected.
+               @return the paint's typeface (or NULL)
+       */
+       SkTypeface*     getTypeface() const { return fTypeface; }
+       /**     Set or clear the typeface object.
+               <p />
+               Pass NULL to clear any previous typeface.
+               As a convenience, the parameter passed is also returned.
+               If a previous typeface exists, its reference count is decremented.
+               If typeface is not NULL, its reference count is incremented.
+               @param typeface May be NULL. The new typeface to be installed in the paint
+               @return         typeface
+       */
+       SkTypeface*     setTypeface(SkTypeface* typeface);
+
+    /** Get the paint's textlayout (or NULL).
+        <p />
+        The textlayout can modify the spacing between letters and words when measured/drawn.
+        The textlayout reference count is not affected.
+        @return the paint's textlayout (or NULL)
+    */
+    SkTextLayout* getTextLayout() const { return fTextLayout; }
+    /** Set or clear the textlayout object.
+        <p />
+        Pass NULL to clear any previous textlayout.
+        As a convenience, the parameter passed is also returned.
+        If a previous layout exists in the paint, its reference count is decremented.
+        If layout is not NULL, its reference count is incremented.
+        @param layout May be NULL. The new layout to be installed in the paint.
+        @return layout
+    */
+    SkTextLayout* setTextLayout(SkTextLayout* layout);
+
+    /** Get the paint's rasterizer (or NULL).
+        <p />
+        The raster controls/modifies how paths/text are turned into alpha masks.
+        @return the paint's rasterizer (or NULL)
+    */
+    SkRasterizer* getRasterizer() const { return fRasterizer; }
+    /** Set or clear the rasterizer object.
+        <p />
+        Pass NULL to clear any previous rasterizer.
+        As a convenience, the parameter passed is also returned.
+        If a previous rasterizer exists in the paint, its reference count is decremented.
+        If r is not NULL, its reference count is incremented.
+        @param rasterizer May be NULL. The new rasterizer to be installed in the paint.
+        @return rasterizer
+    */
+    SkRasterizer* setRasterizer(SkRasterizer* rasterizer);
+
+       enum Align {
+               kLeft_Align,
+               kCenter_Align,
+               kRight_Align,
+
+               kAlignCount
+       };
+       /**     Return the paint's Align value for drawing text.
+        @return the paint's Align value for drawing text.
+       */
+       Align   getTextAlign() const { return (Align)fTextAlign; }
+       /**     Set the paint's text alignment.
+        @param align set the paint's Align value for drawing text.
+       */
+       void    setTextAlign(Align align);
+
+       /**     Return the paint's text size.
+        @return the paint's text size.
+       */
+       SkScalar        getTextSize() const { return fTextSize; }
+       /**     Set the paint's text size. This value must be > 0
+        @param textSize set the paint's text size.
+       */
+       void            setTextSize(SkScalar textSize);
+
+       /**     Return the paint's horizontal scale factor for text. The default value
+               is 1.0.
+        @return the paint's scale factor in X for drawing/measuring text
+       */
+       SkScalar        getTextScaleX() const { return fTextScaleX; }
+       /**     Set the paint's horizontal scale factor for text. The default value
+               is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will
+               stretch the text narrower.
+        @param scaleX   set the paint's scale factor in X for drawing/measuring text.
+       */
+       void            setTextScaleX(SkScalar scaleX);
+
+       /**     Return the paint's horizontal skew factor for text. The default value
+               is 0.
+        @return the paint's skew factor in X for drawing text.
+       */
+       SkScalar        getTextSkewX() const { return fTextSkewX; }
+       /**     Set the paint's horizontal skew factor for text. The default value
+               is 0. For approximating oblique text, use values around -0.25.
+        @param skewX set the paint's skew factor in X for drawing text.
+       */
+       void            setTextSkewX(SkScalar skewX);
+
+       /**     Return the width of the utf8 text.
+        @param utf8     Address of the utf8 text
+        @param length   Number of bytes of utf8 text to measure
+               @param above    If not NULL, returns the distance above the baseline (ascent)
+               @param below    If not NULL, returns the distance below the baseline (descent)
+               @return The width of the utf8 text
+       */
+       SkScalar        measureText(const char utf8[], size_t length,
+                                                       SkScalar* above, SkScalar* below) const;
+       /**     Return the width of the utf16 text.
+        @param utf16    Address of the utf16 text
+        @param numberOf16BitValues  Number of 16bit values to measure
+               @param above    May be NULL. If not NULL, returns the distance above the baseline (ascent)
+               @param below    May be NULL. If not NULL, returns the distance below the baseline (descent)
+               @return The width of the text
+       */
+       SkScalar        measureText16(const uint16_t utf16[], size_t numberOf16BitValues,
+                                                         SkScalar* above, SkScalar* below) const;
+       /** Return the distance above (negative) the baseline (ascent) based on the current typeface and text size.
+        @return the distance above (negative) the baseline (ascent) based on the current typeface and text size.
+    */
+       SkScalar ascent() const;
+       /** Return the distance below (positive) the baseline (descent) based on the current typeface and text size.
+        @return the distance below (positive) the baseline (descent) based on the current typeface and text size.
+    */
+       SkScalar descent() const;
+    
+       /**     Return the width of the utf8 text.
+        @param text The utf8 text to measure
+        @param byteLength   The number of bytes of text to process
+        @return the measured width of the specified text.
+       */
+       SkScalar measureText(const char text[], size_t byteLength) const
+       {
+               return this->measureText(text, byteLength, NULL, NULL);
+       }
+       /**     Return the width of the utf16 text.
+        @param text The utf16 text to measure
+        @param numberOf16BitValues   The number of 16bit values in text to process
+        @return the measured width of the specified text.
+       */
+       SkScalar measureText16(const uint16_t text[], size_t numberOf16BitValues) const
+       {
+               return this->measureText16(text, numberOf16BitValues, NULL, NULL);
+       }
+    
+    /** Return the advance widths for the characters in the string.
+        @param text UTF8 text
+        @param byteLength   number of bytes to read from the UTF8 text parameter
+        @param widths   array of SkScalars to receive the advance widths of the characters.
+                        May be NULL. If not NULL, must be at least a large as the number
+                        of unichars in the specified text.
+        @return the number of unichars in the specified text.
+    */
+    int getTextWidths(const char text[], size_t byteLength, SkScalar widths[]) const;
+    /** Return the advance widths for the characters in the string.
+        @param text UTF16 text
+        @param numberOf16BitValues   number of 16bit values to read from the UTF16 text parameter
+        @param widths   array of SkScalars to receive the advance widths of the characters.
+                        May be NULL. If not NULL, must be at least a large as the number
+                        of unichars in the specified text.
+        @return the number of unichars in the specified text.
+    */
+    int getTextWidths16(const uint16_t text[], size_t numberOf16BitValues, SkScalar widths[]) const;
+
+       /**     Return the path (outline) for the specified text.
+               Note: just like SkCanvas::drawText, this will respect the Align setting in the paint.
+       */
+       void    getTextPath(const char text[], size_t length, SkScalar x, SkScalar y, SkPath* path) const;
+
+       /**     Return the path (outline) for the specified text.
+               Note: just like SkCanvas::drawText, this will respect the Align setting in the paint.
+       */
+       void    getText16Path(const uint16_t text[], size_t numberOf16BitValues, SkScalar x, SkScalar y, SkPath* path) const;
+
+    /** Applies any/all effects (patheffect, stroking) to src, returning the result in dst.
+        The result is that drawing src with this paint will be the same as drawing dst
+        with a default paint (at least from the geometric perspective).
+        @param src  input path
+        @param dst  output path (may be the same as src)
+        @return true if the path should be filled, or false if it should be drawn with a hairline (width == 0)
+    */
+    bool    getFillPath(const SkPath& src, SkPath* dst) const;
+
+private:
+       SkTypeface*             fTypeface;
+       SkScalar                fTextSize;
+       SkScalar                fTextScaleX;
+       SkScalar                fTextSkewX;
+
+       SkPathEffect*   fPathEffect;
+       SkShader*               fShader;
+       SkXfermode*             fXfermode;
+       SkMaskFilter*   fMaskFilter;
+    SkColorFilter*  fColorFilter;
+    SkTextLayout*   fTextLayout;
+    SkRasterizer*   fRasterizer;
+
+       SkColor                 fColor;
+       SkScalar                fWidth;
+       SkScalar                fMiterLimit;
+       unsigned                fFlags : 5;
+       unsigned                fFilterType : 2;
+       unsigned                fTextAlign : 2;
+       unsigned                fCapType : 2;
+       unsigned                fJoinType : 2;
+       unsigned                fStyle : 2;
+
+    SkScalar privateMeasureText(SkUnicodeWalkerProc, const char text[], size_t byteLength,
+                                SkScalar* above, SkScalar* below) const;
+       void    privateGetTextPath(SkUnicodeWalkerProc, const char text[], size_t length,
+                                SkScalar x, SkScalar y, SkPath* path) const;
+    int privateGetTextWidths(const char text[], size_t byteLength,
+                             SkScalar widths[], SkUnicodeWalkerProc textProc) const;
+
+       SkGlyphCache*   detachCache(const SkMatrix*) const;
+
+       friend class SkGlyphCache;
+       enum {
+               kCanonicalTextSizeForPaths = 64
+       };
+       friend class SkDraw;
+       friend class SkTextToPathIter;
+};
+
+class SkAutoRestorePaintFlags {
+public:
+       SkAutoRestorePaintFlags(const SkPaint& paint, uint32_t newFlags)
+       {
+               SkASSERT(&paint);
+               fPaint = (SkPaint*)&paint;      // remove constness
+               fOldFlags = paint.getFlags();
+               fPaint->setFlags(newFlags);
+       }
+       ~SkAutoRestorePaintFlags()
+       {
+               fPaint->setFlags(fOldFlags);
+       }
+private:
+       SkPaint* fPaint;
+       uint32_t fOldFlags;
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+#include "SkPathEffect.h"
+
+/** \class SkStrokePathEffect
+
+    SkStrokePathEffect simulates stroking inside a patheffect, allowing the caller to have explicit
+    control of when to stroke a path. Typically this is used if the caller wants to stroke before
+    another patheffect is applied (using SkComposePathEffect or SkSumPathEffect).
+*/
+class SkStrokePathEffect : public SkPathEffect {
+public:
+       SkStrokePathEffect(const SkPaint&);
+       SkStrokePathEffect(SkScalar width, SkPaint::Style, SkPaint::Join, SkPaint::Cap, SkScalar miterLimit = -1);
+
+       // overrides
+    // This method is not exported to java.
+       virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
+
+       // overrides for SkFlattenable
+    // This method is not exported to java.
+       virtual void flatten(SkWBuffer&);
+    // This method is not exported to java.
+       virtual Factory getFactory();
+
+private:
+       SkScalar        fWidth, fMiter;
+       uint8_t         fStyle, fJoin, fCap;
+
+       static SkFlattenable* CreateProc(SkRBuffer&);
+       SkStrokePathEffect(SkRBuffer&);
+
+       typedef SkPathEffect INHERITED;
+
+       // illegal
+       SkStrokePathEffect(const SkStrokePathEffect&);
+       SkStrokePathEffect& operator=(const SkStrokePathEffect&);
+};
+
+#endif
+
diff --git a/include/graphics/SkParse.h b/include/graphics/SkParse.h
new file mode 100644 (file)
index 0000000..9e513fe
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef SkParse_DEFINED
+#define SkParse_DEFINED
+
+#include "SkColor.h"
+#include "SkMath.h"
+
+class SkParse {
+public:
+       static int Count(const char str[]); // number of scalars or int values
+       static int Count(const char str[], char separator);
+       static const char* FindColor(const char str[], SkColor* value);
+       static const char* FindHex(const char str[], uint32_t* value);
+       static const char* FindMSec(const char str[], SkMSec* value);
+       static const char* FindNamedColor(const char str[], size_t len, SkColor* color);
+       static const char* FindS32(const char str[], int32_t* value);
+       static const char* FindScalar(const char str[], SkScalar* value);
+       static const char* FindScalars(const char str[], SkScalar value[], int count);
+
+       static bool     FindBool(const char str[], bool* value);
+       // return the index of str in list[], or -1 if not found
+       static int      FindList(const char str[], const char list[]);
+#ifdef SK_SUPPORT_UNITTEST
+       static void TestColor();
+       static void UnitTest();
+#endif
+};
+
+#endif
+
diff --git a/include/graphics/SkParsePaint.h b/include/graphics/SkParsePaint.h
new file mode 100644 (file)
index 0000000..d5f7f68
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef SkParsePaint_DEFINED
+#define SkParsePaint_DEFINED
+
+#include "SkPaint.h"
+#include "SkDOM.h"
+
+/**    "color"                         color
+       "opacity"                       scalar  [0..1]
+       "stroke-width"          scalar  (0...inf)
+       "text-size"                     scalar  (0..inf)
+       "is-stroke"                     bool
+       "is-antialias"          bool
+       "is-lineartext"         bool
+*/
+void SkPaint_Inflate(SkPaint*, const SkDOM&, const SkDOM::Node*);
+
+#endif
+
diff --git a/include/graphics/SkPath.h b/include/graphics/SkPath.h
new file mode 100644 (file)
index 0000000..b0a538d
--- /dev/null
@@ -0,0 +1,373 @@
+#ifndef SkPath_DEFINED
+#define SkPath_DEFINED
+
+#include "SkMatrix.h"
+#include "SkTDArray.h"
+
+class SkString;
+
+/**    \class SkPath
+
+       The SkPath class encapsulates compound (multiple contour) geometric paths consisting
+       of straight line segments, quadratic curves, and cubic curves.
+*/
+class SkPath {
+public:
+       SkPath();
+       SkPath(const SkPath&);
+       ~SkPath();
+
+       SkPath& operator=(const SkPath&);
+
+       enum FillType {
+               kWinding_FillType,      //!< Specifies that "inside" is computed by a non-zero sum of signed edge crossings
+               kEvenOdd_FillType       //!< Specifies that "inside" is computed by an odd number of edge crossings
+       };
+       /**     Return the path's fill type. This is used to define how "inside" is computed.
+               The default value is kWinding_FillType.
+        @return the path's fill type
+       */
+       FillType        getFillType() const { return (FillType)fFillType; }
+       /**     Set the path's fill type. This is used to define how "inside" is computed.
+               The default value is kWinding_FillType.
+        @param ft The new fill type for this path
+       */
+       void            setFillType(FillType ft) { fFillType = SkToU8(ft); }
+
+       /**     Clear any lines and curves from the path, making it empty.
+               This does NOT change the fill-type setting.
+       */
+       void    reset();
+       /**     Returns true if the path is empty (contains no lines or curves)
+        @return true if the path is empty (contains no lines or curves)
+       */
+       bool    isEmpty() const;
+       /**     Returns true if the path specifies a rectangle. If so, and if rect is not nil,
+               set rect to the bounds of the path. If the path does not specify a rectangle,
+               return false and ignore rect.
+               @param rect     If not nil, returns the bounds of the path if it specifies a rectangle
+               @return true if the path specifies a rectangle
+       */
+       bool    isRect(SkRect* rect) const;
+       /**     Returns the number of points in the path. Up to max points are copied.
+               @param points If not null, receives up to max points
+               @param max The maximum number of points to copy into points
+               @return the actual number of points in the path
+       */
+       int     getPoints(SkPoint points[], int max) const;
+       //!     Swap contents of this and other. Guaranteed not to throw
+       void    swap(SkPath& other);
+
+       enum BoundsType {
+               kFast_BoundsType,       //!< compute the bounds of the path's control points, may be larger than with kExact_BoundsType, but may be faster to compute
+               kExact_BoundsType       //!< compute the exact bounds of the path, may be smaller than with kFast_BoundsType, but may be slower to compute
+       };
+       /**     Compute the bounds of the path, and write the answer into bounds. If the path contains 0 or 1 points,
+               the bounds is set to (0,0,0,0)
+        @param bounds   Returns the computed bounds of the path
+        @param btype    Specifies if the computed bounds should be exact (slower) or approximate (faster)
+       */
+       void    computeBounds(SkRect* bounds, BoundsType btype) const;
+
+       //      Construction methods
+
+    /** Hint to the path to prepare for adding more points. This can allow the path to more efficiently grow its storage.
+        @param extraPtCount The number of extra points that may be added to this path
+    */
+       void    incReserve(unsigned extraPtCount);
+
+       /**     Set the beginning of the next contour to the point (x,y).
+        @param x    The x-coordinate of the start of a new contour
+        @param y    The y-coordinate of the start of a new contour
+       */
+       void    moveTo(SkScalar x, SkScalar y);
+    /** Set the beginning of the next contour to the point
+        @param p    The start of a new contour
+    */
+       void moveTo(const SkPoint& p)
+       {
+               this->moveTo(p.fX, p.fY);
+       }
+       /**     Set the beginning of the next contour relative to the last point on the previous
+               contour. If there is no previous contour, this is treated the same as moveTo().
+        @param dx   The amount to add to the x-coordinate of the end of the previous contour, to specify the start of a new contour
+        @param dy   The amount to add to the y-coordinate of the end of the previous contour, to specify the start of a new contour
+       */
+       void    rMoveTo(SkScalar dx, SkScalar dy);
+       /**     Add a line from the last point to the specified point (x,y).
+               If no moveTo() call has been made for this contour, the first point is automatically set to (0,0).
+        @param x    The x-coordinate of the end of a line
+        @param y    The y-coordinate of the end of a line
+       */
+       void    lineTo(SkScalar x, SkScalar y);
+       /**     Add a line from the last point to the specified point.
+               If no moveTo() call has been made for this contour, the first point is automatically set to (0,0).
+        @param p    The end of a line
+       */
+       void    lineTo(const SkPoint& p)
+       {
+               this->lineTo(p.fX, p.fY);
+       }
+       /**     Same as lineTo, but the coordinates are considered relative to the last point on this
+               contour. If there is no previous point, then a moveTo(0,0) is inserted automatically.
+        @param dx   The amount to add to the x-coordinate of the previous point on this contour, to specify a line
+        @param dy   The amount to add to the y-coordinate of the previous point on this contour, to specify a line
+       */
+       void    rLineTo(SkScalar dx, SkScalar dy);
+       /**     Add a quadratic bezier from the last point, approaching control point (x1,y1), and ending at (x2,y2).
+               If no moveTo() call has been made for this contour, the first point is automatically set to (0,0).
+        @param x1   The x-coordinate of the control point on a quadratic curve
+        @param y1   The y-coordinate of the control point on a quadratic curve
+        @param x2   The x-coordinate of the end point on a quadratic curve
+        @param y2   The y-coordinate of the end point on a quadratic curve
+       */
+       void    quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2);
+       /**     Add a quadratic bezier from the last point, approaching control point p1, and ending at p2.
+               If no moveTo() call has been made for this contour, the first point is automatically set to (0,0).
+        @param p1   The control point on a quadratic curve
+        @param p2   The end point on a quadratic curve
+       */
+       void    quadTo(const SkPoint& p1, const SkPoint& p2)
+       {
+               this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY);
+       }
+       /**     Same as quadTo, but the coordinates are considered relative to the last point on this
+               contour. If there is no previous point, then a moveTo(0,0) is inserted automatically.
+        @param dx1   The amount to add to the x-coordinate of the last point on this contour, to specify the control point of a quadratic curve
+        @param dy1   The amount to add to the y-coordinate of the last point on this contour, to specify the control point of a quadratic curve
+        @param dx2   The amount to add to the x-coordinate of the last point on this contour, to specify the end point of a quadratic curve
+        @param dy2   The amount to add to the y-coordinate of the last point on this contour, to specify the end point of a quadratic curve
+       */
+       void    rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2);
+       /**     Add a cubic bezier from the last point, approaching control points (x1,y1) and (x2,y2), and ending at (x3,y3).
+               If no moveTo() call has been made for this contour, the first point is automatically set to (0,0).
+        @param x1   The x-coordinate of the 1st control point on a cubic curve
+        @param y1   The y-coordinate of the 1st control point on a cubic curve
+        @param x2   The x-coordinate of the 2nd control point on a cubic curve
+        @param y2   The y-coordinate of the 2nd control point on a cubic curve
+        @param x3   The x-coordinate of the end point on a cubic curve
+        @param y3   The y-coordinate of the end point on a cubic curve
+       */
+       void    cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3);
+       /**     Add a cubic bezier from the last point, approaching control points p1 and p2, and ending at p3.
+               If no moveTo() call has been made for this contour, the first point is automatically set to (0,0).
+        @param p1   The 1st control point on a cubic curve
+        @param p2   The 2nd control point on a cubic curve
+        @param p3   The end point on a cubic curve
+       */
+       void    cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3)
+       {
+               this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY);
+       }
+       /**     Same as cubicTo, but the coordinates are considered relative to the current point on this
+               contour. If there is no previous point, then a moveTo(0,0) is inserted automatically.
+        @param dx1   The amount to add to the x-coordinate of the last point on this contour, to specify the 1st control point of a cubic curve
+        @param dy1   The amount to add to the y-coordinate of the last point on this contour, to specify the 1st control point of a cubic curve
+        @param dx2   The amount to add to the x-coordinate of the last point on this contour, to specify the 2nd control point of a cubic curve
+        @param dy2   The amount to add to the y-coordinate of the last point on this contour, to specify the 2nd control point of a cubic curve
+        @param dx3   The amount to add to the x-coordinate of the last point on this contour, to specify the end point of a cubic curve
+        @param dy3   The amount to add to the y-coordinate of the last point on this contour, to specify the end point of a cubic curve
+       */
+       void    rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3);
+       /**     Close the current contour. If the current point is not equal to the first point of the contour,
+               a line segment is automatically added.
+       */
+       void    close();
+
+       enum Direction {
+               kCW_Direction,  //!< clockwise direction for adding closed contours
+               kCCW_Direction  //!< counter-clockwise direction for adding closed contours
+       };
+       /**     Add a closed rectangle contour to the path
+        @param rect The rectangle to add as a closed contour to the path
+        @param dir  The direction to wind the rectangle's contour
+       */
+       void    addRect(const SkRect& rect, Direction dir = kCW_Direction);
+       /**     Add a closed rectangle contour to the path
+        @param left     The left side of a rectangle to add as a closed contour to the path
+        @param top      The top of a rectangle to add as a closed contour to the path
+        @param right    The right side of a rectangle to add as a closed contour to the path
+        @param bottom   The bottom of a rectangle to add as a closed contour to the path
+        @param dir      The direction to wind the rectangle's contour
+       */
+       void    addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, Direction dir = kCW_Direction);
+       /**     Add a closed oval contour to the path
+        @param oval The bounds of the oval to add as a closed contour to the path
+        @param dir  The direction to wind the oval's contour
+       */
+       void    addOval(const SkRect& oval, Direction dir = kCW_Direction);
+       /**     Add a closed circle contour to the path
+        @param x        The x-coordinate of the center of a circle to add as a closed contour to the path
+        @param y        The y-coordinate of the center of a circle to add as a closed contour to the path
+        @param radius   The radius of a circle to add as a closed contour to the path
+        @param dir      The direction to wind the circle's contour
+       */
+       void    addCircle(SkScalar x, SkScalar y, SkScalar radius, Direction dir = kCW_Direction);
+       /**     Add a closed round-rectangle contour to the path
+        @param rect The bounds of a round-rectangle to add as a closed contour to the path
+        @param rx   The x-radius of the rounded corners on the round-rectangle
+        @param ry   The y-radius of the rounded corners on the round-rectangle
+        @param dir  The direction to wind the round-rectangle's contour
+       */
+       void    addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, Direction dir = kCW_Direction);
+       /**     Add a copy of src to the path, offset by (dx,dy)
+        @param src  The path to add as a new contour
+        @param dx   The amount to translate the path in X as it is added
+        @param dx   The amount to translate the path in Y as it is added
+       */
+       void    addPath(const SkPath& src, SkScalar dx, SkScalar dy);
+       /**     Add a copy of src to the path
+       */
+       void    addPath(const SkPath& src) { SkMatrix m; m.reset(); this->addPath(src, m); }
+       /**     Add a copy of src to the path, transformed by matrix
+        @param src  The path to add as a new contour
+       */
+       void    addPath(const SkPath& src, const SkMatrix& matrix);
+
+       /**     Offset the path by (dx,dy), returning true on success
+        @param dx   The amount in the X direction to offset the entire path 
+        @param dy   The amount in the Y direction to offset the entire path 
+        @param dst  The translated path is written here
+        @return true
+       */
+       bool    offset(SkScalar dx, SkScalar dy, SkPath* dst) const;
+       /**     Offset the path by (dx,dy), returning true on success
+        @param dx   The amount in the X direction to offset the entire path 
+        @param dy   The amount in the Y direction to offset the entire path 
+        @return true
+       */
+    bool    offset(SkScalar dx, SkScalar dy)
+    {
+        return this->offset(dx, dy, this);
+    }
+       /**     Transform the points in this path by matrix, and write the answer into dst.
+        @param matrix   The matrix to apply to the path
+        @param dst      The transformed path is written here
+               @return true
+       */
+       bool    transform(const SkMatrix& matrix, SkPath* dst) const;
+       /**     Transform the points in this path by matrix, and write the answer into dst.
+        @param matrix   The matrix to apply to the path
+               @return true
+       */
+       bool    transform(const SkMatrix& matrix)
+       {
+               return this->transform(matrix, this);
+       }
+
+       /**     Return the last point on the path. If no points have been added, (0,0) is returned.
+        @param lastPt   The last point on the path is returned here
+       */
+       void    getLastPt(SkPoint* lastPt) const;
+       /**     Set the last point on the path. If no points have been added, moveTo(x,y) is automatically called.
+        @param x    The new x-coordinate for the last point
+        @param y    The new y-coordinate for the last point
+       */
+       void    setLastPt(SkScalar x, SkScalar y);
+       /**     Set the last point on the path. If no points have been added, moveTo(p) is automatically called.
+        @param p    The new location for the last point
+       */
+       void    setLastPt(const SkPoint& p) { this->setLastPt(p.fX, p.fY); }
+
+       enum Verb {
+               kMove_Verb,             //!< iter.next returns 1 point
+               kLine_Verb,             //!< iter.next returns 2 points
+               kQuad_Verb,             //!< iter.next returns 3 points
+               kCubic_Verb,    //!< iter.next returns 4 points
+               kClose_Verb,    //!< iter.next returns 1 point (the last point)
+               kDone_Verb              //!< iter.next returns 0 points
+       };
+       /**     Iterate through all of the segments (lines, quadratics, cubics) of
+               each contours in a path.
+       */
+       class Iter {
+       public:
+                               Iter();
+                               Iter(const SkPath&, bool forceClose);
+               void    setPath(const SkPath&, bool forceClose);
+
+        /** Return the next verb in this iteration of the path. When all segments have been
+            visited, return kDone_Verb.
+            @param  pts The point(s) representing the current verb and/or segment
+            @return The verb for the current segment
+        */
+               Verb    next(SkPoint pts[4]);
+
+               /**     If next() returns kLine_Verb, then this query returns
+                       true if the line was the result of a close() command
+                       (i.e. the end point is the initial moveto for this contour).
+                       If next() returned a different verb, this returns an
+                       undefined value.
+            @return If the last call to next() returned kLine_Verb, return true if it was
+                    the result of an explicit close command.
+               */
+               bool    isCloseLine() const { return SkToBool(fCloseLine); }
+        
+        /** Returns true if the current contour is closed (i.e. has a kClose_Verb)
+            @return true if the current contour is closed (i.e. has a kClose_Verb)
+        */
+        bool    isClosedContour() const;
+
+       private:
+               const SkPoint*  fPts;
+               const uint8_t*  fVerbs;
+               const uint8_t*  fVerbStop;
+               SkPoint                 fMoveTo;
+               SkPoint                 fLastPt;
+               SkBool8                 fForceClose;
+               SkBool8                 fNeedClose;
+               SkBool8                 fNeedMoveTo;
+               SkBool8                 fCloseLine;
+
+               bool cons_moveTo(SkPoint pts[1]);
+               Verb autoClose(SkPoint pts[2]);
+       };
+
+#ifdef SK_DEBUG
+  /** @cond UNIT_TEST */
+       void dump(bool forceClose, const char title[] = nil) const;
+       static void UnitTest();
+  /** @endcond */
+#endif
+
+       /**     Return the number of bytes (padded to a multiple of 4) needed to
+               flatten the path into a block of memory. If bufferOrNil is not nil,
+               the path is written into it. The format of the buffer is private,
+               and can be used to create a new path by calling unflatten().
+       */
+       uint32_t    flatten(void* bufferOrNil) const;
+       void        unflatten(const void* buffer);
+
+       /**     Subdivide the path so that no segment is longer that dist.
+               If bendLines is true, then turn all line segments into curves.
+               If dst == nil, then the original path itself is modified (not const!)
+       */
+       void subdivide(SkScalar dist, bool bendLines, SkPath* dst = nil) const;
+
+    /** Return an SVG-compatible string of the path.
+    */
+    void toString(SkString*) const;
+
+private:
+       SkTDArray<SkPoint>      fPts;
+       SkTDArray<uint8_t>  fVerbs;
+       uint8_t                         fFillType;
+
+       friend class Iter;
+       void cons_moveto();
+
+       friend class SkPathStroker;
+       /*      Append the first contour of path, ignoring path's initial point.
+               If no moveTo() call has been made for this contour, the first point is automatically set to (0,0).
+       */
+       void    pathTo(const SkPath& path);
+       /*      Append, in reverse order, the first contour of path, ignoring path's last point.
+               If no moveTo() call has been made for this contour, the first point is automatically set to (0,0).
+       */
+       void    reversePathTo(const SkPath&);
+
+       friend const SkPoint* sk_get_path_points(const SkPath&, int index);
+};
+
+#endif
+
diff --git a/include/graphics/SkPathEffect.h b/include/graphics/SkPathEffect.h
new file mode 100644 (file)
index 0000000..c560f67
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef SkPathEffect_DEFINED
+#define SkPathEffect_DEFINED
+
+#include "SkFlattenable.h"
+
+class SkPath;
+
+/** \class SkPathEffect
+
+       SkPathEffect is the base class for objects in the SkPaint that affect
+       the geometry of a drawing primitive before it is transformed by the
+       canvas' matrix and drawn.
+
+       Dashing is implemented as a subclass of SkPathEffect.
+*/
+class SkPathEffect : public SkFlattenable {
+public:
+       SkPathEffect() {}
+
+       /**     Given a src path and a width value, return true if the patheffect
+               has produced a new path (dst) and a new width value. If false is returned,
+               ignore dst and width.
+               On input, width >= 0 means the src should be stroked
+               On output, width >= 0 means the dst should be stroked
+       */
+       virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
+       /** overrides for SkFlattenable.
+               Subclasses should override this to (re)create their subclass.
+       */
+    //  This method is not exported to java.
+       virtual Factory getFactory();
+
+protected:
+       // visible to our subclasses
+       SkPathEffect(SkRBuffer&) {}
+
+private:
+       // illegal
+       SkPathEffect(const SkPathEffect&);
+       SkPathEffect& operator=(const SkPathEffect&);
+};
+
+/**    \class SkPairPathEffect
+
+       Common baseclass for Compose and Sum. This subclass manages two pathEffects,
+       including flattening them. It does nothing in filterPath, and is only useful
+       for managing the lifetimes of its two arguments.
+*/
+//  This class is not exported to java.
+class SkPairPathEffect : public SkPathEffect {
+public:
+       SkPairPathEffect(SkPathEffect* pe0, SkPathEffect* pe1);
+       virtual ~SkPairPathEffect();
+
+       // overrides
+
+    //  This method is not exported to java.
+       virtual void flatten(SkWBuffer&);
+
+protected:
+       // these are visible to our subclasses
+       SkPathEffect* fPE0, *fPE1;
+       SkPairPathEffect(SkRBuffer&);
+    
+private:
+    typedef SkPathEffect INHERITED;
+};
+
+/**    \class SkComposePathEffect
+
+       This subclass of SkPathEffect composes its two arguments, to create
+       a compound pathEffect.
+*/
+class SkComposePathEffect : public SkPairPathEffect {
+public:
+       /**     Construct a pathEffect whose effect is to apply first the inner pathEffect
+               and the the outer pathEffect (e.g. outer(inner(path)))
+               The reference counts for outer and inner are both incremented in the constructor,
+               and decremented in the destructor.
+       */
+       SkComposePathEffect(SkPathEffect* outer, SkPathEffect* inner)
+               : SkPairPathEffect(outer, inner) {}
+
+       // overrides
+    
+       virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
+
+       // overrides for SkFlattenable
+
+    //  This method is not exported to java.
+       virtual Factory getFactory();
+
+private:
+       SkPathEffect* fOuter, *fInner;
+
+       static SkFlattenable* CreateProc(SkRBuffer&);
+       SkComposePathEffect(SkRBuffer& buffer) : SkPairPathEffect(buffer) {}
+
+       // illegal
+       SkComposePathEffect(const SkComposePathEffect&);
+       SkComposePathEffect& operator=(const SkComposePathEffect&);
+    
+    typedef SkPairPathEffect INHERITED;
+};
+
+/**    \class SkSumPathEffect
+
+       This subclass of SkPathEffect applies two pathEffects, one after the other.
+       Its filterPath() returns true if either of the effects succeeded.
+*/
+class SkSumPathEffect : public SkPairPathEffect {
+public:
+       /**     Construct a pathEffect whose effect is to apply two effects, in sequence.
+               (e.g. first(path) + second(path))
+               The reference counts for first and second are both incremented in the constructor,
+               and decremented in the destructor.
+       */
+       SkSumPathEffect(SkPathEffect* first, SkPathEffect* second)
+               : SkPairPathEffect(first, second) {}
+
+       // overrides
+       virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
+
+       // overrides for SkFlattenable
+
+    //  This method is not exported to java.
+       virtual Factory getFactory();
+
+private:
+       SkPathEffect* fFirst, *fSecond;
+
+       static SkFlattenable* CreateProc(SkRBuffer&);
+       SkSumPathEffect(SkRBuffer& buffer) : SkPairPathEffect(buffer) {}
+
+       // illegal
+       SkSumPathEffect(const SkSumPathEffect&);
+       SkSumPathEffect& operator=(const SkSumPathEffect&);
+
+    typedef SkPairPathEffect INHERITED;
+};
+
+#endif
+
diff --git a/include/graphics/SkPathMeasure.h b/include/graphics/SkPathMeasure.h
new file mode 100644 (file)
index 0000000..7d901a2
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef SkPathMeasure_DEFINED
+#define SkPathMeasure_DEFINED
+
+#include "SkPath.h"
+#include "SkTDArray.h"
+
+class SkPathMeasure {
+public:
+       SkPathMeasure();
+       SkPathMeasure(const SkPath& path, bool forceClosed);
+       ~SkPathMeasure();
+
+       /** Assign a new path, or nil to have none.
+       */
+       void    setPath(const SkPath*, bool forceClosed);
+
+       /**     Return the total length of the current contour, or 0 if no path
+               is associated (e.g. resetPath(nil))
+       */
+       SkScalar getLength();
+
+       /**     Pins distance to 0 <= distance <= getLength(), and then computes
+               the corresponding position and tangent.
+               Returns false if there is no path, or a zero-length path was specified, in which case
+               position and tangent are unchanged.
+       */
+       bool getPosTan(SkScalar distance, SkPoint* position, SkVector* tangent);
+
+       enum MatrixFlags {
+               kGetPosition_MatrixFlag         = 0x01,
+               kGetTangent_MatrixFlag          = 0x02,
+               kGetPosAndTan_MatrixFlag        = kGetPosition_MatrixFlag | kGetTangent_MatrixFlag
+       };
+       /**     Pins distance to 0 <= distance <= getLength(), and then computes
+               the corresponding matrix (by calling getPosTan).
+               Returns false if there is no path, or a zero-length path was specified, in which case
+               matrix is unchanged.
+       */
+       bool getMatrix(SkScalar distance, SkMatrix* matrix, MatrixFlags flags = kGetPosAndTan_MatrixFlag);
+       /**     Given a start and stop distance, return in dst the intervening segment(s).
+               If the segment is zero-length, return false, else return true.
+               startD and stopD are pinned to legal values (0..getLength()). If startD <= stopD
+               then return false (and leave dst untouched).
+               Begin the segment with a moveTo if startWithMoveTo is true
+       */
+       bool getSegment(SkScalar startD, SkScalar stopD, SkPath* dst, bool startWithMoveTo);
+
+       /**     Return true if the current contour is closed()
+       */
+       bool isClosed();
+
+       /**     Move to the next contour in the path. Return true if one exists, or false if
+               we're done with the path.
+       */
+       bool nextContour();
+
+#ifdef SK_DEBUG
+       void    dump();
+       static void UnitTest();
+#endif
+
+private:
+       SkPath::Iter    fIter;
+       const SkPath*   fPath;
+       SkScalar                fLength;                        // relative to the current contour
+       int                             fFirstPtIndex;          // relative to the current contour
+       bool                    fIsClosed;                      // relative to the current contour
+       bool                    fForceClosed;
+
+       struct Segment {
+               SkScalar        fDistance;      // total distance up to this point
+               unsigned        fPtIndex : 15;
+               unsigned        fTValue : 15;
+               unsigned        fType : 2;
+
+               SkScalar getScalarT() const;
+       };
+       SkTDArray<Segment>      fSegments;
+
+       static const Segment* NextSegment(const Segment*);
+
+       void     buildSegments();
+       SkScalar compute_quad_segs(const SkPoint pts[3], SkScalar distance,
+                                                               int mint, int maxt, int ptIndex);
+       SkScalar compute_cubic_segs(const SkPoint pts[3], SkScalar distance,
+                                                               int mint, int maxt, int ptIndex);
+       const Segment* distanceToSegment(SkScalar distance, SkScalar* t);
+
+       // illegal (for now)
+       SkPathMeasure(const SkPathMeasure&);
+       SkPathMeasure& operator=(const SkPathMeasure&);
+};
+
+#endif
+
diff --git a/include/graphics/SkPorterDuff.h b/include/graphics/SkPorterDuff.h
new file mode 100644 (file)
index 0000000..6dbcf58
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef SkPorterDuff_DEFINED
+#define SkPorterDuff_DEFINED
+
+#include "SkColor.h"
+
+class SkXfermode;
+
+class SkPorterDuff {
+public:
+       /**     List of predefined xfermodes. In general, the algebra for the modes
+               uses the following symbols:
+               Sa, Sc  - source alpha and color
+               Da, Dc - destination alpha and color (before compositing)
+               [a, c] - Resulting (alpha, color) values
+               For these equations, the colors are in premultiplied state.
+               If no xfermode is specified, kSrcOver is assumed.
+       */
+       enum Mode {
+               kClear_Mode,    //!< [0, 0]
+               kSrc_Mode,              //!< [Sa, Sc]
+               kDst_Mode,              //!< [Da, Dc]
+               kSrcOver_Mode,  //!< [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] this is the default mode
+               kDstOver_Mode,  //!< [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc]
+               kSrcIn_Mode,    //!< [Sa * Da, Sc * Da]
+               kDstIn_Mode,    //!< [Sa * Da, Sa * Dc]
+               kSrcOut_Mode,   //!< [Sa * (1 - Da), Sc * (1 - Da)]
+               kDstOut_Mode,   //!< [Da * (1 - Sa), Dc * (1 - Sa)]
+               kSrcATop_Mode,  //!< [Da, Sc * Da + (1 - Sa) * Dc]
+               kDstATop_Mode,  //!< [Sa, Sa * Dc + Sc * (1 - Da)]
+               kXor_Mode,              //!< [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
+        kDarken_Mode,   //!< [Sa + Da - Sa\u00B7Da, Sc\u00B7(1 - Da) + Dc\u00B7(1 - Sa) + min(Sc, Dc)]
+        kLighten_Mode,  //!< [Sa + Da - Sa\u00B7Da, Sc\u00B7(1 - Da) + Dc\u00B7(1 - Sa) + max(Sc, Dc)]
+
+               kModeCount
+       };
+       /**     Return an SkXfermode object for the specified mode.
+       */
+       static SkXfermode* CreateXfermode(Mode mode);
+    
+    /** Return a function pointer to a routine that applies the specified porter-duff
+        transfer mode.
+    */
+    static SkXfermodeProc GetXfermodeProc(Mode mode);
+};
+
+#endif
+
diff --git a/include/graphics/SkPrefix_Debug_Fixed.h b/include/graphics/SkPrefix_Debug_Fixed.h
new file mode 100644 (file)
index 0000000..72d15e4
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef SkPrefix_Debug_Fixed_DEFINED
+#define SkPrefix_Debug_Fixed_DEFINED
+
+#define SK_DEBUG
+
+/* define this to test fixed-point */
+#define SK_SCALAR_IS_FIXED
+
+/* these are for expat */
+#define MACOS_CLASSIC
+
+#endif
+
+
diff --git a/include/graphics/SkPrefix_Release_Fixed.h b/include/graphics/SkPrefix_Release_Fixed.h
new file mode 100644 (file)
index 0000000..81238ab
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef SkPrefix_Release_Fixed_DEFINED
+
+#define SkPrefix_Release_Fixed_DEFINED
+
+/* this means we're a release build */
+
+#define NDEBUG
+
+
+
+/* define this to test fixed-point */
+
+#define SK_SCALAR_IS_FIXED
+
+
+
+/* these are for expat */
+
+#define MACOS_CLASSIC
+
+
+
+#endif
+
+
+
diff --git a/include/graphics/SkProgressBarView.h b/include/graphics/SkProgressBarView.h
new file mode 100644 (file)
index 0000000..64351c8
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef SkProgressBarView_DEFINED
+#define SkProgressBarView_DEFINED
+
+#include "SkView.h"
+#include "SkWidgetViews.h"
+#include "SkAnimator.h"
+
+class SkProgressBarView : public SkWidgetView {
+       public:
+               SkProgressBarView();
+               //SkProgressBarView(int max);
+                               
+               //inflate: "sk-progress"
+       
+               void reset();   //reset progress to zero
+               void setProgress(int progress);
+               void changeProgress(int diff);
+               void setMax(int max);
+               
+               int getProgress() const { return fProgress; }
+               int getMax() const { return fMax; }
+       
+       protected:
+               //overrides
+               virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node);
+               virtual void onSizeChange();
+               virtual void onDraw(SkCanvas* canvas);
+               virtual bool onEvent(const SkEvent& evt);
+       
+       private:
+               SkAnimator      fAnim;
+               int                     fProgress;
+               int                     fMax;
+               
+               typedef SkWidgetView INHERITED;
+};
+
+
+
+
+#endif
diff --git a/include/graphics/SkRasterizer.h b/include/graphics/SkRasterizer.h
new file mode 100644 (file)
index 0000000..3a323b0
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef SkRasterizer_DEFINED
+#define SkRasterizer_DEFINED
+
+#include "SkFlattenable.h"
+#include "SkMask.h"
+
+class SkMaskFilter;
+class SkMatrix;
+class SkPath;
+struct SkRect16;
+
+class SkRasterizer : public SkFlattenable {
+public:
+    SkRasterizer() {}
+
+    /** Turn the path into a mask, respecting the specified local->device matrix.
+    */
+    bool rasterize(const SkPath& path, const SkMatrix& matrix,
+                   const SkRect16* clipBounds, SkMaskFilter* filter,
+                   SkMask* mask, SkMask::CreateMode mode);
+
+protected:
+    SkRasterizer(SkRBuffer&);
+
+    virtual bool onRasterize(const SkPath& path, const SkMatrix& matrix,
+                             const SkRect16* clipBounds,
+                             SkMask* mask, SkMask::CreateMode mode);
+
+private:
+    typedef SkFlattenable INHERITED;
+};
+
+#endif
diff --git a/include/graphics/SkRefCnt.h b/include/graphics/SkRefCnt.h
new file mode 100644 (file)
index 0000000..679f955
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef SkRefCnt_DEFINED
+#define SkRefCnt_DEFINED
+
+#include "SkTypes.h"
+
+/**    \class SkRefCnt
+
+       SkRefCnt is the base class for objects that may be shared by multiple objects.
+       When a new owner wants a reference, it calls ref(). When an owner wants to release
+       its reference, it calls unref(). When the shared object's reference count goes to
+       zero as the result of an unref() call, its (virtual) destructor is called. It is
+       an error for the destructor to be called explicitly (or via the object going out
+       of scope on the stack or calling delete) if getRefCnt() > 1.
+*/
+class SkRefCnt {
+public:
+       /**     Default construct, initializing the reference count to 1.
+       */
+                       SkRefCnt() : fRefCnt(1) {}
+       /**      Destruct, asserting that the reference count is 1.
+       */
+       virtual ~SkRefCnt() { SkASSERT(fRefCnt == 1); }
+
+       /**     Return the reference count.
+       */
+       int             getRefCnt() const { return fRefCnt; }
+       /**     Increment the reference count. Must be balanced by a call to unref().
+       */
+       void    ref() const { SkASSERT(fRefCnt > 0); ++fRefCnt; }
+       /**     Decrement the reference count. If the reference count is 1 before the
+               decrement, then call delete on the object. Note that if this is the case,
+               then the object needs to have been allocated via new, and not on the stack.
+       */
+       void    unref() const
+       {
+               SkASSERT(fRefCnt > 0);
+               if (fRefCnt == 1)
+                       delete this;
+               else
+                       --fRefCnt;
+       }
+
+       /**     Helper version of ref(), that first checks to see if this is not nil.
+               If this is nil, then do nothing.
+       */
+       void safeRef() const { if (this) this->ref(); }
+       /**     Helper version of unref(), that first checks to see if this is not nil.
+               If this is nil, then do nothing.
+       */
+       void safeUnref() const { if (this) this->unref(); }
+
+private:
+       mutable int     fRefCnt;
+};
+
+/**    \class SkAutoUnref
+
+       SkAutoUnref is a stack-helper class that will automatically call unref() on
+       the object it points to when the SkAutoUnref object goes out of scope.
+*/
+class SkAutoUnref {
+public:
+       SkAutoUnref(SkRefCnt* obj) : fObj(obj) {}
+       ~SkAutoUnref();
+
+       SkRefCnt*       get() const { return fObj; }
+       bool            ref();
+       bool            unref();
+       SkRefCnt*       detach();
+
+private:
+       SkRefCnt*       fObj;
+};
+
+/**    Helper macro to safely assign one SkRefCnt* to another, checking for
+       nil in on each side of the assignment, and ensuring that ref() is called
+       before unref(), in case the two pointers point to the same object.
+*/
+#define SkRefCnt_SafeAssign(dst, src)  \
+       do {                                                            \
+               if (src) src->ref();                    \
+               if (dst) dst->unref();                  \
+               dst = src;                                              \
+       } while (0)
+
+#endif
+
diff --git a/include/graphics/SkSVGAttribute.h b/include/graphics/SkSVGAttribute.h
new file mode 100644 (file)
index 0000000..b6ae0df
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef SkSVGAttribute_DEFINED
+#define SkSVGAttribute_DEFINED
+
+#include "SkTypes.h"
+
+struct SkSVGAttribute {
+       const char* fName;
+#ifdef SK_DEBUG
+       size_t fOffset;
+#endif
+};
+
+#ifndef SK_OFFSETOF
+#define SK_OFFSETOF(a, b) (((size_t) (&(((a*) 1)->b)))-1)
+#endif
+
+#ifdef SK_DEBUG
+#define SVG_ATTRIBUTE(attr) { #attr, SK_OFFSETOF(BASE_CLASS, f_##attr) }
+#define SVG_LITERAL_ATTRIBUTE(svgAttr, cAttr) { #svgAttr, SK_OFFSETOF(BASE_CLASS, cAttr) }
+#else
+#define SVG_ATTRIBUTE(attr) { #attr }
+#define SVG_LITERAL_ATTRIBUTE(svgAttr, cAttr) { #svgAttr }
+#endif
+
+#define SVG_ADD_ATTRIBUTE(attr) \
+       if (f_##attr.size() > 0) \
+               parser._addAttributeLen(#attr, f_##attr.c_str(), f_##attr.size())
+
+#define SVG_ADD_ATTRIBUTE_ALIAS(attr, alias) \
+       if (f_##alias.size() > 0) \
+               parser._addAttributeLen(#attr, f_##alias.c_str(), f_##alias.size())
+
+#endif // SkSVGAttribute_DEFINED
diff --git a/include/graphics/SkSVGBase.h b/include/graphics/SkSVGBase.h
new file mode 100644 (file)
index 0000000..83b72d9
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef SkSVGBase_DEFINED
+#define SkSVGBase_DEFINED
+
+#include "SkSVGAttribute.h"
+
+class SkSVGParser;
+
+class SkSVGBase {
+public:
+       virtual ~SkSVGBase();
+       virtual void addAttribute(SkSVGParser& parser, int attrIndex, 
+               const char* attrValue, size_t attrLength);
+       virtual int getAttributes(const SkSVGAttribute** attrPtr) = 0;
+};
+
+#endif // SkSVGBase_DEFINED
\ No newline at end of file
diff --git a/include/graphics/SkSVGPaintState.h b/include/graphics/SkSVGPaintState.h
new file mode 100644 (file)
index 0000000..4ec018d
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef SkSVGPaintState_DEFINED
+#define SkSVGPaintState_DEFINED
+
+#include "SkSVGBase.h"
+#include "SkString.h"
+
+class SkSVGPaint : public SkSVGBase {
+public:
+       enum Field {
+               kInitial = -1,
+               kClipPath,
+               kClipRule,
+               kEnableBackground,
+               kFill,
+               kFillRule,
+               kFilter,
+               kFontFamily,
+               kFontSize,
+               kLetterSpacing,
+               kMask,
+               kOpacity,
+               kStopColor,
+               kStopOpacity,
+               kStroke,
+               kStroke_Dasharray,
+               kStroke_Linecap,
+               kStroke_Linejoin,
+               kStroke_Miterlimit,
+               kStroke_Width,
+               kStyle,
+               kTransform,
+               kTerminal
+       };
+
+       SkSVGPaint();
+       virtual void addAttribute(SkSVGParser& parser, int attrIndex, 
+               const char* attrValue, size_t attrLength);
+       bool flush(SkSVGParser& , bool isFlushable, bool isDef);
+       virtual int getAttributes(const SkSVGAttribute** attrPtr); 
+       static void Push(SkSVGPaint** head, SkSVGPaint* add);
+       static void Pop(SkSVGPaint** head);
+       SkString* operator[](int index);
+       SkString fInitial;
+       SkString f_clipPath;
+       SkString f_clipRule;
+       SkString f_enableBackground;
+       SkString f_fill;
+       SkString f_fillRule;
+       SkString f_filter;
+       SkString f_fontFamily;
+       SkString f_fontSize;
+       SkString f_letterSpacing;
+       SkString f_mask;
+       SkString f_opacity;
+       SkString f_stopColor;
+       SkString f_stopOpacity;
+       SkString f_stroke;
+       SkString f_strokeDasharray;
+       SkString f_strokeLinecap;
+       SkString f_strokeLinejoin;
+       SkString f_strokeMiterlimit;
+       SkString f_strokeWidth;
+       SkString f_style; // unused, but allows array access to the rest
+       SkString f_transform;
+#ifdef SK_DEBUG
+       SkString fTerminal;
+#endif
+       SkString fTransformID;
+       static SkSVGAttribute gAttributes[];
+       static const int kAttributesSize;
+private:
+       void setSave(SkSVGParser& );
+       bool writeChangedAttributes(SkSVGParser& , SkSVGPaint& , bool* changed);
+       bool writeChangedElements(SkSVGParser& , SkSVGPaint& , bool* changed);
+       SkSVGPaint* fNext;
+       friend class SkSVGParser;
+       typedef SkSVGPaint BASE_CLASS;
+};
+
+#endif // SkSVGPaintState_DEFINED
diff --git a/include/graphics/SkSVGParser.h b/include/graphics/SkSVGParser.h
new file mode 100644 (file)
index 0000000..b001c22
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef SkSVGParser_DEFINED
+#define SkSVGParser_DEFINED
+
+#include "SkMatrix.h"
+#include "SkTDict.h"
+#include "SkTDStack.h"
+#include "SkSVGPaintState.h"
+#include "SkSVGTypes.h"
+#include "SkStream.h"
+#include "SkString.h"
+#include "SkXMLParser.h"
+#include "SkXMLWriter.h"
+
+class SkSVGBase;
+class SkSVGElement;
+
+class SkSVGParser : public SkXMLParser {
+public:
+       SkSVGParser();
+       virtual ~SkSVGParser();
+       void _addAttribute(const char* attrName, const char* attrValue) {
+               fXMLWriter.addAttribute(attrName, attrValue); }
+       void _addAttribute(const char* attrName, SkString& attrValue) {
+               fXMLWriter.addAttribute(attrName, attrValue.c_str()); }
+       void _addAttributeLen(const char* attrName, const char* attrValue, size_t len) {
+               fXMLWriter.addAttributeLen(attrName, attrValue, len); }
+       void _endElement() { fXMLWriter.endElement(); }
+       int findAttribute(SkSVGBase* , const char* attrValue, size_t len, bool isPaint);
+       const char* getFinal();
+       SkTDict<SkSVGElement*>& getIDs() { return fIDs; }
+       SkString& getPaintLast(SkSVGPaint::Field field);
+       void _startElement(const char name[]) { fXMLWriter.startElement(name); }
+       void translate(SkSVGElement*, bool isDef);
+       void translateMatrix(SkString& , SkString* id);
+       static void ConvertToArray(SkString& vals);
+protected:
+       virtual bool onAddAttribute(const char name[], const char value[]);
+       bool onAddAttributeLen(const char name[], const char value[], size_t len);
+       virtual bool onEndElement(const char elem[]);
+       virtual bool onStartElement(const char elem[]);
+       bool onStartElementLen(const char elem[], size_t len);
+       virtual bool onText(const char text[], int len);
+private:
+       bool isStrokeAndFill(SkSVGPaint** stroke, SkSVGPaint** fill);
+       static SkSVGElement* CreateElement(SkSVGTypes type, SkSVGElement* parent);
+       static void Delete(SkTDArray<SkSVGElement*>& fChildren);
+       static SkSVGTypes GetType(const char name[], size_t len);
+       SkSVGPaint* fHead;
+       SkSVGPaint fEmptyPaint; 
+       SkSVGPaint fLastFlush;
+       SkString fLastColor;
+       SkMatrix fLastTransform;
+       SkTDArray<SkSVGElement*> fChildren;
+       SkTDict<SkSVGElement*> fIDs;
+       SkTDArray<SkSVGElement*> fParents;
+       SkDynamicMemoryWStream fStream;
+       SkXMLStreamWriter fXMLWriter;
+       SkSVGElement*   fCurrElement;
+       SkBool8 fInSVG;
+       SkBool8 fSuppressPaint;
+       friend class SkSVGPaint;
+       friend class SkSVGGradient;
+};
+
+#endif // SkSVGParser_DEFINED
diff --git a/include/graphics/SkSVGTypes.h b/include/graphics/SkSVGTypes.h
new file mode 100644 (file)
index 0000000..b87bfbd
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef SkSVGTypes_DEFINED
+#define SkSVGTypes_DEFINED
+
+enum SkSVGTypes {
+       SkSVGType_Circle,
+       SkSVGType_ClipPath,
+       SkSVGType_Defs,
+       SkSVGType_Ellipse,
+       SkSVGType_FeColorMatrix,
+       SkSVGType_Filter,
+       SkSVGType_G,
+       SkSVGType_Image,
+       SkSVGType_Line,
+       SkSVGType_LinearGradient,
+       SkSVGType_Mask,
+       SkSVGType_Metadata,
+       SkSVGType_Path,
+       SkSVGType_Polygon,
+       SkSVGType_Polyline,
+       SkSVGType_RadialGradient,
+       SkSVGType_Rect,
+       SkSVGType_SVG,
+       SkSVGType_Stop,
+       SkSVGType_Symbol,
+       SkSVGType_Text,
+       SkSVGType_Tspan,
+       SkSVGType_Use
+};
+
+#endif // SkSVGTypes_DEFINED
diff --git a/include/graphics/SkScalerContext.h b/include/graphics/SkScalerContext.h
new file mode 100644 (file)
index 0000000..db12c73
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef SkScalerContext_DEFINED
+#define SkScalerContext_DEFINED
+
+#include "SkMatrix.h"
+#include "SkPath.h"
+#include "SkPoint.h"
+
+class SkDescriptor;
+class SkMaskFilter;
+class SkPaint;
+class SkPathEffect;
+class SkRasterizer;
+
+#define SK_UnknownAuxScalerContextID    0
+#define SK_MaxAuxScalerContextID        16
+
+struct SkGlyph {
+       void*       fImage;
+       SkPath*     fPath;
+       SkFixed     fAdvanceX, fAdvanceY;
+
+       uint16_t        fGlyphID;
+       uint16_t        fWidth, fHeight, fRowBytes;
+       int16_t         fTop, fLeft;
+
+       uint16_t        fCharCode;      // might go away with line layout. really wants 20bits
+       uint8_t         fMaskFormat;
+       SkBool8     fUseAuxContext; // just need 1-bit for this field
+
+       size_t computeImageSize() const;
+};
+
+class SkScalerContext {
+public:
+       struct Rec {
+               SkScalar        fTextSize, fPreScaleX, fPreSkewX;
+               SkScalar        fPost2x2[2][2];
+               SkScalar        fFrameWidth, fMiterLimit;
+               SkBool8         fUseHints;
+               SkBool8         fFrameAndFill;
+               SkBool8         fDoAA;
+               uint8_t         fStrokeJoin;
+
+               void    getMatrixFrom2x2(SkMatrix*) const;
+               void    getLocalMatrix(SkMatrix*) const;
+               void    getSingleMatrix(SkMatrix*) const;
+       };
+
+       SkScalerContext(const SkDescriptor* desc);
+       virtual ~SkScalerContext();
+
+       void    getMetrics(SkGlyph*);
+       void    getImage(const SkGlyph&);
+       void    getPath(const SkGlyph&, SkPath*);
+       void    getLineHeight(SkPoint* above, SkPoint* below);
+
+       static inline void MakeRec(const SkPaint&, const SkMatrix*, Rec* rec);
+       static SkScalerContext* Create(const SkDescriptor*);
+
+protected:
+       Rec     fRec;
+
+       virtual void generateMetrics(SkGlyph*) = 0;
+       virtual void generateImage(const SkGlyph&) = 0;
+       virtual void generatePath(const SkGlyph&, SkPath*) = 0;
+       virtual void generateLineHeight(SkPoint* above, SkPoint* below) = 0;
+
+private:
+       SkPathEffect*   fPathEffect;
+       SkMaskFilter*   fMaskFilter;
+    SkRasterizer*   fRasterizer;
+       SkScalar                fDevFrameWidth;
+
+    void internalGetPath(const SkGlyph& glyph, SkPath* fillPath, SkPath* devPath, SkMatrix* fillToDevMatrix);
+
+    // we index into this with scalerContextID-1
+    SkScalerContext* fAuxContext[SK_MaxAuxScalerContextID];
+};
+
+#define kRec_SkDescriptorTag                   SkSetFourByteTag('s', 'r', 'e', 'c')
+#define kTypeface_SkDescriptorTag              SkSetFourByteTag('t', 'p', 'f', 'c')
+#define kPathEffect_SkDescriptorTag            SkSetFourByteTag('p', 't', 'h', 'e')
+#define kMaskFilter_SkDescriptorTag            SkSetFourByteTag('m', 's', 'k', 'f')
+#define kRasterizer_SkDescriptorTag            SkSetFourByteTag('r', 'a', 's', 't')
+
+#endif
+
diff --git a/include/graphics/SkScrollBarView.h b/include/graphics/SkScrollBarView.h
new file mode 100644 (file)
index 0000000..ee43a3c
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef SkScrollBarView_DEFINED
+#define SkScrollBarView_DEFINED
+
+#include "SkView.h"
+#include "SkWidgetViews.h"
+#include "SkAnimator.h"
+
+class SkScrollBarView : public SkWidgetView {
+public:
+       SkScrollBarView();
+
+       unsigned getStart() const { return fStartPoint; }
+       unsigned getShown() const { return fShownLength; }
+       unsigned getTotal() const { return fTotalLength; }
+
+       void setStart(unsigned start);  
+       void setShown(unsigned shown);
+       void setTotal(unsigned total);
+       
+protected:
+       //overrides
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node);
+       virtual void onSizeChange();
+       virtual void onDraw(SkCanvas* canvas);
+       virtual bool onEvent(const SkEvent& evt);
+
+private:
+       SkAnimator      fAnim;
+       unsigned        fTotalLength, fStartPoint, fShownLength;
+       
+       void adjust();
+       
+       typedef SkWidgetView INHERITED;
+};
+#endif
\ No newline at end of file
diff --git a/include/graphics/SkShader.h b/include/graphics/SkShader.h
new file mode 100644 (file)
index 0000000..e823a7b
--- /dev/null
@@ -0,0 +1,146 @@
+#ifndef SkShader_DEFINED
+#define SkShader_DEFINED
+
+#include "SkRefCnt.h"
+#include "SkBitmap.h"
+#include "SkMask.h"
+#include "SkMatrix.h"
+#include "SkPaint.h"
+
+class SkPath;
+
+/**    \class SkShader
+
+       SkShader is the based class for objects that return horizontal spans of colors during drawing.
+       A subclass of SkShader is installed in a SkPaint calling paint.setShader(shader). After that
+       any object (other than a bitmap) that is drawn with that paint will get its color(s) from the
+       shader.
+*/
+class SkShader : public SkRefCnt {
+public:
+                       SkShader();
+       virtual ~SkShader();
+
+       /**     Return the shader's optional local matrix, or nil.
+       */
+       const SkMatrix* getLocalMatrix() const { return fLocalMatrix; }
+       /**     Set the shader's optional local matrix. If the specified matrix is identity, then
+               getLocalMatrix() will return nil.
+       */
+       void setLocalMatrix(const SkMatrix&);
+
+       enum TileMode {
+               kClamp_TileMode,        //!< replicate the edge color if the shader draws outside of its original bounds
+               kRepeat_TileMode,       //!< repeat the shader's image horizontally and vertically
+               kMirror_TileMode,       //!< repeat the shader's image horizontally and vertically, alternating mirror images so that adjacent images always seam
+
+               kTileModeCount
+       };
+
+       // override these in your subclass
+
+       enum Flags {
+               kOpaqueAlpha_Flag       = 0x01, //!< set if all of the colors will be opaque (if so, kConstAlpha_Flag will not be set)
+               kConstAlpha_Flag        = 0x02, //!< set if all of the colors have the same (non-opaque) alpha
+               kHasSpan16_Flag         = 0x04, //!< set if this shader's shadeSpanOpaque16() method can be called
+
+               kFlagsMask                      = kOpaqueAlpha_Flag | kConstAlpha_Flag | kHasSpan16_Flag
+       };
+
+       /**     Called sometimes before drawing with this shader.
+               Return the type of alpha your shader will return.
+               The default implementation returns 0. Your subclass should override if it can
+               (even sometimes) report a non-zero value, since that will enable various blitters
+               to perform faster.
+       */
+       virtual U32             getFlags();
+
+       /**     Called once before drawing, with the current paint and
+               device matrix. Return true if your shader supports these
+               parameters, or false if not. If false is returned, nothing
+               will be drawn.
+       */
+       virtual bool    setContext(     const SkBitmap& device,
+                                                               const SkPaint& paint,
+                                                               const SkMatrix& matrix);
+
+       /**     Called for each span of the object being drawn. Your subclass
+               should set the appropriate colors (with premultiplied alpha) that
+               correspond to the specified device coordinates.
+       */
+       virtual void    shadeSpan(int x, int y, SkPMColor[], int count) = 0;
+       /**     Called only for 16bit devices when getFlags() returns kOpaqueAlphaFlag | kHasSpan16_Flag
+       */
+       virtual void    shadeSpanOpaque16(int x, int y, U16[], int count);
+       /**     Similar to shadeSpan, but only returns the alpha-channel for a span.
+               The default implementation calls shadeSpan() and then extracts the alpha
+               values from the returned colors.
+       */
+       virtual void    shadeSpanAlpha(int x, int y, U8 alpha[], int count);
+
+       /**     Helper function that returns true if this shader's shadeSpanOpaque16() method can
+               be called.
+       */
+       bool canCallShadeSpanOpaque16()
+       {
+               return SkShader::CanCallShadeSpanOpaque16(this->getFlags());
+       }
+
+       /**     Helper to check the flags to know if it is legal to call shadeSpanOpaque16()
+       */
+       static bool CanCallShadeSpanOpaque16(U32 flags)
+       {
+               return (flags & (kOpaqueAlpha_Flag | kHasSpan16_Flag)) == (kOpaqueAlpha_Flag | kHasSpan16_Flag);
+       }
+
+       //////////////////////////////////////////////////////////////////////////
+       //      Factory methods for stock shaders
+
+       /**     Call this to create a new shader that will draw with the specified bitmap.
+               @param src      The bitmap to use inside the shader
+               @param transferOwnershipOfPixels        If true, the shader will call setOwnsPixels(true) on its private bitmap
+                                                                                       and setOwnsPixels(false) on the src bitmap, resulting in the bitmap's pixels
+                                                                                       being disposed when the shader is deleted.
+               @param ft       The filter type to be used when scaling or rotating the bitmap when it is drawn.
+               @param tmx      The tiling mode to use when sampling the bitmap in the x-direction.
+               @param tmy      The tiling mode to use when sampling the bitmap in the y-direction.
+               @return         Returns a new shader object. Note: this function never returns nil.
+       */
+       static SkShader* CreateBitmapShader(const SkBitmap& src,
+                                                                               bool transferOwnershipOfPixels,
+                                                                               SkPaint::FilterType ft,
+                                                                               TileMode tmx, TileMode tmy);
+
+protected:
+       enum MatrixClass {
+               kLinear_MatrixClass,                    // no perspective
+               kFixedStepInX_MatrixClass,              // fast perspective, need to call fixedStepInX() each scanline
+               kPerspective_MatrixClass                // slow perspective, need to mappoints each pixel
+       };
+       static MatrixClass ComputeMatrixClass(const SkMatrix&);
+
+       // These can be called by your subclass after setContext() has been called
+       U8                               getPaintAlpha() const { return fPaintAlpha; }
+       SkBitmap::Config getDeviceConfig() const { return (SkBitmap::Config)fDeviceConfig; }
+       const SkMatrix&  getTotalInverse() const { return fTotalInverse; }
+       MatrixClass              getInverseClass() const { return (MatrixClass)fTotalInverseClass; }
+       SkMatrix::MapPtProc     getInverseMapPtProc() const { return fInverseMapPtProc; }
+
+private:
+       SkMatrix*       fLocalMatrix;
+       SkMatrix        fTotalInverse;
+       SkMatrix::MapPtProc     fInverseMapPtProc;
+       U8                      fPaintAlpha;
+       U8                      fDeviceConfig;
+       U8                      fTotalInverseClass;
+
+       static SkShader* CreateBitmapShader(const SkBitmap& src,
+                                                                               bool transferOwnershipOfPixels,
+                                                                               SkPaint::FilterType,
+                                                                               TileMode, TileMode,
+                                                                               void* storage, size_t storageSize);
+       friend class SkAutoBitmapShaderInstall;
+};
+
+#endif
+
diff --git a/include/graphics/SkShaderExtras.h b/include/graphics/SkShaderExtras.h
new file mode 100644 (file)
index 0000000..e914304
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef SkShaderExtras_DEFINED
+#define SkShaderExtras_DEFINED
+
+#include "SkShader.h"
+
+class SkColorCombine :  public SkRefCnt {
+public:
+    /** Called with two scanlines of color. The implementation writes out its combination of
+        those into the result[] scaline.
+    */
+    virtual void combineSpan(const SkPMColor srcA[], const SkPMColor srcB[], int count, SkPMColor result[]) = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+class SkComposeShader : public SkShader {
+public:
+    SkComposeShader(SkShader* sA, SkShader* sB, SkColorCombine* combine);
+    virtual ~SkComposeShader();
+    
+    // override
+    virtual bool setContext(const SkBitmap& device, const SkPaint& paint, const SkMatrix& matrix);
+    virtual void shadeSpan(int x, int y, SkPMColor result[], int count);
+
+private:
+    enum {
+        COUNT = 32
+    };
+    SkShader*       fShaderA;
+    SkShader*       fShaderB;
+    SkColorCombine* fCombine;
+
+    typedef SkShader INHERITED;
+};
+
+#endif
diff --git a/include/graphics/SkStackViewLayout.h b/include/graphics/SkStackViewLayout.h
new file mode 100644 (file)
index 0000000..778a32c
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef SkStackViewLayout_DEFINED
+#define SkStackViewLayout_DEFINED
+
+#include "SkView.h"
+
+class SkStackViewLayout : public SkView::Layout {
+public:
+       SkStackViewLayout();
+
+       enum Orient {
+               kHorizontal_Orient,
+               kVertical_Orient,
+
+               kOrientCount
+       };
+       Orient  getOrient() const { return (Orient)fOrient; }
+       void    setOrient(Orient);
+
+       void            getMargin(SkRect*) const;
+       void            setMargin(const SkRect&);
+
+       SkScalar        getSpacer() const { return fSpacer; }
+       void            setSpacer(SkScalar);
+
+       /**     Controls the posititioning in the same direction as the orientation
+       */
+       enum Pack {
+               kStart_Pack,
+               kCenter_Pack,
+               kEnd_Pack,
+               
+               kPackCount
+       };
+       Pack    getPack() const { return (Pack)fPack; }
+       void    setPack(Pack);
+
+       /**     Controls the posititioning at right angles to the orientation
+       */
+       enum Align {
+               kStart_Align,
+               kCenter_Align,
+               kEnd_Align,
+               kStretch_Align,
+
+               kAlignCount
+       };
+       Align   getAlign() const { return (Align)fAlign; }
+       void    setAlign(Align);
+
+       bool    getRound() const { return SkToBool(fRound); }
+       void    setRound(bool);
+
+protected:
+       virtual void onLayoutChildren(SkView* parent);
+       virtual void onInflate(const SkDOM&, const SkDOM::Node*);
+
+private:
+       SkRect          fMargin;
+       SkScalar        fSpacer;
+       U8                      fOrient, fPack, fAlign, fRound;
+};
+
+class SkFillViewLayout : public SkView::Layout {
+public:
+                       SkFillViewLayout();
+       void    getMargin(SkRect*) const;
+       void    setMargin(const SkRect&);
+
+protected:
+       // overrides;
+       virtual void onLayoutChildren(SkView* parent);
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node);
+
+private:
+       SkRect  fMargin;
+       typedef SkView::Layout INHERITED;
+};
+
+#endif
+
diff --git a/include/graphics/SkStdLib_Redirect.h b/include/graphics/SkStdLib_Redirect.h
new file mode 100644 (file)
index 0000000..d5525e1
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef SkStdLib_Redirect_DEFINED
+#define SkStdLib_Redirect_DEFINED
+
+#error
+
+#include "SkTypes.h"
+
+#define fread(buffer, count, size, file)       sk_stdlib_fread(buffer, count, size, file)
+#define qsort
+#define tolower
+#define setjmp
+#define longjmp
+#define memmove
+#define malloc
+#define realloc
+#endif
+
diff --git a/include/graphics/SkStream.h b/include/graphics/SkStream.h
new file mode 100644 (file)
index 0000000..14c71d3
--- /dev/null
@@ -0,0 +1,199 @@
+#ifndef SkStream_DEFINED
+#define SkStream_DEFINED
+
+#include "SkScalar.h"
+
+class SkStream {
+public:
+       virtual ~SkStream() {}
+       /**     Called to rewind to the beginning of the stream. If this cannot be
+               done, return false.
+       */
+       virtual bool rewind() = 0;
+       /**     If this stream represents a file, this method returns the file's name.
+               If it does not, it returns nil (the default behavior).
+       */
+       virtual const char* getFileName();
+       /**     Called to read or skip size number of bytes. If buffer is nil, skip
+               the bytes, else copy them into buffer. If this cannot be done, return false.
+               If buffer is nil and size is zero, return the file length
+               @param buffer   If buffer is nil, ignore and just skip size bytes, otherwise copy size bytes into buffer
+               @param size     The number of bytes to skip or copy
+               @return bytes read on success
+       */
+       virtual size_t read(void* buffer, size_t size) = 0;
+       static SkStream* GetURIStream(const char prefix[], const char path[]);
+       static bool IsAbsoluteURI(const char path[]);
+};
+
+class SkWStream {
+public:
+       virtual ~SkWStream();
+
+       /**     Called to write bytes to a SkWStream. Returns true on success
+               @param buffer the address of at least size bytes to be written to the stream
+               @param size     The number of bytes in buffer to write to the stream
+               @return true on success
+       */
+       virtual bool write(const void* buffer, size_t size) = 0;
+       virtual void newline();
+       virtual void flush();
+
+       // helpers
+
+       bool    writeText(const char text[]);
+       bool    writeDecAsText(S32);
+       bool    writeHexAsText(U32, int minDigits = 0);
+       bool    writeScalarAsText(SkScalar);
+
+       SkDEBUGCODE(static void UnitTest();)
+};
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkString.h"
+
+struct SkFILE;
+
+class SkFILEStream : public SkStream {
+public:
+       SkFILEStream(const char path[] = nil);
+       virtual ~SkFILEStream();
+
+       /**     Returns true if the current path could be opened.
+       */
+       bool isValid() const { return fFILE != nil; }
+       /**     Close the current file, and open a new file with the specified
+               path. If path is nil, just close the current file.
+       */
+       void setPath(const char path[]);
+    
+    SkFILE* getSkFILE() const { return fFILE; }
+
+       virtual bool rewind();
+       virtual size_t read(void* buffer, size_t size);
+       virtual const char* getFileName();
+
+private:
+       SkFILE*         fFILE;
+       SkString        fName;
+};
+
+class SkMemoryStream : public SkStream {
+public:
+       SkMemoryStream(const void* src, size_t length);
+
+       virtual bool rewind();
+       virtual size_t read(void* buffer, size_t size);
+
+private:
+       const void* fSrc;
+       size_t fSize, fOffset;
+};
+
+/**    \class SkBufferStream
+       This is a wrapper class that adds buffering to another stream.
+       The caller can provide the buffer, or ask SkBufferStream to allocated/free
+       it automatically.
+*/
+class SkBufferStream : public SkStream {
+public:
+       /**     Provide the stream to be buffered (proxy), and the size of the buffer that
+               should be used. This will be allocated and freed automatically. If bufferSize is 0,
+               a default buffer size will be used.
+       */
+       SkBufferStream(SkStream& proxy, size_t bufferSize = 0);
+       /**     Provide the stream to be buffered (proxy), and a buffer and size to be used.
+               This buffer is owned by the caller, and must be at least bufferSize bytes big.
+               Passing nil for buffer will cause the buffer to be allocated/freed automatically.
+               If buffer is not nil, it is an error for bufferSize to be 0.
+       */
+       SkBufferStream(SkStream& proxy, void* buffer, size_t bufferSize);
+       virtual ~SkBufferStream();
+
+       virtual bool            rewind();
+       virtual const char*     getFileName();
+       virtual size_t          read(void* buffer, size_t size);
+private:
+       enum {
+               kDefaultBufferSize      = 128
+       };
+       // illegal
+       SkBufferStream(const SkBufferStream&);
+       SkBufferStream& operator=(const SkBufferStream&);
+
+       SkStream&       fProxy;
+       char*           fBuffer;
+       size_t          fOrigBufferSize, fBufferSize, fBufferOffset;
+       bool            fWeOwnTheBuffer;
+
+       void    init(void*, size_t);
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+
+class SkFILEWStream : public SkWStream {
+public:
+                       SkFILEWStream(const char path[]);
+       virtual ~SkFILEWStream();
+
+       /**     Returns true if the current path could be opened.
+       */
+       bool isValid() const { return fFILE != nil; }
+
+       virtual bool write(const void* buffer, size_t size);
+       virtual void flush();
+private:
+       SkFILE* fFILE;
+};
+
+class SkMemoryWStream : public SkWStream {
+public:
+       SkMemoryWStream(void* buffer, size_t size);
+       virtual bool write(const void* buffer, size_t size);
+    
+private:
+    char*   fBuffer;
+    size_t  fMaxLength;
+       size_t  fBytesWritten;
+};
+
+class SkDynamicMemoryWStream : public SkWStream {
+public:
+       SkDynamicMemoryWStream();
+       virtual ~SkDynamicMemoryWStream();
+       virtual bool write(const void* buffer, size_t size);
+    // random access write
+    // modifies stream and returns true if offset + size is less than or equal to getOffset()
+    bool write(const void* buffer, size_t offset, size_t size); 
+       size_t getOffset() { return fBytesWritten; }
+
+    // copy what has been written to the stream into dst
+    void    copyTo(void* dst) const;
+    /*  return a cache of the flattened data returned by copyTo().
+        This copy is only valid until the next call to write().
+        The memory is managed by the stream class.
+    */
+    const char* getStream() const;
+
+private:
+    struct Block;
+    Block*  fHead;
+    Block*  fTail;
+       size_t  fBytesWritten;
+    mutable char*   fCopyToCache;
+};
+
+
+class SkDebugWStream : public SkWStream {
+public:
+       // overrides
+       virtual bool write(const void* buffer, size_t size);
+       virtual void newline();
+};
+
+// for now
+typedef SkFILEStream SkURLStream;
+
+#endif
+
diff --git a/include/graphics/SkStream_Win.h b/include/graphics/SkStream_Win.h
new file mode 100644 (file)
index 0000000..8fdef0a
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef SkStream_Win_DEFINED
+#define SkStream_Win_DEFINED
+
+#ifndef SK_BUILD_FOR_WIN
+#error "only valid for windows and wince builds"
+#endif
+
+#ifndef SkStream_DEFINED
+#include "SkStream.h"
+#endif
+#include "SkString.h"
+#include "Wininet.h"
+
+/** \cond ZERO */
+class SkURLStream : public SkStream {
+public:
+       SkURLStream(const char url[] = nil);
+       virtual ~SkURLStream();
+
+       /**     Close the current URL, and open a new URL.
+               If URL is nil, just close the current URL.
+       */
+       void setURL(const char url[]);
+
+       // overrides
+       virtual bool rewind();
+       virtual size_t read(void* buffer, size_t size);
+       
+private:
+       SkString fURL;
+       HINTERNET fConnection;
+       HINTERNET fURLStream;
+};
+
+/** \endcond */
+#endif // SkStream_Win_DEFINED
+
diff --git a/include/graphics/SkString.h b/include/graphics/SkString.h
new file mode 100644 (file)
index 0000000..84b8493
--- /dev/null
@@ -0,0 +1,150 @@
+#ifndef SkString_DEFINED
+#define SkString_DEFINED
+
+#include "SkScalar.h"
+
+/*     Some helper functions for C strings
+*/
+
+bool SkStrStartsWith(const char string[], const char prefix[]);
+bool SkStrEndsWith(const char string[], const char suffix[]);
+int SkStrStartsWithOneOf(const char string[], const char prefixes[]);
+
+#define SkStrAppendS32_MaxSize  11
+char*   SkStrAppendS32(char buffer[], int32_t);
+#define SkStrAppendScalar_MaxSize  11
+char*   SkStrAppendScalar(char buffer[], SkScalar);
+
+/**    \class SkString
+
+       Light weight class for managing strings. Uses reference
+       counting to make string assignments and copies very fast
+       with no extra RAM cost. Assumes UTF8 encoding.
+*/
+class SkString {
+public:
+                               SkString();
+       explicit        SkString(size_t len);
+       explicit        SkString(const char text[]);
+                               SkString(const char text[], size_t len);
+       explicit        SkString(const SkString&);
+                               ~SkString();
+
+       bool            isEmpty() const { return fRec->fLength == 0; }
+       size_t          size() const { return (size_t) fRec->fLength; }
+       const char*     c_str() const { return fRec->data(); }
+
+       bool    equals(const SkString&) const;
+       bool    equals(const char text[]) const;
+       bool    equals(const char text[], size_t len) const;
+
+       bool    startsWith(const char prefix[]) const
+       {
+               return SkStrStartsWith(fRec->data(), prefix);
+       }
+       bool    endsWith(const char suffix[]) const
+       {
+               return SkStrEndsWith(fRec->data(), suffix);
+       }
+
+       friend int operator==(const SkString& a, const SkString& b)
+       {
+               return a.equals(b);
+       }
+       friend int operator!=(const SkString& a, const SkString& b)
+       {
+               return !a.equals(b);
+       }
+
+       // these methods edit the string
+
+       SkString&       operator=(const SkString&);
+
+       char*   writable_str();
+
+       void    reset();
+       void    resize(size_t len) { this->set(nil, len); }
+       void    set(const SkString& src) { *this = src; }
+       void    set(const char text[]);
+       void    set(const char text[], size_t len);
+       void    setUTF16(const U16[]);
+
+       void    insert(size_t offset, const SkString& src) { this->insert(offset, src.c_str(), src.size()); }
+       void    insert(size_t offset, const char text[]);
+       void    insert(size_t offset, const char text[], size_t len);
+       void    insertUnichar(size_t offset, SkUnichar);
+       void    insertS32(size_t offset, S32 value);
+       void    insertHex(size_t offset, U32 value, int minDigits = 0);
+       void    insertScalar(size_t offset, SkScalar);
+
+       void    append(const SkString& str) { this->insert((size_t)-1, str); }
+       void    append(const char text[]) { this->insert((size_t)-1, text); }
+       void    append(const char text[], size_t len) { this->insert((size_t)-1, text, len); }
+       void    appendUnichar(SkUnichar uni) { this->insertUnichar((size_t)-1, uni); }
+       void    appendS32(S32 value) { this->insertS32((size_t)-1, value); }
+       void    appendHex(U32 value, int minDigits = 0) { this->insertHex((size_t)-1, value, minDigits); }
+       void    appendScalar(SkScalar value) { this->insertScalar((size_t)-1, value); }
+
+       void    prepend(const SkString& str) { this->insert(0, str); }
+       void    prepend(const char text[]) { this->insert(0, text); }
+       void    prepend(const char text[], size_t len) { this->insert(0, text, len); }
+       void    prependUnichar(SkUnichar uni) { this->insertUnichar(0, uni); }
+       void    prependS32(S32 value) { this->insertS32(0, value); }
+       void    prependHex(U32 value, int minDigits = 0) { this->insertHex(0, value, minDigits); }
+       void    prependScalar(SkScalar value) { this->insertScalar((size_t)-1, value); }
+
+       void    printf(const char format[], ...);
+
+       void    remove(size_t offset, size_t length);
+
+       /**     Swap contents between this and other. This function is guaranteed
+               to never fail or throw.
+       */
+       void    swap(SkString& other);
+
+  /** @cond UNIT_TEST */
+       SkDEBUGCODE(static void UnitTest();)
+  /** @endcond */
+    
+private:
+#ifdef SK_DEBUG
+       const char* fStr;
+#endif
+       struct Rec {
+               U16     fLength;
+               U16     fRefCnt;
+               // data[]
+               char* data() { return (char*)(this) + sizeof(Rec); }
+               const char* data() const { return (const char*)(this) + sizeof(Rec); }
+       };
+       Rec* fRec;
+
+#ifdef SK_DEBUG
+       void validate() const;
+#else
+       void validate() const {}
+#endif
+
+       static Rec*     AllocRec(const char text[], U16CPU len);
+       static Rec*     RefRec(Rec*);
+};
+
+class SkAutoUCS2 {
+public:
+       SkAutoUCS2(const char utf8[]);
+       ~SkAutoUCS2();
+
+       /**     This returns the number of ucs2 characters
+       */
+       int                     count() const { return fCount; }
+       /**     This returns a null terminated ucs2 string
+       */
+       const U16*      getUCS2() const { return fUCS2; }
+
+private:
+       int             fCount;
+       U16*    fUCS2;
+};
+
+#endif
+
diff --git a/include/graphics/SkStroke.h b/include/graphics/SkStroke.h
new file mode 100644 (file)
index 0000000..8b148a4
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef SkStroke_DEFINED
+#define SkStroke_DEFINED
+
+#include "SkPoint.h"
+#include "SkPaint.h"
+
+struct SkRect;
+class SkPath;
+
+#define SK_DefaultStrokeWidth          SK_Scalar1
+#define SK_DefaultMiterLimit           SkIntToScalar(4)
+
+
+/**    \class SkStroke
+       SkStroke is the utility class that constructs paths by stroking
+       geometries (lines, rects, ovals, roundrects, paths). This is
+       invoked when a geometry or text is drawn in a canvas with the
+       kStroke_Mask bit set in the paint.
+*/
+class SkStroke {
+public:
+       SkStroke();
+       SkStroke(const SkPaint&);
+       SkStroke(const SkPaint&, SkScalar width);       // width overrides paint.getStrokeWidth()
+
+       SkPaint::Cap    getCap() const { return (SkPaint::Cap)fCap; }
+       void            setCap(SkPaint::Cap);
+
+       SkPaint::Join   getJoin() const { return (SkPaint::Join)fJoin; }
+       void            setJoin(SkPaint::Join);
+
+//     SkScalar        getMiterLimit() const { return fMiterLimit; }
+       void            setMiterLimit(SkScalar);
+
+//     SkScalar        getWidth() const { return fWidth; }
+       void            setWidth(SkScalar);
+
+       bool            getDoFill() const { return SkToBool(fDoFill); }
+       void            setDoFill(bool doFill) { fDoFill = SkToU8(doFill); }
+
+       void    strokeLine(const SkPoint& start, const SkPoint& end, SkPath*) const;
+       void    strokeRect(const SkRect& rect, SkPath*) const;
+       void    strokeOval(const SkRect& oval, SkPath*) const;
+       void    strokeRRect(const SkRect& rect, SkScalar rx, SkScalar ry, SkPath*) const;
+       void    strokePath(const SkPath& path, SkPath*) const;
+
+       ////////////////////////////////////////////////////////////////
+
+private:
+       SkScalar        fWidth, fMiterLimit;
+       U8                      fCap, fJoin;
+       SkBool8         fDoFill;
+
+       friend class SkPaint;
+};
+
+#endif
+
diff --git a/include/graphics/SkSystemEventTypes.h b/include/graphics/SkSystemEventTypes.h
new file mode 100644 (file)
index 0000000..3cf826c
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef SkSystemEventTypes_DEFINED
+#define SkSystemEventTypes_DEFINED
+
+/*
+       The goal of these strings is two-fold:
+       1) make funny strings (containing at least one char < 32) to avoid colliding with "user" strings
+       2) keep them <= 4 bytes, so we can avoid an allocation in SkEvent::setType()
+*/
+#define SK_EventType_Delay             "\xd" "lay"
+#define SK_EventType_Inval             "nv" "\xa" "l"
+#define SK_EventType_Key               "key" "\x1" 
+#define SK_EventType_OnEnd "on" "\xe" "n"
+#define SK_EventType_Unichar   "\xc" "har"
+#define SK_EventType_KeyUp      "key" "\xf"
+
+#endif
diff --git a/include/graphics/SkTDArray.h b/include/graphics/SkTDArray.h
new file mode 100644 (file)
index 0000000..d33205b
--- /dev/null
@@ -0,0 +1,288 @@
+#ifndef SkTDArray_DEFINED
+#define SkTDArray_DEFINED
+
+#include "SkTypes.h"
+
+template <typename T> class SkTDArray {
+public:
+       SkTDArray()
+       {
+               fReserve = fCount = 0;
+               fArray = NULL;
+#ifdef SK_DEBUG
+               fData = NULL;
+#endif
+       }
+       SkTDArray(const T src[], U16CPU count)
+       {
+               SkASSERT(src || count == 0);
+
+               fReserve = fCount = 0;
+               fArray = NULL;
+#ifdef SK_DEBUG
+               fData = NULL;
+#endif
+               if (count)
+               {
+                       fArray = (T*)sk_malloc_throw(count * sizeof(T));
+#ifdef SK_DEBUG
+               //      fData = (T (*)[kDebugArraySize]) fArray;
+                       (T*&)fData = fArray;
+#endif
+                       memcpy(fArray, src, sizeof(T) * count);
+                       fReserve = fCount = SkToU16(count);
+               }
+       }
+       SkTDArray(const SkTDArray<T>& src)
+       {
+               fReserve = fCount = 0;
+               fArray = NULL;
+#ifdef SK_DEBUG
+               fData = NULL;
+#endif
+               SkTDArray<T> tmp(src.fArray, src.fCount);
+               this->swap(tmp);
+       }
+       ~SkTDArray()
+       {
+               sk_free(fArray);
+       }
+
+       SkTDArray<T>& operator=(const SkTDArray<T>& src)
+       {
+               if (this != &src)
+               {
+                       if (src.fCount > fReserve)
+                       {
+                               SkTDArray<T> tmp(src.fArray, src.fCount);
+                               this->swap(tmp);
+                       }
+                       else
+                       {
+                               memcpy(fArray, src.fArray, sizeof(T) * src.fCount);
+                               fCount = src.fCount;
+                       }
+               }
+               return *this;
+       }
+
+       friend int operator==(const SkTDArray<T>& a, const SkTDArray<T>& b)
+       {
+               return  a.fCount == b.fCount &&
+                               (a.fCount == 0 || !memcmp(a.fArray, b.fArray, a.fCount * sizeof(T)));
+       }
+
+       void swap(SkTDArray<T>& other)
+       {
+               SkTSwap(fArray, other.fArray);
+#ifdef SK_DEBUG
+               SkTSwap(fData, other.fData);
+#endif
+               SkTSwap(fReserve, other.fReserve);
+               SkTSwap(fCount, other.fCount);
+       }
+
+       bool isEmpty() const { return fCount == 0; }
+       int     count() const { return fCount; }
+       T*      begin() const { return fArray; }
+       T*      end() const { return fArray ? fArray + fCount : NULL; }
+       T&      operator[](int index) const { SkASSERT((unsigned)index < fCount); return fArray[index]; }
+
+       void reset()
+       {
+               if (fArray)
+               {
+                       sk_free(fArray);
+                       fArray = NULL;
+#ifdef SK_DEBUG
+                       fData = NULL;
+#endif
+                       fReserve = fCount = 0;
+               }
+               else
+               {
+                       SkASSERT(fReserve == 0 && fCount == 0);
+               }
+       }
+
+       void setCount(U16CPU count)
+       {
+               if (count > fReserve)
+                       this->growBy(count - fCount);
+               else
+                       fCount = SkToU16(count);
+       }
+
+       void setReserve(U16CPU reserve)
+       {
+               if (reserve > fReserve)
+               {
+                       SkASSERT(reserve > fCount);
+                       U16     count = fCount;
+                       this->growBy(reserve - fCount);
+                       fCount = count;
+               }
+       }
+
+       T* prepend()
+       {
+               this->growBy(1);
+               memmove(fArray + 1, fArray, (fCount - 1) * sizeof(T));
+               return fArray;
+       }
+
+       T* append() { return this->append(1, NULL); }
+       T* append(U16CPU count, const T* src = NULL)
+       {
+               unsigned oldCount = fCount;
+               if (count)
+               {
+                       SkASSERT(src == NULL || fArray == NULL ||
+                                       src + count <= fArray || fArray + oldCount <= src);
+
+                       this->growBy(count);
+                       if (src)
+                               memcpy(fArray + oldCount, src, sizeof(T) * count);
+               }
+               return fArray + oldCount;
+       }
+       
+       T* appendClear()
+       {
+               T* result = this->append(); 
+               *result = 0;
+               return result;
+       }
+
+       T* insert(U16CPU index) { return this->insert(index, 1, NULL); }
+       T* insert(U16CPU index, U16CPU count, const T* src = NULL)
+       {
+               SkASSERT(count);
+               int oldCount = fCount;
+               this->growBy(count);
+               T* dst = fArray + index;
+               memmove(dst + count, dst, sizeof(T) * (oldCount - index));
+               if (src)
+                       memcpy(dst, src, sizeof(T) * count);
+               return dst;
+       }
+
+       void remove(U16CPU index, U16CPU count = 1)
+       {
+               SkASSERT(index + count <= fCount);
+               fCount = SkToU16(fCount - count);
+               memmove(fArray + index, fArray + index + count, sizeof(T) * (fCount - index));
+       }
+
+       void removeShuffle(U16CPU index)
+       {
+               SkASSERT(index < fCount);
+               unsigned newCount = fCount - 1;
+               fCount = SkToU16(newCount);
+               if (index != newCount)
+                       memcpy(fArray + index, fArray + newCount, sizeof(T));
+       }
+
+       int find(const T& elem) const
+       {
+               const T* iter = fArray;
+               const T* stop = fArray + fCount;
+
+               for (; iter < stop; iter++)
+               {
+                       if (*iter == elem)
+                               return (int) (iter - fArray);
+               }
+               return -1;
+       }
+
+       int rfind(const T& elem) const
+       {
+               const T* iter = fArray + fCount;
+               const T* stop = fArray;
+
+               while (iter > stop)
+               {
+                       if (*--iter == elem)
+                               return iter - stop;
+               }
+               return -1;
+       }
+
+       // routines to treat the array like a stack
+       T*                      push() { return this->append(); }
+       void            push(T& elem) { *this->append() = elem; }
+       const T&        top() const { return (*this)[fCount - 1]; }
+       T&                      top() { return (*this)[fCount - 1]; }
+       void            pop(T* elem) { if (elem) *elem = (*this)[fCount - 1]; --fCount; }
+       void            pop() { --fCount; }
+
+       void deleteAll()
+       {
+               T*      iter = fArray;
+               T*      stop = fArray + fCount;
+               while (iter < stop)
+               {
+                       delete (*iter);
+                       iter += 1;
+               }
+               this->reset();
+       }
+
+       void freeAll()
+       {
+               T*      iter = fArray;
+               T*      stop = fArray + fCount;
+               while (iter < stop)
+               {
+                       sk_free(*iter);
+                       iter += 1;
+               }
+               this->reset();
+       }
+
+       void unrefAll()
+       {
+               T*      iter = fArray;
+               T*      stop = fArray + fCount;
+               while (iter < stop)
+               {
+                       (*iter)->unref();
+                       iter += 1;
+               }
+               this->reset();
+       }
+
+private:
+#ifdef SK_DEBUG
+    enum {
+        kDebugArraySize = 16
+    };
+       T(* fData)[kDebugArraySize];
+#endif
+       T*      fArray;
+       U16     fReserve, fCount;
+
+       void growBy(U16CPU extra)
+       {
+               SkASSERT(extra);
+               SkASSERT(fCount + extra <= 0xFFFF);
+
+               if (fCount + extra > fReserve)
+               {
+                       size_t size = fCount + extra + 4;
+                       size += size >> 2;
+
+                       fArray = (T*)sk_realloc_throw(fArray, size * sizeof(T));
+#ifdef SK_DEBUG
+               //      fData = (T (*)[kDebugArraySize]) fArray;
+                       (T*&)fData = fArray;
+#endif
+                       fReserve = SkToU16((U16CPU)size);
+               }
+               fCount = SkToU16(fCount + extra);
+       }
+};
+
+#endif
+
diff --git a/include/graphics/SkTDStack.h b/include/graphics/SkTDStack.h
new file mode 100644 (file)
index 0000000..ccd7b8e
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef SkTDStack_DEFINED
+#define SkTDStack_DEFINED
+
+#include "SkTypes.h"
+
+template <typename T> class SkTDStack {
+public:
+       SkTDStack() : fCount(0), fTotalCount(0)
+       {
+               fInitialRec.fNext = nil;
+               fRec = &fInitialRec;
+
+       //      fCount = kSlotCount;
+       }
+       ~SkTDStack()
+       {
+               Rec* rec = fRec;
+               while (rec != &fInitialRec)
+               {
+                       Rec* next = rec->fNext;
+                       sk_free(rec);
+                       rec = next;
+               }
+       }
+
+       int count() const { return fTotalCount; }
+
+       T* push()
+       {
+               SkASSERT(fCount <= kSlotCount);
+               if (fCount == kSlotCount)
+               {
+                       Rec* rec = (Rec*)sk_malloc_throw(sizeof(Rec));
+                       rec->fNext = fRec;
+                       fRec = rec;
+                       fCount = 0;
+               }
+               ++fTotalCount;
+               return &fRec->fSlots[fCount++];
+       }
+       void push(const T& elem) { *this->push() = elem; }
+       const T& index(int idx) const
+       {
+               SkASSERT(fRec && fCount > idx);
+               return fRec->fSlots[fCount - idx - 1];
+       }       
+       T& index(int idx)
+       {
+               SkASSERT(fRec && fCount > idx);
+               return fRec->fSlots[fCount - idx - 1];
+       }       
+       const T& top() const
+       {
+               SkASSERT(fRec && fCount > 0);
+               return fRec->fSlots[fCount - 1];
+       }
+       T& top()
+       {
+               SkASSERT(fRec && fCount > 0);
+               return fRec->fSlots[fCount - 1];
+       }
+       void pop(T* elem)
+       {
+               if (elem)
+                       *elem = fRec->fSlots[fCount - 1];
+               this->pop();
+       }
+       void pop()
+       {
+               SkASSERT(fCount > 0 && fRec);
+               --fTotalCount;
+               if (--fCount == 0)
+               {
+                       if (fRec != &fInitialRec)
+                       {
+                               Rec* rec = fRec->fNext;
+                               sk_free(fRec);
+                               fCount = kSlotCount;
+                               fRec = rec;
+                       }
+                       else
+                               SkASSERT(fTotalCount == 0);
+               }
+       }
+
+private:
+       enum {
+               kSlotCount      = 8
+       };
+
+       struct Rec;
+       friend struct Rec;
+
+       struct Rec {
+               Rec* fNext;
+               T        fSlots[kSlotCount];
+       };
+       Rec             fInitialRec;
+       Rec*    fRec;
+       int             fCount, fTotalCount;
+};
+
+#endif
+
diff --git a/include/graphics/SkTDict.h b/include/graphics/SkTDict.h
new file mode 100644 (file)
index 0000000..c717ad1
--- /dev/null
@@ -0,0 +1,154 @@
+#ifndef SkTDict_DEFINED
+#define SkTDict_DEFINED
+
+#include "SkChunkAlloc.h"
+//#include "SkTemplates.h"
+#include "SkTSearch.h"
+#include "SkTDArray.h"
+
+template <typename T> class SkTDict {
+public:
+       SkTDict(size_t minStringAlloc) : fStrings(minStringAlloc) {}
+
+       void reset()
+       {
+               fArray.reset();
+               fStrings.reset();
+       }
+
+       int count() const { return fArray.count(); }
+
+       bool set(const char name[], const T& value)
+       {
+               return set(name, strlen(name), value);
+       }
+
+       bool set(const char name[], size_t len, const T& value)
+       {
+               SkASSERT(name);
+
+               int index = this->find_index(name, len);
+
+               if (index >= 0)
+               {
+                       fArray[index].fValue = value;
+                       return false;
+               }
+               else
+               {
+                       Pair*   pair = fArray.insert(~index);
+                       char*   copy = (char*)fStrings.alloc(len + 1, SkChunkAlloc::kThrow_AllocFailType);
+                       memcpy(copy, name, len);
+            copy[len] = '\0';
+                       pair->fName = copy;
+                       pair->fValue = value;
+                       return true;
+               }
+       }
+
+       bool find(const char name[]) const
+       {
+               return this->find_index(name) >= 0;
+       }
+
+       bool find(const char name[], size_t len) const
+       {
+               return this->find_index(name, len) >= 0;
+       }
+
+       bool find(const char name[], T* value) const
+       {
+               return find(name, strlen(name), value);
+       }
+
+       bool find(const char name[], size_t len, T* value) const
+       {
+               int index = this->find_index(name, len);
+
+               if (index >= 0)
+               {
+                       if (value)
+                               *value = fArray[index].fValue;
+                       return true;
+               }
+               return false;
+       }
+
+       bool findKey(T& value, const char** name) const
+       {
+               Pair* end = fArray.end();
+               for (Pair* pair = fArray.begin(); pair < end; pair++) {
+                       if (pair->fValue != value)
+                               continue;
+                       *name = pair->fName;
+                       return true;
+               }
+               return false;
+       }
+
+public:
+       struct Pair {
+               const char*     fName;
+               T                       fValue;
+
+               friend int operator<(const Pair& a, const Pair& b)
+               {
+                       return strcmp(a.fName, b.fName);
+               }
+               friend int operator!=(const Pair& a, const Pair& b)
+               {
+                       return strcmp(a.fName, b.fName);
+               }
+       };
+       friend class Iter;
+
+public:
+       class Iter {
+       public:
+               Iter(const SkTDict<T>& dict)
+               {
+                       fIter = dict.fArray.begin();
+                       fStop = dict.fArray.end();
+               }
+               const char* next(T* value)
+               {
+                       const char* name = nil;
+                       if (fIter < fStop)
+                       {
+                               name = fIter->fName;
+                               if (value)
+                                       *value = fIter->fValue;
+                               fIter += 1;
+                       }
+                       return name;
+               }
+       private:
+               Pair*   fIter;
+               Pair*   fStop;
+       };
+
+private:
+       SkTDArray<Pair> fArray;
+       SkChunkAlloc    fStrings;
+
+       int find_index(const char name[]) const
+       {
+               return find_index(name, strlen(name));
+       }
+
+       int find_index(const char name[], size_t len) const
+       {
+               SkASSERT(name);
+
+               int     count = fArray.count();
+               int index = ~0;
+
+               if (count)
+                       index = SkStrSearch(&fArray.begin()->fName, count, name, len, sizeof(Pair));
+               return index;
+       }
+       friend class Iter;
+};
+
+#endif
+
diff --git a/include/graphics/SkTSearch.h b/include/graphics/SkTSearch.h
new file mode 100644 (file)
index 0000000..e76d767
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef SkTSearch_DEFINED
+#define SkTSearch_DEFINED
+
+#include "SkTypes.h"
+
+template <typename T>
+int SkTSearch(const T* base, int count, T target, size_t elemSize)
+{
+       SkASSERT(base != nil);
+       SkASSERT(count >= 0);
+
+       if (count <= 0)
+               return ~0;
+
+       int     lo = 0;
+       int     hi = count - 1;
+
+       while (lo < hi)
+       {
+               int mid = (hi + lo) >> 1;
+               const T* elem = (const T*)((const char*)base + mid * elemSize);
+
+               if (*elem < target)
+                       lo = mid + 1;
+               else
+                       hi = mid;
+       }
+
+       const T* elem = (const T*)((const char*)base + hi * elemSize);
+       if (*elem != target)
+       {
+               if (*elem < target)
+                       hi += 1;
+               hi = ~hi;
+       }
+       return hi;
+}
+
+int SkStrSearch(const char*const* base, int count, const char target[], size_t target_len, size_t elemSize);
+int SkStrSearch(const char*const* base, int count, const char target[], size_t elemSize);
+
+/**    Like SkStrSearch, but treats target as if it were all lower-case. Assumes that
+       base points to a table of lower-case strings.
+*/
+int SkStrLCSearch(const char*const* base, int count, const char target[], size_t target_len, size_t elemSize);
+int SkStrLCSearch(const char*const* base, int count, const char target[], size_t elemSize);
+
+extern "C" {
+       typedef int (*SkQSortCompareProc)(const void*, const void*);
+       void SkQSort(void* base, size_t count, size_t elemSize, SkQSortCompareProc);
+}
+
+SkDEBUGCODE(void SkQSort_UnitTest();)
+
+#endif
+
diff --git a/include/graphics/SkTextBox.h b/include/graphics/SkTextBox.h
new file mode 100644 (file)
index 0000000..1a7a3b6
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef SkTextBox_DEFINED
+#define SkTextBox_DEFINED
+
+#include "SkCanvas.h"
+
+/**    \class SkTextBox
+
+       SkTextBox is a helper class for drawing 1 or more lines of text
+       within a rectangle. The textbox is positioned and clipped by its Frame.
+       The Margin rectangle controls where the text is drawn relative to
+       the Frame. Line-breaks occur inside the Margin rectangle.
+
+       Spacing is a linear equation used to compute the distance between lines
+       of text. Spacing consists of two scalars: mul and add, and the spacing
+       between lines is computed as: spacing = paint.getTextSize() * mul + add
+*/
+class SkTextBox {
+public:
+       SkTextBox();
+
+       enum Mode {
+               kOneLine_Mode,
+               kLineBreak_Mode,
+
+               kModeCount
+       };
+       Mode    getMode() const { return (Mode)fMode; }
+       void    setMode(Mode);
+
+       enum SpacingAlign {
+               kStart_SpacingAlign,
+               kCenter_SpacingAlign,
+               kEnd_SpacingAlign,
+
+               kSpacingAlignCount
+       };
+       SpacingAlign    getSpacingAlign() const { return (SpacingAlign)fSpacingAlign; }
+       void                    setSpacingAlign(SpacingAlign);
+
+       void    getBox(SkRect*) const;
+       void    setBox(const SkRect&);
+       void    setBox(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
+
+       void    getSpacing(SkScalar* mul, SkScalar* add) const;
+       void    setSpacing(SkScalar mul, SkScalar add);
+
+       void    draw(SkCanvas*, const char text[], size_t len, const SkPaint&);
+
+private:
+       SkRect          fBox;
+       SkScalar        fSpacingMul, fSpacingAdd;
+       U8                      fMode, fSpacingAlign;
+};
+
+class SkTextLineBreaker {
+public:
+       static int CountLines(const char text[], size_t len, const SkPaint&, SkScalar width);
+};
+
+#endif
+
diff --git a/include/graphics/SkTextLayout.h b/include/graphics/SkTextLayout.h
new file mode 100644 (file)
index 0000000..4aa938e
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef SkTextLayout_DEFINED
+#define SkTextLayout_DEFINED
+
+#include "SkRefCnt.h"
+#include "SkPaint.h"
+#include "SkScalar.h"
+
+class SkTextLayout : public SkRefCnt {
+public:
+    /** Create a textlayout that implements the CSS features of letter-spacing
+        and word-spacing. It takes values to add to the advance width for each
+        letter (charExtra) and to add to the advance width for each space
+        (spaceExtra).
+        @param charExtra    amount to add to every character's advance width
+        @param spaceExtra   amount to add to every space character's advance width
+        @return a new textlayout subclass that implements tracking
+    */
+    static SkTextLayout* CreateTrackingLayout(SkScalar charExtra, SkScalar spaceExtra);
+
+    class Rec;
+
+    int layout( const SkPaint& paint,
+                const char* text, size_t byteLength, SkUnicodeWalkerProc proc,
+                Rec rec[]);
+
+    class Rec {
+    public:
+        SkUnichar   charCode() const { return fCharCode; }
+        SkScalar    fDeltaAdvance;  //!< set by the subclass in onLayout()
+    
+    private:
+        SkUnichar   fCharCode;
+        // to be used in the future
+        uint16_t    fGlyphID;
+        uint16_t    fFlags;
+        
+        friend class SkTextLayout;
+    };
+
+protected:
+    virtual void onLayout(const SkPaint& paint, Rec rec[], int count) {}
+};
+
+#endif
diff --git a/include/graphics/SkTime.h b/include/graphics/SkTime.h
new file mode 100644 (file)
index 0000000..efcef8b
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef SkTime_DEFINED
+#define SkTime_DEFINED
+
+#include "SkTypes.h"
+
+/**    \class SkTime
+       Platform-implemented utilities to return time of day, and millisecond counter.
+*/
+class SkTime {
+public:
+       struct DateTime {
+               U16     fYear;                  //!< e.g. 2005
+               U8      fMonth;                 //!< 1..12
+               U8      fDayOfWeek;             //!< 0..6, 0==Sunday
+               U8      fDay;                   //!< 1..31
+               U8      fHour;                  //!< 0..23
+               U8      fMinute;                //!< 0..59
+               U8      fSecond;                //!< 0..59
+       };
+       static void GetDateTime(DateTime*);
+
+       static SkMSec GetMSecs();
+};
+
+#if defined(SK_DEBUG) && defined(SK_BUILD_FOR_WIN32)
+       extern SkMSec gForceTickCount;
+#endif
+
+#define SK_TIME_FACTOR         1
+
+#endif
+
diff --git a/include/graphics/SkTransparentShader.h b/include/graphics/SkTransparentShader.h
new file mode 100644 (file)
index 0000000..3146caf
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef SkTransparentShader_DEFINED
+#define SkTransparentShader_DEFINED
+
+#include "SkShader.h"
+
+class SkTransparentShader : public SkShader {
+public:
+       virtual U32             getFlags();
+       virtual bool    setContext(     const SkBitmap& device,
+                                                               const SkPaint& paint,
+                                                               const SkMatrix& matrix);
+       virtual void    shadeSpan(int x, int y, SkPMColor[], int count);
+       virtual void    shadeSpanOpaque16(int x, int y, U16 span[], int count);
+
+private:
+       SkBitmap        fDevice;
+       U8                      fAlpha;
+
+       typedef SkShader INHERITED;
+};
+
+#endif
+
diff --git a/include/graphics/SkTypeface.h b/include/graphics/SkTypeface.h
new file mode 100644 (file)
index 0000000..cd0c21f
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef SkTypeface_DEFINED
+#define SkTypeface_DEFINED
+
+#include "SkRefCnt.h"
+
+/** \class SkTypeface
+
+    The SkTypeface class specifies the typeface and intrinsic style of a font.
+    This is used in the paint, along with optionally algorithmic settings like
+    textSize, textSkewX, textScaleX, kFakeBoldText_Mask, to specify
+    how text appears when drawn (and measured).
+*/
+class SkTypeface : public SkRefCnt {
+public:
+    /** Style enum specifies the possible intrinsic style attributes of a given typeface
+    */
+    enum Style {
+        kNormal = 0,
+        kBold   = 0x01,
+        kItalic = 0x02,
+
+        // helpers
+        kBoldItalic = 0x03
+    };
+
+    /** Returns the typeface's intrinsic style attributes
+    */
+    Style   getStyle() const { return (Style)fStyle; }
+    /** Returns true if getStyle() has the kBold bit set.
+    */
+    bool    isBold() const { return (fStyle & kBold) != 0; }
+    /** Returns true if getStyle() has the kItalic bit set.
+    */
+    bool    isItalic() const { return (fStyle & kItalic) != 0; }
+    
+    /** Create a typeface object given a family name, and option style information.
+        If NULL is passed for the name, then the "default" font will be chosen.
+        The resulting typeface object can be queried (getStyle()) to discover what
+        its "real" style characteristics are.
+        
+        @param familyName  May be NULL. The name of the font family.
+        @param s           The style (normal, bold, italic) of the type face.
+
+    */
+    static SkTypeface* Create(const char familyName[], Style s = kNormal);
+    /** Create a typeface object that best matches the specified existing typeface
+        and the specified Style. Use this call if you want to pick a new style
+        from the same family of an existing typeface object. If family is NULL,
+        this selects from the default font's family.
+        
+        @param family  May be NULL. The name of the existing type face.
+        @param s       The style (normal, bold, italic) of the type face.
+    */
+    static SkTypeface* CreateFromTypeface(const SkTypeface* family, Style s);
+
+protected:
+    void setStyle(Style s) {
+        fStyle = SkToU8(s);
+    }
+    
+    SkTypeface() {}
+
+private:
+    uint8_t fStyle;
+};
+
+#endif
diff --git a/include/graphics/SkUnitMapper.h b/include/graphics/SkUnitMapper.h
new file mode 100644 (file)
index 0000000..0bd00bb
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef SkUnitMapper_DEFINED
+#define SkUnitMapper_DEFINED
+
+#include "SkRefCnt.h"
+#include "SkScalar.h"
+
+class SkUnitMapper : public SkRefCnt {
+public:
+       /**     Given a value in [0..0xFFFF], return a value in the same range.
+       */
+       virtual U16CPU mapUnit16(U16CPU x) = 0;
+};
+
+/**    This returns N values between [0...1]
+*/
+class SkDiscreteMapper : public SkUnitMapper {
+public:
+       SkDiscreteMapper(unsigned segments);
+       // override
+       virtual U16CPU mapUnit16(U16CPU x);
+private:
+       unsigned fSegments;
+       SkFract fScale;
+};
+
+/**    This returns 1 - cos(x), to simulate lighting a sphere
+*/
+class SkFlipCosineMapper : public SkUnitMapper {
+public:
+       // override
+       virtual U16CPU mapUnit16(U16CPU x);
+};
+
+#endif
+
diff --git a/include/graphics/SkUtils.h b/include/graphics/SkUtils.h
new file mode 100644 (file)
index 0000000..3ccba31
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef SkUtils_DEFINED
+#define SkUtils_DEFINED
+
+#include "SkTypes.h"
+
+#ifdef FMS_ARCH_ANDROID_ARM
+    #include "utils/memory.h"
+    
+    #define SK_MEMSET16_REDIRECT(dst, value, count)    android_memset16(dst, value, (count) << 1)
+    #define SK_MEMSET32_REDIRECT(dst, value, count)    android_memset32(dst, value, (count) << 2)
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_MEMSET16_REDIRECT
+    #define sk_memset16(dst, value, count)  SK_MEMSET16_REDIRECT(dst, value, count)
+#else
+    /** Similar to memset(), but this function assigns a 16bit value into the buffer.
+        @param buffer  The memory to have value copied into it
+        @param value   The 16bit value to be copied into buffer
+        @param count   The number of times value should be copied into the buffer.
+    */
+    void sk_memset16(uint16_t dst[], U16CPU value, int count);
+#endif
+
+#ifdef SK_MEMSET32_REDIRECT
+    #define sk_memset32(dst, value, count)  SK_MEMSET32_REDIRECT(dst, value, count)
+#else
+    /** Similar to memset(), but this function assigns a 32bit value into the buffer.
+        @param buffer  The memory to have value copied into it
+        @param value   The 32bit value to be copied into buffer
+        @param count   The number of times value should be copied into the buffer.
+    */
+    void sk_memset32(uint32_t dst[], uint32_t value, int count);
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////
+
+#define kMaxBytesInUTF8Sequence                4
+
+#ifdef SK_DEBUG
+       int SkUTF8_LeadByteToCount(unsigned c);
+#else
+       #define SkUTF8_LeadByteToCount(c)       ((((0xE5 << 24) >> ((unsigned)c >> 4 << 1)) & 3) + 1)
+#endif
+
+inline int SkUTF8_CountUTF8Bytes(const char utf8[])
+{
+       SkASSERT(utf8);
+       return SkUTF8_LeadByteToCount(*(const uint8_t*)utf8);
+}
+
+int                    SkUTF8_CountUnichars(const char utf8[]);
+int                    SkUTF8_CountUnichars(const char utf8[], size_t byteLength);
+SkUnichar      SkUTF8_ToUnichar(const char utf8[]);
+SkUnichar      SkUTF8_NextUnichar(const char**);
+
+/**    Return the number of bytes need to convert a unichar
+       into a utf8 sequence. Will be 1..kMaxBytesInUTF8Sequence,
+       or 0 if uni is illegal.
+*/
+size_t         SkUTF8_FromUnichar(SkUnichar uni, char utf8[] = nil);
+
+/////////////////////////////////////////////////////////////////////////////////
+
+#define SkUTF16_IsHighSurrogate(c)  (((c) & 0xFC00) == 0xD800)
+#define SkUTF16_IsLowSurrogate(c)   (((c) & 0xFC00) == 0xDC00)
+
+int         SkUTF16_CountUnichars(const uint16_t utf16[]);
+int         SkUTF16_CountUnichars(const uint16_t utf16[], int numberOf16BitValues);
+SkUnichar   SkUTF16_NextUnichar(const U16**);
+size_t      SkUTF16_FromUnichar(SkUnichar uni, uint16_t utf16[] = nil);
+
+size_t      SkUTF16_ToUTF8(const uint16_t utf16[], int numberOf16BitValues, char utf8[] = nil);
+
+class SkUtils {
+public:
+#ifdef SK_DEBUG
+       static void UnitTest();
+#endif
+};
+
+#endif
+
diff --git a/include/graphics/SkView.h b/include/graphics/SkView.h
new file mode 100644 (file)
index 0000000..a7868d6
--- /dev/null
@@ -0,0 +1,328 @@
+#ifndef SkView_DEFINED
+#define SkView_DEFINED
+
+#include "SkEventSink.h"
+#include "SkRect.h"
+#include "SkDOM.h"
+#include "SkTDict.h"
+
+class SkCanvas;
+class SkLayerView;
+
+/**    \class SkView
+
+       SkView is the base class for screen management. All widgets and controls inherit
+       from SkView.
+*/
+class SkView : public SkEventSink {
+public:
+       enum Flag_Shift {
+               kVisible_Shift,
+               kEnabled_Shift,
+               kFocusable_Shift,
+               kFlexH_Shift,
+               kFlexV_Shift,
+
+               kFlagShiftCount
+       };
+       enum Flag_Mask {
+               kVisible_Mask   = 1 << kVisible_Shift,          //!< set if the view is visible
+               kEnabled_Mask   = 1 << kEnabled_Shift,          //!< set if the view is enabled
+               kFocusable_Mask = 1 << kFocusable_Shift,        //!< set if the view can receive focus
+               kFlexH_Mask             = 1 << kFlexH_Shift,            //!< set if the view's width is stretchable
+               kFlexV_Mask             = 1 << kFlexV_Shift,            //!< set if the view's height is stretchable
+
+               kAllFlagMasks   = (U32)(0 - 1) >> (32 - kFlagShiftCount)
+       };
+
+                               SkView(U32 flags = 0);
+       virtual         ~SkView();
+
+       /**     Return the flags associated with the view
+       */
+       U32                     getFlags() const { return fFlags; }
+       /**     Set the flags associated with the view
+       */
+       void            setFlags(U32 flags);
+
+       /**     Helper that returns non-zero if the kVisible_Mask bit is set in the view's flags
+       */
+       int                     isVisible() const { return fFlags & kVisible_Mask; }
+       int                     isEnabled() const { return fFlags & kEnabled_Mask; }
+       int                     isFocusable() const { return fFlags & kFocusable_Mask; }
+       /**     Helper to set/clear the view's kVisible_Mask flag */
+       void            setVisibleP(bool);
+       void            setEnabledP(bool);
+       void            setFocusableP(bool);
+
+       /**     Return the view's width */
+       SkScalar        width() const { return fWidth; }
+       /**     Return the view's height */
+       SkScalar        height() const { return fHeight; }
+       /**     Set the view's width and height. These must both be >= 0. This does not affect the view's loc */
+       void            setSize(SkScalar width, SkScalar height);
+       void            setSize(const SkPoint& size) { this->setSize(size.fX, size.fY); }
+       void            setWidth(SkScalar width) { this->setSize(width, fHeight); }
+       void            setHeight(SkScalar height) { this->setSize(fWidth, height); }
+       /**     Return a rectangle set to [0, 0, width, height] */
+       void            getLocalBounds(SkRect* bounds) const;
+
+       /**     Return the view's left edge */
+       SkScalar        locX() const { return fLoc.fX; }
+       /**     Return the view's top edge */
+       SkScalar        locY() const { return fLoc.fY; }
+       /**     Set the view's left and top edge. This does not affect the view's size */
+       void            setLoc(SkScalar x, SkScalar y);
+       void            setLoc(const SkPoint& loc) { this->setLoc(loc.fX, loc.fY); }
+       void            setLocX(SkScalar x) { this->setLoc(x, fLoc.fY); }
+       void            setLocY(SkScalar y) { this->setLoc(fLoc.fX, y); }
+       /**     Offset (move) the view by the specified dx and dy. This does not affect the view's size */
+       void            offset(SkScalar dx, SkScalar dy);
+
+       /**     Call this to have the view draw into the specified canvas. */
+       void            draw(SkCanvas* canvas);
+       /**     Call this to invalidate part of all of a view, requesting that the view's
+               draw method be called. The rectangle parameter specifies the part of the view
+               that should be redrawn. If it is nil, it specifies the entire view bounds.
+       */
+       void            inval(SkRect* rectOrNil);
+
+       //      Focus management
+
+       SkView* getFocusView() const;
+       bool    hasFocus() const;
+
+       enum FocusDirection {
+               kNext_FocusDirection,
+               kPrev_FocusDirection,
+
+               kFocusDirectionCount
+       };
+       bool    acceptFocus();
+       SkView* moveFocus(FocusDirection);
+
+       //      Click handling
+
+       class Click {
+       public:
+               Click(SkView* target);
+               virtual ~Click();
+
+               const char*     getType() const { return fType; }
+               bool            isType(const char type[]) const;
+               void            setType(const char type[]);             // does NOT make a copy of the string
+               void            copyType(const char type[]);    // makes a copy of the string
+
+               enum State {
+                       kDown_State,
+                       kMoved_State,
+                       kUp_State
+               };
+               SkPoint         fOrig, fPrev, fCurr;
+               SkPoint16       fIOrig, fIPrev, fICurr;
+               State           fState;
+       private:
+               SkEventSinkID   fTargetID;
+               char*                   fType;
+               bool                    fWeOwnTheType;
+
+               void resetType();
+
+               friend class SkView;
+       };
+       Click*  findClickHandler(SkScalar x, SkScalar y);
+
+       static void     DoClickDown(Click*, int x, int y);
+       static void     DoClickMoved(Click*, int x, int y);
+       static void     DoClickUp(Click*, int x, int y);
+
+       /**     Send the event to the view's parent, and its parent etc. until one of them
+               returns true from its onEvent call. This view is returned. If no parent handles
+               the event, nil is returned.
+       */
+       SkView*         sendEventToParents(const SkEvent&);
+       /**     Depricated helper function. Just call event->post(sinkID, delay);
+       */
+       bool    postEvent(SkEvent* evt, SkEventSinkID sinkID, SkMSec delay) { return evt->post(sinkID, delay); }
+
+       //      View hierarchy management
+
+       /**     Return the view's parent, or nil if it has none. This does not affect the parent's reference count. */
+       SkView*         getParent() const { return fParent; }
+       SkView*         attachChildToFront(SkView* child);
+       /**     Attach the child view to this view, and increment the child's reference count. The child view is added
+               such that it will be drawn before all other child views.
+               The child view parameter is returned.
+       */
+       SkView*         attachChildToBack(SkView* child);
+       /**     If the view has a parent, detach the view from its parent and decrement the view's reference count.
+               If the parent was the only owner of the view, this will cause the view to be deleted.
+       */
+       void            detachFromParent();
+       /**     Attach the child view to this view, and increment the child's reference count. The child view is added
+               such that it will be drawn after all other child views.
+               The child view parameter is returned.
+       */
+       /**     Detach all child views from this view. */
+       void            detachAllChildren();
+
+       /**     Convert the specified point from global coordinates into view-local coordinates
+       */
+       void            globalToLocal(SkPoint* pt) const { if (pt) this->globalToLocal(pt->fX, pt->fY, pt); }
+       /**     Convert the specified x,y from global coordinates into view-local coordinates, returning
+               the answer in the local parameter.
+       */
+       void            globalToLocal(SkScalar globalX, SkScalar globalY, SkPoint* local) const;
+
+       /**     \class F2BIter
+       
+               Iterator that will return each of this view's children, in
+               front-to-back order (the order used for clicking). The first
+               call to next() returns the front-most child view. When
+               next() returns nil, there are no more child views.
+       */
+       class F2BIter {
+       public:
+               F2BIter(const SkView* parent);
+               SkView* next();
+       private:
+               SkView* fFirstChild, *fChild;
+       };
+
+       /**     \class B2FIter
+       
+               Iterator that will return each of this view's children, in
+               back-to-front order (the order they are drawn). The first
+               call to next() returns the back-most child view. When
+               next() returns nil, there are no more child views.
+       */
+       class B2FIter {
+       public:
+               B2FIter(const SkView* parent);
+               SkView* next();
+       private:
+               SkView* fFirstChild, *fChild;
+       };
+
+       /**     \class Artist
+       
+               Install a subclass of this in a view (calling setArtist()), and then the
+               default implementation of that view's onDraw() will invoke this object
+               automatically.
+       */
+       class Artist : public SkRefCnt {
+       public:
+               void draw(SkView*, SkCanvas*);
+               void inflate(const SkDOM&, const SkDOM::Node*);
+       protected:
+               virtual void onDraw(SkView*, SkCanvas*) = 0;
+               virtual void onInflate(const SkDOM&, const SkDOM::Node*);
+       };
+       /**     Return the artist attached to this view (or nil). The artist's reference
+               count is not affected.
+       */
+       Artist* getArtist() const;
+       /**     Attach the specified artist (or nil) to the view, replacing any existing
+               artist. If the new artist is not nil, its reference count is incremented.
+               The artist parameter is returned.
+       */
+       Artist* setArtist(Artist* artist);
+
+       /**     \class Layout
+       
+               Install a subclass of this in a view (calling setLayout()), and then the
+               default implementation of that view's onLayoutChildren() will invoke
+               this object automatically.
+       */
+       class Layout : public SkRefCnt {
+       public:
+               void layoutChildren(SkView* parent);
+               void inflate(const SkDOM&, const SkDOM::Node*);
+       protected:
+               virtual void onLayoutChildren(SkView* parent) = 0;
+               virtual void onInflate(const SkDOM&, const SkDOM::Node*);
+       };
+
+       /**     Return the layout attached to this view (or nil). The layout's reference
+               count is not affected.
+       */
+       Layout* getLayout() const;
+       /**     Attach the specified layout (or nil) to the view, replacing any existing
+               layout. If the new layout is not nil, its reference count is incremented.
+               The layout parameter is returned.
+       */
+       Layout* setLayout(Layout*, bool invokeLayoutNow = true);
+       /**     If a layout is attached to this view, call its layoutChildren() method
+       */
+       void    invokeLayout();
+
+       /**     Call this to initialize this view based on the specified XML node
+       */
+       void    inflate(const SkDOM& dom, const SkDOM::Node* node);
+       /**     After a view hierarchy is inflated, this may be called with a dictionary
+               containing pairs of <name, view*>, where the name string was the view's
+               "id" attribute when it was inflated.
+
+               This will call the virtual onPostInflate for this view, and the recursively
+               call postInflate on all of the view's children.
+       */
+       void    postInflate(const SkTDict<SkView*>& ids);
+
+       SkDEBUGCODE(void dump(bool recurse) const;)
+
+protected:
+       /**     Override this to draw inside the view. Be sure to call the inherited version too */
+       virtual void    onDraw(SkCanvas*);
+       /**     Override this to be notified when the view's size changes. Be sure to call the inherited version too */
+       virtual void    onSizeChange();
+       /** Override this if you want to handle an inval request from this view or one of its children.
+               Tyically this is only overridden by the by the "window". If your subclass does handle the
+               request, return true so the request will not continue to propogate to the parent.
+       */
+       virtual bool    handleInval(const SkRect&);
+       /**     Override this if you might handle the click
+       */
+       virtual Click*  onFindClickHandler(SkScalar x, SkScalar y);
+       /**     Override this to track clicks, returning true as long as you want to track
+               the pen/mouse.
+       */
+       virtual bool    onClick(Click*);
+       /**     Override this to initialize your subclass from the XML node. Be sure to call the inherited version too */
+       virtual void    onInflate(const SkDOM& dom, const SkDOM::Node* node);
+       /** Override this if you want to perform post initialization work based on the ID dictionary built
+               during XML parsing. Be sure to call the inherited version too.
+       */
+       virtual void    onPostInflate(const SkTDict<SkView*>&);
+
+public:
+       // default action is to inval the view
+       virtual void    onFocusChange(bool gainFocusP);
+protected:
+
+       // override these if you're acting as a layer/host
+       virtual bool    onGetFocusView(SkView**) const { return false; }
+       virtual bool    onSetFocusView(SkView*) { return false; }
+
+private:
+       SkScalar        fWidth, fHeight;
+       SkPoint         fLoc;
+       SkView*         fParent;
+       SkView*         fFirstChild;
+       SkView*         fNextSibling;
+       SkView*         fPrevSibling;
+
+       U8                      fFlags;
+       U8                      fContainsFocus;
+
+       friend class B2FIter;
+       friend class F2BIter;
+       
+       friend class SkLayerView;
+
+       bool    setFocusView(SkView* fvOrNil);
+       SkView* acceptFocus(FocusDirection);
+       void    detachFromParent_NoLayout();
+};
+
+#endif
+
diff --git a/include/graphics/SkViewInflate.h b/include/graphics/SkViewInflate.h
new file mode 100644 (file)
index 0000000..5bf9f43
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef SkViewInflate_DEFINED
+#define SkViewInflate_DEFINED
+
+#include "SkDOM.h"
+#include "SkTDict.h"
+#include "SkEvent.h"
+
+class SkView;
+
+class SkViewInflate {
+public: 
+                       SkViewInflate();
+       virtual ~SkViewInflate();
+
+       /**     Return the tree of inflated views. If root is nil, create the root element
+               as a view, otherwise assume root is that view, and just "inflate" it.
+
+               Returns nil if the tree cannot be built.
+       */
+       SkView* inflate(const SkDOM& dom, const SkDOM::Node* node, SkView* root = nil);
+       SkView* inflate(const char xml[], size_t len, SkView* root = nil);
+
+       /**     Given an id attribute value, return the corresponding view, or nil
+               if no match is found.
+       */
+       SkView* findViewByID(const char id[]) const;
+       
+       SkDEBUGCODE(void dump() const;)
+
+protected:
+       /*      Override this in your subclass to handle instantiating views
+               Call the inherited version for nodes you don't recognize.
+
+               Do not call "inflate" on the view, just return it. This will
+               get called automatically after createView returns.
+       */
+       virtual SkView* createView(const SkDOM& dom, const SkDOM::Node* node);
+       /**     Base implementation calls view->inflate(dom, node). Subclasses may override this
+               to perform additional initializations to view, either before or after calling
+               the inherited version.
+       */
+       virtual void inflateView(SkView* view, const SkDOM& dom, const SkDOM::Node* node);
+
+private:
+       enum {
+               kMinIDStrAlloc = 64
+       };
+       SkTDict<SkView*> fIDs;
+
+       struct IDStr {
+               SkView* fView;
+               char*   fStr;
+       };
+       SkTDArray<IDStr>        fListenTo, fBroadcastTo;
+       SkChunkAlloc            fStrings;
+
+       void addIDStr(SkTDArray<IDStr>* list, SkView*, const char* str);
+
+       void    rInflate(const SkDOM& dom, const SkDOM::Node* node, SkView* parent);
+};
+
+#endif
+
diff --git a/include/graphics/SkWidget.h b/include/graphics/SkWidget.h
new file mode 100644 (file)
index 0000000..586eb7a
--- /dev/null
@@ -0,0 +1,460 @@
+#ifndef SkWidget_DEFINED
+#define SkWidget_DEFINED
+
+#include "SkView.h"
+#include "SkBitmap.h"
+#include "SkDOM.h"
+#include "SkPaint.h"
+#include "SkString.h"
+#include "SkTDArray.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+class SkWidget : public SkView {
+public:
+       SkWidget(U32 flags = 0) : SkView(flags | kFocusable_Mask | kEnabled_Mask) {}
+
+       /**     Call this to post the widget's event to its listeners */
+       void    postWidgetEvent();
+
+       static void Init();
+       static void Term();
+protected:
+       // override to add slots to an event before posting
+       virtual void prepareWidgetEvent(SkEvent*);
+       virtual void onEnabledChange();
+
+       // <event ...> to initialize the event from XML
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node);
+
+private:
+       SkEvent fEvent;
+       typedef SkView INHERITED;
+};
+
+class SkHasLabelWidget : public SkWidget {
+public:
+       SkHasLabelWidget(U32 flags = 0) : SkWidget(flags) {}
+
+       size_t  getLabel(SkString* label = nil) const;
+       size_t  getLabel(char lable[] = nil) const;
+       void    setLabel(const SkString&);
+       void    setLabel(const char label[]);
+       void    setLabel(const char label[], size_t len);
+
+protected:
+       // called when the label changes
+       virtual void onLabelChange();
+
+       // overrides
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node*);
+
+private:
+       SkString        fLabel;
+       typedef SkWidget INHERITED;
+};
+
+class SkButtonWidget : public SkHasLabelWidget {
+public:
+       SkButtonWidget(U32 flags = 0) : SkHasLabelWidget(flags), fState(kOff_State) {}
+
+       enum State {
+               kOff_State,             //!< XML: buttonState="off"
+               kOn_State,              //!< XML: buttonState="on"
+               kUnknown_State  //!< XML: buttonState="unknown"
+       };
+       State   getButtonState() const { return fState; }
+       void    setButtonState(State);
+
+protected:
+       /** called when the label changes. default behavior is to inval the widget */
+       virtual void onButtonStateChange();
+
+       // overrides
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node*);
+
+private:
+       State   fState;
+       typedef SkHasLabelWidget INHERITED;
+};
+
+class SkPushButtonWidget : public SkButtonWidget {
+public:
+       SkPushButtonWidget(U32 flags = 0) : SkButtonWidget(flags) {}
+
+protected:
+       virtual bool onEvent(const SkEvent&);
+       virtual void onDraw(SkCanvas*);
+       virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
+       virtual bool onClick(Click* click);
+
+private:
+       typedef SkButtonWidget INHERITED;
+};
+
+class SkCheckBoxWidget : public SkButtonWidget {
+public:
+       SkCheckBoxWidget(U32 flags = 0);
+
+protected:
+       virtual bool onEvent(const SkEvent&);
+       virtual void onDraw(SkCanvas*);
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node*);
+
+private:
+       typedef SkButtonWidget INHERITED;
+};
+
+#include "SkTextBox.h"
+
+class SkStaticTextView : public SkView {
+public:
+                       SkStaticTextView(U32 flags = 0);
+       virtual ~SkStaticTextView();
+
+       enum Mode {
+               kFixedSize_Mode,
+               kAutoWidth_Mode,
+               kAutoHeight_Mode,
+
+               kModeCount
+       };
+       Mode    getMode() const { return (Mode)fMode; }
+       void    setMode(Mode);
+
+       SkTextBox::SpacingAlign getSpacingAlign() const { return (SkTextBox::SpacingAlign)fSpacingAlign; }
+       void    setSpacingAlign(SkTextBox::SpacingAlign);
+
+       void    getMargin(SkPoint* margin) const;
+       void    setMargin(SkScalar dx, SkScalar dy);
+
+       size_t  getText(SkString* text = nil) const;
+       size_t  getText(char text[] = nil) const;
+       void    setText(const SkString&);
+       void    setText(const char text[]);
+       void    setText(const char text[], size_t len);
+
+       void    getPaint(SkPaint*) const;
+       void    setPaint(const SkPaint&);
+
+protected:
+       // overrides
+       virtual void onDraw(SkCanvas*);
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node*);
+
+private:
+       SkPoint         fMargin;
+       SkString        fText;
+       SkPaint         fPaint;
+       U8                      fMode;
+       U8                      fSpacingAlign;
+
+       void computeSize();
+
+       typedef SkView INHERITED;
+};
+
+class SkBitmapView : public SkView {
+public:
+                       SkBitmapView(U32 flags = 0);
+       virtual ~SkBitmapView();
+
+       bool    getBitmap(SkBitmap*) const;
+       void    setBitmap(const SkBitmap*, bool viewOwnsPixels);
+       bool    loadBitmapFromFile(const char path[]);
+
+protected:
+       virtual void onDraw(SkCanvas*);
+       virtual void onInflate(const SkDOM&, const SkDOM::Node*);
+
+private:
+       SkBitmap        fBitmap;
+       typedef SkView INHERITED;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+class SkShader;
+class SkInterpolator;
+
+class SkWidgetView : public SkView {
+public:
+                       SkWidgetView(U32 flags = 0);
+       virtual ~SkWidgetView();
+
+       static const char*      GetEventType();
+};
+
+class SkSliderView : public SkWidgetView {
+public:
+       SkSliderView(U32 flags = 0);
+
+       U16             getValue() const { return fValue; }
+       U16             getMax() const { return fMax; }
+
+       void    setMax(U16CPU max);
+       void    setValue(U16CPU value);
+
+protected:
+       virtual void    onDraw(SkCanvas*);
+       virtual Click*  onFindClickHandler(SkScalar x, SkScalar y);
+       virtual bool    onClick(Click*);
+
+private:
+       U16     fValue, fMax;
+
+       typedef SkWidgetView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+class SkHasLabelView : public SkView {
+public:
+       void    getLabel(SkString*) const;
+       void    setLabel(const SkString&);
+       void    setLabel(const char label[]);
+
+protected:
+       SkString        fLabel;
+
+       // called when the label changes
+       virtual void onLabelChange();
+
+       // overrides
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node*);
+};
+
+class SkPushButtonView : public SkHasLabelView {
+public:
+       SkPushButtonView(U32 flags = 0);
+
+protected:
+       virtual void onDraw(SkCanvas*);
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node*);
+};
+
+class SkCheckBoxView : public SkHasLabelView {
+public:
+       SkCheckBoxView(U32 flags = 0);
+
+       enum State {
+               kOff_State,
+               kOn_State,
+               kMaybe_State
+       };
+       State   getState() const { return fState; }
+       void    setState(State);
+
+protected:
+       virtual void onDraw(SkCanvas*);
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node*);
+
+private:
+       State   fState;
+};
+
+class SkProgressView : public SkView {
+public:
+       SkProgressView(U32 flags = 0);
+       virtual ~SkProgressView();
+
+       U16             getValue() const { return fValue; }
+       U16             getMax() const { return fMax; }
+
+       void    setMax(U16CPU max);
+       void    setValue(U16CPU value);
+
+protected:
+       virtual void onDraw(SkCanvas*);
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node);
+
+private:
+       U16                     fValue, fMax;
+       SkShader*       fOnShader, *fOffShader;
+       SkInterpolator* fInterp;
+       bool fDoInterp;
+
+       typedef SkView INHERITED;
+};
+
+class SkTextView : public SkView {
+public:
+                       SkTextView(U32 flags = 0);
+       virtual ~SkTextView();
+
+       enum AnimaDir {
+               kNeutral_AnimDir,
+               kForward_AnimDir,
+               kBackward_AnimDir,
+               kAnimDirCount
+       };
+
+       void    getText(SkString*) const;
+       void    setText(const SkString&, AnimaDir dir = kNeutral_AnimDir);
+       void    setText(const char text[], AnimaDir dir = kNeutral_AnimDir);
+       void    setText(const char text[], size_t len, AnimaDir dir = kNeutral_AnimDir);
+
+       void    getMargin(SkPoint* margin) const;
+       void    setMargin(const SkPoint&);
+
+       SkPaint&        paint() { return fPaint; }
+
+protected:
+       virtual void onDraw(SkCanvas*);
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node);
+
+private:
+       SkString fText;
+       SkPaint  fPaint;
+       SkPoint  fMargin;
+
+       class Interp;
+       Interp* fInterp;
+       bool    fDoInterp;
+       // called by the other setText methods. This guy does not check for !=
+       // before doing the assign, so the caller must check for us
+       void privSetText(const SkString&, AnimaDir dir);
+
+       typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////
+
+class SkEvent;
+
+class SkListSource : public SkEventSink {
+public:
+       virtual int     countRows() = 0;
+       virtual void getRow(int index, SkString* left, SkString* right) = 0;
+       virtual SkEvent* getEvent(int index);
+
+       static SkListSource* CreateFromDir(const char path[], const char suffix[],
+                                                                               const char targetPrefix[]);
+       static SkListSource* CreateFromDOM(const SkDOM& dom, const SkDOM::Node* node);
+};
+
+class SkListView : public SkWidgetView {
+public:
+                       SkListView(U32 flags = 0);
+       virtual ~SkListView();
+
+       SkScalar        getRowHeight() const { return fRowHeight; }
+       void            setRowHeight(SkScalar);
+
+       /**     Return the index of the selected row, or -1 if none
+       */
+       int             getSelection() const { return fCurrIndex; }
+       /**     Set the index of the selected row, or -1 for none
+       */
+       void    setSelection(int);
+
+       void    moveSelectionUp();
+       void    moveSelectionDown();
+
+       enum Attr {
+               kBG_Attr,
+               kNormalText_Attr,
+               kHiliteText_Attr,
+               kHiliteCell_Attr,
+               kAttrCount
+       };
+       SkPaint&        paint(Attr);
+
+       SkListSource*   getListSource() const { return fSource; }
+       SkListSource*   setListSource(SkListSource*);
+
+#if 0
+       enum Action {
+               kSelectionChange_Action,
+               kSelectionPicked_Action,
+               kActionCount
+       };
+       /**     If event is not nil, it is retained by the view, and a copy
+               of the event will be posted to its listeners when the specified
+               action occurs. If event is nil, then no event will be posted for
+               the specified action.
+       */
+       void    setActionEvent(Action, SkEvent* event);
+#endif
+
+protected:
+       virtual void onDraw(SkCanvas*);
+       virtual void onSizeChange();
+       virtual bool onEvent(const SkEvent&);
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node);
+
+private:
+       SkPaint                 fPaint[kAttrCount];
+       SkListSource*   fSource;
+       SkScalar                fRowHeight;
+       int                             fCurrIndex;             // logical index
+       int                             fScrollIndex;   // logical index of top-most visible row
+       int                             fVisibleRowCount;
+       SkString*               fStrCache;
+
+       void    dirtyStrCache();
+       void    ensureStrCache(int visibleCount);
+
+       int             logicalToVisualIndex(int index) const { return index - fScrollIndex; }
+       void    invalSelection();
+       bool    getRowRect(int index, SkRect*) const;
+       void    ensureSelectionIsVisible();
+
+       typedef SkWidgetView INHERITED;
+};
+
+//////////////////////////////////////////////////////////
+
+class SkGridView : public SkWidgetView {
+public:
+                       SkGridView(U32 flags = 0);
+       virtual ~SkGridView();
+
+       void    getCellSize(SkPoint*) const;
+       void    setCellSize(SkScalar x, SkScalar y);
+
+       /**     Return the index of the selected item, or -1 if none
+       */
+       int             getSelection() const { return fCurrIndex; }
+       /**     Set the index of the selected row, or -1 for none
+       */
+       void    setSelection(int);
+
+       void    moveSelectionUp();
+       void    moveSelectionDown();
+
+       enum Attr {
+               kBG_Attr,
+               kHiliteCell_Attr,
+               kAttrCount
+       };
+       SkPaint&        paint(Attr);
+
+       SkListSource*   getListSource() const { return fSource; }
+       SkListSource*   setListSource(SkListSource*);
+
+protected:
+       virtual void onDraw(SkCanvas*);
+       virtual void onSizeChange();
+       virtual bool onEvent(const SkEvent&);
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node);
+
+private:
+       SkView*                 fScrollBar;
+       SkPaint                 fPaint[kAttrCount];
+       SkListSource*   fSource;
+       int                             fCurrIndex;             // logical index
+
+       SkPoint                 fCellSize;
+       SkPoint16               fVisibleCount;
+
+       int             logicalToVisualIndex(int index) const { return index; }
+       void    invalSelection();
+       bool    getCellRect(int index, SkRect*) const;
+       void    ensureSelectionIsVisible();
+
+       typedef SkWidgetView INHERITED;
+};
+
+#endif
+
diff --git a/include/graphics/SkWidgetViews.h b/include/graphics/SkWidgetViews.h
new file mode 100644 (file)
index 0000000..52a3e0d
--- /dev/null
@@ -0,0 +1,294 @@
+#ifndef SkWidgetViews_DEFINED
+#define SkWidgetViews_DEFINED
+
+#include "SkView.h"
+
+
+enum SkWidgetEnum {
+       kBorder_WidgetEnum,                     //!< <sk-border>
+       kButton_WidgetEnum,                     //!< <sk-button>
+       kImage_WidgetEnum,                      //!< <sk-image>
+       kList_WidgetEnum,                       //!< <sk-list>
+       kProgress_WidgetEnum,           //!< <sk-progress>
+       kScroll_WidgetEnum,                     //!< <sk-scroll>
+       kText_WidgetEnum,                       //!< <sk-text>
+       
+       kWidgetEnumCount
+};
+
+//determines which skin to use
+enum SkinEnum {
+       kBorder_SkinEnum,
+       kButton_SkinEnum,
+       kProgress_SkinEnum,
+       kScroll_SkinEnum,
+       kStaticText_SkinEnum,
+       
+       kSkinEnumCount
+};
+
+#include "SkAnimator.h"
+//used for inflates
+const char* get_skin_enum_path(SkinEnum se);
+void init_skin_anim(const char path[], SkAnimator* anim);
+void init_skin_anim(SkinEnum se, SkAnimator* anim);
+void init_skin_paint(SkinEnum se, SkPaint* paint);
+void inflate_paint(const SkDOM& dom, const SkDOM::Node* node, SkPaint* paint);
+
+/**    Given an enum value, return an instance of the specified widget.
+       If the enum is out of range, returns nil
+*/
+SkView* SkWidgetFactory(SkWidgetEnum);
+/**    Given the inflate/element name of a widget, return an instance of
+       the specified widget, or nil if name does not match any known
+       widget type.
+*/
+SkView* SkWidgetFactory(const char name[]);
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+class SkWidgetView : public SkView {
+public:
+       SkWidgetView();
+
+       const char*     getLabel() const;
+       void            getLabel(SkString* label) const;
+
+       void            setLabel(const char[]);
+       void            setLabel(const char[], size_t len);
+       void            setLabel(const SkString&);
+
+       SkEvent&                event() { return fEvent; }
+       const SkEvent&  event() const { return fEvent; }
+
+       /**     Returns true if the widget can post its event to its listeners.
+       */
+       bool    postWidgetEvent();
+       
+       /**     Returns the sinkID of the widgetview that posted the event, or 0
+       */
+       static SkEventSinkID GetWidgetEventSinkID(const SkEvent&);
+
+protected:
+       /** called when the label changes. override in subclasses. default action invals the view's bounds.
+               called with the old and new labels, before the label has actually changed.
+       */
+       virtual void onLabelChange(const char oldLabel[], const char newLabel[]);
+       /**     called before posting the event to our listeners. Override to add slots to the event
+               before posting. Return true to proceed with posting, or false to not post the event to any
+               listener. Note: the event passed in may not be the same as calling this->event().
+               Be sure to call your INHERITED method as well, so that all classes in the hierarchy get a shot
+               at modifying the event (and possibly returning false to abort).
+       */
+       virtual bool onPrepareWidgetEvent(SkEvent* evt);
+
+       // overrides
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node*);
+       
+private:
+       SkString        fLabel;
+       SkEvent         fEvent;
+       
+       typedef SkView INHERITED;
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+class SkButtonView : public SkWidgetView {
+public:
+       // inflate: "sk-button"
+       
+protected:
+       // overrides
+       virtual bool onEvent(const SkEvent&);
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+class SkCheckButtonView : public SkWidgetView {
+public:
+       SkCheckButtonView();
+
+       // inflate: "sk-checkbutton"
+       
+       enum CheckState {
+               kOff_CheckState,                //!< inflate: check-state="off"
+               kOn_CheckState,                 //!< inflate: check-state="on"
+               kUnknown_CheckState             //!< inflate: check-state="unknown"
+       };
+       CheckState      getCheckState() const { return (CheckState)fCheckState; }
+       void            setCheckState(CheckState);
+
+       /** use this to extract the CheckState from an event (i.e. one that as posted
+               by a SkCheckButtonView). Returns true if the proper slot was present in the event,
+               and sets state to that value. If no proper slot is found, returns false and does not
+               modify state.
+       */
+       static bool GetWidgetEventCheckState(const SkEvent&, CheckState* state);
+
+protected:
+       // called when the check-state is about to change, but before it actually has
+       virtual void onCheckStateChange(CheckState oldState, CheckState newState);
+
+       // overrides
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node*);
+       virtual bool onPrepareWidgetEvent(SkEvent* evt);
+       
+private:
+       U8      fCheckState;
+       
+       typedef SkWidgetView INHERITED;
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+#include "SkTextBox.h"
+
+class SkStaticTextView : public SkView {
+public:
+                       SkStaticTextView();
+       virtual ~SkStaticTextView();
+
+       enum Mode {
+               kFixedSize_Mode,
+               kAutoWidth_Mode,
+               kAutoHeight_Mode,
+
+               kModeCount
+       };
+       Mode    getMode() const { return (Mode)fMode; }
+       void    setMode(Mode);
+
+       SkTextBox::SpacingAlign getSpacingAlign() const { return (SkTextBox::SpacingAlign)fSpacingAlign; }
+       void    setSpacingAlign(SkTextBox::SpacingAlign);
+
+       void    getMargin(SkPoint* margin) const;
+       void    setMargin(SkScalar dx, SkScalar dy);
+
+       size_t  getText(SkString* text = nil) const;
+       size_t  getText(char text[] = nil) const;
+       void    setText(const SkString&);
+       void    setText(const char text[]);
+       void    setText(const char text[], size_t len);
+
+       void    getPaint(SkPaint*) const;
+       void    setPaint(const SkPaint&);
+
+protected:
+       // overrides
+       virtual void onDraw(SkCanvas*);
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node*);
+
+private:
+       SkPoint         fMargin;
+       SkString        fText;
+       SkPaint         fPaint;
+       U8                      fMode;
+       U8                      fSpacingAlign;
+
+       void computeSize();
+
+       typedef SkView INHERITED;
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+class SkAnimator;
+class SkListSource;
+class SkScrollBarView;
+
+class SkListView : public SkWidgetView {
+public:
+                       SkListView();
+       virtual ~SkListView();
+
+       bool    hasScrollBar() const { return fScrollBar != nil; }
+       void    setHasScrollBar(bool);
+       
+       /** Return the number of visible rows
+       */
+       int             getVisibleRowCount() const { return fVisibleRowCount; }
+       /**     Return the index of the selected row, or -1 if none
+       */
+       int             getSelection() const { return fCurrIndex; }
+       /**     Set the index of the selected row, or -1 for none
+       */
+       void    setSelection(int);
+       /**     If possible, move the selection up and return true,
+               else do nothing and return false
+               If nothing is selected, select the last item (unless there are no items).
+       */
+       bool    moveSelectionUp();
+       /**     If possible, move the selection down and return true,
+               else do nothing and return false.
+               If nothing is selected, select the first item (unless there are no items).
+       */
+       bool    moveSelectionDown();
+
+       SkListSource*   getListSource() const { return fSource; }
+       SkListSource*   setListSource(SkListSource*);
+
+       /**     Call this in your event handler. If the specified event is from a SkListView,
+               then it returns the index of the selected item in this list, otherwise it
+               returns -1
+       */
+       static int GetWidgetEventListIndex(const SkEvent&);
+
+protected:
+       // overrides
+       virtual void onDraw(SkCanvas*);
+       virtual void onSizeChange();
+       virtual bool onEvent(const SkEvent&);
+       virtual void onInflate(const SkDOM& dom, const SkDOM::Node* node);
+       virtual bool onPrepareWidgetEvent(SkEvent*);
+
+private:
+       enum DirtyFlags {
+               kAnimCount_DirtyFlag    = 0x01,
+               kAnimContent_DirtyFlag  = 0x02
+       };
+       void    dirtyCache(unsigned dirtyFlags);
+       bool    ensureCache();
+
+       int             logicalToVisualIndex(int index) const { return index - fScrollIndex; }
+       void    invalSelection();
+       SkScalar getContentWidth() const;
+       bool    getRowRect(int index, SkRect*) const;
+       void    ensureSelectionIsVisible();
+       void    ensureVisibleRowCount();
+
+       struct BindingRec;
+
+       enum Heights {
+               kNormal_Height,
+               kSelected_Height
+       };
+       SkListSource*   fSource;
+       SkScrollBarView*        fScrollBar;
+       SkAnimator*             fAnims;
+       BindingRec*             fBindings;
+       SkString                fSkinName;
+       SkScalar                fHeights[2];
+       S16                             fScrollIndex, fCurrIndex;
+       U16                             fVisibleRowCount, fBindingCount;
+       SkBool8                 fAnimContentDirty;
+       SkBool8                 fAnimFocusDirty;
+
+       typedef SkWidgetView INHERITED;
+};
+
+class SkListSource : public SkRefCnt {
+public:
+       virtual int countFields();
+       virtual void getFieldName(int index, SkString* field);
+       /**     Return the index of the named field, or -1 if not found */
+       virtual int findFieldIndex(const char field[]);
+
+       virtual int     countRecords();
+       virtual void getRecord(int rowIndex, int fieldIndex, SkString* data);
+
+       virtual bool prepareWidgetEvent(SkEvent*, int rowIndex);
+       
+       static SkListSource* Factory(const char name[]);
+};
+
+#endif
diff --git a/include/graphics/SkWindow.h b/include/graphics/SkWindow.h
new file mode 100644 (file)
index 0000000..8132b11
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef SkWindow_DEFINED
+#define SkWindow_DEFINED
+
+#include "SkView.h"
+#include "SkBitmap.h"
+#include "SkRegion.h"
+#include "SkEvent.h"
+#include "SkKey.h"
+#include "SkTDArray.h"
+
+#ifdef SK_BUILD_FOR_WINCEx
+       #define SHOW_FPS
+#endif
+//#define USE_GX_SCREEN
+
+class SkOSMenu;
+
+class SkWindow : public SkView {
+public:
+                       SkWindow();
+       virtual ~SkWindow();
+
+       const SkBitmap& getBitmap() const { return fBitmap; }
+
+       void    setConfig(SkBitmap::Config);
+       void    resize(int width, int height, SkBitmap::Config config = SkBitmap::kNo_Config);
+       void    eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
+       void    eraseRGB(U8CPU r, U8CPU g, U8CPU b);
+
+       bool    isDirty() const { return !fDirtyRgn.isEmpty(); }
+       bool    update(SkRect16* updateArea);
+       bool    handleClick(int x, int y, Click::State);
+       bool    handleChar(SkUnichar);
+       bool    handleKey(SkKey);
+    bool    handleKeyUp(SkKey);
+       bool    handleMenu(U32 os_cmd);
+
+       void    addMenu(SkOSMenu*);
+
+protected:
+       virtual bool onEvent(const SkEvent&);
+
+       // called if part of our bitmap is invalidated
+       virtual void onHandleInval(const SkRect16&);
+       virtual bool onHandleChar(SkUnichar);
+       virtual bool onHandleKey(SkKey);
+    virtual bool onHandleKeyUp(SkKey);
+       virtual void onAddMenu(const SkOSMenu*) {}
+
+       // overrides from SkView
+       virtual bool handleInval(const SkRect&);
+       virtual bool onGetFocusView(SkView** focus) const;
+       virtual bool onSetFocusView(SkView* focus);
+
+private:
+       SkBitmap::Config        fConfig;
+       SkBitmap        fBitmap;
+       SkRegion        fDirtyRgn;
+       Click*          fClick; // to track clicks
+
+       SkTDArray<SkOSMenu*>    fMenus;
+
+       SkView* fFocusView;
+       bool    fWaitingOnInval;
+
+       typedef SkView INHERITED;
+};
+
+///////////////////////////////////////////////////////////
+
+#ifndef SK_USE_WXWIDGETS
+#ifdef SK_BUILD_FOR_MAC
+       #include "SkOSWindow_Mac.h"
+#elif defined(SK_BUILD_FOR_WIN)
+       #include "SkOSWindow_Win.h"
+#elif defined(SK_BUILD_FOR_UNIXx)
+  #include "SkOSWindow_Unix.h"
+#endif
+#else
+  #include "SkOSWindow_wxwidgets.h"
+#endif
+
+#endif
+
diff --git a/include/graphics/SkXMLParser.h b/include/graphics/SkXMLParser.h
new file mode 100644 (file)
index 0000000..1255822
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef SkXMLParser_DEFINED
+#define SkXMLParser_DEFINED
+
+#include "SkMath.h"
+#include "SkString.h"
+
+class SkStream;
+
+class SkDOM;
+struct SkDOMNode;
+
+class SkXMLParserError {
+public:
+       enum ErrorCode {
+               kNoError,
+               kEmptyFile,
+               kUnknownElement,
+               kUnknownAttributeName,
+               kErrorInAttributeValue,
+               kDuplicateIDs,
+               kUnknownError
+       };
+
+       SkXMLParserError();
+       virtual ~SkXMLParserError();
+       ErrorCode getErrorCode() const { return fCode; }
+       virtual void getErrorString(SkString* str) const;
+       int getLineNumber() const { return fLineNumber; }
+       int getNativeCode() const { return fNativeCode; }
+       bool hasError() const { return fCode != kNoError || fNativeCode != -1; }
+       bool hasNoun() const { return fNoun.size() > 0; }
+       void reset();
+       void setCode(ErrorCode code) { fCode = code; }
+       void setNoun(const SkString& str) { fNoun.set(str); }
+       void setNoun(const char* ch)  { fNoun.set(ch); }
+       void setNoun(const char* ch, size_t len) { fNoun.set(ch, len); }
+protected:
+       ErrorCode fCode;
+private:
+       int fLineNumber;
+       int fNativeCode;
+       SkString fNoun;
+       friend class SkXMLParser;
+};
+
+class SkXMLParser {
+public:
+                       SkXMLParser(SkXMLParserError* parserError = nil);
+       virtual ~SkXMLParser();
+
+       /**     Returns true for success
+       */
+       bool parse(const char doc[], size_t len);
+       bool parse(SkStream& docStream);
+       bool parse(const SkDOM&, const SkDOMNode*);
+
+       static void GetNativeErrorString(int nativeErrorCode, SkString* str);
+
+protected:
+       // override in subclasses; return true to stop parsing
+       virtual bool onStartElement(const char elem[]);
+       virtual bool onAddAttribute(const char name[], const char value[]);
+       virtual bool onEndElement(const char elem[]);
+       virtual bool onText(const char text[], int len);
+
+public:
+       // public for ported implementation, not meant for clients to call
+       virtual bool startElement(const char elem[]);
+       virtual bool addAttribute(const char name[], const char value[]);
+       virtual bool endElement(const char elem[]);
+       virtual bool text(const char text[], int len); 
+       void* fParser;
+protected:
+       SkXMLParserError* fError;
+private:
+       void reportError(void* parser);
+};
+
+#endif
diff --git a/include/graphics/SkXMLWriter.h b/include/graphics/SkXMLWriter.h
new file mode 100644 (file)
index 0000000..cc2c55a
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef SkXMLWriter_DEFINED
+#define SkXMLWriter_DEFINED
+
+#include "SkTDArray.h"
+#include "SkString.h"
+#include "SkDOM.h"
+
+class SkWStream;
+class SkXMLParser;
+
+class SkXMLWriter {
+public:
+                       SkXMLWriter(bool doEscapeMarkup = true);
+       virtual ~SkXMLWriter();
+
+       void    addS32Attribute(const char name[], S32 value);
+       void    addAttribute(const char name[], const char value[]);
+       void    addAttributeLen(const char name[], const char value[], size_t length);
+       void    addHexAttribute(const char name[], U32 value, int minDigits = 0);
+       void    addScalarAttribute(const char name[], SkScalar value);
+       void    endElement() { this->onEndElement(); }
+       void    startElement(const char elem[]);
+       void    startElementLen(const char elem[], size_t length);
+       void    writeDOM(const SkDOM&, const SkDOM::Node*, bool skipRoot);
+       void    flush();
+       virtual void writeHeader();
+
+protected:
+       virtual void onStartElementLen(const char elem[], size_t length) = 0;
+       virtual void onAddAttributeLen(const char name[], const char value[], size_t length) = 0;
+       virtual void onEndElement() = 0;
+
+       struct Elem {
+               SkString        fName;
+               bool            fHasChildren;
+       };
+       void doEnd(Elem* elem);
+       bool doStart(const char name[], size_t length);
+       Elem* getEnd();
+       const char*     getHeader();
+       SkTDArray<Elem*> fElems;
+
+private:
+       bool fDoEscapeMarkup;
+       // illegal
+       SkXMLWriter& operator=(const SkXMLWriter&);
+};
+
+class SkXMLStreamWriter : public SkXMLWriter {
+public:
+       SkXMLStreamWriter(SkWStream*);
+       virtual ~SkXMLStreamWriter();
+       virtual void    writeHeader();
+       SkDEBUGCODE(static void UnitTest();)
+protected:
+       virtual void onStartElementLen(const char elem[], size_t length);
+       virtual void onEndElement();
+       virtual void onAddAttributeLen(const char name[], const char value[], size_t length);
+private:
+       SkWStream&              fStream;
+};
+
+class SkXMLParserWriter : public SkXMLWriter {
+public:
+       SkXMLParserWriter(SkXMLParser*);
+       virtual ~SkXMLParserWriter();
+protected:
+       virtual void onStartElementLen(const char elem[], size_t length);
+       virtual void onEndElement();
+       virtual void onAddAttributeLen(const char name[], const char value[], size_t length);
+private:
+       SkXMLParser&            fParser;
+};
+
+
+#endif
+
diff --git a/include/graphics/SkXfermode.h b/include/graphics/SkXfermode.h
new file mode 100644 (file)
index 0000000..9a6faad
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef SkXfermode_DEFINED
+#define SkXfermode_DEFINED
+
+#include "SkFlattenable.h"
+#include "SkColor.h"
+
+/**    \class SkXfermode
+
+       SkXfermode is the base class for objects that are called to implement custom
+       "transfer-modes" in the drawing pipeline. The static function Create(Modes)
+       can be called to return an instance of any of the predefined subclasses as
+       specified in the Modes enum. When an SkXfermode is assigned to an SkPaint, then
+       objects drawn with that paint have the xfermode applied.
+*/
+class SkXfermode : public SkFlattenable {
+public:
+    SkXfermode() {}
+
+       virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count, const SkAlpha aa[]);
+       virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count, const SkAlpha aa[]);
+       virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count, const SkAlpha aa[]);
+    
+protected:
+    SkXfermode(SkRBuffer&) {}
+
+private:
+    typedef SkFlattenable INHERITED;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+/** \class SkProcXfermode
+
+    SkProcXfermode is a xfermode that applies the specified proc to its colors.
+    This class is not exported to java.
+*/
+class SkProcXfermode : public SkXfermode {
+public:
+       SkProcXfermode(SkXfermodeProc proc) : fProc(proc) {}
+
+       // overrides from SkXfermode
+       virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count, const SkAlpha aa[]);
+       virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count, const SkAlpha aa[]);
+       virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count, const SkAlpha aa[]);
+
+    // overrides from SkFlattenable
+       virtual Factory getFactory();
+       virtual void    flatten(SkWBuffer&);
+
+protected:
+    SkProcXfermode(SkRBuffer&);
+
+private:
+       SkXfermodeProc  fProc;
+    
+    static SkFlattenable* CreateProc(SkRBuffer&);
+
+    typedef SkXfermode INHERITED;
+};
+
+#endif
+
diff --git a/libs/corecg/Makefile b/libs/corecg/Makefile
new file mode 100644 (file)
index 0000000..2e78667
--- /dev/null
@@ -0,0 +1,30 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+       Sk64.cpp \
+       SkBuffer.cpp \
+       SkChunkAlloc.cpp \
+       SkCordic.cpp \
+       SkDebug.cpp \
+       SkDebug_stdio.cpp \
+       SkFloat.cpp \
+       SkMath.cpp \
+       SkMatrix.cpp \
+       SkMemory_stdlib.cpp \
+       SkPoint.cpp \
+       SkRect.cpp \
+       SkRegion.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+       libutils
+
+LOCAL_C_INCLUDES += \
+       include/corecg
+
+#LOCAL_CFLAGS+= 
+#LOCAL_LDFLAGS:= 
+
+LOCAL_TARGET:= libcorecg
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/corecg/Sk64.cpp b/libs/corecg/Sk64.cpp
new file mode 100644 (file)
index 0000000..3a557fb
--- /dev/null
@@ -0,0 +1,553 @@
+#include "Sk64.h"
+
+#define shift_left(hi, lo)                     \
+       hi = (hi << 1) | (lo >> 31);    \
+       lo <<= 1
+
+#define shift_left_bits(hi, lo, bits)                  \
+       SkASSERT((unsigned)(bits) < 31);                                \
+       hi = (hi << (bits)) | (lo >> (32 - (bits)));    \
+       lo <<= (bits)
+
+//////////////////////////////////////////////////////////////////////
+
+int    Sk64::getClzAbs() const
+{
+       int32_t     hi = fHi;
+       uint32_t        lo = fLo;
+
+       // get abs
+       if (hi < 0)
+       {
+               hi = -hi - Sk32ToBool(lo);
+               lo = 0 - lo;
+       }
+       return hi ? SkCLZ(hi) : SkCLZ(lo) + 32;
+}
+
+void Sk64::shiftLeft(unsigned bits)
+{
+       SkASSERT(bits <= 63);
+       if (bits == 0)
+               return;
+
+       if (bits >= 32)
+       {
+               fHi = fLo << (bits - 32);
+               fLo = 0;
+       }
+       else
+       {
+               fHi = (fHi << bits) | (fLo >> (32 - bits));
+               fLo <<= bits;
+       }
+}
+
+int32_t Sk64::getShiftRight(unsigned bits) const
+{
+       SkASSERT(bits <= 63);
+
+       if (bits == 0)
+               return fLo;
+
+       if (bits >= 32)
+               return fHi >> (bits - 32);
+       else
+       {
+#ifdef SK_DEBUG
+               int32_t tmp = fHi >> bits;
+               SkASSERT(tmp == 0 || tmp == -1);
+#endif
+               return (fHi << (32 - bits)) | (fLo >> bits);
+       }
+}
+
+void Sk64::shiftRight(unsigned bits)
+{
+       SkASSERT(bits <= 63);
+       if (bits == 0)
+               return;
+
+       if (bits >= 32)
+       {
+               fLo = fHi >> (bits - 32);
+               fHi >>= 31;
+       }
+       else
+       {
+               fLo = (fHi << (32 - bits)) | (fLo >> bits);
+               fHi >>= bits;
+       }
+}
+
+void Sk64::roundRight(unsigned bits)
+{
+       SkASSERT(bits <= 63);
+       if (bits)
+       {
+               Sk64 one;
+               one.set(1);
+               one.shiftLeft(bits - 1);
+               this->add(one);
+               this->shiftRight(bits);
+       }
+}
+
+int Sk64::shiftToMake32() const
+{
+       int32_t     hi = fHi;
+       uint32_t        lo = fLo;
+
+       if (hi < 0)     // make it positive
+       {
+               hi = -hi - Sk32ToBool(lo);
+               lo = 0 - lo;
+       }
+
+       if (hi == 0)
+               return lo >> 31;
+       else
+               return 33 - SkCLZ(hi);
+}
+
+void Sk64::negate()
+{
+       fHi = -fHi - Sk32ToBool(fLo);
+       fLo = 0 - fLo;
+}
+
+void Sk64::abs()
+{
+       if (fHi < 0)
+       {
+               fHi = -fHi - Sk32ToBool(fLo);
+               fLo = 0 - fLo;
+       }
+}
+
+////////////////////////////////////////////////////////////////
+
+static inline int32_t round_right_16(int32_t hi, uint32_t lo)
+{
+       uint32_t sum = lo + (1 << 15);
+       hi += (sum < lo);
+       return (hi << 16) | (sum >> 16);
+}
+
+SkBool Sk64::isFixed() const
+{
+       Sk64 tmp = *this;
+       tmp.roundRight(16);
+       return tmp.is32();
+}
+
+SkFract        Sk64::getFract() const
+{
+       Sk64 tmp = *this;
+       tmp.roundRight(30);
+       return tmp.get32();
+}
+
+void Sk64::sub(const Sk64& a)
+{
+       fHi = fHi - a.fHi - (fLo < a.fLo);
+       fLo = fLo - a.fLo;
+}
+
+void Sk64::rsub(const Sk64& a)
+{
+       fHi = a.fHi - fHi - (a.fLo < fLo);
+       fLo = a.fLo - fLo;
+}
+
+void Sk64::setMul(int32_t a, int32_t b)
+{
+       int sa = a >> 31;
+       int sb = b >> 31;
+       // now make them positive
+       a = (a ^ sa) - sa;
+       b = (b ^ sb) - sb;
+
+       uint32_t        ah = a >> 16;
+       uint32_t        al = a & 0xFFFF;
+       uint32_t bh = b >> 16;
+       uint32_t bl = b & 0xFFFF;
+
+       uint32_t A = ah * bh;
+       uint32_t B = ah * bl + al * bh;
+       uint32_t C = al * bl;
+
+       /*      [  A  ]
+                  [  B  ]
+                     [  C  ]
+       */
+       fLo = C + (B << 16);
+       fHi = A + (B >>16) + (fLo < C);
+
+       if (sa != sb)
+               this->negate();
+}
+
+void Sk64::div(int32_t denom, DivOptions option)
+{
+       SkASSERT(denom);
+
+       int32_t     hi = fHi;
+       uint32_t        lo = fLo;
+       int         sign = denom ^ hi;
+
+       denom = SkAbs32(denom);
+       if (hi < 0)
+       {
+               hi = -hi - Sk32ToBool(lo);
+               lo = 0 - lo;
+       }
+
+       if (option == kRound_DivOption) // add denom/2
+       {
+               uint32_t newLo = lo + (denom >> 1);
+               hi += (newLo < lo);
+               lo = newLo;
+       }
+
+       if (hi == 0)    // fast-case
+       {
+               if (lo < (uint32_t)denom)
+                       this->set(0, 0);
+               else
+               {
+                       this->set(0, lo / denom);
+                       if (sign < 0)
+                               this->negate();
+               }
+               return;
+       }
+
+       int     bits;
+
+       {
+               int dbits = SkCLZ(denom);
+               int nbits = SkCLZ(hi);
+
+               bits = 32 + dbits - nbits;
+               SkASSERT(bits <= 63);
+               if (bits <= 0)
+               {
+                       this->set(0, 0);
+                       return;
+               }
+               denom <<= (dbits - 1);
+               shift_left_bits(hi, lo, nbits - 1);
+       }
+
+       int32_t     rhi = 0;
+       uint32_t        rlo = 0;
+
+       do {
+               shift_left(rhi, rlo);
+#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
+               if ((uint32_t)denom <= (uint32_t)hi)
+               {
+                       hi -= denom;
+                       rlo |= 1;
+               }
+#else
+               int32_t diff = (denom - hi - 1) >> 31;
+               hi -= denom & diff;
+               rlo -= diff;
+#endif
+               shift_left(hi, lo);
+       } while (--bits >= 0);
+       SkASSERT(rhi >= 0);
+
+       fHi = rhi;
+       fLo = rlo;
+       if (sign < 0)
+               this->negate();
+}
+
+#define shift_left_2(a, b, c)  \
+       a = (a << 2) | (b >> 30);       \
+       b = (b << 2) | (c >> 30);       \
+       c <<= 2
+
+int32_t Sk64::getSqrt() const
+{
+       SkASSERT(!this->isNeg());
+
+       uint32_t        hi = fHi;
+       uint32_t lo = fLo;
+       uint32_t        sqr = 0;
+       uint32_t root = 0;
+       int     count = 31;
+
+       do {
+               root <<= 1;
+               shift_left_2(sqr, hi, lo);
+
+               uint32_t testDiv = (root << 1) + 1;
+               if (sqr >= testDiv)
+               {
+                       sqr -= testDiv;
+                       root++;
+               }
+       } while (--count >= 0);
+       SkASSERT((int32_t)root >= 0);
+
+       return root;
+}
+
+#ifdef SK_CAN_USE_LONGLONG
+       SkLONGLONG Sk64::getLongLong() const
+       {
+               SkLONGLONG value = fHi;
+               value <<= 32;
+               return value | fLo;
+       }
+#endif
+
+SkFixed Sk64::getFixedDiv(const Sk64& denom) const
+{
+       Sk64    N = *this;
+       Sk64    D = denom;
+       int32_t sign = SkExtractSign(N.fHi ^ D.fHi);
+       SkFixed result;
+
+       N.abs();
+       D.abs();
+
+       // need to knock D down to just 31 bits
+       // either by rounding it to the right, or shifting N to the left
+       // then we can just call 64/32 div
+
+       int nclz = N.fHi ? SkCLZ(N.fHi) : 32;
+       int dclz = D.fHi ? SkCLZ(D.fHi) : (33 - (D.fLo >> 31));
+
+       int shiftN = nclz - 1;
+       SkASSERT(shiftN >= 0);
+       int     shiftD = 33 - dclz;
+       SkASSERT(shiftD >= 0);
+
+       if (shiftD + shiftN < 16)
+               shiftD = 16 - shiftN;
+       else
+               shiftN = 16 - shiftD;
+
+       D.roundRight(shiftD);
+       if (D.isZero())
+               result = SK_MaxS32;
+       else
+       {
+               if (shiftN >= 0)
+                       N.shiftLeft(shiftN);
+               else
+                       N.roundRight(-shiftN);
+               N.div(D.get32(), Sk64::kTrunc_DivOption);
+               if (N.is32())
+                       result = N.get32();
+               else
+                       result = SK_MaxS32;
+       }
+       return SkApplySign(result, sign);
+}
+
+///////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+#include "SkRandom.h"
+#include <math.h>
+
+#ifdef SK_SUPPORT_UNITTEST
+struct BoolTable {
+       S8      zero, pos, neg, toBool, sign;
+};
+
+static void bool_table_test(const Sk64& a, const BoolTable& table)
+{
+       SkASSERT(a.isZero() != a.nonZero());
+
+       SkASSERT(!a.isZero() == !table.zero);
+       SkASSERT(!a.isPos() == !table.pos);
+       SkASSERT(!a.isNeg() == !table.neg);
+       SkASSERT(a.sign() == table.sign);
+}
+
+#ifdef SK_CAN_USE_LONGLONG
+       static SkLONGLONG asLL(const Sk64& a)
+       {
+               return ((SkLONGLONG)a.fHi << 32) | a.fLo;
+       }
+#endif
+#endif
+
+void Sk64::UnitTest()
+{
+#ifdef SK_SUPPORT_UNITTEST
+       enum BoolTests {
+               kZero_BoolTest,
+               kPos_BoolTest,
+               kNeg_BoolTest
+       };
+       static const BoolTable gBoolTable[] = {
+               { 1, 0, 0, 0, 0 },
+               { 0, 1, 0, 1, 1 },
+               { 0, 0, 1, 1, -1 }
+       };
+
+       Sk64    a, b, c;
+
+       a.fHi = a.fLo = 0;
+       b.set(0);
+       c.setZero();
+       SkASSERT(a == b);
+       SkASSERT(a == c);
+       bool_table_test(a, gBoolTable[kZero_BoolTest]);
+
+       a.fHi = 0;      a.fLo = 5;
+       b.set(5);
+       SkASSERT(a == b);
+       SkASSERT(a.is32() && a.get32() == 5 && !a.is64());
+       bool_table_test(a, gBoolTable[kPos_BoolTest]);
+
+       a.fHi = -1;     a.fLo = (uint32_t)-5;
+       b.set(-5);
+       SkASSERT(a == b);
+       SkASSERT(a.is32() && a.get32() == -5 && !a.is64());
+       bool_table_test(a, gBoolTable[kNeg_BoolTest]);
+
+       a.setZero();
+       b.set(6);
+       c.set(-6);
+       SkASSERT(a != b && b != c && a != c);
+       SkASSERT(!(a == b) && !(a == b) && !(a == b));
+       SkASSERT(a < b && b > a && a <= b && b >= a);
+       SkASSERT(c < a && a > c && c <= a && a >= c);
+       SkASSERT(c < b && b > c && c <= b && b >= c);
+
+       // Now test add/sub
+
+       SkRandom        rand;
+       int                     i;
+
+       for (i = 0; i < 1000; i++)
+       {
+               int aa = rand.nextS() >> 1;
+               int bb = rand.nextS() >> 1;
+               a.set(aa);
+               b.set(bb);
+               SkASSERT(a.get32() == aa && b.get32() == bb);
+               c = a; c.add(bb);
+               SkASSERT(c.get32() == aa + bb);
+               c = a; c.add(-bb);
+               SkASSERT(c.get32() == aa - bb);
+               c = a; c.add(b);
+               SkASSERT(c.get32() == aa + bb);
+               c = a; c.sub(b);
+               SkASSERT(c.get32() == aa - bb);
+       }
+
+#ifdef SK_CAN_USE_LONGLONG
+       for (i = 0; i < 1000; i++)
+       {
+               rand.next64(&a); //a.fHi >>= 1; // avoid overflow
+               rand.next64(&b); //b.fHi >>= 1; // avoid overflow
+
+               if (!(i & 3))   // want to explicitly test these cases
+               {
+                       a.fLo = 0;
+                       b.fLo = 0;
+               }
+               else if (!(i & 7))      // want to explicitly test these cases
+               {
+                       a.fHi = 0;
+                       b.fHi = 0;
+               }
+
+               SkLONGLONG aa = asLL(a);
+               SkLONGLONG bb = asLL(b);
+
+               SkASSERT((a < b) == (aa < bb));
+               SkASSERT((a <= b) == (aa <= bb));
+               SkASSERT((a > b) == (aa > bb));
+               SkASSERT((a >= b) == (aa >= bb));
+               SkASSERT((a == b) == (aa == bb));
+               SkASSERT((a != b) == (aa != bb));
+
+               c = a; c.add(b);
+               SkASSERT(asLL(c) == aa + bb);
+               c = a; c.sub(b);
+               SkASSERT(asLL(c) == aa - bb);
+               c = a; c.rsub(b);
+               SkASSERT(asLL(c) == bb - aa);
+               c = a; c.negate();
+               SkASSERT(asLL(c) == -aa);
+
+               int bits = rand.nextU() & 63;
+               c = a; c.shiftLeft(bits);
+               SkASSERT(asLL(c) == (aa << bits));
+               c = a; c.shiftRight(bits);
+               SkASSERT(asLL(c) == (aa >> bits));
+               c = a; c.roundRight(bits);
+
+               SkLONGLONG tmp;
+
+               tmp = aa;
+               if (bits > 0)
+                       tmp += (SkLONGLONG)1 << (bits - 1);
+               SkASSERT(asLL(c) == (tmp >> bits));
+
+               c.setMul(a.fHi, b.fHi);
+               tmp = (SkLONGLONG)a.fHi * b.fHi;
+               SkASSERT(asLL(c) == tmp);
+       }
+
+
+       for (i = 0; i < 100000; i++)
+       {
+               Sk64    wide;
+               int32_t denom = rand.nextS();
+
+               while (denom == 0)
+                       denom = rand.nextS();
+               wide.setMul(rand.nextS(), rand.nextS());
+               SkLONGLONG check = wide.getLongLong();
+
+               wide.div(denom, Sk64::kTrunc_DivOption);
+               check /= denom;
+               SkLONGLONG w = wide.getLongLong();
+
+               SkASSERT(check == w);
+
+#ifdef SK_CAN_USE_FLOAT
+               wide.setMul(rand.nextS(), rand.nextS());
+               wide.abs();
+               denom = wide.getSqrt();
+               int32_t ck = (int32_t)sqrt((double)wide.getLongLong());
+               int     diff = denom - ck;
+               SkASSERT(SkAbs32(diff) <= 1);
+
+               wide.setMul(rand.nextS(), rand.nextS());
+               Sk64    dwide;
+               dwide.setMul(rand.nextS(), rand.nextS());
+               SkFixed fixdiv = wide.getFixedDiv(dwide);
+               double dnumer = (double)wide.getLongLong();
+               double ddenom = (double)dwide.getLongLong();
+               double ddiv = dnumer / ddenom;
+               SkFixed dfixdiv;
+               if (ddiv >= (double)SK_MaxS32 / (double)SK_Fixed1)
+                       dfixdiv = SK_MaxS32;
+               else if (ddiv <= -(double)SK_MaxS32 / (double)SK_Fixed1)
+                       dfixdiv = SK_MinS32;
+               else
+                       dfixdiv = SkFloatToFixed(dnumer / ddenom);
+               diff = fixdiv - dfixdiv;
+               SkASSERT(SkAbs32(diff) <= 1);
+#endif
+       }
+#endif
+#endif
+}
+
+#endif
+
diff --git a/libs/corecg/SkBuffer.cpp b/libs/corecg/SkBuffer.cpp
new file mode 100644 (file)
index 0000000..8f4792f
--- /dev/null
@@ -0,0 +1,106 @@
+#include "SkBuffer.h"
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+void SkRBuffer::readNoSizeCheck(void* buffer, size_t size)
+{
+    SkASSERT(fData != 0 && fStop == 0 || fPos + size <= fStop);
+    if (buffer)
+        memcpy(buffer, fPos, size);
+    fPos += size;
+}
+
+size_t SkRBuffer::skipToAlign4()
+{
+    size_t pos = this->pos();
+    size_t n = SkAlign4(pos) - pos;
+    fPos += n;
+    return n;
+}
+
+void SkWBuffer::writeNoSizeCheck(const void* buffer, size_t size)
+{
+    SkASSERT(fData == 0 || fStop == 0 || fPos + size <= fStop);
+    if (fData && buffer)
+        memcpy(fPos, buffer, size);
+    fPos += size;
+}
+
+size_t SkWBuffer::padToAlign4()
+{
+    size_t pos = this->pos();
+    size_t n = SkAlign4(pos) - pos;
+
+    if (n && fData)
+    {
+        char* p = fPos;
+        char* stop = p + n;
+        do {
+            *p++ = 0;
+        } while (p < stop);
+    }
+    fPos += n;
+    return n;
+}
+
+#if 0
+#ifdef SK_DEBUG
+       static void AssertBuffer32(const void* buffer)
+       {
+               SkASSERT(buffer);
+               SkASSERT(((size_t)buffer & 3) == 0);
+       }
+#else
+       #define AssertBuffer32(buffer)
+#endif
+
+void* sk_buffer_write_int32(void* buffer, int32_t value)
+{
+       AssertBuffer32(buffer);
+       *(int32_t*)buffer = value;
+       return (char*)buffer + sizeof(int32_t);
+}
+
+void* sk_buffer_write_int32(void* buffer, const int32_t values[], int count)
+{
+       AssertBuffer32(buffer);
+       SkASSERT(count >= 0);
+
+       memcpy((int32_t*)buffer, values, count * sizeof(int32_t));
+       return (char*)buffer + count * sizeof(int32_t);
+}
+
+const void*    sk_buffer_read_int32(const void* buffer, int32_t* value)
+{
+       AssertBuffer32(buffer);
+       if (value)
+               *value = *(const int32_t*)buffer;
+       return (const char*)buffer + sizeof(int32_t);
+}
+
+const void*    sk_buffer_read_int32(const void* buffer, int32_t values[], int count)
+{
+       AssertBuffer32(buffer);
+       SkASSERT(count >= 0);
+
+       if (values)
+               memcpy(values, (const int32_t*)buffer, count * sizeof(int32_t));
+       return (const char*)buffer + count * sizeof(int32_t);
+}
+
+void* sk_buffer_write_ptr(void* buffer, void* ptr)
+{
+       AssertBuffer32(buffer);
+       *(void**)buffer = ptr;
+       return (char*)buffer + sizeof(void*);
+}
+
+const void*    sk_buffer_read_ptr(const void* buffer, void** ptr)
+{
+       AssertBuffer32(buffer);
+       if (ptr)
+               *ptr = *(void**)buffer;
+       return (const char*)buffer + sizeof(void*);
+}
+
+#endif
diff --git a/libs/corecg/SkChunkAlloc.cpp b/libs/corecg/SkChunkAlloc.cpp
new file mode 100644 (file)
index 0000000..cfeccc0
--- /dev/null
@@ -0,0 +1,45 @@
+#include "SkChunkAlloc.h"
+
+SkChunkAlloc::~SkChunkAlloc()
+{
+       this->reset();
+}
+
+void SkChunkAlloc::reset()
+{
+       Block* block = fBlock;
+
+       while (block)
+       {
+               Block* next = block->fNext;
+               sk_free(block);
+               block = next;
+       }
+       fBlock = nil;
+}
+
+void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype)
+{
+       bytes = SkAlign4(bytes);
+
+       if (fBlock == nil || bytes > fBlock->fFreeSize)
+       {
+               size_t  size = SkMax32((S32)bytes, (S32)fMinSize);
+               Block*  block = (Block*)sk_malloc_flags(sizeof(Block) + size, ftype == kThrow_AllocFailType ? SK_MALLOC_THROW : 0);
+               if (block == nil)
+                       return nil;
+
+               block->fNext = fBlock;
+               block->fFreeSize = size;
+               block->fFreePtr = (char*)block + sizeof(Block);
+               fBlock = block;
+       }
+
+       SkASSERT(fBlock && bytes <= fBlock->fFreeSize);
+       void* ptr = fBlock->fFreePtr;
+
+       fBlock->fFreeSize -= bytes;
+       fBlock->fFreePtr += bytes;
+       return ptr;
+}
+
diff --git a/libs/corecg/SkCordic.cpp b/libs/corecg/SkCordic.cpp
new file mode 100644 (file)
index 0000000..32266e9
--- /dev/null
@@ -0,0 +1,284 @@
+#include "SkCordic.h"
+#include "SkMath.h"
+#include "Sk64.h"
+
+// 0x20000000 equals pi / 4
+const int32_t kATanDegrees[] = { 0x20000000,
+       0x12E4051D, 0x9FB385B, 0x51111D4, 0x28B0D43, 0x145D7E1, 0xA2F61E, 0x517C55,
+       0x28BE53, 0x145F2E, 0xA2F98, 0x517CC, 0x28BE6, 0x145F3, 0xA2F9, 0x517C,
+       0x28BE, 0x145F, 0xA2F, 0x517, 0x28B, 0x145, 0xA2, 0x51, 0x28, 0x14,
+       0xA, 0x5, 0x2, 0x1 };
+
+const int32_t kFixedInvGain1 = 0x18bde0bb;     // 0.607252935
+
+static void SkCircularRotation(int32_t* x0, int32_t* y0, int32_t* z0) 
+{
+       int32_t t = 0;
+       int32_t x = *x0;
+       int32_t y = *y0;
+       int32_t z = *z0;
+       const int32_t* tanPtr = kATanDegrees;
+   do {
+        int32_t x1 = y >> t;
+               int32_t y1 = x >> t;
+               int32_t tan = *tanPtr++;        
+               if (z >= 0) {
+                       x -= x1;
+                       y += y1;
+                       z -= tan;
+               } else {
+                       x += x1;
+                       y -= y1;
+                       z += tan;
+               }
+   } while (++t < 16); // 30);
+    *x0 = x;
+    *y0 = y;
+    *z0 = z;
+}
+
+SkFixed SkCordicSinCos(SkFixed radians, SkFixed* cosp)
+{
+       int32_t scaledRadians = radians * 0x28be;       // scale radians to 65536 / PI()
+       int quadrant = scaledRadians >> 30;
+       quadrant += 1;
+       if (quadrant & 2) 
+               scaledRadians = -scaledRadians + 0x80000000;
+    /* |a| <= 90 degrees as a 1.31 number */
+    SkFixed sin = 0;
+    SkFixed cos = kFixedInvGain1;
+    SkCircularRotation(&cos, &sin, &scaledRadians);
+       Sk64 scaled;
+       scaled.setMul(sin, 0x6488d);
+       sin = scaled.fHi;
+       scaled.setMul(cos, 0x6488d);
+       if (quadrant & 2)
+               scaled.fHi = - scaled.fHi;
+       *cosp = scaled.fHi;
+    return sin;
+}
+
+SkFixed SkCordicTan(SkFixed a) 
+{
+       int32_t cos;
+       int32_t sin = SkCordicSinCos(a, &cos);
+       return SkFixedDiv(sin, cos);
+}
+
+static int32_t SkCircularVector(int32_t* y0, int32_t* x0, int32_t vecMode) 
+{
+       int32_t x = *x0;
+       int32_t y = *y0;
+       int32_t z = 0;
+       int32_t t = 0;
+       const int32_t* tanPtr = kATanDegrees;
+   do {
+        int32_t x1 = y >> t;
+               int32_t y1 = x >> t;
+               int32_t tan = *tanPtr++;        
+               if (y < vecMode) {
+                       x -= x1;
+                       y += y1;
+                       z -= tan;
+               } else {
+                       x += x1;
+                       y -= y1;
+                       z += tan;
+               }
+   } while (++t < 16); // 30
+       Sk64 scaled;
+       scaled.setMul(z, 0x6488d); // scale back into the SkScalar space (0x100000000/0x28be)
+   return scaled.fHi;
+}
+
+SkFixed SkCordicASin(SkFixed a) {
+       int32_t sign = SkExtractSign(a);
+       int32_t z = SkFixedAbs(a);
+       if (z >= SK_Fixed1)
+               return SkApplySign(SK_FixedPI>>1, sign);
+       int32_t x = kFixedInvGain1;
+       int32_t y = 0;
+       z *= 0x28be;
+       z = SkCircularVector(&y, &x, z);
+       z = SkApplySign(z, ~sign);
+       return z;
+}
+
+SkFixed SkCordicACos(SkFixed a) {
+       int32_t z = SkCordicASin(a);
+       z = (SK_FixedPI>>1) - z;
+       return z;
+}
+
+SkFixed SkCordicATan2(SkFixed y, SkFixed x) {
+       if ((x | y) == 0)
+               return 0;
+       int32_t xsign = SkExtractSign(x);
+       x = SkFixedAbs(x);
+       int32_t result = SkCircularVector(&y, &x, 0);
+       if (xsign) {
+               int32_t rsign = SkExtractSign(result);
+               if (y == 0)
+                       rsign = 0;
+               SkFixed pi = SkApplySign(SK_FixedPI, rsign);
+               result = pi - result;
+       }
+       return result;
+}
+
+const int32_t kATanHDegrees[] = { 
+       0x1661788D, 0xA680D61, 0x51EA6FC, 0x28CBFDD, 0x1460E34,
+       0xA2FCE8, 0x517D2E, 0x28BE6E, 0x145F32,
+       0xA2F98, 0x517CC, 0x28BE6, 0x145F3, 0xA2F9, 0x517C,
+       0x28BE, 0x145F, 0xA2F, 0x517, 0x28B, 0x145, 0xA2, 0x51, 0x28, 0x14,
+       0xA, 0x5, 0x2, 0x1 };
+
+const int32_t kFixedInvGain2 = 0x31330AAA;     // 1.207534495
+
+static void SkHyperbolic(int32_t* x0, int32_t* y0, int32_t* z0, int mode) 
+{
+       int32_t t = 1;
+       int32_t x = *x0;
+       int32_t y = *y0;
+       int32_t z = *z0;
+       const int32_t* tanPtr = kATanHDegrees;
+    int k = -3;
+       do {
+        int32_t x1 = y >> t;
+               int32_t y1 = x >> t;
+               int32_t tan = *tanPtr++;        
+               int count = 2 + (k >> 31);
+               if (++k == 1)
+                       k = -2;
+        do {
+                       if ((y >> 31) & mode | ~((z >> 31) | mode)) {
+                               x += x1;
+                               y += y1;
+                               z -= tan;
+                       } else {
+                               x -= x1;
+                               y -= y1;
+                               z += tan;
+                       }
+               } while (--count);
+       } while (++t < 30);
+    *x0 = x;
+    *y0 = y;
+    *z0 = z;
+}
+
+SkFixed SkCordicLog(SkFixed a) {
+       a *= 0x28be;
+       int32_t x = a + 0x28BE60DB;     // 1.0
+       int32_t y = a - 0x28BE60DB;
+       int32_t z = 0;
+       SkHyperbolic(&x, &y, &z, -1);
+       Sk64 scaled;
+       scaled.setMul(z, 0x6488d);
+       z = scaled.fHi;
+       return z << 1;
+}
+
+SkFixed SkCordicExp(SkFixed a) {
+       int32_t cosh = kFixedInvGain2;
+       int32_t sinh = 0;
+       SkHyperbolic(&cosh, &sinh, &a, 0);
+       return cosh + sinh;
+}
+
+#ifdef SK_DEBUG
+
+#ifdef SK_CAN_USE_FLOAT
+    #include "SkFloatingPoint.h"
+#endif
+
+void SkCordic_UnitTest()
+{
+#if defined(SK_SUPPORT_UNITTEST) && defined(SK_CAN_USE_FLOAT)
+    float val;
+       for (float angle = -720; angle < 720; angle += 30) {
+               float radian = angle * 3.1415925358f / 180.0f;
+               SkFixed f_angle = (int) (radian * 65536.0f);
+       // sincos
+               float sine = sinf(radian);
+               float cosine = cosf(radian);
+               SkFixed f_cosine;
+               SkFixed f_sine = SkCordicSinCos(f_angle, &f_cosine);
+               float sine2 = (float) f_sine / 65536.0f;
+               float cosine2 = (float) f_cosine / 65536.0f;
+               float error = fabsf(sine - sine2);
+               if (error > 0.001)
+                       SkDebugf("sin error : angle = %g ; sin = %g ; cordic = %g\n", angle, sine, sine2);
+               error = fabsf(cosine - cosine2);
+               if (error > 0.001)
+                       SkDebugf("cos error : angle = %g ; cos = %g ; cordic = %g\n", angle, cosine, cosine2);
+       // tan
+               float _tan = tanf(radian);
+               SkFixed f_tan = SkCordicTan(f_angle);
+               float tan2 = (float) f_tan / 65536.0f;
+               error = fabsf(_tan - tan2);
+               if (error > 0.05 && fabsf(_tan) < 1e6)
+                       SkDebugf("tan error : angle = %g ; tan = %g ; cordic = %g\n", angle, _tan, tan2);
+       }
+       for (val = -1; val <= 1; val += .1f) {
+               SkFixed f_val = (int) (val * 65536.0f);
+       // asin
+               float arcsine = asinf(val);
+               SkFixed f_arcsine = SkCordicASin(f_val);
+               float arcsine2 = (float) f_arcsine / 65536.0f;
+               float error = fabsf(arcsine - arcsine2);
+               if (error > 0.001)
+                       SkDebugf("asin error : val = %g ; asin = %g ; cordic = %g\n", val, arcsine, arcsine2);
+       }
+#if 1
+       for (val = -1; val <= 1; val += .1f) {
+#else
+       val = .5; {
+#endif
+               SkFixed f_val = (int) (val * 65536.0f);
+       // acos
+               float arccos = acosf(val);
+               SkFixed f_arccos = SkCordicACos(f_val);
+               float arccos2 = (float) f_arccos / 65536.0f;
+               float error = fabsf(arccos - arccos2);
+               if (error > 0.001)
+                       SkDebugf("acos error : val = %g ; acos = %g ; cordic = %g\n", val, arccos, arccos2);
+       }
+       // atan2
+#if 1
+       for (val = -1000; val <= 1000; val += 500.f) {
+               for (float val2 = -1000; val2 <= 1000; val2 += 500.f) {
+#else
+                       val = 0; {
+                       float val2 = -1000; {
+#endif
+                       SkFixed f_val = (int) (val * 65536.0f);
+                       SkFixed f_val2 = (int) (val2 * 65536.0f);
+                       float arctan = atan2f(val, val2);
+                       SkFixed f_arctan = SkCordicATan2(f_val, f_val2);
+                       float arctan2 = (float) f_arctan / 65536.0f;
+                       float error = fabsf(arctan - arctan2);
+                       if (error > 0.001)
+                               SkDebugf("atan2 error : val = %g ; val2 = %g ; atan2 = %g ; cordic = %g\n", val, val2, arctan, arctan2);
+               }
+       }
+       // log
+#if 1
+       for (val = 0.125f; val <= 8.f; val *= 2.0f) {
+#else
+       val = .5; {
+#endif
+               SkFixed f_val = (int) (val * 65536.0f);
+       // acos
+               float log = logf(val);
+               SkFixed f_log = SkCordicLog(f_val);
+               float log2 = (float) f_log / 65536.0f;
+               float error = fabsf(log - log2);
+               if (error > 0.001)
+                       SkDebugf("log error : val = %g ; log = %g ; cordic = %g\n", val, log, log2);
+       }
+       // exp
+#endif
+}
+
+#endif
diff --git a/libs/corecg/SkCordic.h b/libs/corecg/SkCordic.h
new file mode 100644 (file)
index 0000000..5d8dfe1
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef SkCordic_DEFINED
+#define SkCordic_DEFINED
+
+#include "SkTypes.h"
+#include "SkFixed.h"
+
+SkFixed SkCordicACos(SkFixed a);
+SkFixed SkCordicASin(SkFixed a);
+SkFixed SkCordicATan2(SkFixed y, SkFixed x);
+SkFixed SkCordicExp(SkFixed a);
+SkFixed SkCordicLog(SkFixed a);
+SkFixed SkCordicSinCos(SkFixed radians, SkFixed* cosp);
+SkFixed SkCordicTan(SkFixed a);
+
+#ifdef SK_DEBUG
+       void SkCordic_UnitTest();
+#endif
+
+#endif // SkCordic 
+
diff --git a/libs/corecg/SkDebug.cpp b/libs/corecg/SkDebug.cpp
new file mode 100644 (file)
index 0000000..65c8910
--- /dev/null
@@ -0,0 +1,42 @@
+#include "SkTypes.h"
+
+#ifdef SK_DEBUG
+
+int8_t SkToS8(long x)
+{
+       SkASSERT((int8_t)x == x);
+       return (int8_t)x;
+}
+
+uint8_t SkToU8(size_t x)
+{
+       SkASSERT((uint8_t)x == x);
+       return (uint8_t)x;
+}
+
+int16_t SkToS16(long x)
+{
+       SkASSERT((int16_t)x == x);
+       return (int16_t)x;
+}
+
+uint16_t SkToU16(size_t x)
+{
+       SkASSERT((uint16_t)x == x);
+       return (uint16_t)x;
+}
+
+int32_t SkToS32(long x)
+{
+       SkASSERT((int32_t)x == x);
+       return (int32_t)x;
+}
+
+uint32_t SkToU32(size_t x)
+{
+       SkASSERT((uint32_t)x == x);
+       return (uint32_t)x;
+}
+
+#endif
+
diff --git a/libs/corecg/SkDebug_stdio.cpp b/libs/corecg/SkDebug_stdio.cpp
new file mode 100644 (file)
index 0000000..6a35857
--- /dev/null
@@ -0,0 +1,21 @@
+#include "SkTypes.h"
+
+#if (defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)) && defined(SK_DEBUG)
+
+#include <stdarg.h>
+#include <stdio.h>
+
+void SkDebugf(const char format[], ...)
+{
+       static const size_t kBufferSize = 256;
+
+       char    buffer[kBufferSize + 1];
+       va_list args;
+       va_start(args, format);
+       vsnprintf(buffer, kBufferSize, format, args);
+       va_end(args);
+       fprintf(stderr, buffer);
+}
+
+#endif
+
diff --git a/libs/corecg/SkFP.h b/libs/corecg/SkFP.h
new file mode 100644 (file)
index 0000000..8f1f23d
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef SkFP_DEFINED
+#define SkFP_DEFINED
+
+#include "SkMath.h"
+
+#ifdef SK_SCALAR_IS_FLOAT
+
+       typedef float SkFP;
+
+       #define SkIntToFloat(n)                 SkIntToScalar(n)
+       #define SkFloatRound(x)                 SkScalarRound(n)
+       #define SkFloatCeil(x)                  SkScalarCeil(n)
+       #define SkFloatFloor(x)                 SkScalarFloor(n)
+
+       #define SkFloatNeg(x)                   (-(x))
+       #define SkFloatAbs(x)                   SkScalarAbs(x)
+       #define SkFloatAdd(a, b)                ((a) + (b))
+       #define SkFloatSub(a, b)                ((a) - (b))
+       #define SkFloatMul(a, b)                ((a) * (b))
+       #define SkFloatMulInt(a, n)             ((a) * (n))
+       #define SkFloatDiv(a, b)                ((a) / (b))
+       #define SkFloatDivInt(a, n)             ((a) / (n))
+       #define SkFloatInvert(x)                SkScalarInvert(x)
+       #define SkFloatSqrt(x)                  SkScalarSqrt(x)
+       #define SkFloatCubeRoot(x)              pow(x, 1.0f/3)
+
+       #define SkFloatLT(a, b)                 ((a) < (b))
+       #define SkFloatLE(a, b)                 ((a) <= (b))
+       #define SkFloatGT(a, b)                 ((a) > (b))
+       #define SkFloatGE(a, b)                 ((a) >= (b))
+
+#else  // scalar is fixed
+
+       #include "SkFloat.h"
+
+       typedef S32     SkFP;
+
+       #define SkIntToFloat(n)                 SkFloat::SetShift(n, 0)
+       #define SkFloatRound(x)                 SkFloat::Round(x);
+       #define SkFloatCeil(x)                  SkFloat::Ceil();
+       #define SkFloatFloor(x)                 SkFloat::Floor();
+
+       #define SkScalarToFloat(n)              SkFloat::SetShift(n, -16)
+       #define SkFloatToScalar(n)              SkFloat::GetShift(n, -16)
+       #define SkFloatNeg(x)                   SkFloat::Neg(x)
+       #define SkFloatAbs(x)                   SkFloat::Abs(x)
+       #define SkFloatAdd(a, b)                SkFloat::Add(a, b)
+       #define SkFloatSub(a, b)                SkFloat::Add(a, SkFloat::Neg(b))
+       #define SkFloatMul(a, b)                SkFloat::Mul(a, b)
+       #define SkFloatMulInt(a, n)             SkFloat::MulInt(a, n)
+       #define SkFloatDiv(a, b)                SkFloat::Div(a, b)
+       #define SkFloatDivInt(a, n)             SkFloat::DivInt(a, n)
+       #define SkFloatInvert(x)                SkFloat::Invert(x)
+       #define SkFloatSqrt(x)                  SkFloat::Sqrt(x)
+       #define SkFloatCubeRoot(x)              SkFloat::CubeRoot(x)
+
+       #define SkFloatLT(a, b)                 (SkFloat::Cmp(a, b) < 0)
+       #define SkFloatLE(a, b)                 (SkFloat::Cmp(a, b) <= 0)
+       #define SkFloatGT(a, b)                 (SkFloat::Cmp(a, b) > 0)
+       #define SkFloatGE(a, b)                 (SkFloat::Cmp(a, b) >= 0)
+
+#endif
+
+#ifdef SK_DEBUG
+       void SkFP_UnitTest();
+#endif
+
+#endif
diff --git a/libs/corecg/SkFloat.cpp b/libs/corecg/SkFloat.cpp
new file mode 100644 (file)
index 0000000..044e982
--- /dev/null
@@ -0,0 +1,387 @@
+#include "SkFloat.h"
+
+#define EXP_BIAS       (127+23)
+
+static int get_unsigned_exp(U32 packed)
+{
+       return (packed << 1 >> 24);
+}
+
+static unsigned get_unsigned_value(U32 packed)
+{
+       return (packed << 9 >> 9) | (1 << 23);
+}
+
+static int get_signed_value(S32 packed)
+{
+       return SkApplySign(get_unsigned_value(packed), SkExtractSign(packed));
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+int SkFloat::GetShift(S32 packed, int shift)
+{
+       if (packed == 0)
+               return 0;
+
+       int     exp = get_unsigned_exp(packed) - EXP_BIAS - shift;
+       int value = get_unsigned_value(packed);
+
+       if (exp >= 0)
+       {
+               if (exp > 8)    // overflow
+                       value = SK_MaxS32;
+               else
+                       value <<= exp;
+       }
+       else
+       {
+               exp = -exp;
+               if (exp > 23)   // underflow
+                       value = 0;
+               else
+                       value >>= exp;
+       }
+       return SkApplySign(value, SkExtractSign(packed));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+S32 SkFloat::SetShift(int value, int shift)
+{
+       if (value == 0)
+               return 0;
+
+       // record the sign and make value positive
+       int     sign = SkExtractSign(value);
+       value = SkApplySign(value, sign);
+
+       if (value >> 24)        // value is too big (has more than 24 bits set)
+       {
+               int bias = 8 - SkCLZ(value);
+               SkASSERT(bias > 0 && bias < 8);
+               value >>= bias;
+               shift += bias;
+       }
+       else
+       {
+               int zeros = SkCLZ(value << 8);
+               SkASSERT(zeros >= 0 && zeros <= 23);
+               value <<= zeros;
+               shift -= zeros;
+       }
+       // now value is left-aligned to 24 bits
+       SkASSERT((value >> 23) == 1);
+
+       shift += EXP_BIAS;
+       if (shift < 0)  // underflow
+               return 0;
+       else
+       {
+               if (shift > 255)        // overflow
+               {
+                       shift = 255;
+                       value = 0x00FFFFFF;
+               }
+               S32 packed = sign << 31;                // set the sign-bit
+               packed |= shift << 23;                  // store the packed exponent
+               packed |= ((unsigned)(value << 9) >> 9);        // clear 24th bit of value (its implied)
+
+#ifdef SK_DEBUG
+               {
+                       int     n;
+
+                       n = SkExtractSign(packed);
+                       SkASSERT(n == sign);
+                       n = get_unsigned_exp(packed);
+                       SkASSERT(n == shift);
+                       n = get_unsigned_value(packed);
+                       SkASSERT(n == value);
+               }
+#endif
+               return packed;
+       }
+}
+
+S32 SkFloat::Neg(S32 packed)
+{
+       if (packed)
+               packed = packed ^ (1 << 31);
+       return packed;
+}
+
+S32 SkFloat::Add(S32 packed_a, S32 packed_b)
+{
+       if (packed_a == 0)
+               return packed_b;
+       if (packed_b == 0)
+               return packed_a;
+
+       int     exp_a = get_unsigned_exp(packed_a);
+       int     exp_b = get_unsigned_exp(packed_b);
+       int exp_diff = exp_a - exp_b;
+
+       int     shift_a = 0, shift_b = 0;
+       int     exp;
+
+       if (exp_diff >= 0)
+       {
+               if (exp_diff > 24)      // B is too small to contribute
+                       return packed_a;
+               shift_b = exp_diff;
+               exp = exp_a;
+       }
+       else
+       {
+               exp_diff = -exp_diff;
+               if (exp_diff > 24)      // A is too small to contribute
+                       return packed_b;
+               shift_a = exp_diff;
+               exp = exp_b;
+       }
+
+       int     value_a = get_signed_value(packed_a) >> shift_a;
+       int value_b = get_signed_value(packed_b) >> shift_b;
+
+       return SkFloat::SetShift(value_a + value_b, exp - EXP_BIAS);
+}
+
+#include "Sk64.h"
+
+static inline S32 mul24(S32 a, S32 b)
+{
+       Sk64 tmp;
+
+       tmp.setMul(a, b);
+       tmp.roundRight(24);
+       return tmp.get32();
+}
+
+S32 SkFloat::Mul(S32 packed_a, S32 packed_b)
+{
+       if (packed_a == 0 || packed_b == 0)
+               return 0;
+
+       int     exp_a = get_unsigned_exp(packed_a);
+       int     exp_b = get_unsigned_exp(packed_b);
+
+       int     value_a = get_signed_value(packed_a);
+       int value_b = get_signed_value(packed_b);
+
+       return SkFloat::SetShift(mul24(value_a, value_b), exp_a + exp_b - 2*EXP_BIAS + 24);
+}
+
+S32 SkFloat::MulInt(S32 packed, int n)
+{
+       return Mul(packed, SetShift(n, 0));
+}
+
+S32 SkFloat::Div(S32 packed_n, S32 packed_d)
+{
+       SkASSERT(packed_d != 0);
+
+       if (packed_n == 0)
+               return 0;
+
+       int     exp_n = get_unsigned_exp(packed_n);
+       int     exp_d = get_unsigned_exp(packed_d);
+
+       int     value_n = get_signed_value(packed_n);
+       int value_d = get_signed_value(packed_d);
+
+       return SkFloat::SetShift(SkDivBits(value_n, value_d, 24), exp_n - exp_d - 24);
+}
+
+S32 SkFloat::DivInt(S32 packed, int n)
+{
+       return Div(packed, SetShift(n, 0));
+}
+
+S32 SkFloat::Invert(S32 packed)
+{
+       return Div(packed, SetShift(1, 0));
+}
+
+S32 SkFloat::Sqrt(S32 packed)
+{
+       if (packed < 0)
+       {
+               SkASSERT(!"can't sqrt a negative number");
+               return 0;
+       }
+
+       int     exp = get_unsigned_exp(packed);
+       int     value = get_unsigned_value(packed);
+
+       int nexp = exp - EXP_BIAS;
+       int root = SkSqrtBits(value << (nexp & 1), 26);
+       nexp >>= 1;
+       return SkFloat::SetShift(root, nexp - 11);
+}
+
+#if defined _WIN32 && _MSC_VER >= 1300 // disable warning : unreachable code
+#pragma warning ( push )
+#pragma warning ( disable : 4702 )
+#endif
+
+S32 SkFloat::CubeRoot(S32 packed)
+{
+       sk_throw();
+       return 0;
+}
+
+#if defined _WIN32 && _MSC_VER >= 1300
+#pragma warning ( pop )
+#endif
+
+static inline S32 clear_high_bit(S32 n)
+{
+       return ((U32)(n << 1)) >> 1;
+}
+
+static inline int int_sign(S32 a, S32 b)
+{
+       return a > b ? 1 : (a < b ? -1 : 0);
+}
+
+int SkFloat::Cmp(S32 packed_a, S32 packed_b)
+{
+       packed_a = SkApplySign(clear_high_bit(packed_a), SkExtractSign(packed_a));
+       packed_b = SkApplySign(clear_high_bit(packed_b), SkExtractSign(packed_b));
+
+       return int_sign(packed_a, packed_b);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+#include "SkRandom.h"
+#ifdef SK_CAN_USE_FLOAT
+    #include "SkFloatingPoint.h"
+#endif
+
+void SkFloat::UnitTest()
+{
+#ifdef SK_SUPPORT_UNITTEST
+       SkFloat a, b, c, d;
+       int             n;
+
+       a.setZero();
+       n = a.getInt();
+       SkASSERT(n == 0);
+
+       b.setInt(5);
+       n = b.getInt();
+       SkASSERT(n == 5);
+
+       c.setInt(-3);
+       n = c.getInt();
+       SkASSERT(n == -3);
+
+       d.setAdd(c, b);
+       SkDebugf("SkFloat: %d + %d = %d\n", c.getInt(), b.getInt(), d.getInt());        
+
+       SkRandom        rand;
+
+#ifdef SK_CAN_USE_FLOAT
+       int i;
+       for (i = 0; i < 1000; i++)
+       {
+               float fa, fb;
+               int     aa = rand.nextS() >> 14;
+               int bb = rand.nextS() >> 14;
+               a.setInt(aa);
+               b.setInt(bb);
+               SkASSERT(a.getInt() == aa);
+               SkASSERT(b.getInt() == bb);
+
+               c.setAdd(a, b);
+               int     cc = c.getInt();
+               SkASSERT(cc == aa + bb);
+
+               c.setSub(a, b);
+               cc = c.getInt();
+               SkASSERT(cc == aa - bb);
+
+               aa >>= 5;
+               bb >>= 5;
+               a.setInt(aa);
+               b.setInt(bb);
+               c.setMul(a, b);
+               cc = c.getInt();
+               SkASSERT(cc == aa * bb);
+               /////////////////////////////////////
+
+               aa = rand.nextS() >> 11;
+               a.setFixed(aa);
+               cc = a.getFixed();
+               SkASSERT(aa == cc);
+
+               bb = rand.nextS() >> 11;
+               b.setFixed(bb);
+               cc = b.getFixed();
+               SkASSERT(bb == cc);
+
+               cc = SkFixedMul(aa, bb);
+               c.setMul(a, b);
+               SkFixed dd = c.getFixed();
+               int diff = cc - dd;
+               SkASSERT(SkAbs32(diff) <= 1);
+
+               fa = (float)aa / 65536.0f;
+               fb = (float)bb / 65536.0f;
+               a.assertEquals(fa);
+               b.assertEquals(fb);
+               fa = a.getFloat();
+               fb = b.getFloat();
+
+               c.assertEquals(fa * fb, 1);
+
+               c.setDiv(a, b);
+               cc = SkFixedDiv(aa, bb);
+               dd = c.getFixed();
+               diff = cc - dd;
+               SkASSERT(SkAbs32(diff) <= 3);
+
+               c.assertEquals(fa / fb, 1);
+
+               SkASSERT((aa == bb) == (a == b));
+               SkASSERT((aa != bb) == (a != b));
+               SkASSERT((aa < bb) == (a < b));
+               SkASSERT((aa <= bb) == (a <= b));
+               SkASSERT((aa > bb) == (a > b));
+               SkASSERT((aa >= bb) == (a >= b));
+
+               if (aa < 0)
+               {
+                       aa = -aa;
+                       fa = -fa;
+               }
+               a.setFixed(aa);
+               c.setSqrt(a);
+               cc = SkFixedSqrt(aa);
+               dd = c.getFixed();
+               SkASSERT(dd == cc);
+
+               c.assertEquals(sk_float_sqrt(fa), 2);
+
+               // cuberoot
+#if 0
+               a.setInt(1);
+               a.cubeRoot();
+               a.assertEquals(1.0f, 0);
+               a.setInt(8);
+               a.cubeRoot();
+               a.assertEquals(2.0f, 0);
+               a.setInt(27);
+               a.cubeRoot();
+               a.assertEquals(3.0f, 0);
+#endif
+       }
+#endif
+#endif
+}
+
+#endif
diff --git a/libs/corecg/SkFloat.h b/libs/corecg/SkFloat.h
new file mode 100644 (file)
index 0000000..6ff252d
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef SkFloat_DEFINED
+#define SkFloat_DEFINED
+
+#include "SkMath.h"
+
+class SkFloat {
+public:
+                       SkFloat() {}
+
+       void    setZero() { fPacked = 0; }
+//     void    setShift(int value, int shift) { fPacked = SetShift(value, shift); }
+       void    setInt(int value) { fPacked = SetShift(value, 0); }
+       void    setFixed(SkFixed value) { fPacked = SetShift(value, -16); }
+       void    setFract(SkFract value) { fPacked = SetShift(value, -30); }
+
+//     int             getShift(int shift) const { return GetShift(fPacked, shift); }
+       int             getInt() const { return GetShift(fPacked, 0); }
+       SkFixed getFixed() const { return GetShift(fPacked, -16); }
+       SkFract getFract() const { return GetShift(fPacked, -30); }
+
+       void    abs() { fPacked = Abs(fPacked); }
+       void    negate() { fPacked = Neg(fPacked); }
+
+       void    shiftLeft(int bits) { fPacked = Shift(fPacked, bits); }
+       void    setShiftLeft(const SkFloat& a, int bits) { fPacked = Shift(a.fPacked, bits); }
+
+       void    shiftRight(int bits) { fPacked = Shift(fPacked, -bits); }
+       void    setShiftRight(const SkFloat& a, int bits) { fPacked = Shift(a.fPacked, -bits); }
+
+       void    add(const SkFloat& a) { fPacked = Add(fPacked, a.fPacked); }
+       void    setAdd(const SkFloat& a, const SkFloat& b) { fPacked = Add(a.fPacked, b.fPacked); }
+
+       void    sub(const SkFloat& a) { fPacked = Add(fPacked, Neg(a.fPacked)); }
+       void    setSub(const SkFloat& a, const SkFloat& b) { fPacked = Add(a.fPacked, Neg(b.fPacked)); }
+
+       void    mul(const SkFloat& a) { fPacked = Mul(fPacked, a.fPacked); }
+       void    setMul(const SkFloat& a, const SkFloat& b) { fPacked = Mul(a.fPacked, b.fPacked); }
+
+       void    div(const SkFloat& a) { fPacked = Div(fPacked, a.fPacked); }
+       void    setDiv(const SkFloat& a, const SkFloat& b) { fPacked = Div(a.fPacked, b.fPacked); }
+
+       void    sqrt() { fPacked = Sqrt(fPacked); }
+       void    setSqrt(const SkFloat& a) { fPacked = Sqrt(a.fPacked); }
+       void    cubeRoot() { fPacked = CubeRoot(fPacked); }
+       void    setCubeRoot(const SkFloat& a) { fPacked = CubeRoot(a.fPacked); }
+
+       friend bool operator==(const SkFloat& a, const SkFloat& b) { return a.fPacked == b.fPacked; }
+       friend bool operator!=(const SkFloat& a, const SkFloat& b) { return a.fPacked != b.fPacked; }
+       friend bool operator<(const SkFloat& a, const SkFloat& b) { return Cmp(a.fPacked, b.fPacked) < 0; }
+       friend bool operator<=(const SkFloat& a, const SkFloat& b) { return Cmp(a.fPacked, b.fPacked) <= 0; }
+       friend bool operator>(const SkFloat& a, const SkFloat& b) { return Cmp(a.fPacked, b.fPacked) > 0; }
+       friend bool operator>=(const SkFloat& a, const SkFloat& b) { return Cmp(a.fPacked, b.fPacked) >= 0; }
+
+#ifdef SK_DEBUG
+       static void UnitTest();
+
+       void assertEquals(float f, int tolerance = 0)
+       {
+               S32     s = *(S32*)&f;
+               int d = s - fPacked;
+               SkASSERT(SkAbs32(d) <= tolerance);
+       }
+       float getFloat() const
+       {
+               return *(float*)&fPacked;
+       }
+#endif
+
+private:
+       S32     fPacked;
+
+       SkFloat(S32 packed) : fPacked(fPacked) {}
+
+public:
+       static int GetShift(S32 packed, int shift);
+       static S32 SetShift(int value, int shift);
+       static S32 Neg(S32);
+       static S32 Abs(S32 packed) { return (U32)(packed << 1) >> 1; }
+       static S32 Shift(S32, int bits);
+       static S32 Add(S32, S32);
+       static S32 Mul(S32, S32);
+       static S32 MulInt(S32, int);
+       static S32 Div(S32, S32);
+       static S32 DivInt(S32, int);
+       static S32 Invert(S32);
+       static S32 Sqrt(S32);
+       static S32 CubeRoot(S32);
+       static int Cmp(S32, S32);
+};
+
+#endif
diff --git a/libs/corecg/SkMath.cpp b/libs/corecg/SkMath.cpp
new file mode 100644 (file)
index 0000000..8221310
--- /dev/null
@@ -0,0 +1,703 @@
+#include "SkMath.h"
+#include "SkCordic.h"
+#include "SkFloatingPoint.h"
+#include "Sk64.h"
+
+#ifdef SK_SCALAR_IS_FLOAT
+       const uint32_t gIEEENotANumber = 0x7FFFFFFF;
+       const uint32_t gIEEEInfinity = 0x7F800000;
+#endif
+
+int SkCLZ(uint32_t x)
+{
+#if defined(__arm__) && !defined(__thumb) && defined(__ARM_ARCH_5T__)
+    asm( "clz %0,%0" : "=r"(x) : "0"(x) : );
+    return x;
+#else
+       if (x == 0)
+               return 32;
+
+       SkDEBUGCODE(uint32_t n = x;)
+
+       int zeros = ((x >> 16) - 1) >> 31 << 4;
+       x <<= zeros;
+
+       int nonzero = ((x >> 24) - 1) >> 31 << 3;
+       zeros += nonzero;
+       x <<= nonzero;
+
+       nonzero = ((x >> 28) - 1) >> 31 << 2;
+       zeros += nonzero;
+       x <<= nonzero;
+
+       nonzero = ((x >> 30) - 1) >> 31 << 1;
+       zeros += nonzero;
+       x <<= nonzero;
+
+//     zeros += ((x >> 31) - 1) >> 31;
+       zeros += (~x) >> 31;
+
+#ifdef SK_DEBUG
+       int     slow_zeros;
+
+       if (n == 0)
+               slow_zeros = 32;
+       else
+       {
+               slow_zeros = 0;
+               while ((int32_t)n > 0)
+               {
+                       slow_zeros += 1;
+                       n <<= 1;
+               }
+       }
+       SkASSERT(zeros == slow_zeros);
+#endif
+       return zeros;
+#endif
+}
+
+int32_t SkMulDiv(int32_t numer1, int32_t numer2, int32_t denom)
+{
+       SkASSERT(denom);
+
+       Sk64 tmp;
+       tmp.setMul(numer1, numer2);
+       tmp.div(denom, Sk64::kTrunc_DivOption);
+       return tmp.get32();
+}
+
+int32_t SkMulShift(int32_t a, int32_t b, unsigned shift)
+{
+       int sign = SkExtractSign(a ^ b);
+
+       if (shift > 63)
+               return sign;
+
+       a = SkAbs32(a);
+       b = SkAbs32(b);
+
+       uint32_t ah = a >> 16;
+       uint32_t al = a & 0xFFFF;
+       uint32_t bh = b >> 16;
+       uint32_t bl = b & 0xFFFF;
+
+       uint32_t A = ah * bh;
+       uint32_t B = ah * bl + al * bh;
+       uint32_t C = al * bl;
+
+       /*      [  A  ]
+                  [  B  ]
+                     [  C  ]
+       */
+       uint32_t lo = C + (B << 16);
+       int32_t  hi = A + (B >> 16) + (lo < C);
+
+       if (sign < 0)
+       {
+               hi = -hi - Sk32ToBool(lo);
+               lo = 0 - lo;
+       }
+
+       if (shift == 0)
+       {
+#ifdef SK_DEBUGx
+               SkASSERT(((int32_t)lo >> 31) == hi);
+#endif
+               return lo;
+       }
+       else if (shift >= 32)
+               return hi >> (shift - 32);
+       else
+       {
+#ifdef SK_DEBUGx
+               int32_t tmp = hi >> shift;
+               SkASSERT(tmp == 0 || tmp == -1);
+#endif
+               return (hi << (32 - shift)) | (lo >> shift);
+       }
+}
+
+#if !defined(SK_BUILD_FOR_BREW) || defined(AEE_SIMULATOR)
+SkFixed SkFixedMul(SkFixed a, SkFixed b)
+{
+#if 0
+       Sk64    tmp;
+
+       tmp.setMul(a, b);
+       tmp.shiftRight(16);
+       return tmp.fLo;
+#else
+       int sa = SkExtractSign(a);
+       int sb = SkExtractSign(b);
+       // now make them positive
+       a = SkApplySign(a, sa);
+       b = SkApplySign(b, sb);
+
+       uint32_t        ah = a >> 16;
+       uint32_t        al = a & 0xFFFF;
+       uint32_t bh = b >> 16;
+       uint32_t bl = b & 0xFFFF;
+
+       uint32_t R = ah * b + al * bh + (al * bl >> 16);
+
+       return SkApplySign(R, sa ^ sb);
+#endif
+}
+
+SkFract        SkFractMul(SkFract a, SkFract b)
+{
+#if 0
+       Sk64 tmp;
+       tmp.setMul(a, b);
+       return tmp.getFract();
+#else
+       int sa = SkExtractSign(a);
+       int sb = SkExtractSign(b);
+       // now make them positive
+       a = SkApplySign(a, sa);
+       b = SkApplySign(b, sb);
+
+       uint32_t ah = a >> 16;
+       uint32_t al = a & 0xFFFF;
+       uint32_t bh = b >> 16;
+       uint32_t bl = b & 0xFFFF;
+
+       uint32_t A = ah * bh;
+       uint32_t B = ah * bl + al * bh;
+       uint32_t C = al * bl;
+
+       /*      [  A  ]
+                  [  B  ]
+                     [  C  ]
+       */
+       uint32_t Lo = C + (B << 16);
+       uint32_t Hi = A + (B >>16) + (Lo < C);
+
+       SkASSERT((Hi >> 29) == 0);      // else overflow
+
+       int32_t R = (Hi << 2) + (Lo >> 30);
+
+       return SkApplySign(R, sa ^ sb);
+#endif
+}
+#endif
+
+int SkFixedMulCommon(SkFixed a, int b, int bias)
+{
+       // this function only works if b is 16bits
+       SkASSERT(b == (S16)b);
+       SkASSERT(b >= 0);
+
+       int sa = SkExtractSign(a);
+       a = SkApplySign(a, sa);
+       uint32_t ah = a >> 16;
+       uint32_t al = a & 0xFFFF;
+       uint32_t R = ah * b + ((al * b + bias) >> 16);
+       return SkApplySign(R, sa);
+}
+
+int32_t SkDivBits(int32_t numer, int32_t denom, int shift_bias)
+{
+       SkASSERT(denom != 0);
+       if (numer == 0)
+               return 0;
+               
+       SkFixed result;
+       int32_t sign;
+
+       // make numer and denom positive, and sign hold the resulting sign
+       sign = SkExtractSign(numer ^ denom);
+       numer = SkAbs32(numer);
+       denom = SkAbs32(denom);
+
+#if 0   // faster assuming we have HW divide
+       if ((numer >> (32 - shift_bias)) == 0)
+       {
+               result = (uint32_t)(numer << shift_bias) / denom;
+       }
+       else
+#endif
+       {
+               int     nbits = SkCLZ(numer) - 1;
+               int dbits = SkCLZ(denom) - 1;
+               int bits = shift_bias - nbits + dbits;
+
+               if (bits <= 0)  // answer will underflow
+                       return 0;
+               if (bits > 31)  // answer will overflow
+                       return SkApplySign(SK_MaxS32, sign);
+
+               denom <<= dbits;
+               numer <<= nbits;
+               result = 0;
+               do {
+                       result <<= 1;
+       #ifdef SK_CPU_HAS_CONDITIONAL_INSTR
+                       if ((uint32_t)denom <= (uint32_t)numer)
+                       {
+                               numer -= denom;
+                               result |= 1;
+                       }
+       #else
+                       int32_t diff = (denom - numer - 1) >> 31;
+                       result -= diff;
+                       numer -= denom & diff;
+       #endif
+                       numer <<= 1;
+               } while (--bits >= 0);
+       }
+
+       if (result < 0)
+               result = SK_MaxS32;
+       return SkApplySign(result, sign);
+}
+
+/*  mod(float numer, float denom) seems to always return the sign
+       of the numer, so that's what we do too
+*/
+SkFixed SkFixedMod(SkFixed numer, SkFixed denom)
+{
+       int sn = SkExtractSign(numer);
+       int sd = SkExtractSign(denom);
+
+       numer = SkApplySign(numer, sn);
+       denom = SkApplySign(denom, sd);
+       
+       if (numer < denom)
+               return SkApplySign(numer, sn);
+       else if (numer == denom)
+               return 0;
+       else
+       {
+               SkFixed div = SkFixedDiv(numer, denom);
+               return SkApplySign(SkFixedMul(denom, div & 0xFFFF), sn);
+       }
+}
+
+/* www.worldserver.com/turk/computergraphics/FixedSqrt.pdf
+*/
+int32_t SkSqrtBits(int32_t x, int count)
+{
+       SkASSERT(x >= 0 && count > 0 && (unsigned)count <= 30);
+
+       uint32_t        root = 0;
+       uint32_t        remHi = 0;
+       uint32_t        remLo = x;
+
+       do {
+               root <<= 1;
+
+               remHi = (remHi<<2) | (remLo>>30);
+               remLo <<= 2;
+
+               uint32_t testDiv = (root << 1) + 1;
+               if (remHi >= testDiv)
+               {
+                       remHi -= testDiv;
+                       root++;
+               }
+       } while (--count >= 0);
+
+       return root;
+}
+
+int32_t SkCubeRootBits(int32_t value, int bits)
+{
+       SkASSERT(bits > 0);
+
+       int     sign = SkExtractSign(value);
+       value = SkApplySign(value, sign);
+
+       uint32_t root = 0;
+       uint32_t curr = (uint32_t)value >> 30;
+       value <<= 2;
+
+       do {
+               root <<= 1;
+               uint32_t guess = root * root + root;
+               guess = (guess << 1) + guess;   // guess *= 3
+               if (guess < curr)
+               {       curr -= guess + 1;
+                       root |= 1;
+               }
+               curr = (curr << 3) | ((uint32_t)value >> 29);
+               value <<= 3;
+       } while (--bits);
+
+       return SkApplySign(root, sign);
+}
+
+SkFixed SkFixedMean(SkFixed a, SkFixed b)
+{
+       Sk64 tmp;
+       
+       tmp.setMul(a, b);
+       return tmp.getSqrt();
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_SCALAR_IS_FLOAT
+float SkScalarSinCos(float radians, float* cosValue)
+{
+       float sinValue = sk_float_sin(radians);
+
+       if (cosValue)
+               *cosValue = sk_float_cos(radians);
+       
+       if (SkScalarNearlyZero(*cosValue))
+               *cosValue = 0;
+
+       if (SkScalarNearlyZero(sinValue))
+               sinValue = 0;
+
+       return sinValue;
+}
+#endif
+
+#define INTERP_SINTABLE
+#define BUILD_TABLE_AT_RUNTIMEx
+
+#define kTableSize     256
+
+#ifdef BUILD_TABLE_AT_RUNTIME
+       static uint16_t gSkSinTable[kTableSize];
+
+       static void build_sintable(uint16_t table[])
+       {
+               for (int i = 0; i < kTableSize; i++)
+               {
+                       double  rad = i * 3.141592653589793 / (2*kTableSize);
+                       double  val = sin(rad);
+                       int             ival = (int)(val * SK_Fixed1);
+                       table[i] = SkToU16(ival);
+               }
+       }
+#else
+       #include "SkSinTable.h"
+#endif
+
+#define SK_Fract1024SizeOver2PI                0x28BE60        /* floatToFract(1024 / 2PI) */
+
+#ifdef INTERP_SINTABLE
+static SkFixed interp_table(const uint16_t table[], int index, int partial256)
+{
+       SkASSERT((unsigned)index < kTableSize);
+
+       SkFixed lower = table[index];
+       SkFixed upper = (index == kTableSize - 1) ? SK_Fixed1 : table[index + 1];
+
+       SkASSERT(lower < upper);
+       SkASSERT(lower >= 0);
+       SkASSERT(upper <= SK_Fixed1);
+       SkASSERT((unsigned)partial256 <= 255);
+
+       return lower + ((upper - lower) * partial256 >> 8);
+}
+#endif
+
+SkFixed SkFixedSinCos(SkFixed radians, SkFixed* cosValuePtr)
+{
+       SkASSERT(SK_ARRAY_COUNT(gSkSinTable) == kTableSize);
+
+#ifdef BUILD_TABLE_AT_RUNTIME
+       static bool gFirstTime = true;
+       if (gFirstTime)
+       {
+               build_sintable(gSinTable);
+               gFirstTime = false;
+       }
+#endif
+
+       // make radians positive
+       SkFixed sinValue, cosValue;
+       int32_t cosSign = 0;
+       int32_t sinSign = SkExtractSign(radians);
+       radians = SkApplySign(radians, sinSign);
+       // scale it to 0...1023 ...
+
+#ifdef INTERP_SINTABLE
+       radians = SkMulDiv(radians, 2 * kTableSize * 256, SK_FixedPI);
+       int findex = radians & (kTableSize * 256 - 1);
+       int index = findex >> 8;
+       int partial = findex & 255;
+       sinValue = interp_table(gSkSinTable, index, partial);
+
+       findex = kTableSize * 256 - findex - 1;
+       index = findex >> 8;
+       partial = findex & 255;
+       cosValue = interp_table(gSkSinTable, index, partial);
+
+       int quad = ((unsigned)radians / (kTableSize * 256)) & 3;
+#else
+       radians = SkMulDiv(radians, 2 * kTableSize, SK_FixedPI);
+       int             index = radians & (kTableSize - 1);
+
+       if (index == 0)
+       {
+               sinValue = 0;
+               cosValue = SK_Fixed1;
+       }
+       else
+       {
+               sinValue = gSkSinTable[index];
+               cosValue = gSkSinTable[kTableSize - index];
+       }
+       int quad = ((unsigned)radians / kTableSize) & 3;
+#endif
+
+       if (quad & 1)
+               SkTSwap<SkFixed>(sinValue, cosValue);
+       if (quad & 2)
+               sinSign = ~sinSign;
+       if (((quad - 1) & 2) == 0)
+               cosSign = ~cosSign;
+
+       sinValue = SkApplySign(sinValue, sinSign);
+       cosValue = SkApplySign(cosValue, cosSign);
+
+#ifdef SK_DEBUG
+       if (1)
+       {
+               SkFixed sin2 = SkFixedMul(sinValue, sinValue);
+               SkFixed cos2 = SkFixedMul(cosValue, cosValue);
+               int diff = cos2 + sin2 - SK_Fixed1;
+               SkASSERT(SkAbs32(diff) <= 8);
+       }
+#endif
+
+       // restore the sign for negative angles
+       if (cosValuePtr)
+               *cosValuePtr = cosValue;
+       return sinValue;
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+SkFixed SkFixedTan(SkFixed radians) { return SkCordicTan(radians); }
+SkFixed SkFixedASin(SkFixed x) { return SkCordicASin(x); }
+SkFixed SkFixedACos(SkFixed x) { return SkCordicACos(x); }
+SkFixed SkFixedATan2(SkFixed y, SkFixed x) { return SkCordicATan2(y, x); }
+SkFixed SkFixedExp(SkFixed x) { return SkCordicExp(x); }
+SkFixed SkFixedLog(SkFixed x) { return SkCordicLog(x); }
+
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+#include "SkRandom.h"
+
+#ifdef SK_CAN_USE_LONGLONG
+static int symmetric_fixmul(int a, int b)
+{
+       int sa = SkExtractSign(a);
+       int sb = SkExtractSign(b);
+
+       a = SkApplySign(a, sa);
+       b = SkApplySign(b, sb);
+
+#if 1
+       int c = (int)(((SkLONGLONG)a * b) >> 16);
+       
+       return SkApplySign(c, sa ^ sb);
+#else
+       SkLONGLONG ab = (SkLONGLONG)a * b;
+       if (sa ^ sb)
+               ab = -ab;
+       return ab >> 16;
+#endif
+}
+#endif
+
+void SkMath::UnitTest()
+{
+#ifdef SK_SUPPORT_UNITTEST
+       int                     i;
+       int32_t     x;
+       SkRandom        rand;
+
+       SkToS8(127);    SkToS8(-128);           SkToU8(255);
+       SkToS16(32767); SkToS16(-32768);        SkToU16(65535);
+       SkToS32(2*1024*1024);   SkToS32(-2*1024*1024);  SkToU32(4*1024*1024);
+
+       SkCordic_UnitTest();
+
+       // these should assert
+#if 0
+       SkToS8(128);
+       SkToS8(-129);
+       SkToU8(256);
+       SkToU8(-5);
+
+       SkToS16(32768);
+       SkToS16(-32769);
+       SkToU16(65536);
+       SkToU16(-5);
+
+       if (sizeof(size_t) > 4)
+       {
+               SkToS32(4*1024*1024);
+               SkToS32(-4*1024*1024);
+               SkToU32(5*1024*1024);
+               SkToU32(-5);
+       }
+#endif
+
+    {
+        SkScalar x = SK_ScalarNaN;
+        SkASSERT(SkScalarIsNaN(x));
+    }
+
+       for (i = 1; i <= 10; i++)
+       {
+               x = SkCubeRootBits(i*i*i, 11);
+               SkASSERT(x == i);
+       }
+
+       x = SkFixedSqrt(SK_Fixed1);
+       SkASSERT(x == SK_Fixed1);
+       x = SkFixedSqrt(SK_Fixed1/4);
+       SkASSERT(x == SK_Fixed1/2);
+       x = SkFixedSqrt(SK_Fixed1*4);
+       SkASSERT(x == SK_Fixed1*2);
+
+       x = SkFractSqrt(SK_Fract1);
+       SkASSERT(x == SK_Fract1);
+       x = SkFractSqrt(SK_Fract1/4);
+       SkASSERT(x == SK_Fract1/2);
+       x = SkFractSqrt(SK_Fract1/16);
+       SkASSERT(x == SK_Fract1/4);
+
+       for (i = 1; i < 100; i++)
+       {
+               x = SkFixedSqrt(SK_Fixed1 * i * i);
+               SkASSERT(x == SK_Fixed1 * i);
+       }
+
+       for (i = 0; i < 1000; i++)
+       {
+               int value = rand.nextS16();
+               int max = rand.nextU16();
+
+               int clamp = SkClampMax(value, max);
+               int clamp2 = value < 0 ? 0 : (value > max ? max : value);
+               SkASSERT(clamp == clamp2);
+       }
+
+#ifdef SK_CAN_USE_LONGLONG
+       for (i = 0; i < 100000; i++)
+       {
+               SkFixed numer = rand.nextS();
+               SkFixed denom = rand.nextS();
+               SkFixed result = SkFixedDiv(numer, denom);
+               SkLONGLONG check = ((SkLONGLONG)numer << 16) / denom;
+
+               (void)SkCLZ(numer);
+               (void)SkCLZ(denom);
+
+               SkASSERT(result != (SkFixed)SK_NaN32);
+               if (check > SK_MaxS32)
+                       check = SK_MaxS32;
+               else if (check < -SK_MaxS32)
+                       check = SK_MinS32;
+               SkASSERT(result == check);
+
+               result = SkFractDiv(numer, denom);
+               check = ((SkLONGLONG)numer << 30) / denom;
+
+               SkASSERT(result != (SkFixed)SK_NaN32);
+               if (check > SK_MaxS32)
+                       check = SK_MaxS32;
+               else if (check < -SK_MaxS32)
+                       check = SK_MinS32;
+               SkASSERT(result == (int32_t)check);
+
+               // make them <= 2^24, so we don't overflow in fixmul
+               numer = numer << 8 >> 8;
+               denom = denom << 8 >> 8;
+
+               result = SkFixedMul(numer, denom);
+               SkFixed r2 = symmetric_fixmul(numer, denom);
+               SkASSERT(result == r2);
+
+               result = SkFixedMul(numer, numer);
+               r2 = SkFixedSquare(numer);
+               SkASSERT(result == r2);
+               
+#ifdef SK_CAN_USE_FLOAT
+               if (numer >= 0 && denom >= 0)
+               {
+                       SkFixed mean = SkFixedMean(numer, denom);
+                       float fm = sk_float_sqrt(sk_float_abs(SkFixedToFloat(numer) * SkFixedToFloat(denom)));
+                       SkFixed mean2 = SkFloatToFixed(fm);
+                       int diff = SkAbs32(mean - mean2);
+                       SkASSERT(diff <= 1);
+               }
+
+               {
+                       SkFixed mod = SkFixedMod(numer, denom);
+                       float n = SkFixedToFloat(numer);
+                       float d = SkFixedToFloat(denom);
+                       float m = sk_float_mod(n, d);
+#if 0
+                       SkDebugf("%g mod %g = %g [%g]\n",
+                                       SkFixedToFloat(numer), SkFixedToFloat(denom),
+                                       SkFixedToFloat(mod), m);
+#endif
+                       SkASSERT(mod == 0 || (mod < 0) == (m < 0)); // ensure the same sign
+                       int diff = SkAbs32(mod - SkFloatToFixed(m));
+                       SkASSERT((diff >> 7) == 0);
+               }
+#endif
+       }
+#endif
+
+#ifdef SK_CAN_USE_FLOAT
+       for (i = 0; i < 100000; i++)
+       {
+               SkFract x = rand.nextU() >> 1;
+               double xx = (double)x / SK_Fract1;
+               SkFract xr = SkFractSqrt(x);
+               SkFract check = SkFloatToFract(sqrt(xx));
+               SkASSERT(xr == check || xr == check-1 || xr == check+1);
+
+               xr = SkFixedSqrt(x);
+               xx = (double)x / SK_Fixed1;
+               check = SkFloatToFixed(sqrt(xx));
+               SkASSERT(xr == check || xr == check-1);
+
+               xr = SkSqrt32(x);
+               xx = (double)x;
+               check = (int32_t)sqrt(xx);
+               SkASSERT(xr == check || xr == check-1);
+       }
+#endif
+
+#if !defined(SK_SCALAR_IS_FLOAT) && defined(SK_CAN_USE_FLOAT)
+       int maxDiff = 0;
+       for (i = 0; i < 10000; i++)
+       {
+               SkFixed rads = rand.nextS() >> 10;
+               double frads = SkFixedToFloat(rads);
+
+               SkFixed s, c;
+               s = SkScalarSinCos(rads, &c);
+
+               double fs = sin(frads);
+               double fc = cos(frads);
+
+               SkFixed is = SkFloatToFixed(fs);
+               SkFixed ic = SkFloatToFixed(fc);
+
+               maxDiff = SkMax32(maxDiff, SkAbs32(is - s));
+               maxDiff = SkMax32(maxDiff, SkAbs32(ic - c));
+       }
+       SkDebugf("SinCos: maximum error = %d\n", maxDiff);
+#endif
+#endif
+}
+
+#endif
+
diff --git a/libs/corecg/SkMatrix.cpp b/libs/corecg/SkMatrix.cpp
new file mode 100644 (file)
index 0000000..f510e9f
--- /dev/null
@@ -0,0 +1,1220 @@
+#include "SkMatrix.h"
+#include "Sk64.h"
+
+#ifdef SK_SCALAR_IS_FLOAT
+       #define kMatrix22Elem   SK_Scalar1
+#else
+       #define kMatrix22Elem   SK_Fract1
+#endif
+
+/*             [scale-x        skew-x          trans-x]   [X]   [X']
+               [skew-y         scale-y         trans-y] * [Y] = [Y']
+               [persp-0        persp-1         persp-2]   [1]   [1 ]
+*/
+
+enum {
+       kMScaleX,
+       kMSkewX,
+       kMTransX,
+       kMSkewY,
+       kMScaleY,
+       kMTransY,
+       kMPersp0,
+       kMPersp1,
+       kMPersp2
+};
+
+void SkMatrix::reset()
+{
+       fMat[kMScaleX] = fMat[kMScaleY] = SK_Scalar1;
+       fMat[kMSkewX]  = fMat[kMSkewY] = 
+       fMat[kMTransX] = fMat[kMTransY] =
+       fMat[kMPersp0] = fMat[kMPersp1] = 0;
+       fMat[kMPersp2] = kMatrix22Elem;
+}
+
+static inline int has_perspective(const SkScalar mat[9])
+{
+#ifdef SK_SCALAR_IS_FLOAT
+       return mat[kMPersp0] || mat[kMPersp1] || mat[kMPersp2] != kMatrix22Elem;
+#else
+       return mat[kMPersp0] | mat[kMPersp1] | (mat[kMPersp2] - kMatrix22Elem);
+#endif
+}
+
+SkMatrix::TypeMask SkMatrix::getType() const
+{
+       unsigned type = 0;
+
+       type |= (fMat[kMPersp0] || fMat[kMPersp1] || fMat[kMPersp2] != kMatrix22Elem) << kPerspective_Shift;
+       type |= (fMat[kMSkewX] || fMat[kMSkewY]) << kAffine_Shift;
+       type |= (fMat[kMScaleX] != SK_Scalar1 || fMat[kMScaleY] != SK_Scalar1) << kScale_Shift;
+       type |= (fMat[kMTransX] || fMat[kMTransY]) << kTranslate_Shift;
+
+       return (TypeMask)type;
+}
+
+static inline bool is_identity(const SkScalar fMat[9])
+{
+#ifdef SK_SCALAR_IS_FLOAT
+       return  fMat[kMPersp0] == 0 && fMat[kMPersp1] == 0 && fMat[kMPersp2] == kMatrix22Elem &&
+                       fMat[kMSkewX] == 0 && fMat[kMSkewY] == 0 && fMat[kMTransX] == 0 && fMat[kMTransY] == 0 &&
+                       fMat[kMScaleX] == SK_Scalar1 && fMat[kMScaleY] == SK_Scalar1;
+#else
+       return  !(fMat[kMPersp0] | fMat[kMPersp1] | (fMat[kMPersp2] - kMatrix22Elem) |
+                         fMat[kMSkewX] | fMat[kMSkewY] | fMat[kMTransX] | fMat[kMTransY] |
+                         (fMat[kMScaleX] - SK_Scalar1) | (fMat[kMScaleY] - SK_Scalar1));
+#endif
+}
+
+bool SkMatrix::isIdentity() const
+{
+       return is_identity(fMat);
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void SkMatrix::setTranslate(SkScalar dx, SkScalar dy)
+{
+       fMat[kMTransX] = dx;
+       fMat[kMTransY] = dy;
+
+       fMat[kMScaleX] = fMat[kMScaleY] = SK_Scalar1;
+       fMat[kMSkewX]  = fMat[kMSkewY] = 
+       fMat[kMPersp0] = fMat[kMPersp1] = 0;
+       fMat[kMPersp2] = kMatrix22Elem;
+}
+
+bool SkMatrix::preTranslate(SkScalar dx, SkScalar dy)
+{
+       if (has_perspective(fMat))
+       {
+               SkMatrix        m;
+               m.setTranslate(dx, dy);
+               return this->preConcat(m);
+       }
+       else
+       {
+               fMat[kMTransX] += SkScalarMul(fMat[kMScaleX], dx) + SkScalarMul(fMat[kMSkewX], dy);
+               fMat[kMTransY] += SkScalarMul(fMat[kMSkewY], dx) + SkScalarMul(fMat[kMScaleY], dy);
+               return true;
+       }
+}
+
+bool SkMatrix::postTranslate(SkScalar dx, SkScalar dy)
+{
+       if (has_perspective(fMat))
+       {
+               SkMatrix        m;
+               m.setTranslate(dx, dy);
+               return this->postConcat(m);
+       }
+       else
+       {
+               fMat[kMTransX] += dx;
+               fMat[kMTransY] += dy;
+               return true;
+       }
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
+{
+       fMat[kMScaleX] = sx;
+       fMat[kMScaleY] = sy;
+       fMat[kMTransX] = px - SkScalarMul(sx, px);
+       fMat[kMTransY] = py - SkScalarMul(sy, py);
+
+       fMat[kMSkewX]  = fMat[kMSkewY] = 
+       fMat[kMPersp0] = fMat[kMPersp1] = 0;
+       fMat[kMPersp2] = kMatrix22Elem;
+}
+
+bool SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
+{
+       SkMatrix        m;
+       m.setScale(sx, sy, px, py);
+       return this->preConcat(m);
+}
+
+bool SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
+{
+       SkMatrix        m;
+       m.setScale(sx, sy, px, py);
+       return this->postConcat(m);
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV, SkScalar px, SkScalar py)
+{
+       fMat[kMScaleX]  = cosV;
+       fMat[kMSkewX]   = -sinV;
+       fMat[kMTransX]  = SkScalarMul(sinV, py) + SkScalarMul(SK_Scalar1 - cosV, px);
+
+       fMat[kMSkewY]   = sinV;
+       fMat[kMScaleY]  = cosV;
+       fMat[kMTransY]  = SkScalarMul(-sinV, px) + SkScalarMul(SK_Scalar1 - cosV, py);
+
+       fMat[kMPersp0] = fMat[kMPersp1] = 0;
+       fMat[kMPersp2] = kMatrix22Elem;
+}
+
+void SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py)
+{
+       SkScalar sinV, cosV;
+       sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
+       this->setSinCos(sinV, cosV, px, py);
+}
+
+bool SkMatrix::preRotate(SkScalar degrees, SkScalar px, SkScalar py)
+{
+       SkMatrix        m;
+       m.setRotate(degrees, px, py);
+       return this->preConcat(m);
+}
+
+bool SkMatrix::postRotate(SkScalar degrees, SkScalar px, SkScalar py)
+{
+       SkMatrix        m;
+       m.setRotate(degrees, px, py);
+       return this->postConcat(m);
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
+{
+       fMat[kMScaleX]  = SK_Scalar1;
+       fMat[kMSkewX]   = sx;
+       fMat[kMTransX]  = SkScalarMul(-sx, py);
+
+       fMat[kMSkewY]   = sy;
+       fMat[kMScaleY]  = SK_Scalar1;
+       fMat[kMTransY]  = SkScalarMul(-sy, px);
+
+       fMat[kMPersp0] = fMat[kMPersp1] = 0;
+       fMat[kMPersp2] = kMatrix22Elem;
+}
+
+bool SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
+{
+       SkMatrix        m;
+       m.setSkew(sx, sy, px, py);
+       return this->preConcat(m);
+}
+
+bool SkMatrix::postSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
+{
+       SkMatrix        m;
+       m.setSkew(sx, sy, px, py);
+       return this->postConcat(m);
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+bool SkMatrix::setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit align)
+{
+       if (src.isEmpty())
+       {
+               this->reset();
+               return false;
+       }
+
+       if (dst.isEmpty())
+               memset(fMat, 0, 8 * sizeof(SkScalar));
+       else
+       {
+               SkScalar        tx, sx = SkScalarDiv(dst.width(), src.width());
+               SkScalar        ty, sy = SkScalarDiv(dst.height(), src.height());
+               bool            xLarger = false;
+
+               if (align != kFill_ScaleToFit)
+               {
+                       if (sx > sy)
+                       {
+                               xLarger = true;
+                               sx = sy;
+                       }
+                       else
+                               sy = sx;
+               }
+
+               tx = dst.fLeft - SkScalarMul(src.fLeft, sx);
+               ty = dst.fTop - SkScalarMul(src.fTop, sy);
+               if (align == kCenter_ScaleToFit || align == kEnd_ScaleToFit)
+               {
+                       SkScalar diff;
+
+                       if (xLarger)
+                               diff = dst.width() - SkScalarMul(src.width(), sy);
+                       else
+                               diff = dst.height() - SkScalarMul(src.height(), sy);
+
+                       if (align == kCenter_ScaleToFit)
+                               diff = SkScalarHalf(diff);
+
+                       if (xLarger)
+                               tx += diff;
+                       else
+                               ty += diff;
+               }
+
+               fMat[kMScaleX] = sx;
+               fMat[kMScaleY] = sy;
+               fMat[kMTransX] = tx;
+               fMat[kMTransY] = ty;
+               fMat[kMSkewX]  = fMat[kMSkewY] = 
+               fMat[kMPersp0] = fMat[kMPersp1] = 0;
+       }
+       // shared cleanup
+       fMat[kMPersp2] = kMatrix22Elem;
+       return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_SCALAR_IS_FLOAT
+       static inline int fixmuladdmul(float a, float b, float c, float d, float* result)
+       {
+               *result = a * b + c * d;
+               return true;
+       }
+       static inline int fixmuladdmulshiftmul(float a, float b, float c, float d,
+                                                                                       int /*shift not used*/, float scale, float* result)
+       {
+               *result = (a * b + c * d) * scale;
+               return true;
+       }
+       static inline float rowcol3(const float row[], const float col[])
+       {
+               return row[0] * col[0] + row[1] * col[3] + row[2] * col[6];
+       }
+       static inline int negifaddoverflows(float& result, float a, float b)
+       {
+               result = a + b;
+               return 0;
+       }
+#else
+       static inline bool fixmuladdmul(SkFixed a, SkFixed b, SkFixed c, SkFixed d, SkFixed* result)
+       {
+               Sk64    tmp1, tmp2;
+               tmp1.setMul(a, b);
+               tmp2.setMul(c, d);
+               tmp1.add(tmp2);
+               if (tmp1.isFixed())
+               {
+                       *result = tmp1.getFixed();
+                       return true;
+               }
+               return false;
+       }
+       static inline bool fixmuladdmulshiftmul(SkFixed a, SkFixed b, SkFixed c, SkFixed d,
+                                                                                       int shift, SkFixed scale, SkFixed* result)
+       {
+               Sk64    tmp1, tmp2;
+               tmp1.setMul(a, b);
+               tmp2.setMul(c, d);
+               tmp1.add(tmp2);
+
+               S32     hi = SkAbs32(tmp1.fHi);
+               int     afterShift = 16;
+               if (hi >> 15)
+               {
+                       int clz = 17 - SkCLZ(hi);
+                       SkASSERT(clz > 0 && clz <= 16);
+                       afterShift -= clz;
+                       shift += clz;
+               }
+
+               tmp1.roundRight(shift + 16);
+               SkASSERT(tmp1.is32());
+
+               tmp1.setMul(tmp1.get32(), scale);
+               tmp1.roundRight(afterShift);
+               if (tmp1.is32())
+               {
+                       *result = tmp1.get32();
+                       return true;
+               }
+               return false;
+       }
+       static inline SkFixed fracmuladdmul(SkFixed a, SkFract b, SkFixed c, SkFract d)
+       {
+               Sk64    tmp1, tmp2;
+               tmp1.setMul(a, b);
+               tmp2.setMul(c, d);
+               tmp1.add(tmp2);
+               return tmp1.getFract();
+       }
+
+       static inline SkFixed rowcol3(const SkFixed row[], const SkFixed col[])
+       {
+               Sk64    tmp1, tmp2;
+
+               tmp1.setMul(row[0], col[0]);    // N * fixed
+               tmp2.setMul(row[1], col[3]);    // N * fixed
+               tmp1.add(tmp2);
+
+               tmp2.setMul(row[2], col[6]);    // N * fract
+               tmp2.roundRight(14);                    // make it fixed
+               tmp1.add(tmp2);
+
+               return tmp1.getFixed();
+       }
+       static inline int negifaddoverflows(SkFixed& result, SkFixed a, SkFixed b)
+       {
+               SkFixed c = a + b;
+               result = c;
+               SkASSERT(((c ^ a) & (c ^ b)) >= 0);
+               return (c ^ a) & (c ^ b);
+       }
+#endif
+
+static void normalize_perspective(SkScalar mat[9])
+{
+       if (SkScalarAbs(mat[kMPersp2]) > kMatrix22Elem)
+       {
+               for (int i = 0; i < 9; i++)
+                       mat[i] = SkScalarHalf(mat[i]);
+       }
+}
+
+bool SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b)
+{
+       TypeMask        aType = a.getType();
+       TypeMask        bType = b.getType();
+
+       if (aType == kIdentity_Mask)
+               *this = b;
+       else if (bType == kIdentity_Mask)
+               *this = a;
+       else
+       {
+               SkMatrix        tmp;
+               SkMatrix*       c = this;
+
+               if (this == &a || this == &b)
+                       c = &tmp;
+
+               if ((aType | bType) & kPerspective_Mask)
+               {
+                       c->fMat[kMScaleX] = rowcol3(&a.fMat[0], &b.fMat[0]);
+                       c->fMat[kMSkewX]  = rowcol3(&a.fMat[0], &b.fMat[1]);
+                       c->fMat[kMTransX] = rowcol3(&a.fMat[0], &b.fMat[2]);
+
+                       c->fMat[kMSkewY]  = rowcol3(&a.fMat[3], &b.fMat[0]);
+                       c->fMat[kMScaleY] = rowcol3(&a.fMat[3], &b.fMat[1]);
+                       c->fMat[kMTransY] = rowcol3(&a.fMat[3], &b.fMat[2]);
+
+                       c->fMat[kMPersp0] = rowcol3(&a.fMat[6], &b.fMat[0]);
+                       c->fMat[kMPersp1] = rowcol3(&a.fMat[6], &b.fMat[1]);
+                       c->fMat[kMPersp2] = rowcol3(&a.fMat[6], &b.fMat[2]);
+
+                       normalize_perspective(c->fMat);
+               }
+               else    // not perspective
+               {
+                       if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMScaleX], a.fMat[kMSkewX], b.fMat[kMSkewY], &c->fMat[kMScaleX]))
+                               return false;
+                       if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMSkewX], a.fMat[kMSkewX], b.fMat[kMScaleY], &c->fMat[kMSkewX]))
+                               return false;
+                       if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMTransX], a.fMat[kMSkewX], b.fMat[kMTransY], &c->fMat[kMTransX]))
+                               return false;
+                       if (negifaddoverflows(c->fMat[kMTransX], c->fMat[kMTransX], a.fMat[kMTransX]) < 0)
+                               return false;
+
+                       if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMScaleX], a.fMat[kMScaleY], b.fMat[kMSkewY], &c->fMat[kMSkewY]))
+                               return false;
+                       if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMSkewX], a.fMat[kMScaleY], b.fMat[kMScaleY], &c->fMat[kMScaleY]))
+                               return false;
+                       if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMTransX], a.fMat[kMScaleY], b.fMat[kMTransY], &c->fMat[kMTransY]))
+                               return false;
+                       if (negifaddoverflows(c->fMat[kMTransY], c->fMat[kMTransY], a.fMat[kMTransY]) < 0)
+                               return false;
+
+                       c->fMat[kMPersp0] = c->fMat[kMPersp1] = 0;
+                       c->fMat[kMPersp2] = kMatrix22Elem;
+               }
+
+               if (c == &tmp)
+                       *this = tmp;
+       }
+       return true;
+}
+
+bool SkMatrix::preConcat(const SkMatrix& mat)
+{
+       return this->setConcat(*this, mat);
+}
+
+bool SkMatrix::postConcat(const SkMatrix& mat)
+{
+       return this->setConcat(mat, *this);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_SCALAR_IS_FLOAT
+       #define SkPerspMul(a, b)                        SkScalarMul(a, b)
+       #define SkScalarMulShift(a, b, s)       SkScalarMul(a, b)
+       static float sk_inv_determinant(const float mat[9], int isPerspective, int* /* (only used in Fixed case) */)
+       {
+               double det;
+
+               if (isPerspective)
+                       det =   mat[kMScaleX] * ((double)mat[kMScaleY] * mat[kMPersp2] - (double)mat[kMTransY] * mat[kMPersp1]) +
+                                       mat[kMSkewX] * ((double)mat[kMTransY] * mat[kMPersp0] - (double)mat[kMSkewY] * mat[kMPersp2]) +
+                                       mat[kMTransX] * ((double)mat[kMSkewY] * mat[kMPersp1] - (double)mat[kMScaleY] * mat[kMPersp0]);
+               else
+                       det =   (double)mat[kMScaleX] * mat[kMScaleY] - (double)mat[kMSkewX] * mat[kMSkewY];
+
+               if (SkScalarNearlyZero((float)det))
+                       return 0;
+               return (float)(1.0 / det);
+       }
+#else
+       #define SkPerspMul(a, b)        SkFractMul(a, b)
+       #define SkScalarMulShift(a, b, s)       SkMulShift(a, b, s)
+       static void set_muladdmul(Sk64* dst, S32 a, S32 b, S32 c, S32 d)
+       {
+               Sk64    tmp;
+
+               dst->setMul(a, b);
+               tmp.setMul(c, d);
+               dst->add(tmp);
+       }
+       static SkFixed sk_inv_determinant(const SkFixed mat[9], int isPerspective, int* shift)
+       {
+               Sk64    tmp1, tmp2;
+
+               if (isPerspective)
+               {
+                       tmp1.setMul(mat[kMScaleX], fracmuladdmul(mat[kMScaleY], mat[kMPersp2], -mat[kMTransY], mat[kMPersp1]));
+                       tmp2.setMul(mat[kMSkewX], fracmuladdmul(mat[kMTransY], mat[kMPersp0], -mat[kMSkewY], mat[kMPersp2]));
+                       tmp1.add(tmp2);
+                       tmp2.setMul(mat[kMTransX], fracmuladdmul(mat[kMSkewY], mat[kMPersp1], -mat[kMScaleY], mat[kMPersp0]));
+                       tmp1.add(tmp2);
+               }
+               else
+               {
+                       tmp1.setMul(mat[kMScaleX], mat[kMScaleY]);
+                       tmp2.setMul(mat[kMSkewX], mat[kMSkewY]);
+                       tmp1.sub(tmp2);
+               }
+
+               int     s = tmp1.getClzAbs();
+               *shift = s;
+
+               SkFixed denom;
+               if (s <= 32)
+                       denom = tmp1.getShiftRight(33 - s);
+               else
+                       denom = (S32)tmp1.fLo << (s - 33);
+
+               if (denom == 0)
+                       return 0;
+               /**     This could perhaps be a special fractdiv function, since both of its
+                       arguments are known to have bit 31 clear and bit 30 set (when they
+                       are made positive), thus eliminating the need for calling clz()
+               */
+               return SkFractDiv(SK_Fract1, denom);
+       }
+#endif
+
+bool SkMatrix::invert(SkMatrix* inv) const
+{
+       int                     isPersp = has_perspective(fMat);
+       int                     shift;
+       SkScalar        scale = sk_inv_determinant(fMat, isPersp, &shift);
+
+       if (scale == 0) // underflow
+               return false;
+
+       if (inv)
+       {
+               SkMatrix tmp;
+               if (inv == this)
+                       inv = &tmp;
+
+               if (isPersp)
+               {
+                       shift = 61 - shift;
+                       inv->fMat[kMScaleX] = SkScalarMulShift(SkPerspMul(fMat[kMScaleY], fMat[kMPersp2]) - SkPerspMul(fMat[kMTransY], fMat[kMPersp1]), scale, shift);
+                       inv->fMat[kMSkewX]  = SkScalarMulShift(SkPerspMul(fMat[kMTransX], fMat[kMPersp1]) - SkPerspMul(fMat[kMSkewX],  fMat[kMPersp2]), scale, shift);
+                       inv->fMat[kMTransX] = SkScalarMulShift(SkScalarMul(fMat[kMSkewX], fMat[kMTransY]) - SkScalarMul(fMat[kMTransX], fMat[kMScaleY]), scale, shift);
+
+                       inv->fMat[kMSkewY]  = SkScalarMulShift(SkPerspMul(fMat[kMTransY], fMat[kMPersp0]) - SkPerspMul(fMat[kMSkewY],   fMat[kMPersp2]), scale, shift);
+                       inv->fMat[kMScaleY] = SkScalarMulShift(SkPerspMul(fMat[kMScaleX], fMat[kMPersp2]) - SkPerspMul(fMat[kMTransX],  fMat[kMPersp0]), scale, shift);
+                       inv->fMat[kMTransY] = SkScalarMulShift(SkScalarMul(fMat[kMTransX], fMat[kMSkewY]) - SkScalarMul(fMat[kMScaleX], fMat[kMTransY]), scale, shift);
+
+                       inv->fMat[kMPersp0] = SkScalarMulShift(SkScalarMul(fMat[kMSkewY], fMat[kMPersp1]) - SkScalarMul(fMat[kMScaleY], fMat[kMPersp0]), scale, shift);                         
+                       inv->fMat[kMPersp1] = SkScalarMulShift(SkScalarMul(fMat[kMSkewX], fMat[kMPersp0]) - SkScalarMul(fMat[kMScaleX], fMat[kMPersp1]), scale, shift);
+                       inv->fMat[kMPersp2] = SkScalarMulShift(SkScalarMul(fMat[kMScaleX], fMat[kMScaleY]) - SkScalarMul(fMat[kMSkewX], fMat[kMSkewY]), scale, shift);
+#ifdef SK_SCALAR_IS_FIXED
+                       if (SkAbs32(inv->fMat[kMPersp2]) > SK_Fixed1)
+                       {
+                               Sk64    tmp;
+
+                               tmp.set(SK_Fract1);
+                               tmp.shiftLeft(16);
+                               tmp.div(inv->fMat[kMPersp2], Sk64::kRound_DivOption);
+
+                               SkFract scale = tmp.get32();
+
+                               for (int i = 0; i < 9; i++)
+                                       inv->fMat[i] = SkFractMul(inv->fMat[i], scale);
+                       }
+                       inv->fMat[kMPersp2] = SkFixedToFract(inv->fMat[kMPersp2]);
+#endif
+               }
+               else    // not perspective
+               {
+#ifdef SK_SCALAR_IS_FIXED
+                       Sk64    tx, ty;
+                       int             clzNumer;
+
+                       // check the 2x2 for overflow
+                       {
+                               S32     value = SkAbs32(fMat[kMScaleY]);
+                               value |= SkAbs32(fMat[kMSkewX]);
+                               value |= SkAbs32(fMat[kMScaleX]);
+                               value |= SkAbs32(fMat[kMSkewY]);
+                               clzNumer = SkCLZ(value);
+                               if (shift - clzNumer > 31)
+                                       return false;   // overflow
+                       }
+
+                       set_muladdmul(&tx, fMat[kMSkewX], fMat[kMTransY], -fMat[kMScaleY], fMat[kMTransX]);
+                       set_muladdmul(&ty, fMat[kMSkewY], fMat[kMTransX], -fMat[kMScaleX], fMat[kMTransY]);
+                       // check tx,ty for overflow
+                       clzNumer = SkCLZ(SkAbs32(tx.fHi) | SkAbs32(ty.fHi));
+                       if (shift - clzNumer > 14)
+                               return false;   // overflow
+
+                       int fixedShift = 61 - shift;
+                       int sk64shift = 44 - shift + clzNumer;
+
+                       inv->fMat[kMScaleX] = SkMulShift(fMat[kMScaleY], scale, fixedShift);
+                       inv->fMat[kMSkewX]  = SkMulShift(-fMat[kMSkewX], scale, fixedShift);
+                       inv->fMat[kMTransX] = SkMulShift(tx.getShiftRight(33 - clzNumer), scale, sk64shift);
+                               
+                       inv->fMat[kMSkewY]  = SkMulShift(-fMat[kMSkewY], scale, fixedShift);
+                       inv->fMat[kMScaleY] = SkMulShift(fMat[kMScaleX], scale, fixedShift);
+                       inv->fMat[kMTransY] = SkMulShift(ty.getShiftRight(33 - clzNumer), scale, sk64shift);
+#else
+                       inv->fMat[kMScaleX] = SkScalarMul(fMat[kMScaleY], scale);
+                       inv->fMat[kMSkewX] = SkScalarMul(-fMat[kMSkewX], scale);
+                       if (!fixmuladdmulshiftmul(fMat[kMSkewX], fMat[kMTransY], -fMat[kMScaleY], fMat[kMTransX], shift, scale, &inv->fMat[kMTransX]))
+                               return false;
+                               
+                       inv->fMat[kMSkewY] = SkScalarMul(-fMat[kMSkewY], scale);
+                       inv->fMat[kMScaleY] = SkScalarMul(fMat[kMScaleX], scale);
+                       if (!fixmuladdmulshiftmul(fMat[kMSkewY], fMat[kMTransX], -fMat[kMScaleX], fMat[kMTransY], shift, scale, &inv->fMat[kMTransY]))
+                               return false;
+#endif
+                       inv->fMat[kMPersp0] = 0;
+                       inv->fMat[kMPersp1] = 0;
+                       inv->fMat[kMPersp2] = kMatrix22Elem;
+               }
+
+               if (inv == &tmp)
+                       *(SkMatrix*)this = tmp;
+       }
+       return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+bool SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count, TypeMask typeMask) const
+{
+       SkASSERT(dst && src && count > 0 || count == 0);
+       SkASSERT(src == dst || SkAbs32((S32)(src - dst)) >= count);     // no partial overlap
+
+       if (count <= 0)
+               return true;
+
+       bool ok = true;
+
+       if (typeMask & kPerspective_Mask)
+       {
+#ifdef SK_SCALAR_IS_FIXED
+               SkFixed persp2 = SkFractToFixed(fMat[kMPersp2]);
+#endif
+               for (int i = count - 1; i >= 0; --i)
+               {
+                       SkScalar sx = src[i].fX;
+                       SkScalar sy = src[i].fY;
+                       SkScalar x = SkScalarMul(sx, fMat[kMScaleX]) + SkScalarMul(sy, fMat[kMSkewX]) + fMat[kMTransX];
+                       SkScalar y = SkScalarMul(sx, fMat[kMSkewY]) + SkScalarMul(sy, fMat[kMScaleY]) + fMat[kMTransY];
+#ifdef SK_SCALAR_IS_FIXED
+                       SkFixed z = SkFractMul(sx, fMat[kMPersp0]) + SkFractMul(sy, fMat[kMPersp1]) + persp2;
+#else
+                       float z = SkScalarMul(sx, fMat[kMPersp0]) + SkScalarMul(sy, fMat[kMPersp1]) + fMat[kMPersp2];
+#endif
+                       if (z)
+                               z = SkScalarInvert(z);
+                       dst[i].fX = SkScalarMul(x, z);
+                       dst[i].fY = SkScalarMul(y, z);
+               }
+       }
+       else if (typeMask & kAffine_Mask)
+       {
+               for (int i = count - 1; i >= 0; --i)
+               {
+                       SkScalar sx = src[i].fX;
+                       SkScalar sy = src[i].fY;
+                       dst[i].fX = SkScalarMul(sx, fMat[kMScaleX]) + SkScalarMul(sy, fMat[kMSkewX]) + fMat[kMTransX];
+                       dst[i].fY = SkScalarMul(sx, fMat[kMSkewY]) + SkScalarMul(sy, fMat[kMScaleY]) + fMat[kMTransY];
+               }
+       }
+       else if (typeMask & kScale_Mask)
+       {
+               for (int i = count - 1; i >= 0; --i)
+               {
+                       dst[i].fX = SkScalarMul(src[i].fX, fMat[kMScaleX]) + fMat[kMTransX];
+                       dst[i].fY = SkScalarMul(src[i].fY, fMat[kMScaleY]) + fMat[kMTransY];
+               }
+       }
+       else if (typeMask & kTranslate_Mask)
+       {
+               for (int i = count - 1; i >= 0; --i)
+               {
+                       dst[i].fX = src[i].fX + fMat[kMTransX];
+                       dst[i].fY = src[i].fY + fMat[kMTransY];
+               }
+       }
+       else
+       {
+               SkASSERT(typeMask == 0);
+               if (dst != src)
+                       memcpy(dst, src, count * sizeof(SkPoint));
+       }
+       return ok;
+}
+
+bool SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count, TypeMask maskType) const
+{
+       bool ok;
+
+       if (maskType & kPerspective_Mask)
+       {
+               SkPoint origin;
+
+               origin.set(0, 0);
+               ok = this->mapPoints(&origin, &origin, 1, maskType);
+
+               for (int i = count - 1; i >= 0; --i)
+               {
+                       SkPoint tmp;
+
+                       ok &= this->mapPoints(&tmp, &src[i], 1, maskType);
+                       dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY);
+               }
+       }
+       else
+       {
+               SkMatrix tmp = *this;
+
+               tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0;
+               ok = tmp.mapPoints(dst, src, count, maskType);
+       }
+       return ok;
+}
+
+bool SkMatrix::mapRect(SkRect* dst, const SkRect& src, TypeMask maskType) const
+{
+       SkASSERT(dst && &src);
+
+       bool ok;
+
+       if (RectStaysRect(maskType))
+       {
+               ok = this->mapPoints((SkPoint*)dst, (const SkPoint*)&src, 2, maskType);
+               dst->sort();
+       }
+       else
+       {
+               SkPoint quad[4];
+
+               src.toQuad(quad);
+               ok = this->mapPoints(quad, quad, 4, maskType);
+               dst->set(quad, 4);
+       }
+       return ok;
+}
+
+SkScalar SkMatrix::mapRadius(SkScalar radius) const
+{
+       SkVector        vec[2];
+
+       vec[0].set(radius, 0);
+       vec[1].set(0, radius);
+       this->mapVectors(vec, 2);
+
+       SkScalar d0 = vec[0].length();
+       SkScalar d1 = vec[1].length();
+
+       return SkScalarMean(d0, d1);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void SkMatrix::Perspective_ptProc(const SkMatrix& m, SkScalar sx, SkScalar sy, SkPoint* pt)
+{
+       SkASSERT(m.getType() & kPerspective_Mask);
+
+       SkScalar x = SkScalarMul(sx, m.fMat[kMScaleX]) + SkScalarMul(sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
+       SkScalar y = SkScalarMul(sx, m.fMat[kMSkewY]) + SkScalarMul(sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
+#ifdef SK_SCALAR_IS_FIXED
+       SkFixed z = SkFractMul(sx, m.fMat[kMPersp0]) + SkFractMul(sy, m.fMat[kMPersp1]) + SkFractToFixed(m.fMat[kMPersp2]);
+#else
+       float z = SkScalarMul(sx, m.fMat[kMPersp0]) + SkScalarMul(sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
+#endif
+       if (z)
+               z = SkScalarInvert(z);
+       pt->fX = SkScalarMul(x, z);
+       pt->fY = SkScalarMul(y, z);
+}
+
+#ifdef SK_SCALAR_IS_FIXED
+static SkFixed fixmuladdmul(SkFixed a, SkFixed b, SkFixed c, SkFixed d)
+{
+       Sk64    tmp, tmp1;
+
+       tmp.setMul(a, b);
+       tmp1.setMul(c, d);
+       return tmp.addGetFixed(tmp1);
+//     tmp.add(tmp1);
+//     return tmp.getFixed();
+}
+#endif
+
+void SkMatrix::Affine_ptProc(const SkMatrix& m, SkScalar sx, SkScalar sy, SkPoint* pt)
+{
+       SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask);
+
+#ifdef SK_SCALAR_IS_FIXED
+       pt->fX = fixmuladdmul(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
+       pt->fY = fixmuladdmul(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
+#else
+       pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]) + SkScalarMul(sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
+       pt->fY = SkScalarMul(sx, m.fMat[kMSkewY]) + SkScalarMul(sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
+#endif
+}
+
+void SkMatrix::Scale_ptProc(const SkMatrix& m, SkScalar sx, SkScalar sy, SkPoint* pt)
+{
+       SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask)) == kScale_Mask);
+
+       pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]) + m.fMat[kMTransX];
+       pt->fY = SkScalarMul(sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
+}
+
+void SkMatrix::Translate_ptProc(const SkMatrix& m, SkScalar sx, SkScalar sy, SkPoint* pt)
+{
+       SkASSERT(m.getType() == kTranslate_Mask);
+
+       pt->fX = sx + m.fMat[kMTransX];
+       pt->fY = sy + m.fMat[kMTransY];
+}
+
+void SkMatrix::Identity_ptProc(const SkMatrix& m, SkScalar sx, SkScalar sy, SkPoint* pt)
+{
+       SkASSERT(m.getType() == kIdentity_Mask);
+
+       pt->fX = sx;
+       pt->fY = sy;
+}
+
+SkMatrix::MapPtProc SkMatrix::getMapPtProc() const
+{
+       TypeMask typeMask = this->getType();
+
+       if (typeMask & kPerspective_Mask)
+               return Perspective_ptProc;
+       if (typeMask & kAffine_Mask)
+               return Affine_ptProc;
+       if (typeMask & kScale_Mask)
+               return Scale_ptProc;
+       if (typeMask & kTranslate_Mask)
+               return Translate_ptProc;
+       return Identity_ptProc;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// if its nearly zero (just made up 24 for that, perhaps it should be bigger or smaller)
+#ifdef SK_SCALAR_IS_FIXED
+       typedef SkFract                         SkPerspElemType;
+       #define PerspNearlyZero(x)      (SkAbs32(x) < (SK_Fract1 >> 26))
+#else
+       typedef float                           SkPerspElemType;
+       #define PerspNearlyZero(x)      SkScalarNearlyZero(x, (1.0f / (1 << 26)))
+#endif
+
+bool SkMatrix::fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const
+{
+       if (PerspNearlyZero(fMat[kMPersp0]))
+       {
+               if (stepX || stepY)
+               {
+                       if (PerspNearlyZero(fMat[kMPersp1]) && PerspNearlyZero(fMat[kMPersp2] - kMatrix22Elem))
+                       {
+                               if (stepX)
+                                       *stepX = SkScalarToFixed(fMat[kMScaleX]);
+                               if (stepY)
+                                       *stepY = SkScalarToFixed(fMat[kMSkewY]);
+                       }
+                       else
+                       {
+#ifdef SK_SCALAR_IS_FIXED
+                               SkFixed z = SkFractMul(y, fMat[kMPersp1]) + SkFractToFixed(fMat[kMPersp2]);
+#else
+                               float z = y * fMat[kMPersp1] + fMat[kMPersp2];
+#endif
+                               if (stepX)
+                                       *stepX = SkScalarToFixed(SkScalarDiv(fMat[kMScaleX], z));
+                               if (stepY)
+                                       *stepY = SkScalarToFixed(SkScalarDiv(fMat[kMSkewY], z));
+                       }
+               }
+               return true;
+       }
+       return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_SCALAR_IS_FIXED
+
+static inline void poly_to_point(SkPoint* pt, const SkPoint poly[], int count)
+{
+       SkFixed x = SK_Fixed1, y = SK_Fixed1;
+       SkPoint pt1, pt2;
+       Sk64    w1, w2;
+
+       if (count > 1)
+       {       pt1.fX = poly[1].fX - poly[0].fX;
+               pt1.fY = poly[1].fY - poly[0].fY;
+               y = SkPoint::Length(pt1.fX, pt1.fY);
+               switch (count) {
+               case 2:
+                       break;
+               case 3:
+                       pt2.fX = poly[0].fY - poly[2].fY;
+                       pt2.fY = poly[2].fX - poly[0].fX;
+                       goto CALC_X;
+               default:
+                       pt2.fX = poly[0].fY - poly[3].fY;
+                       pt2.fY = poly[3].fX - poly[0].fX;
+               CALC_X:
+                       w1.setMul(pt1.fX, pt2.fX);
+                       w2.setMul(pt1.fY, pt2.fY);
+                       w1.add(w2);
+                       w1.div(y, Sk64::kRound_DivOption);
+                       x = w1.get32();
+                       break;
+               }
+       }
+       pt->set(x, y);
+}
+
+static inline void Map1Pt(const SkPoint source[], SkMatrix* dst)
+{
+       dst->setTranslate(source[0].fX, source[0].fY);
+}
+
+void SkMatrix::Map2Pt(const SkPoint srcPt[], SkMatrix* dst, SkFixed scale)
+{
+       dst->fMat[kMScaleX] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale);
+       dst->fMat[kMSkewY]  = SkFixedDiv(srcPt[0].fX - srcPt[1].fX, scale);
+       dst->fMat[kMPersp0] = 0;
+       dst->fMat[kMSkewX]  = SkFixedDiv(srcPt[1].fX - srcPt[0].fX, scale);
+       dst->fMat[kMScaleY] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale);
+       dst->fMat[kMPersp1] = 0;
+       dst->fMat[kMTransX] = srcPt[0].fX;
+       dst->fMat[kMTransY] = srcPt[0].fY;
+       dst->fMat[kMPersp2] = SK_Fract1;
+}
+
+void SkMatrix::Map3Pt(const SkPoint srcPt[], SkMatrix* dst, SkFixed scaleX, SkFixed scaleY)
+{
+       dst->fMat[kMScaleX] = SkFixedDiv(srcPt[2].fX - srcPt[0].fX, scaleX);
+       dst->fMat[kMSkewY]  = SkFixedDiv(srcPt[2].fY - srcPt[0].fY, scaleX);
+       dst->fMat[kMPersp0] = 0;
+       dst->fMat[kMSkewX]  = SkFixedDiv(srcPt[1].fX - srcPt[0].fX, scaleY);
+       dst->fMat[kMScaleY] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scaleY);
+       dst->fMat[kMPersp1] = 0;
+       dst->fMat[kMTransX] = srcPt[0].fX;
+       dst->fMat[kMTransY] = srcPt[0].fY;
+       dst->fMat[kMPersp2] = SK_Fract1;
+}
+
+void SkMatrix::Map4Pt(const SkPoint srcPt[], SkMatrix* dst, SkFixed scaleX, SkFixed scaleY)
+{
+       SkFract a1, a2;
+       SkFixed x0, y0, x1, y1, x2, y2;
+
+       x0 = srcPt[2].fX - srcPt[0].fX;
+       y0 = srcPt[2].fY - srcPt[0].fY;
+       x1 = srcPt[2].fX - srcPt[1].fX;
+       y1 = srcPt[2].fY - srcPt[1].fY;
+       x2 = srcPt[2].fX - srcPt[3].fX;
+       y2 = srcPt[2].fY - srcPt[3].fY;
+
+       /* check if abs(x2) > abs(y2) */
+       if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2)
+               a1 = SkFractDiv(SkMulDiv(x0 - x1, y2, x2) - y0 + y1, SkMulDiv(x1, y2, x2) - y1);
+       else
+               a1 = SkFractDiv(x0 - x1 - SkMulDiv(y0 - y1, x2, y2), x1 - SkMulDiv(y1, x2, y2));
+
+       /* check if abs(x1) > abs(y1) */
+       if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1)
+               a2 = SkFractDiv(y0 - y2 - SkMulDiv(x0 - x2, y1, x1), y2 - SkMulDiv(x2, y1, x1));
+       else
+               a2 = SkFractDiv(SkMulDiv(y0 - y2, x1, y1) - x0 + x2, SkMulDiv(y2, x1, y1) - x2);
+
+       dst->fMat[kMScaleX] = SkFixedDiv(SkFractMul(a2, srcPt[3].fX) + srcPt[3].fX - srcPt[0].fX, scaleX);
+       dst->fMat[kMSkewY]  = SkFixedDiv(SkFractMul(a2, srcPt[3].fY) + srcPt[3].fY - srcPt[0].fY, scaleX);
+       dst->fMat[kMPersp0] = SkFixedDiv(a2, scaleX);
+       dst->fMat[kMSkewX]  = SkFixedDiv(SkFractMul(a1, srcPt[1].fX) + srcPt[1].fX - srcPt[0].fX, scaleY);
+       dst->fMat[kMScaleY] = SkFixedDiv(SkFractMul(a1, srcPt[1].fY) + srcPt[1].fY - srcPt[0].fY, scaleY);
+       dst->fMat[kMPersp1] = SkFixedDiv(a1, scaleY);
+       dst->fMat[kMTransX] = srcPt[0].fX;
+       dst->fMat[kMTransY] = srcPt[0].fY;
+       dst->fMat[kMPersp2] = SK_Fract1;
+}
+
+#else  /* Scalar is float */
+
+static inline void poly_to_point(SkPoint* pt, const SkPoint poly[], int count)
+{
+       float   x = 1, y = 1;
+       SkPoint pt1, pt2;
+
+       if (count > 1)
+       {       pt1.fX = poly[1].fX - poly[0].fX;
+               pt1.fY = poly[1].fY - poly[0].fY;
+               y = SkPoint::Length(pt1.fX, pt1.fY);
+               switch (count) {
+               case 2:
+                       break;
+               case 3:
+                       pt2.fX = poly[0].fY - poly[2].fY;
+                       pt2.fY = poly[2].fX - poly[0].fX;
+                       goto CALC_X;
+               default:
+                       pt2.fX = poly[0].fY - poly[3].fY;
+                       pt2.fY = poly[3].fX - poly[0].fX;
+               CALC_X:
+                       x = SkScalarDiv(SkScalarMul(pt1.fX, pt2.fX) + SkScalarMul(pt1.fY, pt2.fY), y);
+                       break;
+               }
+       }
+       pt->set(x, y);
+}
+
+static inline void Map1Pt(const SkPoint source[], SkMatrix* dst)
+{
+       dst->setTranslate(source[0].fX, source[0].fY);
+}
+
+void SkMatrix::Map2Pt(const SkPoint srcPt[], SkMatrix* dst, float scale)
+{
+       float invScale = 1 / scale;
+
+       dst->fMat[kMScaleX] = (srcPt[1].fY - srcPt[0].fY) * invScale;
+       dst->fMat[kMSkewY] = (srcPt[0].fX - srcPt[1].fX) * invScale;
+       dst->fMat[kMPersp0] = 0;
+       dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
+       dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
+       dst->fMat[kMPersp1] = 0;
+       dst->fMat[kMTransX] = srcPt[0].fX;
+       dst->fMat[kMTransY] = srcPt[0].fY;
+       dst->fMat[kMPersp2] = 1;
+}
+
+void SkMatrix::Map3Pt(const SkPoint srcPt[], SkMatrix* dst, float scaleX, float scaleY)
+{
+       float invScale = 1 / scaleX;
+
+       dst->fMat[kMScaleX] = (srcPt[2].fX - srcPt[0].fX) * invScale;
+       dst->fMat[kMSkewY] = (srcPt[2].fY - srcPt[0].fY) * invScale;
+       dst->fMat[kMPersp0] = 0;
+       invScale = 1 / scaleY;
+       dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
+       dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
+       dst->fMat[kMPersp1] = 0;
+       dst->fMat[kMTransX] = srcPt[0].fX;
+       dst->fMat[kMTransY] = srcPt[0].fY;
+       dst->fMat[kMPersp2] = 1;
+}
+
+void SkMatrix::Map4Pt(const SkPoint srcPt[], SkMatrix* dst, float scaleX, float scaleY)
+{
+       float   a1, a2;
+       float   x0, y0, x1, y1, x2, y2;
+
+       x0 = srcPt[2].fX - srcPt[0].fX;
+       y0 = srcPt[2].fY - srcPt[0].fY;
+       x1 = srcPt[2].fX - srcPt[1].fX;
+       y1 = srcPt[2].fY - srcPt[1].fY;
+       x2 = srcPt[2].fX - srcPt[3].fX;
+       y2 = srcPt[2].fY - srcPt[3].fY;
+
+       /* check if abs(x2) > abs(y2) */
+       if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2)
+               a1 = SkScalarDiv(SkScalarMulDiv(x0 - x1, y2, x2) - y0 + y1, SkScalarMulDiv(x1, y2, x2) - y1);
+       else
+               a1 = SkScalarDiv(x0 - x1 - SkScalarMulDiv(y0 - y1, x2, y2), x1 - SkScalarMulDiv(y1, x2, y2));
+
+       /* check if abs(x1) > abs(y1) */
+       if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1)
+               a2 = SkScalarDiv(y0 - y2 - SkScalarMulDiv(x0 - x2, y1, x1), y2 - SkScalarMulDiv(x2, y1, x1));
+       else
+               a2 = SkScalarDiv(SkScalarMulDiv(y0 - y2, x1, y1) - x0 + x2, SkScalarMulDiv(y2, x1, y1) - x2);
+
+       scaleX = 1 / scaleX;
+       dst->fMat[kMScaleX] = SkScalarMul(SkScalarMul(a2, srcPt[3].fX) + srcPt[3].fX - srcPt[0].fX, scaleX);
+       dst->fMat[kMSkewY] = SkScalarMul(SkScalarMul(a2, srcPt[3].fY) + srcPt[3].fY - srcPt[0].fY, scaleX);
+       dst->fMat[kMPersp0] = SkScalarMul(a2, scaleX);
+       scaleY = 1 / scaleY;
+       dst->fMat[kMSkewX] = SkScalarMul(SkScalarMul(a1, srcPt[1].fX) + srcPt[1].fX - srcPt[0].fX, scaleY);
+       dst->fMat[kMScaleY] = SkScalarMul(SkScalarMul(a1, srcPt[1].fY) + srcPt[1].fY - srcPt[0].fY, scaleY);
+       dst->fMat[kMPersp1] = SkScalarMul(a1, scaleY);
+       dst->fMat[kMTransX] = srcPt[0].fX;
+       dst->fMat[kMTransY] = srcPt[0].fY;
+       dst->fMat[kMPersp2] = 1;
+}
+
+#endif
+
+/*     Taken from Rob Johnson's original sample code in QuickDraw GX
+*/
+bool SkMatrix::setPolyToPoly(const SkPoint dst[], const SkPoint src[], int count)
+{
+       SkASSERT((unsigned)count <= 4);
+
+       SkPoint         tempPt;
+       SkMatrix        tempMap;
+
+       poly_to_point(&tempPt, src, count);
+       switch (count) {
+       case 0:
+               this->reset();
+               break;
+       case 1:
+               this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY);
+               break;
+       case 2:
+               Map2Pt(src, &tempMap, tempPt.fY);
+               if (tempMap.invert(this) == false)
+                       return false;
+               Map2Pt(dst, &tempMap, tempPt.fY);
+               goto mapMap;
+       case 3:
+               Map3Pt(src, &tempMap, tempPt.fX, tempPt.fY);
+               if (tempMap.invert(this) == false)
+                       return false;
+               Map3Pt(dst, &tempMap, tempPt.fX, tempPt.fY);
+               goto mapMap;
+       default:
+               Map4Pt(src, &tempMap, tempPt.fX, tempPt.fY);
+               if (tempMap.invert(this) == false)
+                       return false;
+               Map4Pt(dst, &tempMap, tempPt.fX, tempPt.fY);
+       mapMap:
+               this->setConcat(tempMap, *this);
+               break;
+       }
+       return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+void SkMatrix::dump() const
+{
+       static const char* gTypeNames[] = {
+               "translate",
+               "scale",
+               "rotate",
+               "perspective"
+       };
+
+       SkDebugf("SkMatrix mask = ");
+       unsigned mask = this->getType();
+
+       if (mask == 0)
+               SkDebugf("identity\n");
+       else
+       {
+               for (int i = 0; i < kShiftCount; i++)
+               {
+                       if (mask & (1 << i))
+                               SkDebugf(" %s", gTypeNames[i]);
+               }
+               SkDebugf("\n");
+       }
+
+#ifdef SK_CAN_USE_FLOAT
+       SkDebugf("[%8.4f %8.4f %8.4f]\n[%8.4f %8.4f %8.4f]\n[%8.4f %8.4f %8.4f]\n",
+#ifdef SK_SCALAR_IS_FLOAT
+                       fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
+                       fMat[6], fMat[7], fMat[8]);
+#else
+                       SkFixedToFloat(fMat[0]), SkFixedToFloat(fMat[1]), SkFixedToFloat(fMat[2]),
+                       SkFixedToFloat(fMat[3]), SkFixedToFloat(fMat[4]), SkFixedToFloat(fMat[5]),
+                       SkFractToFloat(fMat[6]), SkFractToFloat(fMat[7]), SkFractToFloat(fMat[8]));
+#endif
+#else   // can't use float
+       SkDebugf("[%x %x %x]\n[%x %x %x]\n[%x %x %x]\n",
+                       fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
+                       fMat[6], fMat[7], fMat[8]);
+#endif
+}
+
+void SkMatrix::UnitTest()
+{
+#ifdef SK_SUPPORT_UNITTEST
+       SkMatrix        mat, inverse, iden1, iden2;
+
+       mat.reset();
+       mat.setTranslate(SK_Scalar1, SK_Scalar1);
+       mat.invert(&inverse);
+       inverse.dump();
+       iden1.setConcat(mat, inverse);
+       iden1.dump();
+
+       mat.setScale(SkIntToScalar(2), SkIntToScalar(2), 0, 0);
+       mat.invert(&inverse);
+       inverse.dump();
+       iden1.setConcat(mat, inverse);
+       iden1.dump();
+
+       mat.setScale(SK_Scalar1/2, SK_Scalar1/2, 0, 0);
+       mat.invert(&inverse);
+       inverse.dump();
+       iden1.setConcat(mat, inverse);
+       iden1.dump();
+
+       mat.setScale(SkIntToScalar(3), SkIntToScalar(5), SkIntToScalar(20), 0);
+       mat.postRotate(SkIntToScalar(25), 0, 0);
+
+       SkASSERT(mat.invert(nil));
+       mat.invert(&inverse);
+
+       iden1.setConcat(mat, inverse);
+       iden2.setConcat(inverse, mat);
+
+       iden1.dump();
+       iden2.dump();
+#endif
+}
+
+#endif
diff --git a/libs/corecg/SkMemory_stdlib.cpp b/libs/corecg/SkMemory_stdlib.cpp
new file mode 100644 (file)
index 0000000..5a03dac
--- /dev/null
@@ -0,0 +1,79 @@
+#include "SkTypes.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+void sk_throw()
+{
+#ifdef ANDROID
+    fprintf(stderr, "throwing...\n");
+#endif
+    abort();
+}
+
+void sk_out_of_memory(void)
+{
+#ifdef ANDROID
+    fprintf(stderr,"- out of memory in SGL -\n");
+#endif
+    abort();
+}
+
+void* sk_malloc_throw(size_t size)
+{
+       return sk_malloc_flags(size, SK_MALLOC_THROW);
+}
+
+void* sk_realloc_throw(void* addr, size_t size)
+{
+       SkDEBUGCODE(if (size) size += 4;)
+       SkDEBUGCODE(if (addr) addr = (char*)addr - 4;)
+
+       void* p = realloc(addr, size);
+       if (size == 0)
+               return p;
+
+       if (p == NULL)
+               sk_throw();
+#ifdef SK_DEBUG
+       else
+       {
+               memcpy(p, "skia", 4);
+               p = (char*)p + 4;
+       }
+#endif
+       return p;
+}
+
+void sk_free(void* p)
+{
+       if (p)
+       {
+#ifdef SK_DEBUG
+               SkDEBUGCODE(p = (char*)p - 4;)
+               SkASSERT(memcmp(p, "skia", 4) == 0);
+#endif
+               free(p);
+       }
+}
+
+void* sk_malloc_flags(size_t size, unsigned flags)
+{
+       SkDEBUGCODE(size += 4;)
+       
+       void* p = malloc(size);
+       if (p == NULL)
+       {
+               if (flags & SK_MALLOC_THROW)
+                       sk_throw();
+       }
+#ifdef SK_DEBUG
+       else
+       {
+               memcpy(p, "skia", 4);
+               p = (char*)p + 4;
+               memset(p, 0xCD, size - 4);
+       }
+#endif
+       return p;
+}
+
diff --git a/libs/corecg/SkPoint.cpp b/libs/corecg/SkPoint.cpp
new file mode 100644 (file)
index 0000000..b76c4b3
--- /dev/null
@@ -0,0 +1,238 @@
+#include "SkPoint.h"
+
+void SkPoint16::rotateCW(SkPoint16* dst) const
+{
+       SkASSERT(dst);
+
+       // use a tmp in case this == dst
+       S16 tmp = fX;
+       dst->fX = -fY;
+       dst->fY = tmp;
+}
+
+void SkPoint16::rotateCCW(SkPoint16* dst) const
+{
+       SkASSERT(dst);
+
+       // use a tmp in case this == dst
+       S16 tmp = fX;
+       dst->fX = fY;
+       dst->fY = -tmp;
+}
+
+/////////////////////////////////////////////////////////////////////
+
+void SkPoint::rotateCW(SkPoint* dst) const
+{
+       SkASSERT(dst);
+
+       // use a tmp in case this == dst
+       SkScalar tmp = fX;
+       dst->fX = -fY;
+       dst->fY = tmp;
+}
+
+void SkPoint::rotateCCW(SkPoint* dst) const
+{
+       SkASSERT(dst);
+
+       // use a tmp in case this == dst
+       SkScalar tmp = fX;
+       dst->fX = fY;
+       dst->fY = -tmp;
+}
+
+void SkPoint::scale(SkScalar scale, SkPoint* dst) const
+{
+       SkASSERT(dst);
+       dst->set(SkScalarMul(fX, scale), SkScalarMul(fY, scale));
+}
+
+#define kNearlyZero            (SK_Scalar1 / 8092)
+
+bool SkPoint::normalize()
+{
+       return this->setLength(fX, fY, SK_Scalar1);
+}
+
+bool SkPoint::setUnit(SkScalar x, SkScalar y)
+{
+       return this->setLength(x, y, SK_Scalar1);
+}
+
+bool SkPoint::setLength(SkScalar length)
+{
+       return this->setLength(fX, fY, length);
+}
+
+#ifdef SK_SCALAR_IS_FLOAT
+
+SkScalar SkPoint::Length(SkScalar dx, SkScalar dy)
+{
+       return sk_float_sqrt(dx * dx + dy * dy);
+}
+
+bool SkPoint::setLength(float x, float y, float length)
+{
+       float mag = sk_float_sqrt(x * x + y * y);
+       if (mag > kNearlyZero)
+       {
+               length /= mag;
+               fX = x * length;
+               fY = y * length;
+               return true;
+       }
+       return false;
+}
+
+#else
+
+#include "Sk64.h"
+
+SkScalar SkPoint::Length(SkScalar dx, SkScalar dy)
+{
+       Sk64    tmp1, tmp2;
+
+       tmp1.setMul(dx, dx);
+       tmp2.setMul(dy, dy);
+       tmp1.add(tmp2);
+
+       return tmp1.getSqrt();
+}
+
+#ifdef SK_DEBUGx
+static SkFixed fixlen(SkFixed x, SkFixed y)
+{
+       float fx = (float)x;
+       float fy = (float)y;
+
+       return (int)floorf(sqrtf(fx*fx + fy*fy) + 0.5f);
+}
+#endif
+
+static inline U32 squarefixed(unsigned x)
+{
+       x >>= 16;
+       return x*x;
+}
+
+/*
+       Normalize x,y, and then scale them by length.
+
+       The obvious way to do this would be the following:
+               S64     tmp1, tmp2;
+               tmp1.setMul(x,x);
+               tmp2.setMul(y,y);
+               tmp1.add(tmp2);
+               len = tmp1.getSqrt();
+               x' = SkFixedDiv(x, len);
+               y' = SkFixedDiv(y, len);
+       This is fine, but slower than what we do below.
+
+       The present technique does not compute the starting length, but
+       rather fiddles with x,y iteratively, all the while checking its
+       magnitude^2 (avoiding a sqrt).
+
+       We normalize by first shifting x,y so that at least one of them
+       has bit 31 set (after taking the abs of them).
+       Then we loop, refining x,y by squaring them and comparing
+       against a very large 1.0 (1 << 28), and then adding or subtracting
+       a delta (which itself is reduced by half each time through the loop).
+       For speed we want the squaring to be with a simple integer mul. To keep
+       that from overflowing we shift our coordinates down until we are dealing
+       with at most 15 bits (2^15-1)^2 * 2 says withing 32 bits)
+       When our square is close to 1.0, we shift x,y down into fixed range.
+*/
+bool SkPoint::setLength(SkFixed ox, SkFixed oy, SkFixed length)
+{
+       if (ox == 0)
+       {
+               if (oy == 0)
+                       return false;
+               this->set(0, SkApplySign(length, SkExtractSign(oy)));
+               return true;
+       }
+       if (oy == 0)
+       {
+               this->set(SkApplySign(length, SkExtractSign(ox)), 0);
+               return true;
+       }
+
+       SkFixed x = SkAbs32(ox);
+       SkFixed y = SkAbs32(oy);
+
+       // shift x,y so that the greater of them is 15bits (1.14 fixed point)
+       {
+               int shift = SkCLZ(x | y);
+               // make them .30
+               x <<= shift - 1;
+               y <<= shift - 1;
+       }
+
+       SkFixed dx = x;
+       SkFixed dy = y;
+
+       for (int i = 0; i < 17; i++)
+       {
+               dx >>= 1;
+               dy >>= 1;
+
+               U32 len2 = squarefixed(x) + squarefixed(y);
+               if (len2 >> 28)
+               {
+                       x -= dx;
+                       y -= dy;
+               }
+               else
+               {
+                       x += dx;
+                       y += dy;
+               }
+       }
+       x >>= 14;
+       y >>= 14;
+
+#ifdef SK_DEBUGx       // measure how far we are from unit-length
+       {
+               static int gMaxError;
+               static int gMaxDiff;
+
+               SkFixed len = fixlen(x, y);
+               int err = len - SK_Fixed1;
+               err = SkAbs32(err);
+
+               if (err > gMaxError)
+               {
+                       gMaxError = err;
+                       SkDebugf("gMaxError %d\n", err);
+               }
+
+               float fx = SkAbs32(ox)/65536.0f;
+               float fy = SkAbs32(oy)/65536.0f;
+               float mag = sqrtf(fx*fx + fy*fy);
+               fx /= mag;
+               fy /= mag;
+               SkFixed xx = (int)floorf(fx * 65536 + 0.5f);
+               SkFixed yy = (int)floorf(fy * 65536 + 0.5f);
+               err = SkMax32(SkAbs32(xx-x), SkAbs32(yy-y));
+               if (err > gMaxDiff)
+               {
+                       gMaxDiff = err;
+                       SkDebugf("gMaxDiff %d\n", err);
+               }
+       }
+#endif
+
+       x = SkApplySign(x, SkExtractSign(ox));
+       y = SkApplySign(y, SkExtractSign(oy));
+       if (length != SK_Fixed1)
+       {
+               x = SkFixedMul(x, length);
+               y = SkFixedMul(y, length);
+       }
+       this->set(x, y);
+       return true;
+}
+
+#endif
+
diff --git a/libs/corecg/SkRect.cpp b/libs/corecg/SkRect.cpp
new file mode 100644 (file)
index 0000000..0a09393
--- /dev/null
@@ -0,0 +1,103 @@
+#include "SkRect.h"
+
+bool SkRect16::intersect(S16CPU left, S16CPU top, S16CPU right, S16CPU bottom)
+{
+       if (fLeft < right && left < fRight && fTop < bottom && top < fBottom)
+       {
+               if (fLeft < left) fLeft = SkToS16(left);
+               if (fTop < top) fTop = SkToS16(top);
+               if (fRight > right) fRight = SkToS16(right);
+               if (fBottom > bottom) fBottom = SkToS16(bottom);
+               return true;
+       }
+       return false;
+}
+
+bool SkRect16::intersect(const SkRect16& r)
+{
+       SkASSERT(&r);
+       return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom);
+}
+
+bool SkRect16::intersect(const SkRect16& a, const SkRect16& b)
+{
+       SkASSERT(&a && &b);
+
+       *this = a;
+       return this->intersect(b.fLeft, b.fTop, b.fRight, b.fBottom);
+}
+
+void SkRect16::sort()
+{
+       if (fLeft > fRight)
+               SkTSwap<S16>(fLeft, fRight);
+       if (fTop > fBottom)
+               SkTSwap<S16>(fTop, fBottom);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void SkRect::sort()
+{
+       if (fLeft > fRight)
+               SkTSwap<SkScalar>(fLeft, fRight);
+       if (fTop > fBottom)
+               SkTSwap<SkScalar>(fTop, fBottom);
+}
+
+void SkRect::toQuad(SkPoint quad[4]) const
+{
+       SkASSERT(quad);
+
+       quad[0].set(fLeft, fTop);
+       quad[1].set(fRight, fTop);
+       quad[2].set(fRight, fBottom);
+       quad[3].set(fLeft, fBottom);
+}
+
+void SkRect::set(const SkPoint pts[], int count)
+{
+       SkASSERT(pts && count > 0 || count == 0);
+
+       if (count <= 0)
+               memset(this, 0, sizeof(SkRect));
+       else
+       {
+               SkScalar        l, t, r, b;
+
+               l = r = pts[0].fX;
+               t = b = pts[0].fY;
+
+               for (int i = 1; i < count; i++)
+               {
+                       SkScalar x = pts[i].fX;
+                       SkScalar y = pts[i].fY;
+
+                       if (x < l) l = x; else if (x > r) r = x;
+                       if (y < t) t = y; else if (y > b) b = y;
+               }
+               this->set(l, t, r, b);
+       }
+}
+
+bool SkRect::intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom)
+{
+       if (fLeft < right && left < fRight && fTop < bottom && top < fBottom)
+       {
+               if (fLeft < left) fLeft = left;
+               if (fTop < top) fTop = top;
+               if (fRight > right) fRight = right;
+               if (fBottom > bottom) fBottom = bottom;
+               return true;
+       }
+       return false;
+}
+
+bool SkRect::intersect(const SkRect& r)
+{
+       SkASSERT(&r);
+       return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom);
+}
+
+
+
diff --git a/libs/corecg/SkRegion.cpp b/libs/corecg/SkRegion.cpp
new file mode 100644 (file)
index 0000000..20c7c73
--- /dev/null
@@ -0,0 +1,1168 @@
+#include "SkRegionPriv.h"
+#include "SkTemplates.h"
+#include "SkThread.h"
+
+SkDEBUGCODE(int32_t gRgnAllocCounter;)
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+static SkRegion::RunType* skip_scanline(const SkRegion::RunType runs[])
+{
+       while (runs[0] != kRunTypeSentinel)
+       {
+               SkASSERT(runs[0] < runs[1]);    // valid span
+               runs += 2;
+       }
+       return (SkRegion::RunType*)(runs + 1);  // return past the X-sentinel
+}
+
+static SkRegion::RunType* find_y(const SkRegion::RunType runs[], int y)
+{
+       int     top = *runs++;
+       if (top <= y)
+       {
+               for (;;)
+               {
+                       int bot = *runs++;
+                       if (bot > y)
+                       {
+                               if (bot == kRunTypeSentinel || *runs == kRunTypeSentinel)
+                                       break;
+                               return (SkRegion::RunType*)runs;
+                       }
+                       top = bot;
+                       runs = skip_scanline(runs);
+               }
+       }
+       return nil;
+}
+
+// returns true if runs are a rect
+bool SkRegion::compute_run_bounds(const SkRegion::RunType runs[], int count, SkRect16* bounds)
+{
+       assert_sentinel(runs[0], false);        // top
+
+       if (count == kRectRegionRuns)
+       {
+               assert_sentinel(runs[1], false);        // bottom
+               assert_sentinel(runs[2], false);        // left
+               assert_sentinel(runs[3], false);        // right
+               assert_sentinel(runs[4], true);
+               assert_sentinel(runs[5], true);
+
+               SkASSERT(runs[0] < runs[1]);    // valid height
+               SkASSERT(runs[2] < runs[3]);    // valid width
+
+               bounds->set(runs[2], runs[0], runs[3], runs[1]);
+               return true;
+       }
+
+       int     left = SK_MaxS32;
+       int rite = SK_MinS32;
+       int     bot;
+
+       bounds->fTop = *runs++;
+       do {
+               bot = *runs++;
+               if (*runs < kRunTypeSentinel)
+               {
+                       if (left > *runs)
+                               left = *runs;
+                       runs = skip_scanline(runs);
+                       if (rite < runs[-2])
+                               rite = runs[-2];
+               }
+               else
+                       runs += 1;      // skip X-sentinel
+       } while (runs[0] < kRunTypeSentinel);
+       bounds->fLeft = SkToS16(left);
+       bounds->fRight = SkToS16(rite);
+       bounds->fBottom = SkToS16(bot);
+       return false;
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+SkRegion::SkRegion()
+{
+       fBounds.set(0, 0, 0, 0);
+       fRunHead = SkRegion_gEmptyRunHeadPtr;
+}
+
+SkRegion::SkRegion(const SkRegion& src)
+{
+       fRunHead = SkRegion_gEmptyRunHeadPtr;   // just need a value that won't trigger sk_free(fRunHead)
+    this->setRegion(src);
+}
+
+SkRegion::SkRegion(const SkRect16& rect)
+{
+       fRunHead = SkRegion_gEmptyRunHeadPtr;   // just need a value that won't trigger sk_free(fRunHead)
+       this->setRect(rect);
+}
+
+SkRegion::~SkRegion()
+{
+       this->freeRuns();
+}
+
+void SkRegion::freeRuns()
+{
+       if (fRunHead->isComplex())
+       {
+        SkASSERT(fRunHead->fRefCnt >= 1);
+        if (sk_atomic_dec(&fRunHead->fRefCnt) == 1)
+        {
+            //SkASSERT(gRgnAllocCounter > 0);
+            //SkDEBUGCODE(sk_atomic_dec(&gRgnAllocCounter));
+            //SkDEBUGF(("************** gRgnAllocCounter::free %d\n", gRgnAllocCounter));
+            sk_free(fRunHead);
+        }
+       }
+}
+
+void SkRegion::allocateRuns(int count)
+{
+    fRunHead = RunHead::Alloc(count);
+}
+
+SkRegion& SkRegion::operator=(const SkRegion& src)
+{
+       (void)this->setRegion(src);
+       return *this;
+}
+
+void SkRegion::swap(SkRegion& other)
+{
+       SkTSwap<SkRect16>(fBounds, other.fBounds);
+       SkTSwap<RunHead*>(fRunHead, other.fRunHead);
+}
+
+bool SkRegion::setEmpty()
+{
+       this->freeRuns();
+       fBounds.set(0, 0, 0, 0);
+       fRunHead = SkRegion_gEmptyRunHeadPtr;
+       return false;
+}
+
+bool SkRegion::setRect(S16CPU left, S16CPU top, S16CPU right, S16CPU bottom)
+{
+       if (left >= right || top >= bottom)
+               return this->setEmpty();
+
+       this->freeRuns();
+       fBounds.set(left, top, right, bottom);
+       fRunHead = SkRegion_gRectRunHeadPtr;
+       return true;
+}
+
+bool SkRegion::setRect(const SkRect16& r)
+{
+       return this->setRect(r.fLeft, r.fTop, r.fRight, r.fBottom);
+}
+
+bool SkRegion::setRegion(const SkRegion& src)
+{
+       if (this != &src)
+       {
+               this->freeRuns();
+
+               fBounds = src.fBounds;
+        fRunHead = src.fRunHead;
+        if (fRunHead->isComplex())
+            sk_atomic_inc(&fRunHead->fRefCnt);
+       }
+       return fRunHead != SkRegion_gEmptyRunHeadPtr;
+}
+
+bool SkRegion::op(const SkRect16& rect, Op op)
+{
+       SkRegion tmp(rect);
+
+       return this->op(*this, tmp, op);
+}
+
+bool SkRegion::op(const SkRect16& rect, const SkRegion& rgn, Op op)
+{
+       SkRegion tmp(rect);
+
+       return this->op(tmp, rgn, op);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+int SkRegion::count_runtype_values(int* itop, int* ibot) const
+{
+       if (this == nil)
+       {
+               *itop = SK_MinS16;
+               *ibot = SK_MaxS16;
+               return 0;
+       }
+
+       int     maxT;
+
+       if (this->isRect())
+               maxT = 2;
+       else
+       {
+        SkASSERT(this->isComplex());
+               // skip the top
+               const RunType*  runs = fRunHead->runs() + 1;
+               maxT = 0;
+
+               do {
+                       const RunType* next = skip_scanline(runs + 1);
+                       SkASSERT(next > runs);
+                       int                     T = (int)(next - runs - 1);
+                       if (maxT < T)
+                               maxT = T;
+                       runs = next;
+               } while (runs[0] < kRunTypeSentinel);
+       }
+       *itop = fBounds.fTop;
+       *ibot = fBounds.fBottom;
+       return maxT;
+}
+
+bool SkRegion::setRuns(RunType runs[], int count)
+{
+       SkASSERT(count > 0);
+
+       if (count <= 2)
+       {
+       //      SkDEBUGF(("setRuns: empty\n"));
+               assert_sentinel(runs[count-1], true);
+               return this->setEmpty();
+       }
+
+       // trim off any empty spans from the top and bottom
+       // weird I should need this, perhaps op() could be smarter...
+       if (count > kRectRegionRuns)
+       {
+               RunType* stop = runs + count;
+               assert_sentinel(runs[0], false);        // top
+               assert_sentinel(runs[1], false);        // bottom
+               if (runs[2] == kRunTypeSentinel)        // should be first left...
+               {
+                       runs += 2;      // skip empty initial span
+                       runs[0] = runs[-1];     // set new top to prev bottom
+                       assert_sentinel(runs[1], false);        // bot: a sentinal would mean two in a row
+                       assert_sentinel(runs[2], false);        // left
+                       assert_sentinel(runs[3], false);        // right
+               }
+
+               // now check for a trailing empty span
+               assert_sentinel(stop[-1], true);
+               assert_sentinel(stop[-2], true);
+               assert_sentinel(stop[-3], false);       // should be last right
+               if (stop[-4] == kRunTypeSentinel)       // eek, stop[-3] was a bottom with no x-runs
+               {
+                       stop[-3] = kRunTypeSentinel;    // kill empty last span
+                       stop -= 2;
+                       assert_sentinel(stop[-1], true);
+                       assert_sentinel(stop[-2], true);
+                       assert_sentinel(stop[-3], false);
+                       assert_sentinel(stop[-4], false);
+                       assert_sentinel(stop[-5], false);
+               }
+               count = (int)(stop - runs);
+       }
+
+       SkASSERT(count >= kRectRegionRuns);
+
+       if (compute_run_bounds(runs, count, &fBounds))
+       {
+       //      SkDEBUGF(("setRuns: rect[%d %d %d %d]\n", fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom));
+               return this->setRect(fBounds);
+       }
+
+    //  if we get here, we need to become a complex region
+
+    if (!fRunHead->isComplex() || fRunHead->fRunCount != count)
+       {
+#ifdef SK_DEBUGx
+               SkDebugf("setRuns: rgn [");
+               {
+                       const RunType* r = runs;
+
+                       SkDebugf(" top: %d\n", *r++);
+                       while (*r < kRunTypeSentinel)
+                       {
+                               SkDebugf(" bottom: %d", *r++);
+                               while (*r < kRunTypeSentinel)
+                               {
+                                       SkDebugf(" [%d %d]", r[0], r[1]);
+                                       r += 2;
+                               }
+                               SkDebugf("\n");
+                       }
+               }
+#endif
+               this->freeRuns();
+        this->allocateRuns(count);
+       }
+       memcpy(fRunHead->runs(), runs, count * sizeof(RunType));
+
+       SkDEBUGCODE(this->validate();)
+
+       return true;
+}
+
+void SkRegion::build_rect_runs(const SkRect16& bounds,
+                               RunType runs[kRectRegionRuns])
+{
+       runs[0] = bounds.fTop;
+       runs[1] = bounds.fBottom;
+       runs[2] = bounds.fLeft;
+       runs[3] = bounds.fRight;
+       runs[4] = kRunTypeSentinel;
+       runs[5] = kRunTypeSentinel;
+}
+
+static SkRegion::RunType* find_scanline(const SkRegion::RunType runs[], S16CPU y)
+{
+       SkASSERT(y >= runs[0]); // if this fails, we didn't do a quick check on the boudns
+
+       runs += 1;      // skip top-Y
+       for (;;)
+       {
+               if (runs[0] == kRunTypeSentinel)
+                       break;
+               if (y < runs[0])
+                       return (SkRegion::RunType*)&runs[1];
+               runs = skip_scanline(runs);
+       }
+       return nil;
+}
+
+bool SkRegion::contains(S16CPU x, S16CPU y) const
+{
+       if (!fBounds.contains(x, y))
+               return false;
+
+       if (this->isRect())
+               return true;
+
+    SkASSERT(this->isComplex());
+       const RunType* runs = find_scanline(fRunHead->runs(), y);
+
+       if (runs)
+       {       for (;;)
+               {       if (x < runs[0])
+                               break;
+                       if (x < runs[1])
+                               return true;
+                       runs += 2;
+               }
+       }
+       return false;
+}
+
+const SkRegion::RunType* SkRegion::getRuns(RunType tmpStorage[], int* count) const
+{
+       SkASSERT(tmpStorage && count);
+
+       if (this->isEmpty())
+       {
+               tmpStorage[0] = kRunTypeSentinel;
+               *count = 1;
+       }
+       else if (this->isRect())
+       {
+               build_rect_runs(fBounds, tmpStorage);
+               *count = kRectRegionRuns;
+       }
+       else
+       {
+               *count = fRunHead->fRunCount;
+               tmpStorage = fRunHead->runs();
+       }
+       return tmpStorage;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+int operator==(const SkRegion& a, const SkRegion& b)
+{
+    SkDEBUGCODE(a.validate();)
+    SkDEBUGCODE(b.validate();)
+
+    if (&a == &b)
+        return true;
+    if (a.fBounds != b.fBounds)
+        return false;
+    
+    const SkRegion::RunHead* ah = a.fRunHead;
+    const SkRegion::RunHead* bh = b.fRunHead;
+
+    // this catches empties and rects being equal
+    if (ah == bh) 
+        return true;
+    
+    // now we insist that both are complex (but different ptrs)
+    if (!ah->isComplex() || !bh->isComplex())
+        return false;
+
+    return  ah->fRunCount == bh->fRunCount &&
+            !memcmp(ah->runs(), bh->runs(), ah->fRunCount * sizeof(SkRegion::RunType));
+}
+
+void SkRegion::translate(int dx, int dy, SkRegion* dst) const
+{
+    SkDEBUGCODE(this->validate();)
+
+    if (dst == nil)
+        return;
+
+    if (this->isEmpty())
+        dst->setEmpty();
+    else if (this->isRect())
+        dst->setRect(fBounds.fLeft + dx, fBounds.fTop + dy,
+                     fBounds.fRight + dx, fBounds.fBottom + dy);
+    else
+    {
+        if (this == dst)
+        {
+            dst->fRunHead = dst->fRunHead->ensureWritable();
+        }
+        else
+        {
+            SkRegion    tmp;
+            tmp.allocateRuns(fRunHead->fRunCount);
+            tmp.fBounds = fBounds;
+            dst->swap(tmp);
+        }
+
+        dst->fBounds.offset(dx, dy);
+        
+        const RunType*  sruns = fRunHead->runs();
+        RunType*        druns = dst->fRunHead->runs();
+
+        *druns++ = SkToS16(*sruns++ + dy);    // top
+        for (;;)
+        {
+            int bottom = *sruns++;
+            if (bottom == kRunTypeSentinel)
+                break;
+            *druns++ = SkToS16(bottom + dy);  // bottom;
+            for (;;)
+            {
+                int x = *sruns++;
+                if (x == kRunTypeSentinel)
+                    break;
+                *druns++ = SkToS16(x + dx);
+                *druns++ = SkToS16(*sruns++ + dx);
+            }
+            *druns++ = kRunTypeSentinel;    // x sentinel
+        }
+        *druns++ = kRunTypeSentinel;    // y sentinel
+
+        SkASSERT(sruns - fRunHead->runs() == fRunHead->fRunCount);
+        SkASSERT(druns - dst->fRunHead->runs() == dst->fRunHead->fRunCount);
+    }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+#if defined _WIN32 && _MSC_VER >= 1300 // disable warning : local variable used without having been initialized
+#pragma warning ( push )
+#pragma warning ( disable : 4701 )
+#endif
+
+#ifdef SK_DEBUG
+static void assert_valid_pair(S16CPU left, S16CPU rite)
+{
+       SkASSERT(left == kRunTypeSentinel || left < rite);
+}
+#else
+       #define assert_valid_pair(left, rite)
+#endif
+
+struct spanRec {
+    const SkRegion::RunType*    fA_runs;
+    const SkRegion::RunType*    fB_runs;
+    int                         fA_left, fA_rite, fB_left, fB_rite;
+    int                         fLeft, fRite, fInside;
+    
+    void init(const SkRegion::RunType a_runs[], const SkRegion::RunType b_runs[])
+    {        
+        fA_left = *a_runs++;
+        fA_rite = *a_runs++;
+        fB_left = *b_runs++;
+        fB_rite = *b_runs++;
+
+        fA_runs = a_runs;
+        fB_runs = b_runs;
+    }
+    
+    bool done() const
+    {
+        SkASSERT(fA_left <= kRunTypeSentinel);
+        SkASSERT(fB_left <= kRunTypeSentinel);
+        return fA_left == kRunTypeSentinel && fB_left == kRunTypeSentinel;
+    }
+
+    void next()
+    {
+               assert_valid_pair(fA_left, fA_rite);
+               assert_valid_pair(fB_left, fB_rite);
+
+               int             inside, left, rite SK_INIT_TO_AVOID_WARNING;
+               bool    a_flush = false;
+               bool    b_flush = false;
+        
+        int a_left = fA_left;
+        int a_rite = fA_rite;
+        int b_left = fB_left;
+        int b_rite = fB_rite;
+
+               if (a_left < b_left)
+               {
+                       inside = 1;
+                       left = a_left;
+                       if (a_rite <= b_left)   // [...] <...>
+                       {
+                               rite = a_rite;
+                               a_flush = true;
+                       }
+                       else // [...<..]...> or [...<...>...]
+                               rite = a_left = b_left;
+               }
+               else if (b_left < a_left)
+               {
+                       inside = 2;
+                       left = b_left;
+                       if (b_rite <= a_left)   // [...] <...>
+                       {
+                               rite = b_rite;
+                               b_flush = true;
+                       }
+                       else // [...<..]...> or [...<...>...]
+                               rite = b_left = a_left;
+               }
+               else    // a_left == b_left
+               {
+                       inside = 3;
+                       left = a_left;  // or b_left
+                       if (a_rite <= b_rite)
+                       {
+                               rite = b_left = a_rite;
+                               a_flush = true;
+                       }
+                       if (b_rite <= a_rite)
+                       {
+                               rite = a_left = b_rite;
+                               b_flush = true;
+                       }
+               }
+
+               if (a_flush)
+               {
+                       a_left = *fA_runs++;
+                       a_rite = *fA_runs++;
+               }
+               if (b_flush)
+               {
+                       b_left = *fB_runs++;
+                       b_rite = *fB_runs++;
+               }
+
+               SkASSERT(left <= rite);
+        
+        // now update our state
+        fA_left = a_left;
+        fA_rite = a_rite;
+        fB_left = b_left;
+        fB_rite = b_rite;
+        
+        fLeft = left;
+        fRite = rite;
+        fInside = inside;
+    }
+};
+
+static SkRegion::RunType* operate_on_span(const SkRegion::RunType a_runs[],
+                                          const SkRegion::RunType b_runs[],
+                                          SkRegion::RunType dst[],
+                                          int min, int max)
+{
+    spanRec rec;
+    bool    firstInterval = true;
+    
+    rec.init(a_runs, b_runs);
+
+       while (!rec.done())
+       {
+        rec.next();
+        
+        int left = rec.fLeft;
+        int rite = rec.fRite;
+        
+               // add left,rite to our dst buffer (checking for coincidence
+               if ((unsigned)(rec.fInside - min) <= (unsigned)(max - min) &&
+                       left < rite)    // skip if equal
+               {
+                       if (firstInterval || dst[-1] < left)
+                       {
+                               *dst++ = SkToS16(left);
+                               *dst++ = SkToS16(rite);
+                               firstInterval = false;
+                       }
+                       else    // update the right edge
+                               dst[-1] = SkToS16(rite);
+               }
+       }
+
+       *dst++ = kRunTypeSentinel;
+       return dst;
+}
+
+#if defined _WIN32 && _MSC_VER >= 1300
+#pragma warning ( pop )
+#endif
+
+class RgnOper {
+public:
+       RgnOper(S16CPU top, SkRegion::RunType dst[], SkRegion::Op op)
+       {
+               fStartDst = dst;
+               fPrevDst = dst + 1;
+               fPrevLen = 0;           // will never match a length from operate_on_span
+               fTop = SkToS16(top);    // just a first guess, we might update this
+
+               static const struct {
+                       U8      fMin;
+                       U8      fMax;
+               } gOpMinMax[] = {
+                       { 1, 1 },       // Difference
+                       { 3, 3 },       // Intersection
+                       { 1, 3 },       // Union
+                       { 1, 2 }        // XOR
+               };
+               
+               SkASSERT((unsigned)op < SkRegion::kOpCount);
+               fMin = gOpMinMax[op].fMin;
+               fMax = gOpMinMax[op].fMax;
+       }
+
+       void addSpan(S16CPU bottom, const SkRegion::RunType a_runs[], const SkRegion::RunType b_runs[])
+       {
+               SkRegion::RunType*      start = fPrevDst + fPrevLen + 1;        // skip X values and slot for the next Y
+               SkRegion::RunType*      stop = operate_on_span(a_runs, b_runs, start, fMin, fMax);
+               size_t              len = stop - start;
+
+               if (fPrevLen == len && !memcmp(fPrevDst, start, len * sizeof(SkRegion::RunType)))       // update Y value
+                       fPrevDst[-1] = SkToS16(bottom);
+               else    // accept the new span
+               {
+                       if (len == 1 && fPrevLen == 0)
+                               fTop = SkToS16(bottom); // just update our bottom
+                       else
+                       {
+                               start[-1] = SkToS16(bottom);
+                               fPrevDst = start;
+                               fPrevLen = len;
+                       }
+               }
+       }
+    
+       int flush()
+       {
+               fStartDst[0] = fTop;
+               fPrevDst[fPrevLen] = kRunTypeSentinel;
+               return (int)(fPrevDst - fStartDst + fPrevLen + 1);
+       }
+
+       U8              fMin, fMax;
+
+private:
+       SkRegion::RunType*      fStartDst;
+       SkRegion::RunType*      fPrevDst;
+       size_t              fPrevLen;
+       SkRegion::RunType   fTop;
+};
+
+static int operate( const SkRegion::RunType a_runs[],
+                    const SkRegion::RunType b_runs[],
+                    SkRegion::RunType dst[],
+                    SkRegion::Op op)
+{
+       const SkRegion::RunType sentinel = kRunTypeSentinel;
+
+       int     a_top = *a_runs++;
+       int     a_bot = *a_runs++;
+       int b_top = *b_runs++;
+       int b_bot = *b_runs++;
+
+       assert_sentinel(a_top, false);
+       assert_sentinel(a_bot, false);
+       assert_sentinel(b_top, false);
+       assert_sentinel(b_bot, false);
+
+       RgnOper oper(SkMin32(a_top, b_top), dst, op);
+    
+    bool firstInterval = true;
+    int prevBot = kRunTypeSentinel; // so we fail the first test
+    
+       while (a_bot < kRunTypeSentinel || b_bot < kRunTypeSentinel)
+       {
+               int                     top, bot SK_INIT_TO_AVOID_WARNING;
+               const SkRegion::RunType*        run0 = &sentinel;
+               const SkRegion::RunType*        run1 = &sentinel;
+               bool            a_flush = false;
+               bool            b_flush = false;
+        int         inside;
+
+               if (a_top < b_top)
+               {
+            inside = 1;
+            top = a_top;
+                       run0 = a_runs;
+                       if (a_bot <= b_top)     // [...] <...>
+                       {
+                               bot = a_bot;
+                               a_flush = true;
+                       }
+                       else // [...<..]...> or [...<...>...]
+                               bot = a_top = b_top;
+               }
+               else if (b_top < a_top)
+               {
+            inside = 2;
+            top = b_top;
+                       run1 = b_runs;
+                       if (b_bot <= a_top)     // [...] <...>
+                       {
+                               bot = b_bot;
+                               b_flush = true;
+                       }
+                       else // [...<..]...> or [...<...>...]
+                               bot = b_top = a_top;
+               }
+               else    // a_top == b_top
+               {
+            inside = 3;
+            top = a_top;    // or b_top
+                       run0 = a_runs;
+                       run1 = b_runs;
+                       if (a_bot <= b_bot)
+                       {
+                               bot = b_top = a_bot;
+                               a_flush = true;
+                       }
+                       if (b_bot <= a_bot)
+                       {
+                               bot = a_top = b_bot;
+                               b_flush = true;
+                       }
+               }
+        
+        if (top > prevBot)
+            oper.addSpan(top, &sentinel, &sentinel);
+
+//             if ((unsigned)(inside - oper.fMin) <= (unsigned)(oper.fMax - oper.fMin))
+        {
+                       oper.addSpan(bot, run0, run1);
+            firstInterval = false;
+        }
+
+               if (a_flush)
+               {
+                       a_runs = skip_scanline(a_runs);
+                       a_top = a_bot;
+                       a_bot = *a_runs++;
+                       if (a_bot == kRunTypeSentinel)
+                               a_top = a_bot;
+               }
+               if (b_flush)
+               {
+                       b_runs = skip_scanline(b_runs);
+                       b_top = b_bot;
+                       b_bot = *b_runs++;
+                       if (b_bot == kRunTypeSentinel)
+                               b_top = b_bot;
+               }
+        
+        prevBot = bot;
+       }
+       return oper.flush();
+}
+
+bool SkRegion::op(const SkRegion& rgna, const SkRegion& rgnb, Op op)
+{
+       SkDEBUGCODE(this->validate();)
+
+       SkASSERT((unsigned)op < kOpCount);
+
+       SkRect16        bounds;
+       bool            a_empty = rgna.isEmpty();
+       bool            b_empty = rgnb.isEmpty();
+       bool            a_rect = rgna.isRect();
+       bool            b_rect = rgnb.isRect();
+
+       switch (op) {
+       case kDifference_Op:
+               if (a_empty)
+                       return this->setEmpty();
+               if (b_empty || !SkRect16::Intersects(rgna.fBounds, rgnb.fBounds))
+                       return this->setRegion(rgna);
+               break;
+
+       case kIntersect_Op:
+               if ((a_empty | b_empty) || !bounds.intersect(rgna.fBounds, rgnb.fBounds))
+                       return this->setEmpty();
+               if (a_rect & b_rect)
+                       return this->setRect(bounds);
+               break;
+
+       case kUnion_Op:
+               if (a_empty)
+                       return this->setRegion(rgnb);
+               if (b_empty)
+                       return this->setRegion(rgna);
+               if (a_rect && rgna.fBounds.contains(rgnb.fBounds))
+                       return this->setRegion(rgna);
+               if (b_rect && rgnb.fBounds.contains(rgna.fBounds))
+                       return this->setRegion(rgnb);
+               break;
+
+       case kXOR_Op:
+               if (a_empty)
+                       return this->setRegion(rgnb);
+               if (b_empty)
+                       return this->setRegion(rgna);
+               break;
+       default:
+               break;
+       }
+
+       RunType tmpA[kRectRegionRuns];
+       RunType tmpB[kRectRegionRuns];
+
+       int     a_count, b_count;
+       const RunType* a_runs = rgna.getRuns(tmpA, &a_count);
+       const RunType* b_runs = rgnb.getRuns(tmpB, &b_count);
+
+       int     dstCount = 3 * SkMax32(a_count, b_count);
+       SkAutoSTMalloc<32, RunType>     array(dstCount);
+
+       int count = operate(a_runs, b_runs, array.get(), op);
+       SkASSERT(count <= dstCount);
+       return this->setRuns(array.get(), count);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkBuffer.h"
+
+size_t SkRegion::computeBufferSize() const
+{
+    size_t  size = sizeof(int32_t); // -1 (empty), 0 (rect), runCount
+
+    if (!this->isEmpty())
+    {
+        size += sizeof(fBounds);
+        if (this->isComplex())
+            size += fRunHead->fRunCount * sizeof(RunType);
+    }
+    return size;
+}
+
+size_t SkRegion::writeToBuffer(void* storage) const
+{
+    SkWBuffer   buffer(storage);
+
+    if (this->isEmpty())
+    {
+        buffer.write32(-1);
+    }
+    else
+    {
+        bool isRect = this->isRect();
+
+        buffer.write32(isRect ? 0 : fRunHead->fRunCount);
+        buffer.write(&fBounds, sizeof(fBounds));
+
+        if (!isRect)
+        {
+            buffer.write(fRunHead->runs(), fRunHead->fRunCount * sizeof(RunType));
+        }
+    }
+    return buffer.pos();
+}
+
+size_t SkRegion::readFromBuffer(const void* storage)
+{
+    SkRBuffer   buffer(storage);
+    SkRegion        tmp;
+    int32_t         count;
+    
+    count = buffer.readS32();
+    if (count >= 0)
+    {
+        buffer.read(&tmp.fBounds, sizeof(tmp.fBounds));
+        if (count == 0)
+        {
+            tmp.fRunHead = SkRegion_gRectRunHeadPtr;
+        }
+        else
+        {
+            tmp.allocateRuns(count);
+            buffer.read(tmp.fRunHead->runs(), count * sizeof(RunType));
+        }
+    }
+    this->swap(tmp);
+    return buffer.pos();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+static const SkRegion::RunType* validate_line(const SkRegion::RunType run[], const SkRect16& bounds)
+{
+       SkASSERT(*run >= bounds.fTop);
+       SkASSERT(*run <= bounds.fBottom);
+       run += 1;
+       while (*run < kRunTypeSentinel)
+       {
+               SkASSERT(run[0] < run[1]);
+               SkASSERT(run[0] >= bounds.fLeft);
+               SkASSERT(run[1] <= bounds.fRight);
+               run += 2;
+       }
+       return run + 1; // skip sentinel
+}
+
+void SkRegion::validate() const
+{
+       if (this->isEmpty())
+       {
+        // check for explicit empty (the zero rect), so we can compare rects to know when
+        // two regions are equal (i.e. emptyRectA == emptyRectB)
+        // this is stricter than just asserting fBounds.isEmpty()
+               SkASSERT(fBounds.fLeft == 0 && fBounds.fTop == 0 && fBounds.fRight == 0 && fBounds.fBottom == 0);
+       }
+       else
+       {
+               SkASSERT(!fBounds.isEmpty());
+               if (!this->isRect())
+               {
+            SkASSERT(fRunHead->fRefCnt >= 1);
+            SkASSERT(fRunHead->fRunCount >= kRectRegionRuns);
+
+                       const RunType* run = fRunHead->runs();
+                       const RunType* stop = run + fRunHead->fRunCount;
+                       
+                       SkASSERT(*run++ == fBounds.fTop);
+                       do {
+                               run = validate_line(run, fBounds);
+                       } while (*run < kRunTypeSentinel);
+                       SkASSERT(run + 1 == stop);
+               }
+       }
+}
+
+void SkRegion::dump() const
+{
+    if (this->isEmpty())
+        SkDebugf("  rgn: empty\n");
+    else
+    {
+        SkDebugf("  rgn: [%d %d %d %d]", fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
+        if (this->isComplex())
+        {
+            const RunType* runs = fRunHead->runs();
+            for (int i = 0; i < fRunHead->fRunCount; i++)
+                SkDebugf(" %d", runs[i]);
+        }
+        SkDebugf("\n");
+    }
+}
+
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+SkRegion::Iterator::Iterator(const SkRegion& rgn)
+{
+       if (rgn.isEmpty())
+               fDone = true;
+       else
+       {
+               fDone = false;
+               if (rgn.isRect())
+               {
+                       fRect = rgn.fBounds;
+                       fRuns = nil;
+               }
+               else
+               {
+                       fRuns = rgn.fRunHead->runs();
+                       fRect.set(fRuns[2], fRuns[0], fRuns[3], fRuns[1]);
+                       fRuns += 4;
+               }
+       }
+}
+
+void SkRegion::Iterator::next()
+{
+       if (fDone) return;
+
+       if (fRuns == nil)       // rect case
+       {
+               fDone = true;
+               return;
+       }
+
+       const RunType* runs = fRuns;
+
+       if (runs[0] < kRunTypeSentinel) // valid X value
+       {
+               fRect.fLeft = runs[0];
+               fRect.fRight = runs[1];
+               runs += 2;
+       }
+       else    // we're at the end of a line
+       {
+               runs += 1;
+               if (runs[0] < kRunTypeSentinel) // valid Y value
+               {
+                       if (runs[1] == kRunTypeSentinel)        // empty line
+                       {
+                               fRect.fTop = runs[0];
+                               runs += 2;
+                       }
+                       else
+                               fRect.fTop = fRect.fBottom;
+       
+                       fRect.fBottom = runs[0];
+                       assert_sentinel(runs[1], false);
+                       fRect.fLeft = runs[1];
+                       fRect.fRight = runs[2];
+                       runs += 3;
+               }
+               else    // end of rgn
+                       fDone = true;
+       }
+       fRuns = runs;
+}
+
+SkRegion::Cliperator::Cliperator(const SkRegion& rgn, const SkRect16& clip)
+       : fIter(rgn), fClip(clip), fDone(true)
+{
+       const SkRect16& r = fIter.rect();
+
+       while (!fIter.done())
+       {
+               if (r.fTop >= clip.fBottom)
+                       break;
+               if (fRect.intersect(clip, r))
+               {
+                       fDone = false;
+                       break;
+               }
+               fIter.next();
+       }
+}
+
+void SkRegion::Cliperator::next()
+{
+       if (fDone) return;
+
+       const SkRect16& r = fIter.rect();
+
+       fDone = true;
+       fIter.next();
+       while (!fIter.done())
+       {
+               if (r.fTop >= fClip.fBottom)
+                       break;
+               if (fRect.intersect(fClip, r))
+               {
+                       fDone = false;
+                       break;
+               }
+               fIter.next();
+       }
+}
+
+//////////////////////////////////////////////////////////////////////
+
+SkRegion::Spanerator::Spanerator(const SkRegion& rgn, int y, int left, int right)
+{
+       const SkRect16& r = rgn.getBounds();
+
+       fDone = true;
+       if (!rgn.isEmpty() && y >= r.fTop && y < r.fBottom && right > r.fLeft && left < r.fRight)
+       {
+               if (rgn.isRect())
+               {
+                       if (left < r.fLeft)
+                               left = r.fLeft;
+                       if (right > r.fRight)
+                               right = r.fRight;
+
+                       fLeft = left;
+                       fRight = right;
+                       fRuns = nil;    // means we're a rect, not a rgn
+                       fDone = false;
+               }
+               else
+               {
+                       const SkRegion::RunType* runs = find_y(rgn.fRunHead->runs(), y);
+                       if (runs)
+                       {
+                               for (;;)
+                               {
+                                       if (runs[0] >= right)   // runs[0..1] is to the right of the span, so we're done
+                                               break;
+                                       if (runs[1] <= left)    // runs[0..1] is to the left of the span, so continue
+                                       {
+                                               runs += 2;
+                                               continue;
+                                       }
+                                       // runs[0..1] intersects the span
+                                       fRuns = runs;
+                                       fLeft = left;
+                                       fRight = right;
+                                       fDone = false;
+                                       break;
+                               }
+                       }
+               }
+       }
+}
+
+bool SkRegion::Spanerator::next(int* left, int* right)
+{
+       if (fDone) return false;
+
+       if (fRuns == nil)       // we're a rect
+       {
+               fDone = true;   // ok, now we're done
+               if (left) *left = fLeft;
+               if (right) *right = fRight;
+               return true;    // this interval is legal
+       }
+
+       const SkRegion::RunType* runs = fRuns;
+
+       if (runs[0] >= fRight)
+       {
+               fDone = true;
+               return false;
+       }
+
+       SkASSERT(runs[1] > fLeft);
+
+       if (left)
+               *left = SkMax32(fLeft, runs[0]);
+       if (right)
+               *right = SkMin32(fRight, runs[1]);
+       fRuns = runs + 2;
+       return true;
+}
+
diff --git a/libs/corecg/SkRegionPriv.h b/libs/corecg/SkRegionPriv.h
new file mode 100644 (file)
index 0000000..7626a35
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef SkRegionPriv_DEFINED
+#define SkRegionPriv_DEFINED
+
+#include "SkRegion.h"
+#include "SkThread.h"
+
+#define kRunTypeSentinel       0x7FFF
+#define assert_sentinel(value, isSentinel)     SkASSERT(((value) == kRunTypeSentinel) == isSentinel)
+
+//SkDEBUGCODE(extern int32_t gRgnAllocCounter;)
+
+struct SkRegion::RunHead {
+    int32_t fRefCnt;
+    int32_t fRunCount;
+    
+    static RunHead* Alloc(int count)
+    {
+        //SkDEBUGCODE(sk_atomic_inc(&gRgnAllocCounter);)
+        //SkDEBUGF(("************** gRgnAllocCounter::alloc %d\n", gRgnAllocCounter));
+
+        SkASSERT(count >= SkRegion::kRectRegionRuns);
+
+        RunHead* head = (RunHead*)sk_malloc_throw(sizeof(RunHead) + count * sizeof(RunType));
+        head->fRefCnt = 1;
+        head->fRunCount = count;
+        return head;
+    }
+    
+    bool isComplex() const
+    {
+        return this != SkRegion_gEmptyRunHeadPtr && this != SkRegion_gRectRunHeadPtr;
+    }
+
+    SkRegion::RunType* runs()
+    {
+        SkASSERT(this->isComplex());
+        return (SkRegion::RunType*)(this + 1);
+    }
+    const SkRegion::RunType* runs() const
+    {
+        SkASSERT(this->isComplex());
+        return (const SkRegion::RunType*)(this + 1);
+    }
+    
+    RunHead* ensureWritable()
+    {
+        SkASSERT(this->isComplex());
+        
+        RunHead* writable = this;
+        if (fRefCnt > 1)
+        {
+            // We need to alloc & copy the current region before we call
+            // sk_atomic_dec because it could be freed in the meantime,
+            // otherwise.            
+            writable = Alloc(fRunCount);
+            memcpy(writable->runs(), this->runs(), fRunCount * sizeof(RunType));
+
+            // fRefCount might have changed since we last checked.
+            // If we own the last reference at this point, we need to
+            // free the memory.
+            if (sk_atomic_dec(&fRefCnt) == 1)
+            {
+                sk_free(this);
+            }
+        }
+        return writable;
+    }
+};
+
+#endif
diff --git a/libs/corecg/SkSinTable.h b/libs/corecg/SkSinTable.h
new file mode 100644 (file)
index 0000000..2c4c11d
--- /dev/null
@@ -0,0 +1,268 @@
+#ifndef SkSinTable_DEFINED
+#define SkSinTable_DEFINED
+
+#include "SkTypes.h"
+
+/* Fixed point values (low 16 bits) of sin(radians) for
+       radians in [0...PI/2)
+*/
+static const U16 gSkSinTable[256] = {
+       0x0000,
+       0x0192,
+       0x0324,
+       0x04B6,
+       0x0648,
+       0x07DA,
+       0x096C,
+       0x0AFE,
+       0x0C8F,
+       0x0E21,
+       0x0FB2,
+       0x1144,
+       0x12D5,
+       0x1466,
+       0x15F6,
+       0x1787,
+       0x1917,
+       0x1AA7,
+       0x1C37,
+       0x1DC7,
+       0x1F56,
+       0x20E5,
+       0x2273,
+       0x2402,
+       0x2590,
+       0x271D,
+       0x28AA,
+       0x2A37,
+       0x2BC4,
+       0x2D50,
+       0x2EDB,
+       0x3066,
+       0x31F1,
+       0x337B,
+       0x3505,
+       0x368E,
+       0x3817,
+       0x399F,
+       0x3B26,
+       0x3CAD,
+       0x3E33,
+       0x3FB9,
+       0x413E,
+       0x42C3,
+       0x4447,
+       0x45CA,
+       0x474D,
+       0x48CE,
+       0x4A50,
+       0x4BD0,
+       0x4D50,
+       0x4ECF,
+       0x504D,
+       0x51CA,
+       0x5347,
+       0x54C3,
+       0x563E,
+       0x57B8,
+       0x5931,
+       0x5AAA,
+       0x5C22,
+       0x5D98,
+       0x5F0E,
+       0x6083,
+       0x61F7,
+       0x636A,
+       0x64DC,
+       0x664D,
+       0x67BD,
+       0x692D,
+       0x6A9B,
+       0x6C08,
+       0x6D74,
+       0x6EDF,
+       0x7049,
+       0x71B1,
+       0x7319,
+       0x7480,
+       0x75E5,
+       0x774A,
+       0x78AD,
+       0x7A0F,
+       0x7B70,
+       0x7CD0,
+       0x7E2E,
+       0x7F8B,
+       0x80E7,
+       0x8242,
+       0x839C,
+       0x84F4,
+       0x864B,
+       0x87A1,
+       0x88F5,
+       0x8A48,
+       0x8B9A,
+       0x8CEA,
+       0x8E39,
+       0x8F87,
+       0x90D3,
+       0x921E,
+       0x9368,
+       0x94B0,
+       0x95F6,
+       0x973C,
+       0x987F,
+       0x99C2,
+       0x9B02,
+       0x9C42,
+       0x9D7F,
+       0x9EBC,
+       0x9FF6,
+       0xA12F,
+       0xA267,
+       0xA39D,
+       0xA4D2,
+       0xA605,
+       0xA736,
+       0xA866,
+       0xA994,
+       0xAAC0,
+       0xABEB,
+       0xAD14,
+       0xAE3B,
+       0xAF61,
+       0xB085,
+       0xB1A8,
+       0xB2C8,
+       0xB3E7,
+       0xB504,
+       0xB620,
+       0xB73A,
+       0xB852,
+       0xB968,
+       0xBA7C,
+       0xBB8F,
+       0xBCA0,
+       0xBDAE,
+       0xBEBC,
+       0xBFC7,
+       0xC0D0,
+       0xC1D8,
+       0xC2DE,
+       0xC3E2,
+       0xC4E3,
+       0xC5E4,
+       0xC6E2,
+       0xC7DE,
+       0xC8D8,
+       0xC9D1,
+       0xCAC7,
+       0xCBBB,
+       0xCCAE,
+       0xCD9F,
+       0xCE8D,
+       0xCF7A,
+       0xD064,
+       0xD14D,
+       0xD233,
+       0xD318,
+       0xD3FA,
+       0xD4DB,
+       0xD5B9,
+       0xD695,
+       0xD770,
+       0xD848,
+       0xD91E,
+       0xD9F2,
+       0xDAC4,
+       0xDB94,
+       0xDC61,
+       0xDD2D,
+       0xDDF6,
+       0xDEBE,
+       0xDF83,
+       0xE046,
+       0xE106,
+       0xE1C5,
+       0xE282,
+       0xE33C,
+       0xE3F4,
+       0xE4AA,
+       0xE55E,
+       0xE60F,
+       0xE6BE,
+       0xE76B,
+       0xE816,
+       0xE8BF,
+       0xE965,
+       0xEA09,
+       0xEAAB,
+       0xEB4B,
+       0xEBE8,
+       0xEC83,
+       0xED1C,
+       0xEDB2,
+       0xEE46,
+       0xEED8,
+       0xEF68,
+       0xEFF5,
+       0xF080,
+       0xF109,
+       0xF18F,
+       0xF213,
+       0xF294,
+       0xF314,
+       0xF391,
+       0xF40B,
+       0xF484,
+       0xF4FA,
+       0xF56D,
+       0xF5DE,
+       0xF64D,
+       0xF6BA,
+       0xF724,
+       0xF78B,
+       0xF7F1,
+       0xF853,
+       0xF8B4,
+       0xF912,
+       0xF96E,
+       0xF9C7,
+       0xFA1E,
+       0xFA73,
+       0xFAC5,
+       0xFB14,
+       0xFB61,
+       0xFBAC,
+       0xFBF5,
+       0xFC3B,
+       0xFC7E,
+       0xFCBF,
+       0xFCFE,
+       0xFD3A,
+       0xFD74,
+       0xFDAB,
+       0xFDE0,
+       0xFE13,
+       0xFE43,
+       0xFE70,
+       0xFE9B,
+       0xFEC4,
+       0xFEEA,
+       0xFF0E,
+       0xFF2F,
+       0xFF4E,
+       0xFF6A,
+       0xFF84,
+       0xFF9C,
+       0xFFB1,
+       0xFFC3,
+       0xFFD3,
+       0xFFE1,
+       0xFFEC,
+       0xFFF4,
+       0xFFFB,
+       0xFFFE
+};
+
+#endif
diff --git a/libs/corecg/SkTSort.h b/libs/corecg/SkTSort.h
new file mode 100644 (file)
index 0000000..bdfbf6d
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef SkTSort_DEFINED
+#define SkTSort_DEFINED
+
+#include "SkTypes.h"
+
+template <typename T>
+void SkTHeapSort_SiftDown(T array[], int root, int bottom)
+{
+       int     root2 = root << 1;
+
+       while (root2 <= bottom)
+       {
+               int     maxChild;
+
+               if (root2 == bottom)
+                       maxChild = root2;
+               else if (array[root2] > array[root2 + 1])
+                       maxChild = root2;
+               else
+                       maxChild = root2 + 1;
+
+               if (array[root] < array[maxChild])
+               {
+                       SkTSwap<T>(array[root], array[maxChild]);
+                       root = maxChild;
+                       root2 = root << 1;
+               }
+               else
+                       break;
+       }
+}
+
+template <typename T>
+void SkTHeapSort(T array[], int count)
+{
+       int i;
+
+       for (i = count/2 - 1; i >= 0; --i)
+               SkTHeapSort_SiftDown<T>(array, i, count);
+
+       for (i = count - 2; i >= 0; --i)
+       {
+               SkTSwap<T>(array[0], array[i + 1]);
+               SkTHeapSort_SiftDown<T>(array, 0, i);
+       }
+}
+
+#endif
diff --git a/libs/graphics/Makefile b/libs/graphics/Makefile
new file mode 100644 (file)
index 0000000..7bccd3a
--- /dev/null
@@ -0,0 +1,137 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+       effects/Sk1DPathEffect.cpp \
+       effects/Sk2DPathEffect.cpp \
+       effects/SkBlurMask.cpp \
+       effects/SkBlurMaskFilter.cpp \
+       effects/SkCamera.cpp \
+       effects/SkColorFilters.cpp \
+       effects/SkCornerPathEffect.cpp \
+       effects/SkDashPathEffect.cpp \
+       effects/SkDiscretePathEffect.cpp \
+       effects/SkEmbossMask.cpp \
+       effects/SkEmbossMaskFilter.cpp \
+       effects/SkGradientShader.cpp \
+       effects/SkLayerRasterizer.cpp \
+       effects/SkNinePatch.cpp \
+       effects/SkShaderExtras.cpp \
+       effects/SkTransparentShader.cpp \
+       images/SkBitmapRef.cpp \
+       images/SkImageDecoder.cpp \
+       images/SkImageDecoder_libgif.cpp \
+       images/SkImageDecoder_libjpeg.cpp \
+       images/SkImageDecoder_libpng.cpp \
+       images/SkStream.cpp \
+       sgl/SkAlphaRuns.cpp \
+       sgl/SkBitmap.cpp \
+       sgl/SkBitmapSampler.cpp \
+       sgl/SkBitmapShader.cpp \
+       sgl/SkBlitter.cpp \
+       sgl/SkBlitter_A1.cpp \
+       sgl/SkBlitter_A8.cpp \
+       sgl/SkBlitter_ARGB32.cpp \
+       sgl/SkBlitter_RGB16.cpp \
+       sgl/SkBlitter_Sprite.cpp \
+       sgl/SkCanvas.cpp \
+       sgl/SkColor.cpp \
+       sgl/SkColorFilter.cpp \
+       sgl/SkColorTable.cpp \
+       sgl/SkDeque.cpp \
+       sgl/SkDraw.cpp \
+       sgl/SkEdge.cpp \
+       sgl/SkFilterProc.cpp \
+       sgl/SkGeometry.cpp \
+       sgl/SkGlobals.cpp \
+       sgl/SkGlyphCache.cpp \
+       sgl/SkGraphics.cpp \
+       sgl/SkMaskFilter.cpp \
+       sgl/SkPaint.cpp \
+       sgl/SkPath.cpp \
+       sgl/SkPathEffect.cpp \
+       sgl/SkPathMeasure.cpp \
+       sgl/SkProcSpriteBlitter.cpp \
+       sgl/SkRasterizer.cpp \
+       sgl/SkRefCnt.cpp \
+       sgl/SkRegion_path.cpp \
+       sgl/SkScalerContext.cpp \
+       sgl/SkScan.cpp \
+       sgl/SkScan_AntiPath.cpp \
+       sgl/SkScan_Antihair.cpp \
+       sgl/SkScan_Hairline.cpp \
+       sgl/SkScan_Path.cpp \
+       sgl/SkShader.cpp \
+       sgl/SkSpriteBlitter_ARGB32.cpp \
+       sgl/SkSpriteBlitter_RGB16.cpp \
+       sgl/SkString.cpp \
+       sgl/SkStroke.cpp \
+       sgl/SkStrokerPriv.cpp \
+       sgl/SkTSearch.cpp \
+    sgl/SkTextLayout.cpp \
+       sgl/SkUtils.cpp \
+       sgl/SkXfermode.cpp \
+       views/SkEvent.cpp \
+    views/SkEventSink.cpp \
+    views/SkMetaData.cpp \
+    views/SkTagList.cpp \
+    views/SkTextBox.cpp \
+       ports/SkImageDecoder_Factory.cpp \
+       ports/SkFontHost.cpp \
+       ports/SkFontHost_FreeType.cpp \
+       ports/SkGlobals_global.cpp \
+       ports/SkOSFile_stdio.cpp \
+       ports/SkOSEvent_android.cpp \
+       ports/SkTime_Unix.cpp \
+       ports/SkXMLParser_expat.cpp \
+       xml/SkDOM.cpp \
+       xml/SkXMLParser.cpp \
+       xml/SkXMLWriter.cpp \
+       xml/SkParseColor.cpp \
+       xml/SkParse.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+       libutils \
+       libcorecg \
+       libpng \
+       libgif \
+       libjpeg \
+       libft2 \
+       libexpat \
+       libz
+
+LOCAL_C_INCLUDES += \
+       $(LOCAL_PATH)/animator \
+       $(LOCAL_PATH)/sgl \
+       $(LOCAL_PATH)/images \
+       $(LOCAL_PATH)/ports \
+       include/graphics \
+       include/corecg \
+       libs/corecg \
+       extlibs/freetype-2.1.10/include \
+       extlibs/zlib-1.2.3 \
+       extlibs/libpng-1.2.8 \
+       extlibs/libgif-4.0 \
+       extlibs/jpeg-6b \
+       extlibs/expat-2.0.0/lib
+
+ifeq ($(DEVICE_OS),darwin)
+       LOCAL_CFLAGS += -fPIC
+else
+       LOCAL_CFLAGS += -fpic
+endif
+
+ifeq ($(DEVICE_ARCH),arm)
+       LOCAL_CFLAGS += -DFMS_ARCH_ANDROID_ARM
+endif
+
+# TODO RELEASE_BUILD isn't right
+ifeq ($(RELEASE_BUILD),true)
+       LOCAL_CFLAGS += -O2
+endif
+
+LOCAL_LDLIBS += -lpthread
+
+LOCAL_TARGET:= libsgl
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/graphics/animator/SkAnimate.h b/libs/graphics/animator/SkAnimate.h
new file mode 100644 (file)
index 0000000..aa593bf
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef SkAnimate_DEFINED
+#define SkAnimate_DEFINED
+
+#include "SkAnimateBase.h"
+#include "SkDisplayType.h"
+#include "SkIntArray.h"
+#include "SkUtils.h"
+
+class SkAnimate : public SkAnimateBase {
+       DECLARE_MEMBER_INFO(Animate);
+       SkAnimate();
+       virtual ~SkAnimate();
+       virtual int components();
+#ifdef SK_DUMP_ENABLED
+       virtual void dump(SkAnimateMaker* );
+#endif
+       virtual void onEndElement(SkAnimateMaker& maker);
+protected:
+       bool resolveCommon(SkAnimateMaker& );
+       int fComponents;
+private:
+       typedef SkAnimateBase INHERITED;
+};
+
+#endif // SkAnimateField_DEFINED
+
diff --git a/libs/graphics/animator/SkAnimate3DSchema.xsd b/libs/graphics/animator/SkAnimate3DSchema.xsd
new file mode 100644 (file)
index 0000000..5063b75
--- /dev/null
@@ -0,0 +1,39 @@
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"\r
+       xmlns:Sk="http://www.skia.com/schema/SkAnimateSchema.xsd"\r
+       targetNamespace="urn:skia3D" xmlns:Sk3D="urn:skia3D">\r
+\r
+       <xs:simpleType name="Patch" >\r
+               <xs:restriction base="xs:string" >\r
+               </xs:restriction>\r
+       </xs:simpleType>\r
+\r
+       <xs:simpleType name="Point" >\r
+               <xs:restriction base="xs:string" >\r
+                       <xs:pattern value="[+-]?([0-9]*\.[0-9]+|[0-9]+\.?)( *[ ,] *[+-]?([0-9]*\.[0-9]+|[0-9]+\.?)){2}" /> \r
+               </xs:restriction>\r
+       </xs:simpleType>\r
+\r
+       <xs:element name="camera">\r
+               <xs:complexType >\r
+                       <xs:attribute name="axis" type="Sk3D:Point" />\r
+                       <xs:attribute name="hackHeight" type="Sk:Float" />\r
+                       <xs:attribute name="hackWidth" type="Sk:Float" />\r
+                       <xs:attribute name="location" type="Sk3D:Point" />\r
+                       <xs:attribute name="observer" type="Sk3D:Point" />\r
+                       <xs:attribute name="patch" type="Sk3D:Patch" />\r
+                       <xs:attribute name="zenith" type="Sk3D:Point" />\r
+                       <xs:attribute name="id" type="xs:ID" />\r
+               </xs:complexType>\r
+       </xs:element>\r
+\r
+       <xs:element name="patch">\r
+               <xs:complexType >\r
+                       <xs:attribute name="origin" type="Sk3D:Point" />\r
+                       <xs:attribute name="rotateDegrees" type="Sk:MemberFunction" />\r
+                       <xs:attribute name="u" type="Sk3D:Point" />\r
+                       <xs:attribute name="v" type="Sk3D:Point" />\r
+                       <xs:attribute name="id" type="xs:ID" />\r
+               </xs:complexType>\r
+       </xs:element>\r
+\r
+</xs:schema>\r
diff --git a/libs/graphics/animator/SkAnimate3DSchema.xsx b/libs/graphics/animator/SkAnimate3DSchema.xsx
new file mode 100644 (file)
index 0000000..ceb7d89
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<!--This file is auto-generated by the XML Schema Designer. It holds layout information for components on the designer surface.-->\r
+<XSDDesignerLayout />
diff --git a/libs/graphics/animator/SkAnimateActive.cpp b/libs/graphics/animator/SkAnimateActive.cpp
new file mode 100644 (file)
index 0000000..85f676f
--- /dev/null
@@ -0,0 +1,492 @@
+#include "SkAnimateActive.h"
+#include "SkAnimateBase.h"
+#include "SkAnimateMaker.h"
+#include "SkAnimateSet.h"
+#include "SkDrawGroup.h"
+#ifdef SK_DEBUG
+#include "SkTime.h"
+#endif
+
+// SkActive holds array of interpolators
+
+SkActive::SkActive(SkApply& apply, SkAnimateMaker& maker) : fApply(apply),
+       fMaxTime(0), fMaker(maker), fDrawIndex(0), fDrawMax(0) {
+}
+
+void SkActive::init() 
+{
+       fAnimators = fApply.fAnimators;
+       int animators = fAnimators.count();
+       fInterpolators.setCount(animators);
+       memset(fInterpolators.begin(), 0, animators * sizeof(SkOperandInterpolator*));
+       fState.setCount(animators);
+       int index;
+       for (index = 0; index < animators; index++)
+               fInterpolators[index] = SkNEW(SkOperandInterpolator);
+       initState(&fApply, 0);
+//     for (index = 0; index < animators; index++)
+//             fState[index].bumpSave();
+       SkASSERT(fInterpolators.count() == fAnimators.count());
+}
+
+SkActive::~SkActive() {
+       int index;
+       for (index = 0; index < fSaveRestore.count(); index++)
+               delete[] fSaveRestore[index];
+       for (index = 0; index < fSaveInterpolators.count(); index++)
+               delete[] fSaveInterpolators[index];
+       for (index = 0; index < fInterpolators.count(); index++)
+               delete fInterpolators[index];
+}
+
+void SkActive::advance() {
+       if (fDrawMax < fDrawIndex)
+               fDrawMax = fDrawIndex;
+       fDrawIndex += fAnimators.count();
+}
+
+void SkActive::append(SkApply* apply) {
+       int oldCount = fAnimators.count();
+       SkTDAnimateArray& animates = apply->fAnimators;
+       int newCount = animates.count();
+       int index;
+       int total = oldCount + newCount;
+       if (total == 0)
+               return;
+       fInterpolators.setCount(total);
+       memset(&fInterpolators.begin()[oldCount], 0, newCount * sizeof(SkOperandInterpolator*));
+       for (index = oldCount; index < total; index++)
+               fInterpolators[index] = SkNEW(SkOperandInterpolator);
+       fAnimators.setCount(total);
+       memcpy(&fAnimators[oldCount], animates.begin(), sizeof(fAnimators[0]) *
+               newCount);
+       fState.setCount(total);
+       initState(apply, oldCount);
+       SkASSERT(fApply.scope == apply->scope);
+       for (index = 0; index < newCount; index++) {
+               SkAnimateBase* test = animates[index];
+//             SkASSERT(fApply.scope == test->fTarget || fApply.scope->contains(test->fTarget));
+               SkActive::SkState& testState = fState[oldCount + index];
+               for (int inner = 0; inner < oldCount; inner++) {
+                       SkAnimateBase* oldGuard = fAnimators[inner];
+                       SkActive::SkState& oldState = fState[inner];
+                       if (oldGuard->fTarget == test->fTarget && oldGuard->fFieldInfo == test->fFieldInfo &&
+                                       testState.fBegin == oldState.fBegin) {
+                               delete fInterpolators[inner];
+                               fInterpolators.remove(inner);
+                               fAnimators.remove(inner);
+                               testState.fSave = oldState.fSave;
+                               if (oldState.fUnpostedEndEvent) {
+//                                     SkDEBUGF(("%8x %8x active append: post on end\n", this, oldGuard));
+                                       fMaker.postOnEnd(oldGuard, oldState.fBegin + oldState.fDuration);
+                               }
+                               fState.remove(inner);
+                               if (fApply.restore) {
+                                       int saveIndex = fSaveRestore.count();
+                                       SkASSERT(fSaveInterpolators.count() == saveIndex);
+                                       saveIndex += inner;
+                                       do {
+                                               saveIndex -= oldCount;
+                                               delete[] fSaveRestore[saveIndex];
+                                               fSaveRestore.remove(saveIndex);
+                                               delete[] fSaveInterpolators[saveIndex]; 
+                                               fSaveInterpolators.remove(saveIndex);
+                                       } while (saveIndex > 0);
+                               }
+                               oldCount--;
+                               break;
+                       }
+               }
+       }
+//     total = oldCount + newCount;
+//     for (index = oldCount; index < total; index++)
+//             fState[index].bumpSave();
+       SkASSERT(fInterpolators.count() == fAnimators.count());
+}
+
+void SkActive::appendSave(int oldCount) {
+       SkASSERT(fDrawMax == 0);        // if true, we can optimize below quite a bit
+       int newCount = fAnimators.count();
+       int saveIndex = fSaveRestore.count();
+       SkASSERT(fSaveInterpolators.count() == saveIndex);
+       int records = saveIndex / oldCount;
+       int newTotal = records * newCount;
+       fSaveRestore.setCount(newTotal);
+       do {
+               saveIndex -= oldCount;
+               newTotal -= newCount;
+               SkASSERT(saveIndex >= 0);
+               SkASSERT(newTotal >= 0);
+               memmove(&fSaveRestore[newTotal], &fSaveRestore[saveIndex], oldCount);
+               memset(&fSaveRestore[newTotal + oldCount], 0, 
+                       sizeof(fSaveRestore[0]) * (newCount - oldCount));
+               memmove(&fSaveInterpolators[newTotal], 
+                       &fSaveInterpolators[saveIndex], oldCount);
+               memset(&fSaveInterpolators[newTotal + oldCount], 0, 
+                       sizeof(fSaveRestore[0]) * (newCount - oldCount));
+       } while (saveIndex > 0);
+       SkASSERT(newTotal == 0);
+}
+
+void SkActive::calcDurations(int index) 
+{
+       SkAnimateBase* animate = fAnimators[index];
+       SkMSec duration = animate->dur;
+       SkState& state = fState[index];
+       if (state.fMode == SkApply::kMode_immediate || state.fMode == SkApply::kMode_create)
+               duration = state.fSteps ? state.fSteps * SK_MSec1 : 1;
+//     else if (state.fMode == SkApply::kMode_hold) {
+//             int entries = animate->entries();
+//             SkScriptValue value;
+//             value.fOperand = animate->getValues()[entries - 1];
+//             value.fType = animate->getValuesType();
+//             bool result = SkScriptEngine::ConvertTo(nil, SkType_Int, &value);
+//             SkASSERT(result);
+//             duration = value.fOperand.fS32 * SK_MSec1;
+//     }
+       state.fDuration = duration;
+       SkMSec maxTime = state.fBegin + duration;
+       if (fMaxTime < maxTime)
+               fMaxTime = maxTime;
+}
+
+void SkActive::create(SkDrawable* drawable, SkMSec time) {
+       fApply.fLastTime = time;
+       fApply.refresh(fMaker);
+       for (int index = 0; index < fAnimators.count(); index++) {
+               SkAnimateBase* animate = fAnimators[index];
+               SkOperandInterpolator& interpolator = *fInterpolators[index];
+               int count = animate->components();
+               if (animate->formula.size() > 0) {
+                       SkTDOperandArray values;
+                       values.setCount(count);
+                       bool success = animate->fFieldInfo->setValue(fMaker, &values, 0, 0, nil, 
+                               animate->getValuesType(), animate->formula);
+                       SkASSERT(success);
+                       fApply.applyValues(index, values.begin(), count, animate->getValuesType(), time);
+               } else {
+                       SkAutoSTMalloc<16, SkOperand> values(count);
+                       interpolator.timeToValues(time, values.get());
+                       fApply.applyValues(index, values.get(), count, animate->getValuesType(), time);
+               }
+       }
+       drawable->enable(fMaker);
+       SkASSERT(fAnimators.count() == fInterpolators.count());
+}
+
+bool SkActive::immediate(bool enable) {
+       SkMSec time = 0;
+       bool result = false;
+       SkDrawable* drawable = fApply.scope;
+       SkMSec final = fMaxTime;
+       do {
+               bool applied = fAnimators.count() == 0;
+               fApply.fLastTime = time;
+               fApply.refresh(fMaker);
+               for (int index = 0; index < fAnimators.count(); index++) {
+                       SkAnimateBase* animate = fAnimators[index];
+                       SkState& state = fState[index];
+                       if (state.fMode != SkApply::kMode_immediate)
+                               continue;
+                       if (state.fBegin > time)
+                               continue;
+                       if (time > state.fBegin + state.fDuration)
+                               continue;
+                       applied = true;
+                       SkOperandInterpolator& interpolator = *fInterpolators[index];
+                       int count = animate->components();
+                       if (animate->formula.size() > 0) {
+                               SkTDOperandArray values;
+                               values.setCount(count);
+                               bool success = animate->fFieldInfo->setValue(fMaker, &values, 0, 0, nil, 
+                                       animate->getValuesType(), animate->formula);
+                               SkASSERT(success);
+                               fApply.applyValues(index, values.begin(), count, animate->getValuesType(), time);
+                       } else {
+                               SkAutoSTMalloc<16, SkOperand> values(count);
+                               interpolator.timeToValues(time, values.get());
+                               fApply.applyValues(index, values.get(), count, animate->getValuesType(), time);
+                       }
+               }
+               if (enable)
+                       drawable->enable(fMaker);
+               else if (applied)
+                       result |= drawable->draw(fMaker);
+               time += SK_MSec1;
+       } while (time <= final);
+       return result;
+}
+
+void SkActive::fixInterpolator(SkBool save) {
+       int animators = fAnimators.count();
+       for (int index = 0; index < animators; index++) {
+               SkAnimateBase* animate = fAnimators[index];
+               if (save) { // saved slots increased
+                       animate->refresh(fMaker);
+                       SkOperand* values = animate->getValues();
+                       setInterpolator(index, values);
+                       saveInterpolatorValues(index);
+               } else
+                       restoreInterpolatorValues(index);
+       }
+}
+
+SkMSec SkActive::getTime(SkMSec inTime, int animatorIndex) {
+       fState[animatorIndex].fTicks = inTime;
+       return inTime - fState[animatorIndex].fStartTime;
+}
+
+bool SkActive::initializeSave() {
+       int animators = fAnimators.count();
+       int activeTotal = fDrawIndex + animators;
+       int oldCount = fSaveRestore.count();
+       if (oldCount < activeTotal) {
+               fSaveRestore.setCount(activeTotal);
+               memset(&fSaveRestore[oldCount], 0, sizeof(fSaveRestore[0]) * (activeTotal - oldCount));
+               SkASSERT(fSaveInterpolators.count() == oldCount);
+               fSaveInterpolators.setCount(activeTotal);
+               memset(&fSaveInterpolators[oldCount], 0, 
+                       sizeof(fSaveInterpolators[0]) * (activeTotal - oldCount));
+               return true;
+       }
+       return false;
+}
+
+void SkActive::initState(SkApply* apply, int offset) {
+       int count = fState.count();
+       for (int index = offset; index < count; index++) {
+               SkState& state = fState[index];
+               SkAnimateBase* animate = fAnimators[index];
+#if 0 // def SK_DEBUG
+               if (animate->fHasEndEvent)
+                       SkDebugf("%8x %8x active initState:\n", this, animate);
+#endif
+               SkOperand* from = animate->getValues();
+               state.fStartTime = state.fBegin = apply->begin + animate->begin;
+               state.fMode = apply->mode;
+               state.fTransition = apply->transition;
+#if 0
+               state.fPickup = (SkBool8) apply->pickup;
+#endif
+               state.fRestore = (SkBool8) apply->restore;
+               state.fSave = apply->begin;
+               state.fStarted = false;
+               state.fSteps = apply->steps;
+               state.fTicks = 0;
+               state.fUnpostedEndEvent = (SkBool8) animate->fHasEndEvent; 
+               calcDurations(index);
+               setInterpolator(index, from);
+       }
+       if (count == 0 && (apply->mode == SkApply::kMode_immediate || apply->mode == SkApply::kMode_create))
+               fMaxTime = apply->begin + apply->steps * SK_MSec1;
+}
+
+void SkActive::pickUp(SkActive* existing) {
+       SkTDOperandArray existingValues;
+       for (int index = 0; index < fAnimators.count(); index++) {
+               SkAnimateBase* animate = fAnimators[index];
+               SkASSERT(animate->getValuesType() == SkType_Float);
+               int components = animate->components();
+               SkOperand* from = animate->getValues();
+               SkOperand* to = &from[animate->components()];
+               existingValues.setCount(components);
+               existing->fInterpolators[index]->timeToValues(
+                       existing->fState[index].fTicks - existing->fState[index].fStartTime, existingValues.begin());
+               SkScalar originalSum = 0;
+               SkScalar workingSum = 0;
+               for (int cIndex = 0; cIndex < components; cIndex++) {
+                       SkScalar delta = to[cIndex].fScalar - from[cIndex].fScalar;
+                       originalSum += SkScalarMul(delta, delta);
+                       delta = to[cIndex].fScalar - existingValues[cIndex].fScalar;
+                       workingSum += SkScalarMul(delta, delta);
+               }
+               if (workingSum < originalSum) {
+                       SkScalar originalDistance = SkScalarSqrt(originalSum);
+                       SkScalar workingDistance = SkScalarSqrt(workingSum);
+                       existing->fState[index].fDuration = (SkMSec) SkScalarMulDiv(fState[index].fDuration, 
+                               workingDistance, originalDistance);
+               }
+               fInterpolators[index]->reset(components, 2, SkType_Float);
+               fInterpolators[index]->setKeyFrame(0, 0, existingValues.begin(), animate->blend[0]);
+               fInterpolators[index]->setKeyFrame(1, fState[index].fDuration, to, animate->blend[0]);
+       }
+}
+
+void SkActive::resetInterpolators() {
+       int animators = fAnimators.count();
+       for (int index = 0; index < animators; index++) {
+               SkAnimateBase* animate = fAnimators[index];
+               SkOperand* values = animate->getValues();
+               setInterpolator(index, values);
+       }
+}
+
+void SkActive::resetState() {
+       fDrawIndex = 0;
+       int count = fState.count();
+       for (int index = 0; index < count; index++) {
+               SkState& state = fState[index];
+               SkAnimateBase* animate = fAnimators[index];
+#if 0 // def SK_DEBUG
+               if (animate->fHasEndEvent)
+                       SkDebugf("%8x %8x active resetState: has end event\n", this, animate);
+#endif
+               state.fStartTime = state.fBegin = fApply.begin + animate->begin;
+               state.fStarted = false;
+               state.fTicks = 0;
+       }
+}
+
+void SkActive::restoreInterpolatorValues(int index) {
+       SkOperandInterpolator& interpolator = *fInterpolators[index];
+       index += fDrawIndex ;
+       int count = interpolator.getValuesCount();
+       memcpy(interpolator.getValues(), fSaveInterpolators[index], count * sizeof(SkOperand));
+}
+
+void SkActive::saveInterpolatorValues(int index) {
+       SkOperandInterpolator& interpolator = *fInterpolators[index];
+       index += fDrawIndex ;
+       int count = interpolator.getValuesCount();
+       SkOperand* cache = new SkOperand[count];        // this should use sk_malloc/sk_free since SkOperand does not have a constructor/destructor
+       fSaveInterpolators[index] = cache;
+       memcpy(cache,   interpolator.getValues(), count * sizeof(SkOperand));
+}
+
+void SkActive::setInterpolator(int index, SkOperand* from) {
+       if (from == nil) // legitimate for set string
+               return;
+       SkAnimateBase* animate = fAnimators[index];
+       int entries = animate->entries();
+       SkASSERT(entries > 0);
+       SkMSec duration = fState[index].fDuration;
+       int components = animate->components();
+       SkOperandInterpolator& interpolator = *fInterpolators[index];
+       interpolator.reset(components, entries == 1 ? 2 : entries, animate->getValuesType()); 
+       interpolator.setMirror(SkToBool(animate->fMirror));
+       interpolator.setReset(SkToBool(animate->fReset));
+       interpolator.setRepeatCount(animate->repeat);
+       if (entries == 1) {
+               interpolator.setKeyFrame(0, 0, from, animate->blend[0]);
+               interpolator.setKeyFrame(1, duration, from, animate->blend[0]);
+               return;
+       }
+       for (int entry = 0; entry < entries; entry++) {
+               int blendIndex = SkMin32(animate->blend.count() - 1, entry);
+               interpolator.setKeyFrame(entry, entry * duration / (entries - 1), from, 
+                       animate->blend[blendIndex]);
+               from += components;
+       }
+}
+
+void SkActive::setSteps(int steps) {
+       int count = fState.count();
+       fMaxTime = 0;
+       for (int index = 0; index < count; index++) {
+               SkState& state = fState[index];
+               state.fSteps = steps;
+               calcDurations(index);
+       }
+}
+
+void SkActive::start() {
+       int count = fState.count();
+       SkASSERT(count == fAnimators.count());
+       SkASSERT(count == fInterpolators.count());
+       for (int index = 0; index < count; index++) {
+               SkState& state = fState[index];
+               if (state.fStarted)
+                       continue;
+               state.fStarted = true;
+#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
+               SkString debugOut;
+               SkMSec time = fMaker.getAppTime();
+               debugOut.appendS32(time - fMaker.fDebugTimeBase);
+               debugOut.append(" active start adjust delay id=");
+               debugOut.append(fApply._id);
+               debugOut.append("; ");
+               debugOut.append(fAnimators[index]->_id);
+               debugOut.append("=");
+               debugOut.appendS32(fAnimators[index]->fStart - fMaker.fDebugTimeBase);
+               debugOut.append(":");
+               debugOut.appendS32(state.fStartTime);
+#endif
+               if (state.fStartTime > 0) {
+                       SkMSec future = fAnimators[index]->fStart + state.fStartTime;
+                       if (future > fMaker.fEnableTime)
+                               fMaker.notifyInvalTime(future);
+                       else
+                               fMaker.notifyInval();
+#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
+                       debugOut.append(":");
+                       debugOut.appendS32(future - fMaker.fDebugTimeBase);
+#endif
+               }
+               if (state.fStartTime >= fMaker.fAdjustedStart) {
+                       state.fStartTime -= fMaker.fAdjustedStart;
+#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
+                       debugOut.append(" (less adjust = ");
+                       debugOut.appendS32(fMaker.fAdjustedStart);
+#endif
+               }
+               state.fStartTime += fAnimators[index]->fStart;
+#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
+               debugOut.append(") new start = ");
+               debugOut.appendS32(state.fStartTime - fMaker.fDebugTimeBase);
+               SkDebugf("%s\n", debugOut.c_str());
+//             SkASSERT((int) (state.fStartTime - fMaker.fDebugTimeBase) >= 0);
+#endif
+       }
+       SkASSERT(fAnimators.count() == fInterpolators.count());
+}
+
+#ifdef SK_DEBUG
+void SkActive::validate() {
+       int count = fState.count();
+       SkASSERT(count == fAnimators.count());
+       SkASSERT(count == fInterpolators.count());
+       for (int index = 0; index < count; index++) {
+               SkASSERT(fAnimators[index]);
+               SkASSERT(fInterpolators[index]);
+//             SkAnimateBase* test = fAnimators[index];
+//             SkASSERT(fApply.scope == test->fTarget || fApply.scope->contains(test->fTarget));
+       }
+}
+#endif
+
+// think about this
+// there should only be one animate object, not two, to go up and down
+// when the apply with reverse came into play, it needs to pick up the value
+// of the existing animate object then remove it from the list
+// the code below should only be bumping fSave, and there shouldn't be anything
+// it needs to be synchronized with
+
+// however, if there are two animates both operating on the same field, then 
+// when one replaces the other, it may make sense to pick up the old value as a starting 
+// value for the new one somehow.
+
+//void SkActive::SkState::bumpSave() {
+//     if (fMode != SkApply::kMode_hold) 
+//             return;
+//     if (fTransition == SkApply::kTransition_reverse) {
+//             if (fSave > 0)
+//                     fSave -= SK_MSec1;
+//     } else if (fSave < fDuration)
+//             fSave += SK_MSec1;
+//}
+
+SkMSec SkActive::SkState::getRelativeTime(SkMSec time) {
+       SkMSec result = time;
+//     if (fMode == SkApply::kMode_hold)
+//             result = fSave;
+//     else
+       if (fTransition == SkApply::kTransition_reverse) {
+               if (SkMSec_LT(fDuration, time))
+                       result = 0;
+               else
+                       result = fDuration - time;
+       }
+       return result;
+}
+
+
diff --git a/libs/graphics/animator/SkAnimateActive.h b/libs/graphics/animator/SkAnimateActive.h
new file mode 100644 (file)
index 0000000..3bdf933
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef SkAnimateActive_DEFINED
+#define SkAnimateActive_DEFINED
+
+#include "SkDisplayApply.h"
+#include "SkOperandInterpolator.h"
+#include "SkIntArray.h"
+
+class SkAnimateMaker;
+
+class SkActive {
+public:
+       SkActive(SkApply& , SkAnimateMaker& );
+       ~SkActive();
+       void advance();
+       void append(SkApply* );
+       void calcDurations(int index);
+       void create(SkDrawable* scope, SkMSec time);
+       bool draw() { return immediate(false); }
+       bool enable() { return immediate(true); }
+       void init( );
+       SkMSec getTime(SkMSec inTime, int animatorIndex);
+       void pickUp(SkActive* existing);
+       void reset() { fDrawIndex = 0; }
+       void setInterpolator(int index, SkOperand* from);
+       void start();
+#ifdef SK_DEBUG
+       void validate();
+#endif
+private:
+       void appendSave(int oldCount);
+       void fixInterpolator(SkBool save);
+       bool immediate(bool enable);
+       bool initializeSave();
+       void initState(SkApply* , int offset);
+       void resetInterpolators();
+       void resetState();
+       void restoreInterpolatorValues(int index);
+       void saveInterpolatorValues(int index);
+       void setSteps(int steps);
+       struct SkState {
+//             void bumpSave();
+               SkMSec getRelativeTime(SkMSec time);
+               SkApply::Mode fMode;
+               SkApply::Transition fTransition;
+               SkBool8 fPickup;
+               SkBool8 fRestore;
+               SkBool8 fStarted;
+               SkBool8 fUnpostedEndEvent;
+               S32 fSteps;
+               SkMSec fBegin;
+               SkMSec fStartTime;
+               SkMSec fDuration;
+               SkMSec fSave;
+               SkMSec fTicks;
+       };
+       SkActive& operator= (const SkActive& );
+       SkTDArray<SkOperandInterpolator*> fInterpolators;
+       SkApply& fApply;
+       SkTDArray<SkState> fState;      // one per animator
+       SkTDOperandPtrArray fSaveRestore;       // if apply has restore="true"
+       SkTDOperandPtrArray fSaveInterpolators;
+       SkTDAnimateArray fAnimators;
+       SkMSec fMaxTime;        // greatest of all animation durations; only used by immediate mode
+       SkAnimateMaker& fMaker;
+       int fDrawIndex;
+       int fDrawMax;
+       friend class SkApply;
+};
+
+#endif // SkAnimateActive_DEFINED
diff --git a/libs/graphics/animator/SkAnimateBase.cpp b/libs/graphics/animator/SkAnimateBase.cpp
new file mode 100644 (file)
index 0000000..fd3bd67
--- /dev/null
@@ -0,0 +1,230 @@
+#include "SkAnimateBase.h"
+#include "SkAnimateMaker.h"
+#include "SkAnimateProperties.h"
+#include "SkAnimatorScript.h"
+#include "SkDisplayApply.h"
+#include "SkDrawable.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkAnimateBase::fInfo[] = {
+       SK_MEMBER(begin, MSec),
+       SK_MEMBER_ARRAY(blend, Float),
+       SK_MEMBER(dur, MSec),
+       SK_MEMBER_PROPERTY(dynamic, Boolean),
+       SK_MEMBER(field, String),       // name of member info in target
+       SK_MEMBER(formula, DynamicString),
+       SK_MEMBER(from, DynamicString),
+       SK_MEMBER(lval, DynamicString),
+       SK_MEMBER_PROPERTY(mirror, Boolean),
+       SK_MEMBER(repeat, Float),
+       SK_MEMBER_PROPERTY(reset, Boolean),
+       SK_MEMBER_PROPERTY(step, Int),
+       SK_MEMBER(target, DynamicString),
+       SK_MEMBER(to, DynamicString),
+       SK_MEMBER_PROPERTY(values, DynamicString)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkAnimateBase);
+
+SkAnimateBase::SkAnimateBase() : begin(0), dur(1), repeat(SK_Scalar1),
+               fApply(nil), fFieldInfo(nil), fFieldOffset(0), fStart((SkMSec) -1), fTarget(nil), 
+               fChanged(0), fDelayed(0), fDynamic(0), fHasEndEvent(0), fHasValues(0), 
+               fMirror(0), fReset(0), fResetPending(0), fTargetIsScope(0) {
+       blend.setCount(1);
+       blend[0] = SK_Scalar1;
+}
+
+SkAnimateBase::~SkAnimateBase() {
+       SkDisplayTypes type = fValues.getType();
+       if (type == SkType_String || type == SkType_DynamicString) {
+               SkASSERT(fValues.count() == 1);
+               delete fValues[0].fString;
+       }
+}
+
+int SkAnimateBase::components() { 
+       return 1; 
+}
+
+SkDisplayable* SkAnimateBase::deepCopy(SkAnimateMaker* maker) {
+       SkAnimateBase* result = (SkAnimateBase*) INHERITED::deepCopy(maker);
+       result->fApply = fApply;
+       result->fFieldInfo =fFieldInfo;
+       result->fHasValues = false;
+       return result;
+}
+
+void SkAnimateBase::dirty() {
+       fChanged = true;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkAnimateBase::dump(SkAnimateMaker* maker) {
+       dumpBase(maker);
+       if (target.size() > 0)
+               SkDebugf("target=\"%s\" ", target.c_str());
+    else if (fTarget && strcmp(fTarget->id, ""))
+        SkDebugf("target=\"%s\" ", fTarget->id);
+       if (lval.size() > 0)
+               SkDebugf("lval=\"%s\" ", lval.c_str());
+       if (field.size() > 0)
+               SkDebugf("field=\"%s\" ", field.c_str());
+    else if (fFieldInfo)
+        SkDebugf("field=\"%s\" ", fFieldInfo->fName);
+       if (formula.size() > 0)
+               SkDebugf("formula=\"%s\" ", formula.c_str());
+    else {
+        if (from.size() > 0)
+            SkDebugf("from=\"%s\" ", from.c_str());
+               SkDebugf("to=\"%s\" ", to.c_str());
+       }
+       if (begin != 0) {
+#ifdef SK_CAN_USE_FLOAT
+               SkDebugf("begin=\"%g\" ", SkScalarToFloat(SkScalarDiv(begin,1000)));
+#else
+               SkDebugf("begin=\"%x\" ", SkScalarDiv(begin,1000));
+#endif
+    }
+}
+#endif
+
+SkDisplayable* SkAnimateBase::getParent() const {
+       return (SkDisplayable*) fApply;
+}
+
+bool SkAnimateBase::getProperty(int index, SkScriptValue* value) const {
+       int boolResult;
+       switch (index) {
+               case SK_PROPERTY(dynamic):
+                       boolResult = fDynamic;
+                       goto returnBool;
+               case SK_PROPERTY(mirror):
+                       boolResult = fMirror;
+                       goto returnBool;
+               case SK_PROPERTY(reset):
+                       boolResult = fReset;
+returnBool:
+                       value->fOperand.fS32 = SkToBool(boolResult);
+                       value->fType = SkType_Boolean;
+                       break;
+               case SK_PROPERTY(step):
+                       if (fApply == nil)
+                               return false;    // !!! notify there's an error?
+                       fApply->getStep(value);
+                       break;
+               case SK_PROPERTY(values):
+                       value->fOperand.fString = (SkString*) &to;
+                       value->fType = SkType_String;
+                       break;
+               default:
+                       SkASSERT(0);
+                       return false;
+       }
+       return true;
+}
+
+bool SkAnimateBase::hasExecute() const 
+{
+       return false; 
+}
+
+void SkAnimateBase::onEndElement(SkAnimateMaker& maker) {
+       fChanged = false;
+       setTarget(maker);
+       if (field.size()) {
+               SkASSERT(fTarget);
+               fFieldInfo = fTarget->getMember(field.c_str());
+               field.reset();
+       }
+       if (lval.size()) {
+               // lval must be of the form x[y]
+               const char* lvalStr = lval.c_str();
+               const char* arrayEnd = strchr(lvalStr, '[');
+               if (arrayEnd == nil)
+                       return; //should this return an error?
+               size_t arrayNameLen = arrayEnd - lvalStr;
+               SkString arrayStr(lvalStr, arrayNameLen);
+               SkASSERT(fTarget);  //this return an error?
+               fFieldInfo = fTarget->getMember(arrayStr.c_str());
+               SkString scriptStr(arrayEnd + 1, lval.size() - arrayNameLen - 2);
+               SkAnimatorScript::EvaluateInt(maker, this, scriptStr.c_str(), &fFieldOffset);
+       }
+}
+
+void SkAnimateBase::packARGB(SkScalar array[], int count, SkTDOperandArray* converted) 
+{ 
+       SkASSERT(count == 4);
+       converted->setCount(1);
+       SkColor color = SkColorSetARGB(SkScalarRound(array[0]), SkScalarRound(array[1]), 
+               SkScalarRound(array[2]), SkScalarRound(array[3]));
+       (*converted)[0].fS32 = color;
+}
+
+
+
+void SkAnimateBase::refresh(SkAnimateMaker& ) {
+}
+
+bool SkAnimateBase::setParent(SkDisplayable* apply) {
+       SkASSERT(apply->isApply());
+       fApply = (SkApply*) apply;
+       return false;
+}
+
+bool SkAnimateBase::setProperty(int index, SkScriptValue& value) {
+       bool boolValue = SkToBool(value.fOperand.fS32);
+       switch (index) {
+               case SK_PROPERTY(dynamic):
+                       fDynamic = boolValue;
+                       goto checkForBool;
+               case SK_PROPERTY(values):
+                       fHasValues = true;
+                       SkASSERT(value.fType == SkType_String);
+                       to = *value.fOperand.fString;
+                       break;
+               case SK_PROPERTY(mirror):
+                       fMirror = boolValue;
+                       goto checkForBool;
+               case SK_PROPERTY(reset):
+                       fReset = boolValue;
+checkForBool:
+                       SkASSERT(value.fType == SkType_Boolean);
+                       break;
+               default:
+                       return false;
+       }
+       return true;
+}
+
+void SkAnimateBase::setTarget(SkAnimateMaker& maker) {
+       if (target.size()) {
+               SkAnimatorScript engine(maker, this, SkType_Displayable);
+               const char* script = target.c_str();
+               SkScriptValue scriptValue;
+               bool success = engine.evaluateScript(&script, &scriptValue);
+               if (success && scriptValue.fType == SkType_Displayable)
+                       fTarget = scriptValue.fOperand.fDrawable;
+               else if (maker.find(target.c_str(), (SkDisplayable**) &fTarget) == false) {
+                       if (fApply->getMode() == SkApply::kMode_create)
+                               return; // may not be an error
+                       if (engine.getError() != SkScriptEngine::kNoError)
+                               maker.setScriptError(engine);
+                       else {
+                               maker.setErrorNoun(target);
+                               maker.setErrorCode(SkDisplayXMLParserError::kTargetIDNotFound);
+                       }
+                       return;
+               }
+               if (fApply && fApply->getMode() != SkApply::kMode_create)
+                       target.reset();
+       }
+}
+
+bool SkAnimateBase::targetNeedsInitialization() const { 
+       return false; 
+}
+
+
diff --git a/libs/graphics/animator/SkAnimateBase.h b/libs/graphics/animator/SkAnimateBase.h
new file mode 100644 (file)
index 0000000..510b593
--- /dev/null
@@ -0,0 +1,74 @@
+#ifndef SkAnimateBase_DEFINED
+#define SkAnimateBase_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkMath.h"
+#include "SkMemberInfo.h"
+#include "SkTypedArray.h"
+
+class SkApply;
+class SkDrawable;
+
+class SkAnimateBase : public SkDisplayable {
+public:
+       DECLARE_MEMBER_INFO(AnimateBase);
+       SkAnimateBase();
+       virtual ~SkAnimateBase();
+       virtual int components();
+       virtual SkDisplayable* deepCopy(SkAnimateMaker* );
+       virtual void dirty();
+#ifdef SK_DUMP_ENABLED
+       virtual void dump(SkAnimateMaker* );
+#endif
+       int entries() { return fValues.count() / components(); }
+       virtual bool hasExecute() const;
+       bool isDynamic() const { return SkToBool(fDynamic); }
+       virtual SkDisplayable* getParent() const;
+       virtual bool getProperty(int index, SkScriptValue* value) const;
+       SkMSec getStart() const { return fStart; }
+       SkOperand* getValues() { return fValues.begin(); }
+       SkDisplayTypes getValuesType() { return fValues.getType(); }
+       virtual void onEndElement(SkAnimateMaker& );
+       void packARGB(SkScalar [], int count, SkTDOperandArray* );
+       virtual void refresh(SkAnimateMaker& );
+       void setChanged(bool changed) { fChanged = changed; }
+       void setHasEndEvent() { fHasEndEvent = true; }
+       virtual bool setParent(SkDisplayable* );
+       virtual bool setProperty(int index, SkScriptValue& value);
+       void setTarget(SkAnimateMaker& );
+       virtual bool targetNeedsInitialization() const;
+protected:
+       SkMSec begin;
+       SkTDScalarArray blend;
+       SkMSec dur;
+       // !!! make field part of a union with fFieldInfo, or fValues, something known later?
+       SkString field; // temporary; once target is known, this is reset
+       SkString formula;
+       SkString from;
+       SkString lval;
+       SkScalar repeat;
+       SkString target;        // temporary; once target is known, this is reset
+       SkString to;
+       SkApply* fApply;
+       const SkMemberInfo* fFieldInfo;
+       int fFieldOffset;
+       SkMSec fStart;  // corrected time when this apply was enabled
+       SkDrawable* fTarget;
+       SkTypedArray fValues;
+       unsigned fChanged : 1; // true when value referenced by script has changed
+       unsigned fDelayed : 1;  // enabled, but undrawn pending delay
+       unsigned fDynamic : 1;
+       unsigned fHasEndEvent : 1;
+       unsigned fHasValues : 1;                // set if 'values' passed instead of 'to'
+       unsigned fMirror : 1;
+       unsigned fReset : 1;
+       unsigned fResetPending : 1;
+       unsigned fTargetIsScope : 1;
+private:
+       typedef SkDisplayable INHERITED;
+       friend class SkActive;
+       friend class SkApply;
+       friend class SkDisplayList;
+};
+
+#endif // SkAnimateBase_DEFINED
diff --git a/libs/graphics/animator/SkAnimateField.cpp b/libs/graphics/animator/SkAnimateField.cpp
new file mode 100644 (file)
index 0000000..b2b6355
--- /dev/null
@@ -0,0 +1,113 @@
+#include "SkAnimate.h"
+#include "SkAnimateMaker.h"
+#include "SkDrawable.h"
+#include "SkParse.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkAnimate::fInfo[] = {
+       SK_MEMBER_INHERITED
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkAnimate);
+
+SkAnimate::SkAnimate() : fComponents(0) {
+}
+
+SkAnimate::~SkAnimate() {
+}
+
+int SkAnimate::components() { 
+       return fComponents; 
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkAnimate::dump(SkAnimateMaker* maker) {
+       INHERITED::dump(maker); //from animateBase
+    //SkSet inherits from this class
+       if (getType() != SkType_Set) {
+        if (fMirror)
+            SkDebugf("mirror=\"true\" ");
+        if (fReset)
+            SkDebugf("reset=\"true\" ");
+#ifdef SK_CAN_USE_FLOAT
+               SkDebugf("dur=\"%g\" ", SkScalarToFloat(SkScalarDiv(dur,1000)));
+               if (repeat != SK_Scalar1)
+                       SkDebugf("repeat=\"%g\" ", SkScalarToFloat(repeat));
+#else
+               SkDebugf("dur=\"%x\" ", SkScalarDiv(dur,1000));
+               if (repeat != SK_Scalar1)
+                       SkDebugf("repeat=\"%x\" ", repeat);
+#endif
+        //if (fHasValues)
+        //    SkDebugf("values=\"%s\" ", values);
+        if (blend.count() != 1 || blend[0] != SK_Scalar1) {
+            SkDebugf("blend=\"[");
+            bool firstElem = true;
+            for (int i = 0; i < blend.count(); i++) {
+                if (!firstElem) 
+                    SkDebugf(",");
+                firstElem = false;
+#ifdef SK_CAN_USE_FLOAT
+                SkDebugf("%g", SkScalarToFloat(blend[i]));
+#else
+                SkDebugf("%x", blend[i]);
+#endif
+            }
+            SkDebugf("]\" ");
+        }
+        SkDebugf("/>\n");//i assume that if it IS, we will do it separately
+       }
+}
+#endif
+
+bool SkAnimate::resolveCommon(SkAnimateMaker& maker) {
+       if (fTarget == nil)     // if nil, recall onEndElement after apply closes and sets target to scope
+               return false;
+       INHERITED::onEndElement(maker);
+       return maker.hasError() == false;
+}
+
+void SkAnimate::onEndElement(SkAnimateMaker& maker) {
+       bool resolved = resolveCommon(maker);
+       if (resolved && fFieldInfo == nil) {
+               maker.setErrorNoun(field);
+               maker.setErrorCode(SkDisplayXMLParserError::kFieldNotInTarget);
+       }
+       if (resolved == false || fFieldInfo == nil)
+               return;
+       SkDisplayTypes outType = fFieldInfo->getType();
+       if (fHasValues) {
+               SkASSERT(to.size() > 0);
+               fFieldInfo->setValue(maker, &fValues, 0, 0, nil, outType, to);
+               SkASSERT(0);
+               // !!! this needs to set fComponents 
+               return;
+       }
+       fComponents = fFieldInfo->getCount();
+       if (fFieldInfo->fType == SkType_Array) {
+               SkTypedArray* array = (SkTypedArray*) fFieldInfo->memberData(fTarget);
+               int count = array->count();
+               if (count > 0)
+                       fComponents = count;
+       }
+       if (outType == SkType_ARGB) {
+               fComponents <<= 2;      // four color components
+               outType = SkType_Float;
+       }
+       fValues.setType(outType);
+       if (formula.size() > 0){
+               fComponents = 1;
+               from.set("0");
+               to.set("dur");
+               outType = SkType_MSec;
+       }
+       int max = fComponents * 2;
+       fValues.setCount(max);
+       memset(fValues.begin(), 0, max * sizeof(fValues.begin()[0]));
+       fFieldInfo->setValue(maker, &fValues, fFieldOffset, max, this, outType, from);
+       fFieldInfo->setValue(maker, &fValues, fComponents + fFieldOffset, max, this, outType, to);
+}
+
diff --git a/libs/graphics/animator/SkAnimateMaker.cpp b/libs/graphics/animator/SkAnimateMaker.cpp
new file mode 100644 (file)
index 0000000..e66f7df
--- /dev/null
@@ -0,0 +1,356 @@
+#include "SkAnimateMaker.h"
+#include "SkAnimator.h"
+#include "SkAnimatorScript.h"
+#include "SkDisplayable.h"
+#include "SkDisplayApply.h"
+#include "SkDisplayList.h"
+#include "SkDisplayMovie.h"
+#include "SkDisplayType.h"
+#include "SkExtras.h"
+#include "SkMemberInfo.h"
+#include "SkStream.h"
+#include "SkSystemEventTypes.h"
+#include "SkTime.h"
+
+class DefaultTimeline : public SkAnimator::Timeline {
+       virtual SkMSec getMSecs() const {
+               return SkTime::GetMSecs();
+       }
+} gDefaultTimeline;
+
+SkAnimateMaker::SkAnimateMaker(SkAnimator* animator, SkCanvas* canvas, SkPaint* paint)
+       : fActiveEvent(NULL), fAdjustedStart(0), fCanvas(canvas), fEnableTime(0), 
+               fHostEventSinkID(0), fMinimumInterval((SkMSec) -1), fPaint(paint), fParentMaker(NULL),
+               fTimeline(&gDefaultTimeline), fInInclude(false), fInMovie(false),
+               fFirstScriptError(false), fLoaded(false), fIDs(256), fAnimator(animator)
+{
+       fScreenplay.time = 0;
+#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
+       fDebugTimeBase = (SkMSec) -1;
+#endif
+#ifdef SK_DUMP_ENABLED
+       fDumpEvents = fDumpGConditions = fDumpPosts = false;
+#endif
+}
+
+SkAnimateMaker::~SkAnimateMaker() {
+       deleteMembers();
+}
+
+#if 0
+SkMSec SkAnimateMaker::adjustDelay(SkMSec expectedBase, SkMSec delay) {
+       SkMSec appTime = (*fTimeCallBack)();
+       if (appTime)
+               delay -= appTime - expectedBase;
+       if (delay < 0)
+               delay = 0;
+       return delay;
+}
+#endif
+
+void SkAnimateMaker::appendActive(SkActive* active) {
+       fDisplayList.append(active);
+}
+
+void SkAnimateMaker::clearExtraPropertyCallBack(SkDisplayTypes type) {
+       SkExtras** end = fExtras.end();
+       for (SkExtras** extraPtr = fExtras.begin(); extraPtr < end; extraPtr++) {
+               SkExtras* extra = *extraPtr;
+               if (extra->definesType(type)) {
+                       extra->fExtraCallBack = NULL;
+                       extra->fExtraStorage = NULL;
+                       break;
+               }
+       }
+}
+
+bool SkAnimateMaker::computeID(SkDisplayable* displayable, SkDisplayable* parent, SkString* newID) {
+       const char* script;
+  if (findKey(displayable, &script) == false)
+               return true;
+       return SkAnimatorScript::EvaluateString(*this, displayable, parent, script, newID);
+}
+
+SkDisplayable* SkAnimateMaker::createInstance(const char name[], size_t len) {
+       SkDisplayTypes type = SkDisplayType::GetType(this, name, len );
+       if ((int)type >= 0) 
+               return SkDisplayType::CreateInstance(this, type);
+       return NULL;
+}
+
+// differs from SkAnimator::decodeStream in that it does not reset error state
+bool SkAnimateMaker::decodeStream(SkStream* stream)
+{
+       SkDisplayXMLParser parser(*this);
+       return parser.parse(*stream);
+}
+
+// differs from SkAnimator::decodeURI in that it does not set URI base
+bool SkAnimateMaker::decodeURI(const char uri[]) {
+//     SkDebugf("animator decode %s\n", uri);
+       SkStream* stream = SkStream::GetURIStream(fPrefix.c_str(), uri);
+       SkAutoTDelete<SkStream> autoDel(stream);
+       bool success = decodeStream(stream);
+       if (hasError() && fError.hasNoun() == false)
+               fError.setNoun(uri);
+       return success;
+}
+
+#if defined SK_DEBUG && 0
+//used for the if'd out section of deleteMembers
+#include "SkTSearch.h"
+
+extern "C" {
+       int compare_disp(const void* a, const void* b) {
+               return *(const SkDisplayable**)a - *(const SkDisplayable**)b;
+       }
+}
+#endif
+
+void SkAnimateMaker::delayEnable(SkApply* apply, SkMSec time) {
+       int index = fDelayed.find(apply);
+       if (index < 0)
+               *fDelayed.append() = apply;
+       (new SkEvent(SK_EventType_Delay))->postTime(fAnimator->getSinkID(), time);
+}
+
+void SkAnimateMaker::deleteMembers() {
+       int index;
+#if defined SK_DEBUG && 0
+       //this code checks to see if helpers are among the children, but it is not complete -
+       //it should check the children of the children
+       int result;
+       SkTDArray<SkDisplayable*> children(fChildren.begin(), fChildren.count());
+       SkQSort(children.begin(), children.count(), sizeof(SkDisplayable*),compare_disp);
+       for (index = 0; index < fHelpers.count(); index++) {
+               SkDisplayable* helper = fHelpers[index];
+               result = SkTSearch(children.begin(), children.count(), helper, sizeof(SkDisplayable*));
+               SkASSERT(result < 0);
+       }
+#endif
+       for (index = 0; index < fChildren.count(); index++) {
+               SkDisplayable* child = fChildren[index];
+               delete child;
+       }
+       for (index = 0; index < fHelpers.count(); index++) {
+               SkDisplayable* helper = fHelpers[index];
+               delete helper;
+       }
+       for (index = 0; index < fExtras.count(); index++) {
+               SkExtras* extras = fExtras[index];
+               delete extras;
+       }
+}
+
+void SkAnimateMaker::doDelayedEvent() {
+       fEnableTime = getAppTime();
+       for (int index = 0; index < fDelayed.count(); ) {
+               SkDisplayable* child = fDelayed[index];
+               SkASSERT(child->isApply());
+               SkApply* apply = (SkApply*) child;
+               apply->interpolate(*this, fEnableTime);
+               if (apply->hasDelayedAnimator())
+                       index++;
+               else
+                       fDelayed.remove(index);
+       }
+}
+
+bool SkAnimateMaker::doEvent(const SkEvent& event) {
+       return (!fInMovie || fLoaded) && fAnimator->doEvent(event);
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkAnimateMaker::dump(const char* match) {
+               SkTDict<SkDisplayable*>::Iter iter(fIDs);
+               const char* name;
+               SkDisplayable* result;
+               while ((name = iter.next(&result)) != NULL) {
+                       if (strcmp(match,name) == 0)
+                result->dump(this);
+               }
+}
+#endif
+
+int SkAnimateMaker::dynamicProperty(SkString& nameStr, SkDisplayable** displayablePtr ) {
+       const char* name = nameStr.c_str();
+       const char* dot = strchr(name, '.');
+       SkASSERT(dot);
+       SkDisplayable* displayable;
+       if (find(name, dot - name, &displayable) == false) {
+               SkASSERT(0);
+               return 0;
+       }
+       const char* fieldName = dot + 1;
+       const SkMemberInfo* memberInfo = displayable->getMember(fieldName);
+       *displayablePtr = displayable;
+       return (int) memberInfo->fOffset;
+}
+
+SkMSec SkAnimateMaker::getAppTime() const {
+       return fTimeline->getMSecs();
+}
+
+#ifdef SK_DEBUG
+SkAnimator* SkAnimateMaker::getRoot()
+{
+       SkAnimateMaker* maker = this;
+       while (maker->fParentMaker)
+               maker = maker->fParentMaker;
+       return maker == this ? NULL : maker->fAnimator;
+}
+#endif
+
+void SkAnimateMaker::helperAdd(SkDisplayable* trackMe) {
+       SkASSERT(fHelpers.find(trackMe) < 0);
+       *fHelpers.append() = trackMe;
+}
+
+void SkAnimateMaker::helperRemove(SkDisplayable* alreadyTracked) {
+       int helperIndex = fHelpers.find(alreadyTracked);
+       if (helperIndex >= 0)
+               fHelpers.remove(helperIndex);
+}
+
+#if 0
+void SkAnimateMaker::loadMovies() {
+       for (SkDisplayable** dispPtr = fMovies.begin(); dispPtr < fMovies.end(); dispPtr++) {
+               SkDisplayable* displayable = *dispPtr;
+               SkASSERT(displayable->getType() == SkType_Movie);
+               SkDisplayMovie* movie = (SkDisplayMovie*) displayable;
+               SkAnimateMaker* movieMaker = movie->fMovie.fMaker;
+               movieMaker->fEvents.doEvent(*movieMaker, SkDisplayEvent::kOnload, NULL);
+               movieMaker->fEvents.removeEvent(SkDisplayEvent::kOnload, NULL);
+               movieMaker->loadMovies();
+       }
+}
+#endif
+
+void SkAnimateMaker::notifyInval() {
+       if (fHostEventSinkID)
+               fAnimator->onEventPost(new SkEvent(SK_EventType_Inval), fHostEventSinkID);
+}
+
+void SkAnimateMaker::notifyInvalTime(SkMSec time) {
+       if (fHostEventSinkID)
+               fAnimator->onEventPostTime(new SkEvent(SK_EventType_Inval), fHostEventSinkID, time);
+}
+
+void SkAnimateMaker::postOnEnd(SkAnimateBase* animate, SkMSec end) {
+               SkEvent evt;
+               evt.setS32("time", animate->getStart() + end);
+               evt.setPtr("anim", animate);
+               evt.setType(SK_EventType_OnEnd);
+               SkEventSinkID sinkID = fAnimator->getSinkID();
+               fAnimator->onEventPost(new SkEvent(evt), sinkID);
+}
+
+void SkAnimateMaker::reset() {
+       deleteMembers();
+       fChildren.reset();
+       fHelpers.reset();
+       fIDs.reset();
+       fEvents.reset();
+       fDisplayList.hardReset();
+}
+
+void SkAnimateMaker::removeActive(SkActive* active) {
+       if (active == NULL)
+               return;
+       fDisplayList.remove(active);
+}
+
+bool SkAnimateMaker::resolveID(SkDisplayable* displayable, SkDisplayable* original) {
+       SkString newID;
+       bool success = computeID(original, NULL, &newID);
+       if (success)
+               setID(displayable, newID);
+       return success;
+}
+
+void SkAnimateMaker::setErrorString() {
+       fErrorString.reset();
+       if (fError.hasError()) {
+               SkString err;
+               if (fFileName.size() > 0)
+                       fErrorString.set(fFileName.c_str());
+               else
+                       fErrorString.set("screenplay error");
+               int line = fError.getLineNumber();
+               if (line >= 0) {
+                       fErrorString.append(", ");
+                       fErrorString.append("line ");
+                       fErrorString.appendS32(line);
+               }
+               fErrorString.append(": ");
+               fError.getErrorString(&err);
+               fErrorString.append(err);
+#if defined SK_DEBUG
+               SkDebugf("%s\n", fErrorString.c_str());
+#endif
+       } 
+}
+
+void SkAnimateMaker::setEnableTime(SkMSec appTime, SkMSec expectedTime) {
+#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
+       SkString debugOut;
+       SkMSec time = getAppTime();
+       debugOut.appendS32(time - fDebugTimeBase);
+       debugOut.append(" set enable old enable=");
+       debugOut.appendS32(fEnableTime - fDebugTimeBase);
+       debugOut.append(" old adjust=");
+       debugOut.appendS32(fAdjustedStart);
+       debugOut.append(" new enable=");
+       debugOut.appendS32(expectedTime - fDebugTimeBase);
+       debugOut.append(" new adjust=");
+       debugOut.appendS32(appTime - expectedTime);
+       SkDebugf("%s\n", debugOut.c_str());
+#endif
+       fAdjustedStart = appTime - expectedTime;
+       fEnableTime = expectedTime;
+       SkDisplayable** firstMovie = fMovies.begin();
+       SkDisplayable** endMovie = fMovies.end();
+       for (SkDisplayable** ptr = firstMovie; ptr < endMovie; ptr++) {
+               SkDisplayMovie* movie = (SkDisplayMovie*) *ptr;
+               movie->fMovie.fMaker->setEnableTime(appTime, expectedTime);
+       }
+}
+
+void SkAnimateMaker::setExtraPropertyCallBack(SkDisplayTypes type, 
+               SkScriptEngine::_propertyCallBack callBack, void* userStorage) {
+       SkExtras** end = fExtras.end();
+       for (SkExtras** extraPtr = fExtras.begin(); extraPtr < end; extraPtr++) {
+               SkExtras* extra = *extraPtr;
+               if (extra->definesType(type)) {
+                       extra->fExtraCallBack = callBack;
+                       extra->fExtraStorage = userStorage;
+                       break;
+               }
+       }
+}
+
+void SkAnimateMaker::setID(SkDisplayable* displayable, const SkString& newID) {
+       fIDs.set(newID.c_str(), displayable);
+#ifdef SK_DEBUG
+       displayable->_id.set(newID);
+       displayable->id = displayable->_id.c_str();
+#endif
+}
+
+void SkAnimateMaker::setScriptError(const SkScriptEngine& engine) {
+       SkString errorString;
+#ifdef SK_DEBUG
+       engine.getErrorString(&errorString);
+#endif
+       setErrorNoun(errorString);
+       setErrorCode(SkDisplayXMLParserError::kErrorInScript);
+}
+
+bool SkAnimateMaker::GetStep(const char* token, size_t len, void* stepPtr, SkScriptValue* value) {
+       if (SK_LITERAL_STR_EQUAL("step", token, len)) {
+               value->fOperand.fS32 = *(S32*) stepPtr;
+               value->fType = SkType_Int;
+               return true;
+       }
+       return false;
+}
diff --git a/libs/graphics/animator/SkAnimateMaker.h b/libs/graphics/animator/SkAnimateMaker.h
new file mode 100644 (file)
index 0000000..acc2c54
--- /dev/null
@@ -0,0 +1,153 @@
+#ifndef SkAnimateMaker_DEFINED
+#define SkAnimateMaker_DEFINED
+
+// #define SK_DEBUG_ANIMATION_TIMING
+
+#include "SkAnimator.h"
+#include "SkBitmap.h"
+#include "SkIntArray.h"
+#include "SkDisplayEvents.h"
+#include "SkDisplayList.h"
+#include "SkDisplayScreenplay.h"
+#include "SkDisplayXMLParser.h"
+#include "SkScript.h"
+#include "SkString.h"
+#include "SkTDict.h"
+
+// not sure where this little helper macro should go
+
+
+class SkActive;
+class SkAnimate;
+class SkCanvas;
+class SkDisplayable;
+class SkDrawable;
+class SkDump;
+class SkEvent;
+class SkEventSink;
+class SkExtras;
+class SkGroup;
+class SkPaint;
+class SkStream;
+
+class SkAnimateMaker {
+public:
+       SkAnimateMaker(SkAnimator* animator, SkCanvas* canvas, SkPaint* paint);
+       ~SkAnimateMaker();
+       void appendActive(SkActive* );
+       void childrenAdd(SkDisplayable* child) { *fChildren.append() = child; }
+       void clearExtraPropertyCallBack(SkDisplayTypes type);
+       bool computeID(SkDisplayable* displayable, SkDisplayable* parent, SkString* newID);
+       SkDisplayable* createInstance(const char name[], size_t len);
+       bool decodeStream(SkStream* stream);
+       bool decodeURI(const char uri[]);
+       void delayEnable(SkApply* apply, SkMSec time);
+       void doDelayedEvent();
+       bool doEvent(const SkEvent& event);
+#ifdef SK_DUMP_ENABLED
+       void dump(const char* match);
+#endif
+       int dynamicProperty(SkString& nameStr, SkDisplayable**  );
+       bool find(const char* str, SkDisplayable** displayablePtr) const { 
+               return fIDs.find(str, displayablePtr);
+       }
+       bool find(const char* str, size_t len, SkDisplayable** displayablePtr) const { 
+               return fIDs.find(str, len, displayablePtr);
+       }
+       bool findKey(SkDisplayable* displayable, const char** string) const {
+               return fIDs.findKey(displayable, string);
+       }
+//     bool find(SkString& string, SkDisplayable** displayablePtr) { 
+//             return fIDs.find(string.c_str(), displayablePtr);
+//     }
+       SkAnimator* getAnimator() { return fAnimator; }
+       SkMSec getAppTime() const; // call caller to get current time
+#ifdef SK_DEBUG
+       SkAnimator* getRoot();
+#endif
+       SkXMLParserError::ErrorCode getErrorCode() const { return fError.getErrorCode(); }
+       SkMSec getInTime() { return fDisplayList.getTime(); }
+       int getNativeCode() const { return fError.getNativeCode(); }
+       bool hasError() { return fError.hasError(); }
+       void helperAdd(SkDisplayable* trackMe);
+       void helperRemove(SkDisplayable* alreadyTracked);
+       void idsSet(const char* attrValue, size_t len, SkDisplayable* displayable) { 
+               fIDs.set(attrValue, len, displayable); }
+//     void loadMovies();
+       void notifyInval();
+       void notifyInvalTime(SkMSec time);
+       void postOnEnd(SkAnimateBase* animate, SkMSec end);
+       void removeActive(SkActive* );
+       void reset();
+       bool resolveID(SkDisplayable* displayable, SkDisplayable* original);
+       void setEnableTime(SkMSec appTime, SkMSec expectedTime);
+       void setErrorCode(SkXMLParserError::ErrorCode err) { if (fError.hasError() == false) fError.INHERITED::setCode(err); }
+       void setErrorCode(SkDisplayXMLParserError::ErrorCode err) { if (fError.hasError() == false) fError.setCode(err); }
+       void setErrorNoun(const SkString& str) { if (fError.hasError() == false) fError.setNoun(str); }
+       void setErrorString();
+       void setExtraPropertyCallBack(SkDisplayTypes type, SkScriptEngine::_propertyCallBack , void* userStorage);
+       void setID(SkDisplayable* displayable, const SkString& newID);
+       void setInnerError(SkAnimateMaker* maker, const SkString& str) { fError.setInnerError(maker, str); }
+       void setScriptError(const SkScriptEngine& );
+#ifdef SK_DEBUG
+       void validate() { fDisplayList.validate(); }
+#else
+       void validate() {}
+#endif
+       SkDisplayEvent* fActiveEvent;
+       SkMSec fAdjustedStart;
+       SkBitmap fBitmap;
+       SkCanvas* fCanvas;
+       SkMSec fEnableTime;
+       int fEndDepth;  // passed parameter to onEndElement
+       SkEvents fEvents;
+       SkDisplayList fDisplayList;
+       SkEventSinkID fHostEventSinkID;
+       SkMSec fMinimumInterval;
+       SkPaint* fPaint;
+       SkAnimateMaker* fParentMaker;
+       SkString fPrefix;
+       SkDisplayScreenplay fScreenplay;
+       const SkAnimator::Timeline* fTimeline;
+    SkBool8 fInInclude;
+       SkBool8 fInMovie;
+       SkBool8 fFirstScriptError;
+#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
+       SkMSec fDebugTimeBase;
+#endif
+#ifdef SK_DUMP_ENABLED
+       SkString fDumpAnimated;
+       SkBool8 fDumpEvents;
+       SkBool8 fDumpGConditions;
+       SkBool8 fDumpPosts;
+#endif
+private:
+       void deleteMembers();
+       static bool GetStep(const char* token, size_t len, void* stepPtr, SkScriptValue* );
+       SkAnimateMaker& operator=(SkAnimateMaker& );
+       SkTDDisplayableArray fChildren;
+       SkTDDisplayableArray fDelayed; // SkApply that contain delayed enable events
+       SkDisplayXMLParserError fError;
+       SkString fErrorString;
+       SkTDArray<SkExtras*> fExtras;
+       SkString fFileName;
+       SkTDDisplayableArray fHelpers;  // helper displayables
+       SkBool8 fLoaded;
+       SkTDDisplayableArray fMovies;
+       SkTDict<SkDisplayable*> fIDs;
+       SkAnimator* fAnimator;
+       friend class SkAdd;
+       friend class SkAnimateBase;
+       friend class SkDisplayXMLParser;
+       friend class SkAnimator;
+       friend class SkAnimatorScript;
+       friend class SkApply;
+       friend class SkDisplayMovie;
+       friend class SkDisplayType;
+       friend class SkEvents;
+       friend class SkGroup;
+       friend struct SkMemberInfo;
+};
+
+#endif // SkAnimateMaker_DEFINED
+
diff --git a/libs/graphics/animator/SkAnimateProperties.h b/libs/graphics/animator/SkAnimateProperties.h
new file mode 100644 (file)
index 0000000..17bc777
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef SkAnimateProperties_DEFINED
+#define SkAnimateProperties_DEFINED
+
+enum SkAnimateBase_Properties {
+       SK_PROPERTY(dynamic),
+       SK_PROPERTY(mirror),
+       SK_PROPERTY(reset),
+       SK_PROPERTY(step),
+       SK_PROPERTY(values)
+};
+
+#endif // SkAnimateProperties_DEFINED
diff --git a/libs/graphics/animator/SkAnimateSchema.xsd b/libs/graphics/animator/SkAnimateSchema.xsd
new file mode 100644 (file)
index 0000000..2c75eb4
--- /dev/null
@@ -0,0 +1,2787 @@
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
+xmlns:Sk="urn:screenplay" targetNamespace="urn:screenplay">
+
+       <!-- /** Animate
+               An ID of an element of type <animate> or <set> 
+       */ -->
+       <xs:simpleType name="Animate">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+
+       <!-- /** 3D_Point
+               An array of three floats in ECMAScript notation: [x, y, z].
+       */ -->
+       <xs:simpleType name="3D_Point">
+               <xs:restriction base="xs:string">
+                       <xs:pattern value="[+-]?([0-9]*\.[0-9]+|[0-9]+\.?)( *, *[+-]?([0-9]*\.[0-9]+|[0-9]+\.?)){2}" /> 
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** ARGB
+               The red, green, blue, and optional alpha color components.
+       */ -->
+       <xs:simpleType name="ARGB">
+               <xs:restriction base="xs:string">
+               <!-- @pattern #[0-9a-fA-F]{3} #rgb contains three hexadecimal digits. #rgb is equivalent to 0xFFrrggbb. -->
+                       <xs:pattern value="#[0-9a-fA-F]{3}"/>
+               <!-- @pattern #[0-9a-fA-F]{4} #argb contains four hexadecimal digits. #argb is equivalent to 0xaarrggbb. -->
+                       <xs:pattern value="#[0-9a-fA-F]{4}"/>
+               <!-- @pattern #[0-9a-fA-F]{6} #rrggbb contains six hexadecimal digits. #rrggbb is equivalent to 0xFFrrggbb. -->
+                       <xs:pattern value="#[0-9a-fA-F]{6}"/>
+               <!-- @pattern #[0-9a-fA-F]{8} #aarrggbb contains eight hexadecimal digits. #aarrggbb is equivalent to 0xaarrggbb. -->
+                       <xs:pattern value="#[0-9a-fA-F]{8}"/>
+               <!-- @pattern 0[xX][0-9a-fA-F]{8} 0xaarrggbb describes the color as a packed hexadecimal; each pair of digits 
+                       corresponds to alpha, red, green, and blue respectively. -->
+                       <xs:pattern value="0[xX][0-9a-fA-F]{8}"/>
+               <!-- @pattern rgb\(\d+{1,3},\d+{1,3},\d+{1,3}\) rgb(r, g, b) describes color with three integers ranging from 0 to 255, 
+                       corresponding to red, green, and blue respectively. -->
+                       <xs:pattern value="rgb\(\d+{1,3},\d+{1,3},\d+{1,3}\)"/>
+               <!-- @patternList Color can be described by the following standard CSS color names. -->
+                       <xs:pattern value="aliceblue"/>
+                       <xs:pattern value="antiquewhite"/>
+                       <xs:pattern value="aqua"/>
+                       <xs:pattern value="aquamarine"/>
+                       <xs:pattern value="azure"/>
+                       <xs:pattern value="beige"/>
+                       <xs:pattern value="bisque"/>
+                       <xs:pattern value="black"/>
+                       <xs:pattern value="blanchedalmond"/>
+                       <xs:pattern value="blue"/>
+                       <xs:pattern value="blueviolet"/>
+                       <xs:pattern value="brown"/>
+                       <xs:pattern value="burlywood"/>
+                       <xs:pattern value="cadetblue"/>
+                       <xs:pattern value="chartreuse"/>
+                       <xs:pattern value="chocolate"/>
+                       <xs:pattern value="coral"/>
+                       <xs:pattern value="cornflowerblue"/>
+                       <xs:pattern value="cornsilk"/>
+                       <xs:pattern value="crimson"/>
+                       <xs:pattern value="cyan"/>
+                       <xs:pattern value="darkblue"/>
+                       <xs:pattern value="darkcyan"/>
+                       <xs:pattern value="darkgoldenrod"/>
+                       <xs:pattern value="darkgray"/>
+                       <xs:pattern value="darkgreen"/>
+                       <xs:pattern value="darkkhaki"/>
+                       <xs:pattern value="darkmagenta"/>
+                       <xs:pattern value="darkolivegreen"/>
+                       <xs:pattern value="darkorange"/>
+                       <xs:pattern value="darkorchid"/>
+                       <xs:pattern value="darkred"/>
+                       <xs:pattern value="darksalmon"/>
+                       <xs:pattern value="darkseagreen"/>
+                       <xs:pattern value="darkslateblue"/>
+                       <xs:pattern value="darkslategray"/>
+                       <xs:pattern value="darkturquoise"/>
+                       <xs:pattern value="darkviolet"/>
+                       <xs:pattern value="deeppink"/>
+                       <xs:pattern value="deepskyblue"/>
+                       <xs:pattern value="dimgray"/>
+                       <xs:pattern value="dodgerblue"/>
+                       <xs:pattern value="firebrick"/>
+                       <xs:pattern value="floralwhite"/>
+                       <xs:pattern value="forestgreen"/>
+                       <xs:pattern value="fuchsia"/>
+                       <xs:pattern value="gainsboro"/>
+                       <xs:pattern value="ghostwhite"/>
+                       <xs:pattern value="gold"/>
+                       <xs:pattern value="goldenrod"/>
+                       <xs:pattern value="gray"/>
+                       <xs:pattern value="green"/>
+                       <xs:pattern value="greenyellow"/>
+                       <xs:pattern value="honeydew"/>
+                       <xs:pattern value="hotpink"/>
+                       <xs:pattern value="indianred"/>
+                       <xs:pattern value="indigo"/>
+                       <xs:pattern value="ivory"/>
+                       <xs:pattern value="khaki"/>
+                       <xs:pattern value="lavender"/>
+                       <xs:pattern value="lavenderblush"/>
+                       <xs:pattern value="lawngreen"/>
+                       <xs:pattern value="lemonchiffon"/>
+                       <xs:pattern value="lightblue"/>
+                       <xs:pattern value="lightcoral"/>
+                       <xs:pattern value="lightcyan"/>
+                       <xs:pattern value="lightgoldenrodyellow"/>
+                       <xs:pattern value="lightgreen"/>
+                       <xs:pattern value="lightgrey"/>
+                       <xs:pattern value="lightpink"/>
+                       <xs:pattern value="lightsalmon"/>
+                       <xs:pattern value="lightseagreen"/>
+                       <xs:pattern value="lightskyblue"/>
+                       <xs:pattern value="lightslategray"/>
+                       <xs:pattern value="lightsteelblue"/>
+                       <xs:pattern value="lightyellow"/>
+                       <xs:pattern value="lime"/>
+                       <xs:pattern value="limegreen"/>
+                       <xs:pattern value="linen"/>
+                       <xs:pattern value="magenta"/>
+                       <xs:pattern value="maroon"/>
+                       <xs:pattern value="mediumaquamarine"/>
+                       <xs:pattern value="mediumblue"/>
+                       <xs:pattern value="mediumorchid"/>
+                       <xs:pattern value="mediumpurple"/>
+                       <xs:pattern value="mediumseagreen"/>
+                       <xs:pattern value="mediumslateblue"/>
+                       <xs:pattern value="mediumspringgreen"/>
+                       <xs:pattern value="mediumturquoise"/>
+                       <xs:pattern value="mediumvioletred"/>
+                       <xs:pattern value="midnightblue"/>
+                       <xs:pattern value="mintcream"/>
+                       <xs:pattern value="mistyrose"/>
+                       <xs:pattern value="moccasin"/>
+                       <xs:pattern value="navajowhite"/>
+                       <xs:pattern value="navy"/>
+                       <xs:pattern value="oldlace"/>
+                       <xs:pattern value="olive"/>
+                       <xs:pattern value="olivedrab"/>
+                       <xs:pattern value="orange"/>
+                       <xs:pattern value="orangered"/>
+                       <xs:pattern value="orchid"/>
+                       <xs:pattern value="palegoldenrod"/>
+                       <xs:pattern value="palegreen"/>
+                       <xs:pattern value="paleturquoise"/>
+                       <xs:pattern value="palevioletred"/>
+                       <xs:pattern value="papayawhip"/>
+                       <xs:pattern value="peachpuff"/>
+                       <xs:pattern value="peru"/>
+                       <xs:pattern value="pink"/>
+                       <xs:pattern value="plum"/>
+                       <xs:pattern value="powderblue"/>
+                       <xs:pattern value="purple"/>
+                       <xs:pattern value="red"/>
+                       <xs:pattern value="rosybrown"/>
+                       <xs:pattern value="royalblue"/>
+                       <xs:pattern value="saddlebrown"/>
+                       <xs:pattern value="salmon"/>
+                       <xs:pattern value="sandybrown"/>
+                       <xs:pattern value="seagreen"/>
+                       <xs:pattern value="seashell"/>
+                       <xs:pattern value="sienna"/>
+                       <xs:pattern value="silver"/>
+                       <xs:pattern value="skyblue"/>
+                       <xs:pattern value="slateblue"/>
+                       <xs:pattern value="slategray"/>
+                       <xs:pattern value="snow"/>
+                       <xs:pattern value="springgreen"/>
+                       <xs:pattern value="steelblue"/>
+                       <xs:pattern value="tan"/>
+                       <xs:pattern value="teal"/>
+                       <xs:pattern value="thistle"/>
+                       <xs:pattern value="tomato"/>
+                       <xs:pattern value="turquoise"/>
+                       <xs:pattern value="violet"/>
+                       <xs:pattern value="wheat"/>
+                       <xs:pattern value="white"/>
+                       <xs:pattern value="whitesmoke"/>
+                       <xs:pattern value="yellow"/>
+               <!--@patternListLast -->
+                       <xs:pattern value="yellowgreen"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** AddMode
+               AddMode controls how the add element adds its referenced element to the 
+               display list. By default, the referenced element remains in the add element
+               so that the add element's use attribute may be animated to change the 
+               element it refers to. Setting the mode attribute to "immediate" causes the 
+               add element to put the referenced element in the display list directly. 
+               The move and replace elements are not affected by the mode attribute;
+               they always move or replace the referenced element directly.
+       */ -->
+       <xs:simpleType name="AddMode">
+               <xs:restriction base="xs:string">
+                       <!-- @pattern immediate Puts the referenced element in the display list. -->
+                       <xs:pattern value="immediate"/>
+                       <!-- @pattern indirect Puts the containing element in the display list. -->
+                       <xs:pattern value="indirect"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** Align
+               Align places text to the left, center, or right of the text position.
+       */ -->
+       <xs:simpleType name="Align">
+               <xs:restriction base="xs:string">
+                       <!-- @pattern left The first character in the text string is drawn at the text position. -->
+                       <xs:pattern value="left"/>
+                       <!-- @pattern center The  text string is measured and centered on the text position. -->
+                       <xs:pattern value="center"/>
+                       <!-- @pattern right The last character in the text string is drawn to the left of the text position. -->
+                       <xs:pattern value="right"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** ApplyMode
+               ApplyMode affects how the apply element animates values.
+       */ -->
+       <xs:simpleType name="ApplyMode">
+               <xs:restriction base="xs:string">
+                       <!-- @pattern immediate Iterates through all animation values immediately. -->
+                       <xs:pattern value="immediate"/>
+                       <!-- @pattern once Performs the animation at once without adding the scope to
+                               the display list. -->
+                       <xs:pattern value="once"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** ApplyTransition
+               ApplyTransition affects how the apply element sets the time of the animators.
+       */ -->
+       <xs:simpleType name="ApplyTransition">
+               <xs:restriction base="xs:string">
+                       <!-- @pattern reverse Performs the animation in reverse. -->
+                       <xs:pattern value="reverse"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** Base64
+               Base64 describes 8 bit binary using 64 character values. 
+               See http://rfc.net/rfc2045.html for the base64 format.
+       */ -->
+       <xs:simpleType name="Base64">
+               <xs:restriction base="xs:string">
+                       <xs:pattern value="[A-Za-z0-9+/ ]+"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** BaseBitmap
+               A reference to an image like a JPEG, GIF, or PNG; or a reference to a bitmap element
+               that has been drawn into with a drawTo element.
+       */ -->
+       <xs:simpleType name="BaseBitmap">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+       
+       <!-- /** BitmapEncoding
+               Used to specify the compression format for writing an image file with the snapshot element.
+       */ -->
+       <xs:simpleType name="BitmapEncoding">
+               <xs:restriction base="xs:string">
+                       <!-- @pattern jpeg See http://www.jpeg.org/jpeg/ for more information about JPEG. -->
+                       <xs:pattern value="jpeg"/>
+                       <!-- @pattern png See http://www.libpng.org/pub/png/ for more information about PNG. -->
+                       <xs:pattern value="png"/>
+               </xs:restriction>
+       </xs:simpleType>
+
+       <!-- /** BitmapFormat
+               Determines the number of bits per pixel in a bitmap.
+       */ -->
+       <xs:simpleType name="BitmapFormat">
+               <xs:restriction base="xs:string">
+                       <xs:pattern value="none"/>
+                       <!-- @pattern A1 1-bit per pixel, (0 is transparent, 1 is opaque). -->
+                       <xs:pattern value="A1"/>
+                       <!-- @pattern A8 8-bits per pixel, with only alpha specified (0 is transparent, 0xFF is opaque). -->
+                       <xs:pattern value="A8"/>
+                       <!-- @pattern Index8 8-bits per pixel, using a ColorTable element to specify the colors. -->
+                       <xs:pattern value="Index8"/>
+                       <!-- @pattern RGB16 16-bits per pixel, compile-time configured to be either 555 or 565. -->
+                       <xs:pattern value="RGB16"/>
+                       <!-- @pattern RGB32 32-bits per pixel, plus alpha. -->
+                       <xs:pattern value="RGB32"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** Boolean
+               Either "true" (non-zero) or "false" (zero). 
+       */ -->
+       <xs:simpleType name="Boolean">
+               <xs:restriction base="xs:string">
+                       <xs:pattern value="false"/>
+                       <xs:pattern value="true"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** Cap
+               The values for the strokeCap attribute. 
+       */ -->
+       <xs:simpleType name="Cap">
+               <xs:restriction base="xs:string">
+                       <!-- @pattern butt begin and end a contour with no extension -->
+                       <xs:pattern value="butt"/>
+                       <!-- @pattern round begin and end a contour with a semi-circle extension -->
+                       <xs:pattern value="round"/>
+                       <!-- @pattern  square begin and end a contour with a half square extension -->
+                       <xs:pattern value="square"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** Color
+               A reference to a color element. 
+       */ -->
+       <xs:simpleType name="Color">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+       
+       <!-- /** Displayable
+               A reference to any element: @list(Displayable)
+       */ -->
+       <xs:simpleType name="Displayable">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+
+       <!-- /** DisplayableArray
+               An array of one or more element IDs.
+       */ -->
+       <xs:simpleType name="DisplayableArray">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+
+       <!-- /** Drawable
+               A reference to an element that can be drawn: @list(Drawable)
+       */ -->
+       <xs:simpleType name="Drawable">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+
+       <!-- /** DynamicString
+               Dynamic strings contain scripts that are re-evaluated each time the script is enabled.
+       */ -->
+       <xs:simpleType name="DynamicString">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+       
+       <!-- /** EventCode
+               Key codes that can trigger events, usually corresponding to physical buttons on the device.
+       */ -->
+       <xs:simpleType name="EventCode">
+               <xs:restriction base="xs:string">
+                       <xs:pattern value="none"/>
+                       <!-- @pattern up The up arrow. -->
+                       <xs:pattern value="up"/>
+                       <!-- @pattern down The down arrow. -->
+                       <xs:pattern value="down"/>
+                       <!-- @pattern left The left arrow. -->
+                       <xs:pattern value="left"/>
+                       <!-- @pattern right The right arrow. -->
+                       <xs:pattern value="right"/>
+                       <!-- @pattern back The back button (may not be present; the Backspace key on a PC). -->
+                       <xs:pattern value="back"/>
+                       <!-- @pattern end The end button (may not be present; the Esc key on a PC). -->
+                       <xs:pattern value="end"/>
+                       <!-- @pattern OK The OK button (the Enter key on a PC). -->
+                       <xs:pattern value="OK"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** EventKind
+               Specifies how an event is triggered; by a key, when an animation ends, when the 
+               document is loaded, or when this event is triggered by the user's C++ or XML.
+       */ -->
+       <xs:simpleType name="EventKind">
+               <xs:restriction base="xs:string">
+                       <xs:pattern value="none"/>
+                       <!-- @pattern keyChar A key corresponding to a Unichar value. -->
+                       <xs:pattern value="keyChar"/>
+                       <!-- @pattern keyPress A key with a particular function, such as an arrow key or the OK button. -->
+                       <xs:pattern value="keyPress"/>
+                       <!-- @pattern mouseDown Triggered when the primary mouse button is pressed. -->
+                       <xs:pattern value="mouseDown"/>
+                       <!-- @pattern mouseDrag Triggered when the primary mouse is moved while the button is pressed. -->
+                       <xs:pattern value="mouseDrag"/>
+                       <!-- @pattern mouseMove Triggered when the primary mouse is moved. -->
+                       <xs:pattern value="mouseMove"/>
+                       <!-- @pattern mouseUp Triggered when the primary mouse button is released. -->
+                       <xs:pattern value="mouseUp"/>
+                       <!-- @pattern onEnd Triggered when an event ends. -->
+                       <xs:pattern value="onEnd"/>
+                       <!-- @pattern onLoad Triggered when the document loads. -->
+                       <xs:pattern value="onLoad"/>
+                       <!-- @pattern user Triggered when a post element or C++ event is activated. -->
+                       <xs:pattern value="user"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** EventMode
+               Specifies whether the event is delivered immediately to matching event element or deferred to 
+               the application-wide event handler.
+       */ -->
+       <xs:simpleType name="EventMode">
+               <xs:restriction base="xs:string">
+                       <!-- @pattern deferred Process the event using the host's event queue. -->
+                       <xs:pattern value="deferred"/>
+                       <!-- @pattern immediate Activate the event element immediately. -->
+                       <xs:pattern value="immediate"/>
+               </xs:restriction>
+       </xs:simpleType>
+
+       <!-- /** FillType
+               Filled paths that self-intersect use the winding or evenOdd rule to determine whether the 
+               overlaps are filled or are holes.
+       */ -->
+       <xs:simpleType name="FillType">
+               <xs:restriction base="xs:string">
+                       <!-- @pattern winding Fill if the sum of edge directions is non-zero. -->
+                       <xs:pattern value="winding"/>
+                       <!-- @pattern evenOdd Fill if the sum of edges is an odd number. -->
+                       <xs:pattern value="evenOdd"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** FilterType
+               Scaled bitmaps without a filter type set point-sample the source bitmap to determine the
+               destination pixels' colors. Bilinear and bicubic compute the values of intermediate pixels
+               by sampling the pixels around them.
+       */ -->
+       <xs:simpleType name="FilterType">
+               <xs:restriction base="xs:string">
+                       <xs:pattern value="none"/>
+                       <!-- @pattern bilinear Compute the pixel value as the linear interpolation of adjacent pixels. -->
+                       <xs:pattern value="bilinear"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** Float
+               A signed fractional value.
+       */ -->
+       <xs:simpleType name="Float">
+               <xs:restriction base="xs:float">
+                       <xs:pattern value="[+-]?([0-9]*\.[0-9]+|[0-9]+\.?)"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** FloatArray
+               An array of one or more signed fractional values.
+       */ -->
+       <xs:simpleType name="FloatArray">
+               <xs:restriction base="xs:float">
+                       <xs:pattern value="\[[+-]?([0-9]*\.[0-9]+|[0-9]+\.?)( *, *[+-]?([0-9]*\.[0-9]+|[0-9]+\.?))*\]"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** FromPathMode
+               A matrix computed from an offset along a path may include the point's position, the angle 
+               tangent, or both. 
+               .
+       */ -->
+       <xs:simpleType name="FromPathMode">
+               <xs:restriction base="xs:string">
+                       <!-- @pattern normal Compute the matrix using the path's angle and position. -->
+                       <xs:pattern value="normal"/>
+                       <!-- @pattern angle Compute the matrix using only the path's angle. -->
+                       <xs:pattern value="angle"/>
+                       <!-- @pattern position Compute the matrix using only the path's position. -->
+                       <xs:pattern value="position"/>
+               </xs:restriction>
+       </xs:simpleType>
+
+       <!-- /** Int
+               A signed integer.
+       */ -->
+       <xs:simpleType name="Int">
+               <xs:restriction base="xs:integer"/>
+       </xs:simpleType>
+       
+       <!-- /** IntArray
+               An array of one or more signed integer values.
+       */ -->
+       <xs:simpleType name="IntArray">
+               <xs:restriction base="xs:integer">
+                       <xs:pattern value="\[[+-]?[0-9]+( *, *[+-]?[0-9]+)*\]"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** Join
+               The edges of thick lines in a path are joined by extending the outer edges to form a miter, 
+               or by adding a round circle at the intersection point, or by connecting the outer edges with a line 
+               to form a blunt joint.
+       */ -->
+       <xs:simpleType name="Join">
+               <xs:restriction base="xs:string">
+                       <!-- @pattern miter Extend the outer edges to form a miter. -->
+                       <xs:pattern value="miter"/>
+                       <!-- @pattern round Join the outer edges with a circular arc. -->
+                       <xs:pattern value="round"/>
+                       <!-- @pattern blunt Connect the outer edges with a line. -->
+                       <xs:pattern value="blunt"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** MaskFilterBlurStyle
+               A blur can affect the inside or outside part of the shape, or it can affect both. The shape
+               itself can be drawn solid, or can be invisible.
+       */ -->
+       <xs:simpleType name="MaskFilterBlurStyle">
+               <xs:restriction base="xs:string">
+                       <!-- @pattern normal Blur inside and outside. -->
+                       <xs:pattern value="normal"/>
+                       <!-- @pattern solid Solid inside, blur outside. -->
+                       <xs:pattern value="solid"/>
+                       <!-- @pattern outer Invisible inside, blur outside. -->
+                       <xs:pattern value="outer"/>
+                       <!-- @pattern inner Blur inside only.. -->
+                       <xs:pattern value="inner"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** MaskFilter
+               The ID of a blur or emboss element.
+       */ -->
+       <xs:simpleType name="MaskFilter">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+       
+       <!-- /** Matrix
+               The ID of a matrix element.
+       */ -->
+       <xs:simpleType name="Matrix">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+       
+       <!-- /** MSec
+               A fractional second with millisecond resolution.
+       */ -->
+       <xs:simpleType name="MSec">
+               <xs:restriction base="xs:float"/>
+       </xs:simpleType>
+       
+       <!-- /** Paint
+               The ID of a paint element.
+       */ -->
+       <xs:simpleType name="Paint">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+
+       <!-- /** Path
+               The ID of a path element.
+       */ -->
+       <xs:simpleType name="Path">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+       
+       <!-- /** PathDirection
+               PathDirection determines if the path is traveled clockwise or counterclockwise.
+       */ -->
+       <xs:simpleType name="PathDirection">
+               <xs:restriction base="xs:string">
+               <!-- @pattern cw The path is traveled clockwise. -->
+                       <xs:pattern value="cw"/>
+               <!-- @pattern ccw The path is traveled counterclockwise. -->
+                       <xs:pattern value="ccw"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** PathEffect
+               The ID of a dash or discrete element.
+       */ -->
+       <xs:simpleType name="PathEffect">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+       
+       <!-- /** Point
+               A pair of signed values representing the x and y coordinates of a point.
+       */ -->
+       <xs:simpleType name="Point">
+               <xs:restriction base="xs:string">
+                       <xs:pattern value="\[ *[+-]?([0-9]*\.[0-9]+|[0-9]+\.?) *[ ,] *[+-]?([0-9]*\.[0-9]+|[0-9]+\.?)\]"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** Rect
+               The ID of a rectangle element.
+       */ -->
+       <xs:simpleType name="Rect">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+       
+       <!-- /** Shader
+               The ID of a linear or radial gradient.
+       */ -->
+       <xs:simpleType name="Shader">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+       
+       <!-- /** String
+               A sequence of characters.
+       */ -->
+       <xs:simpleType name="String">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+       
+       <!-- /** Style
+               Geometry can be filled, stroked or both.
+       */ -->
+       <xs:simpleType name="Style">
+               <xs:restriction base="xs:string">
+               <!-- @pattern fill The interior of the geometry is filled with the paint's color. -->
+                       <xs:pattern value="fill"/>
+               <!-- @pattern stroke The outline of the geometry is stroked with the paint's color. -->
+                       <xs:pattern value="stroke"/>
+               <!-- @pattern strokeAndFill The interior is filled and outline is stroked with the paint's color. -->
+                       <xs:pattern value="strokeAndFill"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** Text
+               The ID of a text element.
+       */ -->
+       <xs:simpleType name="Text">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+       
+       <!-- /** TextBoxAlign
+               Multiple lines of text may be aligned to the start of the box, the center, or the end.
+       */ -->
+       <xs:simpleType name="TextBoxAlign">
+               <xs:restriction base="xs:string">
+               <!-- @pattern start The text begins within the upper left of the box. -->
+                       <xs:pattern value="start"/>
+               <!-- @pattern center The text is positioned in the center of the box. -->
+                       <xs:pattern value="center"/>
+               <!-- @pattern end The text ends within the lower right of the box. -->
+                       <xs:pattern value="end"/>
+               </xs:restriction>
+       </xs:simpleType>
+
+       <!-- /** TextBoxMode
+               Fitting the text may optionally introduce line breaks.
+       */ -->
+       <xs:simpleType name="TextBoxMode">
+               <xs:restriction base="xs:string">
+               <!-- @pattern oneLine No additional linebreaks are added. -->
+                       <xs:pattern value="oneLine"/>
+               <!-- @pattern lineBreak Line breaks may be added to fit the text to the box. -->
+                       <xs:pattern value="lineBreak"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** TileMode
+               A shader describes how to draw within a rectangle. 
+               Outside of the rectangle, the shader may be ignored, clamped on the edges, or repeated.
+               The repetitions may be mirrored from the original shader.
+       */ -->
+       <xs:simpleType name="TileMode">
+               <xs:restriction base="xs:string">
+               <!-- @pattern clamp The edge shader color is extended. -->
+                       <xs:pattern value="clamp"/>
+               <!-- @pattern repeat The shader is repeated horizontally and vertically. -->
+                       <xs:pattern value="repeat"/>
+               <!-- @pattern mirror The shader is mirrored horizontally and vertically. -->
+                       <xs:pattern value="mirror"/>
+               </xs:restriction>
+       </xs:simpleType>
+       
+       <!-- /** Typeface
+               The ID of a typeface element.
+       */ -->
+       <xs:simpleType name="Typeface">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+       
+       <!-- /** UnknownArray
+               An array of values of any type.
+       */ -->
+       <xs:simpleType name="UnknownArray">
+               <xs:restriction base="xs:string"/>
+       </xs:simpleType>
+
+       <!-- /** Xfermode
+               The operation applied when drawing a color to the destination background.
+       */ -->
+       <xs:simpleType name="Xfermode">
+               <xs:restriction base="xs:string">
+               <!-- @pattern clear Set the destination alpha to zero and the destination color to black. -->
+                       <xs:pattern value="clear"/>
+               <!-- @pattern src Set the destination to the source alpha and color. -->
+                       <xs:pattern value="src"/>
+               <!-- @pattern dst Set the destination to the destination alpha and color. -->
+                       <xs:pattern value="dst"/>
+               <!-- @pattern srcOver The default. Set the destination to the source color blended
+                       with the destination by the source alpha. -->
+                       <xs:pattern value="srcOver"/>
+               <!-- @pattern dstOver Set the destination to the destination color blended
+                       with the source by the destination alpha. -->
+                       <xs:pattern value="dstOver"/>
+               <!-- @pattern srcIn Set the destination to the source color scaled by the destination
+                       alpha. -->
+                       <xs:pattern value="srcIn"/>
+               <!-- @pattern dstIn Set the destination to the destination color scaled by the source
+                       alpha. -->
+                       <xs:pattern value="dstIn"/>
+               <!-- @pattern srcOut Set the destination to the source color scaled by the 
+                       inverse of the destination alpha. -->
+                       <xs:pattern value="srcOut"/>
+               <!-- @pattern dstOut Set the destination to the destination color scaled by the 
+                       inverse of the source alpha. -->
+                       <xs:pattern value="dstOut"/>
+               <!-- @pattern srcATop Set the destination to the source color times the destination alpha, 
+                       blended with the destination times the inverse of the source alpha. -->
+                       <xs:pattern value="srcATop"/>
+               <!-- @pattern dstATop Set the destination to the destination color times the source alpha, 
+                       blended with the source times the inverse of the destination alpha. -->
+                       <xs:pattern value="dstATop"/>
+               <!-- @pattern xor Set the destination to the destination color times the 
+                       inverse of the source alpha, 
+                       blended with the source times the inverse of the destination alpha. -->
+                       <xs:pattern value="xor"/>
+               </xs:restriction>
+       </xs:simpleType>
+
+       <!-- /** Math
+               Math provides functions and properties in the ECMAScript library to screenplay script expressions.
+               The Math element is always implicitly added at the top of every screenplay description, so
+               its functions and properties are always available.
+       */ -->
+       <xs:element name="Math">
+               <xs:complexType>
+                       <!-- @attribute E The value 2.718281828. -->
+                       <xs:attribute name="E" type="Sk:Float"/>
+                       <!-- @attribute LN10 The value 2.302585093. -->
+                       <xs:attribute name="LN10" type="Sk:Float"/>
+                       <!-- @attribute LN2 The value 0.693147181. -->
+                       <xs:attribute name="LN2" type="Sk:Float"/>
+                       <!-- @attribute LOG10E The value 0.434294482. -->
+                       <xs:attribute name="LOG10E" type="Sk:Float"/>
+                       <!-- @attribute LOG2E The value 1.442695041. -->
+                       <xs:attribute name="LOG2E" type="Sk:Float"/>
+                       <!-- @attribute PI The value 3.141592654. -->
+                       <xs:attribute name="PI" type="Sk:Float"/>
+                       <!-- @attribute SQRT1_2 The value 0.707106781. -->
+                       <xs:attribute name="SQRT1_2" type="Sk:Float"/>
+                       <!-- @attribute SQRT2 The value 1.414213562. -->
+                       <xs:attribute name="SQRT2" type="Sk:Float"/>
+                       <!-- @attribute abs A function that returns the absolute value of its argument. -->
+                       <xs:attribute name="abs" type="Sk:Float"/>
+                       <!-- @attribute acos A function that returns the arc cosine of its argument. -->
+                       <xs:attribute name="acos" type="Sk:Float"/>
+                       <!-- @attribute asin A function that returns the arc sine of its argument. -->
+                       <xs:attribute name="asin" type="Sk:Float"/>
+                       <!-- @attribute atan A function that returns the arc tan of its argument. -->
+                       <xs:attribute name="atan" type="Sk:Float"/>
+                       <!-- @attribute atan2 A function that returns the arc tan of the ratio of its two arguments. -->
+                       <xs:attribute name="atan2" type="Sk:Float"/>
+                       <!-- @attribute ceil A function that returns the rounded up value of its argument. -->
+                       <xs:attribute name="ceil" type="Sk:Float"/>
+                       <!-- @attribute cos A function that returns the cosine of its argument. -->
+                       <xs:attribute name="cos" type="Sk:Float"/>
+                       <!-- @attribute exp A function that returns E raised to a power (the argument). -->
+                       <xs:attribute name="exp" type="Sk:Float"/>
+                       <!-- @attribute floor A function that returns the rounded down value of its argument. -->
+                       <xs:attribute name="floor" type="Sk:Float"/>
+                       <!-- @attribute log A function that returns the natural logarithm its argument. -->
+                       <xs:attribute name="log" type="Sk:Float"/>
+                       <!-- @attribute max A function that returns the largest of any number of arguments. -->
+                       <xs:attribute name="max" type="Sk:Float"/>
+                       <!-- @attribute min A function that returns the smallest of any number of arguments. -->
+                       <xs:attribute name="min" type="Sk:Float"/>
+                       <!-- @attribute pow A function that returns the first argument raised to the power of the second argument. -->
+                       <xs:attribute name="pow" type="Sk:Float"/>
+                       <!-- @attribute random A function that returns a random value from zero to one.
+                               (See also the &lt;random&gt; element.) -->
+                       <xs:attribute name="random" type="Sk:Float"/>
+                       <!-- @attribute round A function that returns the rounded value of its argument. -->
+                       <xs:attribute name="round" type="Sk:Float"/>
+                       <!-- @attribute sin A function that returns the sine of its argument. -->
+                       <xs:attribute name="sin" type="Sk:Float"/>
+                       <!-- @attribute sqrt A function that returns the square root of its argument. -->
+                       <xs:attribute name="sqrt" type="Sk:Float"/>
+                       <!-- @attribute tan A function that returns the tangent of its argument. -->
+                       <xs:attribute name="tan" type="Sk:Float"/>      
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** Number
+               Number provides properties in the ECMAScript library to screenplay script expressions.
+               The Number element is always implicitly added at the top of every screenplay description, so
+               its properties are always available.
+       */ -->
+       <xs:element name="Number">
+               <xs:complexType>
+                       <!-- @attribute MAX_VALUE The maximum number value; approximately 32767.999985 fixed point, 
+                               3.4028235e+38 floating point. -->
+                       <xs:attribute name="MAX_VALUE" type="Sk:Float"/>
+                       <!-- @attribute MIN_VALUE The minimum number value; approximately 0.000015 fixed point, 
+                               1.1754944e-38 floating point. -->
+                       <xs:attribute name="MIN_VALUE" type="Sk:Float"/>
+                       <!-- @attribute NEGATIVE_INFINITY The most negative number value. Fixed point does not
+                               have a value for negative infinity, and approximates it with -32767.999985. -->
+                       <xs:attribute name="NEGATIVE_INFINITY" type="Sk:Float"/>
+                       <!-- @attribute NaN A bit pattern representing "Not a Number". Fixed point does not
+                               have a value for NaN, and approximates it with -32768. -->
+                       <xs:attribute name="NaN" type="Sk:Float"/>
+                       <!-- @attribute POSITIVE_INFINITY The greatest positive number value. Fixed point does not
+                               have a value for positive infinity, and approximates it with 32767.999985. -->
+                       <xs:attribute name="POSITIVE_INFINITY" type="Sk:Float"/>
+               </xs:complexType>
+       </xs:element>
+
+       <!-- /** add
+               Add references a drawable element, and adds it to the display list. 
+               If where and offset are omitted, the element is appended to the end of the display list.
+               If where is specified, the element is inserted at the first occurance of where in the display list.
+               If offset and where are specified, the element is inserted at where plus offset.
+               A positive offset without where inserts the element at the start of the list plus offset.
+               A negative offset without where inserts the element at the end of the list minus offset.
+       */ -->
+       <xs:element name="add">
+               <xs:complexType>
+                       <!-- @attribute mode If indirect (the default), keep the add element in the display list,
+                               and draw the add's use element. If immediate, put the add's use element in the display list. -->
+                       <xs:attribute name="mode" type="Sk:AddMode"/>
+                       <!-- @attribute offset The offset added to the insert index. -->
+                       <xs:attribute name="offset" type="Sk:Int"/>
+                       <!-- @attribute use The drawable element to add to the display list. -->
+                       <xs:attribute name="use" type="Sk:Drawable"/>
+                       <!-- @attribute where The drawable element marking where to insert. -->
+                       <xs:attribute name="where" type="Sk:Drawable"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** addCircle
+               AddCircle adds a closed circle to the parent path element. 
+       */ -->
+       <xs:element name="addCircle">
+               <xs:complexType>
+                       <!-- @attribute direction One of @pattern. @patternDescription -->
+                       <xs:attribute name="direction" type="Sk:PathDirection"/>
+                       <!-- @attribute radius The distance from the center to the edge of the circle. -->
+                       <xs:attribute name="radius" type="Sk:Float"/>
+                       <!-- @attribute x The x coordinate of the circle's center. -->
+                       <xs:attribute name="x" type="Sk:Float"/>
+                       <!-- @attribute y The y coordinate of the circle's center.-->
+                       <xs:attribute name="y" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** addOval
+               AddOval adds a closed oval described by its bounding box to the parent path element. 
+       */ -->
+       <xs:element name="addOval">
+               <xs:complexType>
+                       <!-- @attribute direction One of @pattern. @patternDescription -->
+                       <xs:attribute name="direction" type="Sk:PathDirection"/>
+                       <!-- @attribute bottom The bottom edge of the oval's bounding box. -->
+                       <xs:attribute name="bottom" type="Sk:Float"/>
+                       <!-- @attribute left The left edge of the oval's bounding box. -->
+                       <xs:attribute name="left" type="Sk:Float"/>
+                       <!-- @attribute right The right edge of the oval's bounding box. -->
+                       <xs:attribute name="right" type="Sk:Float"/>
+                       <!-- @attribute top The top edge of the oval's bounding box. -->
+                       <xs:attribute name="top" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** addPath
+               AddPath adds a path to the parent path element. 
+               An optional matrix may transform the path as it is added.
+       */ -->
+       <xs:element name="addPath">
+               <xs:complexType>
+                       <!-- @attribute matrix The matrix applied to the path as it is added.  -->
+                       <xs:attribute name="matrix" type="Sk:Matrix"/>
+                       <!-- @attribute path The path to add.  -->
+                       <xs:attribute name="path" type="Sk:Path"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** addRect
+               AddRect adds a closed rectangle to the parent path element. 
+       */ -->
+       <xs:element name="addRect">
+               <xs:complexType>
+                       <!-- @attribute direction One of @pattern. @patternDescription -->
+                       <xs:attribute name="direction" type="Sk:PathDirection"/>
+                       <!-- @attribute bottom The bottom edge of the rectangle. -->
+                       <xs:attribute name="bottom" type="Sk:Float"/>
+                       <!-- @attribute left The left edge of the rectangle. -->
+                       <xs:attribute name="left" type="Sk:Float"/>
+                       <!-- @attribute right The right edge of the rectangle. -->
+                       <xs:attribute name="right" type="Sk:Float"/>
+                       <!-- @attribute top" The top" edge of the rectangle. -->
+                       <xs:attribute name="top" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** addRoundRect
+               AddRoundRect adds a closed rounded rectangle to the parent path element. 
+       */ -->
+       <xs:element name="addRoundRect">
+               <xs:complexType>
+                       <!-- @attribute direction One of @pattern. @patternDescription -->
+                       <xs:attribute name="direction" type="Sk:PathDirection"/>
+                       <!-- @attribute bottom The bottom edge of the rounded rectangle's bounding box. -->
+                       <xs:attribute name="bottom" type="Sk:Float"/>
+                       <!-- @attribute left The left edge of the rounded rectangle's bounding box. -->
+                       <xs:attribute name="left" type="Sk:Float"/>
+                       <!-- @attribute right The right edge of the rounded rectangle's bounding box. -->
+                       <xs:attribute name="right" type="Sk:Float"/>
+                       <!-- @attribute top The top edge of the rounded rectangle's bounding box. -->
+                       <xs:attribute name="top" type="Sk:Float"/>
+                       <!-- @attribute rx The X-radius of the oval used to round the corners. -->
+                       <xs:attribute name="rx" type="Sk:Float"/>
+                       <!-- @attribute ry The Y-radius of the oval used to round the corners. -->
+                       <xs:attribute name="ry" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+               
+       <!-- /** animate
+               Animate varies the value of an element's attribute over time.
+               The animation may vary starting at the 'from' attribute, and ending at the 'to' attribute,
+               or may compute the value using the 'formula' attribute.
+       */ -->
+       <xs:element name="animate">
+               <xs:complexType>
+                       <!-- @attribute begin An optional offset that must elapse before the animation begins. The apply
+                               begin attribute is added to any animator's begin attribute. -->
+                       <xs:attribute name="begin" type="Sk:MSec"/>
+                       <!-- @attribute blend Specifies how the from and to values are blended. A value from 0.0 to
+                               1.0 specifies a cubic lag/log/lag blend (slow to change at the beginning and end); the closer
+                               blend is to 1.0, the more linear the blend. If omitted, the blend is linear. -->
+                       <xs:attribute name="blend" type="Sk:FloatArray"/>
+                       <!-- @attribute dur The duration of the animation in milliseconds. -->
+                       <xs:attribute name="dur" type="Sk:MSec"/>
+                       <!-- @attribute dynamic If true, restart the animation if any of the simple values the 'from', 'formula',
+                        'lval', or 'to' attributes reference are changed. Simple values are contained by the array, boolean, float, int, 
+                        and string elements. -->
+                       <xs:attribute name="dynamic" type="Sk:Boolean" />
+                       <!-- @attribute field The attribute to animate. -->
+                       <xs:attribute name="field" type="Sk:String"/>
+                       <!-- @attribute formula A script to execute over time to compute the field's value. Typically,
+                               the fomula is a script expression which includes a reference to the time attribute of the 
+                               containing apply        element.  Requires a dur.  For animations that do not stop, set dur="Number.POSITIVE_INFINITY" -->
+                       <xs:attribute name="formula" type="Sk:DynamicString"/>
+                       <!-- @attribute from The starting value (requires a 'to' attribute) -->
+                       <xs:attribute name="from" type="Sk:DynamicString"/>
+                       <!-- @attribute lval An expression evaluating to the attribute to animate.
+                               If present, lval overrides 'field'. The expression is typically an array element,
+                               e.g. lval="x[y]" . -->
+                       <xs:attribute name="lval" type="Sk:DynamicString"/>
+                       <!-- @attribute mirror If true, reverses the interpolated value during even repeat cycles. -->
+                       <xs:attribute name="mirror" type="Sk:Boolean"/>
+                       <!-- @attribute repeat Specifies the number of times to repeat the animation. 
+                               (May be fractional.)  -->
+                       <xs:attribute name="repeat" type="Sk:Float"/>
+                       <!-- @attribute reset  If true, the computed value is the initial value after the 
+                               animation is complete. If false, or by default, the computed value is the final value 
+                               after the animation is complete. -->
+                       <xs:attribute name="reset" type="Sk:Boolean"/>
+                       <!-- @attribute step When the apply's attribute mode="immediate" or "create", the step attribute can be read by 
+                               script to determine the current animation iteration.  -->
+                       <xs:attribute name="step" type="Sk:Int" />
+                       <!-- @attribute target The element to animate. By default, the element contained by the apply
+                               or referenced by the apply's scope attribute is the animate target. -->
+                       <xs:attribute name="target" type="Sk:DynamicString"/>
+                       <!-- @attribute to The ending value (requires a 'from' attribute) -->
+                       <xs:attribute name="to" type="Sk:DynamicString"/>
+                       <!-- @attribute values [Depreciated]  -->
+                       <xs:attribute name="values" type="Sk:DynamicString"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+               
+       <!-- /** apply
+               Apply changes one or more attributes of an element.
+               Apply either contains one displayable element or references the element scoping the change
+               with the 'scope' attribute. Apply either contains one animator element or references it with 
+               the 'animator' attribute.
+               In the display list, apply draws the element it scopes after evaluating the animation.
+       */ -->
+       <xs:element name="apply">
+               <xs:complexType>
+                       <xs:choice minOccurs="0" maxOccurs="1">
+                               <xs:element ref="Sk:animate"/>
+                               <xs:element ref="Sk:set" />
+               <!-- not quite right; want to say 'one of the above, one of the below'
+                       </xs:choice>
+                       <xs:choice minOccurs="0" maxOccurs="1">
+               -->
+                               <xs:element ref="Sk:add"/>
+                               <xs:element ref="Sk:array"/>
+                               <xs:element ref="Sk:apply"/>
+                               <xs:element ref="Sk:bitmap"/>
+                               <xs:element ref="Sk:boolean"/>
+                               <xs:element ref="Sk:bounds"/>
+               <!--            <xs:element ref="Sk3D:camera"/>    -->
+                               <xs:element ref="Sk:clear"/>
+                               <xs:element ref="Sk:clip"/>
+                               <xs:element ref="Sk:color"/>
+                               <xs:element ref="Sk:drawTo"/>
+                               <xs:element ref="Sk:float"/>
+                               <xs:element ref="Sk:full"/>
+                               <xs:element ref="Sk:group"/>
+                               <xs:element ref="Sk:image"/>
+                               <xs:element ref="Sk:int"/>
+                               <xs:element ref="Sk:line"/>
+                               <xs:element ref="Sk:matrix"/>
+                               <xs:element ref="Sk:move"/>
+                               <xs:element ref="Sk:oval"/>
+                               <xs:element ref="Sk:paint"/>
+                       <!--    <xs:element ref="Sk:patch"/>   -->
+                               <xs:element ref="Sk:path"/>
+                               <xs:element ref="Sk:point"/>
+                               <xs:element ref="Sk:polygon"/>
+                               <xs:element ref="Sk:polyline"/>
+                               <xs:element ref="Sk:post"/>
+                               <xs:element ref="Sk:random"/>
+                               <xs:element ref="Sk:rect"/>
+                               <xs:element ref="Sk:remove"/>
+                               <xs:element ref="Sk:replace"/>
+                               <xs:element ref="Sk:roundRect"/>
+                               <xs:element ref="Sk:save"/>
+                               <xs:element ref="Sk:snapshot"/>
+                               <xs:element ref="Sk:string"/>
+                               <xs:element ref="Sk:text"/>
+                               <xs:element ref="Sk:textBox"/>
+                               <xs:element ref="Sk:textOnPath"/>
+                               <xs:element ref="Sk:textToPath"/>
+                       </xs:choice>
+                       <!-- @attribute animator The description of how the element is changed over time. -->
+                       <xs:attribute name="animator" type="Sk:Animate"/>
+                       <!-- @attribute begin An optional offset that must elapse before the animation begins. The apply
+                               begin attribute is added to any animator's begin attribute. -->
+                       <xs:attribute name="begin" type="Sk:MSec" />
+                       <!-- @attribute dontDraw Edits an element's attribute without drawing it; for instance,
+                               to edit a clip's rectangle without drawing the rectangle, set dontDraw="true".  -->
+                       <xs:attribute name="dontDraw" type="Sk:Boolean"/>
+                       <!-- @attribute dynamicScope The location in the display list where animations are stored. Use 
+                       dynamicScope instead of scope if a script expression with potentially different values is desired to 
+                       describe the scope. -->
+                       <xs:attribute name="dynamicScope" type="Sk:String"/>
+                       <!-- @attribute interval The optional time interval from one animation frame to the next. -->
+                       <xs:attribute name="interval" type="Sk:MSec" />
+                       <!-- @attribute mode One of @pattern. @patternDescription  -->
+                       <xs:attribute name="mode" type="Sk:ApplyMode"/>
+                       <!-- @attribute pickup Starts the animation at the current target's attribute value. Enabling
+                               'pickup' permits omitting the 'from' attribute of the animator.  -->
+                       <xs:attribute name="pickup" type="Sk:Boolean"/>
+                       <!-- @attribute restore If true, multiple references to the same apply statement save and
+                               restore the interpolated target values.  -->
+                       <xs:attribute name="restore" type="Sk:Boolean"/>
+                       <!-- @attribute scope The location in the display list where animations are stored.  -->
+                       <xs:attribute name="scope" type="Sk:Drawable"/>
+                       <!-- @attribute step When mode="immediate" or "create", the step attribute can be read by 
+                               script to determine the current animation iteration.  -->
+                       <xs:attribute name="step" type="Sk:Int" />
+                       <!-- @attribute steps When mode="immediate", the number of times the animation
+                               is stepped. The animation iterates 'steps' times plus one.  -->
+                       <xs:attribute name="steps" type="Sk:Int" />
+                       <!-- @attribute time When read from script, returns the animation time. Typically used by
+                               an animate element's formula attribute.  -->
+                       <xs:attribute name="time" type="Sk:MSec" />
+                       <!-- @attribute transition One of @pattern. @patternDescription  -->
+                       <xs:attribute name="transition" type="Sk:ApplyTransition"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** array
+               Array contains an array of values of the same type. The values may be
+               numbers or strings.
+       */ -->
+       <xs:element name="array">
+               <xs:complexType>
+                       <!-- @attribute length The number of elements in the array (read only). -->
+                       <xs:attribute name="length" type="Sk:Int"/>
+                       <!-- @attribute values The elements in the array. -->
+                       <xs:attribute name="values" type="Sk:UnknownArray"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** bitmap
+               Bitmap describes a rectangle of pixels. 
+               Use the <drawTo> element to draw to a bitmap.
+               Add the bitmap to the display list to draw from a bitmap.  
+       */ -->
+       <xs:element name="bitmap">
+               <xs:complexType>
+                       <!-- @attribute erase The color, including the alpha, the bitmap is intially set to.  -->
+                       <xs:attribute name="erase" type="Sk:ARGB"/>
+                       <!-- @attribute format One of @pattern. @patternDescription  -->
+                       <xs:attribute name="format" type="Sk:BitmapFormat"/>
+                       <!-- @attribute height The height of the bitmap in pixels.  -->
+                       <xs:attribute name="height" type="Sk:Int"/>
+                       <!-- @attribute rowBytes The number of byte describing each row of pixels (optional).  -->
+                       <xs:attribute name="rowBytes" type="Sk:Int"/>
+                       <!-- @attribute  width The height of the width in pixels. -->
+                       <xs:attribute name="width" type="Sk:Int"/>
+                       <!-- @attribute x The left edge of the bitmap in unit space.  -->
+                       <xs:attribute name="x" type="Sk:Float"/>
+                       <!-- @attribute y The top edge of teh bitmap in unit space.  -->
+                       <xs:attribute name="y" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** bitmapShader
+               BitmapShader sets the paint shader to draw the bitmap as a texture. 
+       */ -->
+       <xs:element name="bitmapShader">
+               <xs:complexType>
+                       <xs:choice >
+                               <xs:element ref="Sk:image" minOccurs="0" />
+                               <xs:element ref="Sk:matrix" minOccurs="0" />
+                       </xs:choice>
+                       <!-- @attribute matrix Matrix applies a 3x3 transform to the gradient. -->
+                       <xs:attribute name="matrix" type="Sk:Matrix"/>
+                       <!-- @attribute tileMode One of @pattern. @patternDescription -->
+                       <xs:attribute name="tileMode" type="Sk:TileMode"/>
+                       <!-- @attribute filterType The bitmap filter to employ, one of @pattern. -->
+                       <xs:attribute name="filterType" type="Sk:FilterType"/>
+                       <!-- @attribute image The bitmap to draw. -->
+                       <xs:attribute name="image" type="Sk:BaseBitmap"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       
+       <!-- /** blur
+               Blur describes an image filter in the paint that blurs the drawn geometry.  
+       */ -->
+       <xs:element name="blur">
+               <xs:complexType>
+                       <!-- @attribute blurStyle One of @pattern. @patternDescription  -->
+                       <xs:attribute name="blurStyle" type="Sk:MaskFilterBlurStyle"/>
+                       <!-- @attribute radius The extent of the filter effect in unit space. If the radius is less 
+                               than zero,      the blur has no effect. -->             
+                       <xs:attribute name="radius" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** boolean
+               Boolean contains an boolean. The boolean element cannot be added to a display list, but can
+               by set by animations and read by any attribute definition. An boolean element may be referenced,
+               for instance, by a group's condition attribute to make an animation conditionally execute.
+       */ -->
+       <xs:element name="boolean">
+               <xs:complexType>
+                       <!-- @attribute value The contained boolean. -->
+                       <xs:attribute name="value" type="Sk:Boolean"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+
+       <!-- /** bounds
+               Bounds describes a bounding box that is not drawn. Bounds is used to specify a rectangle to
+               invalidate or record whether the specified area was drawn.
+               The width and height attribute compute the rectangle's right and bottom edges when the rectangle
+               description is first seen. Animating the rectangle's left or top will not recompute the right or bottom
+               if the width or height have been specified.
+       */ -->
+       <xs:element name="bounds">
+               <xs:complexType>
+                       <!-- @attribute bottom The bottom edge of the rectangle. -->
+                       <xs:attribute name="bottom" type="Sk:Float"/>
+                       <!-- @attribute height The height of the rectangle. Setting height computes the 
+                               bottom attribute from the top attribute. -->
+                       <xs:attribute name="height" type="Sk:Float"/>
+                       <!-- @attribute inval If set to true, union the drawn bounds to compute an inval area. -->
+                       <xs:attribute name="inval" type="Sk:Boolean"/>
+                       <!-- @attribute left The left edge of the rectangle. -->
+                       <xs:attribute name="left" type="Sk:Float"/>
+                       <!-- @attribute needsRedraw Set to true if last draw was visible. -->
+                       <xs:attribute name="needsRedraw" type="Sk:Boolean"/>
+                       <!-- @attribute right The right edge of the rectangle. -->
+                       <xs:attribute name="right" type="Sk:Float"/>
+                       <!-- @attribute top The top edge of the rectangle. -->
+                       <xs:attribute name="top" type="Sk:Float"/>
+                       <!-- @attribute width The width of the rectangle. -->
+                       <xs:attribute name="width" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** clear
+               Clear removes all entries in the display list.  
+       */ -->
+       <xs:element name="clear">
+               <xs:complexType>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** clip
+               Clip sets the canvas to clip drawing to an element's geometry.  
+               A clip element may contain an element or reference an element with the path or
+               rectangle attributes. To make the clip unrestricted, enclose a 'full' element.
+       */ -->
+       <xs:element name="clip">
+               <xs:complexType>
+                       <xs:choice minOccurs="0" maxOccurs="1">
+                               <xs:element ref="Sk:full"/>
+                               <xs:element ref="Sk:rect"/>
+                               <xs:element ref="Sk:path"/>
+                               <xs:element ref="Sk:polygon"/>
+                               <xs:element ref="Sk:polyline"/>
+                       </xs:choice>
+                       <!-- @attribute path A path-derived element to clip to: either an oval,
+                               a path, a polygon, a polyline, or a roundRect.  -->
+                       <xs:attribute name="path" type="Sk:Path"/>
+                       <!-- @attribute rect A rectangle element to clip to.  -->
+                       <xs:attribute name="rect" type="Sk:Rect"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** close
+               Close connects the last point in the path's contour to the first if the contour is not already closed.  
+       */ -->
+       <xs:element name="close">
+               <xs:complexType>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** color
+               Color describes a color in RGB space or HSV space, and its alpha (transparency).  
+       */ -->
+       <xs:element name="color">
+               <xs:complexType>
+                       <!-- @attribute alpha The alpha component, which describes transparency.
+                        Alpha ranges from 0.0 (transparent) to 1.0 (completely opaque). -->
+                       <xs:attribute name="alpha" type="Sk:Float"/>
+                       <!-- @attribute blue The blue component of an RGB color. Blue ranges from 0 to 255.  -->
+                       <xs:attribute name="blue" type="Sk:Float"/>
+                       <!-- @attribute color The complete color. The color can be specified by name,
+                               by hexadecimal value, or with the rgb function.  -->
+                       <xs:attribute name="color" type="Sk:ARGB"/>
+                       <!-- @attribute green The green component of an RGB color. Green ranges from 0 to 255.  -->
+                       <xs:attribute name="green" type="Sk:Float"/>
+                       <!-- @attribute hue The hue component of an HSV color. Hue ranges from 0 to 360. -->
+                       <xs:attribute name="hue" type="Sk:Float"/>
+                       <!-- @attribute red The red component of an RGB color. Red ranges from 0 to 255.  -->
+                       <xs:attribute name="red" type="Sk:Float"/>
+                       <!-- @attribute saturation The saturation component of an HSV color. Saturation ranges from 0 to 1. -->
+                       <xs:attribute name="saturation" type="Sk:Float"/>
+                       <!-- @attribute value The value component of an HSV color. Value ranges from 0 to 1. -->
+                       <xs:attribute name="value" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** cubicTo
+               CubicTo adds a cubic to the path, using the last point in the path as the first point of the cubic. 
+       */ -->
+       <xs:element name="cubicTo">
+               <xs:complexType>
+                       <!-- @attribute x1 The x position of the first off-curve point. -->
+                       <xs:attribute name="x1" type="Sk:Float"/>
+                       <!-- @attribute x2 The x position of the second off-curve point. -->
+                       <xs:attribute name="x2" type="Sk:Float"/>
+                       <!-- @attribute x3 The x position of the final on-curve point. -->
+                       <xs:attribute name="x3" type="Sk:Float"/>
+                       <!-- @attribute y1 The y position of the first off-curve point. -->
+                       <xs:attribute name="y1" type="Sk:Float"/>
+                       <!-- @attribute y2 The y position of the second off-curve point. -->
+                       <xs:attribute name="y2" type="Sk:Float"/>
+                       <!-- @attribute y3 The y position of the final on-curve point. -->
+                       <xs:attribute name="y3" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** dash
+               Dash describes an array of dashes and gaps that describe how the paint strokes lines,
+               rectangles, and paths. The intervals, phase, and dashed path are all measured in the same 
+               unit space. The phase and distance between dashes is unaffected by the paint's stroke width.
+       */ -->
+       <xs:element name="dash">
+               <xs:complexType>
+                       <!-- @attribute intervals An array of floats that alternately describe the lengths of 
+                       dashes and gaps. Intervals must contain an even number of entries. -->
+                       <xs:attribute name="intervals" type="Sk:FloatArray"/>
+                       <!-- @attribute phase Phase advances the placement of the first dash. A positive phase 
+                       preceeds the first dash with a gap. A negative phase shortens the length of the first dash. -->
+                       <xs:attribute name="phase" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** data
+               Data provides metadata to an event. The metadata may be an integer, a float, 
+                       or a string. 
+       */ -->
+       <xs:element name="data">
+               <xs:complexType>
+                       <!-- @attribute float The float value associated with the metadata. -->
+                       <xs:attribute name="float" type="Sk:Float"/>
+                       <!-- @attribute initialized A read-only value set to false (unused by data). -->
+                       <xs:attribute name="initialized" type="Sk:Boolean"/>
+                       <!-- @attribute int The integer value associated with the metadata. -->
+                       <xs:attribute name="int" type="Sk:Int"/>
+                       <!-- @attribute name The name of the metadata. This is the name of the data. --> 
+                       <xs:attribute name="name" type="Sk:String"/>
+                       <!-- @attribute string The string value associated with the metadata. -->
+                       <xs:attribute name="string" type="Sk:String"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+
+       <!-- /** discrete
+               Discrete alters the edge of the stroke randomly.  Discrete is a path effect, and only has an 
+               effect when referenced from a paint.. A <pathEffect/>
+               element with no attributes will dissable discrete. 
+       */ -->
+       <xs:element name="discrete">
+               <xs:complexType>
+                       <!-- @attribute deviation The amount of wobble in the stroke. -->
+                       <xs:attribute name="deviation" type="Sk:Float"/>
+                       <!-- @attribute segLength The length of wobble in the stroke. -->
+                       <xs:attribute name="segLength" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** drawTo
+               DrawTo images to a bitmap. The bitmap can be added to the display list
+               to draw the composite image. 
+               DrawTo can be used as an offscreen to speed complicated animations, and
+               for bitmap effects such as pixelated zooming.  
+               DrawTo can only reference a single drawable element. Use <add>,
+               <group>, or <save> to draw multiple elements with <drawTo>.
+       */ -->
+       <xs:element name="drawTo">
+               <xs:complexType>
+                       <xs:choice maxOccurs="unbounded" >
+                               <xs:element ref="Sk:add"/>
+                               <xs:element ref="Sk:apply"/>
+                               <xs:element ref="Sk:bitmap"/>
+                               <xs:element ref="Sk:bounds"/>
+               <!--            <xs:element ref="Sk3D:camera"/>    -->
+                               <xs:element ref="Sk:clear"/>
+                               <xs:element ref="Sk:clip"/>
+                               <xs:element ref="Sk:color"/>
+                               <xs:element ref="Sk:full"/>
+                               <xs:element ref="Sk:group"/>
+                               <xs:element ref="Sk:image"/>
+                               <xs:element ref="Sk:line"/>
+                               <xs:element ref="Sk:matrix"/>
+                               <xs:element ref="Sk:move"/>
+                               <xs:element ref="Sk:oval"/>
+                               <xs:element ref="Sk:paint"/>
+                       <!--    <xs:element ref="Sk:patch"/>   -->
+                               <xs:element ref="Sk:path"/>
+                               <xs:element ref="Sk:point"/>
+                               <xs:element ref="Sk:polygon"/>
+                               <xs:element ref="Sk:polyline"/>
+                               <xs:element ref="Sk:rect"/>
+                               <xs:element ref="Sk:remove"/>
+                               <xs:element ref="Sk:replace"/>
+                               <xs:element ref="Sk:roundRect"/>
+                               <xs:element ref="Sk:save"/>
+                               <xs:element ref="Sk:text"/>
+                               <xs:element ref="Sk:textBox"/>
+                               <xs:element ref="Sk:textOnPath"/>
+                               <xs:element ref="Sk:textToPath"/>
+                       </xs:choice>
+                       <!-- @attribute drawOnce If set, the drawTo will only draw a single time. -->
+                       <xs:attribute name="drawOnce" type="Sk:Boolean"/>
+                       <!-- @attribute use The bitmap to draw into. -->
+                       <xs:attribute name="use" type="Sk:bitmap"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** dump
+               Dump prints a list of the items in the display list and all items' 
+               children to the debug console. Dump is only available in Debug
+               builds. */ -->
+       <xs:element name="dump">        
+               <xs:complexType>
+                       <!-- @attribute displayList Dumps the current display list if true. The display list is also
+                       dumped if dump has no attributes. -->
+                       <xs:attribute name="displayList" type="Sk:Boolean"/>
+                       <!-- @attribute eventList Dumps the list of events, both enabled and disabled. -->
+                       <xs:attribute name="eventList" type="Sk:Boolean"/>
+                       <!-- @attribute events Outputs each event element as it is enabled. -->
+                       <xs:attribute name="events" type="Sk:Boolean"/>
+                       <!-- @attribute groups Outputs each group element as its condition is evaluated. -->
+                       <xs:attribute name="groups" type="Sk:Boolean"/>
+                       <!-- @attribute name Outputs the values associated with a single named element. -->
+                       <xs:attribute name="name" type="Sk:String"/>
+                       <!-- @attribute posts Outputs each post element as it is enabled. -->
+                       <xs:attribute name="posts" type="Sk:Boolean"/>
+            <!-- @attribute script Evaluates the provided script -->
+            <xs:attribute name="script" type=Sk:String"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** emboss
+               PRELIMINARY [to be replaced with SkEmbossMaskFilter.h doxyfomation
+               at some point]
+               Emboss applies a mask filter to the paint that makes bias the object's color
+               towards white or black depending on the normals of the path contour, giving
+               the shape a 3D raised or depressed effect.
+               Embossing is replaced by subsequent mask filter elements, or
+               disabled a negative radius, or by an empty <mask filter> element.
+       */ -->
+       <xs:element name="emboss">
+               <xs:complexType>
+                       <!-- @attribute ambient The amount of ambient light, from 0 to 1. -->           
+                       <xs:attribute name="ambient" type="Sk:Float"/>
+                       <!--  @attribute direction The direction of the light source, as descibed by a 3D vector. 
+                               (The vector is normalized to a unit length of 1.0.) -->         
+                       <xs:attribute name="direction" type="Sk:FloatArray"/>
+                       <!-- @attribute radius The extent of the filter effect in unit space. If the radius is less 
+                               than zero,      the emboss has no effect. -->           
+                       <xs:attribute name="radius" type="Sk:Float"/>
+                       <!--  @attribute specular The expotential intensity of the light, from 0 to 1. 
+                               Each increase of 0.0625 doubles the intensity. -->              
+                       <xs:attribute name="specular" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** event
+               Event contains a series of actions performed each time the event's criteria are satisfied.
+               These actions may modify the display list, may enable animations which in turn modify 
+               elements' attributes, and may post other events. 
+       */ -->
+       <xs:element name="event">
+               <xs:complexType>
+                       <xs:choice maxOccurs="unbounded" >
+                               <xs:element ref="Sk:add"/>
+                               <xs:element ref="Sk:apply"/>
+                               <xs:element ref="Sk:array"/>
+                               <xs:element ref="Sk:bitmap"/>
+                               <xs:element ref="Sk:boolean"/>
+                               <xs:element ref="Sk:bounds"/>
+               <!--            <xs:element ref="Sk3D:camera"/>    -->
+                               <xs:element ref="Sk:clear"/>
+                               <xs:element ref="Sk:clip"/>
+                               <xs:element ref="Sk:color"/>
+                               <xs:element ref="Sk:drawTo"/>
+                               <xs:element ref="Sk:dump"/>
+                               <xs:element ref="Sk:float"/>
+                               <xs:element ref="Sk:full"/>
+                               <xs:element ref="Sk:group"/>
+                               <xs:element ref="Sk:hitClear"/>
+                               <xs:element ref="Sk:hitTest"/>
+                               <xs:element ref="Sk:image"/>
+                               <xs:element ref="Sk:input"/>
+                               <xs:element ref="Sk:int"/>
+                               <xs:element ref="Sk:line"/>
+                               <xs:element ref="Sk:matrix"/>
+                               <xs:element ref="Sk:move"/>
+                               <xs:element ref="Sk:movie"/>
+                               <xs:element ref="Sk:oval"/>
+                               <xs:element ref="Sk:paint"/>
+                       <!--    <xs:element ref="Sk:patch"/>   -->
+                               <xs:element ref="Sk:path"/>
+                               <xs:element ref="Sk:point"/>
+                               <xs:element ref="Sk:polygon"/>
+                               <xs:element ref="Sk:polyline"/>
+                               <xs:element ref="Sk:post"/>
+                               <xs:element ref="Sk:random"/>
+                               <xs:element ref="Sk:rect"/>
+                               <xs:element ref="Sk:remove"/>
+                               <xs:element ref="Sk:replace"/>
+                               <xs:element ref="Sk:roundRect"/>
+                               <xs:element ref="Sk:save"/>
+                               <xs:element ref="Sk:snapshot"/>
+                               <xs:element ref="Sk:string"/>
+                               <xs:element ref="Sk:text"/>
+                               <xs:element ref="Sk:textBox"/>
+                               <xs:element ref="Sk:textOnPath"/>
+                               <xs:element ref="Sk:textToPath"/>
+                       </xs:choice>
+                       <!-- @attribute code The key code to match to a key press event, one of @pattern. 
+                               If the code is set to @pattern[0], the event is never activated. -->            
+                       <xs:attribute name="code" type="Sk:EventCode"/>
+                       <!-- @attribute disable If true, the event cannot be activated. By default false.. -->          
+                       <xs:attribute name="disable" type="Sk:Boolean"/>
+                       <!-- @attribute key The character code to match to a key down event.
+                                When read, the key that activated this event. -->              
+                       <xs:attribute name="key" type="Sk:String"/>
+                       <!-- @attribute keys A dash-separated continuous range of character codes to match 
+                               to a key         down event. Read the key attribute to determine the key that activated this event. -->         
+                       <xs:attribute name="keys" type="Sk:String"/> <!-- single or range of keys -->
+                       <!-- @attribute kind The event kind that activates this event, one of @pattern. 
+                               If kind equals keyChar, either attribute key or keys is expected.
+                               If kind equals keyPress, attribute code is expected.
+                               If kind equals onEnd, attribute target is expected. 
+                               If kind equals onLoad, the event is activated when the document containing the event
+                               is loaded. The onLoad attribute cannot be activated through a post event.
+                               If kind equals user, the event is activated when the posted event targets this event's ID.  -->         
+                       <xs:attribute name="kind" type="Sk:EventKind"/>
+                       <!-- @attribute target The element to listen to which activates this event. -->
+                       <xs:attribute name="target" type="Sk:String" />
+                       <!-- @attribute x For click events, the x-coordinate of the click.  -->
+                       <xs:attribute name="x" type="Sk:Float" />
+                       <!-- @attribute y For click events, the y-coordinate of the click.  -->
+                       <xs:attribute name="y" type="Sk:Float" />
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** float
+               Float contains a signed fractional value. The float element cannot be added to a display list, 
+               but can be set by animations and read by any attribute definition.
+       */ -->
+       <xs:element name="float">
+               <xs:complexType>
+                       <!-- @attribute value The contained float. -->
+                       <xs:attribute name="value" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+
+       <!-- /** fromPath
+               FromPath concatenates the parent matrix with a new matrix 
+               that maps a unit vector to a point on the given path. 
+               A fromPath element may contain a path element, or may refer to a previously
+               defined path element with the path attribute.
+       */ -->
+       <xs:element name="fromPath">
+               <xs:complexType>
+                       <xs:choice >
+                               <!-- @element path The path to evaluate. -->
+                               <xs:element ref="Sk:path" minOccurs="0" />
+                       </xs:choice>
+                       <!-- @attribute mode One of @pattern. 
+                       If mode is set to normal, the matrix maps the unit vector's angle and position.
+                       If mode is set to angle, the matrix maps only the unit vector's angle.
+                       If mode is set to position, the matrix maps only the unit vector's position. -->
+                       <xs:attribute name="mode" type="Sk:FromPathMode"/>
+                       <!-- @attribute offset The distance along the path to evaluate. -->
+                       <xs:attribute name="offset" type="Sk:Float"/>
+                       <!-- @attribute path The path to evaluate. -->
+                       <xs:attribute name="path" type="Sk:Path"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** full
+               Full paints the entire canvas to the limit of the canvas' clip.
+       */ -->
+       <xs:element name="full">
+               <xs:complexType>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** group
+               The group element collects a series of elements into a group.  The group can be referenced
+               or defined within elements, like apply, which operate on any kind of element. Groups 
+               may contain groups. An element in a group draws identically to an element outside a group.
+       */ -->
+       <xs:element name="group">
+               <xs:complexType>
+                       <xs:choice maxOccurs="unbounded">
+                               <xs:element ref="Sk:add"/>
+                               <xs:element ref="Sk:apply"/>
+                               <xs:element ref="Sk:array"/>
+                               <xs:element ref="Sk:bitmap"/>
+                               <xs:element ref="Sk:boolean"/>
+                               <xs:element ref="Sk:bounds"/>
+               <!--            <xs:element ref="Sk3D:camera"/>    -->
+                               <xs:element ref="Sk:clear"/>
+                               <xs:element ref="Sk:clip"/>
+                               <xs:element ref="Sk:drawTo"/>
+                               <xs:element ref="Sk:float"/>
+                               <xs:element ref="Sk:full"/>
+                               <xs:element ref="Sk:group"/>
+                               <xs:element ref="Sk:hitClear"/>
+                               <xs:element ref="Sk:hitTest"/>
+                               <xs:element ref="Sk:image"/>
+                               <xs:element ref="Sk:int"/>
+                               <xs:element ref="Sk:line"/>
+                               <xs:element ref="Sk:matrix"/>
+                               <xs:element ref="Sk:move"/>
+                               <xs:element ref="Sk:oval"/>
+                               <xs:element ref="Sk:paint"/>
+                       <!--    <xs:element ref="Sk:patch"/>   -->
+                               <xs:element ref="Sk:path"/>
+                               <xs:element ref="Sk:point"/>
+                               <xs:element ref="Sk:polygon"/>
+                               <xs:element ref="Sk:polyline"/>
+                               <xs:element ref="Sk:post"/>
+                               <xs:element ref="Sk:random"/>
+                               <xs:element ref="Sk:rect"/>
+                               <xs:element ref="Sk:remove"/>
+                               <xs:element ref="Sk:replace"/>
+                               <xs:element ref="Sk:roundRect"/>
+                               <xs:element ref="Sk:save"/>
+                               <xs:element ref="Sk:snapshot"/>
+                               <xs:element ref="Sk:string"/>
+                               <xs:element ref="Sk:text"/>
+                               <xs:element ref="Sk:textBox"/>
+                               <xs:element ref="Sk:textOnPath"/>
+                               <xs:element ref="Sk:textToPath"/>
+                       </xs:choice>
+                       <!-- @attribute condition If present and zero, the contained elements are ignored
+                               when drawn. -->
+                       <xs:attribute name="condition" type="Sk:DynamicString"/>
+                       <!-- @attribute enableCondition If present and zero, the contained elements are ignored
+                               when enabled. -->
+                       <xs:attribute name="enableCondition" type="Sk:DynamicString"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <xs:element name="hitClear" >
+               <xs:complexType>
+                       <xs:choice maxOccurs="1">
+                               <xs:element ref="Sk:array"/>
+                       </xs:choice>
+                       <!-- @attribute targets An array of element IDs to clear their hit-tested state. -->
+                       <xs:attribute name="targets" type="Sk:DisplayableArray"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <xs:element name="hitTest" >
+               <xs:complexType>
+                       <xs:choice maxOccurs="2">
+                               <xs:element ref="Sk:array"/>
+                       </xs:choice>
+                       <!-- @attribute bullets An array of element IDs to test for intersection with targets. -->
+                       <xs:attribute name="bullets" type="Sk:DisplayableArray"/>
+                       <!-- @attribute hits The targets the bullets hit. A read-only array of indices, one index
+                               per bullet. The value of the array element is the index of the target hit, or -1 if no
+                               target was hit. -->
+                       <xs:attribute name="hits" type="Sk:IntArray"/>
+                       <!-- @attribute targets An array of element IDs to test for intersection with bullets. -->
+                       <xs:attribute name="targets" type="Sk:DisplayableArray"/>
+                       <!-- @attribute value Read only; set to true if some bullet hit some target. -->
+                       <xs:attribute name="value" type="Sk:Boolean"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** image
+               Image creates a reference to a JPEG, PNG or GIF. The image may be referenced
+               through the local file system, the internet, or embedded in the document in Base64
+               format. The specific image type is determined by examining the byte stream.  
+       */ -->
+       <xs:element name="image">
+               <xs:complexType>
+                       <!-- @attribute base64 The image in Base64 notation. See http://rfc.net/rfc2045.html 
+                       for the base64 format. -->
+                       <xs:attribute name="base64" type="Sk:Base64"/>
+                       <!-- @attribute height The height of the image (read-only). -->
+                       <xs:attribute name="height" type="Sk:Int"/>
+                       <!-- @attribute src The URI reference, local to the contaiing document. -->
+                       <xs:attribute name="src" type="Sk:String"/>
+                       <!-- @attribute width The width of the image (read-only). -->
+                       <xs:attribute name="width" type="Sk:Int"/>
+                       <!-- @attribute x The position of the left edge of the image in local coordinates. -->
+                       <xs:attribute name="x" type="Sk:Float"/>
+                       <!-- @attribute y The position of the top edge of the image in local coordinates. -->
+                       <xs:attribute name="y" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** include
+               Include adds the referenced XML to the containing document. Unlike movie, the XML
+               directives can reference the document's IDs and can define new IDs that are referenced
+               by the remainder of the document or subsequent includes.  
+       */ -->
+       <xs:element name="include">
+               <xs:complexType>
+                       <!-- @attribute src The URI reference, local to the containing document, 
+                       containing the include's XML. -->
+                       <xs:attribute name="src" type="Sk:String"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** input
+               Input captures the metadata passed from an event. When the metadata's name or id 
+               matches the metadata's name, the metadata's payload is copied to the corresponding
+               input attribute.
+       */ -->
+       <xs:element name="input">
+               <xs:complexType>
+                       <!-- @attribute float The floating point payload carried by the metadata. -->
+                       <xs:attribute name="float" type="Sk:Float"/>
+                       <!-- @attribute initialized A read-only value set to true if the input received a value 
+                               from the event. -->
+                       <xs:attribute name="initialized" type="Sk:Boolean"/>
+                       <!-- @attribute int The signed integer payload carried by the metadata. -->
+                       <xs:attribute name="int" type="Sk:Int"/>
+                       <!-- @attribute name The name of the metadata containing the payload. Note that 
+                               the name or id may match the payload, but that XML requires the id to be
+                               uniquely defined in the document, while multiple input elements may reuse 
+                               the name. -->
+                       <xs:attribute name="name" type="Sk:String"/>
+                       <!-- @attribute string The text payload carried by the metadata. -->
+                       <xs:attribute name="string" type="Sk:String"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** int
+               Int contains an integer. The int element cannot be added to a display list, but can
+               by set by animations and read by any attribute definition. An int element may be used,
+               for instance, to index through an array element.
+       */ -->
+       <xs:element name="int">
+               <xs:complexType>
+                       <!-- @attribute value The contained integer. -->
+                       <xs:attribute name="value" type="Sk:Int"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+
+       <!-- /** line
+               Line describes a line between two points. As noted below, the paint's stroke and
+               strokeAndFill attributes are ignored.
+       */ -->
+       <xs:element name="line">
+               <xs:complexType>
+                       <!-- @attribute x1 The start point's x value. -->
+                       <xs:attribute name="x1" type="Sk:Float"/>
+                       <!-- @attribute x2 The stop point's x value. -->
+                       <xs:attribute name="x2" type="Sk:Float"/>
+                       <!-- @attribute y1 The start point's y value. -->
+                       <xs:attribute name="y1" type="Sk:Float"/>
+                       <!-- @attribute y2 The stop point's y value. -->
+                       <xs:attribute name="y2" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** lineTo
+               LineTo adds a line from the last point in a path to the specified point. 
+       */ -->
+       <xs:element name="lineTo">
+               <xs:complexType>
+                       <!-- @attribute x The final path x coordinate. -->
+                       <xs:attribute name="x" type="Sk:Float"/>
+                       <!-- @attribute y The final path y coordinate. -->
+                       <xs:attribute name="y" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** linearGradient
+               LinearGradient sets the paint shader to ramp between two or more colors. 
+       */ -->
+       <xs:element name="linearGradient">
+               <xs:complexType>
+                       <xs:choice maxOccurs="unbounded">
+                               <xs:element ref="Sk:color"/>
+                               <xs:element ref="Sk:matrix"/>
+                       </xs:choice>
+                       <!-- @attribute matrix Matrix applies a 3x3 transform to the gradient. -->
+                       <xs:attribute name="matrix" type="Sk:Matrix"/>
+                       <!-- @attribute tileMode One of @pattern. @patternDescription -->
+                       <xs:attribute name="tileMode" type="Sk:TileMode"/>
+                       <!-- @attribute offsets An optional array of values used to bias the colors. The first entry
+                               in the array must be 0.0, the last must be 1.0, and intermediate values must ascend. -->
+                       <xs:attribute name="offsets" type="Sk:FloatArray"/>
+                       <!-- @attribute points Two points describing the start and end of the gradient. -->
+                       <xs:attribute name="points" type="Sk:Point"/>   <!-- not right; should be array of 2 points -->
+                       <!-- @attribute unitMapper A script that returns the mapping for [0,1] for the gradient.
+                               The script can use the predefined variable 'unit' to compute the mapping. For instance,
+                               "unit*unit" squares the value (while still keeping it in the range of [0,1].) The computed number
+                               is pinned to from 0 to 1 after the script is executed. -->
+                       <xs:attribute name="unitMapper" type="Sk:String"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** maskFilter
+               MaskFilter disables any mask filter referenced by the paint. 
+       */ -->
+       <xs:element name="maskFilter">
+               <xs:complexType>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** matrix
+               Matrix transforms all points drawn to the canvas. The matrix may translate, scale, skew, rotate,
+               or apply perspective, or apply any combination.  
+       */ -->
+       <xs:element name="matrix">
+               <xs:complexType>
+                       <xs:choice maxOccurs="unbounded">
+                       <!-- @element fromPath FromPath maps a unit vector to a position and direction on a path. -->
+                               <xs:element ref="Sk:fromPath"/>
+                       <!-- @element polyToPoly PolyToPoly maps a points between two polygons. -->
+                               <xs:element ref="Sk:polyToPoly"/>
+                       <!-- @element rectToRect RectToRect maps a points between two rectangles. -->
+                               <xs:element ref="Sk:rectToRect"/>
+                       <!-- @element rotate Rotate computes the matrix rotation in degrees. -->
+                               <xs:element ref="Sk:rotate"/>
+                       <!-- @element scale Scale stretches or shrinks horizontally, vertically, or both. -->
+                               <xs:element ref="Sk:scale"/>
+                       <!-- @element skew Skew slants horizontally, vertically, or both. -->
+                               <xs:element ref="Sk:skew"/>
+                       <!-- @element translate Translate moves horizontally, vertically, or both. -->
+                               <xs:element ref="Sk:translate"/>
+                       </xs:choice>
+                       <!-- @attribute matrix Nine floats describing a 3x3 matrix. -->
+                       <xs:attribute name="matrix" type="Sk:FloatArray"/>
+                       <!-- @attribute perspectX The [0][2] element of the 3x3 matrix. -->
+                       <xs:attribute name="perspectX" type="Sk:Float"/>
+                       <!-- @attribute perspectY The [1][2] element of the 3x3 matrix. -->
+                       <xs:attribute name="perspectY" type="Sk:Float"/>
+                       <!-- @attribute rotate The angle to rotate in degrees. -->
+                       <xs:attribute name="rotate" type="Sk:Float"/>
+                       <!-- @attribute scale The scale to apply in both X and Y.. -->
+                       <xs:attribute name="scale" type="Sk:Float"/>
+                       <!-- @attribute scaleX The [0][0] element of the 3x3 matrix. -->
+                       <xs:attribute name="scaleX" type="Sk:Float"/>
+                       <!-- @attribute scaleY The [1][1] element of the 3x3 matrix. -->
+                       <xs:attribute name="scaleY" type="Sk:Float"/>
+                       <!-- @attribute skewX The [0][1] element of the 3x3 matrix. -->
+                       <xs:attribute name="skewX" type="Sk:Float"/>
+                       <!-- @attribute skewY The [1][0] element of the 3x3 matrix. -->
+                       <xs:attribute name="skewY" type="Sk:Float"/>
+                       <!-- @attribute translate A point specifying the translation in X and Y. -->
+                       <xs:attribute name="translate" type="Sk:Point"/>
+                       <!-- @attribute translateX The [2][0] element of the 3x3 matrix. -->
+                       <xs:attribute name="translateX" type="Sk:Float"/>
+                       <!-- @attribute translateY The [2][1] element of the 3x3 matrix. -->
+                       <xs:attribute name="translateY" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** move
+               Move an element in the display list in front or behind other elements.  
+               If where and offset are omitted, the element is moved to the end of the display list.
+               If where is specified, the element is moved before the first occurance of where in the display list.
+               If offset and where are specified, the element is moved before where plus offset.
+               A positive offset without where moves the element to the start of the list plus offset.
+               A negative offset without where moves the element to the end of the list minus offset.
+       */ -->
+       <xs:element name="move">
+               <xs:complexType>
+                       <!-- @attribute mode Has no effect. -->
+                       <xs:attribute name="mode" type="Sk:AddMode"/>
+                       <!-- @attribute offset The destination position using the rules listed above. -->
+                       <xs:attribute name="offset" type="Sk:Int"/>
+                       <!-- @attribute use The element to move. -->
+                       <xs:attribute name="use" type="Sk:Drawable"/>
+                       <!-- @attribute where The ID of the first display list entry to move to. -->
+                       <xs:attribute name="where" type="Sk:Drawable"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** moveTo
+               MoveTo specifies the first point in a path contour.
+       */ -->
+       <xs:element name="moveTo">
+               <xs:complexType>
+                       <!-- @attribute x The point's x coordinate. -->
+                       <xs:attribute name="x" type="Sk:Float"/>
+                       <!-- @attribute y The point's y coordinate. -->
+                       <xs:attribute name="y" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** movie
+               Movie describes a display list within the current canvas and paint. Movies can contain 
+               movies. One movie cannot affect how another movie draws, but movies can communicate
+               with each other by posting events.
+       */ -->
+       <xs:element name="movie">
+               <xs:complexType>
+                       <!-- @attribute src The URI reference, local to the containing document, containing the movie's XML. -->
+                       <xs:attribute name="src" type="Sk:String"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** oval
+               Oval describes a circle stretched to fit in a rectangle.
+               The width and height attribute compute the oval's right and bottom edges when the oval
+               description is first seen. Animating the oval's left or top will not recompute the right or bottom
+               if the width or height have been specified.
+       */ -->
+       <xs:element name="oval">
+               <xs:complexType>
+                       <!-- @attribute bottom The bottom edge of the oval. -->
+                       <xs:attribute name="bottom" type="Sk:Float"/>
+                       <!-- @attribute height The height of the oval. -->
+                       <xs:attribute name="height" type="Sk:Float"/>
+                       <!-- @attribute left The left edge of the oval. -->
+                       <xs:attribute name="left" type="Sk:Float"/>
+                       <!-- @attribute needsRedraw Set to true if last draw was visible. -->
+                       <xs:attribute name="needsRedraw" type="Sk:Boolean"/>
+                       <!-- @attribute right The right edge of the oval. -->
+                       <xs:attribute name="right" type="Sk:Float"/>
+                       <!-- @attribute top The top edge of the oval. -->
+                       <xs:attribute name="top" type="Sk:Float"/>
+                       <!-- @attribute width The width of the oval. -->
+                       <xs:attribute name="width" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** paint
+               Paint uses color, flags, path effects, mask filters, shaders, and stroke effects when drawing 
+               geometries, images, and text.
+       */ -->
+       <xs:element name="paint">
+               <xs:complexType>
+                       <xs:choice maxOccurs="unbounded">
+                       <!-- @element bitmapShader Sets or cancels an image to draw as the color. -->
+                               <xs:element ref="Sk:bitmapShader"/>
+                       <!-- @element blur Blur radially draws the shape with varying transparency. -->
+                               <xs:element ref="Sk:blur"/>
+                       <!-- @element color Color specifies a solid color in RGB or HSV. -->
+                               <xs:element ref="Sk:color"/>
+                       <!-- @element dash Dashes alternates stroking with dashes and gaps. -->
+                               <xs:element ref="Sk:dash"/>
+                       <!-- @element discrete Discrete wobbles the geometry randomly. -->
+                               <xs:element ref="Sk:discrete"/>
+                       <!-- @element emboss Emboss simulates a 3D light to show highlights and relief. -->
+                               <xs:element ref="Sk:emboss"/>
+                       <!-- @element linearGradient LinearGradient linearly ramps between two or more colors. -->
+                               <xs:element ref="Sk:linearGradient"/>
+                       <!-- @element maskFilter MaskFilter cancels a blur or emboss. -->
+                               <xs:element ref="Sk:maskFilter"/>
+                       <!-- @element  pathEffect PathEffect cancels a discrete or dash. -->
+                               <xs:element ref="Sk:pathEffect"/>
+                       <!-- @element radialGradient RadialGradient radially ramps between two or more colors. -->
+                               <xs:element ref="Sk:radialGradient"/>
+                       <!-- @element shader Shader cancels a linear or radial gradient. -->
+                               <xs:element ref="Sk:shader"/>
+                       <!-- @element typeface Typeface chooses a font out of a font family. -->
+                               <xs:element ref="Sk:typeface"/>
+                       <!-- @element transparentShader  TransparentShader ? [not sure what this is for] -->
+                               <xs:element ref="Sk:transparentShader"/>
+                       </xs:choice>
+                       <!-- @attribute antiAlias AntiAlias uses gray shades to increase the definition of paths. -->
+                       <xs:attribute name="antiAlias" type="Sk:Boolean"/>
+                       <!-- @attribute ascent Ascent returns the height above the baseline defined by the font. -->
+                       <xs:attribute name="ascent" type="Sk:Float"/>
+                       <!-- @attribute color Color sets the paint to the color element with this ID. -->
+                       <xs:attribute name="color" type="Sk:Color"/>
+                       <!-- @attribute descent Descent returns the height below the baseline defined by thte font -->
+                       <xs:attribute name="descent" type="Sk:Float"/>
+                       <!-- @attribute fakeBold FakeBold enables a faked bold for text. -->
+                       <xs:attribute name="fakeBold" type="Sk:Boolean"/>
+                       <!-- @attribute filterType FilterType -->
+                       <xs:attribute name="filterType" type="Sk:FilterType"/>
+                       <!-- @attribute linearText LinearText uses the ideal path metrics at all sizes to describe text. -->
+                       <xs:attribute name="linearText" type="Sk:Boolean"/>
+                       <!-- @attribute maskFilter MaskFilter specifies a blur or emboss with this ID. -->
+                       <xs:attribute name="maskFilter" type="Sk:MaskFilter"/>
+                       <!-- @attribute measureText MeasureText(String) returns the width of the string in this paint. -->
+                       <xs:attribute name="measureText" type="Sk:Float"/>
+                       <!-- @attribute pathEffect PathEffect specifies a discrete or dash with this ID. -->
+                       <xs:attribute name="pathEffect" type="Sk:PathEffect"/>
+                       <!-- @attribute shader Shader specifies a gradient with this ID. -->
+                       <xs:attribute name="shader" type="Sk:Shader"/>
+                       <!-- @attribute strikeThru StrikeThru adds a line through the middle of drawn text. -->
+                       <xs:attribute name="strikeThru" type="Sk:Boolean"/>
+                       <!-- @attribute stroke Stroke draws the outline of geometry according to the pen attributes. 
+                               If style is also present, its setting overrides stroke. -->
+                       <xs:attribute name="stroke" type="Sk:Boolean"/>
+                       <!-- @attribute strokeCap StrokeCap is one of @pattern. -->
+                       <xs:attribute name="strokeCap" type="Sk:Cap"/>
+                       <!-- @attribute strokeJoin StrokeJoin is one of @pattern. -->
+                       <xs:attribute name="strokeJoin" type="Sk:Join"/>
+                       <!-- @attribute strokeMiter StrokeMiter limits the pen's joins on narrow angles. -->
+                       <xs:attribute name="strokeMiter" type="Sk:Float"/>
+                       <!-- @attribute strokeWidth StrokeWidth specifies the width of the pen. -->
+                       <xs:attribute name="strokeWidth" type="Sk:Float"/>
+                       <!-- @attribute style Style fills, strokes, or strokes and fills the geometry with the paint's color. -->
+                       <xs:attribute name="style" type="Sk:Style"/>
+                       <!-- @attribute textAlign TextAlign is one of @pattern. -->
+                       <xs:attribute name="textAlign" type="Sk:Align"/>
+                       <!-- @attribute textScaleX TextScaleX condenses or exapnds the text. -->
+                       <xs:attribute name="textScaleX" type="Sk:Float"/>
+                       <!-- @attribute textSize TextSize specifies the point size of the text. -->
+                       <xs:attribute name="textSize" type="Sk:Float"/>
+                       <!-- @attribute textSkewX TextSkewX draws the text obliquely. -->
+                       <xs:attribute name="textSkewX" type="Sk:Float"/>
+                       <!-- @attribute textTracking TextTracking specifies the space between letters. -->
+                       <xs:attribute name="textTracking" type="Sk:Float"/>
+                       <!-- @attribute typeface Typeface specifies a typeface element with this ID. -->
+                       <xs:attribute name="typeface" type="Sk:Typeface"/>
+                       <!-- @attribute underline Underline draws a line under the baseline of the text. -->
+                       <xs:attribute name="underline" type="Sk:Boolean"/>
+                       <!-- @attribute xfermode Xfermode specifies a transfer mode, one of @pattern. -->
+                       <xs:attribute name="xfermode" type="Sk:Xfermode"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** path
+               Path creates a geometry out of lines and curves.
+       */ -->
+       <xs:element name="path">
+               <xs:complexType>
+                       <xs:choice maxOccurs="unbounded">
+                       <!-- @element addCircle Adds a circle to the path. -->
+                               <xs:element ref="Sk:addCircle"/>
+                       <!-- @element addOval Adds an oval to the path. -->
+                               <xs:element ref="Sk:addOval"/>
+                       <!-- @element addPath Adds another path to the path. -->
+                               <xs:element ref="Sk:addPath"/>
+                       <!-- @element addRoundRect Adds a rounded-corner rectangle  to the path. -->
+                               <xs:element ref="Sk:addRoundRect"/>
+                       <!-- @element close Connects the last point on the path to the first. -->
+                               <xs:element ref="Sk:close"/>
+                       <!-- @element cubicTo Extends the path with a cubic curve. -->
+                               <xs:element ref="Sk:cubicTo"/>
+                       <!-- @element lineTo Extends the path with a line. -->
+                               <xs:element ref="Sk:lineTo"/>
+                       <!-- @element moveTo Starts a new path contour. -->
+                               <xs:element ref="Sk:moveTo"/>
+                       <!-- @element quadTo Extends the path with a quadratic curve. -->
+                               <xs:element ref="Sk:quadTo"/>
+                       <!-- @element rCubicTo Extends the path with a cubic curve expressed with relative offsets. -->
+                               <xs:element ref="Sk:rCubicTo"/>
+                       <!-- @element rLineTo Extends the path with a line expressed with relative offsets. -->
+                               <xs:element ref="Sk:rLineTo"/>
+                       <!-- @element rMoveTo Starts a new path contour relative to the path's last point. -->
+                               <xs:element ref="Sk:rMoveTo"/>
+                       <!-- @element rQuadTo Extends the path with a quadratic curve expressed with relative offsets. -->
+                               <xs:element ref="Sk:rQuadTo"/>
+                       </xs:choice>
+                       <!-- @attribute d Creates a path using SVG path notation. -->
+                       <xs:attribute name="d" type="Sk:String"/>
+                       <!-- @attribute fillType One of @pattern. -->
+                       <xs:attribute name="fillType" type="Sk:FillType"/>
+                       <!-- @attribute length Returns the length of the path. -->
+                       <xs:attribute name="length" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** pathEffect
+               PathEffect cancels any current path effect within the paint, such as dashing or discrete.
+       */ -->
+       <xs:element name="pathEffect">
+               <xs:complexType>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+               
+       <!-- /** point
+               Point describes a two dimensional point in space. The point element can be added
+               to the display list and drawn.
+       */ -->
+       <xs:element name="point">
+               <xs:complexType>
+                       <!-- @attribute x The x coordinate of the point. -->
+                       <xs:attribute name="x" type="Sk:Float"/>
+                       <!-- @attribute y The y coordinate of the point. -->
+                       <xs:attribute name="y" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** polygon
+               Polygon creates a geometry out of lines. Polygon is a specialization of path; element that 
+               refers to a path can refer to a polygon also. A polygon specified through elements behaves identically
+               to a path. A polygon specified by the points attribute contains a single contour, and the contour is 
+               automatically closed.
+       */ -->
+       <xs:element name="polygon">
+               <xs:complexType>
+                       <xs:choice maxOccurs="unbounded">
+                       <!-- @element close Connects the last point on the path to the first. -->
+                               <xs:element ref="Sk:close"/>
+                       <!-- @element addPath Adds another path to the path. -->
+                               <xs:element ref="Sk:addPath"/>
+                       <!-- @element lineTo Extends the path with a line. -->
+                               <xs:element ref="Sk:lineTo"/>
+                       <!-- @element moveTo Starts a new path contour. -->
+                               <xs:element ref="Sk:moveTo"/>
+                       <!-- @element rLineTo Extends the path with a line expressed with relative offsets. -->
+                               <xs:element ref="Sk:rLineTo"/>
+                       <!-- @element rMoveTo Starts a new path contour relative to the path's last point. -->
+                               <xs:element ref="Sk:rMoveTo"/>
+                       </xs:choice>
+                       <!-- @attribute points An array of values that describe a sequence of points, compatible with SVG. -->
+                       <xs:attribute name="points" type="Sk:FloatArray"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** polyline
+               Polyline creates a geometry out of lines. Polygon is a specialization of path; element that 
+               refers to a path can refer to a polygon also. A polygon specified through elements behaves identically
+               to a path. A polygon specified by the points attribute contains a single contour, and the contour is 
+               not automatically closed.
+       */ -->
+       <xs:element name="polyline">
+               <xs:complexType>
+                       <xs:choice maxOccurs="unbounded">
+                       <!-- @element close Connects the last point on the path to the first. -->
+                               <xs:element ref="Sk:close"/>
+                       <!-- @element addPath Adds another path to the path. -->
+                               <xs:element ref="Sk:addPath"/>
+                       <!-- @element lineTo Extends the path with a line. -->
+                               <xs:element ref="Sk:lineTo"/>
+                       <!-- @element moveTo Starts a new path contour. -->
+                               <xs:element ref="Sk:moveTo"/>
+                       <!-- @element rLineTo Extends the path with a line expressed with relative offsets. -->
+                               <xs:element ref="Sk:rLineTo"/>
+                       <!-- @element rMoveTo Starts a new path contour relative to the path's last point. -->
+                               <xs:element ref="Sk:rMoveTo"/>
+                       </xs:choice>
+                       <!-- @attribute points An array of values that describe a sequence of points, compatible with SVG. -->
+                       <xs:attribute name="points" type="Sk:FloatArray"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** polyToPoly
+               PolyToPoly creates a matrix which maps points proportionally from one polygon to the other.
+       */ -->
+       <xs:element name="polyToPoly">
+               <xs:complexType>
+                       <xs:choice maxOccurs="2">
+                               <xs:element ref="Sk:polygon"/>
+                       </xs:choice>
+                       <!-- @attribute source The polygon to map from.. -->
+                       <xs:attribute name="source" type="Sk:polygon"/>
+                       <!-- @attribute destination The polygon to map to.. -->
+                       <xs:attribute name="destination" type="Sk:polygon"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** post
+               Post activates an event. The event can trigger one or more actions, and can carry a data payload.
+       */ -->
+       <xs:element name="post">
+               <xs:complexType>
+                       <xs:choice maxOccurs="unbounded">
+                               <xs:element ref="Sk:data"/>
+                       </xs:choice>
+                       <!-- @attribute delay Time in seconds that must elapse before the target event is activated. -->
+                       <xs:attribute name="delay" type="Sk:MSec"/>
+                       <!-- @attribute mode One of @pattern. @patternDescription -->
+                       <xs:attribute name="mode" type="Sk:EventMode"/>
+                       <!-- @attribute sink The optional named EventSink to direct the event to. -->
+                       <xs:attribute name="sink" type="Sk:String"/>
+                       <!-- @attribute target The ID of the user event to trigger. -->
+                       <xs:attribute name="target" type="Sk:String"/>
+                       <!-- @attribute type The name of the external event to post. -->
+                       <xs:attribute name="type" type="Sk:String"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+
+       <!-- /** quadTo
+               QuadTo adds a quadratic curve to a path.
+       */ -->
+       <xs:element name="quadTo">
+               <xs:complexType>
+                       <!-- @attribute x1 The x position of the off-curve point. -->
+                       <xs:attribute name="x1" type="Sk:Float"/>
+                       <!-- @attribute x2 The x position of the final point. -->
+                       <xs:attribute name="x2" type="Sk:Float"/>
+                       <!-- @attribute y1 The y position of the off-curve point. -->
+                       <xs:attribute name="y1" type="Sk:Float"/>
+                       <!-- @attribute y2 The y position of the final point. -->
+                       <xs:attribute name="y2" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** rCubicTo
+               RCubicTo adds a cubic to the path, using the last point in the path as the first point of the cubic.  THe
+               added points are offsets from the last point in the path.
+       */ -->
+       <xs:element name="rCubicTo">
+               <xs:complexType>
+                       <!-- @attribute x1 The x offset of the first off-curve point. -->
+                       <xs:attribute name="x1" type="Sk:Float"/>
+                       <!-- @attribute x2 The x offset of the second off-curve point. -->
+                       <xs:attribute name="x2" type="Sk:Float"/>
+                       <!-- @attribute x3 The x offset of the final on-curve point. -->
+                       <xs:attribute name="x3" type="Sk:Float"/>
+                       <!-- @attribute y1 The y offset of the first off-curve point. -->
+                       <xs:attribute name="y1" type="Sk:Float"/>
+                       <!-- @attribute y2 The y offset of the second off-curve point. -->
+                       <xs:attribute name="y2" type="Sk:Float"/>
+                       <!-- @attribute y3 The y offset of the final on-curve point. -->
+                       <xs:attribute name="y3" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** rLineTo
+               RLineTo adds a line from the last point in a path to the specified point. The specified
+               point is relative to the last point in the path.
+       */ -->
+       <xs:element name="rLineTo">
+               <xs:complexType>
+                       <!-- @attribute x The final path x coordinate. -->
+                       <xs:attribute name="x" type="Sk:Float"/>
+                       <!-- @attribute y The final path y coordinate. -->
+                       <xs:attribute name="y" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** rMoveTo
+               RMoveTo specifies the first point in a path contour. The specified
+               point is relative to the last point in the path.
+       */ -->
+       <xs:element name="rMoveTo">
+               <xs:complexType>
+                       <!-- @attribute x The point's x coordinate. -->
+                       <xs:attribute name="x" type="Sk:Float"/>
+                       <!-- @attribute y The point's y coordinate. -->
+                       <xs:attribute name="y" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+               
+       <!-- /** rQuadTo
+               RQuadTo adds a quadratic curve to a path. The quadratic 
+               points are relative to the last point in the path.
+       */ -->
+       <xs:element name="rQuadTo">
+               <xs:complexType>
+                       <!-- @attribute x1 The x position of the off-curve point. -->
+                       <xs:attribute name="x1" type="Sk:Float"/>
+                       <!-- @attribute x2 The x position of the final point. -->
+                       <xs:attribute name="x2" type="Sk:Float"/>
+                       <!-- @attribute y1 The y position of the off-curve point. -->
+                       <xs:attribute name="y1" type="Sk:Float"/>
+                       <!-- @attribute y2 The y position of the final point. -->
+                       <xs:attribute name="y2" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+               
+       <!-- /** radialGradient
+               RadialGradient sets the paint shader to ramp between two or more colors in concentric circles. 
+       */ -->
+       <xs:element name="radialGradient">
+               <xs:complexType>
+                       <xs:choice maxOccurs="unbounded">
+                               <xs:element ref="Sk:color"/>
+                               <xs:element ref="Sk:matrix"/>
+                       </xs:choice>
+                       <!-- @attribute matrix Matrix applies a 3x3 transform to the gradient. -->
+                       <xs:attribute name="matrix" type="Sk:Matrix"/>
+                       <!-- @attribute tileMode One of @pattern. @patternDescription -->
+                       <xs:attribute name="tileMode" type="Sk:TileMode"/>
+                       <!-- @attribute center The center point of the radial gradient. -->
+                       <xs:attribute name="center" type="Sk:Point"/>
+                       <!-- @attribute offsets An optional array of values used to bias the colors. The first entry
+                               in the array must be 0.0, the last must be 1.0, and intermediate values must ascend. -->
+                       <xs:attribute name="offsets" type="Sk:FloatArray"/>
+                       <!-- @attribute radius The distance from the first color to the last color. -->
+                       <xs:attribute name="radius" type="Sk:Float"/>
+                       <!-- @attribute unitMapper A script that returns the mapping for [0,1] for the gradient.
+                               The script can use the predefined variable 'unit' to compute the mapping. For instance,
+                               "unit*unit" squares the value (while still keeping it in the range of [0,1].) The computed number
+                               is pinned to from 0 to 1 after the script is executed. -->
+                       <xs:attribute name="unitMapper" type="Sk:String"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** random
+               Random generates a random number, from min to max. Each time the random attribute is
+               read, a new random number is generated.
+       */ -->
+       <xs:element name="random">
+               <xs:complexType>
+                       <!-- @attribute blend The random bias from 0.0 to 1.0.
+                        0.0 biias the number towards the start and end of the range.
+                        1.0 (the default) generates a linear distribution.-->
+                       <xs:attribute name="blend" type="Sk:Float"/>
+                       <!-- @attribute max The largest value to generate. -->
+                       <xs:attribute name="max" type="Sk:Float"/>
+                       <!-- @attribute min The smallest value to generate. -->
+                       <xs:attribute name="min" type="Sk:Float"/>
+                       <!-- @attribute random The generated value. -->
+                       <xs:attribute name="random" type="Sk:Float"/>
+                       <!-- @attribute seed The random seed. Identical seeds generate the same series of 
+                       numbers. -->
+                       <xs:attribute name="seed" type="Sk:Int"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+
+       <!-- /** rect
+               Rect describes a bounding box.
+               The width and height attribute compute the rectangle's right and bottom edges when the rectangle
+               description is first seen. Animating the rectangle's left or top will not recompute the right or bottom
+               if the width or height have been specified.
+       */ -->
+       <xs:element name="rect">
+               <xs:complexType>
+                       <!-- @attribute bottom The bottom edge of the rectangle. -->
+                       <xs:attribute name="bottom" type="Sk:Float"/>
+                       <!-- @attribute height The height of the rectangle. Setting height computes the 
+                               bottom attribute from the top attribute. -->
+                       <xs:attribute name="height" type="Sk:Float"/>
+                       <!-- @attribute left The left edge of the rectangle. -->
+                       <xs:attribute name="left" type="Sk:Float"/>
+                       <!-- @attribute needsRedraw Set to true if last draw was visible. -->
+                       <xs:attribute name="needsRedraw" type="Sk:Boolean"/>
+                       <!-- @attribute right The right edge of the rectangle. -->
+                       <xs:attribute name="right" type="Sk:Float"/>
+                       <!-- @attribute top The top edge of the rectangle. -->
+                       <xs:attribute name="top" type="Sk:Float"/>
+                       <!-- @attribute width The width of the rectangle. -->
+                       <xs:attribute name="width" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** rectToRect
+               RectToRect adds a matrix to map one rectangle's coordinates to another.
+       */ -->
+       <xs:element name="rectToRect">
+               <xs:complexType>
+                       <xs:choice maxOccurs="2">
+                               <xs:element ref="Sk:rect"/>
+                       </xs:choice>
+                       <!-- @attribute source The rectangle to map from. -->
+                       <xs:attribute name="source" type="Sk:rect"/>
+                       <!-- @attribute destination The rectangle to map to. -->
+                       <xs:attribute name="destination" type="Sk:rect"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** remove
+               Remove an item from the display list.
+               If where is specified, the first occurance of where in the display list is removed.
+               If offset and where are specified, the element at where plus offset is removed.
+               A positive offset without where removes the element at the start of the list plus offset.
+               A negative offset without where removes the element at the end of the list minus offset.
+       */ -->
+       <xs:element name="remove">
+               <xs:complexType>
+                       <!-- @attribute delete If true, reverse the action of apply's attribute mode="create". 
+                               (Experimental.) -->
+                       <xs:attribute name="delete" type="Sk:Boolean"/>
+                       <!-- @attribute offset The destination position using the rules listed above. -->
+                       <xs:attribute name="offset" type="Sk:Int"/>
+                       <!-- @attribute where The ID of the first display list entry to remove. -->
+                       <xs:attribute name="where" type="Sk:Drawable"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** replace
+               Replace an item in the display list.
+               If where is specified, the first occurance of where in the display list is replaced by use.
+               If offset and where are specified, the element at where plus offset is replaced by use.
+               A positive offset without where replaces  the element at the start of the list plus offset.
+               A negative offset without where replaces the element at the end of the list minus offset.
+       */ -->
+       <xs:element name="replace">
+               <xs:complexType>
+                       <!-- @attribute mode Has no effect. -->
+                       <xs:attribute name="mode" type="Sk:AddMode"/>
+                       <!-- @attribute offset The destination position using the rules listed above. -->
+                       <xs:attribute name="offset" type="Sk:Int"/>
+                       <!-- @attribute use The element to be added to the display list.. -->
+                       <xs:attribute name="use" type="Sk:Drawable"/>
+                       <!-- @attribute where The ID of the first display list entry to remove. -->
+                       <xs:attribute name="where" type="Sk:Drawable"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+               
+       <!-- /** rotate
+               Rotate creates a matrix that rotates a unit vector about a center point, and concatenated
+               with the containing matrix.
+       */ -->
+       <xs:element name="rotate">
+               <xs:complexType>
+                       <!-- @attribute center A point the rotation is centered about; by default, [0.0, 0.0]. -->
+                       <xs:attribute name="center" type="Sk:Point"/>
+                       <!-- @attribute degrees The rotation in degrees. -->
+                       <xs:attribute name="degrees" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** roundRect
+               RoundRect creates a rectangle with rounded corners. The rounded corners are specified by
+               two axes, which describe an quarter-section of the oval which is used in each corner.
+               The width and height attribute compute the rectangle's right and bottom edges when the rectangle
+               description is first seen. Animating the rectangle's left or top will not recompute the right or bottom
+               if the width or height have been specified.
+       */ -->
+       <xs:element name="roundRect">
+               <xs:complexType>
+                       <!-- @attribute bottom The bottom edge of the rectangle. -->
+                       <xs:attribute name="bottom" type="Sk:Float"/>
+                       <!-- @attribute height The height of the rectangle. Setting height computes the 
+                               bottom attribute from the top attribute. -->
+                       <xs:attribute name="height" type="Sk:Float"/>
+                       <!-- @attribute left The left edge of the rectangle. -->
+                       <xs:attribute name="left" type="Sk:Float"/>
+                       <!-- @attribute needsRedraw Set to true if last draw was visible. -->
+                       <xs:attribute name="needsRedraw" type="Sk:Boolean"/>
+                       <!-- @attribute right The right edge of the rectangle. -->
+                       <xs:attribute name="right" type="Sk:Float"/>
+                       <!-- @attribute top The top edge of the rectangle. -->
+                       <xs:attribute name="top" type="Sk:Float"/>
+                       <!-- @attribute rx The radius of the corners on the x axis. -->
+                       <xs:attribute name="rx" type="Sk:Float"/>
+                       <!-- @attribute ry The radius of the corners on the y axis. -->
+                       <xs:attribute name="ry" type="Sk:Float"/>
+                       <!-- @attribute width The width of the rectangle. Setting width computes the 
+                               right attribute from the left attribute. -->
+                       <xs:attribute name="width" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** save
+               The save element collects a series of elements into a group. The state of the paint and
+               canvas are saved, so that edits to the paint and canvas within the group are restored
+               to their original value at the end of the group. 
+               The save element can be referenced
+               or defined within elements, like apply, which operate on any kind of element. Groups 
+               may contain groups. 
+       */ -->
+       <xs:element name="save">
+               <xs:complexType>
+                       <xs:choice maxOccurs="unbounded">
+                               <xs:element ref="Sk:add"/>
+                               <xs:element ref="Sk:apply"/>
+                               <xs:element ref="Sk:array"/>
+                               <xs:element ref="Sk:bitmap"/>
+                               <xs:element ref="Sk:boolean"/>
+                               <xs:element ref="Sk:bounds"/>
+               <!--            <xs:element ref="Sk3D:camera"/>    -->
+                               <xs:element ref="Sk:clear"/>
+                               <xs:element ref="Sk:clip"/>
+                               <xs:element ref="Sk:color"/>
+                               <xs:element ref="Sk:drawTo"/>
+                               <xs:element ref="Sk:float"/>
+                               <xs:element ref="Sk:full"/>
+                               <xs:element ref="Sk:group"/>
+                               <xs:element ref="Sk:hitClear"/>
+                               <xs:element ref="Sk:hitTest"/>
+                               <xs:element ref="Sk:image"/>
+                               <xs:element ref="Sk:int"/>
+                               <xs:element ref="Sk:line"/>
+                               <xs:element ref="Sk:matrix"/>
+                               <xs:element ref="Sk:move"/>
+                               <xs:element ref="Sk:oval"/>
+                               <xs:element ref="Sk:paint"/>
+                       <!--    <xs:element ref="Sk:patch"/>   -->
+                               <xs:element ref="Sk:path"/>
+                               <xs:element ref="Sk:point"/>
+                               <xs:element ref="Sk:polygon"/>
+                               <xs:element ref="Sk:polyline"/>
+                               <xs:element ref="Sk:post"/>
+                               <xs:element ref="Sk:random"/>
+                               <xs:element ref="Sk:rect"/>
+                               <xs:element ref="Sk:remove"/>
+                               <xs:element ref="Sk:replace"/>
+                               <xs:element ref="Sk:roundRect"/>
+                               <xs:element ref="Sk:save"/>
+                               <xs:element ref="Sk:set"/>
+                               <xs:element ref="Sk:snapshot"/>
+                               <xs:element ref="Sk:string"/>
+                               <xs:element ref="Sk:text"/>
+                               <xs:element ref="Sk:textBox"/>
+                               <xs:element ref="Sk:textOnPath"/>
+                               <xs:element ref="Sk:textToPath"/>
+                       </xs:choice>
+                       <!-- @attribute condition If present and zero, the contained elements are ignored. -->
+                       <xs:attribute name="condition" type="Sk:DynamicString"/>
+                       <!-- @attribute enableCondition If present and zero, the contained elements are ignored
+                               when enabled. -->
+                       <xs:attribute name="enableCondition" type="Sk:DynamicString"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** scale
+               Scale creates a matrix that scales a unit vector about a center point, and concatenated
+               with the containing matrix.
+       */ -->
+       <xs:element name="scale">
+               <xs:complexType>
+                       <!-- @attribute center A point the scale is centered about; by default, [0.0, 0.0]. -->
+                       <xs:attribute name="center" type="Sk:Point"/>
+                       <!-- @attribute x The factor all x values are scaled by; by default, 1.0.  -->
+                       <xs:attribute name="x" type="Sk:Float"/>
+                       <!-- @attribute y The factor all y values are scaled by; by default, 1.0.  -->
+                       <xs:attribute name="y" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** screenplay
+               Screenplay contains all events and elements referenced by the events.
+               A document may only contain a single screenplay element.
+       */ -->
+       <xs:element name="screenplay">
+               <xs:complexType>
+                       <xs:choice maxOccurs="unbounded" >
+                               <xs:element ref="Sk:add"/>
+                               <xs:element ref="Sk:apply"/>
+                               <xs:element ref="Sk:array"/>
+                               <xs:element ref="Sk:bitmap"/>
+                               <xs:element ref="Sk:boolean"/>
+                               <xs:element ref="Sk:bounds"/>
+               <!--            <xs:element ref="Sk3D:camera"/>    -->
+                               <xs:element ref="Sk:clear"/>
+                               <xs:element ref="Sk:clip"/>
+                               <xs:element ref="Sk:color"/>
+                               <xs:element ref="Sk:drawTo"/>
+                               <xs:element ref="Sk:event"/>
+                               <xs:element ref="Sk:float"/>
+                               <xs:element ref="Sk:full"/>
+                               <xs:element ref="Sk:group"/>
+                               <xs:element ref="Sk:hitClear"/>
+                               <xs:element ref="Sk:hitTest"/>
+                               <xs:element ref="Sk:image"/>
+                               <xs:element ref="Sk:include"/>
+                               <xs:element ref="Sk:int"/>
+                               <xs:element ref="Sk:line"/>
+                               <xs:element ref="Sk:matrix"/>
+                               <xs:element ref="Sk:move"/>
+                               <xs:element ref="Sk:movie"/>
+                               <xs:element ref="Sk:oval"/>
+                               <xs:element ref="Sk:paint"/>
+                       <!--    <xs:element ref="Sk:patch"/>   -->
+                               <xs:element ref="Sk:path"/>
+                               <xs:element ref="Sk:point"/>
+                               <xs:element ref="Sk:polygon"/>
+                               <xs:element ref="Sk:polyline"/>
+                               <xs:element ref="Sk:post"/>
+                               <xs:element ref="Sk:random"/>
+                               <xs:element ref="Sk:rect"/>
+                               <xs:element ref="Sk:remove"/>
+                               <xs:element ref="Sk:replace"/>
+                               <xs:element ref="Sk:roundRect"/>
+                               <xs:element ref="Sk:save"/>
+                               <xs:element ref="Sk:set"/>
+                               <xs:element ref="Sk:snapshot"/>
+                               <xs:element ref="Sk:string"/>
+                               <xs:element ref="Sk:text"/>
+                               <xs:element ref="Sk:textBox"/>
+                               <xs:element ref="Sk:textOnPath"/>
+                               <xs:element ref="Sk:textToPath"/>
+                       </xs:choice>
+                       <!-- @attribute time The time of the draw (readable from script; not part of the document XML) -->
+                       <xs:attribute name="time" type="Sk:MSec"/>
+       </xs:complexType>
+       </xs:element>
+       
+       <!-- /** set
+               Set animates the target element's attribute directly to the specified value.
+       */ -->
+       <xs:element name="set">
+               <xs:complexType>
+                       <!-- @attribute begin An optional offset that must elapse before the animation begins. The apply
+                               begin attribute is added to any animator's begin attribute. -->
+                       <xs:attribute name="begin" type="Sk:MSec"/>
+                       <!-- @attribute dur The duration of the animation in milliseconds. -->
+                       <xs:attribute name="dur" type="Sk:MSec"/>
+                       <!-- @attribute dynamic If true, restart the animation if any of the simple values the 
+                        'lval' or 'to' attributes reference are changed. Simple values are contained by the array, boolean, float, int, 
+                        and string elements. -->
+                       <!-- @attribute dynamic [Depreciated.] -->
+                       <xs:attribute name="dynamic" type="Sk:Boolean" />
+                       <!-- @attribute field The attribute to animate. -->
+                       <xs:attribute name="field" type="Sk:String"/>
+                       <!-- @attribute formula A script to execute over time to compute the field's value. Typically,
+                               the fomula is a script expression which includes a reference to the time attribute of the 
+                               containing apply        element.  -->
+                       <xs:attribute name="formula" type="Sk:DynamicString"/>
+                       <!-- @attribute lval An expression evaluating to the attribute to animate.
+                               If present, lval overrides 'field'. The expression is typically an array element,
+                               e.g. lval="x[y]" . -->
+                       <xs:attribute name="lval" type="Sk:DynamicString"/>
+                       <!-- @attribute reset  If true, the computed value is the initial value after the 
+                               animation is complete. If false, or by default, the computed value is the final value 
+                               after the animation is complete. -->
+                       <xs:attribute name="reset" type="Sk:Boolean"/>
+                       <!-- @attribute step When apply's attribute mode="immediate" or "create", the step attribute can be read by 
+                               script to determine the current animation iteration.  -->
+                       <xs:attribute name="step" type="Sk:Int" />
+                       <!-- @attribute target The element to animate. By default, the element contained by the apply
+                               or referenced by the apply's scope attribute is the animate target. -->
+                       <xs:attribute name="target" type="Sk:DynamicString"/>
+                       <!-- @attribute to The ending value (requires a 'from' attribute) -->
+                       <xs:attribute name="to" type="Sk:DynamicString"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** skew
+               Skew creates a matrix that skews a unit vector about a center point, and concatenated
+               with the containing matrix.
+       */ -->
+       <xs:element name="skew">
+               <xs:complexType>
+                       <!-- @attribute center A point the skew is centered about; by default, [0.0, 0.0]. -->
+                       <xs:attribute name="center" type="Sk:Point"/>
+                       <!-- @attribute x The factor all x values are skewed by; by default, 0.0.  -->
+                       <xs:attribute name="x" type="Sk:Float"/>
+                       <!-- @attribute y The factor all y values are skewed by; by default, 0.0.  -->
+                       <xs:attribute name="y" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** snapshot
+               Snapshot creates an image file containing the display list.
+       */ -->
+       <xs:element name="snapshot">
+               <xs:complexType>
+                       <!-- @attribute filename The name of the file to generate. -->
+                       <xs:attribute name="filename" type="Sk:String"/>
+                       <!-- @attribute quality The quality of the image, from 0 to 100. -->
+                       <xs:attribute name="quality" type="Sk:Float"/>
+                       <!-- @attribute sequence Set to true to number the filenames sequentially. -->
+                       <xs:attribute name="sequence" type="Sk:Boolean"/>
+                       <!-- @attribute type One of @pattern. The type of encoding to use. -->
+                       <xs:attribute name="type" type="Sk:BitmapEncoding"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** string
+               String contains an array of characters.
+       */ -->
+       <xs:element name="string" >
+               <xs:complexType>
+                       <!-- @attribute length The number of characters in the string (read only). -->
+                       <xs:attribute name="length" type="Sk:Int"/>
+                       <!-- @attribute slice An ECMAScript compatible function that returns part of the string. -->
+                       <xs:attribute name="slice" type="Sk:String"/>
+                       <!-- @attribute value The string itself. -->
+                       <xs:attribute name="value" type="Sk:String"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** text
+               A drawable string with a position.
+       */ -->
+       <xs:element name="text">
+               <xs:complexType>
+                       <!-- @attribute length The number of characters in the string (read only). -->
+                       <xs:attribute name="length" type="Sk:Int"/>
+                       <!-- @attribute text The string itself. -->
+                       <xs:attribute name="text" type="Sk:String"/>
+                       <!-- @attribute x The x coordinate of the string. -->
+                       <xs:attribute name="x" type="Sk:Float"/>
+                       <!-- @attribute y The y coordinate of the string. -->
+                       <xs:attribute name="y" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** textBox
+               A drawable string fit into a box.
+       */ -->
+       <xs:element name="textBox" >
+               <xs:complexType>
+                       <!-- @attribute bottom The bottom of the box. -->
+                       <xs:attribute name="bottom" type="Sk:Float"/>
+                       <!-- @attribute height The height of the box, computed from top and bottom. -->
+                       <xs:attribute name="height" type="Sk:Float"/>
+                       <!-- @attribute left The left side of the box. -->
+                       <xs:attribute name="left" type="Sk:Float"/>
+                       <!-- @attribute mode One of @pattern. -->
+                       <xs:attribute name="mode" type="Sk:TextBoxMode"/>
+                       <!-- @attribute needsRedraw Set to true if last draw was visible. -->
+                       <xs:attribute name="needsRedraw" type="Sk:Boolean"/>
+                       <!-- @attribute right The right side of the box. -->
+                       <xs:attribute name="right" type="Sk:Float"/>
+                       <!-- @attribute spacingAdd The extra spacing between lines. -->
+                       <xs:attribute name="spacingAdd" type="Sk:Float"/>
+                       <!-- @attribute spacingAlign One of @pattern. -->
+                       <xs:attribute name="spacingAlign" type="Sk:TextBoxAlign"/>
+                       <!-- @attribute spacingMul The line spacing scaled by the text height. -->
+                       <xs:attribute name="spacingMul" type="Sk:Float"/>
+                       <!-- @attribute text The text to fit to the box. -->
+                       <xs:attribute name="text" type="Sk:String"/>
+                       <!-- @attribute top The top of the box. -->
+                       <xs:attribute name="top" type="Sk:Float"/>
+                       <!-- @attribute width The width of the box, computed from left and right. -->
+                       <xs:attribute name="width" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** textOnPath
+               TextOnPath specifies the baseline for a string of text with a path.
+       */ -->
+       <xs:element name="textOnPath">
+               <xs:complexType>
+                       <xs:choice >
+                               <xs:element ref="Sk:text" minOccurs="0" />
+                               <xs:element ref="Sk:path" minOccurs="0" />
+                       </xs:choice>
+                       <!-- @attribute offset The distance along the path to place the first text character. -->
+                       <xs:attribute name="offset" type="Sk:Float"/>
+                       <!-- @attribute path The baseline of the text. -->
+                       <xs:attribute name="path" type="Sk:Path"/>
+                       <!-- @attribute text The text to place along the path. -->
+                       <xs:attribute name="text" type="Sk:Text"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** textToPath
+               TextToPath sets the path to the contours described by the text's glyphs, using the current paint.
+       */ -->
+       <xs:element name="textToPath">
+               <xs:complexType>
+                       <xs:choice >
+                               <xs:element ref="Sk:text" minOccurs="0" />
+                               <xs:element ref="Sk:paint" minOccurs="0" />
+                               <xs:element ref="Sk:path" minOccurs="0" />
+                       </xs:choice>
+                       <!-- @attribute paint The paint selects the text font, size and other text properties. -->
+                       <xs:attribute name="paint" type="Sk:Paint"/>
+                       <!-- @attribute path The reference to the path element where the text as path is stored. -->
+                       <xs:attribute name="path" type="Sk:Path"/>
+                       <!-- @attribute text The reference to the text element to turn into a path. -->
+                       <xs:attribute name="text" type="Sk:Text"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** translate
+               Translate concatenates a translation-only matrix onto the current matrix.
+       */ -->
+       <xs:element name="translate">
+               <xs:complexType>
+                       <!-- @attribute x The translation in x. -->
+                       <xs:attribute name="x" type="Sk:Float"/>
+                       <!-- @attribute y The translation in y. -->
+                       <xs:attribute name="y" type="Sk:Float"/>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** transparentShader
+               TransparentShader uses the background for its paint.  Works well with emboss.
+       */ -->
+       <xs:element name="transparentShader">
+               <xs:complexType>
+                       <xs:attribute name="id" type="xs:ID"/>
+               </xs:complexType>
+       </xs:element>
+       
+       <!-- /** typeface
+               Typeface describes the text font.
+       */ -->
+       <xs:element name="typeface">
+               <xs:complexType>
+                       <!-- @attribute fontName The name of the font. -->
+                       <xs:attribute name="fontName" type="Sk:String"/>
+               </xs:complexType>
+       </xs:element>
+       
+</xs:schema>
+
diff --git a/libs/graphics/animator/SkAnimateSchema.xsx b/libs/graphics/animator/SkAnimateSchema.xsx
new file mode 100644 (file)
index 0000000..ceb7d89
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<!--This file is auto-generated by the XML Schema Designer. It holds layout information for components on the designer surface.-->\r
+<XSDDesignerLayout />
diff --git a/libs/graphics/animator/SkAnimateSet.cpp b/libs/graphics/animator/SkAnimateSet.cpp
new file mode 100644 (file)
index 0000000..4de2de5
--- /dev/null
@@ -0,0 +1,81 @@
+#include "SkAnimateSet.h"
+#include "SkAnimateMaker.h"
+#include "SkAnimateProperties.h"
+#include "SkParse.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkSet::fInfo[] = {
+       SK_MEMBER(begin, MSec),
+       SK_MEMBER(dur, MSec),
+       SK_MEMBER_PROPERTY(dynamic, Boolean),
+       SK_MEMBER(field, String),
+//     SK_MEMBER(formula, DynamicString),
+       SK_MEMBER(lval, DynamicString),
+//     SK_MEMBER_PROPERTY(reset, Boolean),
+       SK_MEMBER_PROPERTY(step, Int),
+       SK_MEMBER(target, DynamicString),
+       SK_MEMBER(to, DynamicString)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkSet);
+
+SkSet::SkSet() {
+       dur = 1; 
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkSet::dump(SkAnimateMaker* maker) {
+       INHERITED::dump(maker);
+       if (dur != 1) {
+#ifdef SK_CAN_USE_FLOAT
+               SkDebugf("dur=\"%g\" ", SkScalarToFloat(SkScalarDiv(dur,1000)));
+#else
+               SkDebugf("dur=\"%x\" ", SkScalarDiv(dur,1000));
+#endif
+    }
+    //don't want double />\n's
+    SkDebugf("/>\n");
+
+}
+#endif
+
+void SkSet::refresh(SkAnimateMaker& maker) {
+       fFieldInfo->setValue(maker, &fValues, 0, fFieldInfo->fCount, nil, 
+               fFieldInfo->getType(), to);
+}
+
+void SkSet::onEndElement(SkAnimateMaker& maker) {
+       if (resolveCommon(maker) == false)
+               return;
+       if (fFieldInfo == nil) {
+               maker.setErrorCode(SkDisplayXMLParserError::kFieldNotInTarget);
+               return;
+       }
+       fReset = dur != 1;
+       SkDisplayTypes outType = fFieldInfo->getType();
+       int comps = outType == SkType_String || outType == SkType_DynamicString ? 1 :
+               fFieldInfo->getSize((const SkDisplayable*) fTarget) / sizeof(int);
+       if (fValues.getType() == SkType_Unknown) {
+               fValues.setType(outType);
+               fValues.setCount(comps);
+               if (outType == SkType_String || outType == SkType_DynamicString)
+                       fValues[0].fString = SkNEW(SkString);
+               else
+                       memset(fValues.begin(), 0, fValues.count() * sizeof(fValues.begin()[0]));
+       } else {
+               SkASSERT(fValues.getType() == outType);
+               if (fFieldInfo->fType == SkType_Array)
+                       comps = fValues.count();
+               else
+                       SkASSERT(fValues.count() == comps);
+       }
+       if (formula.size() > 0) {
+               comps = 1;
+               outType = SkType_MSec;
+       }
+       fFieldInfo->setValue(maker, &fValues, fFieldOffset, comps, this, outType, formula.size() > 0 ? formula : to);
+       fComponents = fValues.count();
+}
diff --git a/libs/graphics/animator/SkAnimateSet.h b/libs/graphics/animator/SkAnimateSet.h
new file mode 100644 (file)
index 0000000..476459f
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef SkAnimateSet_DEFINED
+#define SkAnimateSet_DEFINED
+
+#include "SkAnimate.h"
+
+class SkSet : public SkAnimate {
+       DECLARE_MEMBER_INFO(Set);
+       SkSet();
+#ifdef SK_DUMP_ENABLED
+       virtual void dump(SkAnimateMaker* );
+#endif
+       virtual void onEndElement(SkAnimateMaker& );
+       virtual void refresh(SkAnimateMaker& );
+private:
+       typedef SkAnimate INHERITED;
+};
+
+#endif // SkAnimateSet_DEFINED
+
diff --git a/libs/graphics/animator/SkAnimator.cpp b/libs/graphics/animator/SkAnimator.cpp
new file mode 100644 (file)
index 0000000..17f6855
--- /dev/null
@@ -0,0 +1,705 @@
+#include "SkAnimator.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+#include "SkDisplayApply.h"
+#include "SkDisplayMovie.h"
+#include "SkDisplayTypes.h"
+#include "SkDisplayXMLParser.h"
+#include "SkStream.h"
+#include "SkScript.h"
+#include "SkScript2.h" //      compiled script experiment
+#include "SkSystemEventTypes.h"
+#include "SkTypedArray.h"
+#ifdef ANDROID
+#include "SkDrawExtraPathEffect.h"
+#endif
+#ifdef SK_DEBUG
+#include "SkTime.h"
+#endif
+
+#if defined SK_BUILD_FOR_WIN32 && defined SK_DEBUG
+       #define _static
+       extern const char gMathPrimerText[];
+       extern const char gMathPrimerBinary[];
+#else
+       #define _static static
+#endif
+
+#if !defined SK_BUILD_FOR_BREW || defined SK_DEBUG
+       _static const char gMathPrimerText[] = 
+       "<screenplay>"
+               "<Math id=\"Math\"/>"
+               "<Number id=\"Number\"/>"
+       "</screenplay>";
+#endif
+
+#if defined SK_BUILD_FOR_BREW || defined SK_DEBUG
+       _static const char gMathPrimerBinary[] = 
+       "\x0Ascreenplay\x04Mathbid\x04Math@@";  // !!! now out of date -- does not include Number
+#endif
+
+#if defined SK_BUILD_FOR_BREW
+       #define gMathPrimer gMathPrimerBinary
+#else
+       #define gMathPrimer gMathPrimerText
+#endif
+
+SkAnimator::SkAnimator() : fMaker(nil) {
+       initialize();
+}
+
+SkAnimator::~SkAnimator() {
+       SkDELETE(fMaker);
+}
+
+void SkAnimator::addExtras(SkExtras* extras) {
+       *fMaker->fExtras.append() = extras;
+}
+
+bool SkAnimator::appendStream(SkStream* stream) {
+       return decodeStream(stream);
+}
+
+bool SkAnimator::decodeMemory(const void* buffer, size_t size)
+{
+       fMaker->fFileName.reset();
+       SkDisplayXMLParser parser(*fMaker);
+       return parser.parse((const char*)buffer, size);
+}
+
+bool SkAnimator::decodeStream(SkStream* stream)
+{
+       SkDisplayXMLParser parser(*fMaker);
+       bool result = parser.parse(*stream);
+       fMaker->setErrorString();
+       return result;
+}
+
+bool SkAnimator::decodeDOM(const SkDOM& dom, const SkDOMNode* node)
+{
+       fMaker->fFileName.reset();
+       SkDisplayXMLParser parser(*fMaker);
+       return parser.parse(dom, node);
+}
+
+bool SkAnimator::decodeURI(const char uri[]) {
+//     SkDebugf("animator decode %s\n", uri);
+       SkStream* stream = SkStream::GetURIStream(fMaker->fPrefix.c_str(), uri);
+       SkAutoTDelete<SkStream> autoDel(stream);
+       setURIBase(uri);
+       return decodeStream(stream);
+}
+
+bool SkAnimator::doCharEvent(SkUnichar code) {
+       if (code == 0)
+               return false;
+       struct SkEventState state;
+       state.fCode = code;
+       fMaker->fEnableTime = fMaker->getAppTime();
+       bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kKeyChar, &state);
+       fMaker->notifyInval();
+       return result;
+}
+
+bool SkAnimator::doClickEvent(int clickState, SkScalar x, SkScalar y) {
+       SkASSERT(clickState >= 0 && clickState <= 2);
+       struct SkEventState state;
+       state.fX = x;
+       state.fY = y;
+       fMaker->fEnableTime = fMaker->getAppTime();
+       bool result = fMaker->fEvents.doEvent(*fMaker, 
+               clickState == 0 ? SkDisplayEvent::kMouseDown : 
+               clickState == 1 ? SkDisplayEvent::kMouseDrag : 
+               SkDisplayEvent::kMouseUp, &state);
+       fMaker->notifyInval();
+       return result;
+}
+
+bool SkAnimator::doKeyEvent(SkKey code) {
+       if (code == 0)
+               return false;
+       struct SkEventState state;
+       state.fCode = code;
+       fMaker->fEnableTime = fMaker->getAppTime();
+       bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kKeyPress, &state);
+       fMaker->notifyInval();
+       return result;
+}
+
+bool SkAnimator::doKeyUpEvent(SkKey code) {
+    if (code == 0)
+        return false;
+    struct SkEventState state;
+    state.fCode = code;
+    fMaker->fEnableTime = fMaker->getAppTime();
+    bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kKeyPressUp, &state);
+    fMaker->notifyInval();
+    return result;
+}
+
+bool SkAnimator::doUserEvent(const SkEvent& evt) {
+       fMaker->fEnableTime = fMaker->getAppTime();
+       return onEvent(evt);
+}
+
+SkAnimator::DifferenceType SkAnimator::draw(SkCanvas* canvas, SkPaint* paint, SkMSec time) {
+       if (paint == nil)
+               return draw(canvas, time);
+       fMaker->fScreenplay.time = time;
+       fMaker->fCanvas = canvas;
+       fMaker->fPaint = paint;
+       fMaker->fCanvas->getPixels(&fMaker->fBitmap);
+       fMaker->fDisplayList.fHasUnion = false;
+       int result = fMaker->fDisplayList.draw(*fMaker, time);
+       if (result)
+               result += fMaker->fDisplayList.fHasUnion;
+       return (DifferenceType) result;
+}
+
+SkAnimator::DifferenceType SkAnimator::draw(SkCanvas* canvas, SkMSec time) {
+       SkPaint paint;
+       return draw(canvas, &paint, time);
+}
+       
+#ifdef SK_DEBUG
+void SkAnimator::eventDone(const SkEvent& ) {
+}
+#endif
+
+bool SkAnimator::findClickEvent(SkScalar x, SkScalar y) {
+       struct SkEventState state;
+       state.fDisable = true;
+       state.fX = x;
+       state.fY = y;
+       fMaker->fEnableTime = fMaker->getAppTime();
+       bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kMouseDown, &state);
+       fMaker->notifyInval();
+       return result;
+}
+
+const SkAnimator* SkAnimator::getAnimator(const SkDisplayable* displayable) const {
+       if (displayable->getType() != SkType_Movie)
+               return nil;
+       const SkDisplayMovie* movie = (const SkDisplayMovie*) displayable;
+       return movie->getAnimator();
+}
+
+const SkDisplayable* SkAnimator::getElement(const char* id) {
+       SkDisplayable* element;
+       if (fMaker->find(id, &element) == false)
+               return nil;
+       return (const SkDisplayable*) element;
+}
+
+SkElementType SkAnimator::getElementType(const SkDisplayable* ae) {
+       SkDisplayable* element = (SkDisplayable*) ae;
+       const SkMemberInfo* info = SkDisplayType::GetMembers(fMaker, element->getType(), nil);
+       return (SkElementType) SkDisplayType::Find(fMaker, info);
+}
+
+SkElementType SkAnimator::getElementType(const char* id) {
+       const SkDisplayable* element = getElement(id);
+       return getElementType(element);
+}
+
+const SkMemberInfo* SkAnimator::getField(const SkDisplayable* ae, const char* field) {
+       SkDisplayable* element = (SkDisplayable*) ae;
+       const SkMemberInfo* info = element->getMember(field);
+       return (const SkMemberInfo*) info;
+}
+
+const SkMemberInfo* SkAnimator::getField(const char* elementID, const char* field) {
+       const SkDisplayable* element = getElement(elementID);
+       return getField(element, field);
+}
+
+SkFieldType SkAnimator::getFieldType(const SkMemberInfo* ai) {
+       const SkMemberInfo* info = (const SkMemberInfo*) ai;
+       return (SkFieldType) info->getType();
+}
+
+SkFieldType SkAnimator::getFieldType(const char* id, const char* fieldID) {
+       const SkMemberInfo* field = getField(id, fieldID);
+       return getFieldType(field);
+}
+
+ static bool getArrayCommon(const SkDisplayable* ae, const SkMemberInfo* ai,
+        int index, SkOperand* operand, SkDisplayTypes type) {
+       const SkDisplayable* element = (const SkDisplayable*) ae;
+       const SkMemberInfo* info = (const SkMemberInfo*) ai;
+       SkASSERT(info->fType == SkType_Array);
+       return info->getArrayValue(element, index, operand);
+}
+
+int32_t SkAnimator::getArrayInt(const SkDisplayable* ae, 
+               const SkMemberInfo* ai, int index) {
+       SkOperand operand;
+       bool result = getArrayCommon(ae, ai, index, &operand, SkType_Int);
+       return result ? operand.fS32 : SK_NaN32;
+}
+
+int32_t SkAnimator::getArrayInt(const char* id, const char* fieldID, int index) {
+       const SkDisplayable* element = getElement(id);
+       if (element == nil)
+               return SK_NaN32;
+       const SkMemberInfo* field = getField(element, fieldID);
+       if (field == nil)
+               return SK_NaN32;
+       return getArrayInt(element, field, index);
+}
+
+SkScalar SkAnimator::getArrayScalar(const SkDisplayable* ae, 
+               const SkMemberInfo* ai, int index) {
+       SkOperand operand;
+       bool result = getArrayCommon(ae, ai, index, &operand, SkType_Float);
+       return result ? operand.fScalar : SK_ScalarNaN;
+}
+
+SkScalar SkAnimator::getArrayScalar(const char* id, const char* fieldID, int index) {
+       const SkDisplayable* element = getElement(id);
+       if (element == nil)
+               return SK_ScalarNaN;
+       const SkMemberInfo* field = getField(element, fieldID);
+       if (field == nil)
+               return SK_ScalarNaN;
+       return getArrayScalar(element, field, index);
+}
+
+const char* SkAnimator::getArrayString(const SkDisplayable* ae, 
+               const SkMemberInfo* ai, int index) {
+       SkOperand operand;
+       bool result = getArrayCommon(ae, ai, index, &operand, SkType_String);
+       return result ? operand.fString->c_str() : nil;
+}
+
+const char* SkAnimator::getArrayString(const char* id, const char* fieldID, int index) {
+       const SkDisplayable* element = getElement(id);
+       if (element == nil)
+               return nil;
+       const SkMemberInfo* field = getField(element, fieldID);
+       if (field == nil)
+               return nil;
+       return getArrayString(element, field, index);
+}
+
+SkMSec SkAnimator::getInterval() {
+       return fMaker->fMinimumInterval == (SkMSec) -1 ? 0 : fMaker->fMinimumInterval;
+}
+
+void SkAnimator::getInvalBounds(SkRect* inval) {
+       if (fMaker->fDisplayList.fHasUnion) {
+               inval->fLeft = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fLeft);
+               inval->fTop = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fTop);
+               inval->fRight = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fRight);
+               inval->fBottom = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fBottom);
+       } else {
+               inval->fLeft = inval->fTop = -SK_ScalarMax;
+               inval->fRight = inval->fBottom = SK_ScalarMax;
+       }
+}
+
+const SkXMLParserError* SkAnimator::getParserError() {
+       return &fMaker->fError;
+}
+
+const char* SkAnimator::getParserErrorString() {
+       if (fMaker->fErrorString.size() == 0 && fMaker->fError.hasError())
+               fMaker->setErrorString();
+       return fMaker->fErrorString.c_str();
+}
+
+int32_t SkAnimator::getInt(const SkDisplayable* element, const SkMemberInfo* info) {
+       if (info->fType != SkType_MemberProperty) {
+               SkOperand operand;
+               if (info->getType() == SkType_Int) {
+                       info->getValue(element, &operand, 1);
+                       return operand.fS32;
+               }
+               return SK_NaN32;
+       }
+       SkScriptValue scriptValue;
+       bool success = element->getProperty(info->propertyIndex(), &scriptValue);
+       if (success && scriptValue.fType == SkType_Int)
+               return scriptValue.fOperand.fS32;
+       return SK_NaN32;
+}
+
+int32_t SkAnimator::getInt(const char* id, const char* fieldID) {
+       const SkDisplayable* element = getElement(id);
+       if (element == nil)
+               return SK_NaN32;
+       const SkMemberInfo* field = getField(element, fieldID);
+       if (field == nil)
+               return SK_NaN32;
+       return getInt(element, field);
+}
+
+SkScalar SkAnimator::getScalar(const SkDisplayable* element, const SkMemberInfo* info) {
+       if (info->fType != SkType_MemberProperty) {
+               SkOperand operand;
+               if (info->getType() == SkType_Float) {
+                       info->getValue(element, &operand, 1);
+                       return operand.fScalar;
+               }
+               return SK_ScalarNaN;
+       }
+       SkScriptValue scriptValue;
+       bool success = element->getProperty(info->propertyIndex(), &scriptValue);
+       if (success && scriptValue.fType == SkType_Float)
+               return scriptValue.fOperand.fScalar;
+       return SK_ScalarNaN;
+}
+
+SkScalar SkAnimator::getScalar(const char* id, const char* fieldID) {
+       const SkDisplayable* element = getElement(id);
+       if (element == nil)
+               return SK_ScalarNaN;
+       const SkMemberInfo* field = getField(element, fieldID);
+       if (field == nil)
+               return SK_ScalarNaN;
+       return getScalar(element, field);
+}
+
+const char* SkAnimator::getString(const SkDisplayable* ae, 
+               const SkMemberInfo* ai) {
+       const SkDisplayable* element = (const SkDisplayable*) ae;
+       const SkMemberInfo* info = (const SkMemberInfo*) ai;
+       SkString* temp;
+       info->getString(element, &temp);
+       return temp->c_str();
+}
+
+const char* SkAnimator::getString(const char* id, const char* fieldID) {
+       const SkDisplayable* element = getElement(id);
+       if (element == nil)
+               return nil;
+       const SkMemberInfo* field = getField(element, fieldID);
+       if (field == nil)
+               return nil;
+       return getString(element, field);
+}
+
+const char* SkAnimator::getURIBase() {
+       return fMaker->fPrefix.c_str();
+}
+
+void SkAnimator::initialize() {
+       SkDELETE(fMaker);
+       fMaker = SkNEW_ARGS(SkAnimateMaker, (this, nil, nil));
+       decodeMemory(gMathPrimer, sizeof(gMathPrimer)-1);
+#ifdef ANDROID
+    InitializeSkExtraPathEffects(this);
+#endif
+}
+
+
+#ifdef SK_DEBUG
+bool SkAnimator::isTrackingEvents() {
+       return false;
+}
+#endif
+
+bool SkAnimator::onEvent(const SkEvent& evt) {
+#ifdef SK_DEBUG
+       SkAnimator* root = fMaker->getRoot();
+       if (root == nil)
+               root = this;
+       if (root->isTrackingEvents())
+               root->eventDone(evt);
+#endif
+       if (evt.isType(SK_EventType_OnEnd)) {
+               SkEventState eventState;
+               bool success = evt.findPtr("anim", (void**) &eventState.fDisplayable);
+               SkASSERT(success);
+               success = evt.findS32("time", (int32_t*) &fMaker->fEnableTime);
+               SkASSERT(success);
+               fMaker->fAdjustedStart = fMaker->getAppTime() - fMaker->fEnableTime;
+               fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kOnEnd, &eventState);
+               fMaker->fAdjustedStart = 0;
+               goto inval;
+       }
+       if (evt.isType(SK_EventType_Delay)) {
+               fMaker->doDelayedEvent();
+               goto inval;
+       }
+       {
+               const char* id = evt.findString("id");
+               if (id == nil)
+                       return false;
+               SkDisplayable** firstMovie = fMaker->fMovies.begin();
+               SkDisplayable** endMovie = fMaker->fMovies.end();
+               for (SkDisplayable** ptr = firstMovie; ptr < endMovie; ptr++) {
+                       SkDisplayMovie* movie = (SkDisplayMovie*) *ptr;
+                       movie->doEvent(evt);
+               }
+               {
+                       SkDisplayable* event;
+                       if (fMaker->find(id, &event) == false)
+                               return false;
+       #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
+                       SkString debugOut;
+                       SkMSec realTime = fMaker->getAppTime();
+                       debugOut.appendS32(realTime - fMaker->fDebugTimeBase);
+                       debugOut.append(" onEvent id=");
+                       debugOut.append(id);
+       #endif
+                       SkMSec time = evt.getFast32();
+                       if (time != 0) {
+                               SkMSec app  = fMaker->getAppTime();
+                               fMaker->setEnableTime(app, time);
+       #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
+                               debugOut.append(" time=");
+                               debugOut.appendS32(time - fMaker->fDebugTimeBase);
+                               debugOut.append(" adjust=");
+                               debugOut.appendS32(fMaker->fAdjustedStart);
+       #endif
+                       }
+       #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
+                       SkDebugf("%s\n", debugOut.c_str());
+       #endif
+                       SkASSERT(event->isEvent());
+                       SkDisplayEvent* displayEvent = (SkDisplayEvent*) event;
+                       displayEvent->populateInput(*fMaker, evt);
+                       displayEvent->enableEvent(*fMaker);
+               }
+       }
+inval:
+       fMaker->notifyInval();
+       return true;
+}
+
+void SkAnimator::onEventPost(SkEvent* evt, SkEventSinkID sinkID)
+{
+#ifdef SK_DEBUG
+       SkAnimator* root = fMaker->getRoot();
+       if (root) {
+               root->onEventPost(evt, sinkID);
+               return;
+       }
+#else
+       SkASSERT(sinkID == this->getSinkID() || this->getHostEventSinkID() == sinkID);
+#endif
+       SkEvent::Post(evt, sinkID);
+}
+
+void SkAnimator::onEventPostTime(SkEvent* evt, SkEventSinkID sinkID, SkMSec time)
+{
+#ifdef SK_DEBUG
+       SkAnimator* root = fMaker->getRoot();
+       if (root) {
+               root->onEventPostTime(evt, sinkID, time);
+               return;
+       }
+#else
+       SkASSERT(sinkID == this->getSinkID() || this->getHostEventSinkID() == sinkID);
+#endif
+       SkEvent::PostTime(evt, sinkID, time);
+}
+
+void SkAnimator::reset() {
+       fMaker->fDisplayList.reset();
+}
+
+SkEventSinkID SkAnimator::getHostEventSinkID() const {
+       return fMaker->fHostEventSinkID; 
+}
+
+void SkAnimator::setHostEventSinkID(SkEventSinkID target) {
+       fMaker->fHostEventSinkID = target; 
+}
+
+void SkAnimator::onSetHostHandler(Handler ) {
+}
+
+void SkAnimator::setJavaOwner(Handler ) {
+}
+
+bool SkAnimator::setArrayString(const char* id, const char* fieldID, const char** array, int num)
+{
+    SkTypedArray tArray(SkType_String);
+    tArray.setCount(num);
+    for (int i = 0; i < num; i++) {
+        SkOperand op;
+        op.fString = new SkString(array[i]);
+        tArray[i] = op;
+    }
+    return setArray(id, fieldID, tArray);
+}
+bool SkAnimator::setArrayInt(const char* id, const char* fieldID, const int* array, int num)
+{
+    SkTypedArray tArray(SkType_Int);
+    tArray.setCount(num);
+    for (int i = 0; i < num; i++) {
+        SkOperand op;   
+        op.fS32 = array[i];
+        tArray[i] = op;
+    }
+    return setArray(id, fieldID, tArray);
+}
+
+bool SkAnimator::setArray(SkDisplayable* element, const SkMemberInfo* info, SkTypedArray array) {
+    if (info->fType != SkType_Array)
+        return false;   //the field is not an array
+    //i think we can handle the case where the displayable itself is an array differently from the
+    //case where it has an array - for one thing, if it is an array, i think we can change its type
+    //if it's not, we cannot
+    SkDisplayTypes type = element->getType();
+    if (type == SkType_Array) {
+        SkDisplayArray* dispArray = (SkDisplayArray*) element;
+        dispArray->values = array;  
+        return true;
+    }
+    else
+        return false;   //currently i don't care about this case
+}
+
+bool SkAnimator::setArray(const char* id, const char* fieldID, SkTypedArray array) {
+    SkDisplayable* element = (SkDisplayable*) getElement(id);
+    //should I go ahead and change all 'nil's to 'NULL'?
+    if (element == nil)
+        return false;
+    const SkMemberInfo* field = getField(element, fieldID);
+    if (field == nil)
+        return false;
+    return setArray(element, field, array);
+}
+
+bool SkAnimator::setInt(SkDisplayable* element, const SkMemberInfo* info, int32_t s32) {
+       if (info->fType != SkType_MemberProperty) {
+               SkOperand operand;
+               operand.fS32 = s32;
+               SkASSERT(info->getType() == SkType_Int);
+               info->setValue(element, &operand, 1);
+       } else {
+               SkScriptValue scriptValue;
+               scriptValue.fType = SkType_Int;
+               scriptValue.fOperand.fS32 = s32;
+               element->setProperty(info->propertyIndex(), scriptValue);
+       }
+       return true;
+}
+
+bool SkAnimator::setInt(const char* id, const char* fieldID, int32_t s32) {
+       SkDisplayable* element = (SkDisplayable*) getElement(id);
+       if (element == nil)
+               return false;
+       const SkMemberInfo* field = getField(element, fieldID);
+       if (field == nil)
+               return false;
+       return setInt(element, field, s32);
+}
+
+bool SkAnimator::setScalar(SkDisplayable* element, const SkMemberInfo* info, SkScalar scalar) {
+       if (info->fType != SkType_MemberProperty) {
+               SkOperand operand;
+               operand.fScalar = scalar;
+               SkASSERT(info->getType() == SkType_Float);
+               info->setValue(element, &operand, 1);
+       } else {
+               SkScriptValue scriptValue;
+               scriptValue.fType = SkType_Float;
+               scriptValue.fOperand.fScalar = scalar;
+               element->setProperty(info->propertyIndex(), scriptValue);
+       }
+       return true;
+}
+
+bool SkAnimator::setScalar(const char* id, const char* fieldID, SkScalar scalar) {
+       SkDisplayable* element = (SkDisplayable*) getElement(id);
+       if (element == nil)
+               return false;
+       const SkMemberInfo* field = getField(element, fieldID);
+       if (field == nil)
+               return false;
+       return setScalar(element, field, scalar);
+}
+
+bool SkAnimator::setString(SkDisplayable* element, 
+               const SkMemberInfo* info, const char* str) {
+       // !!! until this is fixed, can't call script with global references from here 
+       info->setValue(*fMaker, nil, 0, info->fCount, element, info->getType(), str, strlen(str));
+       return true;
+}
+
+bool SkAnimator::setString(const char* id, const char* fieldID, const char* str) {
+       SkDisplayable* element = (SkDisplayable*) getElement(id);
+       if (element == nil)
+               return false;
+       const SkMemberInfo* field = getField(element, fieldID);
+       if (field == nil)
+               return false;
+       return setString(element, field, str);
+}
+
+void SkAnimator::setTimeline(const Timeline& timeline) {
+       fMaker->fTimeline = &timeline;
+}
+
+void SkAnimator::setURIBase(const char* uri) {
+       if (uri)
+       {
+               const char* tail = strrchr(uri, '/');
+               if (tail) {
+                       SkString prefix(uri, tail - uri + 1);
+                       if (SkStream::IsAbsoluteURI(uri))
+                               fMaker->fPrefix.reset();
+                       fMaker->fPrefix.append(prefix);
+                       fMaker->fFileName.set(tail + 1);
+               } else
+                       fMaker->fFileName.set(uri);
+       }
+}
+
+#ifdef SK_DEBUG
+bool SkAnimator::NoLeaks() {
+#ifdef SK_BUILD_FOR_MAC
+       if (SkDisplayable::fAllocations.count() == 0)
+               return true;
+//     return SkDisplayable::fAllocationCount == 0;
+       SkDebugf("!!! leaked %d displayables:\n", SkDisplayable::fAllocations.count());
+       for (SkDisplayable** leak = SkDisplayable::fAllocations.begin(); leak < SkDisplayable::fAllocations.end(); leak++)
+               SkDebugf("%08x %s\n", *leak, (*leak)->id);
+#endif
+       return false;
+}
+#endif
+
+#ifdef SK_SUPPORT_UNITTEST
+#include "SkAnimatorScript.h"
+#include "SkBase64.h"
+#include "SkParse.h"
+#include "SkMemberInfo.h"
+
+#define unittestline(type)     { #type , type::UnitTest }
+#endif
+
+
+void SkAnimator::Init(bool runUnitTests) {
+#ifdef SK_SUPPORT_UNITTEST
+       if (runUnitTests == false)
+               return;
+       static const struct {
+               const char*     fTypeName;
+               void (*fUnitTest)( );
+       } gUnitTests[] = {
+               unittestline(SkBase64),
+               unittestline(SkDisplayType),
+               unittestline(SkParse),
+               unittestline(SkScriptEngine),
+//             unittestline(SkScriptEngine2),  // compiled script experiment
+               unittestline(SkAnimatorScript)
+       };
+       for (int i = 0; i < (int)SK_ARRAY_COUNT(gUnitTests); i++)
+       {
+               SkDebugf("SkAnimator: Running UnitTest for %s\n", gUnitTests[i].fTypeName);
+               gUnitTests[i].fUnitTest();
+               SkDebugf("SkAnimator: End UnitTest for %s\n", gUnitTests[i].fTypeName);
+       }
+#endif
+}
+
+void SkAnimator::Term() {
+}
+
+
+
diff --git a/libs/graphics/animator/SkAnimatorScript.cpp b/libs/graphics/animator/SkAnimatorScript.cpp
new file mode 100644 (file)
index 0000000..cce5723
--- /dev/null
@@ -0,0 +1,590 @@
+#include "SkAnimatorScript.h"
+#include "SkAnimateBase.h"
+#include "SkAnimateMaker.h"
+#include "SkDisplayTypes.h"
+#include "SkExtras.h"
+#include "SkMemberInfo.h"
+#include "SkParse.h"
+
+static const SkDisplayEnumMap gEnumMaps[] = {
+       { SkType_AddMode, "indirect|immediate" },
+       { SkType_Align, "left|center|right" },
+       { SkType_ApplyMode, "create|immediate|once" },
+       { SkType_ApplyTransition, "normal|reverse" },
+       { SkType_BitmapEncoding, "jpeg|png" },
+       { SkType_BitmapFormat, "none|A1|A8|Index8|RGB16|RGB32" },
+       { SkType_Boolean, "false|true" },
+       { SkType_Cap, "butt|round|square" },
+       { SkType_EventCode, "none|leftSoftKey|rightSoftKey|home|back|send|end|key0|key1|key2|key3|key4|key5|key6|key7|key8|key9|star|hash|up|down|left|right|OK|volUp|volDown|camera" },
+       { SkType_EventKind, "none|keyChar|keyPress|keyPressUp|mouseDown|mouseDrag|mouseMove|mouseUp|onEnd|onLoad|user" },
+       { SkType_EventMode, "deferred|immediate" },
+       { SkType_FillType, "winding|evenOdd" },
+       { SkType_FilterType, "none|bilinear" },
+    { SkType_FontStyle, "normal|bold|italic|boldItalic" },
+       { SkType_FromPathMode, "normal|angle|position" },
+       { SkType_Join, "miter|round|blunt" },
+       { SkType_MaskFilterBlurStyle, "normal|solid|outer|inner" },
+       { SkType_PathDirection, "cw|ccw" },
+       { SkType_Style, "fill|stroke|strokeAndFill" },
+       { SkType_TextBoxAlign, "start|center|end" },
+       { SkType_TextBoxMode, "oneLine|lineBreak" },
+       { SkType_TileMode, "clamp|repeat|mirror" },
+       { SkType_Xfermode, "clear|src|dst|srcOver|dstOver|srcIn|dstIn|srcOut|dstOut|"
+               "srcATop|dstATop|xor|darken|lighten" },
+};
+
+static int gEnumMapCount = SK_ARRAY_COUNT(gEnumMaps);
+
+SkAnimatorScript::SkAnimatorScript(SkAnimateMaker& maker, SkDisplayable* working, SkDisplayTypes type)
+    : SkScriptEngine(SkScriptEngine::ToOpType(type)), fMaker(maker), fParent(NULL), fWorking(working)
+{
+       memberCallBack(EvalMember, (void*) this);
+       memberFunctionCallBack(EvalMemberFunction, (void*) this);
+       boxCallBack(Box, (void*) this);
+       unboxCallBack(Unbox, (void*) &maker);
+       propertyCallBack(EvalID, (void*) this); // must be first (entries are prepended, will be last), since it never fails
+       propertyCallBack(Infinity, (void*) this);
+       propertyCallBack(NaN, (void*) this);
+       functionCallBack(Eval, (void*) this);
+       functionCallBack(IsFinite, (void*) this);
+       functionCallBack(IsNaN, (void*) this);
+       if (type == SkType_ARGB) {
+               functionCallBack(EvalRGB, (void*) this);
+               propertyCallBack(EvalNamedColor, (void*) &maker.fIDs);
+       }
+       if (SkDisplayType::IsEnum(&maker, type)) {
+               // !!! for SpiderMonkey, iterate through the enum values, and map them to globals
+               const SkDisplayEnumMap& map = GetEnumValues(type);
+               propertyCallBack(EvalEnum, (void*) map.fValues); 
+       } 
+       for (SkExtras** extraPtr = maker.fExtras.begin(); extraPtr < maker.fExtras.end(); extraPtr++) {
+               SkExtras* extra = *extraPtr;
+               if (extra->fExtraCallBack)
+                       propertyCallBack(extra->fExtraCallBack, extra->fExtraStorage);
+       }
+}
+
+SkAnimatorScript::~SkAnimatorScript() {
+       for (SkDisplayable** dispPtr = fTrackDisplayable.begin(); dispPtr < fTrackDisplayable.end(); dispPtr++)
+               delete *dispPtr;
+}
+
+bool SkAnimatorScript::evaluate(const char* original, SkScriptValue* result, SkDisplayTypes type) {
+               const char* script = original;
+               bool success = evaluateScript(&script, result);
+               if (success == false || result->fType != type) {
+                       fMaker.setScriptError(*this);
+                       return false;
+               }
+               return true;
+}
+
+bool SkAnimatorScript::Box(void* user, SkScriptValue* scriptValue) {
+       SkAnimatorScript* engine = (SkAnimatorScript*) user;
+       SkDisplayTypes type = scriptValue->fType;
+       SkDisplayable* displayable;
+       switch (type) {
+               case SkType_Array: {
+                       SkDisplayArray* boxedValue = new SkDisplayArray(*scriptValue->fOperand.fArray);
+                       displayable = boxedValue;
+                       } break;
+               case SkType_Boolean: {
+                       SkDisplayBoolean* boxedValue = new SkDisplayBoolean;
+                       displayable = boxedValue;
+                       boxedValue->value = !! scriptValue->fOperand.fS32;
+                       } break;
+               case SkType_Int: {
+                       SkDisplayInt* boxedValue = new SkDisplayInt;
+                       displayable = boxedValue;
+                       boxedValue->value = scriptValue->fOperand.fS32;
+                       } break;
+               case SkType_Float: {
+                       SkDisplayFloat* boxedValue = new SkDisplayFloat;
+                       displayable = boxedValue;
+                       boxedValue->value = scriptValue->fOperand.fScalar;
+                       } break;
+               case SkType_String: {
+                       SkDisplayString* boxedValue = new SkDisplayString(*scriptValue->fOperand.fString);
+                       displayable = boxedValue;
+                       } break;
+               case SkType_Displayable: 
+                       scriptValue->fOperand.fObject = scriptValue->fOperand.fDisplayable;
+                       scriptValue->fType = SkType_Displayable;
+                       return true;
+               default:
+                       SkASSERT(0);
+                       return false;
+       }
+       engine->track(displayable);
+       scriptValue->fOperand.fObject = displayable;
+       scriptValue->fType = SkType_Displayable;
+       return true;
+}
+
+bool SkAnimatorScript::Eval(const char* function, size_t len, SkTDArray<SkScriptValue>& params, 
+               void* eng, SkScriptValue* value) {
+       if (SK_LITERAL_STR_EQUAL("eval", function, len) == false)
+               return false;
+       if (params.count() != 1)
+               return false;
+       SkAnimatorScript* host = (SkAnimatorScript*) eng;
+       SkAnimatorScript engine(host->fMaker, host->fWorking, SkScriptEngine::ToDisplayType(host->fReturnType));
+       SkScriptValue* scriptValue = params.begin();
+       bool success = true;
+       if (scriptValue->fType == SkType_String) {
+               const char* script = scriptValue->fOperand.fString->c_str();
+               success = engine.evaluateScript(&script, value);
+       } else
+               *value = *scriptValue;
+       return success;
+}
+
+bool SkAnimatorScript::EvalEnum(const char* token, size_t len, void* callBack, SkScriptValue* value) {
+       const char* tokens = (const char*) callBack;
+       value->fType = SkType_Int;
+       if (MapEnums(tokens, token, len, (int*)&value->fOperand.fS32))
+               return true; 
+       return false;
+}
+
+bool SkAnimatorScript::EvalID(const char* token, size_t len, void* user, SkScriptValue* value) {
+       SkAnimatorScript* engine = (SkAnimatorScript*) user;
+       SkTDict<SkDisplayable*>* ids = &engine->fMaker.fIDs;
+       SkDisplayable* displayable;
+       bool success = ids->find(token, len, &displayable); 
+       if (success == false) {
+               displayable = engine->fWorking;
+               if (SK_LITERAL_STR_EQUAL("parent", token, len)) {
+                       SkDisplayable* parent = displayable->getParent();
+                       if (parent == false)
+                               parent = engine->fParent;
+                       if (parent) {
+                               value->fOperand.fDisplayable = parent;
+                               value->fType = SkType_Displayable;
+                               return true;
+                       }
+               }
+               if (displayable && EvalMember(token, len, displayable, engine, value))
+                       return true;
+               value->fOperand.fString = NULL;
+               value->fType = SkType_String;   
+       } else {
+               SkDisplayable* working = engine->fWorking;
+               value->fOperand.fDisplayable = displayable;
+               value->fType = SkType_Displayable;
+               if (displayable->canContainDependents() && working && working->isAnimate()) {
+                       SkAnimateBase* animator = (SkAnimateBase*) working;
+                       if (animator->isDynamic()) {
+                               SkDisplayDepend* depend = (SkDisplayDepend* ) displayable;
+                               depend->addDependent(working);
+                       }
+               }
+       }
+       return true;
+}
+
+bool SkAnimatorScript::EvalNamedColor(const char* token, size_t len, void* callback, SkScriptValue* value) {
+               value->fType = SkType_Int;
+       if (SkParse::FindNamedColor(token, len, (SkColor*) &value->fOperand.fS32) != NULL)
+               return true;
+       return false;
+}
+
+bool SkAnimatorScript::EvalRGB(const char* function, size_t len, SkTDArray<SkScriptValue>& params, 
+               void* eng, SkScriptValue* value) {
+       if (SK_LITERAL_STR_EQUAL("rgb", function, len) == false)
+               return false;
+       if (params.count() != 3)
+               return false;
+       SkScriptEngine* engine = (SkScriptEngine*) eng;
+       unsigned result = 0xFF000000;
+       int shift = 16;
+       for (SkScriptValue* valuePtr = params.begin(); valuePtr < params.end(); valuePtr++) {
+               engine->convertTo(SkType_Int, valuePtr);
+               result |= SkClampMax(valuePtr->fOperand.fS32, 255) << shift;
+               shift -= 8;
+       }
+       value->fOperand.fS32 = result;
+       value->fType = SkType_Int;
+       return true;
+}
+
+bool SkAnimatorScript::EvalMemberCommon(SkScriptEngine* engine, const SkMemberInfo* info, 
+               SkDisplayable* displayable, SkScriptValue* value) {
+       SkDisplayTypes original;
+       SkDisplayTypes type = original = (SkDisplayTypes) info->getType();
+       if (info->fType == SkType_Array)
+               type = SkType_Array;
+       switch (type) {
+               case SkType_ARGB:
+                       type = SkType_Int;
+               case SkType_Boolean:
+               case SkType_Int:
+               case SkType_MSec:
+               case SkType_Float:
+                       SkASSERT(info->getCount() == 1);
+                       if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction) 
+                               value->fOperand.fS32 = *(int32_t*) info->memberData(displayable);       // OK for SkScalar too
+                       if (type == SkType_MSec) {
+                               value->fOperand.fScalar = SkScalarDiv((SkScalar) value->fOperand.fS32, 1000); // dividing two ints is the same as dividing two scalars 
+                               type = SkType_Float;
+                       }
+                       break;
+               case SkType_String: {
+                       SkString* displayableString;
+                       if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction) {
+                               info->getString(displayable, &displayableString);
+                               value->fOperand.fString = new SkString(*displayableString);
+                       }
+                       } break;
+               case SkType_Array: {
+                       SkASSERT(info->fType != SkType_MemberProperty); // !!! incomplete
+                       SkTDOperandArray* displayableArray = (SkTDOperandArray*) info->memberData(displayable);
+                       if (displayable->getType() == SkType_Array) {
+                               SkDisplayArray* typedArray = (SkDisplayArray*) displayable;
+                               original = typedArray->values.getType();
+                       }
+                       SkASSERT(original != SkType_Unknown);
+                       SkTypedArray* array = value->fOperand.fArray = new SkTypedArray(original);
+                       engine->track(array);
+                       int count = displayableArray->count();
+                       if (count > 0) {
+                               array->setCount(count);
+                               memcpy(array->begin(), displayableArray->begin(), count * sizeof(SkOperand));
+                       }
+                       } break;
+               default:
+                       SkASSERT(0); // unimplemented
+       }
+       value->fType = type;
+       return true;
+}
+
+bool SkAnimatorScript::EvalMember(const char* member, size_t len, void* object, void* eng, 
+               SkScriptValue* value) {
+       SkScriptEngine* engine = (SkScriptEngine*) eng;
+       SkDisplayable* displayable = (SkDisplayable*) object;
+       SkString name(member, len);
+       SkDisplayable* named = displayable->contains(name);
+       if (named) {
+               value->fOperand.fDisplayable = named;
+               value->fType = SkType_Displayable;
+               return true;
+       }
+       const SkMemberInfo* info = displayable->getMember(name.c_str());
+       if (info == NULL)
+               return false;
+       if (info->fType == SkType_MemberProperty) {
+               if (displayable->getProperty(info->propertyIndex(), value) == false) {
+                       SkASSERT(0);
+                       return false;
+               }
+       }
+       return EvalMemberCommon(engine, info, displayable, value);
+}
+
+bool SkAnimatorScript::EvalMemberFunction(const char* member, size_t len, void* object, 
+               SkTDArray<SkScriptValue>& params, void* eng, SkScriptValue* value) {
+       SkScriptEngine* engine = (SkScriptEngine*) eng;
+       SkDisplayable* displayable = (SkDisplayable*) object;
+       SkString name(member, len);
+       const SkMemberInfo* info = displayable->getMember(name.c_str());
+       SkASSERT(info != NULL); /* !!! error handling unimplemented */
+       if (info->fType != SkType_MemberFunction) {
+               SkASSERT(0);
+               return false;
+       }
+       displayable->executeFunction(displayable, info->functionIndex(), params, info->getType(), 
+               value);
+       return EvalMemberCommon(engine, info, displayable, value);
+}
+
+bool SkAnimatorScript::EvaluateDisplayable(SkAnimateMaker& maker, SkDisplayable* displayable, const char* script, SkDisplayable** result) {
+       SkAnimatorScript engine(maker, displayable, SkType_Displayable);
+       SkScriptValue value;
+       bool success = engine.evaluate(script, &value, SkType_Displayable);
+       if (success)
+               *result = value.fOperand.fDisplayable;
+       return success;
+}
+
+bool SkAnimatorScript::EvaluateInt(SkAnimateMaker& maker, SkDisplayable* displayable, const char* script, int32_t* result) {
+       SkAnimatorScript engine(maker, displayable, SkType_Int);
+       SkScriptValue value;
+       bool success = engine.evaluate(script, &value, SkType_Int);
+       if (success)
+               *result = value.fOperand.fS32;
+       return success;
+}
+
+bool SkAnimatorScript::EvaluateFloat(SkAnimateMaker& maker, SkDisplayable* displayable, const char* script, SkScalar* result) {
+       SkAnimatorScript engine(maker, displayable, SkType_Float);
+       SkScriptValue value;
+       bool success = engine.evaluate(script, &value, SkType_Float);
+       if (success)
+               *result = value.fOperand.fScalar;
+       return success;
+}
+
+bool SkAnimatorScript::EvaluateString(SkAnimateMaker& maker, SkDisplayable* displayable, const char* script, SkString* result) {
+       SkAnimatorScript engine(maker, displayable, SkType_String);
+       SkScriptValue value;
+       bool success = engine.evaluate(script, &value, SkType_String);
+       if (success)
+               result->set(*(value.fOperand.fString));
+  return success;
+}
+
+bool SkAnimatorScript::EvaluateString(SkAnimateMaker& maker, SkDisplayable* displayable, SkDisplayable* parent, const char* script, SkString* result) {
+       SkAnimatorScript engine(maker, displayable, SkType_String);
+       engine.fParent = parent;
+       SkScriptValue value;
+       bool success = engine.evaluate(script, &value, SkType_String);
+       if (success)
+               result->set(*(value.fOperand.fString));
+  return success;
+}
+
+const SkDisplayEnumMap& SkAnimatorScript::GetEnumValues(SkDisplayTypes type) {
+       int index = SkTSearch<SkDisplayTypes>(&gEnumMaps[0].fType, gEnumMapCount, type, 
+               sizeof(SkDisplayEnumMap));
+       SkASSERT(index >= 0);
+       return gEnumMaps[index];
+}
+
+bool SkAnimatorScript::Infinity(const char* token, size_t len, void* user, SkScriptValue* value) {
+       if (SK_LITERAL_STR_EQUAL("Infinity", token, len) == false)
+               return false;
+       value->fType = SkType_Float;
+       value->fOperand.fScalar = SK_ScalarInfinity;
+       return true;
+}
+
+bool SkAnimatorScript::IsFinite(const char* function, size_t len, SkTDArray<SkScriptValue>& params, 
+               void* eng, SkScriptValue* value) {
+       if (SK_LITERAL_STR_EQUAL(function, "isFinite", len) == false)
+               return false;
+       if (params.count() != 1)
+               return false;
+       SkScriptValue* scriptValue = params.begin();
+       SkDisplayTypes type = scriptValue->fType;
+       SkScalar scalar = scriptValue->fOperand.fScalar;
+       value->fType = SkType_Int;
+       value->fOperand.fS32 = type == SkType_Float ? SkScalarIsNaN(scalar) == false && 
+               SkScalarAbs(scalar) != SK_ScalarInfinity        : type == SkType_Int;
+       return true;
+}
+
+bool SkAnimatorScript::IsNaN(const char* function, size_t len, SkTDArray<SkScriptValue>& params, 
+               void* eng, SkScriptValue* value) {
+       if (SK_LITERAL_STR_EQUAL("isNaN", function, len) == false)
+               return false;
+       if (params.count() != 1)
+               return false;
+       SkScriptValue* scriptValue = params.begin();
+       value->fType = SkType_Int;
+       value->fOperand.fS32 = scriptValue->fType == SkType_Float ? SkScalarIsNaN(scriptValue->fOperand.fScalar) : 0;
+       return true;
+}
+
+bool SkAnimatorScript::MapEnums(const char* ptr, const char* match, size_t len, int* value) {
+       int index = 0;
+       bool more = true;
+       do {
+               const char* last = strchr(ptr, '|');
+               if (last == NULL) {
+                       last = &ptr[strlen(ptr)];
+                       more = false;
+               }
+               size_t length = last - ptr;
+               if (len == length && strncmp(ptr, match, length) == 0) {
+                       *value = index;
+                       return true;
+               }
+               index++;
+               ptr = last + 1;
+       } while (more);
+       return false;
+}
+
+bool SkAnimatorScript::NaN(const char* token, size_t len, void* user, SkScriptValue* value) {
+       if (SK_LITERAL_STR_EQUAL("NaN", token, len) == false)
+               return false;
+       value->fType = SkType_Float;
+       value->fOperand.fScalar = SK_ScalarNaN;
+       return true;
+}
+
+#if 0
+bool SkAnimatorScript::ObjectToString(void* object, void* user, SkScriptValue* value) {
+       SkTDict<SkDisplayable*>* ids = (SkTDict<SkDisplayable*>*) user;
+       SkDisplayable* displayable = (SkDisplayable*) object;
+       const char* key;
+       bool success = ids->findKey(displayable, &key); 
+       if (success == false)
+               return false;
+       value->fOperand.fString =       new SkString(key);
+       value->fType = SkType_String;
+       return true;
+}
+#endif
+
+bool SkAnimatorScript::Unbox(void* m, SkScriptValue* scriptValue) {
+       SkAnimateMaker* maker = (SkAnimateMaker*) m;
+       SkASSERT((unsigned) scriptValue->fType == (unsigned) SkType_Displayable);
+       SkDisplayable* displayable = (SkDisplayable*) scriptValue->fOperand.fObject;
+       SkDisplayTypes type = displayable->getType();
+       switch (displayable->getType()) {
+               case SkType_Array: {
+                       SkDisplayArray* boxedValue = (SkDisplayArray*) displayable;
+                       scriptValue->fOperand.fArray = &boxedValue->values;
+                       } break;
+               case SkType_Boolean: {
+                       SkDisplayBoolean* boxedValue = (SkDisplayBoolean*) displayable;
+                       scriptValue->fOperand.fS32 = boxedValue->value;
+                       } break;
+               case SkType_Int: {
+                       SkDisplayInt* boxedValue = (SkDisplayInt*) displayable;
+                       scriptValue->fOperand.fS32 = boxedValue->value;
+                       } break;
+               case SkType_Float: {
+                       SkDisplayFloat* boxedValue = (SkDisplayFloat*) displayable;
+                       scriptValue->fOperand.fScalar = boxedValue->value;
+                       } break;
+               case SkType_String: {
+                       SkDisplayString* boxedValue = (SkDisplayString*) displayable;
+                       scriptValue->fOperand.fString = SkNEW_ARGS(SkString, (boxedValue->value));
+                       } break;
+               default: {
+                       const char* id;
+                       bool success = maker->findKey(displayable, &id);
+                       SkASSERT(success);
+                       scriptValue->fOperand.fString = SkNEW_ARGS(SkString, (id));
+                       type = SkType_String;
+               }
+       }
+       scriptValue->fType = type;
+       return true;
+}
+
+#if defined SK_SUPPORT_UNITTEST
+
+#include "SkAnimator.h"
+
+static const char scriptTestSetup[]  = 
+"<screenplay>\n"
+       "<text id='label' text='defg'/>\n"
+       "<add id='addLabel' use='label'/>\n"
+       "<text id='text1' text='test'/>\n"
+       "<apply scope='addLabel'>\n"
+               "<set target='label' field='text' to='#script:text1.text'/>\n"
+       "</apply>\n"
+       "<apply>\n"
+               "<paint id='labelPaint'>\n"
+                       "<emboss id='emboss' direction='[1,1,1]'  />\n"
+               "</paint>\n"
+               "<animate id='animation' field='direction' target='emboss' from='[1,1,1]' to='[-1,1,1]' dur='1'/>\n"
+               "<set lval='direction[0]' target='emboss' to='-1' />\n"
+       "</apply>\n"
+       "<color id='testColor' color='0 ? rgb(0,0,0) : rgb(255,255,255)' />\n"
+       "<color id='xColor' color='rgb(12,34,56)' />\n"
+       "<array id='emptyArray' />\n"
+       "<array id='intArray' values='[1, 4, 6]' />\n"
+       "<int id='idx' value='2' />\n"
+       "<int id='idy' value='2' />\n"
+       "<string id='alpha' value='abc' />\n"
+       "<rect id='testRect' left='Math.cos(0)' top='2' right='12' bottom='5' />\n"
+       "<event id='evt'>\n"
+               "<input name='x' />\n"
+               "<apply scope='idy'>\n"
+                       "<set field='value' to='evt.x.int' />\n"
+               "</apply>\n"
+       "</event>\n"
+"</screenplay>";
+
+#if !defined(SK_BUILD_FOR_BREW)
+
+#define DEFAULT_ANSWER   , 0
+
+static const SkScriptNAnswer scriptTests[]  = {
+       { "label.text.length == 4", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER },
+//     { "labelPaint.measureText(label.text) > 0 ? labelPaint.measureText(label.text)+10 : 40", SkType_Float, 0, SkIntToScalar(0x23)  },
+       {       "Number.POSITIVE_INFINITY >= Number.MAX_VALUE ? 1 : 0", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "Infinity >= Number.MAX_VALUE ? 1 : 0", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "Number.NEGATIVE_INFINITY <= -Number.MAX_VALUE ? 1 : 0", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "Number.MIN_VALUE > 0 ? 1 : 0", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "isNaN(Number.NaN)", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "isNaN(NaN)", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "Math.sin(0)", SkType_Float, 0, SkIntToScalar(0) DEFAULT_ANSWER },
+       {       "alpha+alpha", SkType_String, 0, 0, "abcabc" },
+       {       "intArray[4]", SkType_Unknown DEFAULT_ANSWER DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "emptyArray[4]", SkType_Unknown DEFAULT_ANSWER DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "idx", SkType_Int, 2 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "intArray.length", SkType_Int, 3 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "intArray.values[0]", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "intArray[0]", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "idx.value", SkType_Int, 2 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "alpha.value", SkType_String, 0, 0, "abc" },
+       {       "alpha", SkType_String, 0, 0, "abc" },
+       {       "alpha.value+alpha.value", SkType_String, 0, 0, "abcabc" },
+       {       "alpha+idx", SkType_String, 0, 0, "abc2" },
+       {       "idx+alpha", SkType_String, 0, 0, "2abc" },
+       {       "intArray[idx]", SkType_Int, 6 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "alpha.slice(1,2)", SkType_String, 0, 0, "b" },
+       {       "alpha.value.slice(1,2)", SkType_String, 0, 0, "b" },
+       {       "testRect.left+2", SkType_Float, 0, SkIntToScalar(3) DEFAULT_ANSWER },
+       {       "0 ? Math.sin(0) : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "0 ? intArray[0] : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "0 ? intArray.values[0] : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "0 ? idx : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "0 ? idx.value : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "0 ? alpha.slice(1,2) : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER },
+       {       "0 ? alpha.value.slice(1,2) : 1", SkType_Int, 1 DEFAULT_ANSWER DEFAULT_ANSWER },
+       { "idy", SkType_Int, 3 DEFAULT_ANSWER DEFAULT_ANSWER }
+};
+#endif
+
+#define SkScriptNAnswer_testCount      SK_ARRAY_COUNT(scriptTests)
+
+void SkAnimatorScript::UnitTest() {
+#if !defined(SK_BUILD_FOR_BREW) && defined(SK_SUPPORT_UNITTEST)
+       SkAnimator animator;
+       SkASSERT(animator.decodeMemory(scriptTestSetup, sizeof(scriptTestSetup)-1));
+       SkEvent evt;
+       evt.setString("id", "evt");
+       evt.setS32("x", 3);
+       animator.doUserEvent(evt);
+       // set up animator with memory script above, then run value tests
+       for (unsigned index = 0; index < SkScriptNAnswer_testCount; index++) {
+               SkAnimatorScript engine(*animator.fMaker, NULL, scriptTests[index].fType);
+               SkScriptValue value;
+               const char* script = scriptTests[index].fScript;
+               bool success = engine.evaluateScript(&script, &value);
+               if (success == false) {
+                       SkDebugf("script failed: %s\n", scriptTests[index].fScript);
+                       SkASSERT(scriptTests[index].fType == SkType_Unknown);
+                       continue;
+               }
+               SkASSERT(value.fType == scriptTests[index].fType);
+               SkScalar error;
+               switch (value.fType) {
+                       case SkType_Int:
+                               SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer);
+                               break;
+                       case SkType_Float:
+                               error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer);
+                               SkASSERT(error < SK_Scalar1 / 10000);
+                               break;
+                       case SkType_String:
+                               SkASSERT(strcmp(value.fOperand.fString->c_str(), scriptTests[index].fStringAnswer) == 0);
+                               break;
+                       default:
+                               SkASSERT(0);
+               }
+       }
+#endif
+}
+
+#endif
+
+
diff --git a/libs/graphics/animator/SkAnimatorScript.h b/libs/graphics/animator/SkAnimatorScript.h
new file mode 100644 (file)
index 0000000..2a02a2f
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef SkAnimatorScript_DEFINED
+#define SkAnimatorScript_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkScript.h"
+#include "SkTypedArray.h"
+
+class SkAnimateMaker;
+struct SkMemberInfo;
+
+struct SkDisplayEnumMap {
+       SkDisplayTypes fType;
+       const char* fValues;
+};
+
+class SkAnimatorScript : public SkScriptEngine {
+public:
+       SkAnimatorScript(SkAnimateMaker& , SkDisplayable* , SkDisplayTypes type);
+       ~SkAnimatorScript();
+       bool evaluate(const char* script, SkScriptValue* , SkDisplayTypes type);
+       void track(SkDisplayable* displayable) { 
+               SkASSERT(fTrackDisplayable.find(displayable) < 0);  
+               *fTrackDisplayable.append() = displayable; }
+       static bool EvaluateDisplayable(SkAnimateMaker& , SkDisplayable* , const char* script, SkDisplayable** );
+       static bool EvaluateFloat(SkAnimateMaker& , SkDisplayable* , const char* script, SkScalar* );
+       static bool EvaluateInt(SkAnimateMaker& , SkDisplayable* , const char* script, int32_t* );
+       static bool EvaluateString(SkAnimateMaker& , SkDisplayable* , const char* script, SkString* );
+       static bool EvaluateString(SkAnimateMaker& , SkDisplayable* , SkDisplayable* parent, const char* script, SkString* );
+       static bool MapEnums(const char* ptr, const char* match, size_t len, int* value);
+protected:
+       static bool Box(void* user, SkScriptValue* );
+       static bool Eval(const char* function, size_t len, SkTDArray<SkScriptValue>& params, 
+               void* callBack, SkScriptValue* );
+       static bool EvalEnum(const char* token, size_t len, void* callBack, SkScriptValue* );
+       static bool EvalID(const char* token, size_t len, void* callBack, SkScriptValue* );
+       static bool EvalMember(const char* member, size_t len, void* object, void* eng, 
+               SkScriptValue* value);
+       static bool EvalMemberCommon(SkScriptEngine* , const SkMemberInfo* info, 
+               SkDisplayable* displayable, SkScriptValue* value);
+       static bool EvalMemberFunction(const char* member, size_t len, void* object, 
+               SkTDArray<SkScriptValue>& params, void* user, SkScriptValue* value);
+       static bool EvalNamedColor(const char* token, size_t len, void* callBack, SkScriptValue* );
+       static bool EvalRGB(const char* function, size_t len, SkTDArray<SkScriptValue>& params, 
+               void* callBack, SkScriptValue* );
+       static const SkDisplayEnumMap& GetEnumValues(SkDisplayTypes type); 
+       static bool Infinity(const char* token, size_t len, void* callBack, SkScriptValue* );
+       static bool IsFinite(const char* function, size_t len, SkTDArray<SkScriptValue>& params, 
+               void* callBack, SkScriptValue* );
+       static bool IsNaN(const char* function, size_t len, SkTDArray<SkScriptValue>& params, 
+               void* callBack, SkScriptValue* );
+       static bool NaN(const char* token, size_t len, void* callBack, SkScriptValue* );
+       static bool Unbox(void* , SkScriptValue* scriptValue);
+       SkTDDisplayableArray fTrackDisplayable;
+       SkAnimateMaker& fMaker;
+       SkDisplayable* fParent;
+       SkDisplayable* fWorking;
+private:
+       friend class SkDump;
+       friend struct SkScriptNAnswer;
+#ifdef SK_SUPPORT_UNITTEST
+public:
+       static void UnitTest();
+#endif
+};
+
+#endif // SkAnimatorScript_DEFINED
+
diff --git a/libs/graphics/animator/SkAnimatorScript2.cpp b/libs/graphics/animator/SkAnimatorScript2.cpp
new file mode 100755 (executable)
index 0000000..a3aeaf6
--- /dev/null
@@ -0,0 +1,618 @@
+#include "SkAnimatorScript2.h"
+#include "SkAnimateBase.h"
+#include "SkAnimateMaker.h"
+#include "SkDisplayTypes.h"
+#include "SkExtras.h"
+#include "SkMemberInfo.h"
+#include "SkOpArray.h"
+#include "SkParse.h"
+#include "SkScript2.h"
+#include "SkScriptCallBack.h"
+
+static const SkDisplayEnumMap gEnumMaps[] = {
+       { SkType_AddMode, "indirect|immediate" },
+       { SkType_Align, "left|center|right" },
+       { SkType_ApplyMode, "immediate|once" },
+       { SkType_ApplyTransition, "reverse" },
+       { SkType_BitmapEncoding, "jpeg|png" },
+       { SkType_BitmapFormat, "none|A1|A8|Index8|RGB16|RGB32" },
+       { SkType_Boolean, "false|true" },
+       { SkType_Cap, "butt|round|square" },
+       { SkType_EventCode, "none|up|down|left|right|back|end|OK|send|leftSoftKey|rightSoftKey|key0|key1|key2|key3|key4|key5|key6|key7|key8|key9|star|hash" },
+       { SkType_EventKind, "none|keyChar|keyPress|mouseDown|mouseDrag|mouseMove|mouseUp|onEnd|onLoad|user" },
+       { SkType_EventMode, "deferred|immediate" },
+       { SkType_FillType, "winding|evenOdd" },
+       { SkType_FilterType, "none|bilinear" },
+       { SkType_FromPathMode, "normal|angle|position" },
+       { SkType_Join, "miter|round|blunt" },
+       { SkType_MaskFilterBlurStyle, "normal|solid|outer|inner" },
+       { SkType_PathDirection, "cw|ccw" },
+       { SkType_Style, "fill|stroke|strokeAndFill" },
+       { SkType_TextBoxAlign, "start|center|end" },
+       { SkType_TextBoxMode, "oneLine|lineBreak" },
+       { SkType_TileMode, "clamp|repeat|mirror" },
+       { SkType_Xfermode, "clear|src|dst|srcOver|dstOver|srcIn|dstIn|srcOut|dstOut|"
+               "srcATop|dstATop|xor|darken|lighten" },
+};
+
+static int gEnumMapCount = SK_ARRAY_COUNT(gEnumMaps);
+
+
+class SkAnimatorScript_Box : public SkScriptCallBackConvert {
+public:
+       SkAnimatorScript_Box() {}
+
+       ~SkAnimatorScript_Box() {
+               for (SkDisplayable** dispPtr = fTrackDisplayable.begin(); dispPtr < fTrackDisplayable.end(); dispPtr++)
+                       delete *dispPtr;
+       }
+
+       virtual bool convert(SkOperand2::OpType type, SkOperand2* operand) {
+               SkDisplayable* displayable;
+               switch (type) {
+                       case SkOperand2::kArray: {
+                               SkDisplayArray* boxedValue = new SkDisplayArray(*operand->fArray);
+                               displayable = boxedValue;
+                               } break;
+                       case SkOperand2::kS32: {
+                               SkDisplayInt* boxedValue = new SkDisplayInt;
+                               displayable = boxedValue;
+                               boxedValue->value = operand->fS32;
+                               } break;
+                       case SkOperand2::kScalar: {
+                               SkDisplayFloat* boxedValue = new SkDisplayFloat;
+                               displayable = boxedValue;
+                               boxedValue->value = operand->fScalar;
+                               } break;
+                       case SkOperand2::kString: {
+                               SkDisplayString* boxedValue = new SkDisplayString(*operand->fString);
+                               displayable = boxedValue;
+                               } break;
+                       case SkOperand2::kObject: 
+                               return true;
+                       default:
+                               SkASSERT(0);
+                               return false;
+               }
+               track(displayable);
+               operand->fObject = (void*) displayable;
+               return true;
+       }
+
+       virtual SkOperand2::OpType getReturnType(int index) { 
+               return SkOperand2::kObject; 
+       }
+
+       virtual Type getType() const { 
+               return kBox; 
+       }
+
+       void track(SkDisplayable* displayable) { 
+               SkASSERT(fTrackDisplayable.find(displayable) < 0);  
+               *fTrackDisplayable.append() = displayable; 
+       }
+
+       SkTDDisplayableArray fTrackDisplayable;
+};
+
+
+class SkAnimatorScript_Enum : public SkScriptCallBackProperty {
+public:
+       SkAnimatorScript_Enum(const char* tokens) : fTokens(tokens) {}
+
+       virtual bool getConstValue(const char* name, int len, SkOperand2* value) { 
+               return SkAnimatorScript2::MapEnums(fTokens, name, len, &value->fS32);
+       }
+
+private:
+       const char* fTokens;
+};
+
+       // !!! if type is string, call invoke
+       // if any other type, return original value
+               // distinction is undone: could do this by returning index == 0 only if param is string
+               // still, caller of getParamTypes will attempt to convert param to string (I guess)
+class SkAnimatorScript_Eval : public SkScriptCallBackFunction {
+public:
+       SkAnimatorScript_Eval(SkAnimatorScript2* engine) : fEngine(engine) {}
+
+       virtual bool getIndex(const char* name, int len, size_t* result) {
+               if (SK_LITERAL_STR_EQUAL("eval", name, len) != 0)
+                       return false;
+               *result = 0;
+               return true;
+       }
+       
+       virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) {
+               types->setCount(1);
+               SkOperand2::OpType* type = types->begin();
+               type[0] = SkOperand2::kString;
+       }
+
+       virtual bool invoke(size_t index, SkOpArray* params, SkOperand2* answer) {
+               SkAnimatorScript2 engine(fEngine->getMaker(), fEngine->getWorking(), 
+                       SkAnimatorScript2::ToDisplayType(fEngine->getReturnType()));
+               SkOperand2* op = params->begin();
+               const char* script = op->fString->c_str();
+               SkScriptValue2 value;
+               return engine.evaluateScript(&script, &value);
+               SkASSERT(value.fType == fEngine->getReturnType());
+               *answer = value.fOperand;
+               // !!! incomplete ?
+               return true;
+       }
+
+private:
+       SkAnimatorScript2* fEngine;
+};
+
+class SkAnimatorScript_ID : public SkScriptCallBackProperty {
+public:
+       SkAnimatorScript_ID(SkAnimatorScript2* engine) : fEngine(engine) {}
+
+       virtual bool getIndex(const char* token, int len, size_t* result) {  
+               SkDisplayable* displayable;
+               bool success = fEngine->getMaker().find(token, len, &displayable);
+               if (success == false) {
+                       *result = 0;
+               } else {
+                       *result = (size_t) displayable;
+                       SkDisplayable* working = fEngine->getWorking();
+                       if (displayable->canContainDependents() && working && working->isAnimate()) {
+                               SkAnimateBase* animator = (SkAnimateBase*) working;
+                               if (animator->isDynamic()) {
+                                       SkDisplayDepend* depend = (SkDisplayDepend* ) displayable;
+                                       depend->addDependent(working);
+                               }
+                       }
+               }
+               return true; 
+       }
+
+       virtual bool getResult(size_t ref, SkOperand2* answer) {
+               answer->fObject = (void*) ref;
+               return true;
+       }
+
+       virtual SkOperand2::OpType getReturnType(size_t index) {
+               return index == 0 ? SkOperand2::kString : SkOperand2::kObject;
+       }
+
+private:
+       SkAnimatorScript2* fEngine;
+};
+
+
+class SkAnimatorScript_Member : public SkScriptCallBackMember {
+public:
+
+       SkAnimatorScript_Member(SkAnimatorScript2* engine) : fEngine(engine) {}
+
+       bool getMemberReference(const char* member, size_t len, void* object, SkScriptValue2* ref) {
+               SkDisplayable* displayable = (SkDisplayable*) object;
+               SkString name(member, len);
+               SkDisplayable* named = displayable->contains(name);
+               if (named) {
+                       ref->fType = SkOperand2::kObject;
+                       ref->fOperand.fObject = named;
+                       return true;
+               }
+               const SkMemberInfo* info = displayable->getMember(name.c_str());
+               if (info == nil)
+                       return false;   // !!! add additional error info?
+               ref->fType = SkAnimatorScript2::ToOpType(info->getType());
+               ref->fOperand.fObject = (void*) info;
+               return true;
+       }
+
+       bool invoke(size_t ref, void* object, SkOperand2* value) {
+               const SkMemberInfo* info = (const SkMemberInfo* ) ref;
+               SkDisplayable* displayable = (SkDisplayable*) object;
+               if (info->fType == SkType_MemberProperty) {
+                       if (displayable->getProperty2(info->propertyIndex(), value) == false) {
+                               return false;
+                       }
+               }
+               return fEngine->evalMemberCommon(info, displayable, value);
+       }
+
+       SkAnimatorScript2* fEngine;
+};
+
+
+class SkAnimatorScript_MemberFunction : public SkScriptCallBackMemberFunction {
+public:
+       SkAnimatorScript_MemberFunction(SkAnimatorScript2* engine) : fEngine(engine) {}
+
+       bool getMemberReference(const char* member, size_t len, void* object, SkScriptValue2* ref) {
+               SkDisplayable* displayable = (SkDisplayable*) object;
+               SkString name(member, len);
+               const SkMemberInfo* info = displayable->getMember(name.c_str());
+               if (info == nil || info->fType != SkType_MemberFunction)
+                       return false;   // !!! add additional error info?
+               ref->fType = SkAnimatorScript2::ToOpType(info->getType());
+               ref->fOperand.fObject = (void*) info;
+               return true;
+       }
+
+       virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) {
+               types->setCount(3);
+               SkOperand2::OpType* type = types->begin();
+               type[0] = type[1] = type[2] = SkOperand2::kS32;
+       }
+
+       bool invoke(size_t ref, void* object, SkOpArray* params, SkOperand2* value)
+       {
+               const SkMemberInfo* info = (const SkMemberInfo* ) ref;
+               SkDisplayable* displayable = (SkDisplayable*) object;
+               displayable->executeFunction2(displayable, info->functionIndex(), params, info->getType(), 
+                       value);
+               return fEngine->evalMemberCommon(info, displayable, value);
+       }
+
+       SkAnimatorScript2* fEngine;
+};
+
+
+class SkAnimatorScript_NamedColor : public SkScriptCallBackProperty {
+public:
+       virtual bool getConstValue(const char* name, int len, SkOperand2* value) {
+               return SkParse::FindNamedColor(name, len, (SkColor*) &value->fS32) != nil;
+       }
+};
+
+
+class SkAnimatorScript_RGB : public SkScriptCallBackFunction {
+public:
+       virtual bool getIndex(const char* name, int len, size_t* result) {
+               if (SK_LITERAL_STR_EQUAL("rgb", name, len) != 0)
+                       return false;
+               *result = 0;
+               return true;
+       }
+
+       virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) {
+               types->setCount(3);
+               SkOperand2::OpType* type = types->begin();
+               type[0] = type[1] = type[2] = SkOperand2::kS32;
+       }
+
+       virtual bool invoke(size_t index, SkOpArray* params, SkOperand2* answer) {
+               SkASSERT(index == 0);
+               unsigned result = 0xFF000000;
+               int shift = 16;
+               for (int index = 0; index < 3; index++) {
+                       result |= SkClampMax(params->begin()[index].fS32, 255) << shift;
+                       shift -= 8;
+               }
+               answer->fS32 = result;
+               return true;
+       }
+
+};
+
+
+class SkAnimatorScript_Unbox : public SkScriptCallBackConvert {
+public:
+       SkAnimatorScript_Unbox(SkAnimatorScript2* engine) : fEngine(engine) {}
+
+       virtual bool convert(SkOperand2::OpType type, SkOperand2* operand) {
+               SkASSERT(type == SkOperand2::kObject);
+               SkDisplayable* displayable = (SkDisplayable*) operand->fObject;
+               switch (displayable->getType()) {
+                       case SkType_Array: {
+                               SkDisplayArray* boxedValue = (SkDisplayArray*) displayable;
+                               operand->fArray = new SkOpArray(SkAnimatorScript2::ToOpType(boxedValue->values.getType()));
+                               int count = boxedValue->values.count();
+                               operand->fArray->setCount(count);
+                               memcpy(operand->fArray->begin(), boxedValue->values.begin(), count * sizeof(SkOperand2));
+                               fEngine->track(operand->fArray);
+                               } break;
+                       case SkType_Boolean: {
+                               SkDisplayBoolean* boxedValue = (SkDisplayBoolean*) displayable;
+                               operand->fS32 = boxedValue->value;
+                               } break;
+                       case SkType_Int: {
+                               SkDisplayInt* boxedValue = (SkDisplayInt*) displayable;
+                               operand->fS32 = boxedValue->value;
+                               } break;
+                       case SkType_Float: {
+                               SkDisplayFloat* boxedValue = (SkDisplayFloat*) displayable;
+                               operand->fScalar = boxedValue->value;
+                               } break;
+                       case SkType_String: {
+                               SkDisplayString* boxedValue = (SkDisplayString*) displayable;
+                               operand->fString = SkNEW_ARGS(SkString, (boxedValue->value));
+                               } break;
+                       default: {
+                               const char* id;
+                               bool success = fEngine->getMaker().findKey(displayable, &id);
+                               SkASSERT(success);
+                               operand->fString = SkNEW_ARGS(SkString, (id));
+                       }
+               }
+               return true;
+       }
+
+       virtual SkOperand2::OpType getReturnType(int /*index*/, SkOperand2* operand) { 
+               SkDisplayable* displayable = (SkDisplayable*) operand->fObject;
+               switch (displayable->getType()) {
+                       case SkType_Array:
+                               return SkOperand2::kArray;
+                       case SkType_Int:
+                               return SkOperand2::kS32;
+                       case SkType_Float:
+                               return SkOperand2::kScalar;
+                       case SkType_String:
+                       default:
+                               return SkOperand2::kString;
+               }
+       }
+
+       virtual Type getType() const { 
+               return kUnbox; 
+       }
+
+       SkAnimatorScript2* fEngine;
+};
+
+SkAnimatorScript2::SkAnimatorScript2(SkAnimateMaker& maker, SkDisplayable* working, SkDisplayTypes type) : 
+               SkScriptEngine2(ToOpType(type)), fMaker(maker), fWorking(working) {
+       *fCallBackArray.append() = new SkAnimatorScript_Member(this);
+       *fCallBackArray.append() = new SkAnimatorScript_MemberFunction(this);
+       *fCallBackArray.append() = new SkAnimatorScript_Box();
+       *fCallBackArray.append() = new SkAnimatorScript_Unbox(this);
+       *fCallBackArray.append() = new SkAnimatorScript_ID(this);
+       if (type == SkType_ARGB) {
+               *fCallBackArray.append() = new SkAnimatorScript_RGB();
+               *fCallBackArray.append() = new SkAnimatorScript_NamedColor();
+       }
+       if (SkDisplayType::IsEnum(&maker, type)) {
+               // !!! for SpiderMonkey, iterate through the enum values, and map them to globals
+               const SkDisplayEnumMap& map = GetEnumValues(type);
+               *fCallBackArray.append() = new SkAnimatorScript_Enum(map.fValues); 
+       }
+       *fCallBackArray.append() = new SkAnimatorScript_Eval(this);
+#if 0          // !!! no extra support for now
+       for (SkExtras** extraPtr = maker.fExtras.begin(); extraPtr < maker.fExtras.end(); extraPtr++) {
+               SkExtras* extra = *extraPtr;
+               if (extra->fExtraCallBack)
+                       *fCallBackArray.append() = new propertyCallBack(extra->fExtraCallBack, extra->fExtraStorage);
+       }
+#endif
+}
+
+SkAnimatorScript2::~SkAnimatorScript2() {
+       SkScriptCallBack** end = fCallBackArray.end();
+       for (SkScriptCallBack** ptr = fCallBackArray.begin(); ptr < end; ptr++)
+               delete *ptr;
+}
+
+bool SkAnimatorScript2::evalMemberCommon(const SkMemberInfo* info, 
+               SkDisplayable* displayable, SkOperand2* value) {
+       SkDisplayTypes original;
+       SkDisplayTypes type = original = (SkDisplayTypes) info->getType();
+       if (info->fType == SkType_Array)
+               type = SkType_Array;
+       switch (type) {
+               case SkType_ARGB:
+                       type = SkType_Int;
+               case SkType_Boolean:
+               case SkType_Int:
+               case SkType_MSec:
+               case SkType_Float:
+                       SkASSERT(info->getCount() == 1);
+                       if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction) 
+                               value->fS32 = *(int32_t*) info->memberData(displayable);        // OK for SkScalar too
+                       if (type == SkType_MSec) {
+                               value->fScalar = SkScalarDiv((SkScalar) value->fS32, 1000); // dividing two ints is the same as dividing two scalars 
+                               type = SkType_Float;
+                       }
+                       break;
+               case SkType_String: {
+                       SkString* displayableString;
+                       if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction) {
+                               info->getString(displayable, &displayableString);
+                               value->fString = new SkString(*displayableString);
+                       }
+                       } break;
+               case SkType_Array: {
+                       SkASSERT(info->fType != SkType_MemberProperty); // !!! incomplete
+                       SkTDOperandArray* displayableArray = (SkTDOperandArray*) info->memberData(displayable);
+                       if (displayable->getType() == SkType_Array) {
+                               SkDisplayArray* typedArray = (SkDisplayArray*) displayable;
+                               original = typedArray->values.getType();
+                       }
+                       SkASSERT(original != SkType_Unknown);
+                       SkOpArray* array = value->fArray = new SkOpArray(ToOpType(original));
+                       track(array);
+                       int count = displayableArray->count();
+                       if (count > 0) {
+                               array->setCount(count);
+                               memcpy(array->begin(), displayableArray->begin(), count * sizeof(SkOperand2));
+                       }
+                       } break;
+               default:
+                       SkASSERT(0); // unimplemented
+       }
+       return true;
+}
+
+const SkDisplayEnumMap& SkAnimatorScript2::GetEnumValues(SkDisplayTypes type) {
+       int index = SkTSearch<SkDisplayTypes>(&gEnumMaps[0].fType, gEnumMapCount, type, 
+               sizeof(SkDisplayEnumMap));
+       SkASSERT(index >= 0);
+       return gEnumMaps[index];
+}
+
+SkDisplayTypes SkAnimatorScript2::ToDisplayType(SkOperand2::OpType type) {
+       int val = type;
+       switch (val) {
+               case SkOperand2::kNoType:
+                       return SkType_Unknown;
+               case SkOperand2::kS32:
+                       return SkType_Int;
+               case SkOperand2::kScalar:
+                       return SkType_Float;
+               case SkOperand2::kString:
+                       return SkType_String;
+               case SkOperand2::kArray:
+                       return SkType_Array;
+               case SkOperand2::kObject:
+                       return SkType_Displayable;
+               default:
+                       SkASSERT(0);
+                       return SkType_Unknown;
+       }
+}
+
+SkOperand2::OpType SkAnimatorScript2::ToOpType(SkDisplayTypes type) {
+       if (SkDisplayType::IsDisplayable(nil /* fMaker */, type))
+               return SkOperand2::kObject;
+       if (SkDisplayType::IsEnum(nil /* fMaker */, type))
+               return SkOperand2::kS32;
+       switch (type) {
+               case SkType_ARGB:
+               case SkType_MSec:
+               case SkType_Int:
+                       return SkOperand2::kS32;
+               case SkType_Float:
+               case SkType_Point:
+               case SkType_3D_Point:
+                       return SkOperand2::kScalar;
+               case SkType_Base64:
+               case SkType_DynamicString:
+               case SkType_String:
+                       return SkOperand2::kString;
+               case SkType_Array:
+                       return SkOperand2::kArray;
+               case SkType_Unknown:
+                       return SkOperand2::kNoType;
+               default:
+                       SkASSERT(0);
+                       return SkOperand2::kNoType;
+       }
+}
+
+bool SkAnimatorScript2::MapEnums(const char* ptr, const char* match, size_t len, int* value) {
+       int index = 0;
+       bool more = true;
+       do {
+               const char* last = strchr(ptr, '|');
+               if (last == nil) {
+                       last = &ptr[strlen(ptr)];
+                       more = false;
+               }
+               size_t length = last - ptr;
+               if (len == length && strncmp(ptr, match, length) == 0) {
+                       *value = index;
+                       return true;
+               }
+               index++;
+               ptr = last + 1;
+       } while (more);
+       return false;
+}
+
+#if defined SK_DEBUG
+
+#include "SkAnimator.h"
+
+static const char scriptTestSetup[]  = 
+"<screenplay>"
+       "<apply>"
+               "<paint>"
+                       "<emboss id='emboss' direction='[1,1,1]'  />"
+               "</paint>"
+               "<animateField id='animation' field='direction' target='emboss' from='[1,1,1]' to='[-1,1,1]' dur='1'/>"
+               "<set lval='direction[0]' target='emboss' to='-1' />"
+       "</apply>"
+       "<color id='testColor' color='0 ? rgb(0,0,0) : rgb(255,255,255)' />"
+       "<color id='xColor' color='rgb(12,34,56)' />"
+       "<typedArray id='emptyArray' />"
+       "<typedArray id='intArray' values='[1, 4, 6]' />"
+       "<s32 id='idx' value='2' />"
+       "<s32 id='idy' value='2' />"
+       "<string id='alpha' value='abc' />"
+       "<rectangle id='testRect' left='Math.cos(0)' top='2' right='12' bottom='5' />"
+       "<event id='evt'>"
+               "<input name='x' />"
+               "<apply scope='idy'>"
+                       "<set field='value' to='evt.x.s32' />"
+               "</apply>"
+       "</event>"
+"</screenplay>";
+
+#if !defined(SK_BUILD_FOR_BREW)
+static const SkScriptNAnswer scriptTests[]  = {
+       {       "alpha+alpha", SkType_String, 0, 0, "abcabc" },
+       {       "0 ? Math.sin(0) : 1", SkType_Int, 1 },
+       {       "intArray[4]", SkType_Unknown },
+       {       "emptyArray[4]", SkType_Unknown },
+       {       "idx", SkType_Int, 2 },
+       {       "intArray.length", SkType_Int, 3 },
+       {       "intArray.values[0]", SkType_Int, 1 },
+       {       "intArray[0]", SkType_Int, 1 },
+       {       "idx.value", SkType_Int, 2 },
+       {       "alpha.value", SkType_String, 0, 0, "abc" },
+       {       "alpha", SkType_String, 0, 0, "abc" },
+       {       "alpha.value+alpha.value", SkType_String, 0, 0, "abcabc" },
+       {       "alpha+idx", SkType_String, 0, 0, "abc2" },
+       {       "idx+alpha", SkType_String, 0, 0, "2abc" },
+       {       "intArray[idx]", SkType_Int, 6 },
+       {       "alpha.slice(1,2)", SkType_String, 0, 0, "b" },
+       {       "alpha.value.slice(1,2)", SkType_String, 0, 0, "b" },
+       {       "Math.sin(0)", SkType_Float, 0, SkIntToScalar(0) },
+       {       "testRect.left+2", SkType_Float, 0, SkIntToScalar(3) },
+       {       "0 ? intArray[0] : 1", SkType_Int, 1 },
+       {       "0 ? intArray.values[0] : 1", SkType_Int, 1 },
+       {       "0 ? idx : 1", SkType_Int, 1 },
+       {       "0 ? idx.value : 1", SkType_Int, 1 },
+       {       "0 ? alpha.slice(1,2) : 1", SkType_Int, 1 },
+       {       "0 ? alpha.value.slice(1,2) : 1", SkType_Int, 1 },
+       { "idy", SkType_Int, 3 }
+};
+#endif
+
+#define SkScriptNAnswer_testCount      SK_ARRAY_COUNT(scriptTests)
+
+void SkAnimatorScript2::UnitTest() {
+#if !defined(SK_BUILD_FOR_BREW) && defined(SK_SUPPORT_UNITTEST)
+       SkAnimator animator;
+       SkASSERT(animator.decodeMemory(scriptTestSetup, sizeof(scriptTestSetup)-1));
+       SkEvent evt;
+       evt.setString("id", "evt");
+       evt.setS32("x", 3);
+       animator.doUserEvent(evt);
+       // set up animator with memory script above, then run value tests
+       for (int index = 0; index < SkScriptNAnswer_testCount; index++) {
+               SkAnimatorScript2 engine(*animator.fMaker, nil, scriptTests[index].fType);
+               SkScriptValue2 value;
+               const char* script = scriptTests[index].fScript;
+               bool success = engine.evaluateScript(&script, &value);
+               if (success == false) {
+                       SkASSERT(scriptTests[index].fType == SkType_Unknown);
+                       continue;
+               }
+               SkASSERT(value.fType == ToOpType(scriptTests[index].fType));
+               SkScalar error;
+               switch (value.fType) {
+                       case SkOperand2::kS32:
+                               SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer);
+                               break;
+                       case SkOperand2::kScalar:
+                               error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer);
+                               SkASSERT(error < SK_Scalar1 / 10000);
+                               break;
+                       case SkOperand2::kString:
+                               SkASSERT(value.fOperand.fString->equals(scriptTests[index].fStringAnswer));
+                               break;
+                       default:
+                               SkASSERT(0);
+               }
+       }
+#endif
+}
+
+#endif
+
diff --git a/libs/graphics/animator/SkAnimatorScript2.h b/libs/graphics/animator/SkAnimatorScript2.h
new file mode 100755 (executable)
index 0000000..61261e9
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef SkAnimatorScript2_DEFINED
+#define SkAnimatorScript2_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkScript2.h"
+#include "SkTypedArray.h"
+
+class SkAnimateMaker;
+struct SkMemberInfo;
+
+#ifndef SkAnimatorScript_DEFINED
+struct SkDisplayEnumMap {
+       SkDisplayTypes fType;
+       const char* fValues;
+};
+#endif
+
+class SkAnimatorScript2 : public SkScriptEngine2 {
+public:
+       SkAnimatorScript2(SkAnimateMaker& , SkDisplayable* working, SkDisplayTypes type);
+       ~SkAnimatorScript2();
+       bool evalMemberCommon(const SkMemberInfo* info, 
+               SkDisplayable* displayable, SkOperand2* value);
+       SkAnimateMaker& getMaker() { return fMaker; }
+       SkDisplayable* getWorking() { return fWorking; }
+       static bool MapEnums(const char* ptr, const char* match, size_t len, int* value);
+       static const SkDisplayEnumMap& GetEnumValues(SkDisplayTypes type); 
+       static SkDisplayTypes ToDisplayType(SkOperand2::OpType type);
+       static SkOperand2::OpType ToOpType(SkDisplayTypes type);
+private:
+       SkAnimateMaker& fMaker;
+       SkDisplayable* fWorking;
+       friend class SkDump;
+       friend struct SkScriptNAnswer;
+       // illegal
+       SkAnimatorScript2& operator=(const SkAnimatorScript2&);
+#ifdef SK_DEBUG
+public:
+       static void UnitTest();
+#endif
+};
+
+#endif // SkAnimatorScript2_DEFINED
diff --git a/libs/graphics/animator/SkBase64.cpp b/libs/graphics/animator/SkBase64.cpp
new file mode 100644 (file)
index 0000000..664841a
--- /dev/null
@@ -0,0 +1,171 @@
+#include "SkBase64.h"
+
+#define DecodePad -2
+#define EncodePad 64
+
+static const char encode[] = 
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+       "abcdefghijklmnopqrstuvwxyz"
+       "0123456789+/=";
+
+static const signed char decodeData[] = {
+    62, -1, -1, -1, 63,
+    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, DecodePad, -1, -1,
+    -1,  0,  1,  2,  3,  4,  5,  6, 7,  8,  9, 10, 11, 12, 13, 14,
+    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
+};
+
+SkBase64::SkBase64() : fLength((size_t) -1), fData(nil) {
+}
+
+#if defined _WIN32 && _MSC_VER >= 1300 // disable 'two', etc. may be used without having been initialized
+#pragma warning ( push )
+#pragma warning ( disable : 4701 )
+#endif
+
+SkBase64::Error SkBase64::decode(const void* srcPtr, size_t size, bool writeDestination) {
+       unsigned char* dst = (unsigned char*) fData;
+       const unsigned char* dstStart = (const unsigned char*) fData;
+       const unsigned char* src = (const unsigned char*) srcPtr;
+       bool padTwo = false;
+       bool padThree = false;
+       const unsigned char* end = src + size;
+       while (src < end) {
+               unsigned char bytes[4];
+               int byte = 0;
+               do {
+                       unsigned char srcByte = *src++;
+                       if (srcByte == 0)
+                               goto goHome;
+                       if (srcByte <= ' ')
+                               continue; // treat as white space
+                       if (srcByte < '+' || srcByte > 'z')
+                               return kBadCharError;
+                       signed char decoded = decodeData[srcByte - '+'];
+                       bytes[byte] = decoded;
+                       if (decoded < 0) {
+                               if (decoded == DecodePad) 
+                                       goto handlePad;
+                               return kBadCharError;
+                       } else
+                               byte++;
+                       if (*src)
+                               continue;
+                       if (byte == 0)
+                               goto goHome;
+                       if (byte == 4)
+                               break;
+handlePad:
+                       if (byte < 2)
+                               return kPadError;
+                       padThree = true;
+                       if (byte == 2)
+                               padTwo = true;
+                       break;
+               } while (byte < 4);
+               int two, three;
+               if (writeDestination) {
+                       int one = (U8) (bytes[0] << 2);
+                       two = bytes[1];
+                       one |= two >> 4;
+                       two = (U8) (two << 4);
+                       three = bytes[2];
+                       two |= three >> 2;
+                       three = (U8) (three << 6);
+                       three |= bytes[3];
+                       SkASSERT(one < 256 && two < 256 && three < 256);
+                       *dst = (unsigned char) one;
+               }
+               dst++;
+               if (padTwo) 
+                       break;
+               if (writeDestination)
+                       *dst = (unsigned char) two;
+               dst++;
+               if (padThree)
+                       break;
+               if (writeDestination)
+                       *dst = (unsigned char) three;
+               dst++;
+       }
+goHome:
+       fLength = dst - dstStart;
+       return kNoError;
+}
+
+#if defined _WIN32 && _MSC_VER >= 1300 
+#pragma warning ( pop )
+#endif
+
+size_t SkBase64::Encode(const void* srcPtr, size_t length, void* dstPtr) {
+       const unsigned char* src = (const unsigned char*) srcPtr;
+       unsigned char* dst = (unsigned char*) dstPtr;
+       if (dst) {
+               size_t remainder = length % 3;
+               const unsigned char* end = &src[length - remainder];
+               while (src < end) {
+                       unsigned a = *src++;
+                       unsigned b = *src++;
+                       unsigned c = *src++;
+                       int              d = c & 0x3F;
+                       c = (c >> 6 | b << 2) & 0x3F; 
+                       b = (b >> 4 | a << 4) & 0x3F;
+                       a = a >> 2;
+                       *dst++ = encode[a];
+                       *dst++ = encode[b];
+                       *dst++ = encode[c];
+                       *dst++ = encode[d];
+               }
+               if (remainder > 0) {
+                       int k1 = 0;
+                       int k2 = EncodePad;
+                       int a = (U8) *src++;
+                       if (remainder == 2)
+                       {
+                               int b = *src++;
+                               k1 = b >> 4;
+                               k2 = (b << 2) & 0x3F;
+                       }
+                       *dst++ = encode[a >> 2];
+                       *dst++ = encode[(k1 | a << 4) & 0x3F];
+                       *dst++ = encode[k2];
+                       *dst++ = encode[EncodePad];
+               }
+       }
+       return (length + 2) / 3 * 4;
+}
+
+SkBase64::Error SkBase64::decode(const char* src, size_t len) {
+       Error err = decode(src, len, false);
+       SkASSERT(err == kNoError);
+       if (err != kNoError)
+               return err;
+       fData = new char[fLength];      // should use sk_malloc/sk_free
+       decode(src, len, true);
+       return kNoError;
+}
+
+#ifdef SK_SUPPORT_UNITTEST
+void SkBase64::UnitTest() {
+       signed char all[256];
+       for (int index = 0; index < 256; index++)
+               all[index] = (signed char) (index + 1);
+       for (int offset = 0; offset < 6; offset++) {
+               size_t length = 256 - offset;
+               size_t encodeLength = Encode(all + offset, length, nil);
+               char* src = (char*)sk_malloc_throw(encodeLength + 1);
+               Encode(all + offset, length, src);
+               src[encodeLength] = '\0';
+               SkBase64 tryMe;
+               tryMe.decode(src, encodeLength);
+               SkASSERT(length == tryMe.fLength);
+               SkASSERT(strcmp((const char*) (all + offset), tryMe.fData) == 0);
+               sk_free(src);
+               delete[] tryMe.fData;
+       }
+}
+#endif
+
+
diff --git a/libs/graphics/animator/SkBase64.h b/libs/graphics/animator/SkBase64.h
new file mode 100644 (file)
index 0000000..4132dd3
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef SkBase64_DEFINED
+#define SkBase64_DEFINED
+
+#include "SkTypes.h"
+
+struct SkBase64 {
+public:
+       enum Error {
+               kNoError,
+               kPadError,
+               kBadCharError
+       };
+
+       SkBase64();
+       Error decode(const char* src, size_t length);
+       char* getData() { return fData; }
+       static size_t Encode(const void* src, size_t length, void* dest);
+
+#ifdef SK_SUPPORT_UNITTEST
+       static void UnitTest();
+#endif
+private:
+       Error decode(const void* srcPtr, size_t length, bool writeDestination);
+
+       size_t fLength;
+       char* fData;
+       friend class SkImage;
+};
+
+#endif // SkBase64_DEFINED
diff --git a/libs/graphics/animator/SkBoundable.cpp b/libs/graphics/animator/SkBoundable.cpp
new file mode 100644 (file)
index 0000000..92c8fd0
--- /dev/null
@@ -0,0 +1,47 @@
+#include "SkBoundable.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+
+SkBoundable::SkBoundable() {
+       clearBounds();
+       fBounds.fTop = 0;
+       fBounds.fRight = 0;
+       fBounds.fBottom = 0;
+}
+
+void SkBoundable::clearBounder() {
+       fBounds.fLeft = 0x7fff;
+}
+
+void SkBoundable::getBounds(SkRect* rect) {
+       SkASSERT(rect);
+       if (fBounds.fLeft == (S16)0x8000U) {
+               INHERITED::getBounds(rect);
+               return;
+       }
+       rect->fLeft = SkIntToScalar(fBounds.fLeft);
+       rect->fTop = SkIntToScalar(fBounds.fTop);
+       rect->fRight = SkIntToScalar(fBounds.fRight);
+       rect->fBottom = SkIntToScalar(fBounds.fBottom);
+}
+
+void SkBoundable::enableBounder() {
+       fBounds.fLeft = 0;
+}
+
+
+SkBoundableAuto::SkBoundableAuto(SkBoundable* boundable, 
+               SkAnimateMaker& maker) : fBoundable(boundable), fMaker(maker) {
+       if (fBoundable->hasBounds()) {
+               fMaker.fCanvas->setBounder(&maker.fDisplayList);
+               fMaker.fDisplayList.fBounds.setEmpty();
+       }
+}
+
+SkBoundableAuto::~SkBoundableAuto() {
+       if (fBoundable->hasBounds() == false)
+               return;
+       fMaker.fCanvas->setBounder(nil);
+       fBoundable->setBounds(fMaker.fDisplayList.fBounds);
+}
+
diff --git a/libs/graphics/animator/SkBoundable.h b/libs/graphics/animator/SkBoundable.h
new file mode 100644 (file)
index 0000000..d3e3586
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef SkBoundable_DEFINED
+#define SkBoundable_DEFINED
+
+#include "SkDrawable.h"
+#include "SkRect.h"
+
+class SkBoundable : public SkDrawable {
+public:
+       SkBoundable();
+       virtual void clearBounder();
+       virtual void enableBounder();
+       virtual void getBounds(SkRect* );
+       bool hasBounds() { return fBounds.fLeft != (S16)0x8000U; }
+       void setBounds(SkRect16& bounds) { fBounds = bounds; }
+protected:
+       void clearBounds() { fBounds.fLeft = (S16) SkToU16(0x8000); }; // mark bounds as unset
+       SkRect16 fBounds;
+private:
+       typedef SkDrawable INHERITED;
+};
+
+class SkBoundableAuto {
+public:
+       SkBoundableAuto(SkBoundable* boundable, SkAnimateMaker& maker);
+       ~SkBoundableAuto();
+private:
+       SkBoundable* fBoundable;
+       SkAnimateMaker& fMaker;
+       SkBoundableAuto& operator= (const SkBoundableAuto& );
+};
+
+#endif // SkBoundable_DEFINED
+
diff --git a/libs/graphics/animator/SkBuildCondensedInfo.cpp b/libs/graphics/animator/SkBuildCondensedInfo.cpp
new file mode 100644 (file)
index 0000000..6c29499
--- /dev/null
@@ -0,0 +1,275 @@
+#include "SkTypes.h"
+#if defined SK_BUILD_CONDENSED
+#include "SkMemberInfo.h"
+#if SK_USE_CONDENSED_INFO == 1 
+#error "SK_USE_CONDENSED_INFO must be zero to build condensed info"
+#endif
+#if !defined SK_BUILD_FOR_WIN32
+#error "SK_BUILD_FOR_WIN32 must be defined to build condensed info"
+#endif
+#include "SkDisplayType.h"
+#include "SkIntArray.h"
+#include <stdio.h>
+
+SkTDMemberInfoArray gInfos;
+SkTDIntArray gInfosCounts;
+SkTDDisplayTypesArray gInfosTypeIDs;
+SkTDMemberInfoArray gUnknowns;
+SkTDIntArray gUnknownsCounts;
+
+static void AddInfo(SkDisplayTypes type, const SkMemberInfo* info, int infoCount) {
+       SkASSERT(gInfos[type] == nil);
+       gInfos[type] = info;
+       gInfosCounts[type] = infoCount;
+       *gInfosTypeIDs.append() = type;
+       size_t allStrs = 0;
+       for (int inner = 0; inner < infoCount; inner++) {
+               SkASSERT(info[inner].fCount < 256);
+               int offset = (int) info[inner].fOffset;
+               SkASSERT(offset < 128 && offset > -129);
+               SkASSERT(allStrs < 256);
+               if (info[inner].fType == SkType_BaseClassInfo) {
+                       const SkMemberInfo* innerInfo = (const SkMemberInfo*) info[inner].fName;
+                       if (gUnknowns.find(innerInfo) == -1) {
+                               *gUnknowns.append() = innerInfo;
+                               *gUnknownsCounts.append() = info[inner].fCount;
+                       }
+               }
+               if (info[inner].fType != SkType_BaseClassInfo && info[inner].fName)
+                       allStrs += strlen(info[inner].fName);
+               allStrs += 1;
+               SkASSERT(info[inner].fType < 256);
+       }
+}
+
+static void WriteInfo(FILE* condensed, const SkMemberInfo* info, int infoCount,
+                       const char* typeName, bool draw, bool display) {
+       fprintf(condensed, "static const char g%sStrings[] = \n", typeName);
+       int inner;
+       // write strings
+       for (inner = 0; inner < infoCount; inner++) {
+               const char* name = (info[inner].fType != SkType_BaseClassInfo && info[inner].fName) ?
+                       info[inner].fName : "";
+               const char* zero = inner < infoCount - 1 ? "\\0" : "";
+               fprintf(condensed, "\t\"%s%s\"\n", name, zero);
+       }
+       fprintf(condensed, ";\n\nstatic const SkMemberInfo g%s", draw ? "Draw" : display ? "Display" : "");
+       fprintf(condensed, "%sInfo[] = {", typeName);
+       size_t nameOffset = 0;
+       // write info tables
+       for (inner = 0; inner < infoCount; inner++) {
+               size_t offset = info[inner].fOffset;
+               if (info[inner].fType == SkType_BaseClassInfo) {
+                       offset = (size_t) gInfos.find((const SkMemberInfo* ) info[inner].fName);
+                       SkASSERT((int) offset >= 0);
+                       offset = gInfosTypeIDs.find((SkDisplayTypes) offset);
+                       SkASSERT((int) offset >= 0);
+               }
+               fprintf(condensed, "\n\t{%d, %d, %d, %d}", nameOffset, offset,
+                       info[inner].fType, info[inner].fCount);
+               if (inner < infoCount - 1)
+                       putc(',', condensed);
+               if (info[inner].fType != SkType_BaseClassInfo && info[inner].fName)
+                       nameOffset += strlen(info[inner].fName);
+               nameOffset += 1;
+       }
+       fprintf(condensed, "\n};\n\n");
+}
+
+static void Get3DName(char* scratch, const char* name) {
+       if (strncmp("skia3d:", name, sizeof("skia3d:") - 1) == 0) {
+               strcpy(scratch, "3D_");
+               scratch[3]= name[7] & ~0x20;
+               strcpy(&scratch[4], &name[8]);
+       } else {
+               scratch[0] = name[0] & ~0x20;
+               strcpy(&scratch[1], &name[1]);
+       }
+}
+
+int type_compare(const void* a, const void* b) {
+       SkDisplayTypes first = *(SkDisplayTypes*) a;
+       SkDisplayTypes second = *(SkDisplayTypes*) b;
+       return first < second ? -1 : first == second ? 0 : 1;
+}
+
+void SkDisplayType::BuildCondensedInfo(SkAnimateMaker* maker) {
+       gInfos.setCount(kNumberOfTypes);
+       memset(gInfos.begin(), 0, sizeof(gInfos[0]) * kNumberOfTypes);
+       gInfosCounts.setCount(kNumberOfTypes);
+       memset(gInfosCounts.begin(), -1, sizeof(gInfosCounts[0]) * kNumberOfTypes);
+       // check to see if it is condensable
+       int index, infoCount;
+       for (index = 0; index < kTypeNamesSize; index++) {
+               const SkMemberInfo* info = GetMembers(maker, gTypeNames[index].fType, &infoCount);
+               if (info == nil)
+                       continue;
+               AddInfo(gTypeNames[index].fType, info, infoCount);
+       }
+       const SkMemberInfo* extraInfo = 
+               SkDisplayType::GetMembers(maker, SkType_3D_Point, &infoCount);
+       AddInfo(SkType_Point, extraInfo, infoCount);
+       AddInfo(SkType_3D_Point, extraInfo, infoCount);
+//     int baseInfos = gInfos.count();
+       do {
+               SkTDMemberInfoArray oldRefs = gUnknowns;
+               SkTDIntArray oldRefCounts = gUnknownsCounts;
+               gUnknowns.reset();
+               gUnknownsCounts.reset();
+               for (index = 0; index < oldRefs.count(); index++) {
+                       const SkMemberInfo* info = oldRefs[index];
+                       if (gInfos.find(info) == -1) {
+                               int typeIndex = 0;
+                               for (; typeIndex < kNumberOfTypes; typeIndex++) {
+                                       const SkMemberInfo* temp = SkDisplayType::GetMembers(
+                                               maker, (SkDisplayTypes) typeIndex, nil);
+                                       if (temp == info)
+                                               break;
+                               }
+                               SkASSERT(typeIndex < kNumberOfTypes);
+                               AddInfo((SkDisplayTypes) typeIndex, info, oldRefCounts[index]);
+                       }
+               }
+       } while (gUnknowns.count() > 0);
+       qsort(gInfosTypeIDs.begin(), gInfosTypeIDs.count(), sizeof(gInfosTypeIDs[0]), &type_compare);
+#ifdef SK_DEBUG
+       FILE* condensed = fopen("../../src/animator/SkCondensedDebug.cpp", "w+");
+       fprintf(condensed, "#include \"SkTypes.h\"\n");
+       fprintf(condensed, "#ifdef SK_DEBUG\n");
+#else
+       FILE* condensed = fopen("../../src/animator/SkCondensedRelease.cpp", "w+");
+       fprintf(condensed, "#include \"SkTypes.h\"\n");
+       fprintf(condensed, "#ifdef SK_RELEASE\n");
+#endif
+       // write header
+       fprintf(condensed, "// This file was automatically generated.\n");
+       fprintf(condensed, "// To change it, edit the file with the matching debug info.\n");
+       fprintf(condensed, "// Then execute SkDisplayType::BuildCondensedInfo() to "
+               "regenerate this file.\n\n");
+       // write name of memberInfo
+       int typeNameIndex = 0;
+       int unknown = 1;
+       for (index = 0; index < gInfos.count(); index++) {
+               const SkMemberInfo* info = gInfos[index];
+               if (info == nil)
+                       continue;
+               char scratch[64];
+               bool drawPrefix, displayPrefix;
+               while (gTypeNames[typeNameIndex].fType < index)
+                       typeNameIndex++;
+               if (gTypeNames[typeNameIndex].fType == index) {
+                       Get3DName(scratch, gTypeNames[typeNameIndex].fName);
+                       drawPrefix = gTypeNames[typeNameIndex].fDrawPrefix;
+                       displayPrefix = gTypeNames[typeNameIndex].fDisplayPrefix;
+               } else {
+                       sprintf(scratch, "Unknown%d", unknown++);
+                       drawPrefix = displayPrefix = false;
+               }
+               WriteInfo(condensed, info, gInfosCounts[index], scratch, drawPrefix, displayPrefix);
+       }
+       // write array of table pointers
+//     start here;
+       fprintf(condensed, "static const SkMemberInfo* const gInfoTables[] = {");
+       typeNameIndex = 0;
+       unknown = 1;
+       for (index = 0; index < gInfos.count(); index++) {
+               const SkMemberInfo* info = gInfos[index];
+               if (info == nil)
+                       continue;
+               char scratch[64];
+               bool drawPrefix, displayPrefix;
+               while (gTypeNames[typeNameIndex].fType < index)
+                       typeNameIndex++;
+               if (gTypeNames[typeNameIndex].fType == index) {
+                       Get3DName(scratch, gTypeNames[typeNameIndex].fName);
+                       drawPrefix = gTypeNames[typeNameIndex].fDrawPrefix;
+                       displayPrefix = gTypeNames[typeNameIndex].fDisplayPrefix;
+               } else {
+                       sprintf(scratch, "Unknown%d", unknown++);
+                       drawPrefix = displayPrefix = false;
+               }
+               fprintf(condensed, "\n\tg");
+               if (drawPrefix)
+                       fprintf(condensed, "Draw");
+               if (displayPrefix)
+                       fprintf(condensed, "Display");
+               fprintf(condensed, "%sInfo", scratch);
+               if (index < gInfos.count() - 1)
+                               putc(',', condensed);
+       }
+       fprintf(condensed, "\n};\n\n");
+       // write the array of number of entries in the info table
+       fprintf(condensed, "static const unsigned char gInfoCounts[] = {\n\t");
+       int written = 0;
+       for (index = 0; index < gInfosCounts.count(); index++) {
+               int count = gInfosCounts[index];
+               if (count < 0)
+                       continue;
+               if (written > 0)
+                       putc(',', condensed);
+               if (written % 20 == 19)
+                       fprintf(condensed, "\n\t");
+               fprintf(condensed, "%d",count);
+               written++;
+       }
+       fprintf(condensed, "\n};\n\n");
+       // write array of type ids table entries correspond to
+       fprintf(condensed, "static const unsigned char gTypeIDs[] = {\n\t");
+       int typeIDCount = 0;
+       typeNameIndex = 0;
+       unknown = 1;
+       for (index = 0; index < gInfosCounts.count(); index++) {
+               const SkMemberInfo* info = gInfos[index];
+               if (info == nil)
+                       continue;
+               typeIDCount++;
+               char scratch[64];
+               while (gTypeNames[typeNameIndex].fType < index)
+                       typeNameIndex++;
+               if (gTypeNames[typeNameIndex].fType == index) {
+                       Get3DName(scratch, gTypeNames[typeNameIndex].fName);
+               } else
+                       sprintf(scratch, "Unknown%d", unknown++);
+               fprintf(condensed, "%d%c // %s\n\t", index, 
+                       index < gInfosCounts.count() ? ',' : ' ', scratch);
+       }
+       fprintf(condensed, "\n};\n\n");
+       fprintf(condensed, "static const int kTypeIDs = %d;\n\n", typeIDCount);
+       // write the array of string pointers
+       fprintf(condensed, "static const char* const gInfoNames[] = {");
+       typeNameIndex = 0;
+       unknown = 1;
+       written = 0;
+       for (index = 0; index < gInfosCounts.count(); index++) {
+               const SkMemberInfo* info = gInfos[index];
+               if (info == nil)
+                       continue;
+               if (written > 0)
+                               putc(',', condensed);
+               written++;
+               fprintf(condensed, "\n\tg");
+               char scratch[64];
+               while (gTypeNames[typeNameIndex].fType < index)
+                       typeNameIndex++;
+               if (gTypeNames[typeNameIndex].fType == index) {
+                       Get3DName(scratch, gTypeNames[typeNameIndex].fName);
+               } else
+                       sprintf(scratch, "Unknown%d", unknown++);
+               fprintf(condensed, "%sStrings", scratch);
+       }
+       fprintf(condensed, "\n};\n\n");
+       fprintf(condensed, "#endif\n");
+       fclose(condensed);
+       gInfos.reset();
+       gInfosCounts.reset();
+       gInfosTypeIDs.reset();
+       gUnknowns.reset();
+       gUnknownsCounts.reset();
+}
+
+#elif defined SK_DEBUG
+#include "SkDisplayType.h"
+void SkDisplayType::BuildCondensedInfo(SkAnimateMaker* ) {}
+#endif
+
+
diff --git a/libs/graphics/animator/SkCondensedDebug.cpp b/libs/graphics/animator/SkCondensedDebug.cpp
new file mode 100644 (file)
index 0000000..f60487b
--- /dev/null
@@ -0,0 +1,1380 @@
+#include "SkTypes.h"
+#ifndef SK_BUILD_FOR_UNIX
+#ifdef SK_DEBUG
+// This file was automatically generated.
+// To change it, edit the file with the matching debug info.
+// Then execute SkDisplayType::BuildCondensedInfo() to regenerate this file.
+
+static const char gMathStrings[] = 
+       "E\0"
+       "LN10\0"
+       "LN2\0"
+       "LOG10E\0"
+       "LOG2E\0"
+       "PI\0"
+       "SQRT1_2\0"
+       "SQRT2\0"
+       "abs\0"
+       "acos\0"
+       "asin\0"
+       "atan\0"
+       "atan2\0"
+       "ceil\0"
+       "cos\0"
+       "exp\0"
+       "floor\0"
+       "log\0"
+       "max\0"
+       "min\0"
+       "pow\0"
+       "random\0"
+       "round\0"
+       "sin\0"
+       "sqrt\0"
+       "tan"
+;
+
+static const SkMemberInfo gMathInfo[] = {
+       {0, -1, 67, 98},
+       {2, -2, 67, 98},
+       {7, -3, 67, 98},
+       {11, -4, 67, 98},
+       {18, -5, 67, 98},
+       {24, -6, 67, 98},
+       {27, -7, 67, 98},
+       {35, -8, 67, 98},
+       {41, -1, 66, 98},
+       {45, -2, 66, 98},
+       {50, -3, 66, 98},
+       {55, -4, 66, 98},
+       {60, -5, 66, 98},
+       {66, -6, 66, 98},
+       {71, -7, 66, 98},
+       {75, -8, 66, 98},
+       {79, -9, 66, 98},
+       {85, -10, 66, 98},
+       {89, -11, 66, 98},
+       {93, -12, 66, 98},
+       {97, -13, 66, 98},
+       {101, -14, 66, 98},
+       {108, -15, 66, 98},
+       {114, -16, 66, 98},
+       {118, -17, 66, 98},
+       {123, -18, 66, 98}
+};
+
+static const char gAddStrings[] = 
+       "inPlace\0"
+       "offset\0"
+       "use\0"
+       "where"
+;
+
+static const SkMemberInfo gAddInfo[] = {
+       {0, 16, 26, 1},
+       {8, 20, 96, 1},
+       {15, 24, 37, 1},
+       {19, 28, 37, 1}
+};
+
+static const char gAddCircleStrings[] = 
+       "\0"
+       "radius\0"
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gAddCircleInfo[] = {
+       {0, 3, 18, 1},
+       {1, 24, 98, 1},
+       {8, 28, 98, 1},
+       {10, 32, 98, 1}
+};
+
+static const char gUnknown1Strings[] = 
+       "direction"
+;
+
+static const SkMemberInfo gUnknown1Info[] = {
+       {0, 20, 75, 1}
+};
+
+static const char gAddOvalStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gAddOvalInfo[] = {
+       {0, 6, 18, 5}
+};
+
+static const char gAddPathStrings[] = 
+       "matrix\0"
+       "path"
+;
+
+static const SkMemberInfo gAddPathInfo[] = {
+       {0, 20, 65, 1},
+       {7, 24, 74, 1}
+};
+
+static const char gAddRectangleStrings[] = 
+       "\0"
+       "bottom\0"
+       "left\0"
+       "right\0"
+       "top"
+;
+
+static const SkMemberInfo gAddRectangleInfo[] = {
+       {0, 3, 18, 1},
+       {1, 36, 98, 1},
+       {8, 24, 98, 1},
+       {13, 32, 98, 1},
+       {19, 28, 98, 1}
+};
+
+static const char gAddRoundRectStrings[] = 
+       "\0"
+       "rx\0"
+       "ry"
+;
+
+static const SkMemberInfo gAddRoundRectInfo[] = {
+       {0, 6, 18, 5},
+       {1, 40, 98, 1},
+       {4, 44, 98, 1}
+};
+
+static const char gUnknown2Strings[] = 
+       "begin\0"
+       "blend\0"
+       "dur\0"
+       "dynamic\0"
+       "field\0"
+       "formula\0"
+       "from\0"
+       "mirror\0"
+       "repeat\0"
+       "reset\0"
+       "target\0"
+       "to\0"
+       "values"
+;
+
+static const SkMemberInfo gUnknown2Info[] = {
+       {0, 16, 71, 1},
+       {6, 20, 119, 98},
+       {12, 36, 71, 1},
+       {16, -1, 67, 26},
+       {24, 40, 108, 2},
+       {30, 48, 40, 2},
+       {38, 56, 40, 2},
+       {43, -2, 67, 26},
+       {50, 64, 98, 1},
+       {57, -3, 67, 26},
+       {63, 68, 40, 2},
+       {70, 76, 40, 2},
+       {73, -4, 67, 40}
+};
+
+static const char gAnimateFieldStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gAnimateFieldInfo[] = {
+       {0, 8, 18, 13}
+};
+
+static const char gApplyStrings[] = 
+       "animator\0"
+       "begin\0"
+       "dontDraw\0"
+       "dynamicScope\0"
+       "interval\0"
+       "mode\0"
+       "pickup\0"
+       "restore\0"
+       "scope\0"
+       "step\0"
+       "steps\0"
+       "time\0"
+       "transition"
+;
+
+static const SkMemberInfo gApplyInfo[] = {
+       {0, -1, 67, 10},
+       {9, 16, 71, 1},
+       {15, 20, 26, 1},
+       {24, 24, 108, 2},
+       {37, 32, 71, 1},
+       {46, 36, 13, 1},
+       {51, 40, 26, 1},
+       {58, 44, 26, 1},
+       {66, 48, 37, 1},
+       {72, -2, 67, 96},
+       {77, 52, 96, 1},
+       {83, -3, 67, 71},
+       {88, 56, 14, 1}
+};
+
+static const char gUnknown3Strings[] = 
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gUnknown3Info[] = {
+       {0, 48, 98, 1},
+       {2, 52, 98, 1}
+};
+
+static const char gBitmapStrings[] = 
+       "\0"
+       "erase\0"
+       "format\0"
+       "height\0"
+       "rowBytes\0"
+       "width"
+;
+
+static const SkMemberInfo gDrawBitmapInfo[] = {
+       {0, 11, 18, 2},
+       {1, -1, 67, 15},
+       {7, 56, 21, 1},
+       {14, 60, 96, 1},
+       {21, 64, 96, 1},
+       {30, 68, 96, 1}
+};
+
+static const char gBitmapShaderStrings[] = 
+       "\0"
+       "filterType\0"
+       "image"
+;
+
+static const SkMemberInfo gDrawBitmapShaderInfo[] = {
+       {0, 67, 18, 2},
+       {1, 28, 47, 1},
+       {12, 32, 17, 1}
+};
+
+static const char gBlurStrings[] = 
+       "blurStyle\0"
+       "radius"
+;
+
+static const SkMemberInfo gDrawBlurInfo[] = {
+       {0, 24, 63, 1},
+       {10, 20, 98, 1}
+};
+
+static const char gBoundsStrings[] = 
+       "\0"
+       "inval"
+;
+
+static const SkMemberInfo gDisplayBoundsInfo[] = {
+       {0, 58, 18, 7},
+       {1, 44, 26, 1}
+};
+
+static const char gClipStrings[] = 
+       "path\0"
+       "rectangle"
+;
+
+static const SkMemberInfo gDrawClipInfo[] = {
+       {0, 20, 74, 1},
+       {5, 16, 91, 1}
+};
+
+static const char gColorStrings[] = 
+       "alpha\0"
+       "blue\0"
+       "color\0"
+       "green\0"
+       "hue\0"
+       "red\0"
+       "saturation\0"
+       "value"
+;
+
+static const SkMemberInfo gDrawColorInfo[] = {
+       {0, -1, 67, 98},
+       {6, -2, 67, 98},
+       {11, 20, 15, 1},
+       {17, -3, 67, 98},
+       {23, -4, 67, 98},
+       {27, -5, 67, 98},
+       {31, -6, 67, 98},
+       {42, -7, 67, 98}
+};
+
+static const char gCubicToStrings[] = 
+       "x1\0"
+       "x2\0"
+       "x3\0"
+       "y1\0"
+       "y2\0"
+       "y3"
+;
+
+static const SkMemberInfo gCubicToInfo[] = {
+       {0, 20, 98, 1},
+       {3, 28, 98, 1},
+       {6, 36, 98, 1},
+       {9, 24, 98, 1},
+       {12, 32, 98, 1},
+       {15, 40, 98, 1}
+};
+
+static const char gDashStrings[] = 
+       "intervals\0"
+       "phase"
+;
+
+static const SkMemberInfo gDashInfo[] = {
+       {0, 20, 119, 98},
+       {10, 36, 98, 1}
+};
+
+static const char gDataStrings[] = 
+       "\0"
+       "name"
+;
+
+static const SkMemberInfo gDataInfo[] = {
+       {0, 33, 18, 3},
+       {1, 32, 108, 2}
+};
+
+static const char gDiscreteStrings[] = 
+       "deviation\0"
+       "segLength"
+;
+
+static const SkMemberInfo gDiscreteInfo[] = {
+       {0, 20, 98, 1},
+       {10, 24, 98, 1}
+};
+
+static const char gDrawToStrings[] = 
+       "drawOnce\0"
+       "use"
+;
+
+static const SkMemberInfo gDrawToInfo[] = {
+       {0, 72, 26, 1},
+       {9, 76, 19, 1}
+};
+
+static const char gDumpStrings[] = 
+       "displayList\0"
+       "eventList\0"
+       "events\0"
+       "groups\0"
+       "name\0"
+       "posts"
+;
+
+static const SkMemberInfo gDumpInfo[] = {
+       {0, 16, 26, 1},
+       {12, 20, 26, 1},
+       {22, 24, 26, 1},
+       {29, 36, 26, 1},
+       {36, 28, 108, 2},
+       {41, 40, 26, 1}
+};
+
+static const char gEmbossStrings[] = 
+       "ambient\0"
+       "direction\0"
+       "radius\0"
+       "specular"
+;
+
+static const SkMemberInfo gDrawEmbossInfo[] = {
+       {0, -1, 67, 98},
+       {8, 20, 119, 98},
+       {18, 36, 98, 1},
+       {25, -2, 67, 98}
+};
+
+static const char gEventStrings[] = 
+       "code\0"
+       "disable\0"
+       "key\0"
+       "keys\0"
+       "kind\0"
+       "target\0"
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gDisplayEventInfo[] = {
+       {0, 16, 43, 1},
+       {5, 20, 26, 1},
+       {13, -1, 67, 108},
+       {17, -2, 67, 108},
+       {22, 24, 44, 1},
+       {27, 28, 108, 2},
+       {34, 36, 98, 1},
+       {36, 40, 98, 1}
+};
+
+static const char gFromPathStrings[] = 
+       "mode\0"
+       "offset\0"
+       "path"
+;
+
+static const SkMemberInfo gFromPathInfo[] = {
+       {0, 20, 49, 1},
+       {5, 24, 98, 1},
+       {12, 28, 74, 1}
+};
+
+static const char gUnknown4Strings[] = 
+       "\0"
+       "offsets\0"
+       "unitMapper"
+;
+
+static const SkMemberInfo gUnknown4Info[] = {
+       {0, 67, 18, 2},
+       {1, 28, 119, 98},
+       {9, 44, 108, 2}
+};
+
+static const char gGStrings[] = 
+       "condition\0"
+       "enableCondition"
+;
+
+static const SkMemberInfo gGInfo[] = {
+       {0, 16, 40, 2},
+       {10, 24, 40, 2}
+};
+
+static const char gHitClearStrings[] = 
+       "targets"
+;
+
+static const SkMemberInfo gHitClearInfo[] = {
+       {0, 16, 119, 36}
+};
+
+static const char gHitTestStrings[] = 
+       "bullets\0"
+       "hits\0"
+       "targets\0"
+       "value"
+;
+
+static const SkMemberInfo gHitTestInfo[] = {
+       {0, 16, 119, 36},
+       {8, 32, 119, 96},
+       {13, 48, 119, 36},
+       {21, 64, 26, 1}
+};
+
+static const char gImageStrings[] = 
+       "\0"
+       "base64\0"
+       "src"
+;
+
+static const SkMemberInfo gImageInfo[] = {
+       {0, 11, 18, 2},
+       {1, 56, 16, 2},
+       {8, 64, 108, 2}
+};
+
+static const char gIncludeStrings[] = 
+       "src"
+;
+
+static const SkMemberInfo gIncludeInfo[] = {
+       {0, 16, 108, 2}
+};
+
+static const char gInputStrings[] = 
+       "s32\0"
+       "scalar\0"
+       "string"
+;
+
+static const SkMemberInfo gInputInfo[] = {
+       {0, 16, 96, 1},
+       {4, 20, 98, 1},
+       {11, 24, 108, 2}
+};
+
+static const char gLineStrings[] = 
+       "x1\0"
+       "x2\0"
+       "y1\0"
+       "y2"
+;
+
+static const SkMemberInfo gLineInfo[] = {
+       {0, 24, 98, 1},
+       {3, 28, 98, 1},
+       {6, 32, 98, 1},
+       {9, 36, 98, 1}
+};
+
+static const char gLineToStrings[] = 
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gLineToInfo[] = {
+       {0, 20, 98, 1},
+       {2, 24, 98, 1}
+};
+
+static const char gLinearGradientStrings[] = 
+       "\0"
+       "points"
+;
+
+static const SkMemberInfo gLinearGradientInfo[] = {
+       {0, 27, 18, 3},
+       {1, 88, 77, 4}
+};
+
+static const char gMatrixStrings[] = 
+       "matrix\0"
+       "perspectX\0"
+       "perspectY\0"
+       "rotate\0"
+       "scale\0"
+       "scaleX\0"
+       "scaleY\0"
+       "skewX\0"
+       "skewY\0"
+       "translate\0"
+       "translateX\0"
+       "translateY"
+;
+
+static const SkMemberInfo gDrawMatrixInfo[] = {
+       {0, 16, 119, 98},
+       {7, -1, 67, 98},
+       {17, -2, 67, 98},
+       {27, -3, 67, 98},
+       {34, -4, 67, 98},
+       {40, -5, 67, 98},
+       {47, -6, 67, 98},
+       {54, -7, 67, 98},
+       {60, -8, 67, 98},
+       {66, -9, 67, 77},
+       {76, -10, 67, 98},
+       {87, -11, 67, 98}
+};
+
+static const char gMoveStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gMoveInfo[] = {
+       {0, 1, 18, 4}
+};
+
+static const char gMoveToStrings[] = 
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gMoveToInfo[] = {
+       {0, 20, 98, 1},
+       {2, 24, 98, 1}
+};
+
+static const char gMovieStrings[] = 
+       "src"
+;
+
+static const SkMemberInfo gMovieInfo[] = {
+       {0, 16, 108, 2}
+};
+
+static const char gOvalStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gOvalInfo[] = {
+       {0, 58, 18, 7}
+};
+
+static const char gPaintStrings[] = 
+       "antiAlias\0"
+       "ascent\0"
+       "color\0"
+       "descent\0"
+       "filterType\0"
+       "linearText\0"
+       "maskFilter\0"
+       "measureText\0"
+       "pathEffect\0"
+       "shader\0"
+       "strikeThru\0"
+       "stroke\0"
+       "strokeCap\0"
+       "strokeJoin\0"
+       "strokeMiter\0"
+       "strokeWidth\0"
+       "style\0"
+       "textAlign\0"
+       "textScaleX\0"
+       "textSize\0"
+       "textSkewX\0"
+       "textTracking\0"
+       "typeface\0"
+       "underline\0"
+       "xfermode"
+;
+
+static const SkMemberInfo gDrawPaintInfo[] = {
+       {0, 16, 26, 1},
+       {10, -1, 67, 98},
+       {17, 20, 31, 1},
+       {23, -2, 67, 98},
+       {31, 24, 47, 1},
+       {42, 28, 26, 1},
+       {53, 32, 62, 1},
+       {64, -1, 66, 98},
+       {76, 36, 76, 1},
+       {87, 40, 102, 1},
+       {94, 44, 26, 1},
+       {105, 48, 26, 1},
+       {112, 52, 27, 1},
+       {122, 56, 58, 1},
+       {133, 60, 98, 1},
+       {145, 64, 98, 1},
+       {157, 68, 109, 1},
+       {163, 72, 9, 1},
+       {173, 76, 98, 1},
+       {184, 80, 98, 1},
+       {193, 84, 98, 1},
+       {203, 88, 98, 1},
+       {216, 92, 120, 1},
+       {225, 96, 26, 1},
+       {235, 100, 121, 1}
+};
+
+static const char gPathStrings[] = 
+       "d\0"
+       "fillType\0"
+       "length"
+;
+
+static const SkMemberInfo gDrawPathInfo[] = {
+       {0, 52, 108, 2},
+       {2, -1, 67, 46},
+       {11, -2, 67, 98}
+};
+
+static const char gUnknown5Strings[] = 
+       "x\0"
+       "y\0"
+       "z"
+;
+
+static const SkMemberInfo gUnknown5Info[] = {
+       {0, 0, 98, 1},
+       {2, 4, 98, 1},
+       {4, 8, 98, 1}
+};
+
+static const char gPointStrings[] = 
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gDrawPointInfo[] = {
+       {0, 16, 98, 1},
+       {2, 20, 98, 1}
+};
+
+static const char gPolyToPolyStrings[] = 
+       "destination\0"
+       "source"
+;
+
+static const SkMemberInfo gPolyToPolyInfo[] = {
+       {0, 24, 80, 1},
+       {12, 20, 80, 1}
+};
+
+static const char gPolygonStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gPolygonInfo[] = {
+       {0, 48, 18, 1}
+};
+
+static const char gPolylineStrings[] = 
+       "points"
+;
+
+static const SkMemberInfo gPolylineInfo[] = {
+       {0, 88, 119, 98}
+};
+
+static const char gPostStrings[] = 
+       "delay\0"
+       "initialized\0"
+       "mode\0"
+       "sink\0"
+       "target\0"
+       "type"
+;
+
+static const SkMemberInfo gPostInfo[] = {
+       {0, 16, 71, 1},
+       {6, 20, 26, 1},
+       {18, 24, 45, 1},
+       {23, -1, 67, 108},
+       {28, -2, 67, 108},
+       {35, -3, 67, 108}
+};
+
+static const char gQuadToStrings[] = 
+       "x1\0"
+       "x2\0"
+       "y1\0"
+       "y2"
+;
+
+static const SkMemberInfo gQuadToInfo[] = {
+       {0, 20, 98, 1},
+       {3, 28, 98, 1},
+       {6, 24, 98, 1},
+       {9, 32, 98, 1}
+};
+
+static const char gRCubicToStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gRCubicToInfo[] = {
+       {0, 18, 18, 6}
+};
+
+static const char gRLineToStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gRLineToInfo[] = {
+       {0, 35, 18, 2}
+};
+
+static const char gRMoveToStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gRMoveToInfo[] = {
+       {0, 39, 18, 2}
+};
+
+static const char gRQuadToStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gRQuadToInfo[] = {
+       {0, 50, 18, 4}
+};
+
+static const char gRadialGradientStrings[] = 
+       "\0"
+       "center\0"
+       "radius"
+;
+
+static const SkMemberInfo gRadialGradientInfo[] = {
+       {0, 27, 18, 3},
+       {1, 88, 77, 2},
+       {8, 96, 98, 1}
+};
+
+static const char gRandomStrings[] = 
+       "blend\0"
+       "max\0"
+       "min\0"
+       "random\0"
+       "seed"
+;
+
+static const SkMemberInfo gDisplayRandomInfo[] = {
+       {0, 16, 98, 1},
+       {6, 24, 98, 1},
+       {10, 20, 98, 1},
+       {14, 1, 67, 98},
+       {21, -2, 67, 96}
+};
+
+static const char gRectToRectStrings[] = 
+       "destination\0"
+       "source"
+;
+
+static const SkMemberInfo gRectToRectInfo[] = {
+       {0, 24, 91, 1},
+       {12, 20, 91, 1}
+};
+
+static const char gRectangleStrings[] = 
+       "bottom\0"
+       "height\0"
+       "left\0"
+       "needsRedraw\0"
+       "right\0"
+       "top\0"
+       "width"
+;
+
+static const SkMemberInfo gRectangleInfo[] = {
+       {0, 36, 98, 1},
+       {7, -1, 67, 98},
+       {14, 24, 98, 1},
+       {19, -2, 67, 26},
+       {31, 32, 98, 1},
+       {37, 28, 98, 1},
+       {41, -3, 67, 98}
+};
+
+static const char gRemoveStrings[] = 
+       "offset\0"
+       "where"
+;
+
+static const SkMemberInfo gRemoveInfo[] = {
+       {0, 20, 96, 1},
+       {7, 28, 37, 1}
+};
+
+static const char gReplaceStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gReplaceInfo[] = {
+       {0, 1, 18, 4}
+};
+
+static const char gRotateStrings[] = 
+       "center\0"
+       "degrees"
+;
+
+static const SkMemberInfo gRotateInfo[] = {
+       {0, 24, 77, 2},
+       {7, 20, 98, 1}
+};
+
+static const char gRoundRectStrings[] = 
+       "\0"
+       "rx\0"
+       "ry"
+;
+
+static const SkMemberInfo gRoundRectInfo[] = {
+       {0, 58, 18, 7},
+       {1, 44, 98, 1},
+       {4, 48, 98, 1}
+};
+
+static const char gS32Strings[] = 
+       "value"
+;
+
+static const SkMemberInfo gS32Info[] = {
+       {0, 16, 96, 1}
+};
+
+static const char gScalarStrings[] = 
+       "value"
+;
+
+static const SkMemberInfo gScalarInfo[] = {
+       {0, 16, 98, 1}
+};
+
+static const char gScaleStrings[] = 
+       "center\0"
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gScaleInfo[] = {
+       {0, 28, 77, 2},
+       {7, 20, 98, 1},
+       {9, 24, 98, 1}
+};
+
+static const char gSetStrings[] = 
+       "begin\0"
+       "dur\0"
+       "dynamic\0"
+       "field\0"
+       "formula\0"
+       "reset\0"
+       "target\0"
+       "to"
+;
+
+static const SkMemberInfo gSetInfo[] = {
+       {0, 16, 71, 1},
+       {6, 36, 71, 1},
+       {10, -1, 67, 26},
+       {18, 40, 108, 2},
+       {24, 48, 40, 2},
+       {32, -3, 67, 26},
+       {38, 68, 40, 2},
+       {45, 76, 40, 2}
+};
+
+static const char gShaderStrings[] = 
+       "matrix\0"
+       "tileMode"
+;
+
+static const SkMemberInfo gShaderInfo[] = {
+       {0, 20, 65, 1},
+       {7, 24, 116, 1}
+};
+
+static const char gSkewStrings[] = 
+       "center\0"
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gSkewInfo[] = {
+       {0, 28, 77, 2},
+       {7, 20, 98, 1},
+       {9, 24, 98, 1}
+};
+
+static const char g3D_CameraStrings[] = 
+       "axis\0"
+       "hackHeight\0"
+       "hackWidth\0"
+       "location\0"
+       "observer\0"
+       "patch\0"
+       "zenith"
+;
+
+static const SkMemberInfo g3D_CameraInfo[] = {
+       {0, 36, 106, 3},
+       {5, 20, 98, 1},
+       {16, 16, 98, 1},
+       {26, 24, 106, 3},
+       {35, 60, 106, 3},
+       {44, 108, 105, 1},
+       {50, 48, 106, 3}
+};
+
+static const char g3D_PatchStrings[] = 
+       "origin\0"
+       "rotateDegrees\0"
+       "u\0"
+       "v"
+;
+
+static const SkMemberInfo g3D_PatchInfo[] = {
+       {0, 40, 106, 3},
+       {7, -1, 66, 98},
+       {21, 16, 106, 3},
+       {23, 28, 106, 3}
+};
+
+static const char gUnknown6Strings[] = 
+       "x\0"
+       "y\0"
+       "z"
+;
+
+static const SkMemberInfo gUnknown6Info[] = {
+       {0, 0, 98, 1},
+       {2, 4, 98, 1},
+       {4, 8, 98, 1}
+};
+
+static const char gSnapshotStrings[] = 
+       "filename\0"
+       "quality\0"
+       "sequence\0"
+       "type"
+;
+
+static const SkMemberInfo gSnapshotInfo[] = {
+       {0, 16, 108, 2},
+       {9, 24, 98, 1},
+       {17, 28, 26, 1},
+       {26, 32, 20, 1}
+};
+
+static const char gStringStrings[] = 
+       "length\0"
+       "slice\0"
+       "value"
+;
+
+static const SkMemberInfo gStringInfo[] = {
+       {0, -1, 67, 96},
+       {7, -1, 66, 108},
+       {13, 16, 108, 2}
+};
+
+static const char gTextStrings[] = 
+       "length\0"
+       "text\0"
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gTextInfo[] = {
+       {0, -1, 67, 96},
+       {7, 24, 108, 2},
+       {12, 32, 98, 1},
+       {14, 36, 98, 1}
+};
+
+static const char gTextBoxStrings[] = 
+       "\0"
+       "mode\0"
+       "spacingAdd\0"
+       "spacingAlign\0"
+       "spacingMul\0"
+       "text"
+;
+
+static const SkMemberInfo gTextBoxInfo[] = {
+       {0, 58, 18, 7},
+       {1, 60, 113, 1},
+       {6, 56, 98, 1},
+       {17, 64, 112, 1},
+       {30, 52, 98, 1},
+       {41, 44, 108, 2}
+};
+
+static const char gTextOnPathStrings[] = 
+       "offset\0"
+       "path\0"
+       "text"
+;
+
+static const SkMemberInfo gTextOnPathInfo[] = {
+       {0, 24, 98, 1},
+       {7, 28, 74, 1},
+       {12, 32, 110, 1}
+};
+
+static const char gTextToPathStrings[] = 
+       "path\0"
+       "text"
+;
+
+static const SkMemberInfo gTextToPathInfo[] = {
+       {0, 16, 74, 1},
+       {5, 20, 110, 1}
+};
+
+static const char gTranslateStrings[] = 
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gTranslateInfo[] = {
+       {0, 20, 98, 1},
+       {2, 24, 98, 1}
+};
+
+static const char gTypedArrayStrings[] = 
+       "length\0"
+       "values"
+;
+
+static const SkMemberInfo gTypedArrayInfo[] = {
+       {0, -1, 67, 96},
+       {7, 16, 119, 0}
+};
+
+static const char gTypefaceStrings[] = 
+       "fontName"
+;
+
+static const SkMemberInfo gTypefaceInfo[] = {
+       {0, 20, 108, 2}
+};
+
+static const SkMemberInfo* const gInfoTables[] = {
+       gMathInfo,
+       gAddInfo,
+       gAddCircleInfo,
+       gUnknown1Info,
+       gAddOvalInfo,
+       gAddPathInfo,
+       gAddRectangleInfo,
+       gAddRoundRectInfo,
+       gUnknown2Info,
+       gAnimateFieldInfo,
+       gApplyInfo,
+       gUnknown3Info,
+       gDrawBitmapInfo,
+       gDrawBitmapShaderInfo,
+       gDrawBlurInfo,
+       gDisplayBoundsInfo,
+       gDrawClipInfo,
+       gDrawColorInfo,
+       gCubicToInfo,
+       gDashInfo,
+       gDataInfo,
+       gDiscreteInfo,
+       gDrawToInfo,
+       gDumpInfo,
+       gDrawEmbossInfo,
+       gDisplayEventInfo,
+       gFromPathInfo,
+       gUnknown4Info,
+       gGInfo,
+       gHitClearInfo,
+       gHitTestInfo,
+       gImageInfo,
+       gIncludeInfo,
+       gInputInfo,
+       gLineInfo,
+       gLineToInfo,
+       gLinearGradientInfo,
+       gDrawMatrixInfo,
+       gMoveInfo,
+       gMoveToInfo,
+       gMovieInfo,
+       gOvalInfo,
+       gDrawPaintInfo,
+       gDrawPathInfo,
+       gUnknown5Info,
+       gDrawPointInfo,
+       gPolyToPolyInfo,
+       gPolygonInfo,
+       gPolylineInfo,
+       gPostInfo,
+       gQuadToInfo,
+       gRCubicToInfo,
+       gRLineToInfo,
+       gRMoveToInfo,
+       gRQuadToInfo,
+       gRadialGradientInfo,
+       gDisplayRandomInfo,
+       gRectToRectInfo,
+       gRectangleInfo,
+       gRemoveInfo,
+       gReplaceInfo,
+       gRotateInfo,
+       gRoundRectInfo,
+       gS32Info,
+       gScalarInfo,
+       gScaleInfo,
+       gSetInfo,
+       gShaderInfo,
+       gSkewInfo,
+       g3D_CameraInfo,
+       g3D_PatchInfo,
+       gUnknown6Info,
+       gSnapshotInfo,
+       gStringInfo,
+       gTextInfo,
+       gTextBoxInfo,
+       gTextOnPathInfo,
+       gTextToPathInfo,
+       gTranslateInfo,
+       gTypedArrayInfo,
+       gTypefaceInfo,
+};
+
+static const unsigned char gInfoCounts[] = {
+       26,4,4,1,1,2,5,3,13,1,13,2,6,3,2,2,2,8,6,
+       2,2,2,2,6,4,8,3,3,2,1,4,3,1,3,4,2,2,12,1,
+       2,1,1,25,3,3,2,2,1,1,6,4,1,1,1,1,3,5,2,7,
+       2,1,2,3,1,1,3,8,2,3,7,4,3,4,3,4,6,3,2,2,
+       2,1
+};
+
+static const unsigned char gTypeIDs[] = {
+       1, // Math
+       2, // Add
+       3, // AddCircle
+       4, // Unknown1
+       5, // AddOval
+       6, // AddPath
+       7, // AddRectangle
+       8, // AddRoundRect
+       10, // Unknown2
+       11, // AnimateField
+       12, // Apply
+       17, // Unknown3
+       19, // Bitmap
+       22, // BitmapShader
+       23, // Blur
+       25, // Bounds
+       29, // Clip
+       31, // Color
+       32, // CubicTo
+       33, // Dash
+       34, // Data
+       35, // Discrete
+       38, // DrawTo
+       39, // Dump
+       41, // Emboss
+       42, // Event
+       48, // FromPath
+       51, // Unknown4
+       52, // G
+       53, // HitClear
+       54, // HitTest
+       55, // Image
+       56, // Include
+       57, // Input
+       59, // Line
+       60, // LineTo
+       61, // LinearGradient
+       65, // Matrix
+       68, // Move
+       69, // MoveTo
+       70, // Movie
+       72, // Oval
+       73, // Paint
+       74, // Path
+       77, // Unknown5
+       78, // Point
+       79, // PolyToPoly
+       80, // Polygon
+       81, // Polyline
+       82, // Post
+       83, // QuadTo
+       84, // RCubicTo
+       85, // RLineTo
+       86, // RMoveTo
+       87, // RQuadTo
+       88, // RadialGradient
+       89, // Random
+       90, // RectToRect
+       91, // Rectangle
+       92, // Remove
+       93, // Replace
+       94, // Rotate
+       95, // RoundRect
+       96, // S32
+       98, // Scalar
+       99, // Scale
+       101, // Set
+       102, // Shader
+       103, // Skew
+       104, // 3D_Camera
+       105, // 3D_Patch
+       106, // Unknown6
+       107, // Snapshot
+       108, // String
+       110, // Text
+       111, // TextBox
+       114, // TextOnPath
+       115, // TextToPath
+       117, // Translate
+       119, // TypedArray
+       120, // Typeface
+       
+};
+
+static const int kTypeIDs = 81;
+
+static const char* const gInfoNames[] = {
+       gMathStrings,
+       gAddStrings,
+       gAddCircleStrings,
+       gUnknown1Strings,
+       gAddOvalStrings,
+       gAddPathStrings,
+       gAddRectangleStrings,
+       gAddRoundRectStrings,
+       gUnknown2Strings,
+       gAnimateFieldStrings,
+       gApplyStrings,
+       gUnknown3Strings,
+       gBitmapStrings,
+       gBitmapShaderStrings,
+       gBlurStrings,
+       gBoundsStrings,
+       gClipStrings,
+       gColorStrings,
+       gCubicToStrings,
+       gDashStrings,
+       gDataStrings,
+       gDiscreteStrings,
+       gDrawToStrings,
+       gDumpStrings,
+       gEmbossStrings,
+       gEventStrings,
+       gFromPathStrings,
+       gUnknown4Strings,
+       gGStrings,
+       gHitClearStrings,
+       gHitTestStrings,
+       gImageStrings,
+       gIncludeStrings,
+       gInputStrings,
+       gLineStrings,
+       gLineToStrings,
+       gLinearGradientStrings,
+       gMatrixStrings,
+       gMoveStrings,
+       gMoveToStrings,
+       gMovieStrings,
+       gOvalStrings,
+       gPaintStrings,
+       gPathStrings,
+       gUnknown5Strings,
+       gPointStrings,
+       gPolyToPolyStrings,
+       gPolygonStrings,
+       gPolylineStrings,
+       gPostStrings,
+       gQuadToStrings,
+       gRCubicToStrings,
+       gRLineToStrings,
+       gRMoveToStrings,
+       gRQuadToStrings,
+       gRadialGradientStrings,
+       gRandomStrings,
+       gRectToRectStrings,
+       gRectangleStrings,
+       gRemoveStrings,
+       gReplaceStrings,
+       gRotateStrings,
+       gRoundRectStrings,
+       gS32Strings,
+       gScalarStrings,
+       gScaleStrings,
+       gSetStrings,
+       gShaderStrings,
+       gSkewStrings,
+       g3D_CameraStrings,
+       g3D_PatchStrings,
+       gUnknown6Strings,
+       gSnapshotStrings,
+       gStringStrings,
+       gTextStrings,
+       gTextBoxStrings,
+       gTextOnPathStrings,
+       gTextToPathStrings,
+       gTranslateStrings,
+       gTypedArrayStrings,
+       gTypefaceStrings
+};
+
+#endif
+#endif
+
+
diff --git a/libs/graphics/animator/SkCondensedRelease.cpp b/libs/graphics/animator/SkCondensedRelease.cpp
new file mode 100644 (file)
index 0000000..70bb1b4
--- /dev/null
@@ -0,0 +1,1357 @@
+#include "SkTypes.h"
+#ifndef SK_BUILD_FOR_UNIX
+#ifdef SK_RELEASE
+// This file was automatically generated.
+// To change it, edit the file with the matching debug info.
+// Then execute SkDisplayType::BuildCondensedInfo() to regenerate this file.
+
+static const char gMathStrings[] = 
+       "E\0"
+       "LN10\0"
+       "LN2\0"
+       "LOG10E\0"
+       "LOG2E\0"
+       "PI\0"
+       "SQRT1_2\0"
+       "SQRT2\0"
+       "abs\0"
+       "acos\0"
+       "asin\0"
+       "atan\0"
+       "atan2\0"
+       "ceil\0"
+       "cos\0"
+       "exp\0"
+       "floor\0"
+       "log\0"
+       "max\0"
+       "min\0"
+       "pow\0"
+       "random\0"
+       "round\0"
+       "sin\0"
+       "sqrt\0"
+       "tan"
+;
+
+static const SkMemberInfo gMathInfo[] = {
+       {0, -1, 67, 98},
+       {2, -2, 67, 98},
+       {7, -3, 67, 98},
+       {11, -4, 67, 98},
+       {18, -5, 67, 98},
+       {24, -6, 67, 98},
+       {27, -7, 67, 98},
+       {35, -8, 67, 98},
+       {41, -1, 66, 98},
+       {45, -2, 66, 98},
+       {50, -3, 66, 98},
+       {55, -4, 66, 98},
+       {60, -5, 66, 98},
+       {66, -6, 66, 98},
+       {71, -7, 66, 98},
+       {75, -8, 66, 98},
+       {79, -9, 66, 98},
+       {85, -10, 66, 98},
+       {89, -11, 66, 98},
+       {93, -12, 66, 98},
+       {97, -13, 66, 98},
+       {101, -14, 66, 98},
+       {108, -15, 66, 98},
+       {114, -16, 66, 98},
+       {118, -17, 66, 98},
+       {123, -18, 66, 98}
+};
+
+static const char gAddStrings[] = 
+       "inPlace\0"
+       "offset\0"
+       "use\0"
+       "where"
+;
+
+static const SkMemberInfo gAddInfo[] = {
+       {0, 4, 26, 1},
+       {8, 8, 96, 1},
+       {15, 12, 37, 1},
+       {19, 16, 37, 1}
+};
+
+static const char gAddCircleStrings[] = 
+       "\0"
+       "radius\0"
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gAddCircleInfo[] = {
+       {0, 3, 18, 1},
+       {1, 12, 98, 1},
+       {8, 16, 98, 1},
+       {10, 20, 98, 1}
+};
+
+static const char gUnknown1Strings[] = 
+       "direction"
+;
+
+static const SkMemberInfo gUnknown1Info[] = {
+       {0, 8, 75, 1}
+};
+
+static const char gAddOvalStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gAddOvalInfo[] = {
+       {0, 6, 18, 5}
+};
+
+static const char gAddPathStrings[] = 
+       "matrix\0"
+       "path"
+;
+
+static const SkMemberInfo gAddPathInfo[] = {
+       {0, 8, 65, 1},
+       {7, 12, 74, 1}
+};
+
+static const char gAddRectangleStrings[] = 
+       "\0"
+       "bottom\0"
+       "left\0"
+       "right\0"
+       "top"
+;
+
+static const SkMemberInfo gAddRectangleInfo[] = {
+       {0, 3, 18, 1},
+       {1, 24, 98, 1},
+       {8, 12, 98, 1},
+       {13, 20, 98, 1},
+       {19, 16, 98, 1}
+};
+
+static const char gAddRoundRectStrings[] = 
+       "\0"
+       "rx\0"
+       "ry"
+;
+
+static const SkMemberInfo gAddRoundRectInfo[] = {
+       {0, 6, 18, 5},
+       {1, 28, 98, 1},
+       {4, 32, 98, 1}
+};
+
+static const char gUnknown2Strings[] = 
+       "begin\0"
+       "blend\0"
+       "dur\0"
+       "dynamic\0"
+       "field\0"
+       "formula\0"
+       "from\0"
+       "mirror\0"
+       "repeat\0"
+       "reset\0"
+       "target\0"
+       "to\0"
+       "values"
+;
+
+static const SkMemberInfo gUnknown2Info[] = {
+       {0, 4, 71, 1},
+       {6, 8, 119, 98},
+       {12, 16, 71, 1},
+       {16, -1, 67, 26},
+       {24, 20, 108, 1},
+       {30, 24, 40, 1},
+       {38, 28, 40, 1},
+       {43, -2, 67, 26},
+       {50, 32, 98, 1},
+       {57, -3, 67, 26},
+       {63, 36, 40, 1},
+       {70, 40, 40, 1},
+       {73, -4, 67, 40}
+};
+
+static const char gAnimateFieldStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gAnimateFieldInfo[] = {
+       {0, 8, 18, 13}
+};
+
+static const char gApplyStrings[] = 
+       "animator\0"
+       "begin\0"
+       "dontDraw\0"
+       "dynamicScope\0"
+       "interval\0"
+       "mode\0"
+       "pickup\0"
+       "restore\0"
+       "scope\0"
+       "step\0"
+       "steps\0"
+       "time\0"
+       "transition"
+;
+
+static const SkMemberInfo gApplyInfo[] = {
+       {0, -1, 67, 10},
+       {9, 4, 71, 1},
+       {15, 8, 26, 1},
+       {24, 12, 108, 1},
+       {37, 16, 71, 1},
+       {46, 20, 13, 1},
+       {51, 24, 26, 1},
+       {58, 28, 26, 1},
+       {66, 32, 37, 1},
+       {72, -2, 67, 96},
+       {77, 36, 96, 1},
+       {83, -3, 67, 71},
+       {88, 40, 14, 1}
+};
+
+static const char gUnknown3Strings[] = 
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gUnknown3Info[] = {
+       {0, 36, 98, 1},
+       {2, 40, 98, 1}
+};
+
+static const char gBitmapStrings[] = 
+       "\0"
+       "erase\0"
+       "format\0"
+       "height\0"
+       "rowBytes\0"
+       "width"
+;
+
+static const SkMemberInfo gDrawBitmapInfo[] = {
+       {0, 11, 18, 2},
+       {1, -1, 67, 15},
+       {7, 44, 21, 1},
+       {14, 48, 96, 1},
+       {21, 52, 96, 1},
+       {30, 56, 96, 1}
+};
+
+static const char gBitmapShaderStrings[] = 
+       "\0"
+       "filterType\0"
+       "image"
+;
+
+static const SkMemberInfo gDrawBitmapShaderInfo[] = {
+       {0, 66, 18, 2},
+       {1, 16, 47, 1},
+       {12, 20, 17, 1}
+};
+
+static const char gBlurStrings[] = 
+       "blurStyle\0"
+       "radius"
+;
+
+static const SkMemberInfo gDrawBlurInfo[] = {
+       {0, 12, 63, 1},
+       {10, 8, 98, 1}
+};
+
+static const char gBoundsStrings[] = 
+       "\0"
+       "inval"
+;
+
+static const SkMemberInfo gDisplayBoundsInfo[] = {
+       {0, 57, 18, 7},
+       {1, 32, 26, 1}
+};
+
+static const char gClipStrings[] = 
+       "path\0"
+       "rectangle"
+;
+
+static const SkMemberInfo gDrawClipInfo[] = {
+       {0, 8, 74, 1},
+       {5, 4, 91, 1}
+};
+
+static const char gColorStrings[] = 
+       "alpha\0"
+       "blue\0"
+       "color\0"
+       "green\0"
+       "hue\0"
+       "red\0"
+       "saturation\0"
+       "value"
+;
+
+static const SkMemberInfo gDrawColorInfo[] = {
+       {0, -1, 67, 98},
+       {6, -2, 67, 98},
+       {11, 8, 15, 1},
+       {17, -3, 67, 98},
+       {23, -4, 67, 98},
+       {27, -5, 67, 98},
+       {31, -6, 67, 98},
+       {42, -7, 67, 98}
+};
+
+static const char gCubicToStrings[] = 
+       "x1\0"
+       "x2\0"
+       "x3\0"
+       "y1\0"
+       "y2\0"
+       "y3"
+;
+
+static const SkMemberInfo gCubicToInfo[] = {
+       {0, 8, 98, 1},
+       {3, 16, 98, 1},
+       {6, 24, 98, 1},
+       {9, 12, 98, 1},
+       {12, 20, 98, 1},
+       {15, 28, 98, 1}
+};
+
+static const char gDashStrings[] = 
+       "intervals\0"
+       "phase"
+;
+
+static const SkMemberInfo gDashInfo[] = {
+       {0, 8, 119, 98},
+       {10, 16, 98, 1}
+};
+
+static const char gDataStrings[] = 
+       "\0"
+       "name"
+;
+
+static const SkMemberInfo gDataInfo[] = {
+       {0, 32, 18, 3},
+       {1, 16, 108, 1}
+};
+
+static const char gDiscreteStrings[] = 
+       "deviation\0"
+       "segLength"
+;
+
+static const SkMemberInfo gDiscreteInfo[] = {
+       {0, 8, 98, 1},
+       {10, 12, 98, 1}
+};
+
+static const char gDrawToStrings[] = 
+       "drawOnce\0"
+       "use"
+;
+
+static const SkMemberInfo gDrawToInfo[] = {
+       {0, 36, 26, 1},
+       {9, 40, 19, 1}
+};
+
+static const char gEmbossStrings[] = 
+       "ambient\0"
+       "direction\0"
+       "radius\0"
+       "specular"
+;
+
+static const SkMemberInfo gDrawEmbossInfo[] = {
+       {0, -1, 67, 98},
+       {8, 8, 119, 98},
+       {18, 16, 98, 1},
+       {25, -2, 67, 98}
+};
+
+static const char gEventStrings[] = 
+       "code\0"
+       "disable\0"
+       "key\0"
+       "keys\0"
+       "kind\0"
+       "target\0"
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gDisplayEventInfo[] = {
+       {0, 4, 43, 1},
+       {5, 8, 26, 1},
+       {13, -1, 67, 108},
+       {17, -2, 67, 108},
+       {22, 12, 44, 1},
+       {27, 16, 108, 1},
+       {34, 20, 98, 1},
+       {36, 24, 98, 1}
+};
+
+static const char gFromPathStrings[] = 
+       "mode\0"
+       "offset\0"
+       "path"
+;
+
+static const SkMemberInfo gFromPathInfo[] = {
+       {0, 8, 49, 1},
+       {5, 12, 98, 1},
+       {12, 16, 74, 1}
+};
+
+static const char gUnknown4Strings[] = 
+       "\0"
+       "offsets\0"
+       "unitMapper"
+;
+
+static const SkMemberInfo gUnknown4Info[] = {
+       {0, 66, 18, 2},
+       {1, 16, 119, 98},
+       {9, 24, 108, 1}
+};
+
+static const char gGStrings[] = 
+       "condition\0"
+       "enableCondition"
+;
+
+static const SkMemberInfo gGInfo[] = {
+       {0, 4, 40, 1},
+       {10, 8, 40, 1}
+};
+
+static const char gHitClearStrings[] = 
+       "targets"
+;
+
+static const SkMemberInfo gHitClearInfo[] = {
+       {0, 4, 119, 36}
+};
+
+static const char gHitTestStrings[] = 
+       "bullets\0"
+       "hits\0"
+       "targets\0"
+       "value"
+;
+
+static const SkMemberInfo gHitTestInfo[] = {
+       {0, 4, 119, 36},
+       {8, 12, 119, 96},
+       {13, 20, 119, 36},
+       {21, 28, 26, 1}
+};
+
+static const char gImageStrings[] = 
+       "\0"
+       "base64\0"
+       "src"
+;
+
+static const SkMemberInfo gImageInfo[] = {
+       {0, 11, 18, 2},
+       {1, 44, 16, 2},
+       {8, 52, 108, 1}
+};
+
+static const char gIncludeStrings[] = 
+       "src"
+;
+
+static const SkMemberInfo gIncludeInfo[] = {
+       {0, 4, 108, 1}
+};
+
+static const char gInputStrings[] = 
+       "s32\0"
+       "scalar\0"
+       "string"
+;
+
+static const SkMemberInfo gInputInfo[] = {
+       {0, 4, 96, 1},
+       {4, 8, 98, 1},
+       {11, 12, 108, 1}
+};
+
+static const char gLineStrings[] = 
+       "x1\0"
+       "x2\0"
+       "y1\0"
+       "y2"
+;
+
+static const SkMemberInfo gLineInfo[] = {
+       {0, 12, 98, 1},
+       {3, 16, 98, 1},
+       {6, 20, 98, 1},
+       {9, 24, 98, 1}
+};
+
+static const char gLineToStrings[] = 
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gLineToInfo[] = {
+       {0, 8, 98, 1},
+       {2, 12, 98, 1}
+};
+
+static const char gLinearGradientStrings[] = 
+       "\0"
+       "points"
+;
+
+static const SkMemberInfo gLinearGradientInfo[] = {
+       {0, 26, 18, 3},
+       {1, 48, 77, 4}
+};
+
+static const char gMatrixStrings[] = 
+       "matrix\0"
+       "perspectX\0"
+       "perspectY\0"
+       "rotate\0"
+       "scale\0"
+       "scaleX\0"
+       "scaleY\0"
+       "skewX\0"
+       "skewY\0"
+       "translate\0"
+       "translateX\0"
+       "translateY"
+;
+
+static const SkMemberInfo gDrawMatrixInfo[] = {
+       {0, 4, 119, 98},
+       {7, -1, 67, 98},
+       {17, -2, 67, 98},
+       {27, -3, 67, 98},
+       {34, -4, 67, 98},
+       {40, -5, 67, 98},
+       {47, -6, 67, 98},
+       {54, -7, 67, 98},
+       {60, -8, 67, 98},
+       {66, -9, 67, 77},
+       {76, -10, 67, 98},
+       {87, -11, 67, 98}
+};
+
+static const char gMoveStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gMoveInfo[] = {
+       {0, 1, 18, 4}
+};
+
+static const char gMoveToStrings[] = 
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gMoveToInfo[] = {
+       {0, 8, 98, 1},
+       {2, 12, 98, 1}
+};
+
+static const char gMovieStrings[] = 
+       "src"
+;
+
+static const SkMemberInfo gMovieInfo[] = {
+       {0, 4, 108, 1}
+};
+
+static const char gOvalStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gOvalInfo[] = {
+       {0, 57, 18, 7}
+};
+
+static const char gPaintStrings[] = 
+       "antiAlias\0"
+       "ascent\0"
+       "color\0"
+       "descent\0"
+       "filterType\0"
+       "linearText\0"
+       "maskFilter\0"
+       "measureText\0"
+       "pathEffect\0"
+       "shader\0"
+       "strikeThru\0"
+       "stroke\0"
+       "strokeCap\0"
+       "strokeJoin\0"
+       "strokeMiter\0"
+       "strokeWidth\0"
+       "style\0"
+       "textAlign\0"
+       "textScaleX\0"
+       "textSize\0"
+       "textSkewX\0"
+       "textTracking\0"
+       "typeface\0"
+       "underline\0"
+       "xfermode"
+;
+
+static const SkMemberInfo gDrawPaintInfo[] = {
+       {0, 4, 26, 1},
+       {10, -1, 67, 98},
+       {17, 8, 31, 1},
+       {23, -2, 67, 98},
+       {31, 12, 47, 1},
+       {42, 16, 26, 1},
+       {53, 20, 62, 1},
+       {64, -1, 66, 98},
+       {76, 24, 76, 1},
+       {87, 28, 102, 1},
+       {94, 32, 26, 1},
+       {105, 36, 26, 1},
+       {112, 40, 27, 1},
+       {122, 44, 58, 1},
+       {133, 48, 98, 1},
+       {145, 52, 98, 1},
+       {157, 56, 109, 1},
+       {163, 60, 9, 1},
+       {173, 64, 98, 1},
+       {184, 68, 98, 1},
+       {193, 72, 98, 1},
+       {203, 76, 98, 1},
+       {216, 80, 120, 1},
+       {225, 84, 26, 1},
+       {235, 88, 121, 1}
+};
+
+static const char gPathStrings[] = 
+       "d\0"
+       "fillType\0"
+       "length"
+;
+
+static const SkMemberInfo gDrawPathInfo[] = {
+       {0, 32, 108, 1},
+       {2, -1, 67, 46},
+       {11, -2, 67, 98}
+};
+
+static const char gUnknown5Strings[] = 
+       "x\0"
+       "y\0"
+       "z"
+;
+
+static const SkMemberInfo gUnknown5Info[] = {
+       {0, 0, 98, 1},
+       {2, 4, 98, 1},
+       {4, 8, 98, 1}
+};
+
+static const char gPointStrings[] = 
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gDrawPointInfo[] = {
+       {0, 4, 98, 1},
+       {2, 8, 98, 1}
+};
+
+static const char gPolyToPolyStrings[] = 
+       "destination\0"
+       "source"
+;
+
+static const SkMemberInfo gPolyToPolyInfo[] = {
+       {0, 12, 80, 1},
+       {12, 8, 80, 1}
+};
+
+static const char gPolygonStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gPolygonInfo[] = {
+       {0, 47, 18, 1}
+};
+
+static const char gPolylineStrings[] = 
+       "points"
+;
+
+static const SkMemberInfo gPolylineInfo[] = {
+       {0, 56, 119, 98}
+};
+
+static const char gPostStrings[] = 
+       "delay\0"
+       "initialized\0"
+       "mode\0"
+       "sink\0"
+       "target\0"
+       "type"
+;
+
+static const SkMemberInfo gPostInfo[] = {
+       {0, 4, 71, 1},
+       {6, 8, 26, 1},
+       {18, 12, 45, 1},
+       {23, -1, 67, 108},
+       {28, -2, 67, 108},
+       {35, -3, 67, 108}
+};
+
+static const char gQuadToStrings[] = 
+       "x1\0"
+       "x2\0"
+       "y1\0"
+       "y2"
+;
+
+static const SkMemberInfo gQuadToInfo[] = {
+       {0, 8, 98, 1},
+       {3, 16, 98, 1},
+       {6, 12, 98, 1},
+       {9, 20, 98, 1}
+};
+
+static const char gRCubicToStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gRCubicToInfo[] = {
+       {0, 18, 18, 6}
+};
+
+static const char gRLineToStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gRLineToInfo[] = {
+       {0, 34, 18, 2}
+};
+
+static const char gRMoveToStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gRMoveToInfo[] = {
+       {0, 38, 18, 2}
+};
+
+static const char gRQuadToStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gRQuadToInfo[] = {
+       {0, 49, 18, 4}
+};
+
+static const char gRadialGradientStrings[] = 
+       "\0"
+       "center\0"
+       "radius"
+;
+
+static const SkMemberInfo gRadialGradientInfo[] = {
+       {0, 26, 18, 3},
+       {1, 48, 77, 2},
+       {8, 56, 98, 1}
+};
+
+static const char gRandomStrings[] = 
+       "blend\0"
+       "max\0"
+       "min\0"
+       "random\0"
+       "seed"
+;
+
+static const SkMemberInfo gDisplayRandomInfo[] = {
+       {0, 4, 98, 1},
+       {6, 12, 98, 1},
+       {10, 8, 98, 1},
+       {14, 1, 67, 98},
+       {21, -2, 67, 96}
+};
+
+static const char gRectToRectStrings[] = 
+       "destination\0"
+       "source"
+;
+
+static const SkMemberInfo gRectToRectInfo[] = {
+       {0, 12, 91, 1},
+       {12, 8, 91, 1}
+};
+
+static const char gRectangleStrings[] = 
+       "bottom\0"
+       "height\0"
+       "left\0"
+       "needsRedraw\0"
+       "right\0"
+       "top\0"
+       "width"
+;
+
+static const SkMemberInfo gRectangleInfo[] = {
+       {0, 24, 98, 1},
+       {7, -1, 67, 98},
+       {14, 12, 98, 1},
+       {19, -2, 67, 26},
+       {31, 20, 98, 1},
+       {37, 16, 98, 1},
+       {41, -3, 67, 98}
+};
+
+static const char gRemoveStrings[] = 
+       "offset\0"
+       "where"
+;
+
+static const SkMemberInfo gRemoveInfo[] = {
+       {0, 8, 96, 1},
+       {7, 16, 37, 1}
+};
+
+static const char gReplaceStrings[] = 
+       ""
+;
+
+static const SkMemberInfo gReplaceInfo[] = {
+       {0, 1, 18, 4}
+};
+
+static const char gRotateStrings[] = 
+       "center\0"
+       "degrees"
+;
+
+static const SkMemberInfo gRotateInfo[] = {
+       {0, 12, 77, 2},
+       {7, 8, 98, 1}
+};
+
+static const char gRoundRectStrings[] = 
+       "\0"
+       "rx\0"
+       "ry"
+;
+
+static const SkMemberInfo gRoundRectInfo[] = {
+       {0, 57, 18, 7},
+       {1, 32, 98, 1},
+       {4, 36, 98, 1}
+};
+
+static const char gS32Strings[] = 
+       "value"
+;
+
+static const SkMemberInfo gS32Info[] = {
+       {0, 4, 96, 1}
+};
+
+static const char gScalarStrings[] = 
+       "value"
+;
+
+static const SkMemberInfo gScalarInfo[] = {
+       {0, 4, 98, 1}
+};
+
+static const char gScaleStrings[] = 
+       "center\0"
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gScaleInfo[] = {
+       {0, 16, 77, 2},
+       {7, 8, 98, 1},
+       {9, 12, 98, 1}
+};
+
+static const char gSetStrings[] = 
+       "begin\0"
+       "dur\0"
+       "dynamic\0"
+       "field\0"
+       "formula\0"
+       "reset\0"
+       "target\0"
+       "to"
+;
+
+static const SkMemberInfo gSetInfo[] = {
+       {0, 4, 71, 1},
+       {6, 16, 71, 1},
+       {10, -1, 67, 26},
+       {18, 20, 108, 1},
+       {24, 24, 40, 1},
+       {32, -3, 67, 26},
+       {38, 36, 40, 1},
+       {45, 40, 40, 1}
+};
+
+static const char gShaderStrings[] = 
+       "matrix\0"
+       "tileMode"
+;
+
+static const SkMemberInfo gShaderInfo[] = {
+       {0, 8, 65, 1},
+       {7, 12, 116, 1}
+};
+
+static const char gSkewStrings[] = 
+       "center\0"
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gSkewInfo[] = {
+       {0, 16, 77, 2},
+       {7, 8, 98, 1},
+       {9, 12, 98, 1}
+};
+
+static const char g3D_CameraStrings[] = 
+       "axis\0"
+       "hackHeight\0"
+       "hackWidth\0"
+       "location\0"
+       "observer\0"
+       "patch\0"
+       "zenith"
+;
+
+static const SkMemberInfo g3D_CameraInfo[] = {
+       {0, 24, 106, 3},
+       {5, 8, 98, 1},
+       {16, 4, 98, 1},
+       {26, 12, 106, 3},
+       {35, 48, 106, 3},
+       {44, 96, 105, 1},
+       {50, 36, 106, 3}
+};
+
+static const char g3D_PatchStrings[] = 
+       "origin\0"
+       "rotateDegrees\0"
+       "u\0"
+       "v"
+;
+
+static const SkMemberInfo g3D_PatchInfo[] = {
+       {0, 28, 106, 3},
+       {7, -1, 66, 98},
+       {21, 4, 106, 3},
+       {23, 16, 106, 3}
+};
+
+static const char gUnknown6Strings[] = 
+       "x\0"
+       "y\0"
+       "z"
+;
+
+static const SkMemberInfo gUnknown6Info[] = {
+       {0, 0, 98, 1},
+       {2, 4, 98, 1},
+       {4, 8, 98, 1}
+};
+
+static const char gSnapshotStrings[] = 
+       "filename\0"
+       "quality\0"
+       "sequence\0"
+       "type"
+;
+
+static const SkMemberInfo gSnapshotInfo[] = {
+       {0, 4, 108, 1},
+       {9, 8, 98, 1},
+       {17, 12, 26, 1},
+       {26, 16, 20, 1}
+};
+
+static const char gStringStrings[] = 
+       "length\0"
+       "slice\0"
+       "value"
+;
+
+static const SkMemberInfo gStringInfo[] = {
+       {0, -1, 67, 96},
+       {7, -1, 66, 108},
+       {13, 4, 108, 1}
+};
+
+static const char gTextStrings[] = 
+       "length\0"
+       "text\0"
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gTextInfo[] = {
+       {0, -1, 67, 96},
+       {7, 12, 108, 1},
+       {12, 16, 98, 1},
+       {14, 20, 98, 1}
+};
+
+static const char gTextBoxStrings[] = 
+       "\0"
+       "mode\0"
+       "spacingAdd\0"
+       "spacingAlign\0"
+       "spacingMul\0"
+       "text"
+;
+
+static const SkMemberInfo gTextBoxInfo[] = {
+       {0, 57, 18, 7},
+       {1, 44, 113, 1},
+       {6, 40, 98, 1},
+       {17, 48, 112, 1},
+       {30, 36, 98, 1},
+       {41, 32, 108, 1}
+};
+
+static const char gTextOnPathStrings[] = 
+       "offset\0"
+       "path\0"
+       "text"
+;
+
+static const SkMemberInfo gTextOnPathInfo[] = {
+       {0, 12, 98, 1},
+       {7, 16, 74, 1},
+       {12, 20, 110, 1}
+};
+
+static const char gTextToPathStrings[] = 
+       "path\0"
+       "text"
+;
+
+static const SkMemberInfo gTextToPathInfo[] = {
+       {0, 4, 74, 1},
+       {5, 8, 110, 1}
+};
+
+static const char gTranslateStrings[] = 
+       "x\0"
+       "y"
+;
+
+static const SkMemberInfo gTranslateInfo[] = {
+       {0, 8, 98, 1},
+       {2, 12, 98, 1}
+};
+
+static const char gTypedArrayStrings[] = 
+       "length\0"
+       "values"
+;
+
+static const SkMemberInfo gTypedArrayInfo[] = {
+       {0, -1, 67, 96},
+       {7, 4, 119, 0}
+};
+
+static const char gTypefaceStrings[] = 
+       "fontName"
+;
+
+static const SkMemberInfo gTypefaceInfo[] = {
+       {0, 8, 108, 1}
+};
+
+static const SkMemberInfo* const gInfoTables[] = {
+       gMathInfo,
+       gAddInfo,
+       gAddCircleInfo,
+       gUnknown1Info,
+       gAddOvalInfo,
+       gAddPathInfo,
+       gAddRectangleInfo,
+       gAddRoundRectInfo,
+       gUnknown2Info,
+       gAnimateFieldInfo,
+       gApplyInfo,
+       gUnknown3Info,
+       gDrawBitmapInfo,
+       gDrawBitmapShaderInfo,
+       gDrawBlurInfo,
+       gDisplayBoundsInfo,
+       gDrawClipInfo,
+       gDrawColorInfo,
+       gCubicToInfo,
+       gDashInfo,
+       gDataInfo,
+       gDiscreteInfo,
+       gDrawToInfo,
+       gDrawEmbossInfo,
+       gDisplayEventInfo,
+       gFromPathInfo,
+       gUnknown4Info,
+       gGInfo,
+       gHitClearInfo,
+       gHitTestInfo,
+       gImageInfo,
+       gIncludeInfo,
+       gInputInfo,
+       gLineInfo,
+       gLineToInfo,
+       gLinearGradientInfo,
+       gDrawMatrixInfo,
+       gMoveInfo,
+       gMoveToInfo,
+       gMovieInfo,
+       gOvalInfo,
+       gDrawPaintInfo,
+       gDrawPathInfo,
+       gUnknown5Info,
+       gDrawPointInfo,
+       gPolyToPolyInfo,
+       gPolygonInfo,
+       gPolylineInfo,
+       gPostInfo,
+       gQuadToInfo,
+       gRCubicToInfo,
+       gRLineToInfo,
+       gRMoveToInfo,
+       gRQuadToInfo,
+       gRadialGradientInfo,
+       gDisplayRandomInfo,
+       gRectToRectInfo,
+       gRectangleInfo,
+       gRemoveInfo,
+       gReplaceInfo,
+       gRotateInfo,
+       gRoundRectInfo,
+       gS32Info,
+       gScalarInfo,
+       gScaleInfo,
+       gSetInfo,
+       gShaderInfo,
+       gSkewInfo,
+       g3D_CameraInfo,
+       g3D_PatchInfo,
+       gUnknown6Info,
+       gSnapshotInfo,
+       gStringInfo,
+       gTextInfo,
+       gTextBoxInfo,
+       gTextOnPathInfo,
+       gTextToPathInfo,
+       gTranslateInfo,
+       gTypedArrayInfo,
+       gTypefaceInfo,
+};
+
+static const unsigned char gInfoCounts[] = {
+       26,4,4,1,1,2,5,3,13,1,13,2,6,3,2,2,2,8,6,
+       2,2,2,2,4,8,3,3,2,1,4,3,1,3,4,2,2,12,1,2,
+       1,1,25,3,3,2,2,1,1,6,4,1,1,1,1,3,5,2,7,2,
+       1,2,3,1,1,3,8,2,3,7,4,3,4,3,4,6,3,2,2,2,
+       1
+};
+
+static const unsigned char gTypeIDs[] = {
+       1, // Math
+       2, // Add
+       3, // AddCircle
+       4, // Unknown1
+       5, // AddOval
+       6, // AddPath
+       7, // AddRectangle
+       8, // AddRoundRect
+       10, // Unknown2
+       11, // AnimateField
+       12, // Apply
+       17, // Unknown3
+       19, // Bitmap
+       22, // BitmapShader
+       23, // Blur
+       25, // Bounds
+       29, // Clip
+       31, // Color
+       32, // CubicTo
+       33, // Dash
+       34, // Data
+       35, // Discrete
+       38, // DrawTo
+       41, // Emboss
+       42, // Event
+       48, // FromPath
+       51, // Unknown4
+       52, // G
+       53, // HitClear
+       54, // HitTest
+       55, // Image
+       56, // Include
+       57, // Input
+       59, // Line
+       60, // LineTo
+       61, // LinearGradient
+       65, // Matrix
+       68, // Move
+       69, // MoveTo
+       70, // Movie
+       72, // Oval
+       73, // Paint
+       74, // Path
+       77, // Unknown5
+       78, // Point
+       79, // PolyToPoly
+       80, // Polygon
+       81, // Polyline
+       82, // Post
+       83, // QuadTo
+       84, // RCubicTo
+       85, // RLineTo
+       86, // RMoveTo
+       87, // RQuadTo
+       88, // RadialGradient
+       89, // Random
+       90, // RectToRect
+       91, // Rectangle
+       92, // Remove
+       93, // Replace
+       94, // Rotate
+       95, // RoundRect
+       96, // S32
+       98, // Scalar
+       99, // Scale
+       101, // Set
+       102, // Shader
+       103, // Skew
+       104, // 3D_Camera
+       105, // 3D_Patch
+       106, // Unknown6
+       107, // Snapshot
+       108, // String
+       110, // Text
+       111, // TextBox
+       114, // TextOnPath
+       115, // TextToPath
+       117, // Translate
+       119, // TypedArray
+       120, // Typeface
+       
+};
+
+static const int kTypeIDs = 80;
+
+static const char* const gInfoNames[] = {
+       gMathStrings,
+       gAddStrings,
+       gAddCircleStrings,
+       gUnknown1Strings,
+       gAddOvalStrings,
+       gAddPathStrings,
+       gAddRectangleStrings,
+       gAddRoundRectStrings,
+       gUnknown2Strings,
+       gAnimateFieldStrings,
+       gApplyStrings,
+       gUnknown3Strings,
+       gBitmapStrings,
+       gBitmapShaderStrings,
+       gBlurStrings,
+       gBoundsStrings,
+       gClipStrings,
+       gColorStrings,
+       gCubicToStrings,
+       gDashStrings,
+       gDataStrings,
+       gDiscreteStrings,
+       gDrawToStrings,
+       gEmbossStrings,
+       gEventStrings,
+       gFromPathStrings,
+       gUnknown4Strings,
+       gGStrings,
+       gHitClearStrings,
+       gHitTestStrings,
+       gImageStrings,
+       gIncludeStrings,
+       gInputStrings,
+       gLineStrings,
+       gLineToStrings,
+       gLinearGradientStrings,
+       gMatrixStrings,
+       gMoveStrings,
+       gMoveToStrings,
+       gMovieStrings,
+       gOvalStrings,
+       gPaintStrings,
+       gPathStrings,
+       gUnknown5Strings,
+       gPointStrings,
+       gPolyToPolyStrings,
+       gPolygonStrings,
+       gPolylineStrings,
+       gPostStrings,
+       gQuadToStrings,
+       gRCubicToStrings,
+       gRLineToStrings,
+       gRMoveToStrings,
+       gRQuadToStrings,
+       gRadialGradientStrings,
+       gRandomStrings,
+       gRectToRectStrings,
+       gRectangleStrings,
+       gRemoveStrings,
+       gReplaceStrings,
+       gRotateStrings,
+       gRoundRectStrings,
+       gS32Strings,
+       gScalarStrings,
+       gScaleStrings,
+       gSetStrings,
+       gShaderStrings,
+       gSkewStrings,
+       g3D_CameraStrings,
+       g3D_PatchStrings,
+       gUnknown6Strings,
+       gSnapshotStrings,
+       gStringStrings,
+       gTextStrings,
+       gTextBoxStrings,
+       gTextOnPathStrings,
+       gTextToPathStrings,
+       gTranslateStrings,
+       gTypedArrayStrings,
+       gTypefaceStrings
+};
+#endif
+#endif
+
diff --git a/libs/graphics/animator/SkDisplayAdd.cpp b/libs/graphics/animator/SkDisplayAdd.cpp
new file mode 100644 (file)
index 0000000..0264a5f
--- /dev/null
@@ -0,0 +1,237 @@
+#include "SkDisplayAdd.h"
+#include "SkAnimateMaker.h"
+#include "SkDisplayApply.h"
+#include "SkDisplayList.h"
+#include "SkDrawable.h"
+#include "SkDrawGroup.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkAdd::fInfo[] = {
+       SK_MEMBER(mode, AddMode),
+       SK_MEMBER(offset, Int),
+       SK_MEMBER(use, Drawable),
+       SK_MEMBER(where, Drawable)
+};
+
+#endif
+
+// start here;
+// add onEndElement to turn where string into f_Where
+// probably need new SkAnimateMaker::resolve flavor that takes
+// where="id", where="event-target" or not-specified
+// offset="#" (implements before, after, and index if no 'where')
+
+DEFINE_GET_MEMBER(SkAdd);
+
+SkAdd::SkAdd() : mode(kMode_indirect), 
+       offset(SK_MaxS32), use(nil), where(nil) {
+}
+
+SkDisplayable* SkAdd::deepCopy(SkAnimateMaker* maker) {
+       SkDrawable* saveUse = use;
+       SkDrawable* saveWhere = where;
+       use = nil;
+       where = nil;
+       SkAdd* copy = (SkAdd*) INHERITED::deepCopy(maker);
+       copy->use = use = saveUse;
+       copy->where = where = saveWhere;
+       return copy;
+}
+
+bool SkAdd::draw(SkAnimateMaker& maker) {
+       SkASSERT(use);
+       SkASSERT(use->isDrawable());
+       if (mode == kMode_indirect)
+               use->draw(maker);
+       return false;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkAdd::dump(SkAnimateMaker* maker) {
+       dumpBase(maker);
+    dumpAttrs(maker);
+    if (where)
+        SkDebugf("where=\"%s\" ", where->id);
+    if (mode == kMode_immediate)
+        SkDebugf("mode=\"immediate\" ");
+    SkDebugf(">\n");
+       SkDisplayList::fIndent += 4;
+       int save = SkDisplayList::fDumpIndex;
+    if (use)    //just in case
+        use->dump(maker);
+       SkDisplayList::fIndent -= 4;
+       SkDisplayList::fDumpIndex = save;
+    dumpEnd(maker);
+}
+#endif
+
+bool SkAdd::enable(SkAnimateMaker& maker ) {
+       SkDisplayTypes type = getType();
+       SkDisplayList& displayList = maker.fDisplayList;
+       SkTDDrawableArray* parentList = displayList.getDrawList();
+       if (type == SkType_Add) {
+               if (use == nil) // not set in apply yet
+                       return true;
+       }
+       bool skipAddToParent = true;
+       SkASSERT(type != SkType_Replace || where);
+       SkTDDrawableArray* grandList SK_INIT_TO_AVOID_WARNING;
+       SkGroup* parentGroup = nil;
+       SkGroup* thisGroup = nil;
+       int index = where ? displayList.findGroup(where, &parentList, &parentGroup,
+               &thisGroup, &grandList) : 0;
+       if (index < 0)
+               return true;
+       int max = parentList->count();
+       if (where == nil && type == SkType_Move)
+               index = max;
+       if (offset != SK_MaxS32) {
+               index += offset;
+               if (index > max) {
+                       maker.setErrorCode(SkDisplayXMLParserError::kIndexOutOfRange);
+                       return true;    // caller should not add
+               }
+       }
+       if (offset < 0 && where == nil)
+               index += max + 1;
+       switch (type) {
+               case SkType_Add:
+                       if (offset == SK_MaxS32 && where == nil) {
+                               if (use->isDrawable()) {
+                                       skipAddToParent = mode == kMode_immediate;
+                                       if (skipAddToParent) {
+                                               if (where == nil) {
+                                                       SkTDDrawableArray* useParentList;
+                                                       index = displayList.findGroup(this, &useParentList, &parentGroup,
+                                                               &thisGroup, &grandList);
+                                                       if (index >= 0) {
+                                                               parentGroup->markCopySize(index);
+                                                               parentGroup->markCopySet(index);
+                                                               useParentList->begin()[index] = use;
+                                                               break;
+                                                       }                                                               
+                                               }
+                                               *parentList->append() = use;
+                                       }
+                               }
+                               break;
+                       } else {
+                               if (thisGroup)
+                                       thisGroup->markCopySize(index);
+                               *parentList->insert(index) = use;
+                               if (thisGroup)
+                                       thisGroup->markCopySet(index);
+                               if (use->isApply())
+                                       ((SkApply*) use)->setEmbedded();
+                       }
+                       break;
+               case SkType_Move: {
+                       int priorLocation = parentList->find(use);
+                       if (priorLocation < 0)
+                               break;
+                       *parentList->insert(index) = use;
+                       if (index < priorLocation)
+                               priorLocation++;
+                       parentList->remove(priorLocation);
+                       } break;
+               case SkType_Remove: {
+                       SkDisplayable* old = (*parentList)[index];
+                       if (((SkRemove*)(this))->fDelete) {
+                               delete old;
+                               goto noHelperNeeded;
+                       }
+                       for (int inner = 0; inner < maker.fChildren.count(); inner++) {
+                               SkDisplayable* child = maker.fChildren[inner];
+                               if (child == old || child->contains(old))
+                                       goto noHelperNeeded;
+                       }
+                       if (maker.fHelpers.find(old) < 0)
+                               maker.helperAdd(old);
+noHelperNeeded:
+                       parentList->remove(index);
+                       } break;
+               case SkType_Replace:
+            if (thisGroup) {
+                thisGroup->markCopySize(index);
+                if (thisGroup->markedForDelete(index)) {
+                    SkDisplayable* old = (*parentList)[index];
+                    if (maker.fHelpers.find(old) < 0)
+                        maker.helperAdd(old);
+                }
+            }
+                       (*parentList)[index] = use;
+            if (thisGroup)
+                thisGroup->markCopySet(index);
+                       break;
+               default:
+                       SkASSERT(0);
+       }
+       if (type == SkType_Remove)
+               return true;
+       if (use->hasEnable())
+               use->enable(maker);
+       return skipAddToParent; // append if indirect: *parentList->append() = this;
+}
+
+bool SkAdd::hasEnable() const {
+       return true;
+}
+
+void SkAdd::initialize() {
+       if (use)
+               use->initialize();
+}
+
+bool SkAdd::isDrawable() const {
+       return getType() == SkType_Add && mode == kMode_indirect && offset == SK_MaxS32 &&
+               where == nil && use != nil && use->isDrawable();
+}
+
+//SkDisplayable* SkAdd::resolveTarget(SkAnimateMaker& maker) {
+//     return use;
+//}
+
+
+bool SkClear::enable(SkAnimateMaker& maker ) {
+       SkDisplayList& displayList = maker.fDisplayList;
+       displayList.clear();
+       return true;
+}
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkMove::fInfo[] = {
+       SK_MEMBER_INHERITED
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkMove);
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkRemove::fInfo[] = {
+       SK_MEMBER_ALIAS(delete, fDelete, Boolean),      // !!! experimental
+       SK_MEMBER(offset, Int),
+       SK_MEMBER(where, Drawable)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkRemove);
+
+SkRemove::SkRemove() : fDelete(false) {
+}
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkReplace::fInfo[] = {
+       SK_MEMBER_INHERITED
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkReplace);
+
diff --git a/libs/graphics/animator/SkDisplayAdd.h b/libs/graphics/animator/SkDisplayAdd.h
new file mode 100644 (file)
index 0000000..ed72730
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef SkDisplayAdd_DEFINED
+#define SkDisplayAdd_DEFINED
+
+#include "SkDrawable.h"
+#include "SkMemberInfo.h"
+
+class SkAdd : public SkDrawable {
+       DECLARE_MEMBER_INFO(Add);
+       SkAdd();
+       
+       enum Mode {
+               kMode_indirect,
+               kMode_immediate
+       };
+       
+       virtual SkDisplayable* deepCopy(SkAnimateMaker* );
+       virtual bool draw(SkAnimateMaker& );
+#ifdef SK_DUMP_ENABLED
+       virtual void dump(SkAnimateMaker* );
+#endif
+       virtual bool enable(SkAnimateMaker& );
+       virtual bool hasEnable() const;
+       virtual void initialize();
+       virtual bool isDrawable() const;
+protected:
+//     struct _A {
+               Mode mode;
+               S32 offset;
+               SkDrawable* use;
+               SkDrawable* where;      // if nil, offset becomes index
+//     } A;
+private:
+       typedef SkDrawable INHERITED;
+};
+
+class SkClear : public SkDisplayable {
+       virtual bool enable(SkAnimateMaker& );
+};
+
+class SkMove : public SkAdd {
+       DECLARE_MEMBER_INFO(Move);
+private:
+       typedef SkAdd INHERITED;
+};
+
+class SkRemove : public SkAdd {
+       DECLARE_MEMBER_INFO(Remove);
+       SkRemove();
+protected:
+       SkBool fDelete;
+private:
+       friend class SkAdd;
+       typedef SkAdd INHERITED;
+};
+
+class SkReplace : public SkAdd {
+       DECLARE_MEMBER_INFO(Replace);
+private:
+       typedef SkAdd INHERITED;
+};
+
+#endif // SkDisplayAdd_DEFINED
+
+
diff --git a/libs/graphics/animator/SkDisplayApply.cpp b/libs/graphics/animator/SkDisplayApply.cpp
new file mode 100644 (file)
index 0000000..af88631
--- /dev/null
@@ -0,0 +1,797 @@
+#include "SkDisplayApply.h"
+#include "SkAnimateActive.h"
+#include "SkAnimateMaker.h"
+#include "SkAnimateSet.h"
+#include "SkAnimatorScript.h"
+#include "SkDisplayType.h"
+#include "SkDrawGroup.h"
+#include "SkParse.h"
+#include "SkScript.h"
+#include "SkSystemEventTypes.h"
+#ifdef SK_DEBUG
+#include "SkTime.h"
+#endif
+#include <ctype.h>
+
+enum SkApply_Properties {
+       SK_PROPERTY(animator),
+       SK_PROPERTY(step),
+       SK_PROPERTY(steps),
+       SK_PROPERTY(time)
+};
+
+#if SK_USE_CONDENSED_INFO == 0
+
+// if no attibutes, enclosed displayable is both scope & target
+// only if both scope & target are specified, or if target and enclosed displayable, are scope and target different
+const SkMemberInfo SkApply::fInfo[] = {
+       SK_MEMBER_PROPERTY(animator, Animate),
+       SK_MEMBER(begin, MSec),
+       SK_MEMBER(dontDraw, Boolean),
+       SK_MEMBER(dynamicScope, String),
+       SK_MEMBER(interval, MSec),      // recommended redraw interval
+       SK_MEMBER(mode, ApplyMode),
+#if 0
+       SK_MEMBER(pickup, Boolean),
+#endif
+       SK_MEMBER(restore, Boolean),
+       SK_MEMBER(scope, Drawable),     // thing that scopes animation (unnamed enclosed displayable goes here)
+       SK_MEMBER_PROPERTY(step, Int),
+       SK_MEMBER_PROPERTY(steps, Int),
+       SK_MEMBER_PROPERTY(time, MSec),
+       SK_MEMBER(transition, ApplyTransition)
+};
+
+#endif 
+
+DEFINE_GET_MEMBER(SkApply);
+
+SkApply::SkApply() : begin(0), dontDraw(false), interval((SkMSec) -1), mode((Mode) -1), /*pickup(false), */
+       restore(false), scope(nil), steps(-1), transition((Transition) -1), fActive(nil), /*fCurrentScope(nil),*/
+       fLastTime(0), fAppended(false), fContainsScope(false), fDeleteScope(false), fEmbedded(false), 
+       fEnabled(false), fEnabling(false) {
+}
+
+SkApply::~SkApply() {
+       for (SkDrawable** curPtr = fScopes.begin(); curPtr < fScopes.end(); curPtr++)
+               delete *curPtr;
+       if (fDeleteScope)
+               delete scope;
+       // !!! caller must call maker.removeActive(fActive)
+       delete fActive;
+}
+
+void SkApply::activate(SkAnimateMaker& maker) {
+       if (fActive != nil) {
+               if (fActive->fDrawIndex == 0 && fActive->fDrawMax == 0)
+                       return; // if only one use, nothing more to do
+               if (restore == false)
+                       return; // all share same state, regardless of instance number
+               bool save = fActive->initializeSave();
+               fActive->fixInterpolator(save);
+       } else {
+               fActive = new SkActive(*this, maker);
+               fActive->init();
+               maker.appendActive(fActive);
+               if (restore) {
+                       fActive->initializeSave();
+                       int animators = fAnimators.count();
+                       for (int index = 0; index < animators; index++)
+                               fActive->saveInterpolatorValues(index);
+               }
+       }
+}
+
+void SkApply::append(SkApply* apply) {
+       if (fActive == nil)
+               return;
+       int oldCount = fActive->fAnimators.count();
+       fActive->append(apply);
+       if (restore) {
+               fActive->appendSave(oldCount);
+               int newCount = fActive->fAnimators.count();
+               for (int index = oldCount; index < newCount; index++)
+                       fActive->saveInterpolatorValues(index);
+       }
+}
+
+void SkApply::applyValues(int animatorIndex, SkOperand* values, int count,
+        SkDisplayTypes valuesType, SkMSec time) 
+{
+       SkAnimateBase* animator = fActive->fAnimators[animatorIndex];
+       const SkMemberInfo * info = animator->fFieldInfo;
+       SkASSERT(animator);
+       SkASSERT(info != nil);
+       SkDisplayTypes type = (SkDisplayTypes) info->fType;
+       SkDisplayable* target = getTarget(animator);
+       if (animator->hasExecute() || type == SkType_MemberFunction || type == SkType_MemberProperty) {
+               SkDisplayable* executor = animator->hasExecute() ? animator : target;
+               if (type != SkType_MemberProperty) {
+                       SkTDArray<SkScriptValue> typedValues;
+                       for (int index = 0; index < count; index++) {
+                               SkScriptValue temp;
+                               temp.fType = valuesType;
+                               temp.fOperand = values[index];
+                               *typedValues.append() = temp;
+                       }
+                       executor->executeFunction(target, info->functionIndex(), typedValues, info->getType(), nil);
+               } else {
+                       SkScriptValue scriptValue;
+                       scriptValue.fOperand = values[0];
+                       scriptValue.fType = info->getType();
+                       target->setProperty(info->propertyIndex(), scriptValue);
+               }
+       } else {
+               SkTypedArray converted;
+               if (type == SkType_ARGB) {
+                       if (count == 4) {
+                               // !!! assert that it is SkType_Float ?
+                               animator->packARGB(&values->fScalar, count, &converted);
+                               values = converted.begin();
+                               count = converted.count();
+                       } else
+                               SkASSERT(count == 1);
+               }
+//             SkASSERT(type == SkType_ARGB || type == SkType_String ||info->isSettable());
+               if (type == SkType_String || type == SkType_DynamicString)
+                       info->setString(target, values->fString);
+               else if (type == SkType_Drawable || type == SkType_Displayable)
+                       target->setReference(info, values->fDisplayable);
+               else
+                       info->setValue(target, values, count);
+       } 
+}
+
+bool SkApply::contains(SkDisplayable* child) {
+       for (SkDrawable** curPtr = fScopes.begin(); curPtr < fScopes.end(); curPtr++) {
+               if (*curPtr == child || (*curPtr)->contains(child))
+                       return true;
+       }
+       return fDeleteScope && scope == child;
+}
+
+SkDisplayable* SkApply::deepCopy(SkAnimateMaker* maker) {
+       SkDrawable* saveScope = scope;
+       scope = nil;
+       SkApply* result = (SkApply*) INHERITED::deepCopy(maker);
+       result->scope = scope = saveScope;
+       SkAnimateBase** end = fAnimators.end();
+       for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < end; animPtr++) {
+               SkAnimateBase* anim = (SkAnimateBase*) (*animPtr)->deepCopy(maker);
+               *result->fAnimators.append() = anim;
+               maker->helperAdd(anim);
+       }
+       return result;
+}
+
+void SkApply::disable() {
+       //!!! this is the right thing to do, but has bad side effects because of other problems
+       // currently, if an apply is in a g and scopes a statement in another g, it ends up as members
+       // of both containers. The disabling here incorrectly disables both instances
+       // maybe the fEnabled flag needs to be moved to the fActive data so that both 
+       // instances are not affected.
+//     fEnabled = false;
+}
+
+bool SkApply::draw(SkAnimateMaker& maker) {
+       if (scope ==nil)
+               return false;
+       if (scope->isApply() || scope->isDrawable() == false)
+               return false;
+       if (fEnabled == false)
+               enable(maker);
+       SkASSERT(scope);
+       activate(maker);
+       if (mode == kMode_immediate)
+               return fActive->draw();
+       bool result = interpolate(maker, maker.getInTime());
+       if (dontDraw == false) {
+//             if (scope->isDrawable())
+                       result |= scope->draw(maker);
+       }
+       if (restore) {
+               for (int index = 0; index < fActive->fAnimators.count(); index++)
+                       endSave(index);
+               fActive->advance();
+       }
+       return result;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkApply::dump(SkAnimateMaker* maker) {
+       dumpBase(maker);
+    if (dynamicScope.isEmpty() == false)
+        SkDebugf("dynamicScope=\"%s\" ", dynamicScope.c_str());
+    if (dontDraw)
+        SkDebugf("dontDraw=\"true\" ");
+    if (begin != 0) //perhaps we want this no matter what?
+        SkDebugf("begin=\"%g\" ", (float) begin/1000.0f);   //is this correct?
+    if (interval != (SkMSec) -1)
+        SkDebugf("interval=\"%g\" ", (float) interval/1000.0f);
+    if (steps != -1)
+        SkDebugf("steps=\"%d\" ", steps);
+    if (restore)
+        SkDebugf("restore=\"true\" ");
+    if (transition == kTransition_reverse)
+        SkDebugf("transition=\"reverse\" ");
+    if (mode == kMode_immediate) {
+        SkDebugf("mode=\"immediate\" ");
+    }
+    else if (mode == kMode_create) {
+        SkDebugf("mode=\"create\" ");
+    }
+    bool closedYet = false;
+       SkDisplayList::fIndent += 4;
+       int save = SkDisplayList::fDumpIndex;
+    if (scope) {
+        if (closedYet == false) {
+            SkDebugf(">\n");
+            closedYet = true;
+        }
+        scope->dump(maker);
+    }
+       int index;
+//     if (fActive) {
+               for (index = 0; index < fAnimators.count(); index++) {
+            if (closedYet == false) {
+                SkDebugf(">\n");
+                closedYet = true;
+            }
+                       SkAnimateBase* animator = fAnimators[index];
+                       animator->dump(maker);
+//             }
+       }
+       SkDisplayList::fIndent -= 4;
+       SkDisplayList::fDumpIndex = save;
+    if (closedYet)
+        dumpEnd(maker);
+    else
+        SkDebugf("/>\n");
+}
+#endif
+
+bool SkApply::enable(SkAnimateMaker& maker) {
+       fEnabled = true;
+       bool initialized = fActive != nil;
+       if (dynamicScope.size() > 0)
+               enableDynamic(maker);
+    if (maker.fError.hasError()) 
+        return false;
+       int animators = fAnimators.count();
+       int index;
+       for (index = 0; index < animators; index++) {
+               SkAnimateBase* animator = fAnimators[index];
+               animator->fStart = maker.fEnableTime;
+               animator->fResetPending = animator->fReset;
+       }
+       if (scope && scope->isApply())
+               ((SkApply*) scope)->setEmbedded();
+/*     if (mode == kMode_once) {
+               if (scope) {
+                       activate(maker);
+                       interpolate(maker, maker.fEnableTime);
+                       inactivate(maker);
+               }
+               return true;
+       }*/
+       if ((mode == kMode_immediate || mode == kMode_create) && scope == nil)
+               return false;   // !!! error?
+       bool enableMe = scope && (scope->hasEnable() || scope->isApply() || scope->isDrawable() == false);
+       if (mode == kMode_immediate && enableMe || mode == kMode_create)
+               activate(maker);        // for non-drawables like post, prime them here
+       if (mode == kMode_immediate && enableMe)
+               fActive->enable();
+       if (mode == kMode_create && scope != nil) {
+               enableCreate(maker);
+               return true;
+       }
+       if (mode == kMode_immediate) {
+               return scope->isApply() || scope->isDrawable() == false;
+       }
+       refresh(maker);
+       SkDisplayList& displayList = maker.fDisplayList;
+       SkDrawable* drawable;
+#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
+       SkString debugOut;
+       SkMSec time = maker.getAppTime();
+       debugOut.appendS32(time - maker.fDebugTimeBase);
+       debugOut.append(" apply enable id=");
+       debugOut.append(_id);
+       debugOut.append("; start=");
+       debugOut.appendS32(maker.fEnableTime - maker.fDebugTimeBase);
+       SkDebugf("%s\n", debugOut.c_str());
+#endif
+       if (scope == nil || scope->isApply() || scope->getType() == SkType_Movie || scope->isDrawable() == false) {
+               activate(maker);        // for non-drawables like post, prime them here
+               if (initialized) {
+                       append(this);
+               }
+               fEnabling = true;
+               interpolate(maker, maker.fEnableTime);
+               fEnabling = false;
+               if (scope != nil && dontDraw == false)
+                       scope->enable(maker);
+               return true;
+       } else if (initialized && restore == false)
+               append(this);
+#if 0
+       bool wasActive = inactivate(maker); // start fresh
+       if (wasActive) {
+               activate(maker);
+               interpolate(maker, maker.fEnableTime);
+               return true;
+       }
+#endif
+//     start here;
+       // now that one apply might embed another, only the parent apply should replace the scope 
+       // or get appended to the display list
+       // similarly, an apply added by an add immediate has already been located in the display list
+       // and should not get moved or added again here
+       if (fEmbedded) {
+               return false;   // already added to display list by embedder
+       }
+       drawable = (SkDrawable*) scope;
+       SkTDDrawableArray* parentList;
+       SkTDDrawableArray* grandList;
+       SkGroup* parentGroup;
+       SkGroup* thisGroup;
+       int old = displayList.findGroup(drawable, &parentList, &parentGroup, &thisGroup, &grandList);
+       if (old < 0)
+               goto append;
+       else if (fContainsScope) {
+               if ((*parentList)[old] != this || restore == true) {
+append:
+                       if (parentGroup)
+                               parentGroup->markCopySize(old);
+                       if (parentList->count() < 10000) {
+                               fAppended = true;
+                               *parentList->append() = this;
+                       } else
+                               maker.setErrorCode(SkDisplayXMLParserError::kDisplayTreeTooDeep);
+                       old = -1;
+               } else
+                       reset();
+       } else {
+               SkASSERT(old < parentList->count());
+               if ((*parentList)[old]->isApply()) {
+                       SkApply* apply = (SkApply*) (*parentList)[old];
+                       if (apply != this && apply->fActive == nil)
+                               apply->activate(maker);
+                       apply->append(this);
+                       parentGroup = nil;
+               } else {
+                       if (parentGroup)
+                               parentGroup->markCopySize(old);
+                       SkDrawable** newApplyLocation = &(*parentList)[old];
+                       SkGroup* pGroup;
+                       int oldApply = displayList.findGroup(this, &parentList, &pGroup, &thisGroup, &grandList);
+                       if (oldApply >= 0) {
+                               (*parentList)[oldApply] = (SkDrawable*) SkDisplayType::CreateInstance(&maker, SkType_Apply);
+                               parentGroup = nil;
+                               fDeleteScope = true;
+                       }
+                       *newApplyLocation = this;
+               }
+       }
+       if (parentGroup) {
+               parentGroup->markCopySet(old);
+               fDeleteScope = dynamicScope.size() == 0;
+       }
+       return true;
+}
+
+void SkApply::enableCreate(SkAnimateMaker& maker) {
+       SkString newID;
+       for (int step = 0; step <= steps; step++) {
+               fLastTime = step * SK_MSec1;
+               bool success = maker.computeID(scope, this, &newID);
+               if (success == false)
+                       return;
+               if (maker.find(newID.c_str(), nil))
+                       continue;
+               SkApply* copy = (SkApply*) deepCopy(&maker); // work on copy of animator state
+               if (mode == kMode_create)
+                       copy->mode = (Mode) -1;
+               SkDrawable* copyScope = copy->scope = (SkDrawable*) scope->deepCopy(&maker);
+               *fScopes.append() = copyScope;
+               if (copyScope->resolveIDs(maker, scope, this)) {
+                       step = steps; // quit
+                       goto next; // resolveIDs failed
+               }
+               if (newID.size() > 0) 
+                       maker.setID(copyScope, newID);
+               if (copy->resolveIDs(maker, this, this)) { // fix up all fields, including target
+                       step = steps; // quit
+                       goto next; // resolveIDs failed
+               }
+               copy->activate(maker);
+               copy->interpolate(maker, step * SK_MSec1);
+               maker.removeActive(copy->fActive);
+       next:
+               delete copy;
+       }
+}
+
+void SkApply::enableDynamic(SkAnimateMaker& maker) {
+       SkASSERT(mode != kMode_create); // create + dynamic are not currently compatible
+       SkDisplayable* newScope;
+       bool success = SkAnimatorScript::EvaluateDisplayable(maker, this, dynamicScope.c_str(),
+               &newScope);
+       if (success && scope != newScope) {
+               SkTDDrawableArray* pList, * gList;
+               SkGroup* pGroup = nil, * found = nil;
+               int old = maker.fDisplayList.findGroup(scope, &pList, &pGroup, &found, &gList);
+               if (pList && old >= 0 && (*pList)[old]->isApply() && (*pList)[old] != this) {
+                       if (fAppended == false) {
+                               if (found != nil) {
+                                       SkDisplayable* oldChild = (*pList)[old];
+                                       if (oldChild->isApply() && found->copySet(old)) {
+                                               found->markCopyClear(old);
+       //                                      delete oldChild;
+                                       }
+                               }
+                               (*pList)[old] = scope;
+                       } else
+                               pList->remove(old);
+               }
+               scope = (SkDrawable*) newScope;
+               onEndElement(maker);
+       }
+       maker.removeActive(fActive);
+       delete fActive;
+       fActive = nil;
+}
+
+void SkApply::endSave(int index) {
+       SkAnimateBase* animate = fActive->fAnimators[index];
+       const SkMemberInfo* info = animate->fFieldInfo;
+       SkDisplayTypes type = (SkDisplayTypes) info->fType;
+       if (type == SkType_MemberFunction)
+               return;
+       SkDisplayable* target = getTarget(animate);
+       size_t size = info->getSize(target);
+       int count = (int) (size / sizeof(SkScalar));
+       int activeIndex = fActive->fDrawIndex + index;
+       SkOperand* last = new SkOperand[count];
+       SkAutoTDelete<SkOperand> autoLast(last);
+       if (type != SkType_MemberProperty) {
+               info->getValue(target, last, count);
+               SkOperand* saveOperand = fActive->fSaveRestore[activeIndex];
+               if (saveOperand)
+                       info->setValue(target, fActive->fSaveRestore[activeIndex], count);
+       } else {
+               SkScriptValue scriptValue;
+               bool success = target->getProperty(info->propertyIndex(), &scriptValue);
+               SkASSERT(success = true);
+               last[0] = scriptValue.fOperand;
+               scriptValue.fOperand = fActive->fSaveRestore[activeIndex][0];
+               target->setProperty(info->propertyIndex(), scriptValue);
+       }
+       SkOperand* save = fActive->fSaveRestore[activeIndex];
+       if (save)
+               memcpy(save, last, count * sizeof(SkOperand));
+}
+
+bool SkApply::getProperty(int index, SkScriptValue* value) const {
+       switch (index) {
+               case SK_PROPERTY(step):
+                       value->fType = SkType_Int;
+                       value->fOperand.fS32 = fLastTime / SK_MSec1;
+                       break;
+               case SK_PROPERTY(steps):
+                       value->fType = SkType_Int;
+                       value->fOperand.fS32 = steps;
+                       break;
+               case SK_PROPERTY(time):
+                       value->fType = SkType_MSec;
+                       value->fOperand.fS32 = fLastTime;
+                       break;
+               default:
+       //              SkASSERT(0);
+                       return false;
+       }
+       return true;
+}
+
+void SkApply::getStep(SkScriptValue* value) {
+       getProperty(SK_PROPERTY(step), value);
+}
+
+SkDrawable* SkApply::getTarget(SkAnimateBase* animate) {
+       if (animate->fTargetIsScope == false || mode != kMode_create)
+               return animate->fTarget;
+       return scope;
+}
+
+bool SkApply::hasDelayedAnimator() const {
+       SkAnimateBase** animEnd = fAnimators.end();
+       for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < animEnd; animPtr++) {
+               SkAnimateBase* animator = *animPtr;
+               if (animator->fDelayed) 
+                       return true;
+       }
+       return false;
+}
+
+bool SkApply::hasEnable() const {
+       return true;
+}
+
+bool SkApply::inactivate(SkAnimateMaker& maker) {
+       if (fActive == nil)
+               return false;
+       maker.removeActive(fActive);
+       delete fActive;
+       fActive = nil;
+       return true;
+}
+
+#ifdef SK_DEBUG
+SkMSec lastTime = (SkMSec) -1;
+#endif
+
+bool SkApply::interpolate(SkAnimateMaker& maker, SkMSec rawTime) {
+       if (fActive == nil)
+               return false;
+       bool result = false;
+#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
+       SkMSec time = maker.getAppTime();
+       if (lastTime == (SkMSec) -1)
+               lastTime = rawTime - 1;
+       if (fActive != nil && 
+               strcmp(id, "a3") == 0 && rawTime > lastTime) {
+               lastTime += 1000;
+               SkString debugOut;
+               debugOut.appendS32(time - maker.fDebugTimeBase);
+               debugOut.append(" apply id=");
+               debugOut.append(_id);
+               debugOut.append("; ");
+               debugOut.append(fActive->fAnimators[0]->_id);
+               debugOut.append("=");
+               debugOut.appendS32(rawTime - fActive->fState[0].fStartTime);
+               debugOut.append(")");
+               SkDebugf("%s\n", debugOut.c_str());
+       }
+#endif
+       fActive->start();
+       if (restore)
+               fActive->initializeSave();
+       int animators = fActive->fAnimators.count();
+       for (int inner = 0; inner < animators; inner++) {
+               SkAnimateBase* animate = fActive->fAnimators[inner];
+               if (animate->fChanged) {
+                       animate->fChanged = false;
+                       animate->fStart = rawTime;
+       //              SkTypedArray values;
+       //              int count = animate->fValues.count();
+       //              values.setCount(count);
+       //              memcpy(values.begin(), animate->fValues.begin(), sizeof(SkOperand) * count);
+                       animate->onEndElement(maker);
+       //              if (memcmp(values.begin(), animate->fValues.begin(), sizeof(SkOperand) * count) != 0) {
+                               fActive->append(this);
+                               fActive->start();
+       //              }
+               }
+               SkMSec time = fActive->getTime(rawTime, inner);
+               SkActive::SkState& state = fActive->fState[inner];
+               if (SkMSec_LT(rawTime, state.fStartTime)) {
+                       if (fEnabling) {
+                               animate->fDelayed = true;
+                               maker.delayEnable(this, state.fStartTime);
+                       }
+                       continue;
+               } else
+                       animate->fDelayed = false;
+               SkMSec innerTime = fLastTime = state.getRelativeTime(time);
+               if (restore) 
+                       fActive->restoreInterpolatorValues(inner);
+               if (animate->fReset) {
+                       if (transition != SkApply::kTransition_reverse) {
+                               if (SkMSec_LT(state.fBegin + state.fDuration, innerTime)) {
+                                       if (animate->fResetPending) {
+                                               innerTime = 0;
+                                               animate->fResetPending = false;
+                                       } else
+                                               continue;
+                               }
+                       } else if (innerTime == 0) {
+                                       if (animate->fResetPending) {
+                                               innerTime = state.fBegin + state.fDuration;
+                                               animate->fResetPending = false;
+                                       } else
+                                               continue;
+                       }
+               }
+               int count = animate->components();
+               SkAutoSTMalloc<16, SkOperand> values(count);
+               SkInterpolatorBase::Result interpResult = fActive->fInterpolators[inner]->timeToValues(
+                       innerTime, values.get());
+               result |= (interpResult != SkInterpolatorBase::kFreezeEnd_Result);
+               if ((transition != SkApply::kTransition_reverse && interpResult == SkInterpolatorBase::kFreezeEnd_Result ||
+                               transition == SkApply::kTransition_reverse && fLastTime == 0) && state.fUnpostedEndEvent) {
+//                     SkDEBUGF(("interpolate: post on end\n"));
+                       state.fUnpostedEndEvent = false;
+                       maker.postOnEnd(animate, state.fBegin + state.fDuration);
+                       maker.fAdjustedStart = 0;        // !!! left over from synchronizing animation days, undoubtably out of date (and broken)
+               }
+               if (animate->formula.size() > 0) {
+                       if (fLastTime > animate->dur)
+                               fLastTime = animate->dur;
+                       SkTypedArray formulaValues;
+                       formulaValues.setCount(count);
+                       bool success = animate->fFieldInfo->setValue(maker, &formulaValues, 0, 0, nil, 
+                               animate->getValuesType(), animate->formula);
+                       SkASSERT(success);
+                       if (restore)
+                               save(inner); // save existing value
+                       applyValues(inner, formulaValues.begin(), count, animate->getValuesType(), innerTime);
+               } else {
+                       if (restore)
+                               save(inner); // save existing value
+                       applyValues(inner, values.get(), count, animate->getValuesType(), innerTime);
+               }
+       }
+       return result;
+}
+
+void SkApply::initialize() {
+       if (scope == nil)
+               return;
+       if (scope->isApply() || scope->isDrawable() == false)
+               return;
+       scope->initialize();
+}
+
+void SkApply::onEndElement(SkAnimateMaker& maker) 
+{
+    SkDrawable* scopePtr = scope;
+    while (scopePtr && scopePtr->isApply()) {
+        SkApply* scopedApply = (SkApply*) scopePtr;
+        if (scopedApply->scope == this) {
+            maker.setErrorCode(SkDisplayXMLParserError::kApplyScopesItself);
+            return;
+        }
+        scopePtr = scopedApply->scope;
+    }
+       if (mode == kMode_create)
+               return;
+       if (scope != nil && steps >= 0 && scope->isApply() == false && scope->isDrawable())
+               scope->setSteps(steps);
+       for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < fAnimators.end(); animPtr++) {
+               SkAnimateBase* anim = *animPtr;
+        //for reusing apply statements with dynamic scope
+               if (anim->fTarget == nil || anim->fTargetIsScope) {
+                       anim->fTargetIsScope = true;
+                       if (scope)
+                               anim->fTarget = scope;
+                       else
+                               anim->setTarget(maker);
+                       anim->onEndElement(maker);      // allows animate->fFieldInfo to be set
+               }
+               if (scope != nil && steps >= 0 && anim->fTarget != scope && anim->fTarget->isDrawable())
+                       anim->fTarget->setSteps(steps);
+       }
+}
+
+const SkMemberInfo* SkApply::preferredChild(SkDisplayTypes type) {
+       SkASSERT(SkDisplayType::IsAnimate(type) == false);
+       fContainsScope = true;
+       return getMember("scope"); // !!! cwap! need to refer to member through enum like kScope instead
+}
+
+void SkApply::refresh(SkAnimateMaker& maker) {
+       for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < fAnimators.end(); animPtr++) {
+               SkAnimateBase* animate = *animPtr;
+               animate->onEndElement(maker);
+       }
+       if (fActive)
+               fActive->resetInterpolators();
+}
+
+void SkApply::reset() {
+       if (fActive)
+               fActive->resetState();
+}
+
+bool SkApply::resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* apply) { //  replace to/formula strings in animators of the form xxx.step with the step value, if xxx.step is in scope
+       if (resolveField(maker, apply, &dynamicScope) == false)
+               return true;    // failed
+       SkAnimateBase** endPtr = fAnimators.end();
+       SkAnimateBase** origPtr = ((SkApply*) original)->fAnimators.begin();
+       for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < endPtr; ) {
+               SkAnimateBase* animator = *animPtr++;
+               maker.resolveID(animator, *origPtr++);
+               if (resolveField(maker, this, &animator->target) == false)
+                       return true;
+               if (resolveField(maker, this, &animator->from) == false)
+                       return true;
+               if (resolveField(maker, this, &animator->to) == false)
+                       return true;
+               if (resolveField(maker, this, &animator->formula) == false)
+                       return true;
+       }
+//     setEmbedded();
+       onEndElement(maker);
+       return false; // succeeded
+}
+
+bool SkApply::resolveField(SkAnimateMaker& maker, SkDisplayable* parent, SkString* str) {
+       const char* script = str->c_str();
+       if (str->startsWith("#string:") == false)
+               return true;
+       script += sizeof("#string:") - 1;
+       return SkAnimatorScript::EvaluateString(maker, this, parent, script, str);
+}
+
+void SkApply::save(int index) {
+       SkAnimateBase* animate = fActive->fAnimators[index];
+       const SkMemberInfo * info = animate->fFieldInfo;
+       SkDisplayable* target = getTarget(animate);
+//     if (animate->hasExecute())
+//             info = animate->getResolvedInfo();
+       SkDisplayTypes type = (SkDisplayTypes) info->fType;
+       if (type == SkType_MemberFunction)
+               return; // nothing to save
+       size_t size = info->getSize(target);
+       int count = (int) (size / sizeof(SkScalar));
+       bool useLast = true;
+// !!! this all may be unneeded, at least in the dynamic case ??
+       int activeIndex = fActive->fDrawIndex + index;
+       SkTDOperandArray last;
+       if (fActive->fSaveRestore[activeIndex] == nil) {
+               fActive->fSaveRestore[activeIndex] = new SkOperand[count];
+               useLast = false;
+       } else {
+               last.setCount(count);
+               memcpy(last.begin(), fActive->fSaveRestore[activeIndex], count * sizeof(SkOperand));
+       }
+       if (type != SkType_MemberProperty) {
+               info->getValue(target, fActive->fSaveRestore[activeIndex], count);
+               if (useLast)
+                       info->setValue(target, last.begin(), count);
+       } else {
+               SkScriptValue scriptValue;
+               bool success = target->getProperty(info->propertyIndex(), &scriptValue);
+               SkASSERT(success == true);
+               SkASSERT(scriptValue.fType == SkType_Float);
+               fActive->fSaveRestore[activeIndex][0] = scriptValue.fOperand;
+               if (useLast) {
+                       SkScriptValue scriptValue;
+                       scriptValue.fType = type;
+                       scriptValue.fOperand = last[0];
+                       target->setProperty(info->propertyIndex(), scriptValue);
+               }
+       }
+// !!!  end of unneeded
+}
+
+bool SkApply::setProperty(int index, SkScriptValue& scriptValue) {
+       switch (index) {
+               case SK_PROPERTY(animator): {
+                       SkAnimateBase* animate = (SkAnimateBase*) scriptValue.fOperand.fDisplayable;
+                       SkASSERT(animate->isAnimate());
+                       *fAnimators.append() = animate;
+                       return true; 
+               }
+               case SK_PROPERTY(steps):
+                       steps = scriptValue.fOperand.fS32;
+                       if (fActive)
+                               fActive->setSteps(steps);
+                       return true;
+       }
+       return false;
+}
+
+void SkApply::setSteps(int _steps) { 
+       steps = _steps; 
+}
+
+#ifdef SK_DEBUG
+void SkApply::validate() {
+       if (fActive)
+               fActive->validate();
+}
+#endif
+
+
+
diff --git a/libs/graphics/animator/SkDisplayApply.h b/libs/graphics/animator/SkDisplayApply.h
new file mode 100644 (file)
index 0000000..883323a
--- /dev/null
@@ -0,0 +1,99 @@
+#ifndef SkDisplayApply_DEFINED
+#define SkDisplayApply_DEFINED
+
+#include "SkAnimateBase.h"
+#include "SkDrawable.h"
+#include "SkIntArray.h"
+
+class SkActive;
+
+class SkApply : public SkDrawable {
+       DECLARE_MEMBER_INFO(Apply);
+public:
+
+       SkApply();
+       virtual ~SkApply();
+
+       enum Transition {
+               kTransition_normal,
+               kTransition_reverse
+       };
+       
+       enum Mode {
+               kMode_create,
+               kMode_immediate,
+               //kMode_once
+       };
+       void activate(SkAnimateMaker& );
+       void append(SkApply* apply);
+       void appendActive(SkActive* );
+       void applyValues(int animatorIndex, SkOperand* values, int count,
+               SkDisplayTypes , SkMSec time);
+       virtual bool contains(SkDisplayable*);
+//     void createActive(SkAnimateMaker& );
+       virtual SkDisplayable* deepCopy(SkAnimateMaker* );
+       void disable();
+       virtual bool draw(SkAnimateMaker& );
+#ifdef SK_DUMP_ENABLED
+       virtual void dump(SkAnimateMaker* );
+#endif
+       virtual bool enable(SkAnimateMaker& );
+       void enableCreate(SkAnimateMaker& );
+       void enableDynamic(SkAnimateMaker& );
+       void endSave(int index);
+       Mode getMode() { return mode; }
+       virtual bool getProperty(int index, SkScriptValue* value) const;
+       SkDrawable* getScope() { return scope; }
+       void getStep(SkScriptValue* );
+       SkDrawable* getTarget(SkAnimateBase* );
+       bool hasDelayedAnimator() const;
+       virtual bool hasEnable() const;
+       bool inactivate(SkAnimateMaker& maker);
+       virtual void initialize(); 
+       bool interpolate(SkAnimateMaker& , SkMSec time);
+       virtual void onEndElement(SkAnimateMaker& );
+       virtual const SkMemberInfo* preferredChild(SkDisplayTypes type);
+       void refresh(SkAnimateMaker& );
+       void reset();
+       virtual bool resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* );
+       bool resolveField(SkAnimateMaker& , SkDisplayable* parent, SkString* str);
+       void save(int index);
+       void setEmbedded() { fEmbedded = true; }
+       virtual bool setProperty(int index, SkScriptValue& );
+       virtual void setSteps(int _steps);
+//     virtual void setTime(SkMSec time);
+#ifdef SK_DEBUG
+       virtual void validate();
+#endif
+private:
+       SkMSec begin;
+       SkBool dontDraw;
+       SkString dynamicScope;
+       SkMSec interval;
+       Mode mode;
+#if 0
+       SkBool pickup;
+#endif
+       SkBool restore;
+       SkDrawable* scope;
+       S32 steps;
+       Transition transition;
+       SkActive* fActive;
+       SkTDAnimateArray fAnimators;
+//     SkDrawable* fCurrentScope;
+       SkMSec fLastTime;       // used only to return script property time
+       SkTDDrawableArray fScopes;
+       SkBool fAppended : 1;
+       SkBool fContainsScope : 1;
+       SkBool fDeleteScope : 1;
+       SkBool fEmbedded : 1;
+       SkBool fEnabled : 1;
+       SkBool fEnabling : 1; // set if calling interpolate from enable
+       friend class SkActive;
+       friend class SkDisplayList;
+       typedef SkDrawable INHERITED;
+};
+
+#endif // SkDisplayApply_DEFINED
+
+
diff --git a/libs/graphics/animator/SkDisplayBounds.cpp b/libs/graphics/animator/SkDisplayBounds.cpp
new file mode 100644 (file)
index 0000000..e6abcc3
--- /dev/null
@@ -0,0 +1,37 @@
+#include "SkDisplayBounds.h"
+#include "SkAnimateMaker.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDisplayBounds::fInfo[] = {
+       SK_MEMBER_INHERITED,
+       SK_MEMBER(inval, Boolean)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDisplayBounds);
+
+SkDisplayBounds::SkDisplayBounds() : inval(false) {
+}
+
+bool SkDisplayBounds::draw(SkAnimateMaker& maker) {
+       maker.fDisplayList.fUnionBounds = SkToBool(inval);
+       maker.fDisplayList.fDrawBounds = false;
+       fBounds.setEmpty();
+       bool result = INHERITED::draw(maker);
+       maker.fDisplayList.fUnionBounds = false;
+       maker.fDisplayList.fDrawBounds = true;
+       if (inval && fBounds.isEmpty() == false) {
+               SkRect16& rect = maker.fDisplayList.fInvalBounds;
+               maker.fDisplayList.fHasUnion = true;
+               if (rect.isEmpty())
+                       rect = fBounds;
+               else 
+                       rect.join(fBounds);
+       }
+       return result;
+}
+
+
+
diff --git a/libs/graphics/animator/SkDisplayBounds.h b/libs/graphics/animator/SkDisplayBounds.h
new file mode 100644 (file)
index 0000000..077d4cc
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef SkDisplayBounds_DEFINED
+#define SkDisplayBounds_DEFINED
+
+#include "SkDrawRectangle.h"
+
+class SkDisplayBounds : public SkDrawRect {
+       DECLARE_DISPLAY_MEMBER_INFO(Bounds);
+       SkDisplayBounds();
+       virtual bool draw(SkAnimateMaker& );
+private:
+       SkBool inval;
+       typedef SkDrawRect INHERITED;
+};
+
+#endif // SkDisplayBounds_DEFINED
+
diff --git a/libs/graphics/animator/SkDisplayEvent.cpp b/libs/graphics/animator/SkDisplayEvent.cpp
new file mode 100644 (file)
index 0000000..46af81c
--- /dev/null
@@ -0,0 +1,248 @@
+#include "SkDisplayEvent.h"
+#include "SkAnimateMaker.h"
+#include "SkDisplayApply.h"
+#include "SkDisplayInput.h"
+#include "SkDisplayList.h"
+#ifdef SK_DEBUG
+#include "SkDump.h"
+#endif
+#include "SkEvent.h"
+#include "SkDisplayInput.h"
+#include "SkKey.h"
+#include "SkMetaData.h"
+#include "SkScript.h"
+#include "SkUtils.h"
+
+enum SkDisplayEvent_Properties {
+       SK_PROPERTY(key),
+       SK_PROPERTY(keys)
+};
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDisplayEvent::fInfo[] = {
+       SK_MEMBER(code, EventCode),
+       SK_MEMBER(disable, Boolean),
+       SK_MEMBER_PROPERTY(key, String), // a single key (also last key pressed)
+       SK_MEMBER_PROPERTY(keys, String), // a single key or dash-delimited range of keys
+       SK_MEMBER(kind, EventKind),
+       SK_MEMBER(target, String),
+       SK_MEMBER(x, Float),
+       SK_MEMBER(y, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDisplayEvent);
+
+SkDisplayEvent::SkDisplayEvent() : code((SkKey) -1), disable(false),
+       kind(kUser), x(0), y(0), fLastCode((SkKey) -1), fMax((SkKey) -1), fTarget(nil) {
+}
+
+SkDisplayEvent::~SkDisplayEvent() {
+       deleteMembers();
+}
+
+bool SkDisplayEvent::add(SkAnimateMaker& , SkDisplayable* child) { 
+       *fChildren.append() = child; 
+       return true; 
+}
+
+bool SkDisplayEvent::contains(SkDisplayable* match) {
+       for (int index = 0; index < fChildren.count(); index++) {
+               if (fChildren[index] == match || fChildren[index]->contains(match))
+                       return true;
+       }
+       return false;
+}
+
+SkDisplayable* SkDisplayEvent::contains(const SkString& match) {
+       for (int index = 0; index < fChildren.count(); index++) {
+               SkDisplayable* child = fChildren[index];
+               if (child->contains(match))
+                       return child;
+       }
+       return nil;
+}
+
+void SkDisplayEvent::deleteMembers() {
+       for (int index = 0; index < fChildren.count(); index++) {
+               SkDisplayable* evt = fChildren[index];
+               delete evt;
+       }
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkDisplayEvent::dumpEvent(SkAnimateMaker* maker) {
+    dumpBase(maker);
+    SkString str;
+    SkDump::GetEnumString(SkType_EventKind, kind, &str);
+    SkDebugf("kind=\"%s\" ", str.c_str());
+    if (kind == SkDisplayEvent::kKeyPress || kind == SkDisplayEvent::kKeyPressUp) {
+        if (code >= 0)
+            SkDump::GetEnumString(SkType_EventCode, code, &str);
+        else
+            str.set("none");
+        SkDebugf("code=\"%s\" ", str.c_str());
+    }
+    if (kind == SkDisplayEvent::kKeyChar) {
+        if (fMax != (SkKey) -1 && fMax != code)
+            SkDebugf("keys=\"%c - %c\" ", code, fMax);
+        else
+            SkDebugf("key=\"%c\" ", code);
+    }
+    if (fTarget != nil) {
+        SkDebugf("target=\"%s\" ", fTarget->id);
+    }
+    if (kind >= SkDisplayEvent::kMouseDown && kind <= SkDisplayEvent::kMouseUp) {
+#ifdef SK_CAN_USE_FLOAT
+        SkDebugf("x=\"%g\" y=\"%g\" ", SkScalarToFloat(x), SkScalarToFloat(y));
+#else
+        SkDebugf("x=\"%x\" y=\"%x\" ", x, y);
+#endif
+    }
+    if (disable)
+        SkDebugf("disable=\"true\" ");
+    SkDebugf("/>\n");
+}
+#endif
+
+bool SkDisplayEvent::enableEvent(SkAnimateMaker& maker) 
+{
+       maker.fActiveEvent = this;
+       if (fChildren.count() == 0)
+               return false;
+       if (disable)
+               return false;
+#ifdef SK_DUMP_ENABLED
+       if (maker.fDumpEvents) {
+               SkDebugf("enable: ");
+               dumpEvent(&maker);
+       }
+#endif
+       SkDisplayList& displayList = maker.fDisplayList;
+       for (int index = 0; index < fChildren.count(); index++) {
+               SkDisplayable* displayable = fChildren[index];
+               if (displayable->isGroup()) {
+                       SkTDDrawableArray* parentList = displayList.getDrawList();
+                       *parentList->append() = (SkDrawable*) displayable;      // make it findable before children are enabled
+               }
+               if (displayable->enable(maker))
+                       continue;
+        if (maker.hasError()) 
+            return true;
+               if (displayable->isDrawable() == false)
+                       return true;    // error
+               SkDrawable* drawable = (SkDrawable*) displayable;
+               SkTDDrawableArray* parentList = displayList.getDrawList();
+               *parentList->append() = drawable;
+       }
+       return false;
+}
+
+bool SkDisplayEvent::getProperty(int index, SkScriptValue* value) const {
+       switch (index) {
+               case SK_PROPERTY(key):
+               case SK_PROPERTY(keys): {
+                       value->fType = SkType_String;
+                       char scratch[8];
+                       SkKey convert = index == SK_PROPERTY(keys) ? code : fLastCode;
+                       size_t size = convert > 0 ? SkUTF8_FromUnichar(convert, scratch) : 0;
+            fKeyString.set(scratch, size);
+                       value->fOperand.fString = &fKeyString;
+                       if (index != SK_PROPERTY(keys) || fMax == (SkKey) -1 || fMax == code)
+                               break;
+                       value->fOperand.fString->append("-");
+                       size = SkUTF8_FromUnichar(fMax, scratch);
+                       value->fOperand.fString->append(scratch, size);
+                       } break;
+               default:
+                       SkASSERT(0);
+                       return false;
+       }
+       return true;
+}
+
+void SkDisplayEvent::onEndElement(SkAnimateMaker& maker)
+{
+       if (kind == kUser)
+               return;
+       maker.fEvents.addEvent(this);
+       if (kind == kOnEnd) {
+               bool found = maker.find(target.c_str(), &fTarget);
+               SkASSERT(found);
+               SkASSERT(fTarget && fTarget->isAnimate());
+               SkAnimateBase* animate = (SkAnimateBase*) fTarget;
+               animate->setHasEndEvent();
+       }
+}
+
+void SkDisplayEvent::populateInput(SkAnimateMaker& maker, const SkEvent& fEvent) {
+       const SkMetaData& meta = fEvent.getMetaData();
+       SkMetaData::Iter iter(meta);
+       SkMetaData::Type        type;
+       int number;
+       const char* name;
+       while ((name = iter.next(&type, &number)) != nil) {
+               if (name[0] == '\0')
+                       continue;
+               SkDisplayable* displayable;
+               SkInput* input;
+               for (int index = 0; index < fChildren.count(); index++) {
+                       displayable = fChildren[index];
+                       if (displayable->getType() != SkType_Input)
+                               continue;
+                       input = (SkInput*) displayable;
+                       if (input->name.equals(name))
+                               goto found;
+               }
+               if (!maker.find(name, &displayable) || displayable->getType() != SkType_Input)
+                       continue;
+               input = (SkInput*) displayable;
+       found:
+               switch (type) {
+                       case SkMetaData::kS32_Type:
+                               meta.findS32(name, &input->fInt);
+                               break;
+                       case SkMetaData::kScalar_Type:
+                               meta.findScalar(name, &input->fFloat);
+                               break;
+                       case SkMetaData::kPtr_Type:
+                               SkASSERT(0);
+                               break; // !!! not handled for now
+                       case SkMetaData::kString_Type:
+                               input->string.set(meta.findString(name));
+                               break;
+                       default:
+                               SkASSERT(0);
+               }
+       }
+       // re-evaluate all animators that may have built their values from input strings
+       for (SkDisplayable** childPtr = fChildren.begin(); childPtr < fChildren.end(); childPtr++) {
+               SkDisplayable* displayable = *childPtr;
+               if (displayable->isApply() == false)
+                       continue;
+               SkApply* apply = (SkApply*) displayable;
+               apply->refresh(maker);
+       }
+}
+
+bool SkDisplayEvent::setProperty(int index, SkScriptValue& value) {
+       SkASSERT(index == SK_PROPERTY(key) || index == SK_PROPERTY(keys));
+       SkASSERT(value.fType == SkType_String);
+       SkString* string = value.fOperand.fString;
+       const char* chars = string->c_str();
+       int count = SkUTF8_CountUnichars(chars);
+       SkASSERT(count >= 1);
+       code = (SkKey) SkUTF8_NextUnichar(&chars);
+       fMax = code;
+       SkASSERT(count == 1 || index == SK_PROPERTY(keys));
+       if (--count > 0) {
+               SkASSERT(*chars == '-');
+               chars++;
+               fMax = (SkKey) SkUTF8_NextUnichar(&chars);
+               SkASSERT(fMax >= code);
+       }
+       return true;
+}
+
diff --git a/libs/graphics/animator/SkDisplayEvent.h b/libs/graphics/animator/SkDisplayEvent.h
new file mode 100644 (file)
index 0000000..4d5be02
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef SkDisplayEvent_DEFINED
+#define SkDisplayEvent_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkMemberInfo.h"
+#include "SkIntArray.h"
+#include "SkKey.h"
+
+class SkEvent;
+
+class SkDisplayEvent : public SkDisplayable {
+       DECLARE_DISPLAY_MEMBER_INFO(Event);
+       enum Kind {
+               kNo_kind,
+               kKeyChar,
+               kKeyPress,
+        kKeyPressUp,    //i assume the order here is intended to match with skanimatorscript.cpp
+               kMouseDown,
+               kMouseDrag,
+               kMouseMove,
+               kMouseUp,
+               kOnEnd,
+               kOnload,
+               kUser
+       };
+       SkDisplayEvent();
+       virtual ~SkDisplayEvent();
+       virtual bool add(SkAnimateMaker& , SkDisplayable* child);
+       virtual bool contains(SkDisplayable*);
+       virtual SkDisplayable* contains(const SkString& );
+#ifdef SK_DEBUG
+       void dumpEvent(SkAnimateMaker* );
+#endif
+       bool enableEvent(SkAnimateMaker& );
+       virtual bool getProperty(int index, SkScriptValue* ) const;
+       virtual void onEndElement(SkAnimateMaker& maker);
+       void populateInput(SkAnimateMaker& , const SkEvent& fEvent);
+       virtual bool setProperty(int index, SkScriptValue& );
+protected:
+       SkKey code;
+       SkBool disable;
+       Kind kind;
+       SkString target;
+       SkScalar x;
+       SkScalar y;
+       SkTDDisplayableArray fChildren;
+    mutable SkString fKeyString;
+       SkKey fLastCode; // last key to trigger this event
+       SkKey fMax; // if the code expresses a range
+       SkDisplayable* fTarget; // used by onEnd
+private:
+       void deleteMembers();
+       friend class SkEvents;
+       typedef SkDisplayable INHERITED;
+};
+
+#endif // SkDisplayEvent_DEFINED
+
diff --git a/libs/graphics/animator/SkDisplayEvents.cpp b/libs/graphics/animator/SkDisplayEvents.cpp
new file mode 100644 (file)
index 0000000..405e134
--- /dev/null
@@ -0,0 +1,104 @@
+#include "SkDisplayEvents.h"
+#include "SkAnimateMaker.h"
+#include "SkAnimator.h"
+#include "SkDisplayEvent.h"
+#include "SkDisplayMovie.h"
+#include "SkDrawable.h"
+#ifdef SK_DEBUG
+#include "SkDump.h"
+#endif
+
+SkEventState::SkEventState() : fCode(0), fDisable(false), fDisplayable(0), fX(0), fY(0) {
+}
+
+SkEvents::SkEvents() {
+}
+
+SkEvents::~SkEvents() {
+}
+
+bool SkEvents::doEvent(SkAnimateMaker& maker, SkDisplayEvent::Kind kind, SkEventState* state) {
+/*#ifdef SK_DUMP_ENABLED
+       if (maker.fDumpEvents) {
+               SkDebugf("doEvent: ");
+               SkString str;
+               SkDump::GetEnumString(SkType_EventKind, kind, &str);
+               SkDebugf("kind=%s ", str.c_str());
+               if (state && state->fDisplayable)
+                       state->fDisplayable->SkDisplayable::dump(&maker);
+               else
+                       SkDebugf("\n");
+       }
+#endif*/
+       bool handled = false;
+       SkDisplayable** firstMovie = maker.fMovies.begin();
+       SkDisplayable** endMovie = maker.fMovies.end();
+       for (SkDisplayable** ptr = firstMovie; ptr < endMovie; ptr++) {
+               SkDisplayMovie* movie = (SkDisplayMovie*) *ptr;
+               if (kind != SkDisplayEvent::kOnload)
+                       movie->doEvent(kind, state);
+       }
+       SkDisplayable* displayable = state ? state->fDisplayable : nil;
+       int keyCode = state ? state->fCode : 0;
+       int count = fEvents.count();
+       for (int index = 0; index < count; index++) {
+               SkDisplayEvent* evt = fEvents[index];
+               if (evt->disable)
+                       continue;
+               if (evt->kind != kind)
+                       continue;
+               if (evt->code != (SkKey) -1) {
+                       if ((int) evt->code > keyCode || (int) (evt->fMax != (SkKey) -1 ? evt->fMax : evt->code) < keyCode)
+                               continue;
+                       evt->fLastCode = (SkKey) keyCode;
+               }
+               if (evt->fTarget != nil && evt->fTarget != displayable)
+                       continue;
+               if (state == nil || state->fDisable == 0) {
+                       if (kind >= SkDisplayEvent::kMouseDown && kind <= SkDisplayEvent::kMouseUp) {
+                               evt->x = state->fX;
+                               evt->y = state->fY;
+                       }
+                       if (evt->enableEvent(maker))
+                               fError = true;
+               }
+               handled = true;
+       }
+       return handled;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkEvents::dump(SkAnimateMaker& maker) {
+       int index;
+       SkTDDrawableArray& drawArray = maker.fDisplayList.fDrawList;
+       int count = drawArray.count();
+       for (index = 0; index < count; index++) {
+               SkDrawable* drawable = drawArray[index];
+               drawable->dumpEvents(); 
+       }
+       count = fEvents.count();
+       for (index = 0; index < count; index++) {
+               SkDisplayEvent* evt = fEvents[index];
+               evt->dumpEvent(&maker);
+       }
+}
+#endif
+
+// currently this only removes onLoad events
+void SkEvents::removeEvent(SkDisplayEvent::Kind kind, SkEventState* state) {
+       int keyCode = state ? state->fCode : 0;
+       SkDisplayable* displayable = state ? state->fDisplayable : nil;
+       for (SkDisplayEvent** evtPtr = fEvents.begin(); evtPtr < fEvents.end(); evtPtr++) {
+               SkDisplayEvent* evt = *evtPtr;
+               if (evt->kind != kind)
+                       continue;
+               if (evt->code != (SkKey) -1) {
+                       if ((int) evt->code > keyCode || (int) (evt->fMax != (SkKey) -1 ? evt->fMax : evt->code) < keyCode)
+                               continue;
+               }
+               if (evt->fTarget != nil && evt->fTarget != displayable)
+                       continue;
+               int index = fEvents.find(evt);
+               fEvents.remove(index);
+       }
+}
diff --git a/libs/graphics/animator/SkDisplayEvents.h b/libs/graphics/animator/SkDisplayEvents.h
new file mode 100644 (file)
index 0000000..7000b67
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef SkDisplayEvents_DEFINED
+#define SkDisplayEvents_DEFINED
+
+#include "SkEvent.h"
+#include "SkDisplayEvent.h"
+
+struct SkEventState {
+       SkEventState();
+       int fCode;
+       SkBool fDisable;
+       SkDisplayable* fDisplayable;
+       SkScalar fX;
+       SkScalar fY;
+};
+
+class SkEvents {
+public:
+       SkEvents();
+       ~SkEvents();
+       void addEvent(SkDisplayEvent* evt) { *fEvents.append() = evt; }
+       bool doEvent(SkAnimateMaker& , SkDisplayEvent::Kind , SkEventState* );
+#ifdef SK_DUMP_ENABLED
+       void dump(SkAnimateMaker& );
+#endif
+       void reset() { fEvents.reset(); }
+       void removeEvent(SkDisplayEvent::Kind kind, SkEventState* );
+private:
+       SkTDDisplayEventArray fEvents;
+       SkBool fError;
+       friend class SkDisplayXMLParser;
+};
+
+#endif // SkDisplayEvents_DEFINED
+
diff --git a/libs/graphics/animator/SkDisplayInclude.cpp b/libs/graphics/animator/SkDisplayInclude.cpp
new file mode 100644 (file)
index 0000000..eee5f96
--- /dev/null
@@ -0,0 +1,50 @@
+#include "SkDisplayInclude.h"
+#include "SkAnimateMaker.h"
+#include "SkAnimator.h"
+
+#if 0
+#undef SK_MEMBER
+#define SK_MEMBER(_member, _type) \
+       { #_member, SK_OFFSETOF(BASE_CLASS::_A, _member), SkType_##_type, \
+       sizeof(((BASE_CLASS::_A*) 0)->_member) / sizeof(SkScalar) }
+#endif
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkInclude::fInfo[] = {
+       SK_MEMBER(src, String)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkInclude);
+
+//SkInclude::SkInclude() {
+//     src.init();
+//}
+
+//SkInclude::~SkInclude() {
+//     src.unref();
+//}
+
+bool SkInclude::enable(SkAnimateMaker & ) {
+       return true;
+}
+
+bool SkInclude::hasEnable() const {
+       return true;
+}
+
+void SkInclude::onEndElement(SkAnimateMaker& maker) {
+       maker.fInInclude = true;
+       if (src.size() == 0 || maker.decodeURI(src.c_str()) == false) {
+               if (maker.getErrorCode() != SkXMLParserError::kNoError || maker.getNativeCode() != -1) {
+                       maker.setInnerError(&maker, src);
+                       maker.setErrorCode(SkDisplayXMLParserError::kInInclude);
+               } else {
+                       maker.setErrorNoun(src);
+                       maker.setErrorCode(SkDisplayXMLParserError::kIncludeNameUnknownOrMissing);
+               }
+       }
+       maker.fInInclude = false;
+}
diff --git a/libs/graphics/animator/SkDisplayInclude.h b/libs/graphics/animator/SkDisplayInclude.h
new file mode 100644 (file)
index 0000000..b842c69
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef SkDisplayInclude_DEFINED
+#define SkDisplayInclude_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkMemberInfo.h"
+
+class SkInclude : public SkDisplayable {
+       DECLARE_MEMBER_INFO(Include);
+       virtual void onEndElement(SkAnimateMaker & );
+       virtual bool enable(SkAnimateMaker & );
+       virtual bool hasEnable() const;
+protected:
+       SkString src;
+};
+
+#endif // SkDisplayInclude_DEFINED
+
diff --git a/libs/graphics/animator/SkDisplayInput.cpp b/libs/graphics/animator/SkDisplayInput.cpp
new file mode 100644 (file)
index 0000000..7eec8d3
--- /dev/null
@@ -0,0 +1,46 @@
+#include "SkDisplayInput.h"
+
+enum SkInput_Properties {
+       SK_PROPERTY(initialized)
+};
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkInput::fInfo[] = {
+       SK_MEMBER_ALIAS(float, fFloat, Float),
+       SK_MEMBER_PROPERTY(initialized, Boolean),
+       SK_MEMBER_ALIAS(int, fInt, Int),
+       SK_MEMBER(name, String),
+       SK_MEMBER(string, String)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkInput);
+
+SkInput::SkInput() : fInt((int) SK_NaN32), fFloat(SK_ScalarNaN) {}
+
+SkDisplayable* SkInput::contains(const SkString& string) {
+       return string.equals(name) ? this : nil;
+}
+
+bool SkInput::enable(SkAnimateMaker & ) {
+       return true;
+}
+
+bool SkInput::getProperty(int index, SkScriptValue* value) const {
+       switch (index) {
+               case SK_PROPERTY(initialized):
+                       value->fType = SkType_Boolean;
+                       value->fOperand.fS32 = fInt != (int) SK_NaN32 ||
+                               SkScalarIsNaN(fFloat) == false || string.size() > 0;
+                       break;
+               default:
+                       return false;
+       }
+       return true;
+}
+bool SkInput::hasEnable() const {
+       return true;
+}
diff --git a/libs/graphics/animator/SkDisplayInput.h b/libs/graphics/animator/SkDisplayInput.h
new file mode 100644 (file)
index 0000000..b118b22
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef SkDisplayInput_DEFINED
+#define SkDisplayInput_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkMemberInfo.h"
+
+class SkInput : public SkDisplayable {
+       DECLARE_MEMBER_INFO(Input);
+       SkInput();
+       virtual SkDisplayable* contains(const SkString& );
+       virtual bool getProperty(int index, SkScriptValue* value) const;
+       virtual bool enable(SkAnimateMaker & );
+       virtual bool hasEnable() const;
+protected:
+       SkString name;
+       int32_t  fInt;
+       SkScalar fFloat;
+       SkString string;
+private:
+       friend class SkDisplayEvent;
+       friend class SkPost;
+};
+
+#endif // SkDisplayInput_DEFINED
+
diff --git a/libs/graphics/animator/SkDisplayList.cpp b/libs/graphics/animator/SkDisplayList.cpp
new file mode 100644 (file)
index 0000000..2e4d928
--- /dev/null
@@ -0,0 +1,151 @@
+#include "SkDisplayList.h"
+#include "SkAnimateActive.h"
+#include "SkAnimateBase.h"
+#include "SkAnimateMaker.h"
+#include "SkDisplayApply.h"
+#include "SkDrawable.h"
+#include "SkDrawGroup.h"
+#include "SkDrawMatrix.h"
+#include "SkInterpolator.h"
+#include "SkTime.h"
+
+SkDisplayList::SkDisplayList() : fDrawBounds(true), fUnionBounds(false), fInTime(0) {
+}
+
+SkDisplayList::~SkDisplayList() {
+}
+
+void SkDisplayList::append(SkActive* active) {
+       *fActiveList.append() = active;
+}
+
+bool SkDisplayList::draw(SkAnimateMaker& maker, SkMSec inTime) {
+       validate();
+       fInTime = inTime;
+       bool result = false;
+       fInvalBounds.setEmpty();
+       if (fDrawList.count()) {
+               for (SkActive** activePtr = fActiveList.begin(); activePtr < fActiveList.end(); activePtr++) {
+                       SkActive* active = *activePtr;
+                       active->reset();
+               }
+               for (int index = 0; index < fDrawList.count(); index++) {
+                       SkDrawable* draw = fDrawList[index];
+                       draw->initialize(); // allow matrices to reset themselves
+                       SkASSERT(draw->isDrawable());
+                       validate();
+                       result |= draw->draw(maker);
+               }
+       }
+       validate();
+       return result;
+}
+
+int SkDisplayList::findGroup(SkDrawable* match, SkTDDrawableArray** list,
+               SkGroup** parent, SkGroup** found, SkTDDrawableArray**grandList) { 
+       *parent = nil;
+       *list = &fDrawList;
+       *grandList = &fDrawList;
+       return SearchForMatch(match, list, parent, found, grandList);
+}
+
+void SkDisplayList::hardReset() {
+       fDrawList.reset();
+       fActiveList.reset();
+}
+
+bool SkDisplayList::onIRect(const SkRect16& r) {
+       fBounds = r;
+       return fDrawBounds;
+}
+
+int SkDisplayList::SearchForMatch(SkDrawable* match, SkTDDrawableArray** list,
+               SkGroup** parent, SkGroup** found, SkTDDrawableArray**grandList) { 
+       *found = nil;
+       for (int index = 0; index < (*list)->count(); index++) {
+               SkDrawable* draw = (**list)[index];
+               if (draw == match)
+                       return index;
+               if (draw->isApply()) {
+                       SkApply* apply = (SkApply*) draw;
+                       if (apply->scope == match)
+                               return index;
+            if (apply->scope->isGroup() && SearchGroupForMatch(apply->scope, match, list, parent, found, grandList, index))
+                return index;
+                       if (apply->mode == SkApply::kMode_create) {
+                               for (SkDrawable** ptr = apply->fScopes.begin(); ptr < apply->fScopes.end(); ptr++) {
+                                       SkDrawable* scope = *ptr;
+                                       if (scope == match)
+                                               return index;
+                    //perhaps should call SearchGroupForMatch here as well (on scope)
+                               }
+                       } 
+               }
+               if (draw->isGroup() && SearchGroupForMatch(draw, match, list, parent, found, grandList, index)) 
+                       return index;
+               
+       }
+       return -1;
+}
+
+bool SkDisplayList::SearchGroupForMatch(SkDrawable* draw, SkDrawable* match, SkTDDrawableArray** list,
+        SkGroup** parent, SkGroup** found, SkTDDrawableArray** grandList, int &index) {
+            SkGroup* group = (SkGroup*) draw;
+                       if (group->getOriginal() == match)
+                               return true;
+                       SkTDDrawableArray* saveList = *list;
+                       int groupIndex = group->findGroup(match, list, parent, found, grandList);
+                       if (groupIndex >= 0) {
+                               *found = group;
+                index = groupIndex;
+                               return true;
+                       }
+                       *list = saveList;
+            return false;
+        }
+
+void SkDisplayList::reset() {
+       for (int index = 0; index < fDrawList.count(); index++) {
+               SkDrawable* draw = fDrawList[index];
+               if (draw->isApply() == false)
+                       continue;
+               SkApply* apply = (SkApply*) draw;
+               apply->reset();
+       }                       
+}
+
+void SkDisplayList::remove(SkActive* active) {
+       int index = fActiveList.find(active);
+       SkASSERT(index >= 0);
+       fActiveList.remove(index);      // !!! could use shuffle instead
+       SkASSERT(fActiveList.find(active) < 0);
+}
+
+#ifdef SK_DUMP_ENABLED
+int SkDisplayList::fDumpIndex;
+int SkDisplayList::fIndent;
+
+void SkDisplayList::dump(SkAnimateMaker* maker) {
+       fIndent = 0;
+       dumpInner(maker);
+}
+
+void SkDisplayList::dumpInner(SkAnimateMaker* maker) {
+       for (int index = 0; index < fDrawList.count(); index++) {
+               fDumpIndex = index;
+               fDrawList[fDumpIndex]->dump(maker);
+       }
+}
+
+#endif
+
+#ifdef SK_DEBUG
+void SkDisplayList::validate() {
+       for (int index = 0; index < fDrawList.count(); index++) {
+               SkDrawable* draw = fDrawList[index];
+               draw->validate();
+       }
+}
+#endif
+
+
diff --git a/libs/graphics/animator/SkDisplayList.h b/libs/graphics/animator/SkDisplayList.h
new file mode 100644 (file)
index 0000000..30c21a6
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef SkDisplayList_DEFINED
+#define SkDisplayList_DEFINED
+
+#include "SkOperand.h"
+#include "SkIntArray.h"
+#include "SkBounder.h"
+#include "SkRect.h"
+
+class SkAnimateMaker;
+class SkActive;
+class SkApply;
+class SkDrawable;
+class SkGroup;
+
+class SkDisplayList : public SkBounder {
+public:
+       SkDisplayList();
+       virtual ~SkDisplayList();
+       void append(SkActive* );
+       void clear() { fDrawList.reset(); }
+       int count() { return fDrawList.count(); }
+       bool draw(SkAnimateMaker& , SkMSec time);
+#ifdef SK_DUMP_ENABLED
+       void dump(SkAnimateMaker* maker);
+       void dumpInner(SkAnimateMaker* maker);
+       static int fIndent;
+       static int fDumpIndex;
+#endif
+       int findGroup(SkDrawable* match, SkTDDrawableArray** list, 
+               SkGroup** parent, SkGroup** found, SkTDDrawableArray** grandList); 
+       SkDrawable* get(int index) { return fDrawList[index]; }
+       SkMSec getTime() { return fInTime; }
+       SkTDDrawableArray* getDrawList() { return &fDrawList; }
+       void hardReset();
+       virtual bool onIRect(const SkRect16& r);
+       void reset();
+       void remove(SkActive* );
+#ifdef SK_DEBUG
+       void validate();
+#else
+       void validate() {}
+#endif
+       static int SearchForMatch(SkDrawable* match, SkTDDrawableArray** list,
+               SkGroup** parent, SkGroup** found, SkTDDrawableArray**grandList);
+       static bool SearchGroupForMatch(SkDrawable* draw, SkDrawable* match, 
+               SkTDDrawableArray** list, SkGroup** parent, SkGroup** found, SkTDDrawableArray** grandList, 
+               int &index);
+public:
+       SkRect16 fBounds;
+       SkRect16 fInvalBounds;
+       bool fDrawBounds;
+       bool fHasUnion;
+       bool fUnionBounds;
+private:
+       SkTDDrawableArray fDrawList;
+       SkTDActiveArray fActiveList;
+       SkMSec fInTime;
+       friend class SkEvents;
+};
+
+#endif // SkDisplayList_DEFINED
+
diff --git a/libs/graphics/animator/SkDisplayMath.cpp b/libs/graphics/animator/SkDisplayMath.cpp
new file mode 100644 (file)
index 0000000..da757a3
--- /dev/null
@@ -0,0 +1,231 @@
+#include "SkDisplayMath.h"
+
+enum SkDisplayMath_Properties {
+       SK_PROPERTY(E),
+       SK_PROPERTY(LN10),
+       SK_PROPERTY(LN2),
+       SK_PROPERTY(LOG10E),
+       SK_PROPERTY(LOG2E),
+       SK_PROPERTY(PI),
+       SK_PROPERTY(SQRT1_2),
+       SK_PROPERTY(SQRT2)
+};
+
+const SkScalar SkDisplayMath::gConstants[] = {
+#ifdef SK_SCALAR_IS_FLOAT
+       2.718281828f,   // E
+       2.302585093f,   // LN10
+       0.693147181f,   // LN2
+       0.434294482f,   // LOG10E
+       1.442695041f,   // LOG2E
+       3.141592654f,   // PI
+       0.707106781f,   // SQRT1_2
+       1.414213562f            // SQRT2 
+#else
+       0x2B7E1,        // E
+       0x24D76,        // LN10
+       0xB172,         // LN2
+       0x6F2E,         // LOG10E
+       0x17154,        // LOG2E
+       0x3243F,        // PI
+       0xB505,         // SQRT1_2
+       0x16A0A // SQRT2
+#endif
+};
+
+enum SkDisplayMath_Functions {
+       SK_FUNCTION(abs),
+       SK_FUNCTION(acos),
+       SK_FUNCTION(asin),
+       SK_FUNCTION(atan),
+       SK_FUNCTION(atan2),
+       SK_FUNCTION(ceil),
+       SK_FUNCTION(cos),
+       SK_FUNCTION(exp),
+       SK_FUNCTION(floor),
+       SK_FUNCTION(log),
+       SK_FUNCTION(max),
+       SK_FUNCTION(min),
+       SK_FUNCTION(pow),
+       SK_FUNCTION(random),
+       SK_FUNCTION(round),
+       SK_FUNCTION(sin),
+       SK_FUNCTION(sqrt),
+       SK_FUNCTION(tan)
+};
+
+const SkFunctionParamType SkDisplayMath::fFunctionParameters[] = {
+       (SkFunctionParamType) SkType_Float,     // abs
+       (SkFunctionParamType) 0,
+       (SkFunctionParamType) SkType_Float,     // acos
+       (SkFunctionParamType) 0,
+       (SkFunctionParamType) SkType_Float,     // asin
+       (SkFunctionParamType) 0,
+       (SkFunctionParamType) SkType_Float,     // atan
+       (SkFunctionParamType) 0,
+       (SkFunctionParamType) SkType_Float,     // atan2
+       (SkFunctionParamType) SkType_Float,
+       (SkFunctionParamType) 0,
+       (SkFunctionParamType) SkType_Float,     // ceil
+       (SkFunctionParamType) 0,
+       (SkFunctionParamType) SkType_Float,     // cos
+       (SkFunctionParamType) 0,
+       (SkFunctionParamType) SkType_Float,     // exp
+       (SkFunctionParamType) 0,
+       (SkFunctionParamType) SkType_Float,     // floor
+       (SkFunctionParamType) 0,
+       (SkFunctionParamType) SkType_Float,     // log
+       (SkFunctionParamType) 0,
+       (SkFunctionParamType) SkType_Array,     // max
+       (SkFunctionParamType) 0,
+       (SkFunctionParamType) SkType_Array,     // min
+       (SkFunctionParamType) 0,
+       (SkFunctionParamType) SkType_Float,     // pow
+       (SkFunctionParamType) SkType_Float,
+       (SkFunctionParamType) 0,
+       (SkFunctionParamType) SkType_Float,     // random
+       (SkFunctionParamType) 0,
+       (SkFunctionParamType) SkType_Float,     // round
+       (SkFunctionParamType) 0,
+       (SkFunctionParamType) SkType_Float,     // sin
+       (SkFunctionParamType) 0,
+       (SkFunctionParamType) SkType_Float,     // sqrt
+       (SkFunctionParamType) 0,
+       (SkFunctionParamType) SkType_Float,     // tan
+       (SkFunctionParamType) 0
+};
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDisplayMath::fInfo[] = {
+       SK_MEMBER_PROPERTY(E, Float),
+       SK_MEMBER_PROPERTY(LN10, Float),
+       SK_MEMBER_PROPERTY(LN2, Float),
+       SK_MEMBER_PROPERTY(LOG10E, Float),
+       SK_MEMBER_PROPERTY(LOG2E, Float),
+       SK_MEMBER_PROPERTY(PI, Float),
+       SK_MEMBER_PROPERTY(SQRT1_2, Float),
+       SK_MEMBER_PROPERTY(SQRT2, Float),
+       SK_MEMBER_FUNCTION(abs, Float),
+       SK_MEMBER_FUNCTION(acos, Float),
+       SK_MEMBER_FUNCTION(asin, Float),
+       SK_MEMBER_FUNCTION(atan, Float),
+       SK_MEMBER_FUNCTION(atan2, Float),
+       SK_MEMBER_FUNCTION(ceil, Float),
+       SK_MEMBER_FUNCTION(cos, Float),
+       SK_MEMBER_FUNCTION(exp, Float),
+       SK_MEMBER_FUNCTION(floor, Float),
+       SK_MEMBER_FUNCTION(log, Float),
+       SK_MEMBER_FUNCTION(max, Float),
+       SK_MEMBER_FUNCTION(min, Float),
+       SK_MEMBER_FUNCTION(pow, Float),
+       SK_MEMBER_FUNCTION(random, Float),
+       SK_MEMBER_FUNCTION(round, Float),
+       SK_MEMBER_FUNCTION(sin, Float),
+       SK_MEMBER_FUNCTION(sqrt, Float),
+       SK_MEMBER_FUNCTION(tan, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDisplayMath);
+
+void SkDisplayMath::executeFunction(SkDisplayable* target, int index, 
+               SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type,
+               SkScriptValue* scriptValue) {
+       if (scriptValue == nil)
+               return;
+       SkASSERT(target == this);
+       SkScriptValue* array = parameters.begin();
+       SkScriptValue* end = parameters.end();
+       SkScalar input = parameters[0].fOperand.fScalar;
+       SkScalar scalarResult;
+       switch (index) {
+               case SK_FUNCTION(abs):
+                       scalarResult = SkScalarAbs(input); 
+                       break;
+               case SK_FUNCTION(acos):
+                       scalarResult = SkScalarACos(input);
+                       break;
+               case SK_FUNCTION(asin):
+                       scalarResult = SkScalarASin(input);
+                       break;
+               case SK_FUNCTION(atan):
+                       scalarResult = SkScalarATan2(input, SK_Scalar1);
+                       break;
+               case SK_FUNCTION(atan2):
+                       scalarResult = SkScalarATan2(input, parameters[1].fOperand.fScalar);
+                       break;
+               case SK_FUNCTION(ceil):
+                       scalarResult = SkIntToScalar(SkScalarCeil(input)); 
+                       break;
+               case SK_FUNCTION(cos):
+                       scalarResult = SkScalarCos(input);
+                       break;
+               case SK_FUNCTION(exp):
+                       scalarResult = SkScalarExp(input);
+                       break;
+               case SK_FUNCTION(floor):
+                       scalarResult = SkIntToScalar(SkScalarFloor(input)); 
+                       break;
+               case SK_FUNCTION(log):
+                       scalarResult = SkScalarLog(input);
+                       break;
+               case SK_FUNCTION(max):
+                       scalarResult = -SK_ScalarMax;
+                       while (array < end) {
+                               scalarResult = SkMaxScalar(scalarResult, array->fOperand.fScalar);
+                               array++;
+                       }
+                       break;
+               case SK_FUNCTION(min):
+                       scalarResult = SK_ScalarMax;
+                       while (array < end) {
+                               scalarResult = SkMinScalar(scalarResult, array->fOperand.fScalar);
+                               array++;
+                       }
+                       break;
+               case SK_FUNCTION(pow):
+                       // not the greatest -- but use x^y = e^(y * ln(x))
+                       scalarResult = SkScalarLog(input);
+                       scalarResult = SkScalarMul(parameters[1].fOperand.fScalar, scalarResult);
+                       scalarResult = SkScalarExp(scalarResult);
+                       break;
+               case SK_FUNCTION(random):
+                       scalarResult = fRandom.nextUScalar1();
+                       break;
+               case SK_FUNCTION(round):
+                       scalarResult = SkIntToScalar(SkScalarRound(input)); 
+                       break;
+               case SK_FUNCTION(sin):
+                       scalarResult = SkScalarSin(input);
+                       break;
+               case SK_FUNCTION(sqrt): {
+                       SkASSERT(parameters.count() == 1);
+                       SkASSERT(type == SkType_Float);
+                       scalarResult = SkScalarSqrt(input); 
+                       } break;
+               case SK_FUNCTION(tan):
+                       scalarResult = SkScalarTan(input);
+                       break;
+               default:
+                       SkASSERT(0);
+                       scalarResult = SK_ScalarNaN;
+       }
+       scriptValue->fOperand.fScalar = scalarResult;
+       scriptValue->fType = SkType_Float;
+}
+
+const SkFunctionParamType* SkDisplayMath::getFunctionsParameters() {
+       return fFunctionParameters;
+}
+
+bool SkDisplayMath::getProperty(int index, SkScriptValue* value) const {
+       if ((unsigned)index < SK_ARRAY_COUNT(gConstants)) {
+               value->fOperand.fScalar = gConstants[index];
+               value->fType = SkType_Float;
+               return true;
+       }
+       SkASSERT(0);
+       return false;
+}
diff --git a/libs/graphics/animator/SkDisplayMath.h b/libs/graphics/animator/SkDisplayMath.h
new file mode 100644 (file)
index 0000000..ced6e42
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef SkDisplayMath_DEFINED
+#define SkDisplayMath_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkMemberInfo.h"
+#include "SkRandom.h"
+
+class SkDisplayMath : public SkDisplayable {
+       DECLARE_DISPLAY_MEMBER_INFO(Math);
+       virtual void executeFunction(SkDisplayable* , int index, 
+               SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type,
+               SkScriptValue* );
+       virtual const SkFunctionParamType* getFunctionsParameters();
+       virtual bool getProperty(int index, SkScriptValue* value) const;
+private:
+       mutable SkRandom fRandom;
+       static const SkScalar gConstants[];
+       static const SkFunctionParamType fFunctionParameters[];
+
+};
+       
+#endif // SkDisplayMath_DEFINED
+
diff --git a/libs/graphics/animator/SkDisplayMovie.cpp b/libs/graphics/animator/SkDisplayMovie.cpp
new file mode 100644 (file)
index 0000000..3727efe
--- /dev/null
@@ -0,0 +1,121 @@
+#include "SkDisplayMovie.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDisplayMovie::fInfo[] = {
+       SK_MEMBER(src, String)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDisplayMovie);
+
+SkDisplayMovie::SkDisplayMovie() : fDecodedSuccessfully(false), fLoaded(false), fMovieBuilt(false) {
+       fMovie.fMaker->fInMovie = true;
+}
+
+SkDisplayMovie::~SkDisplayMovie() {
+}
+
+void SkDisplayMovie::buildMovie() {
+       if (fMovieBuilt)
+               return;
+       SkAnimateMaker* movieMaker = fMovie.fMaker;
+       SkAnimateMaker* parentMaker = movieMaker->fParentMaker;
+       if (src.size() == 0 || parentMaker == nil)
+               return;
+       movieMaker->fPrefix.set(parentMaker->fPrefix);
+       fDecodedSuccessfully = fMovie.fMaker->decodeURI(src.c_str());
+       if (fDecodedSuccessfully == false) {
+
+               if (movieMaker->getErrorCode() != SkXMLParserError::kNoError || movieMaker->getNativeCode() != -1) {
+                       movieMaker->setInnerError(parentMaker, src);
+                       parentMaker->setErrorCode(SkDisplayXMLParserError::kInMovie);
+               } else {
+                       parentMaker->setErrorNoun(src);
+                       parentMaker->setErrorCode(SkDisplayXMLParserError::kMovieNameUnknownOrMissing);
+               }
+       }
+       fMovieBuilt = true;
+}
+
+SkDisplayable* SkDisplayMovie::deepCopy(SkAnimateMaker* maker) {
+       SkDisplayMovie* copy = (SkDisplayMovie*) INHERITED::deepCopy(maker);
+       copy->fMovie.fMaker->fParentMaker = fMovie.fMaker->fParentMaker;
+       copy->fMovie.fMaker->fHostEventSinkID = fMovie.fMaker->fHostEventSinkID;
+       copy->fMovieBuilt = false;
+       *fMovie.fMaker->fParentMaker->fMovies.append() = copy;
+       return copy;
+}
+
+void SkDisplayMovie::dirty() {
+       buildMovie();
+}
+
+bool SkDisplayMovie::doEvent(SkDisplayEvent::Kind kind, SkEventState* state) {
+    if (fLoaded == false)
+        return false;
+       fMovie.fMaker->fEnableTime = fMovie.fMaker->fParentMaker->fEnableTime;
+       return fMovie.fMaker->fEvents.doEvent(*fMovie.fMaker, kind, state);
+}
+
+bool SkDisplayMovie::draw(SkAnimateMaker& maker) {
+       if (fDecodedSuccessfully == false)
+               return false;
+       if (fLoaded == false)
+               enable(maker);
+       maker.fCanvas->save();
+       SkPaint local = SkPaint(*maker.fPaint);
+       bool result = fMovie.draw(maker.fCanvas, &local, 
+               maker.fDisplayList.getTime()) != SkAnimator::kNotDifferent;
+       maker.fDisplayList.fInvalBounds.join(fMovie.fMaker->fDisplayList.fInvalBounds);
+       maker.fCanvas->restore();
+       return result;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkDisplayMovie::dump(SkAnimateMaker* maker) {
+       dumpBase(maker);
+       SkDebugf("src=\"%s\"/>\n",  src.c_str());
+       SkAnimateMaker* movieMaker = fMovie.fMaker;
+       SkDisplayList::fIndent += 4;
+       movieMaker->fDisplayList.dumpInner(movieMaker);
+       SkDisplayList::fIndent -= 4;
+    dumpEnd(maker);
+}
+
+void SkDisplayMovie::dumpEvents() {
+       fMovie.fMaker->fEvents.dump(*fMovie.fMaker);
+}
+#endif
+
+bool SkDisplayMovie::enable(SkAnimateMaker& maker) {
+       if (fDecodedSuccessfully == false)
+               return false;
+       SkAnimateMaker* movieMaker = fMovie.fMaker;
+       movieMaker->fEvents.doEvent(*movieMaker, SkDisplayEvent::kOnload, nil);
+       movieMaker->fEvents.removeEvent(SkDisplayEvent::kOnload, nil);
+       fLoaded = true;
+    movieMaker->fLoaded = true;
+       return false;
+}
+
+bool SkDisplayMovie::hasEnable() const {
+       return true;
+}
+
+void SkDisplayMovie::onEndElement(SkAnimateMaker& maker) {
+#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
+       fMovie.fMaker->fDebugTimeBase = maker.fDebugTimeBase;
+#endif
+       fMovie.fMaker->fPrefix.set(maker.fPrefix);
+       fMovie.fMaker->fHostEventSinkID = maker.fHostEventSinkID;
+       fMovie.fMaker->fParentMaker = &maker;
+       buildMovie();
+       *maker.fMovies.append() = this;
+}
+
+
diff --git a/libs/graphics/animator/SkDisplayMovie.h b/libs/graphics/animator/SkDisplayMovie.h
new file mode 100644 (file)
index 0000000..f81a740
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef SkDisplayMovie_DEFINED
+#define SkDisplayMovie_DEFINED
+
+#include "SkAnimator.h"
+#include "SkDrawable.h"
+#include "SkMemberInfo.h"
+
+struct SkEventState;
+
+class SkDisplayMovie : public SkDrawable {
+       DECLARE_DISPLAY_MEMBER_INFO(Movie);
+       SkDisplayMovie();
+       virtual ~SkDisplayMovie();
+       void buildMovie();
+       virtual SkDisplayable* deepCopy(SkAnimateMaker* );
+       virtual void dirty();
+       bool doEvent(const SkEvent& evt) {
+               return fLoaded && fMovie.doEvent(evt);
+       }
+       virtual bool doEvent(SkDisplayEvent::Kind , SkEventState* state );
+       virtual bool draw(SkAnimateMaker& );
+#ifdef SK_DUMP_ENABLED
+       virtual void dump(SkAnimateMaker* );
+       virtual void dumpEvents();
+#endif
+       virtual bool enable(SkAnimateMaker& );
+       const SkAnimator* getAnimator() const { return &fMovie; }
+       virtual bool hasEnable() const;
+       virtual void onEndElement(SkAnimateMaker& );
+protected:
+       SkString src;
+       SkAnimator fMovie;
+       SkBool8 fDecodedSuccessfully;
+       SkBool8 fLoaded;
+       SkBool8 fMovieBuilt;
+       friend class SkAnimateMaker;
+       friend class SkPost;
+private:
+       typedef SkDrawable INHERITED;
+};
+
+#endif // SkDisplayMovie_DEFINED
+
diff --git a/libs/graphics/animator/SkDisplayNumber.cpp b/libs/graphics/animator/SkDisplayNumber.cpp
new file mode 100644 (file)
index 0000000..03de65c
--- /dev/null
@@ -0,0 +1,50 @@
+#include "SkDisplayNumber.h"
+
+enum SkDisplayNumber_Properties {
+       SK_PROPERTY(MAX_VALUE),
+       SK_PROPERTY(MIN_VALUE),
+       SK_PROPERTY(NEGATIVE_INFINITY),
+       SK_PROPERTY(NaN),
+       SK_PROPERTY(POSITIVE_INFINITY)
+};
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDisplayNumber::fInfo[] = {
+       SK_MEMBER_PROPERTY(MAX_VALUE, Float),
+       SK_MEMBER_PROPERTY(MIN_VALUE, Float),
+       SK_MEMBER_PROPERTY(NEGATIVE_INFINITY, Float),
+       SK_MEMBER_PROPERTY(NaN, Float),
+       SK_MEMBER_PROPERTY(POSITIVE_INFINITY, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDisplayNumber);
+
+bool SkDisplayNumber::getProperty(int index, SkScriptValue* value) const {
+       SkScalar constant;
+       switch (index) {
+               case SK_PROPERTY(MAX_VALUE):
+                       constant = SK_ScalarMax;
+               break;
+               case SK_PROPERTY(MIN_VALUE):
+                       constant = SK_ScalarMin;
+               break;
+               case SK_PROPERTY(NEGATIVE_INFINITY):
+                       constant = -SK_ScalarInfinity;
+               break;
+               case SK_PROPERTY(NaN):
+                       constant = SK_ScalarNaN;
+               break;
+               case SK_PROPERTY(POSITIVE_INFINITY):
+                       constant = SK_ScalarInfinity;
+               break;
+               default:
+                       SkASSERT(0);
+                       return false;
+       }
+       value->fOperand.fScalar = constant;
+       value->fType = SkType_Float;
+       return true;
+}
diff --git a/libs/graphics/animator/SkDisplayNumber.h b/libs/graphics/animator/SkDisplayNumber.h
new file mode 100644 (file)
index 0000000..7b2ea58
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef SkDisplayNumber_DEFINED
+#define SkDisplayNumber_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkMemberInfo.h"
+
+class SkDisplayNumber : public SkDisplayable {
+       DECLARE_DISPLAY_MEMBER_INFO(Number);
+       virtual bool getProperty(int index, SkScriptValue* value) const;
+private:
+};
+       
+#endif // SkDisplayNumber_DEFINED
diff --git a/libs/graphics/animator/SkDisplayPost.cpp b/libs/graphics/animator/SkDisplayPost.cpp
new file mode 100644 (file)
index 0000000..fad3aee
--- /dev/null
@@ -0,0 +1,298 @@
+#include "SkDisplayPost.h"
+#include "SkAnimateMaker.h"
+#include "SkAnimator.h"
+#include "SkDisplayMovie.h"
+#include "SkPostParts.h"
+#include "SkScript.h"
+#ifdef SK_DEBUG
+#include "SkDump.h"
+#include "SkTime.h"
+#endif
+
+enum SkPost_Properties {
+       SK_PROPERTY(target),
+       SK_PROPERTY(type)
+};
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkPost::fInfo[] = {
+       SK_MEMBER(delay, MSec),
+//     SK_MEMBER(initialized, Boolean),
+       SK_MEMBER(mode, EventMode),
+       SK_MEMBER(sink, String),
+       SK_MEMBER_PROPERTY(target, String),
+       SK_MEMBER_PROPERTY(type, String)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkPost);
+
+SkPost::SkPost() : delay(0), /*initialized(SkBool(-1)), */ mode(kImmediate), fMaker(nil),
+       fSinkID(0), fTargetMaker(nil), fChildHasID(false), fDirty(false) {
+}
+
+SkPost::~SkPost() {
+       for (SkData** part = fParts.begin(); part < fParts.end();  part++)
+               delete *part;
+}
+
+bool SkPost::add(SkAnimateMaker& , SkDisplayable* child) {
+       SkASSERT(child && child->isData());
+       SkData* part = (SkData*) child;
+       *fParts.append() = part;
+       return true;
+}
+
+bool SkPost::childrenNeedDisposing() const { 
+       return false; 
+}
+
+void SkPost::dirty() { 
+       fDirty = true; 
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkPost::dump(SkAnimateMaker* maker) {
+       dumpBase(maker);
+    SkString* eventType = new SkString();
+    fEvent.getType(eventType);
+    if (eventType->equals("user")) {
+        const char* target = fEvent.findString("id");
+        SkDebugf("target=\"%s\" ", target);
+    }
+    else
+        SkDebugf("type=\"%s\" ", eventType->c_str());
+    delete eventType;
+    
+       if (delay > 0) {
+#ifdef SK_CAN_USE_FLOAT
+               SkDebugf("delay=\"%g\" ", SkScalarToFloat(SkScalarDiv(delay, 1000)));
+#else
+               SkDebugf("delay=\"%x\" ", SkScalarDiv(delay, 1000));
+#endif
+    }
+//     if (initialized == false)
+//             SkDebugf("(uninitialized) ");
+       SkString string;
+       SkDump::GetEnumString(SkType_EventMode, mode, &string);
+    if (!string.equals("immediate"))
+        SkDebugf("mode=\"%s\" ", string.c_str());
+       // !!! could enhance this to search through make hierarchy to show name of sink
+       if (sink.size() > 0) {
+               SkDebugf("sink=\"%s\" sinkID=\"%d\" ", sink.c_str(), fSinkID);
+       } else if (fSinkID != maker->getAnimator()->getSinkID() && fSinkID != 0) {
+               SkDebugf("sinkID=\"%d\" ", fSinkID);
+       }
+       const SkMetaData& meta = fEvent.getMetaData();
+       SkMetaData::Iter iter(meta);
+       SkMetaData::Type        type;
+       int number;
+       const char* name;
+    bool closedYet = false;
+    SkDisplayList::fIndent += 4;
+    //this seems to work, but kinda hacky
+    //for some reason the last part is id, which i don't want
+    //and the parts seem to be in the reverse order from the one in which we find the 
+    //data itself
+    //SkData** ptr = fParts.end();
+    //SkData* data;
+    //const char* ID;
+       while ((name = iter.next(&type, &number)) != nil) {
+        //ptr--;
+        if (strcmp(name, "id") == 0)
+            continue;
+        if (closedYet == false) {
+            SkDebugf(">\n");
+            closedYet = true;
+        }
+        //data = *ptr;
+        //if (data->id)
+        //    ID = data->id;
+        //else
+        //    ID = "";
+               SkDebugf("%*s<data name=\"%s\" ", SkDisplayList::fIndent, "", name);
+               switch (type) {
+                       case SkMetaData::kS32_Type: {
+                               int32_t s32;
+                               meta.findS32(name, &s32);
+                               SkDebugf("int=\"%d\" ", s32);
+                               } break;
+                       case SkMetaData::kScalar_Type: {
+                               SkScalar scalar;
+                               meta.findScalar(name, &scalar);
+#ifdef SK_CAN_USE_FLOAT
+                               SkDebugf("float=\"%g\" ", SkScalarToFloat(scalar));
+#else
+                               SkDebugf("float=\"%x\" ", scalar);
+#endif
+                               } break;
+                       case SkMetaData::kString_Type:
+                               SkDebugf("string=\"%s\" ", meta.findString(name));
+                               break;
+                       case SkMetaData::kPtr_Type: {//when do we have a pointer
+                                       void* ptr;
+                                       meta.findPtr(name, &ptr);
+                                       SkDebugf("0x%08x ", ptr);
+                               } break;
+                       case SkMetaData::kBool_Type: {
+                               bool boolean;
+                               meta.findBool(name, &boolean);
+                               SkDebugf("boolean=\"%s\" ", boolean ? "true " : "false ");
+                               } break;
+            default:
+                break;
+               }
+        SkDebugf("/>\n");
+        //ptr++;
+/*      perhaps this should only be done in the case of a pointer?
+               SkDisplayable* displayable;
+               if (maker->find(name, &displayable))
+                       displayable->dump(maker);
+               else
+                       SkDebugf("\n");*/
+       }
+    SkDisplayList::fIndent -= 4;
+    if (closedYet)
+        dumpEnd(maker);
+    else
+        SkDebugf("/>\n");
+
+}
+#endif
+
+bool SkPost::enable(SkAnimateMaker& maker ) {
+       if (maker.hasError())
+               return true;
+       if (fDirty) {
+               if (sink.size() > 0)
+                       findSinkID();
+               if (fChildHasID) {
+                       SkString preserveID(fEvent.findString("id"));
+                       fEvent.getMetaData().reset();
+                       if (preserveID.size() > 0)
+                               fEvent.setString("id", preserveID);
+                       for (SkData** part = fParts.begin(); part < fParts.end();  part++) {
+                               if ((*part)->add())
+                                       maker.setErrorCode(SkDisplayXMLParserError::kErrorAddingDataToPost);
+                       }
+               }
+               fDirty = false;
+       }
+#ifdef SK_DUMP_ENABLED
+       if (maker.fDumpPosts) {
+               SkDebugf("post enable: ");
+               dump(&maker);
+       }
+#if defined SK_DEBUG_ANIMATION_TIMING
+       SkString debugOut;
+       SkMSec time = maker.getAppTime();
+       debugOut.appendS32(time - maker.fDebugTimeBase);
+       debugOut.append(" post id=");
+       debugOut.append(_id);
+       debugOut.append(" enable=");
+       debugOut.appendS32(maker.fEnableTime - maker.fDebugTimeBase);
+       debugOut.append(" delay=");
+       debugOut.appendS32(delay);
+#endif
+#endif
+//     SkMSec adjustedDelay = maker.adjustDelay(maker.fEnableTime, delay);
+       SkMSec futureTime = maker.fEnableTime + delay;
+       fEvent.setFast32(futureTime);
+#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
+       debugOut.append(" future=");
+       debugOut.appendS32(futureTime - maker.fDebugTimeBase);
+       SkDebugf("%s\n", debugOut.c_str());
+#endif
+       SkEventSinkID targetID = fSinkID;
+       bool isAnimatorEvent = true;
+       SkAnimator* anim = maker.getAnimator();
+       if (targetID == 0) {
+               isAnimatorEvent = fEvent.findString("id") != nil;
+               if (isAnimatorEvent) 
+                       targetID = anim->getSinkID();
+               else if (maker.fHostEventSinkID)
+                       targetID = maker.fHostEventSinkID;
+               else
+                       return true;
+       } else
+               anim = fTargetMaker->getAnimator();
+       if (delay == 0) {
+               if (isAnimatorEvent && mode == kImmediate)
+                       fTargetMaker->doEvent(fEvent);
+               else
+                       anim->onEventPost(new SkEvent(fEvent), targetID);
+       } else
+               anim->onEventPostTime(new SkEvent(fEvent), targetID, futureTime);
+       return true;
+}
+
+void SkPost::findSinkID() {
+       // get the next delimiter '.' if any
+       fTargetMaker = fMaker;
+       const char* ch = sink.c_str();
+       do {
+               const char* end = strchr(ch, '.');
+               size_t len = end ? end - ch : strlen(ch);
+               SkDisplayable* displayable = nil;
+               if (SK_LITERAL_STR_EQUAL("parent", ch, len)) {
+                       if (fTargetMaker->fParentMaker)
+                               fTargetMaker = fTargetMaker->fParentMaker;
+                       else {
+                               fTargetMaker->setErrorCode(SkDisplayXMLParserError::kNoParentAvailable);
+                               return;
+                       }
+               } else {
+                       fTargetMaker->find(ch, len, &displayable);
+                       if (displayable == nil || displayable->getType() != SkType_Movie) {
+                               fTargetMaker->setErrorCode(SkDisplayXMLParserError::kExpectedMovie);
+                               return;
+                       }
+                       SkDisplayMovie* movie = (SkDisplayMovie*) displayable;
+                       fTargetMaker = movie->fMovie.fMaker;
+               }
+               if (end == nil)
+                       break;
+               ch = ++end;
+       } while (true);
+       SkAnimator* anim = fTargetMaker->getAnimator();
+       fSinkID = anim->getSinkID();
+}
+bool SkPost::hasEnable() const {
+       return true;
+}
+
+void SkPost::onEndElement(SkAnimateMaker& maker) {
+       fTargetMaker = fMaker = &maker;
+       if (fChildHasID == false) {
+               for (SkData** part = fParts.begin(); part < fParts.end();  part++)
+                       delete *part;
+               fParts.reset();
+       }
+}
+
+void SkPost::setChildHasID() { 
+       fChildHasID = true; 
+}
+
+bool SkPost::setProperty(int index, SkScriptValue& value) {
+       SkASSERT(value.fType == SkType_String);
+       SkString* string = value.fOperand.fString;
+       switch(index) {
+               case SK_PROPERTY(target): {
+                       fEvent.setType("user");
+                       fEvent.setString("id", *string);
+                       mode = kImmediate;
+                       } break;
+               case SK_PROPERTY(type):
+                       fEvent.setType(*string);
+                       break;
+               default:
+                       SkASSERT(0);
+                       return false;
+       }
+       return true;
+}
+
diff --git a/libs/graphics/animator/SkDisplayPost.h b/libs/graphics/animator/SkDisplayPost.h
new file mode 100644 (file)
index 0000000..cfc2fab
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef SkDisplayPost_DEFINED
+#define SkDisplayPost_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkEvent.h"
+#include "SkEventSink.h"
+#include "SkMemberInfo.h"
+#include "SkIntArray.h"
+
+class SkData;
+class SkAnimateMaker;
+
+class SkPost : public SkDisplayable {
+       DECLARE_MEMBER_INFO(Post);
+       enum Mode {
+               kDeferred,
+               kImmediate
+       };
+       SkPost();
+       virtual ~SkPost();
+       virtual bool add(SkAnimateMaker& , SkDisplayable* child);
+       virtual bool childrenNeedDisposing() const;
+       virtual void dirty();
+#ifdef SK_DUMP_ENABLED
+       virtual void dump(SkAnimateMaker* );
+#endif
+       virtual bool enable(SkAnimateMaker& );
+       virtual bool hasEnable() const;
+       virtual void onEndElement(SkAnimateMaker& );
+       virtual void setChildHasID();
+       virtual bool setProperty(int index, SkScriptValue& );
+protected:
+       SkMSec delay;
+       SkString sink;
+//     SkBool initialized;
+       Mode mode;
+       SkEvent fEvent;
+       SkAnimateMaker* fMaker;
+       SkTDDataArray fParts;
+       SkEventSinkID fSinkID;
+       SkAnimateMaker* fTargetMaker;
+       SkBool8 fChildHasID;
+       SkBool8 fDirty;
+private:
+       void findSinkID();
+       friend class SkData;
+       typedef SkDisplayable INHERITED;
+};
+
+#endif //SkDisplayPost_DEFINED
diff --git a/libs/graphics/animator/SkDisplayRandom.cpp b/libs/graphics/animator/SkDisplayRandom.cpp
new file mode 100644 (file)
index 0000000..53775d3
--- /dev/null
@@ -0,0 +1,63 @@
+#include "SkDisplayRandom.h"
+#include "SkInterpolator.h"
+
+enum SkDisplayRandom_Properties {
+       SK_PROPERTY(random),
+       SK_PROPERTY(seed)
+};
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDisplayRandom::fInfo[] = {
+       SK_MEMBER(blend, Float),
+       SK_MEMBER(max, Float),
+       SK_MEMBER(min, Float),
+       SK_MEMBER_DYNAMIC_PROPERTY(random, Float),
+       SK_MEMBER_PROPERTY(seed, Int)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDisplayRandom);
+
+SkDisplayRandom::SkDisplayRandom() : blend(0), min(0), max(SK_Scalar1) {
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkDisplayRandom::dump(SkAnimateMaker* maker) {
+    dumpBase(maker);
+#ifdef SK_CAN_USE_FLOAT
+    SkDebugf("min=\"%g\" ", SkScalarToFloat(min));
+    SkDebugf("max=\"%g\" ", SkScalarToFloat(max));
+    SkDebugf("blend=\"%g\" ", SkScalarToFloat(blend));    
+#else
+    SkDebugf("min=\"%x\" ", min);
+    SkDebugf("max=\"%x\" ", max);
+    SkDebugf("blend=\"%x\" ", blend);    
+#endif
+    SkDebugf("/>\n");
+}
+#endif
+
+bool SkDisplayRandom::getProperty(int index, SkScriptValue* value) const {
+       switch(index) {
+               case SK_PROPERTY(random): {
+                       SkScalar random = fRandom.nextUScalar1();
+                       SkScalar relativeT = SkInterpolatorBase::Blend(random, blend);
+                       value->fOperand.fScalar = min + SkScalarMul(max - min, relativeT);
+                       value->fType = SkType_Float;
+                       return true;
+               }
+               default:
+                       SkASSERT(0);
+       }
+       return false;
+}
+
+bool SkDisplayRandom::setProperty(int index, SkScriptValue& value) {
+       SkASSERT(index == SK_PROPERTY(seed));
+       SkASSERT(value.fType == SkType_Int);
+       fRandom.setSeed(value.fOperand.fS32);
+       return true;
+}
+
diff --git a/libs/graphics/animator/SkDisplayRandom.h b/libs/graphics/animator/SkDisplayRandom.h
new file mode 100644 (file)
index 0000000..bcfc945
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef SkDisplayRandom_DEFINED
+#define SkDisplayRandom_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkMemberInfo.h"
+#include "SkRandom.h"
+
+#ifdef min
+#undef min
+#endif
+
+#ifdef max
+#undef max
+#endif
+
+class SkDisplayRandom : public SkDisplayable {
+       DECLARE_DISPLAY_MEMBER_INFO(Random);
+       SkDisplayRandom();
+#ifdef SK_DUMP_ENABLED
+    virtual void dump(SkAnimateMaker* );
+#endif
+       virtual bool getProperty(int index, SkScriptValue* value) const;
+       virtual bool setProperty(int index, SkScriptValue& );
+private:
+       SkScalar blend;
+       SkScalar min;
+       SkScalar max;
+       mutable SkRandom fRandom;
+};
+
+#endif // SkDisplayRandom_DEFINED
+
diff --git a/libs/graphics/animator/SkDisplayScreenplay.cpp b/libs/graphics/animator/SkDisplayScreenplay.cpp
new file mode 100644 (file)
index 0000000..44c7a89
--- /dev/null
@@ -0,0 +1,13 @@
+#include "SkDisplayScreenplay.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDisplayScreenplay::fInfo[] = {
+       SK_MEMBER(time, MSec)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDisplayScreenplay);
+
+
diff --git a/libs/graphics/animator/SkDisplayScreenplay.h b/libs/graphics/animator/SkDisplayScreenplay.h
new file mode 100644 (file)
index 0000000..6d11f7a
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef SkDisplayScreenplay_DEFINED
+#define SkDisplayScreenplay_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkMemberInfo.h"
+
+class SkDisplayScreenplay : public SkDisplayable {
+       DECLARE_DISPLAY_MEMBER_INFO(Screenplay);
+       SkMSec time;
+};
+
+#endif // SkDisplayScreenplay_DEFINED
diff --git a/libs/graphics/animator/SkDisplayType.cpp b/libs/graphics/animator/SkDisplayType.cpp
new file mode 100644 (file)
index 0000000..dfb536f
--- /dev/null
@@ -0,0 +1,757 @@
+#include "SkDisplayType.h"
+#include "SkAnimateMaker.h"
+#include "SkAnimateSet.h"
+#include "SkDisplayAdd.h"
+#include "SkDisplayApply.h"
+#include "SkDisplayBounds.h"
+#include "SkDisplayEvent.h"
+#include "SkDisplayInclude.h"
+#ifdef SK_DEBUG
+#include "SkDisplayList.h"
+#endif
+#include "SkDisplayMath.h"
+#include "SkDisplayMovie.h"
+#include "SkDisplayNumber.h"
+#include "SkDisplayPost.h"
+#include "SkDisplayRandom.h"
+#include "SkDisplayTypes.h"
+#include "SkDraw3D.h"
+#include "SkDrawBitmap.h"
+#include "SkDrawClip.h"
+#include "SkDrawDash.h"
+#include "SkDrawDiscrete.h"
+#include "SkDrawEmboss.h"
+#include "SkDrawFull.h"
+#include "SkDrawGradient.h"
+#include "SkDrawLine.h"
+#include "SkDrawMatrix.h"
+#include "SkDrawOval.h"
+#include "SkDrawPaint.h"
+#include "SkDrawPath.h"
+#include "SkDrawPoint.h"
+#include "SkDrawSaveLayer.h"
+#include "SkDrawText.h"
+#include "SkDrawTextBox.h"
+#include "SkDrawTo.h"
+#include "SkDrawTransparentShader.h"
+#include "SkDump.h"
+#include "SkExtras.h"
+#include "SkHitClear.h"
+#include "SkHitTest.h"
+#include "SkMatrixParts.h"
+#include "SkPathParts.h"
+#include "SkPostParts.h"
+#include "SkSnapshot.h"
+#include "SkTextOnPath.h"
+#include "SkTextToPath.h"
+#include "SkTSearch.h"
+
+#define CASE_NEW(_class) \
+       case SkType_##_class: result = new Sk##_class(); break
+#define CASE_DRAW_NEW(_class) \
+       case SkType_##_class: result = new SkDraw##_class(); break
+#define CASE_DISPLAY_NEW(_class) \
+       case SkType_##_class: result = new SkDisplay##_class(); break
+#ifdef SK_DEBUG
+       #define CASE_DEBUG_RETURN_NIL(_class) \
+               case SkType_##_class: return NULL
+#else
+       #define CASE_DEBUG_RETURN_NIL(_class)
+#endif
+       
+
+SkDisplayTypes SkDisplayType::gNewTypes = kNumberOfTypes;
+
+SkDisplayable* SkDisplayType::CreateInstance(SkAnimateMaker* maker, SkDisplayTypes type) {
+       SkDisplayable* result = NULL;
+       switch (type) {
+               // unknown
+               CASE_DISPLAY_NEW(Math);
+               CASE_DISPLAY_NEW(Number);
+               CASE_NEW(Add);
+               CASE_NEW(AddCircle);
+               // addgeom
+               CASE_DEBUG_RETURN_NIL(AddMode);
+               CASE_NEW(AddOval);
+               CASE_NEW(AddPath);
+               CASE_NEW(AddRect);
+               CASE_NEW(AddRoundRect);
+               CASE_DEBUG_RETURN_NIL(Align);
+               CASE_NEW(Animate);
+               // animatebase
+               CASE_NEW(Apply);
+               CASE_DEBUG_RETURN_NIL(ApplyMode);
+               CASE_DEBUG_RETURN_NIL(ApplyTransition);
+               CASE_DISPLAY_NEW(Array);
+               // argb
+               // base64
+               // basebitmap
+               // baseclassinfo
+               CASE_DRAW_NEW(Bitmap);
+               // bitmapencoding
+               // bitmapformat
+               CASE_DRAW_NEW(BitmapShader);
+               CASE_DRAW_NEW(Blur);
+               CASE_DISPLAY_NEW(Boolean);
+               // boundable
+               CASE_DISPLAY_NEW(Bounds);
+               CASE_DEBUG_RETURN_NIL(Cap);
+               CASE_NEW(Clear);
+               CASE_DRAW_NEW(Clip);
+               CASE_NEW(Close);
+               CASE_DRAW_NEW(Color);
+               CASE_NEW(CubicTo);
+               CASE_NEW(Dash);
+               CASE_NEW(Data);
+               CASE_NEW(Discrete);
+               // displayable
+               // drawable
+               CASE_NEW(DrawTo);
+               CASE_NEW(Dump);
+               // dynamicstring
+               CASE_DRAW_NEW(Emboss);
+               CASE_DISPLAY_NEW(Event);
+               CASE_DEBUG_RETURN_NIL(EventCode);
+               CASE_DEBUG_RETURN_NIL(EventKind);
+               CASE_DEBUG_RETURN_NIL(EventMode);
+               // filltype
+               // filtertype
+               CASE_DISPLAY_NEW(Float);
+               CASE_NEW(FromPath);
+               CASE_DEBUG_RETURN_NIL(FromPathMode);
+               CASE_NEW(Full);
+               // gradient
+               CASE_NEW(Group);
+               CASE_NEW(HitClear);
+               CASE_NEW(HitTest);
+               CASE_NEW(Image);
+               CASE_NEW(Include);
+               CASE_NEW(Input);
+               CASE_DISPLAY_NEW(Int);
+               CASE_DEBUG_RETURN_NIL(Join);
+               CASE_NEW(Line);
+               CASE_NEW(LineTo);
+               CASE_NEW(LinearGradient);
+               CASE_DRAW_NEW(MaskFilter);
+               CASE_DEBUG_RETURN_NIL(MaskFilterBlurStyle);
+               // maskfilterlight
+               CASE_DRAW_NEW(Matrix);
+               // memberfunction
+               // memberproperty
+               CASE_NEW(Move);
+               CASE_NEW(MoveTo);
+               CASE_DISPLAY_NEW(Movie);
+               // msec
+               CASE_NEW(Oval);
+               CASE_DRAW_NEW(Paint);
+               CASE_DRAW_NEW(Path);
+               // pathdirection
+               CASE_DRAW_NEW(PathEffect);
+               // point
+               CASE_NEW(DrawPoint);
+               CASE_NEW(PolyToPoly);
+               CASE_NEW(Polygon);
+               CASE_NEW(Polyline);
+               CASE_NEW(Post);
+               CASE_NEW(QuadTo);
+               CASE_NEW(RCubicTo);
+               CASE_NEW(RLineTo);
+               CASE_NEW(RMoveTo);
+               CASE_NEW(RQuadTo);
+               CASE_NEW(RadialGradient);
+               CASE_DISPLAY_NEW(Random);
+               CASE_DRAW_NEW(Rect);
+               CASE_NEW(RectToRect);
+               CASE_NEW(Remove);
+               CASE_NEW(Replace);
+               CASE_NEW(Rotate);
+               CASE_NEW(RoundRect);
+               CASE_NEW(Save);
+        CASE_NEW(SaveLayer);
+               CASE_NEW(Scale);
+               // screenplay
+               CASE_NEW(Set);
+               CASE_DRAW_NEW(Shader);
+               CASE_NEW(Skew);
+               CASE_NEW(3D_Camera);
+               CASE_NEW(3D_Patch);
+               // 3dpoint
+               CASE_NEW(Snapshot);
+               CASE_DISPLAY_NEW(String);
+               // style
+               CASE_NEW(Text);
+               CASE_DRAW_NEW(TextBox);
+               // textboxalign
+               // textboxmode
+               CASE_NEW(TextOnPath);
+               CASE_NEW(TextToPath);
+               CASE_DEBUG_RETURN_NIL(TileMode);
+               CASE_NEW(Translate);
+               CASE_DRAW_NEW(TransparentShader);
+               CASE_DRAW_NEW(Typeface);
+               CASE_DEBUG_RETURN_NIL(Xfermode);
+               default:
+                       SkExtras** end = maker->fExtras.end();
+                       for (SkExtras** extraPtr = maker->fExtras.begin(); extraPtr < end; extraPtr++) {
+                               if ((result = (*extraPtr)->createInstance(type)) != NULL)
+                                       return result;
+                       }
+                       SkASSERT(0);
+       }
+       return result;
+}
+
+#undef CASE_NEW
+#undef CASE_DRAW_NEW
+#undef CASE_DISPLAY_NEW
+
+#if SK_USE_CONDENSED_INFO == 0
+
+#define CASE_GET_INFO(_class) case SkType_##_class: \
+       info = Sk##_class::fInfo; infoCount = Sk##_class::fInfoCount; break
+#define CASE_GET_DRAW_INFO(_class) case SkType_##_class: \
+       info = SkDraw##_class::fInfo; infoCount = SkDraw##_class::fInfoCount; break
+#define CASE_GET_DISPLAY_INFO(_class) case SkType_##_class: \
+       info = SkDisplay##_class::fInfo; infoCount = SkDisplay##_class::fInfoCount; \
+       break
+
+const SkMemberInfo* SkDisplayType::GetMembers(SkAnimateMaker* maker, 
+               SkDisplayTypes type, int* infoCountPtr) {
+       const SkMemberInfo* info = NULL;
+       int infoCount = 0;
+       switch (type) {
+               // unknown
+               CASE_GET_DISPLAY_INFO(Math);
+               CASE_GET_DISPLAY_INFO(Number);
+               CASE_GET_INFO(Add);
+               CASE_GET_INFO(AddCircle);
+               CASE_GET_INFO(AddGeom);
+               // addmode
+               CASE_GET_INFO(AddOval);
+               CASE_GET_INFO(AddPath);
+               CASE_GET_INFO(AddRect);
+               CASE_GET_INFO(AddRoundRect);
+               // align
+               CASE_GET_INFO(Animate);
+               CASE_GET_INFO(AnimateBase);
+               CASE_GET_INFO(Apply);
+               // applymode
+               // applytransition
+               CASE_GET_DISPLAY_INFO(Array);
+               // argb
+               // base64
+               CASE_GET_INFO(BaseBitmap);
+               // baseclassinfo
+               CASE_GET_DRAW_INFO(Bitmap);
+               // bitmapencoding
+               // bitmapformat
+               CASE_GET_DRAW_INFO(BitmapShader);
+               CASE_GET_DRAW_INFO(Blur);
+               CASE_GET_DISPLAY_INFO(Boolean);
+               // boundable
+               CASE_GET_DISPLAY_INFO(Bounds);
+               // cap
+               // clear
+               CASE_GET_DRAW_INFO(Clip);
+               // close
+               CASE_GET_DRAW_INFO(Color);
+               CASE_GET_INFO(CubicTo);
+               CASE_GET_INFO(Dash);
+               CASE_GET_INFO(Data);
+               CASE_GET_INFO(Discrete);
+               // displayable
+               // drawable
+               CASE_GET_INFO(DrawTo);
+               CASE_GET_INFO(Dump);
+               // dynamicstring
+               CASE_GET_DRAW_INFO(Emboss);
+               CASE_GET_DISPLAY_INFO(Event);
+               // eventcode
+               // eventkind
+               // eventmode
+               // filltype
+               // filtertype
+               CASE_GET_DISPLAY_INFO(Float);
+               CASE_GET_INFO(FromPath);
+               // frompathmode
+               // full
+               CASE_GET_INFO(Gradient);
+               CASE_GET_INFO(Group);
+               CASE_GET_INFO(HitClear);
+               CASE_GET_INFO(HitTest);
+               CASE_GET_INFO(Image);
+               CASE_GET_INFO(Include);
+               CASE_GET_INFO(Input);
+               CASE_GET_DISPLAY_INFO(Int);
+               // join
+               CASE_GET_INFO(Line);
+               CASE_GET_INFO(LineTo);
+               CASE_GET_INFO(LinearGradient);
+               // maskfilter
+               // maskfilterblurstyle
+               // maskfilterlight
+               CASE_GET_DRAW_INFO(Matrix);
+               // memberfunction
+               // memberproperty
+               CASE_GET_INFO(Move);
+               CASE_GET_INFO(MoveTo);
+               CASE_GET_DISPLAY_INFO(Movie);
+               // msec
+               CASE_GET_INFO(Oval);
+               CASE_GET_DRAW_INFO(Path);
+               CASE_GET_DRAW_INFO(Paint);
+               // pathdirection
+               // patheffect
+               case SkType_Point: info = Sk_Point::fInfo; infoCount = Sk_Point::fInfoCount; break; // no virtual flavor
+               CASE_GET_INFO(DrawPoint); // virtual flavor
+               CASE_GET_INFO(PolyToPoly);
+               CASE_GET_INFO(Polygon);
+               CASE_GET_INFO(Polyline);
+               CASE_GET_INFO(Post);
+               CASE_GET_INFO(QuadTo);
+               CASE_GET_INFO(RCubicTo);
+               CASE_GET_INFO(RLineTo);
+               CASE_GET_INFO(RMoveTo);
+               CASE_GET_INFO(RQuadTo);
+               CASE_GET_INFO(RadialGradient);
+               CASE_GET_DISPLAY_INFO(Random);
+               CASE_GET_DRAW_INFO(Rect);
+               CASE_GET_INFO(RectToRect);
+               CASE_GET_INFO(Remove);
+               CASE_GET_INFO(Replace);
+               CASE_GET_INFO(Rotate);
+               CASE_GET_INFO(RoundRect);
+               CASE_GET_INFO(Save);
+        CASE_GET_INFO(SaveLayer);
+               CASE_GET_INFO(Scale);
+               // screenplay
+               CASE_GET_INFO(Set);
+               CASE_GET_DRAW_INFO(Shader);
+               CASE_GET_INFO(Skew);
+               CASE_GET_INFO(3D_Camera);
+               CASE_GET_INFO(3D_Patch);
+               CASE_GET_INFO(3D_Point);
+               CASE_GET_INFO(Snapshot);
+               CASE_GET_DISPLAY_INFO(String);
+               // style
+               CASE_GET_INFO(Text);
+               CASE_GET_DRAW_INFO(TextBox);
+               // textboxalign
+               // textboxmode
+               CASE_GET_INFO(TextOnPath);
+               CASE_GET_INFO(TextToPath);
+               // tilemode
+               CASE_GET_INFO(Translate);
+               // transparentshader
+               CASE_GET_DRAW_INFO(Typeface);
+               // xfermode
+               // knumberoftypes
+               default: 
+                       if (maker) {
+                               SkExtras** end = maker->fExtras.end();
+                               for (SkExtras** extraPtr = maker->fExtras.begin(); extraPtr < end; extraPtr++) {
+                                       if ((info = (*extraPtr)->getMembers(type, infoCountPtr)) != NULL)
+                                               return info;
+                               }
+                       }
+                       return NULL;
+       }
+       if (infoCountPtr)
+               *infoCountPtr = infoCount;
+       return info;
+}
+
+const SkMemberInfo* SkDisplayType::GetMember(SkAnimateMaker* maker, 
+               SkDisplayTypes type, const char** matchPtr ) {
+       int infoCount;
+       const SkMemberInfo* info = GetMembers(maker, type, &infoCount);
+       info = SkMemberInfo::Find(info, infoCount, matchPtr);
+//     SkASSERT(info);
+       return info;
+}
+
+#undef CASE_GET_INFO
+#undef CASE_GET_DRAW_INFO
+#undef CASE_GET_DISPLAY_INFO
+
+#endif // SK_USE_CONDENSED_INFO == 0
+
+#if defined SK_DEBUG || defined SK_BUILD_CONDENSED
+       #define DRAW_NAME(_name, _type) {_name, _type, true, false }
+       #define DISPLAY_NAME(_name, _type) {_name, _type, false, true }
+    #define INIT_BOOL_FIELDS    , false, false
+#else
+       #define DRAW_NAME(_name, _type) {_name, _type }
+       #define DISPLAY_NAME(_name, _type) {_name, _type }
+    #define INIT_BOOL_FIELDS
+#endif
+
+const TypeNames gTypeNames[] = {
+       // unknown
+       { "Math", SkType_Math                       INIT_BOOL_FIELDS },
+       { "Number", SkType_Number                   INIT_BOOL_FIELDS },
+       { "add", SkType_Add                         INIT_BOOL_FIELDS },
+       { "addCircle", SkType_AddCircle             INIT_BOOL_FIELDS },
+       // addgeom
+       // addmode
+       { "addOval", SkType_AddOval                 INIT_BOOL_FIELDS },
+       { "addPath", SkType_AddPath                 INIT_BOOL_FIELDS },
+       { "addRect", SkType_AddRect                 INIT_BOOL_FIELDS },
+       { "addRoundRect", SkType_AddRoundRect       INIT_BOOL_FIELDS },
+       // align
+       { "animate", SkType_Animate                 INIT_BOOL_FIELDS },
+       // animateBase
+       { "apply", SkType_Apply                     INIT_BOOL_FIELDS },
+       // applymode
+       // applytransition
+       { "array", SkType_Array                     INIT_BOOL_FIELDS },
+       // argb
+       // base64
+       // basebitmap
+       // baseclassinfo
+       DRAW_NAME("bitmap", SkType_Bitmap),
+       // bitmapencoding
+       // bitmapformat
+       DRAW_NAME("bitmapShader", SkType_BitmapShader),
+       DRAW_NAME("blur", SkType_Blur),
+       { "boolean", SkType_Boolean                 INIT_BOOL_FIELDS },
+       // boundable
+       DISPLAY_NAME("bounds", SkType_Bounds),
+       // cap
+       { "clear", SkType_Clear                     INIT_BOOL_FIELDS },
+       DRAW_NAME("clip", SkType_Clip),
+       { "close", SkType_Close                     INIT_BOOL_FIELDS },
+       DRAW_NAME("color", SkType_Color),
+       { "cubicTo", SkType_CubicTo                 INIT_BOOL_FIELDS },
+       { "dash", SkType_Dash                       INIT_BOOL_FIELDS },
+       { "data", SkType_Data                       INIT_BOOL_FIELDS },
+       { "discrete", SkType_Discrete               INIT_BOOL_FIELDS },
+       // displayable
+       // drawable
+       { "drawTo", SkType_DrawTo                   INIT_BOOL_FIELDS },
+       { "dump", SkType_Dump                       INIT_BOOL_FIELDS },
+       // dynamicstring
+       DRAW_NAME("emboss", SkType_Emboss),
+       DISPLAY_NAME("event", SkType_Event),
+       // eventcode
+       // eventkind
+       // eventmode
+       // filltype
+       // filtertype
+       { "float", SkType_Float                     INIT_BOOL_FIELDS },
+       { "fromPath", SkType_FromPath               INIT_BOOL_FIELDS },
+       // frompathmode
+       { "full", SkType_Full                       INIT_BOOL_FIELDS },
+       // gradient
+       { "group", SkType_Group                     INIT_BOOL_FIELDS },
+       { "hitClear", SkType_HitClear               INIT_BOOL_FIELDS },
+       { "hitTest", SkType_HitTest                 INIT_BOOL_FIELDS },
+       { "image", SkType_Image                     INIT_BOOL_FIELDS },
+       { "include", SkType_Include                 INIT_BOOL_FIELDS },
+       { "input", SkType_Input                     INIT_BOOL_FIELDS },
+       { "int", SkType_Int                         INIT_BOOL_FIELDS },
+       // join
+       { "line", SkType_Line                       INIT_BOOL_FIELDS },
+       { "lineTo", SkType_LineTo                   INIT_BOOL_FIELDS },
+       { "linearGradient", SkType_LinearGradient   INIT_BOOL_FIELDS },
+       { "maskFilter", SkType_MaskFilter           INIT_BOOL_FIELDS },
+       // maskfilterblurstyle
+       // maskfilterlight
+       DRAW_NAME("matrix", SkType_Matrix),
+       // memberfunction
+       // memberproperty
+       { "move", SkType_Move                       INIT_BOOL_FIELDS },
+       { "moveTo", SkType_MoveTo                   INIT_BOOL_FIELDS },
+       { "movie", SkType_Movie                     INIT_BOOL_FIELDS },
+       // msec
+       { "oval", SkType_Oval                       INIT_BOOL_FIELDS },
+       DRAW_NAME("paint", SkType_Paint),
+       DRAW_NAME("path", SkType_Path),
+       // pathdirection
+       { "pathEffect", SkType_PathEffect           INIT_BOOL_FIELDS },
+       // point
+       DRAW_NAME("point", SkType_DrawPoint),
+       { "polyToPoly", SkType_PolyToPoly           INIT_BOOL_FIELDS },
+       { "polygon", SkType_Polygon                 INIT_BOOL_FIELDS },
+       { "polyline", SkType_Polyline               INIT_BOOL_FIELDS },
+       { "post", SkType_Post                       INIT_BOOL_FIELDS },
+       { "quadTo", SkType_QuadTo                   INIT_BOOL_FIELDS },
+       { "rCubicTo", SkType_RCubicTo               INIT_BOOL_FIELDS },
+       { "rLineTo", SkType_RLineTo                 INIT_BOOL_FIELDS },
+       { "rMoveTo", SkType_RMoveTo                 INIT_BOOL_FIELDS },
+       { "rQuadTo", SkType_RQuadTo                 INIT_BOOL_FIELDS },
+       { "radialGradient", SkType_RadialGradient   INIT_BOOL_FIELDS },
+       DISPLAY_NAME("random", SkType_Random),
+       { "rect", SkType_Rect                       INIT_BOOL_FIELDS },
+       { "rectToRect", SkType_RectToRect           INIT_BOOL_FIELDS },
+       { "remove", SkType_Remove                   INIT_BOOL_FIELDS },
+       { "replace", SkType_Replace                 INIT_BOOL_FIELDS },
+       { "rotate", SkType_Rotate                   INIT_BOOL_FIELDS },
+       { "roundRect", SkType_RoundRect             INIT_BOOL_FIELDS },
+       { "save", SkType_Save                       INIT_BOOL_FIELDS },
+    { "saveLayer", SkType_SaveLayer             INIT_BOOL_FIELDS },
+       { "scale", SkType_Scale                     INIT_BOOL_FIELDS },
+       // screenplay
+       { "set", SkType_Set                         INIT_BOOL_FIELDS },
+       { "shader", SkType_Shader                   INIT_BOOL_FIELDS },
+       { "skew", SkType_Skew                       INIT_BOOL_FIELDS },
+       { "skia3d:camera", SkType_3D_Camera         INIT_BOOL_FIELDS },
+       { "skia3d:patch", SkType_3D_Patch           INIT_BOOL_FIELDS },
+       // point
+       { "snapshot", SkType_Snapshot               INIT_BOOL_FIELDS },
+       { "string", SkType_String                   INIT_BOOL_FIELDS },
+       // style
+       { "text", SkType_Text                       INIT_BOOL_FIELDS },
+       { "textBox", SkType_TextBox                 INIT_BOOL_FIELDS },
+       // textboxalign
+       // textboxmode
+       { "textOnPath", SkType_TextOnPath           INIT_BOOL_FIELDS },
+       { "textToPath", SkType_TextToPath           INIT_BOOL_FIELDS },
+       // tilemode
+       { "translate", SkType_Translate             INIT_BOOL_FIELDS },
+       DRAW_NAME("transparentShader", SkType_TransparentShader),
+       { "typeface", SkType_Typeface               INIT_BOOL_FIELDS }
+       // xfermode
+       // knumberoftypes
+};
+
+const int kTypeNamesSize = SK_ARRAY_COUNT(gTypeNames);
+
+SkDisplayTypes SkDisplayType::Find(SkAnimateMaker* maker, const SkMemberInfo* match) {
+       for (int index = 0; index < kTypeNamesSize; index++) {
+               SkDisplayTypes type = gTypeNames[index].fType;
+               const SkMemberInfo* info = SkDisplayType::GetMembers(maker, type, NULL);
+               if (info == match)
+                       return type;
+       }
+       return (SkDisplayTypes) -1;
+}
+
+// !!! optimize this by replacing function with a byte-sized lookup table
+SkDisplayTypes SkDisplayType::GetParent(SkAnimateMaker* maker, SkDisplayTypes base) {
+       if (base == SkType_Group || base == SkType_Save || base == SkType_SaveLayer)            //!!! cheat a little until we have a lookup table
+               return SkType_Displayable;
+       if (base == SkType_Set)
+               return SkType_Animate;  // another cheat until we have a lookup table
+       const SkMemberInfo* info = GetMembers(maker, base, NULL); // get info for this type
+       SkASSERT(info);
+       if (info->fType != SkType_BaseClassInfo)
+               return SkType_Unknown; // if no base, done
+       // !!! could change SK_MEMBER_INHERITED macro to take type, stuff in offset, so that 
+       // this (and table builder) could know type without the following steps:
+       const SkMemberInfo* inherited = info->getInherited();
+       SkDisplayTypes result = (SkDisplayTypes) (SkType_Unknown + 1);
+       for (; result <= SkType_Xfermode; result = (SkDisplayTypes) (result + 1)) {
+               const SkMemberInfo* match = GetMembers(maker, result, NULL);
+               if (match == inherited)
+                       break;
+       }
+       SkASSERT(result <= SkType_Xfermode);
+       return result;
+}
+
+SkDisplayTypes SkDisplayType::GetType(SkAnimateMaker* maker, const char match[], size_t len ) {
+       int index = SkStrSearch(&gTypeNames[0].fName, kTypeNamesSize, match, 
+               len, sizeof(gTypeNames[0]));
+       if (index >= 0 && index < kTypeNamesSize)
+               return gTypeNames[index].fType;
+       SkExtras** end = maker->fExtras.end();
+       for (SkExtras** extraPtr = maker->fExtras.begin(); extraPtr < end; extraPtr++) {
+               SkDisplayTypes result = (*extraPtr)->getType(match, len);
+               if (result != SkType_Unknown)
+                       return result;
+       }
+       return (SkDisplayTypes) -1;
+}
+
+bool SkDisplayType::IsEnum(SkAnimateMaker* , SkDisplayTypes type) {
+       switch (type) {
+               case SkType_AddMode:
+               case SkType_Align:
+               case SkType_ApplyMode:
+               case SkType_ApplyTransition:
+               case SkType_BitmapEncoding:
+               case SkType_BitmapFormat:
+               case SkType_Boolean:
+               case SkType_Cap:
+               case SkType_EventCode:
+               case SkType_EventKind:
+               case SkType_EventMode:
+               case SkType_FillType:
+               case SkType_FilterType:
+        case SkType_FontStyle:
+               case SkType_FromPathMode:
+               case SkType_Join:
+               case SkType_MaskFilterBlurStyle:
+               case SkType_PathDirection:
+               case SkType_Style:
+               case SkType_TextBoxAlign:
+               case SkType_TextBoxMode:
+               case SkType_TileMode:
+               case SkType_Xfermode:
+                       return true;
+               default:        // to avoid warnings
+                       break;
+       }
+       return false;
+}
+
+bool SkDisplayType::IsDisplayable(SkAnimateMaker* , SkDisplayTypes type) {
+       switch (type) {
+               case SkType_Add:
+               case SkType_AddCircle:
+               case SkType_AddOval:
+               case SkType_AddPath:
+               case SkType_AddRect:
+               case SkType_AddRoundRect:
+               case SkType_Animate:
+               case SkType_AnimateBase:
+               case SkType_Apply:
+               case SkType_BaseBitmap:
+               case SkType_Bitmap:
+               case SkType_BitmapShader:
+               case SkType_Blur:
+               case SkType_Clear:
+               case SkType_Clip:
+               case SkType_Close:
+               case SkType_Color:
+               case SkType_CubicTo:
+               case SkType_Dash:
+               case SkType_Data:
+               case SkType_Discrete:
+               case SkType_Displayable:
+               case SkType_Drawable:
+               case SkType_DrawTo:
+               case SkType_Emboss:
+               case SkType_Event:
+               case SkType_FromPath:
+               case SkType_Full:
+               case SkType_Group:
+               case SkType_Image:
+               case SkType_Input:
+               case SkType_Line:
+               case SkType_LineTo:
+               case SkType_LinearGradient:
+               case SkType_Matrix:
+               case SkType_Move:
+               case SkType_MoveTo:
+               case SkType_Movie:
+               case SkType_Oval:
+               case SkType_Paint:
+               case SkType_Path:
+               case SkType_PolyToPoly:
+               case SkType_Polygon:
+               case SkType_Polyline:
+               case SkType_Post:
+               case SkType_QuadTo:
+               case SkType_RCubicTo:
+               case SkType_RLineTo:
+               case SkType_RMoveTo:
+               case SkType_RQuadTo:
+               case SkType_RadialGradient:
+               case SkType_Random:
+               case SkType_Rect:
+               case SkType_RectToRect:
+               case SkType_Remove:
+               case SkType_Replace:
+               case SkType_Rotate:
+               case SkType_RoundRect:
+               case SkType_Save:
+        case SkType_SaveLayer:
+               case SkType_Scale:
+               case SkType_Set:
+               case SkType_Shader:
+               case SkType_Skew:
+               case SkType_3D_Camera:
+               case SkType_3D_Patch:
+               case SkType_Snapshot:
+               case SkType_Text:
+               case SkType_TextBox:
+               case SkType_TextOnPath:
+               case SkType_TextToPath:
+               case SkType_Translate:
+               case SkType_TransparentShader:
+                       return true;
+               default:        // to avoid warnings
+                       break;
+       }
+       return false;
+}
+
+bool SkDisplayType::IsStruct(SkAnimateMaker* , SkDisplayTypes type) {
+       switch (type) {
+               case SkType_Point:
+               case SkType_3D_Point:
+                       return true;
+               default:        // to avoid warnings
+                       break;
+       }
+       return false;
+}
+
+
+SkDisplayTypes SkDisplayType::RegisterNewType() {
+       gNewTypes = (SkDisplayTypes) (gNewTypes + 1);
+       return gNewTypes;
+}
+
+
+
+#ifdef SK_DEBUG
+const char* SkDisplayType::GetName(SkAnimateMaker* maker, SkDisplayTypes type) {
+       for (int index = 0; index < kTypeNamesSize - 1; index++) {
+               if (gTypeNames[index].fType == type)
+                       return gTypeNames[index].fName;
+       }
+       SkExtras** end = maker->fExtras.end();
+       for (SkExtras** extraPtr = maker->fExtras.begin(); extraPtr < end; extraPtr++) {
+               const char* result = (*extraPtr)->getName(type);
+               if (result != NULL)
+                       return result;
+       }
+       return NULL;
+}
+#endif
+
+#ifdef SK_SUPPORT_UNITTEST
+void SkDisplayType::UnitTest() {
+       SkAnimator animator;
+       SkAnimateMaker* maker = animator.fMaker;
+       int index;
+       for (index = 0; index < kTypeNamesSize - 1; index++) {
+               SkASSERT(strcmp(gTypeNames[index].fName, gTypeNames[index + 1].fName) < 0);
+               SkASSERT(gTypeNames[index].fType < gTypeNames[index + 1].fType);
+       }
+       for (index = 0; index < kTypeNamesSize; index++) {
+               SkDisplayable* test = CreateInstance(maker, gTypeNames[index].fType);
+               if (test == NULL)
+                       continue;
+#if defined _WIN32 && _MSC_VER >= 1300 && defined _INC_CRTDBG // only on windows, only if using "crtdbg.h"
+       // we know that crtdbg puts 0xfdfdfdfd at the end of the block
+       // look for unitialized memory, signature 0xcdcdcdcd prior to that
+               int* start = (int*) test;
+               while (*start != 0xfdfdfdfd) {
+                       SkASSERT(*start != 0xcdcdcdcd);
+                       start++;
+               }
+#endif
+               delete test;
+       }
+       for (index = 0; index < kTypeNamesSize; index++) {
+               int infoCount;
+               const SkMemberInfo* info = GetMembers(maker, gTypeNames[index].fType, &infoCount);
+               if (info == NULL)
+                       continue;
+#if SK_USE_CONDENSED_INFO == 0
+               for (int inner = 0; inner < infoCount - 1; inner++) {
+                       if (info[inner].fType == SkType_BaseClassInfo)
+                               continue;
+                       SkASSERT(strcmp(info[inner].fName, info[inner + 1].fName) < 0);
+               }
+#endif
+       }
+#if defined SK_DEBUG || defined SK_BUILD_CONDENSED
+       BuildCondensedInfo(maker);
+#endif
+}
+#endif
diff --git a/libs/graphics/animator/SkDisplayType.h b/libs/graphics/animator/SkDisplayType.h
new file mode 100644 (file)
index 0000000..d6c4a93
--- /dev/null
@@ -0,0 +1,198 @@
+#ifndef SkDisplayType_DEFINED
+#define SkDisplayType_DEFINED
+
+#include "SkMath.h"
+
+#ifdef SK_DEBUG
+    #ifdef SK_CAN_USE_FLOAT
+        #define SK_DUMP_ENABLED
+    #endif
+    #ifdef SK_BUILD_FOR_MAC
+        #define SK_FIND_LEAKS
+    #endif
+#endif
+
+#define SK_LITERAL_STR_EQUAL(str, token, len) (sizeof(str) - 1 == len \
+       && strncmp(str, token, sizeof(str) - 1) == 0)
+
+class SkAnimateMaker;
+class SkDisplayable;
+struct SkMemberInfo;
+
+enum SkDisplayTypes {
+       SkType_Unknown,
+       SkType_Math, // for ecmascript compatible Math functions and constants
+       SkType_Number,  // for for ecmascript compatible Number functions and constants
+       SkType_Add,
+       SkType_AddCircle,
+       SkType_AddGeom,
+       SkType_AddMode,
+       SkType_AddOval,
+       SkType_AddPath,
+       SkType_AddRect, // path part
+       SkType_AddRoundRect,
+       SkType_Align,
+       SkType_Animate,
+       SkType_AnimateBase,     // base type for animate, set
+       SkType_Apply,
+       SkType_ApplyMode,
+       SkType_ApplyTransition,
+       SkType_Array,
+       SkType_ARGB,
+       SkType_Base64,
+       SkType_BaseBitmap,
+       SkType_BaseClassInfo,
+       SkType_Bitmap,
+       SkType_BitmapEncoding,
+       SkType_BitmapFormat,
+       SkType_BitmapShader,
+       SkType_Blur,
+       SkType_Boolean, // can have values -1 (uninitialized), 0, 1
+       SkType_Boundable,
+       SkType_Bounds,
+       SkType_Cap,
+       SkType_Clear,
+       SkType_Clip,
+       SkType_Close,
+       SkType_Color,
+       SkType_CubicTo,
+       SkType_Dash,
+       SkType_Data,
+       SkType_Discrete,
+       SkType_Displayable,
+       SkType_Drawable,
+       SkType_DrawTo,
+       SkType_Dump,
+       SkType_DynamicString,   // evaluate at draw time
+       SkType_Emboss,
+       SkType_Event,
+       SkType_EventCode,
+       SkType_EventKind,
+       SkType_EventMode,
+       SkType_FillType,
+       SkType_FilterType,
+       SkType_Float,
+    SkType_FontStyle,
+       SkType_FromPath,
+       SkType_FromPathMode,
+       SkType_Full,
+       SkType_Gradient,
+       SkType_Group,
+       SkType_HitClear,
+       SkType_HitTest,
+       SkType_Image,
+       SkType_Include,
+       SkType_Input,
+       SkType_Int,
+       SkType_Join,
+       SkType_Line, // simple line primitive
+       SkType_LineTo, // used as part of path construction
+       SkType_LinearGradient,
+       SkType_MaskFilter,
+       SkType_MaskFilterBlurStyle,
+       SkType_MaskFilterLight,
+       SkType_Matrix,
+       SkType_MemberFunction,
+       SkType_MemberProperty,
+       SkType_Move,
+       SkType_MoveTo,
+       SkType_Movie,
+       SkType_MSec,
+       SkType_Oval,
+       SkType_Paint,
+       SkType_Path,
+       SkType_PathDirection,
+       SkType_PathEffect,
+       SkType_Point,   // used inside other structures, no vtable
+       SkType_DrawPoint, // used to draw points, has a vtable
+       SkType_PolyToPoly,
+       SkType_Polygon,
+       SkType_Polyline,
+       SkType_Post,
+       SkType_QuadTo,
+       SkType_RCubicTo,
+       SkType_RLineTo,
+       SkType_RMoveTo,
+       SkType_RQuadTo,
+       SkType_RadialGradient,
+       SkType_Random,
+       SkType_Rect,
+       SkType_RectToRect,
+       SkType_Remove,
+       SkType_Replace,
+       SkType_Rotate,
+       SkType_RoundRect,
+       SkType_Save,
+    SkType_SaveLayer,
+       SkType_Scale,
+       SkType_Screenplay,
+       SkType_Set,
+       SkType_Shader,
+       SkType_Skew,
+       SkType_3D_Camera,
+       SkType_3D_Patch,
+       SkType_3D_Point,
+       SkType_Snapshot,
+       SkType_String,  // pointer to SkString
+       SkType_Style,
+       SkType_Text,
+       SkType_TextBox,
+       SkType_TextBoxAlign,
+       SkType_TextBoxMode,
+       SkType_TextOnPath,
+       SkType_TextToPath,
+       SkType_TileMode,
+       SkType_Translate,
+       SkType_TransparentShader,
+       SkType_Typeface,
+       SkType_Xfermode,
+       kNumberOfTypes
+};
+
+struct TypeNames {
+       const char* fName;
+       SkDisplayTypes fType;
+#if defined SK_DEBUG || defined SK_BUILD_CONDENSED
+       bool fDrawPrefix;
+       bool fDisplayPrefix;
+#endif
+};
+
+#ifdef SK_DEBUG
+typedef SkDisplayTypes SkFunctionParamType;
+#else
+typedef unsigned char SkFunctionParamType;
+#endif
+
+extern const TypeNames gTypeNames[];
+extern const int kTypeNamesSize;
+
+class SkDisplayType {
+public:
+       static SkDisplayTypes Find(SkAnimateMaker* , const SkMemberInfo* );
+       static const SkMemberInfo* GetMember(SkAnimateMaker* , SkDisplayTypes , const char** );
+       static const SkMemberInfo* GetMembers(SkAnimateMaker* , SkDisplayTypes , int* infoCountPtr);
+       static SkDisplayTypes GetParent(SkAnimateMaker* , SkDisplayTypes );
+       static bool IsDisplayable(SkAnimateMaker* , SkDisplayTypes );
+       static bool IsEnum(SkAnimateMaker* , SkDisplayTypes );
+       static bool IsStruct(SkAnimateMaker* , SkDisplayTypes );
+       static SkDisplayTypes RegisterNewType();
+       static SkDisplayTypes Resolve(const char[] , const SkMemberInfo** );
+#ifdef SK_DEBUG
+       static bool IsAnimate(SkDisplayTypes type ) { return type == SkType_Animate || 
+               type == SkType_Set; }
+       static const char* GetName(SkAnimateMaker* , SkDisplayTypes );
+#endif
+#ifdef SK_SUPPORT_UNITTEST
+       static void UnitTest();
+#endif
+#if defined SK_DEBUG || defined SK_BUILD_CONDENSED
+       static void BuildCondensedInfo(SkAnimateMaker* );
+#endif
+       static SkDisplayTypes GetType(SkAnimateMaker* , const char[] , size_t len);
+       static SkDisplayable* CreateInstance(SkAnimateMaker* , SkDisplayTypes );
+private:
+       static SkDisplayTypes gNewTypes;
+};
+
+#endif // SkDisplayType_DEFINED
diff --git a/libs/graphics/animator/SkDisplayTypes.cpp b/libs/graphics/animator/SkDisplayTypes.cpp
new file mode 100644 (file)
index 0000000..b38a04c
--- /dev/null
@@ -0,0 +1,212 @@
+#include "SkDisplayTypes.h"
+#include "SkAnimateBase.h"
+
+bool SkDisplayDepend::canContainDependents() const {
+       return true; 
+}
+
+void SkDisplayDepend::dirty() {
+       SkDisplayable** last = fDependents.end();
+       for (SkDisplayable** depPtr = fDependents.begin(); depPtr < last; depPtr++) {
+               SkAnimateBase* animate = (SkAnimateBase* ) *depPtr;
+               animate->setChanged(true);
+       }
+}
+
+// Boolean
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDisplayBoolean::fInfo[] = {
+       SK_MEMBER(value, Boolean)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDisplayBoolean);
+
+SkDisplayBoolean::SkDisplayBoolean() : value(false) {
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkDisplayBoolean::dump(SkAnimateMaker* maker){
+       dumpBase(maker);
+       SkDebugf("value=\"%s\" />\n", value ? "true" : "false");
+}
+#endif
+
+// S32
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDisplayInt::fInfo[] = {
+       SK_MEMBER(value, Int)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDisplayInt);
+
+SkDisplayInt::SkDisplayInt() : value(0) {
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkDisplayInt::dump(SkAnimateMaker* maker){
+       dumpBase(maker);
+       SkDebugf("value=\"%d\" />\n", value);
+}
+#endif
+
+// SkScalar
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDisplayFloat::fInfo[] = {
+       SK_MEMBER(value, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDisplayFloat);
+
+SkDisplayFloat::SkDisplayFloat() : value(0) {
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkDisplayFloat::dump(SkAnimateMaker* maker) {
+       dumpBase(maker);
+#ifdef SK_CAN_USE_FLOAT
+       SkDebugf("value=\"%g\" />\n", SkScalarToFloat(value));
+#else
+       SkDebugf("value=\"%x\" />\n", value);
+#endif
+}
+#endif
+
+// SkString
+enum SkDisplayString_Functions {
+       SK_FUNCTION(slice)
+};
+
+enum SkDisplayString_Properties {
+       SK_PROPERTY(length)
+};
+
+const SkFunctionParamType SkDisplayString::fFunctionParameters[] = {
+       (SkFunctionParamType) SkType_Int,       // slice
+       (SkFunctionParamType) SkType_Int,
+       (SkFunctionParamType) 0
+};
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDisplayString::fInfo[] = {
+       SK_MEMBER_PROPERTY(length, Int),
+       SK_MEMBER_FUNCTION(slice, String),
+       SK_MEMBER(value, String)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDisplayString);
+
+SkDisplayString::SkDisplayString() {
+}
+
+SkDisplayString::SkDisplayString(SkString& copyFrom) : value(copyFrom) {
+}
+
+void SkDisplayString::executeFunction(SkDisplayable* target, int index, 
+               SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type,
+               SkScriptValue* scriptValue) {
+       if (scriptValue == nil)
+               return;
+       SkASSERT(target == this);
+       switch (index) {
+               case SK_FUNCTION(slice):
+                       scriptValue->fType = SkType_String;
+                       SkASSERT(parameters[0].fType == SkType_Int);
+                       int start =  parameters[0].fOperand.fS32;
+                       if (start < 0)
+                               start = (int) (value.size() - start);
+                       int end = (int) value.size();
+                       if (parameters.count() > 1) {
+                               SkASSERT(parameters[1].fType == SkType_Int);
+                               end = parameters[1].fOperand.fS32;
+                       }
+                       //if (end >= 0 && end < (int) value.size())
+                       if (end >= 0 && end <= (int) value.size())
+                               scriptValue->fOperand.fString = new SkString(&value.c_str()[start], end - start);
+                       else
+                               scriptValue->fOperand.fString = new SkString(value);
+               break;
+       }
+}
+
+const SkFunctionParamType* SkDisplayString::getFunctionsParameters() {
+       return fFunctionParameters;
+}
+
+bool SkDisplayString::getProperty(int index, SkScriptValue* scriptValue) const {
+       switch (index) { 
+               case SK_PROPERTY(length):
+                       scriptValue->fType = SkType_Int;
+                       scriptValue->fOperand.fS32 = (S32) value.size();
+                       break;
+               default:
+                       SkASSERT(0);
+                       return false;
+       }
+       return true;
+}
+
+
+// SkArray
+#if 0  // !!! reason enough to qualify enum with class name or move typedArray into its own file
+enum SkDisplayArray_Properties {
+       SK_PROPERTY(length)
+};
+#endif
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDisplayArray::fInfo[] = {
+       SK_MEMBER_PROPERTY(length, Int),
+       SK_MEMBER_ARRAY(values, Unknown)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDisplayArray);
+
+SkDisplayArray::SkDisplayArray() {
+}
+
+SkDisplayArray::SkDisplayArray(SkTypedArray& copyFrom) : values(copyFrom) {
+
+}
+
+SkDisplayArray::~SkDisplayArray() {
+       if (values.getType() == SkType_String) {
+               for (int index = 0; index < values.count(); index++)
+                       delete values[index].fString;
+               return;
+       }
+       if (values.getType() == SkType_Array) {
+               for (int index = 0; index < values.count(); index++)
+                       delete values[index].fArray;
+       }
+}
+
+bool SkDisplayArray::getProperty(int index, SkScriptValue* value) const {
+       switch (index) { 
+               case SK_PROPERTY(length):
+                       value->fType = SkType_Int;
+                       value->fOperand.fS32 = values.count();
+                       break;
+               default:
+                       SkASSERT(0);
+                       return false;
+       }
+       return true;
+}
+
+
+
diff --git a/libs/graphics/animator/SkDisplayTypes.h b/libs/graphics/animator/SkDisplayTypes.h
new file mode 100644 (file)
index 0000000..ce654ab
--- /dev/null
@@ -0,0 +1,98 @@
+#ifndef SkDisplayTypes_DEFINED
+#define SkDisplayTypes_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkMemberInfo.h"
+#include "SkTypedArray.h"
+
+class SkOpArray; // compiled script experiment
+
+
+class SkDisplayDepend : public SkDisplayable {
+public:
+       virtual bool canContainDependents() const;
+       void addDependent(SkDisplayable* displayable) {
+               if (fDependents.find(displayable) < 0)
+                       *fDependents.append() = displayable;
+       }
+       virtual void dirty();
+private:
+       SkTDDisplayableArray fDependents;
+       typedef SkDisplayable INHERITED;
+};
+
+class SkDisplayBoolean : public SkDisplayDepend {
+       DECLARE_DISPLAY_MEMBER_INFO(Boolean);
+       SkDisplayBoolean();
+#ifdef SK_DUMP_ENABLED
+       virtual void dump(SkAnimateMaker* );
+#endif
+       SkBool value;
+       friend class SkAnimatorScript;
+       friend class SkAnimatorScript_Box;
+       friend class SkAnimatorScript_Unbox;
+       typedef SkDisplayDepend INHERITED;
+};
+
+class SkDisplayInt : public SkDisplayDepend {
+       DECLARE_DISPLAY_MEMBER_INFO(Int);
+       SkDisplayInt();
+#ifdef SK_DUMP_ENABLED
+       virtual void dump(SkAnimateMaker* );
+#endif
+private:
+       S32 value;
+       friend class SkAnimatorScript;
+       friend class SkAnimatorScript_Box;
+       friend class SkAnimatorScript_Unbox;
+       typedef SkDisplayDepend INHERITED;
+};
+
+class SkDisplayFloat : public SkDisplayDepend {
+       DECLARE_DISPLAY_MEMBER_INFO(Float);
+       SkDisplayFloat();
+#ifdef SK_DUMP_ENABLED
+       virtual void dump(SkAnimateMaker* );
+#endif
+private:
+       SkScalar value;
+       friend class SkAnimatorScript;
+       friend class SkAnimatorScript_Box;
+       friend class SkAnimatorScript_Unbox;
+       typedef SkDisplayDepend INHERITED;
+};
+
+class SkDisplayString : public SkDisplayDepend {
+       DECLARE_DISPLAY_MEMBER_INFO(String);
+       SkDisplayString();
+       SkDisplayString(SkString& );
+       virtual void executeFunction(SkDisplayable* , int index, 
+               SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type,
+               SkScriptValue* );
+       virtual const SkFunctionParamType* getFunctionsParameters();
+       virtual bool getProperty(int index, SkScriptValue* ) const;
+       SkString value;
+private:
+       static const SkFunctionParamType fFunctionParameters[];
+};
+
+class SkDisplayArray : public SkDisplayDepend {
+       DECLARE_DISPLAY_MEMBER_INFO(Array);
+       SkDisplayArray();
+       SkDisplayArray(SkTypedArray& );
+       SkDisplayArray(SkOpArray& ); // compiled script experiment
+       virtual ~SkDisplayArray();
+       virtual bool getProperty(int index, SkScriptValue* ) const;
+private:
+       SkTypedArray values;
+    friend class SkAnimator;
+       friend class SkAnimatorScript;
+       friend class SkAnimatorScript2;
+       friend class SkAnimatorScript_Unbox;
+       friend class SkDisplayable;
+       friend struct SkMemberInfo;
+       friend class SkScriptEngine;
+};
+
+#endif // SkDisplayTypes_DEFINED
+
diff --git a/libs/graphics/animator/SkDisplayXMLParser.cpp b/libs/graphics/animator/SkDisplayXMLParser.cpp
new file mode 100644 (file)
index 0000000..fd4840a
--- /dev/null
@@ -0,0 +1,301 @@
+#include "SkDisplayXMLParser.h"
+#include "SkAnimateMaker.h"
+#include "SkDisplayApply.h"
+#include "SkUtils.h"
+#ifdef SK_DEBUG
+#include "SkTime.h"
+#endif
+
+static char const* const gErrorStrings[] = {
+       "unknown error ",
+    "apply scopes itself",
+       "display tree too deep (circular reference?) ",
+       "element missing parent ",
+       "element type not allowed in parent ",
+       "error adding <data> to <post> ",
+       "error adding to <matrix> ",
+       "error adding to <paint> ",
+       "error adding to <path> ",
+       "error in attribute value ",
+       "error in script ",
+       "expected movie in sink attribute ",
+       "field not in target ",
+    "number of offsets in gradient must match number of colors",
+    "no offset in gradient may be greater than one",
+    "last offset in gradient must be one",
+    "offsets in gradient must be increasing",
+    "first offset in gradient must be zero",
+    "gradient attribute \"points\" must have length of four", 
+       "in include ",
+       "in movie ",
+       "include name unknown or missing ",
+       "index out of range ",
+       "movie name unknown or missing ",
+       "no parent available to resolve sink attribute ",
+       "parent element can't contain ",
+    "saveLayer must specify a bounds",
+       "target id not found ",
+       "unexpected type "
+};
+
+SkDisplayXMLParserError::~SkDisplayXMLParserError() {
+}
+
+void SkDisplayXMLParserError::getErrorString(SkString* str) const {
+       if (fCode > kUnknownError)
+               str->set(gErrorStrings[fCode - kUnknownError]);
+       else
+               str->reset();
+       INHERITED::getErrorString(str);
+}
+
+void SkDisplayXMLParserError::setInnerError(SkAnimateMaker* parent, const SkString& src) {
+       SkString inner;
+       getErrorString(&inner);
+       inner.prepend(": ");
+       inner.prependS32(getLineNumber());
+       inner.prepend(", line ");
+       inner.prepend(src);
+       parent->setErrorNoun(inner);
+}
+
+
+SkDisplayXMLParser::SkDisplayXMLParser(SkAnimateMaker& maker)
+       : INHERITED(&maker.fError), fMaker(maker), fInInclude(maker.fInInclude), 
+               fInSkia(maker.fInInclude), fCurrDisplayable(nil)
+{
+}
+
+SkDisplayXMLParser::~SkDisplayXMLParser() {
+       if (fCurrDisplayable && fMaker.fChildren.find(fCurrDisplayable) < 0)
+               delete fCurrDisplayable;
+       for (Parent* parPtr = fParents.begin() + 1; parPtr < fParents.end(); parPtr++) {
+               SkDisplayable* displayable = parPtr->fDisplayable;
+               if (displayable == fCurrDisplayable)
+                       continue;
+               SkASSERT(fMaker.fChildren.find(displayable) < 0);
+               if (fMaker.fHelpers.find(displayable) < 0)
+                       delete displayable;
+       }
+}
+
+
+
+bool SkDisplayXMLParser::onAddAttribute(const char name[], const char value[]) {
+       return onAddAttributeLen(name, value, strlen(value));
+}
+
+bool SkDisplayXMLParser::onAddAttributeLen(const char attrName[], const char attrValue[], 
+                                                                               size_t attrValueLen)
+{
+       if (fCurrDisplayable == nil)    // this signals we should ignore attributes for this element
+               return strncmp(attrName, "xmlns", sizeof("xmlns") - 1) != 0;
+       SkDisplayable*  displayable = fCurrDisplayable;
+       SkDisplayTypes  type = fCurrType;
+
+       if (strcmp(attrName, "id") == 0) {
+               if (fMaker.find(attrValue, attrValueLen, nil)) {
+                       fError->setNoun(attrValue, attrValueLen);
+                       fError->setCode(SkXMLParserError::kDuplicateIDs);
+                       return true;
+               }
+#ifdef SK_DEBUG
+               displayable->_id.set(attrValue, attrValueLen);
+               displayable->id = displayable->_id.c_str();
+#endif
+               fMaker.idsSet(attrValue, attrValueLen, displayable);
+               int parentIndex = fParents.count() - 1;
+               if (parentIndex > 0) {
+                       SkDisplayable* parent = fParents[parentIndex - 1].fDisplayable;
+                       parent->setChildHasID();
+               }
+               return false;
+       }
+       const char* name = attrName;
+       const SkMemberInfo* info = SkDisplayType::GetMember(&fMaker, type, &name);
+       if (info == nil) {
+               fError->setNoun(name);
+               fError->setCode(SkXMLParserError::kUnknownAttributeName);
+               return true;
+       }
+       if (info->setValue(fMaker, nil, 0, info->getCount(), displayable, info->getType(), attrValue,
+                       attrValueLen))
+               return false;
+       if (fMaker.fError.hasError()) {
+               fError->setNoun(attrValue, attrValueLen);
+               return true;
+       }
+       SkDisplayable* ref = nil;
+       if (fMaker.find(attrValue, attrValueLen, &ref) == false) {
+               ref = fMaker.createInstance(attrValue, attrValueLen);
+               if (ref == nil) {
+                       fError->setNoun(attrValue, attrValueLen);
+                       fError->setCode(SkXMLParserError::kErrorInAttributeValue);
+                       return true;
+               } else
+                       fMaker.helperAdd(ref);
+       }
+       if (info->fType != SkType_MemberProperty) {
+               fError->setNoun(name);
+               fError->setCode(SkXMLParserError::kUnknownAttributeName);
+               return true;
+       }
+       SkScriptValue scriptValue;
+       scriptValue.fOperand.fDisplayable = ref;
+       scriptValue.fType = ref->getType();
+       displayable->setProperty(info->propertyIndex(), scriptValue);
+       return false;
+}
+
+bool SkDisplayXMLParser::onEndElement(const char elem[])
+{
+       int parentIndex = fParents.count() - 1;
+       if (parentIndex >= 0) {
+               Parent& container = fParents[parentIndex];
+               SkDisplayable* displayable = container.fDisplayable;
+               fMaker.fEndDepth = parentIndex;
+               displayable->onEndElement(fMaker);
+               if (fMaker.fError.hasError()) 
+                       return true;
+               if (parentIndex > 0) {
+                       SkDisplayable* parent = fParents[parentIndex - 1].fDisplayable;
+                       bool result = parent->add(fMaker, displayable);
+                       if (fMaker.hasError()) 
+                               return true;
+                       if (result == false) {
+                               int infoCount;
+                               const SkMemberInfo* info = 
+                                       SkDisplayType::GetMembers(&fMaker, fParents[parentIndex - 1].fType, &infoCount);
+                               const SkMemberInfo* foundInfo;
+                               if ((foundInfo = searchContainer(info, infoCount)) != nil) {
+                                       parent->setReference(foundInfo, displayable);
+               //                      if (displayable->isHelper() == false)
+                                               fMaker.helperAdd(displayable);
+                               } else {
+                                       fMaker.setErrorCode(SkDisplayXMLParserError::kElementTypeNotAllowedInParent);
+                                       return true;
+                               }
+                       }
+                       if (parent->childrenNeedDisposing())
+                               delete displayable;
+               }
+               fParents.remove(parentIndex);
+       }
+       fCurrDisplayable = nil;
+       if (fInInclude == false && strcasecmp(elem, "screenplay") == 0) {
+               if (fMaker.fInMovie == false) {
+                       fMaker.fEnableTime = fMaker.getAppTime();
+#if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
+                       if (fMaker.fDebugTimeBase == (SkMSec) -1)
+                               fMaker.fDebugTimeBase = fMaker.fEnableTime;
+                       SkString debugOut;
+                       SkMSec time = fMaker.getAppTime();
+                       debugOut.appendS32(time - fMaker.fDebugTimeBase);
+                       debugOut.append(" onLoad enable=");
+                       debugOut.appendS32(fMaker.fEnableTime - fMaker.fDebugTimeBase);
+                       SkDebugf("%s\n", debugOut.c_str());
+#endif
+                       fMaker.fEvents.doEvent(fMaker, SkDisplayEvent::kOnload, nil);
+                       if (fMaker.fError.hasError()) 
+                               return true;
+                       fMaker.fEvents.removeEvent(SkDisplayEvent::kOnload, nil);
+
+               }
+               fInSkia = false;
+       }
+       return false;
+}
+
+bool SkDisplayXMLParser::onStartElement(const char name[])
+{
+       return onStartElementLen(name, strlen(name));
+}
+
+bool SkDisplayXMLParser::onStartElementLen(const char name[], size_t len) {
+       fCurrDisplayable = nil; // init so we'll ignore attributes if we exit early
+
+       if (strncasecmp(name, "screenplay", len) == 0) {
+               fInSkia = true;
+               if (fInInclude == false)
+                       fMaker.idsSet(name, len, &fMaker.fScreenplay);
+               return false;
+       }
+       if (fInSkia == false)
+               return false;
+
+       SkDisplayable* displayable = fMaker.createInstance(name, len);
+       if (displayable == nil) {
+               fError->setNoun(name, len);
+               fError->setCode(SkXMLParserError::kUnknownElement);
+               return true;
+       }
+       SkDisplayTypes type = displayable->getType();
+       Parent record = { displayable, type };
+       *fParents.append() = record;
+       if (fParents.count() == 1)
+               fMaker.childrenAdd(displayable);
+       else {
+               Parent* parent = fParents.end() - 2;
+               if (displayable->setParent(parent->fDisplayable)) {
+                       fError->setNoun(name, len);
+                       getError()->setCode(SkDisplayXMLParserError::kParentElementCantContain);
+                       return true;
+               }
+       }
+
+       // set these for subsequent calls to addAttribute()
+       fCurrDisplayable = displayable;
+       fCurrType = type;
+       return false;
+}
+
+const SkMemberInfo* SkDisplayXMLParser::searchContainer(const SkMemberInfo* infoBase,
+                                                                                                                int infoCount) {
+       const SkMemberInfo* bestDisplayable = nil;
+       const SkMemberInfo* lastResort = nil;
+       for (int index = 0; index < infoCount; index++) {
+               const SkMemberInfo* info = &infoBase[index];
+               if (info->fType == SkType_BaseClassInfo) {
+                       const SkMemberInfo* inherited = info->getInherited();
+                       const SkMemberInfo* result = searchContainer(inherited, info->fCount);
+                       if (result != nil)
+                               return result;
+                       continue;
+               }
+               Parent* container = fParents.end() - 1;
+               SkDisplayTypes type = (SkDisplayTypes) info->fType;
+               if (type == SkType_MemberProperty) 
+                       type = info->propertyType();
+               SkDisplayTypes containerType = container->fType;
+               if (type == containerType && (type == SkType_Rect || type == SkType_Polygon ||
+                       type == SkType_Array || type == SkType_Int || type == SkType_Bitmap))
+                       goto rectNext;
+               while (type != containerType) {
+                       if (containerType == SkType_Displayable)
+                               goto next;
+                       containerType = SkDisplayType::GetParent(&fMaker, containerType);
+                       if (containerType == SkType_Unknown)
+                               goto next;
+               }
+               return info;
+next:
+               if (type == SkType_Drawable || type == SkType_Displayable && 
+                       container->fDisplayable->isDrawable()) {
+rectNext:
+                       if (fParents.count() > 1) {
+                               Parent* parent = fParents.end() - 2;
+                               if (info == parent->fDisplayable->preferredChild(type))
+                                       bestDisplayable = info;
+                               else
+                                       lastResort = info;
+                       }
+               }
+       }
+       if (bestDisplayable)
+               return bestDisplayable;
+       if (lastResort)
+               return lastResort;
+       return nil;
+}
+
+
diff --git a/libs/graphics/animator/SkDisplayXMLParser.h b/libs/graphics/animator/SkDisplayXMLParser.h
new file mode 100644 (file)
index 0000000..3aa42cf
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef SkDisplayXMLParser_DEFINED
+#define SkDisplayXMLParser_DEFINED
+
+#include "SkIntArray.h"
+#include "SkTDict.h"
+#include "SkDisplayType.h"
+#include "SkXMLParser.h"
+
+class SkAnimateMaker;
+class SkDisplayable;
+
+class SkDisplayXMLParserError : public SkXMLParserError {
+public:
+       enum ErrorCode {
+        kApplyScopesItself = kUnknownError + 1,
+               kDisplayTreeTooDeep,
+               kElementMissingParent,
+               kElementTypeNotAllowedInParent,
+               kErrorAddingDataToPost,
+               kErrorAddingToMatrix,
+               kErrorAddingToPaint,
+               kErrorAddingToPath,
+               kErrorInAttributeValue,
+               kErrorInScript,
+               kExpectedMovie,
+               kFieldNotInTarget,
+        kGradientOffsetsDontMatchColors,
+        kGradientOffsetsMustBeNoMoreThanOne,
+        kGradientOffsetsMustEndWithOne,
+        kGradientOffsetsMustIncrease,
+        kGradientOffsetsMustStartWithZero,
+        kGradientPointsLengthMustBeFour,
+               kInInclude,
+               kInMovie,
+               kIncludeNameUnknownOrMissing,
+               kIndexOutOfRange,
+               kMovieNameUnknownOrMissing,
+               kNoParentAvailable,
+               kParentElementCantContain,
+        kSaveLayerNeedsBounds,
+               kTargetIDNotFound,
+               kUnexpectedType
+       };
+       virtual ~SkDisplayXMLParserError();
+       virtual void getErrorString(SkString* str) const;
+       void setCode(ErrorCode code) { INHERITED::setCode((INHERITED::ErrorCode) code); }
+       void setInnerError(SkAnimateMaker* maker, const SkString& str);
+       typedef SkXMLParserError INHERITED;
+       friend class SkDisplayXMLParser;
+};
+
+class SkDisplayXMLParser : public SkXMLParser {
+public:
+       SkDisplayXMLParser(SkAnimateMaker& maker);
+       virtual ~SkDisplayXMLParser();
+protected:
+       virtual bool onAddAttribute(const char name[], const char value[]);
+       bool onAddAttributeLen(const char name[], const char value[], size_t len);
+       virtual bool onEndElement(const char elem[]);
+       virtual bool onStartElement(const char elem[]);
+       bool onStartElementLen(const char elem[], size_t len);
+private:
+       struct Parent {
+               SkDisplayable* fDisplayable;
+               SkDisplayTypes fType;
+       };
+       SkTDArray<Parent> fParents;
+       SkDisplayXMLParser& operator= (const SkDisplayXMLParser& );
+       SkDisplayXMLParserError* getError() { return (SkDisplayXMLParserError*) fError; }
+       const SkMemberInfo* searchContainer(const SkMemberInfo* ,
+               int infoCount);
+       SkAnimateMaker& fMaker;
+       SkBool fInInclude;
+       SkBool fInSkia;
+       // local state between onStartElement and onAddAttribute
+       SkDisplayable*  fCurrDisplayable;
+       SkDisplayTypes  fCurrType;
+       friend class SkXMLAnimatorWriter;
+       typedef SkXMLParser INHERITED;
+};
+
+#endif // SkDisplayXMLParser_DEFINED
+
+
diff --git a/libs/graphics/animator/SkDisplayable.cpp b/libs/graphics/animator/SkDisplayable.cpp
new file mode 100644 (file)
index 0000000..41c4b47
--- /dev/null
@@ -0,0 +1,549 @@
+#include "SkDisplayable.h"
+#include "SkDisplayApply.h"
+#include "SkParse.h"
+#ifdef SK_DEBUG
+#include "SkDisplayList.h"
+#endif
+#include "SkDisplayTypes.h"
+
+#ifdef SK_FIND_LEAKS
+// int SkDisplayable::fAllocationCount;
+SkTDDisplayableArray SkDisplayable::fAllocations;
+#endif
+
+#ifdef SK_DEBUG
+SkDisplayable::SkDisplayable() { 
+       id = _id.c_str();
+#ifdef SK_FIND_LEAKS
+       // fAllocationCount++;
+       *fAllocations.append() = this;
+#endif
+}
+#endif
+
+SkDisplayable::~SkDisplayable() {
+#ifdef SK_FIND_LEAKS
+    // fAllocationCount--;
+       int index = fAllocations.find(this);
+       SkASSERT(index >= 0);
+       fAllocations.remove(index);
+#endif
+}
+
+bool SkDisplayable::add(SkAnimateMaker& , SkDisplayable* child) {
+       return false; 
+}
+
+//void SkDisplayable::apply(SkAnimateMaker& , const SkMemberInfo* , 
+//             SkDisplayable* , SkScalar [], int count) { 
+//     SkASSERT(0); 
+//}
+
+bool SkDisplayable::canContainDependents() const {
+       return false; 
+}
+bool SkDisplayable::childrenNeedDisposing() const { 
+       return false; 
+}
+
+void SkDisplayable::clearBounder() {
+}
+
+bool SkDisplayable::contains(SkDisplayable* ) {
+       return false;
+}
+
+SkDisplayable* SkDisplayable::contains(const SkString& ) {
+       return nil;
+}
+
+SkDisplayable* SkDisplayable::deepCopy(SkAnimateMaker* maker) {
+       SkDisplayTypes type = getType();
+       if (type == SkType_Unknown) {
+               SkASSERT(0);
+               return nil;
+       }
+       SkDisplayable* copy = SkDisplayType::CreateInstance(maker, type);
+       int index = -1;
+       int propIndex = 0;
+       const SkMemberInfo* info;
+       do {
+               info = copy->getMember(++index);
+               if (info == nil)
+                       break;
+               if (info->fType == SkType_MemberProperty) {
+                       SkScriptValue value;
+                       if (getProperty(propIndex, &value))
+                               copy->setProperty(propIndex, value);
+                       propIndex++;
+                       continue;
+               }
+               if (info->fType == SkType_MemberFunction)
+                       continue;
+               if (info->fType == SkType_Array) {
+                       SkTDOperandArray* array = (SkTDOperandArray*) info->memberData(this);
+                       int arrayCount;
+                       if (array == nil || (arrayCount = array->count()) == 0)
+                               continue;
+                       SkTDOperandArray* copyArray = (SkTDOperandArray*) info->memberData(copy);
+                       copyArray->setCount(arrayCount);
+                       SkDisplayTypes elementType;
+                       if (type == SkType_Array) {
+                               SkDisplayArray* dispArray = (SkDisplayArray*) this;
+                               elementType = dispArray->values.getType();
+                       } else
+                               elementType = info->arrayType();
+                       size_t elementSize = SkMemberInfo::GetSize(elementType);
+                       size_t byteSize = elementSize * arrayCount;
+                       memcpy(copyArray->begin(), array->begin(), byteSize);
+                       continue;
+               }
+               if (SkDisplayType::IsDisplayable(maker, info->fType)) {
+                       SkDisplayable** displayable = (SkDisplayable**) info->memberData(this);
+                       if (*displayable == nil || *displayable == (SkDisplayable*) -1)
+                               continue;
+                       SkDisplayable* deeper = (*displayable)->deepCopy(maker);
+                       info->setMemberData(copy, deeper, sizeof(deeper));
+                       continue;
+               }
+               if (info->fType == SkType_String || info->fType == SkType_DynamicString) {
+                       SkString* string;
+                       info->getString(this, &string);
+                       info->setString(copy, string);
+                       continue;
+               }
+               void* data = info->memberData(this);
+               size_t size = SkMemberInfo::GetSize(info->fType);
+               info->setMemberData(copy, data, size);
+       } while (true);
+       copy->dirty();
+       return copy;
+}
+
+void SkDisplayable::dirty() {
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkDisplayable::dump(SkAnimateMaker* maker) {
+       dumpBase(maker);
+#if SK_USE_CONDENSED_INFO == 0
+    this->dumpAttrs(maker);
+    this->dumpChildren(maker);
+#endif
+}
+
+void SkDisplayable::dumpAttrs(SkAnimateMaker* maker) {
+    SkDisplayTypes type = getType();
+       if (type == SkType_Unknown) {
+               //SkDebugf("/>\n");
+               return;
+       }
+       SkDisplayable* blankCopy = SkDisplayType::CreateInstance(maker, type);
+
+    int index = -1;
+    int propIndex = 0;
+    const SkMemberInfo* info;
+    const SkMemberInfo* blankInfo;
+    SkScriptValue value;
+    SkScriptValue blankValue;
+    SkOperand values[2];
+    SkOperand blankValues[2];
+    do {
+        info = this->getMember(++index);
+        if (nil == info) {
+            //SkDebugf("\n");
+            break;
+        }
+        if (SkType_MemberProperty == info->fType) {
+            if (getProperty(propIndex, &value)) {
+                blankCopy->getProperty(propIndex, &blankValue);
+                //last two are dummies
+                dumpValues(info, value.fType, value.fOperand, blankValue.fOperand, value.fOperand, blankValue.fOperand);
+                }
+            
+            propIndex++;
+            continue;
+        }
+        if (SkDisplayType::IsDisplayable(maker, info->fType)) {
+            continue;
+        }
+        
+        if (info->fType == SkType_MemberFunction)
+            continue;
+            
+            
+        if (info->fType == SkType_Array) {
+            SkTDOperandArray* array = (SkTDOperandArray*) info->memberData(this);
+                       int arrayCount;
+                       if (array == nil || (arrayCount = array->count()) == 0)
+                               continue;
+                       SkDisplayTypes elementType;
+                       if (type == SkType_Array) {
+                               SkDisplayArray* dispArray = (SkDisplayArray*) this;
+                               elementType = dispArray->values.getType();
+                       } else
+                               elementType = info->arrayType();
+            bool firstElem = true;
+            SkDebugf("%s=\"[", info->fName);
+            for (SkOperand* op = array->begin(); op < array->end(); op++) {
+                if (!firstElem) SkDebugf(",");
+                switch (elementType) {
+                        case SkType_Displayable:
+                            SkDebugf("%s", op->fDisplayable->id);
+                            break;
+                        case SkType_Int:                            
+                            SkDebugf("%d", op->fS32);
+                            break;
+                        case SkType_Float:
+#ifdef SK_CAN_USE_FLOAT
+                            SkDebugf("%g", SkScalarToFloat(op->fScalar));
+#else
+                            SkDebugf("%x", op->fScalar);
+#endif
+                            break;
+                        case SkType_String:
+                        case SkType_DynamicString:    
+                            SkDebugf("%s", op->fString->c_str());
+                            break;
+                        default:
+                            break;
+                }
+                firstElem = false;
+            }
+            SkDebugf("]\" ");
+            continue;
+        }
+        
+        if (info->fType == SkType_String || info->fType == SkType_DynamicString) {
+            SkString* string;
+            info->getString(this, &string);
+            if (string->isEmpty() == false)
+                SkDebugf("%s=\"%s\"\t", info->fName, string->c_str()); 
+            continue;
+        }
+        
+        
+        blankInfo = blankCopy->getMember(index);
+        int i = info->fCount;
+        info->getValue(this, values, i);
+        blankInfo->getValue(blankCopy, blankValues, i);
+        dumpValues(info, info->fType, values[0], blankValues[0], values[1], blankValues[1]);
+    } while (true);
+    delete blankCopy;
+}
+
+void SkDisplayable::dumpBase(SkAnimateMaker* maker) {
+    SkDisplayTypes type = getType();
+       const char* elementName = "(unknown)";
+       if (type != SkType_Unknown && type != SkType_Screenplay)
+               elementName = SkDisplayType::GetName(maker, type);
+       SkDebugf("%*s", SkDisplayList::fIndent, "");
+       if (SkDisplayList::fDumpIndex != 0 && SkDisplayList::fIndent == 0)
+               SkDebugf("%d: ", SkDisplayList::fDumpIndex);
+       SkDebugf("<%s ", elementName);
+    if (strcmp(id,"") != 0)
+        SkDebugf("id=\"%s\" ", id);
+}
+
+void SkDisplayable::dumpChildren(SkAnimateMaker* maker, bool closedAngle) {
+    
+    int index = -1;
+    const SkMemberInfo* info;
+    index = -1;
+    SkDisplayList::fIndent += 4;
+    do {
+        info = this->getMember(++index);
+        if (nil == info) {
+            break;
+        }
+        if (SkDisplayType::IsDisplayable(maker, info->fType)) {
+            SkDisplayable** displayable = (SkDisplayable**) info->memberData(this);
+            if (*displayable == nil || *displayable == (SkDisplayable*) -1)
+                continue;
+            if (closedAngle == false) {
+                SkDebugf(">\n");
+                closedAngle = true;
+            }
+            (*displayable)->dump(maker);
+        }
+    } while (true);
+    SkDisplayList::fIndent -= 4;
+    if (closedAngle)
+        dumpEnd(maker);
+    else
+        SkDebugf("/>\n");
+}
+
+void SkDisplayable::dumpEnd(SkAnimateMaker* maker) {
+    SkDisplayTypes type = getType();
+       const char* elementName = "(unknown)";
+       if (type != SkType_Unknown && type != SkType_Screenplay)
+               elementName = SkDisplayType::GetName(maker, type);
+       SkDebugf("%*s", SkDisplayList::fIndent, "");
+       SkDebugf("</%s>\n", elementName);
+}
+
+void SkDisplayable::dumpEvents() {
+}
+
+void SkDisplayable::dumpValues(const SkMemberInfo* info, SkDisplayTypes type, SkOperand op, SkOperand blankOp,
+    SkOperand op2, SkOperand blankOp2) {
+    switch (type) {
+    case SkType_BitmapEncoding:
+        switch (op.fS32) {
+            case 0 : SkDebugf("type=\"jpeg\" ");
+                break;
+            case 1 : SkDebugf("type=\"png\" ");
+                break;
+            default: SkDebugf("type=\"UNDEFINED\" ");
+        }
+        break;
+    //should make this a separate case in dump attrs, rather than make dump values have a larger signature
+    case SkType_Point:
+        if (op.fScalar != blankOp.fScalar || op2.fScalar != blankOp.fScalar) {
+#ifdef SK_CAN_USE_FLOAT
+            SkDebugf("%s=\"[%g,%g]\" ", info->fName, SkScalarToFloat(op.fScalar), SkScalarToFloat(op2.fScalar));
+#else
+            SkDebugf("%s=\"[%x,%x]\" ", info->fName, op.fScalar, op2.fScalar);
+#endif
+        }
+        break;
+    case SkType_FromPathMode:
+        switch (op.fS32) {
+            case 0:
+                //don't want to print anything for 0, just adding it to remove it from default:
+                break;
+            case 1:
+                SkDebugf("%s=\"%s\" ", info->fName, "angle");
+                break;
+            case 2:
+                SkDebugf("%s=\"%s\" ", info->fName, "position");
+                break;
+            default:
+                SkDebugf("%s=\"INVALID\" ", info->fName);
+        }
+        break;
+    case SkType_MaskFilterBlurStyle:
+        switch (op.fS32) {
+            case 0:
+                break;
+            case 1:
+                SkDebugf("%s=\"%s\" ", info->fName, "solid");
+                break;
+            case 2:
+                SkDebugf("%s=\"%s\" ", info->fName, "outer");
+                break;
+            case 3:
+                SkDebugf("%s=\"%s\" ", info->fName, "inner");
+                break;
+            default:
+                SkDebugf("%s=\"INVALID\" ", info->fName);
+        }
+        break;
+    case SkType_FilterType:
+        if (op.fS32 == 1)
+            SkDebugf("%s=\"%s\" ", info->fName, "bilinear");
+        break;
+    case SkType_PathDirection:
+        SkDebugf("%s=\"%s\" ", info->fName, op.fS32 == 0 ? "cw" : "ccw");
+        break;
+    case SkType_FillType:
+        SkDebugf("%s=\"%s\" ", info->fName, op.fS32 == 0 ? "winding" : "evenOdd");
+        break;
+    case SkType_TileMode:
+        //correct to look at the S32?
+        if (op.fS32 != blankOp.fS32) 
+            SkDebugf("%s=\"%s\" ", info->fName, op.fS32 == 0 ? "clamp" : op.fS32 == 1 ? "repeat" : "mirror");
+        break;
+    case SkType_Boolean:
+        if (op.fS32 != blankOp.fS32)
+            SkDebugf("%s=\"%s\" ", info->fName, op.fS32 == 0 ? "false" : "true");
+        break;
+    case SkType_Int:
+        if (op.fS32 != blankOp.fS32)
+            SkDebugf(" %s=\"%d\"  ", info->fName, op.fS32);
+        break;
+    case SkType_Float:
+        if (op.fScalar != blankOp.fScalar) { //or /65536?
+#ifdef SK_CAN_USE_FLOAT
+            SkDebugf("%s=\"%g\"  ", info->fName, SkScalarToFloat(op.fScalar));
+#else
+            SkDebugf("%s=\"%x\"  ", info->fName, op.fScalar);
+#endif
+        }
+        break;
+    case SkType_String:
+    case SkType_DynamicString:
+        if (op.fString->size() > 0) 
+            SkDebugf("%s=\"%s\" ", info->fName, op.fString->c_str());
+        break;
+    case SkType_MSec:
+        if (op.fS32 != blankOp.fS32) {
+#ifdef SK_CAN_USE_FLOAT
+            SkDebugf(" %s=\"%g\"  ", info->fName, SkScalarToFloat(SkScalarDiv(op.fS32, 1000)));
+#else
+            SkDebugf(" %s=\"%x\"  ", info->fName, SkScalarDiv(op.fS32, 1000));
+#endif
+        }
+    default:
+        SkDebugf("");
+    }    
+}
+
+#endif
+
+bool SkDisplayable::enable( SkAnimateMaker& ) { 
+       return false;
+}
+
+void SkDisplayable::enableBounder() {
+}
+
+void SkDisplayable::executeFunction(SkDisplayable* , int index, 
+               SkTDArray<SkScriptValue>& , SkDisplayTypes, SkScriptValue*  ) {
+       SkASSERT(0); 
+}
+
+void SkDisplayable::executeFunction(SkDisplayable* target, 
+               const SkMemberInfo* info, SkTypedArray* values, SkScriptValue* value) {
+       SkTDArray<SkScriptValue> typedValues;
+       for (SkOperand* op = values->begin(); op < values->end(); op++) {
+               SkScriptValue temp;
+               temp.fType = values->getType();
+               temp.fOperand = *op;
+               *typedValues.append() = temp;
+       }
+       executeFunction(target, info->functionIndex(), typedValues, info->getType(), value);
+}
+
+void SkDisplayable::executeFunction2(SkDisplayable* , int index, 
+               SkOpArray* params, SkDisplayTypes, SkOperand2*  ) {
+       SkASSERT(0); 
+}
+
+void SkDisplayable::getBounds(SkRect* rect) {
+       SkASSERT(rect);
+       rect->fLeft = rect->fTop = SK_ScalarMax;
+       rect->fRight= rect->fBottom = -SK_ScalarMax;
+}
+
+const SkFunctionParamType* SkDisplayable::getFunctionsParameters() {
+       return nil;
+}
+
+const SkMemberInfo* SkDisplayable::getMember(int index) { 
+       return nil; 
+}
+
+const SkMemberInfo* SkDisplayable::getMember(const char name[]) { 
+       return nil; 
+}
+
+const SkFunctionParamType* SkDisplayable::getParameters(const SkMemberInfo* info, 
+               int* paramCount) {
+       const SkFunctionParamType* params = getFunctionsParameters();
+       SkASSERT(params != nil);
+       int funcIndex = info->functionIndex();
+       // !!! eventually break traversing params into an external function (maybe this whole function)
+       int index = funcIndex;
+       int offset = 0;
+       while (--index >= 0) {
+               while (params[offset] != 0)
+                       offset++;
+               offset++;
+       }
+       int count = 0;
+       while (params[offset] != 0) {
+               count++;
+               offset++;
+       }
+       *paramCount = count;
+       return &params[offset - count];
+}
+
+SkDisplayable* SkDisplayable::getParent() const {
+       return nil;
+}
+
+bool SkDisplayable::getProperty(int index, SkScriptValue* ) const {
+//     SkASSERT(0); 
+       return false; 
+}
+
+bool SkDisplayable::getProperty2(int index, SkOperand2* value) const {
+       SkASSERT(0); 
+       return false; 
+}
+
+SkDisplayTypes SkDisplayable::getType() const { 
+       return SkType_Unknown; 
+}
+
+bool SkDisplayable::hasEnable() const {
+       return false;
+}
+
+bool SkDisplayable::isDrawable() const {
+       return false; 
+}
+
+void SkDisplayable::onEndElement(SkAnimateMaker& ) {}
+
+const SkMemberInfo* SkDisplayable::preferredChild(SkDisplayTypes type) {
+       return nil;
+}
+
+bool SkDisplayable::resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* apply) {
+       return false;
+}
+
+//SkDisplayable* SkDisplayable::resolveTarget(SkAnimateMaker& ) { 
+//     return this; 
+//}
+
+void SkDisplayable::setChildHasID() {
+}
+
+bool SkDisplayable::setParent(SkDisplayable* ) {
+       return false;
+}
+
+bool SkDisplayable::setProperty(int index, SkScriptValue& ) {
+       //SkASSERT(0); 
+       return false; 
+}
+
+void SkDisplayable::setReference(const SkMemberInfo* info, SkDisplayable* displayable) {
+       if (info->fType == SkType_MemberProperty) {
+               SkScriptValue scriptValue;
+               scriptValue.fOperand.fDisplayable = displayable;
+               scriptValue.fType = displayable->getType();
+               setProperty(info->propertyIndex(), scriptValue);
+       } else if (info->fType == SkType_Array) {
+               SkASSERT(displayable->getType() == SkType_Array);
+               SkDisplayArray* dispArray = (SkDisplayArray*) displayable;
+               SkTDScalarArray* array = (SkTDScalarArray* ) info->memberData(this);
+               array->setCount(dispArray->values.count());
+               memcpy(array->begin(), dispArray->values.begin(), dispArray->values.count() * sizeof(int));
+               //
+
+               // !!! need a way for interpreter engine to own array
+               // !!! probably need to replace all scriptable arrays with single bigger array
+               // that has operand and type on every element -- or
+               // when array is dirtied, need to get parent to reparse to local array
+       } else {
+               void* storage = info->memberData(this);
+               memcpy(storage, &displayable, sizeof(SkDisplayable*));
+       }
+// !!! unclear why displayable is dirtied here
+// if this is called, this breaks fromPath.xml
+//     displayable->dirty();
+}
+
+#ifdef SK_DEBUG
+void SkDisplayable::validate() {
+}
+#endif
+
+
diff --git a/libs/graphics/animator/SkDisplayable.h b/libs/graphics/animator/SkDisplayable.h
new file mode 100644 (file)
index 0000000..aea64b5
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef SkDisplayable_DEFINED
+#define SkDisplayable_DEFINED
+
+#include "SkOperand.h"
+#ifdef SK_DEBUG
+#include "SkString.h"
+#endif
+#include "SkIntArray.h"
+#include "SkRect.h"
+#include "SkTDArray.h"
+
+class SkAnimateMaker;
+class SkApply;
+class SkEvents;
+struct SkMemberInfo;
+struct SkScriptValue;
+class SkOpArray; // compiled scripting experiment
+union SkOperand2; // compiled scripting experiment
+
+class SkDisplayable {
+public:
+#ifdef SK_DEBUG
+       SkDisplayable();
+#endif
+       virtual ~SkDisplayable();
+       virtual bool add(SkAnimateMaker& , SkDisplayable* child);
+       virtual bool canContainDependents() const;
+       virtual bool childrenNeedDisposing() const;
+       virtual void clearBounder();
+       virtual bool contains(SkDisplayable* );
+       virtual SkDisplayable* contains(const SkString& );
+       virtual SkDisplayable* deepCopy(SkAnimateMaker* );
+       virtual void dirty();
+#ifdef SK_DUMP_ENABLED
+       virtual void dump(SkAnimateMaker* );
+    void dumpAttrs(SkAnimateMaker* );
+    void dumpBase(SkAnimateMaker* );
+    void dumpChildren(SkAnimateMaker* maker, bool closedAngle = false );
+    void dumpEnd(SkAnimateMaker* );
+       virtual void dumpEvents();
+#endif
+       virtual bool enable( SkAnimateMaker& );
+       virtual void enableBounder();
+       virtual void executeFunction(SkDisplayable* , int functionIndex, 
+               SkTDArray<SkScriptValue>& , SkDisplayTypes , SkScriptValue* ); 
+       void executeFunction(SkDisplayable* , const SkMemberInfo* , 
+               SkTypedArray* , SkScriptValue* ); 
+       virtual void executeFunction2(SkDisplayable* , int functionIndex, 
+               SkOpArray* params , SkDisplayTypes , SkOperand2* ); // compiled scripting experiment
+       virtual void getBounds(SkRect* );
+       virtual const SkFunctionParamType* getFunctionsParameters();
+       virtual const SkMemberInfo* getMember(int index);
+       virtual const SkMemberInfo* getMember(const char name[]);
+       const SkFunctionParamType* getParameters(const SkMemberInfo* info, 
+               int* paramCount);
+       virtual SkDisplayable* getParent() const;
+       virtual bool getProperty(int index, SkScriptValue* value) const;
+       virtual bool getProperty2(int index, SkOperand2* value) const;    // compiled scripting experiment
+       virtual SkDisplayTypes getType() const;
+       virtual bool hasEnable() const;
+       bool isAnimate() const { 
+               SkDisplayTypes type = getType(); 
+               return type == SkType_Animate || type == SkType_Set; }
+       bool isApply() const { return getType() == SkType_Apply; }
+       bool isColor() const { return getType() == SkType_Color; }
+       virtual bool isDrawable() const;
+       bool isGroup() const { return getType() == SkType_Group || 
+               getType() == SkType_Save || getType() == SkType_DrawTo ||
+        getType() == SkType_SaveLayer; }
+       bool isMatrix() const { return getType() == SkType_Matrix; }
+       virtual bool isPaint() const { return getType() == SkType_Paint; }
+       virtual bool isPath() const { return false; }
+       bool isPost() const { return getType() == SkType_Post; }
+       virtual void onEndElement(SkAnimateMaker& );
+       virtual const SkMemberInfo* preferredChild(SkDisplayTypes type);
+       virtual bool resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* );
+       virtual void setChildHasID();
+       virtual bool setParent(SkDisplayable* );
+       virtual bool setProperty(int index, SkScriptValue& );
+       void setReference(const SkMemberInfo* info, SkDisplayable* ref);
+#ifdef SK_DEBUG
+       bool isData() const { return getType() == SkType_Data; };
+       bool isEvent() const { return getType() == SkType_Event; }
+       virtual bool isMatrixPart() const { return false; }
+       bool isPatch() const { return getType() == SkType_3D_Patch; }
+       virtual bool isPaintPart() const { return false; }
+       virtual bool isPathPart() const { return false; }
+       virtual void validate();
+       SkString _id;
+       const char* id;
+//     static int fAllocationCount;
+       static SkTDDisplayableArray fAllocations;
+#else
+       void validate() {}
+#endif
+#ifdef SK_DUMP_ENABLED
+private:
+    void dumpValues(const SkMemberInfo* info, SkDisplayTypes type, SkOperand op, SkOperand blankOp,
+        SkOperand op2, SkOperand blankOp2);
+#endif
+};
+
+#endif // SkDisplayable_DEFINED
diff --git a/libs/graphics/animator/SkDraw3D.cpp b/libs/graphics/animator/SkDraw3D.cpp
new file mode 100644 (file)
index 0000000..8a69445
--- /dev/null
@@ -0,0 +1,100 @@
+#include "SkDraw3D.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+#include "SkTypedArray.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo Sk3D_Point::fInfo[] = {
+       SK_MEMBER_ALIAS(x, fPoint.fX, Float),
+       SK_MEMBER_ALIAS(y, fPoint.fY, Float),
+       SK_MEMBER_ALIAS(z, fPoint.fZ, Float)
+};
+
+#endif
+
+DEFINE_NO_VIRTUALS_GET_MEMBER(Sk3D_Point);
+
+Sk3D_Point::Sk3D_Point() {
+       fPoint.set(0, 0, 0);    
+}
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo Sk3D_Camera::fInfo[] = {
+       SK_MEMBER_ALIAS(axis, fCamera.fAxis, 3D_Point),
+       SK_MEMBER(hackHeight, Float),
+       SK_MEMBER(hackWidth, Float),
+       SK_MEMBER_ALIAS(location, fCamera.fLocation, 3D_Point),
+       SK_MEMBER_ALIAS(observer, fCamera.fObserver, 3D_Point),
+       SK_MEMBER(patch, 3D_Patch),
+       SK_MEMBER_ALIAS(zenith, fCamera.fZenith, 3D_Point),
+};
+
+#endif
+
+DEFINE_GET_MEMBER(Sk3D_Camera);
+
+Sk3D_Camera::Sk3D_Camera() : hackWidth(0), hackHeight(0), patch(nil) {
+}
+
+Sk3D_Camera::~Sk3D_Camera() {
+}
+
+bool Sk3D_Camera::draw(SkAnimateMaker& maker) {
+       fCamera.update();
+       SkMatrix matrix;
+       fCamera.computeMatrix(patch->fPatch, &matrix);
+       matrix.preTranslate(hackWidth / 2, -hackHeight / 2);
+       matrix.postTranslate(hackWidth / 2, hackHeight / 2);
+       maker.fCanvas->concat(matrix);
+       return false;
+}
+
+
+enum Sk3D_Patch_Functions {
+       SK_FUNCTION(rotateDegrees)
+};
+
+const SkFunctionParamType Sk3D_Patch::fFunctionParameters[] = {
+       (SkFunctionParamType) SkType_Float,
+       (SkFunctionParamType) SkType_Float,
+       (SkFunctionParamType) SkType_Float,
+       (SkFunctionParamType) 0 // terminator for parameter list (there may be multiple parameter lists)
+};
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo Sk3D_Patch::fInfo[] = {
+       SK_MEMBER_ALIAS(origin, fPatch.fOrigin, 3D_Point),
+       SK_MEMBER_FUNCTION(rotateDegrees, Float),
+       SK_MEMBER_ALIAS(u, fPatch.fU, 3D_Point),
+       SK_MEMBER_ALIAS(v, fPatch.fV, 3D_Point)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(Sk3D_Patch);
+
+void Sk3D_Patch::executeFunction(SkDisplayable* target, int index, 
+               SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type,
+               SkScriptValue* ) {
+       SkASSERT(target == this);
+       switch (index) {
+               case SK_FUNCTION(rotateDegrees):
+                       SkASSERT(parameters.count() == 3);
+                       SkASSERT(type == SkType_Float);
+                       fPatch.rotateDegrees(parameters[0].fOperand.fScalar, 
+                               parameters[1].fOperand.fScalar, parameters[2].fOperand.fScalar);
+                       break;
+               default:
+                       SkASSERT(0);
+       }
+}
+
+const SkFunctionParamType* Sk3D_Patch::getFunctionsParameters() {
+       return fFunctionParameters;
+}
+
+
+
diff --git a/libs/graphics/animator/SkDraw3D.h b/libs/graphics/animator/SkDraw3D.h
new file mode 100644 (file)
index 0000000..55f7664
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef SkDraw3D_DEFINED
+#define SkDraw3D_DEFINED
+
+#include "SkCamera.h"
+#include "SkDrawable.h"
+#include "SkMemberInfo.h"
+
+class Sk3D_Patch;
+
+struct Sk3D_Point {
+       DECLARE_NO_VIRTUALS_MEMBER_INFO(3D_Point);
+       Sk3D_Point();
+private:
+       SkPoint3D fPoint;
+};
+
+class Sk3D_Camera : public SkDrawable {
+       DECLARE_MEMBER_INFO(3D_Camera);
+       Sk3D_Camera();
+       virtual ~Sk3D_Camera();
+       virtual bool draw(SkAnimateMaker& );
+private:
+       SkScalar hackWidth;
+       SkScalar hackHeight;
+       SkCamera3D fCamera;
+       Sk3D_Patch* patch;
+};
+
+class Sk3D_Patch : public SkDisplayable {
+       DECLARE_MEMBER_INFO(3D_Patch);
+private:
+       virtual void executeFunction(SkDisplayable* , int index, 
+               SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type,
+               SkScriptValue* );
+       virtual const SkFunctionParamType* getFunctionsParameters();
+       SkPatch3D  fPatch;
+       static const SkFunctionParamType fFunctionParameters[];
+       friend class Sk3D_Camera;
+};
+
+#endif // SkDraw3D_DEFINED
+
diff --git a/libs/graphics/animator/SkDrawBitmap.cpp b/libs/graphics/animator/SkDrawBitmap.cpp
new file mode 100644 (file)
index 0000000..3ad4e00
--- /dev/null
@@ -0,0 +1,186 @@
+#include "SkDrawBitmap.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+#include "SkImageDecoder.h"
+#include "SkPaint.h"
+#include "SkStream.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkBaseBitmap::fInfo[] = {
+       SK_MEMBER(x, Float),
+       SK_MEMBER(y, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkBaseBitmap);
+
+SkBaseBitmap::SkBaseBitmap() : x(0), y(0) {
+}
+
+SkBaseBitmap::~SkBaseBitmap() {
+}
+
+bool SkBaseBitmap::draw(SkAnimateMaker& maker) {
+       SkBoundableAuto boundable(this, maker);
+       maker.fCanvas->drawBitmap(fBitmap, x, y, *maker.fPaint);
+       return false;
+}
+
+enum SkDrawBitmap_Properties {
+       SK_PROPERTY(erase)
+};
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawBitmap::fInfo[] = {
+       SK_MEMBER_INHERITED,
+       SK_MEMBER_PROPERTY(erase, ARGB),
+       SK_MEMBER(format, BitmapFormat),
+       SK_MEMBER(height, Int),
+       SK_MEMBER(rowBytes, Int),
+       SK_MEMBER(width, Int),
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawBitmap);
+
+SkDrawBitmap::SkDrawBitmap() : format((SkBitmap::Config) -1), height(-1), 
+       rowBytes(0),    width(-1), fColor(0), fColorSet(false) {
+}
+
+SkDrawBitmap::~SkDrawBitmap() {
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkDrawBitmap::dump(SkAnimateMaker* maker) {
+    dumpBase(maker);
+    dumpAttrs(maker);
+    if (fColorSet)
+        SkDebugf("erase=\"argb(%d,%d,%d,%d)\" ", SkColorGetA(fColor)/255, SkColorGetR(fColor),
+            SkColorGetG(fColor), SkColorGetB(fColor));
+    if (rowBytes > 0)
+        SkDebugf("rowBytes=\"%d\" ", rowBytes);
+    const char* formatName;
+    switch (format) {
+        case 0: formatName = "none"; break;
+        case 1: formatName = "A1"; break;
+        case 2: formatName = "A8"; break;
+        case 3: formatName = "Index8"; break;
+        case 4: formatName = "RGB16"; break;
+        case 5: formatName = "RGB32"; break;
+    }
+    SkDebugf("format=\"%s\" />\n", formatName);
+}
+#endif
+
+void SkDrawBitmap::onEndElement(SkAnimateMaker& maker) {
+       SkASSERT(format != (SkBitmap::Config) -1);
+       SkASSERT(width != -1);
+       SkASSERT(height != -1);
+       SkASSERT(rowBytes >= 0);
+       fBitmap.setConfig((SkBitmap::Config) format, width, height, rowBytes);
+       fBitmap.allocPixels();
+       if (fColorSet)
+               fBitmap.eraseColor(fColor);
+}
+
+bool SkDrawBitmap::setProperty(int index, SkScriptValue& value)
+{
+       switch (index) {
+               case SK_PROPERTY(erase):
+                       SkASSERT(value.fType == SkType_ARGB);
+                       fColor = value.fOperand.fS32;
+                       fColorSet = true;
+                       break;
+               default:
+                       SkASSERT(0);
+                       return false;
+       }
+       return true;
+}
+
+
+enum SkImage_Properties {
+       SK_PROPERTY(height),
+       SK_PROPERTY(width)
+};
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkImage::fInfo[] = {
+       SK_MEMBER_INHERITED,
+       SK_MEMBER(base64, Base64),
+       SK_MEMBER_PROPERTY(height, Int),
+       SK_MEMBER(src, String),
+       SK_MEMBER_PROPERTY(width, Int)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkImage);
+
+SkImage::SkImage() : fDirty(true), fUriBase(nil) {
+       base64.fData = nil;
+       base64.fLength = 0;
+}
+
+SkImage::~SkImage() {
+       delete[] base64.fData; 
+}
+
+SkDisplayable* SkImage::deepCopy(SkAnimateMaker* maker) {
+    SkDisplayable* copy = INHERITED::deepCopy(maker);
+    ((SkImage*) copy)->fUriBase = ((SkImage*) this)->fUriBase;
+    return copy;
+}
+
+void SkImage::dirty() {
+       fDirty = true;
+}
+
+bool SkImage::draw(SkAnimateMaker& maker) {
+       if (fDirty) 
+               resolve();
+       return INHERITED::draw(maker);
+}
+
+bool SkImage::getProperty(int index, SkScriptValue* value) const {
+       if (fDirty) 
+               resolve();
+       switch (index) {
+               case SK_PROPERTY(height):
+                       value->fOperand.fS32 = fBitmap.height();
+                       break;
+               case SK_PROPERTY(width):
+                       value->fOperand.fS32 = fBitmap.width();
+                       break;
+       default:
+               SkASSERT(0);
+               return false;
+       }
+       value->fType = SkType_Int;
+       return true;
+}
+
+void SkImage::onEndElement(SkAnimateMaker& maker) {
+       fUriBase = maker.fPrefix.c_str();
+}
+
+void SkImage::resolve() {
+       fDirty = false;
+       if (base64.fData) {
+               fBitmap.reset();
+               SkImageDecoder::DecodeMemory(base64.fData, base64.fLength, &fBitmap);
+       } else if (src.size()) {
+               if (fLast.equals(src))
+                       return;
+               fLast.set(src);
+               fBitmap.reset();
+               SkStream* stream = SkStream::GetURIStream(fUriBase, src.c_str());
+               SkAutoTDelete<SkStream> autoDel(stream);
+               SkImageDecoder::DecodeStream(stream, &fBitmap);
+       }       
+}
diff --git a/libs/graphics/animator/SkDrawBitmap.h b/libs/graphics/animator/SkDrawBitmap.h
new file mode 100644 (file)
index 0000000..f5ef330
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef SkDrawBitmap_DEFINED
+#define SkDrawBitmap_DEFINED
+
+#include "SkBoundable.h"
+#include "SkBase64.h"
+#include "SkBitmap.h"
+// #include "SkImageDecoder.h"
+#include "SkMemberInfo.h"
+
+class SkBaseBitmap : public SkBoundable {
+       DECLARE_MEMBER_INFO(BaseBitmap);
+       SkBaseBitmap();
+       virtual ~SkBaseBitmap();
+       virtual bool draw(SkAnimateMaker& );
+protected:
+       SkBitmap fBitmap;
+       SkScalar x;
+       SkScalar y;
+private:
+       friend class SkDrawTo;
+       friend class SkDrawBitmapShader;
+       typedef SkBoundable INHERITED;
+};
+
+class SkDrawBitmap : public SkBaseBitmap {
+       DECLARE_DRAW_MEMBER_INFO(Bitmap);
+       SkDrawBitmap();
+       virtual ~SkDrawBitmap();
+#ifdef SK_DUMP_ENABLED
+    virtual void dump(SkAnimateMaker* );
+#endif
+       virtual void onEndElement(SkAnimateMaker& );
+       virtual bool setProperty(int index, SkScriptValue& value);
+protected:
+       int /*SkBitmap::Config*/ format;
+       S32 height;
+       S32 rowBytes;
+       S32 width;
+       SkColor fColor;
+       SkBool fColorSet;
+       typedef SkBaseBitmap INHERITED;
+};
+
+class SkImage : public SkBaseBitmap {
+       DECLARE_MEMBER_INFO(Image);
+       SkImage();
+       virtual ~SkImage();
+    virtual SkDisplayable* deepCopy(SkAnimateMaker* );
+       virtual void dirty();
+       virtual bool draw(SkAnimateMaker& );
+       virtual bool getProperty(int index, SkScriptValue* value) const;
+       virtual void onEndElement(SkAnimateMaker& maker);
+private:
+       void resolve() const { (const_cast<SkImage*>(this))->resolve(); }
+       void resolve();
+protected:
+       SkBase64 base64;
+       SkString src;
+       SkString fLast; // cache of src so that stream isn't unnecessarily decoded 
+       SkBool fDirty;
+       const char* fUriBase;
+       typedef SkBaseBitmap INHERITED;
+};
+
+#endif // SkDrawBitmap_DEFINED
diff --git a/libs/graphics/animator/SkDrawBlur.cpp b/libs/graphics/animator/SkDrawBlur.cpp
new file mode 100644 (file)
index 0000000..170a770
--- /dev/null
@@ -0,0 +1,23 @@
+#include "SkDrawBlur.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawBlur::fInfo[] = {
+       SK_MEMBER(blurStyle, MaskFilterBlurStyle),
+       SK_MEMBER(radius, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawBlur);
+
+SkDrawBlur::SkDrawBlur() : radius(-1), 
+       blurStyle(SkBlurMaskFilter::kNormal_BlurStyle) {
+}
+
+SkMaskFilter* SkDrawBlur::getMaskFilter() {
+       if (radius < 0)
+               return nil;
+       return SkBlurMaskFilter::Create(radius, (SkBlurMaskFilter::BlurStyle) blurStyle);
+}
+
diff --git a/libs/graphics/animator/SkDrawBlur.h b/libs/graphics/animator/SkDrawBlur.h
new file mode 100644 (file)
index 0000000..4bfb268
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef SkDrawBlur_DEFINED
+#define SkDrawBlur_DEFINED
+
+#include "SkPaintParts.h"
+#include "SkBlurMaskFilter.h"
+
+class SkDrawBlur : public SkDrawMaskFilter {
+       DECLARE_DRAW_MEMBER_INFO(Blur);
+       SkDrawBlur();
+       virtual SkMaskFilter* getMaskFilter();
+protected:
+       SkScalar radius;
+       int /*SkBlurMaskFilter::BlurStyle*/ blurStyle;
+};
+
+#endif // SkDrawBlur_DEFINED
+
diff --git a/libs/graphics/animator/SkDrawClip.cpp b/libs/graphics/animator/SkDrawClip.cpp
new file mode 100644 (file)
index 0000000..4717501
--- /dev/null
@@ -0,0 +1,31 @@
+#include "SkDrawClip.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+#include "SkDrawRectangle.h"
+#include "SkDrawPath.h"
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawClip::fInfo[] = {
+       SK_MEMBER(path, Path),
+       SK_MEMBER(rect, Rect)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawClip);
+
+SkDrawClip::SkDrawClip() : rect(nil), path(nil) {
+}
+
+bool SkDrawClip::draw(SkAnimateMaker& maker ) {
+       if (rect != nil)
+               maker.fCanvas->clipRect(rect->fRect);
+       else {
+               SkASSERT(path != nil);
+               maker.fCanvas->clipPath(path->fPath);
+       }
+       return false;
+}
+
diff --git a/libs/graphics/animator/SkDrawClip.h b/libs/graphics/animator/SkDrawClip.h
new file mode 100644 (file)
index 0000000..6c89666
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef SkDrawClip_DEFINED
+#define SkDrawClip_DEFINED
+
+#include "SkDrawable.h"
+#include "SkMemberInfo.h"
+#include "SkRegion.h"
+
+class SkDrawPath;
+class SkDrawRect;
+
+class SkDrawClip : public SkDrawable {
+       DECLARE_DRAW_MEMBER_INFO(Clip);
+       SkDrawClip();
+       virtual bool draw(SkAnimateMaker& );
+private:
+       SkDrawRect* rect;
+       SkDrawPath* path;
+};
+
+#endif // SkDrawClip_DEFINED
diff --git a/libs/graphics/animator/SkDrawColor.cpp b/libs/graphics/animator/SkDrawColor.cpp
new file mode 100644 (file)
index 0000000..a21bde4
--- /dev/null
@@ -0,0 +1,261 @@
+#include "SkDrawColor.h"
+#ifdef SK_DEBUG
+#include "SkDisplayList.h"
+#endif
+#include "SkDrawPaint.h"
+#include "SkParse.h"
+#include "SkScript.h"
+
+enum HSV_Choice {
+       kGetHue,
+       kGetSaturation,
+       kGetValue
+};
+
+static SkScalar RGB_to_HSV(SkColor color, HSV_Choice choice) {
+       SkScalar red = SkIntToScalar(SkColorGetR(color));
+       SkScalar green = SkIntToScalar(SkColorGetG(color));
+       SkScalar blue = SkIntToScalar(SkColorGetB(color));
+       SkScalar min = SkMinScalar(SkMinScalar(red, green), blue);
+       SkScalar value = SkMaxScalar(SkMaxScalar(red, green), blue);
+       if (choice == kGetValue)
+               return value/255;
+       SkScalar delta = value - min;
+       SkScalar saturation = value == 0 ? 0 : SkScalarDiv(delta, value);
+       if (choice == kGetSaturation)
+               return saturation;
+       SkScalar hue;
+       if (saturation == 0)
+               hue = 0;
+       else {
+               SkScalar part60 = SkScalarDiv(60 * SK_Scalar1, delta);
+               if (red == value) {
+                       hue = SkScalarMul(green - blue, part60);
+                       if (hue < 0)
+                               hue += 360 * SK_Scalar1;
+               }
+               else if (green == value)
+                       hue = 120 * SK_Scalar1 + SkScalarMul(blue - red, part60);
+               else  // blue == value
+                       hue = 240 * SK_Scalar1 + SkScalarMul(red - green, part60);
+       }
+       SkASSERT(choice == kGetHue);
+       return hue;
+}
+
+#if defined _WIN32 && _MSC_VER >= 1300 // disable 'red', etc. may be used without having been initialized
+#pragma warning ( push )
+#pragma warning ( disable : 4701 )
+#endif
+
+static SkColor HSV_to_RGB(SkColor color, HSV_Choice choice, SkScalar hsv) {
+       SkScalar hue = choice == kGetHue ? hsv : RGB_to_HSV(color, kGetHue);
+       SkScalar saturation = choice == kGetSaturation ? hsv : RGB_to_HSV(color, kGetSaturation);
+       SkScalar value = choice == kGetValue ? hsv : RGB_to_HSV(color, kGetValue);
+       value *= 255;
+       SkScalar red SK_INIT_TO_AVOID_WARNING;
+       SkScalar green SK_INIT_TO_AVOID_WARNING;
+       SkScalar blue SK_INIT_TO_AVOID_WARNING;
+       if (saturation == 0)    // color is on black-and-white center line
+               red = green = blue = value;
+       else {
+               //SkScalar fraction = SkScalarMod(hue, 60 * SK_Scalar1);
+               int sextant = SkScalarFloor(hue / 60);
+               SkScalar fraction = hue / 60 - SkIntToScalar(sextant);
+               SkScalar p = SkScalarMul(value , SK_Scalar1 - saturation);
+               SkScalar q = SkScalarMul(value, SK_Scalar1 - SkScalarMul(saturation, fraction));
+               SkScalar t = SkScalarMul(value, SK_Scalar1 - 
+                       SkScalarMul(saturation, SK_Scalar1 - fraction));
+               switch (sextant % 6) {
+                       case 0: red = value; green = t; blue = p; break;
+                       case 1: red = q; green = value; blue = p; break;
+                       case 2: red = p; green = value; blue = t; break;
+                       case 3: red = p; green = q; blue = value; break;
+                       case 4: red = t;  green = p; blue = value; break;
+                       case 5: red = value; green = p; blue = q; break;
+               }
+       }
+       //used to say SkToU8((U8CPU) red) etc
+       return SkColorSetARGB(SkColorGetA(color), SkScalarRound(red), 
+               SkScalarRound(green), SkScalarRound(blue));
+}
+
+#if defined _WIN32 && _MSC_VER >= 1300 
+#pragma warning ( pop )
+#endif
+
+enum SkDrawColor_Properties {
+       SK_PROPERTY(alpha),
+       SK_PROPERTY(blue),
+       SK_PROPERTY(green),
+       SK_PROPERTY(hue),
+       SK_PROPERTY(red),
+       SK_PROPERTY(saturation),
+       SK_PROPERTY(value)
+};
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawColor::fInfo[] = {
+       SK_MEMBER_PROPERTY(alpha, Float),
+       SK_MEMBER_PROPERTY(blue, Float),
+       SK_MEMBER(color, ARGB),
+       SK_MEMBER_PROPERTY(green, Float),
+       SK_MEMBER_PROPERTY(hue, Float),
+       SK_MEMBER_PROPERTY(red, Float),
+       SK_MEMBER_PROPERTY(saturation, Float),
+       SK_MEMBER_PROPERTY(value, Float),
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawColor);
+
+SkDrawColor::SkDrawColor() : fDirty(false) { 
+       color = SK_ColorBLACK; 
+       fHue = fSaturation = fValue = SK_ScalarNaN;
+}
+
+bool SkDrawColor::add() {
+       if (fPaint->color != nil)
+               return true; // error (probably color in paint as attribute as well)
+       fPaint->color = this;
+       fPaint->fOwnsColor = true;
+       return false;
+}
+
+SkDisplayable* SkDrawColor::deepCopy(SkAnimateMaker* maker) {
+       SkDrawColor* copy = new SkDrawColor();
+       copy->color = color;
+       copy->fHue = fHue;
+       copy->fSaturation = fSaturation;
+       copy->fValue = fValue;
+       copy->fDirty = fDirty;
+       return copy;
+}
+
+void SkDrawColor::dirty(){
+       fDirty = true;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkDrawColor::dump(SkAnimateMaker* maker) {
+       dumpBase(maker);
+       SkDebugf("alpha=\"%d\" red=\"%d\" green=\"%d\" blue=\"%d\" />\n",  
+               SkColorGetA(color)/255, SkColorGetR(color),
+               SkColorGetG(color), SkColorGetB(color));
+}
+#endif
+
+SkColor SkDrawColor::getColor() { 
+       if (fDirty) {
+               if (SkScalarIsNaN(fValue) == false)
+                       color = HSV_to_RGB(color, kGetValue, fValue);
+               if (SkScalarIsNaN(fSaturation) == false)
+                       color = HSV_to_RGB(color, kGetSaturation, fSaturation);
+               if (SkScalarIsNaN(fHue) == false)
+                       color = HSV_to_RGB(color, kGetHue, fHue);
+               fDirty = false;
+       }
+       return color; 
+}
+
+SkDisplayable* SkDrawColor::getParent() const {
+       return fPaint;
+}
+
+bool SkDrawColor::getProperty(int index, SkScriptValue* value) const {
+       value->fType = SkType_Float;
+       SkScalar result;
+       switch(index) {
+               case SK_PROPERTY(alpha):
+                       result = SkIntToScalar(SkColorGetA(color)) / 255;
+                       break;
+               case SK_PROPERTY(blue):
+                       result = SkIntToScalar(SkColorGetB(color));
+                       break;
+               case SK_PROPERTY(green):
+                       result = SkIntToScalar(SkColorGetG(color));
+                       break;
+               case SK_PROPERTY(hue):
+                       result = RGB_to_HSV(color, kGetHue);
+                       break;
+               case SK_PROPERTY(red):
+                       result = SkIntToScalar(SkColorGetR(color));
+                       break;
+               case SK_PROPERTY(saturation):
+                       result = RGB_to_HSV(color, kGetSaturation);
+                       break;
+               case SK_PROPERTY(value):
+                       result = RGB_to_HSV(color, kGetValue);
+                       break;
+               default:
+                       SkASSERT(0);
+                       return false;
+       }
+       value->fOperand.fScalar = result;
+       return true;
+}
+
+void SkDrawColor::onEndElement(SkAnimateMaker& maker){
+       fDirty = true;
+}
+
+bool SkDrawColor::setParent(SkDisplayable* parent) {
+       SkASSERT(parent != nil);
+       if (parent->getType() == SkType_LinearGradient || parent->getType() == SkType_RadialGradient)
+               return false;
+       if (parent->isPaint() == false)
+               return true;
+       fPaint = (SkDrawPaint*) parent;
+       return false;
+}
+
+bool SkDrawColor::setProperty(int index, SkScriptValue& value) {
+       SkASSERT(value.fType == SkType_Float);
+       SkScalar scalar = value.fOperand.fScalar;
+       switch (index) {
+               case SK_PROPERTY(alpha):
+                       U8 alpha;
+               #ifdef SK_SCALAR_IS_FLOAT
+                       alpha = scalar == SK_Scalar1 ? 255 : SkToU8((U8CPU) (scalar * 256));
+               #else
+                       alpha = SkToU8((scalar - (scalar >= SK_ScalarHalf)) >> 8);
+               #endif
+                       color = SkColorSetARGB(alpha, SkColorGetR(color), 
+                               SkColorGetG(color), SkColorGetB(color));
+                       break;
+               case SK_PROPERTY(blue):
+                       scalar = SkScalarClampMax(scalar, 255 * SK_Scalar1);
+                       color = SkColorSetARGB(SkColorGetA(color), SkColorGetR(color), 
+                               SkColorGetG(color), SkToU8((U8CPU) scalar));
+                       break;
+               case SK_PROPERTY(green):
+                       scalar = SkScalarClampMax(scalar, 255 * SK_Scalar1);
+                       color = SkColorSetARGB(SkColorGetA(color), SkColorGetR(color), 
+                               SkToU8((U8CPU) scalar), SkColorGetB(color));
+                       break;
+               case SK_PROPERTY(hue):
+                       fHue = scalar;//RGB_to_HSV(color, kGetHue);
+                       fDirty = true;
+                       break;
+               case SK_PROPERTY(red):
+                       scalar = SkScalarClampMax(scalar, 255 * SK_Scalar1);
+                       color = SkColorSetARGB(SkColorGetA(color), SkToU8((U8CPU) scalar), 
+                               SkColorGetG(color), SkColorGetB(color));
+               break;
+               case SK_PROPERTY(saturation):
+                       fSaturation = scalar;//RGB_to_HSV(color, kGetSaturation);
+                       fDirty = true;
+                       break;
+               case SK_PROPERTY(value):
+                       fValue = scalar;//RGB_to_HSV(color, kGetValue);
+                       fDirty = true;
+                       break;
+               default:
+                       SkASSERT(0);
+                       return false;
+       }
+       return true;
+}
+
diff --git a/libs/graphics/animator/SkDrawColor.h b/libs/graphics/animator/SkDrawColor.h
new file mode 100644 (file)
index 0000000..ad7c3f8
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef SkDrawColor_DEFINED
+#define SkDrawColor_DEFINED
+
+#include "SkPaintParts.h"
+#include "SkColor.h"
+
+class SkDrawColor : public SkPaintPart {
+       DECLARE_DRAW_MEMBER_INFO(Color);
+       SkDrawColor();
+       virtual bool add();
+       virtual void dirty();
+#ifdef SK_DUMP_ENABLED
+       virtual void dump(SkAnimateMaker* );
+#endif
+       SkColor getColor();
+       virtual SkDisplayable* deepCopy(SkAnimateMaker* );
+       virtual SkDisplayable* getParent() const;
+       virtual bool getProperty(int index, SkScriptValue* value) const;
+       virtual void onEndElement(SkAnimateMaker& );
+       virtual bool setParent(SkDisplayable* parent);
+       virtual bool setProperty(int index, SkScriptValue&);
+protected:
+       SkColor color;
+       SkScalar fHue;
+       SkScalar fSaturation;
+       SkScalar fValue;
+       SkBool fDirty;
+private:
+       friend class SkGradient;
+       typedef SkPaintPart INHERITED;
+};
+
+#endif // SkDrawColor_DEFINED
diff --git a/libs/graphics/animator/SkDrawDash.cpp b/libs/graphics/animator/SkDrawDash.cpp
new file mode 100644 (file)
index 0000000..78e2d66
--- /dev/null
@@ -0,0 +1,27 @@
+#include "SkDrawDash.h"
+#include "SkDashPathEffect.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDash::fInfo[] = {
+       SK_MEMBER_ARRAY(intervals, Float),
+       SK_MEMBER(phase, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDash);
+
+SkDash::SkDash() : phase(0) {
+}
+
+SkDash::~SkDash() {
+}
+
+SkPathEffect* SkDash::getPathEffect() {
+       int count = intervals.count();
+       if (count == 0)
+               return nil;
+       return new SkDashPathEffect(intervals.begin(), count, phase);
+}
+
diff --git a/libs/graphics/animator/SkDrawDash.h b/libs/graphics/animator/SkDrawDash.h
new file mode 100644 (file)
index 0000000..ff89f50
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef SkDrawDash_DEFINED
+#define SkDrawDash_DEFINED
+
+#include "SkPaintParts.h"
+#include "SkIntArray.h"
+
+class SkDash : public SkDrawPathEffect {
+       DECLARE_MEMBER_INFO(Dash);
+       SkDash();
+       virtual ~SkDash();
+       virtual SkPathEffect* getPathEffect();
+private:
+       SkTDScalarArray intervals;
+       SkScalar phase;
+};
+
+#endif // SkDrawDash_DEFINED
+
diff --git a/libs/graphics/animator/SkDrawDiscrete.cpp b/libs/graphics/animator/SkDrawDiscrete.cpp
new file mode 100644 (file)
index 0000000..9e32772
--- /dev/null
@@ -0,0 +1,26 @@
+#include "SkDrawDiscrete.h"
+#include "SkAnimateMaker.h"
+#include "SkPaint.h"
+#include "SkDiscretePathEffect.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDiscrete::fInfo[] = {
+       SK_MEMBER(deviation, Float),
+       SK_MEMBER(segLength, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDiscrete);
+
+SkDiscrete::SkDiscrete() : deviation(0), segLength(0) {
+}
+
+SkPathEffect* SkDiscrete::getPathEffect() {
+       if (deviation <= 0 || segLength <= 0)
+               return nil;
+       else
+               return new SkDiscretePathEffect(segLength, deviation);
+}
+
diff --git a/libs/graphics/animator/SkDrawDiscrete.h b/libs/graphics/animator/SkDrawDiscrete.h
new file mode 100644 (file)
index 0000000..61aeac0
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef SkDrawDiscrete_DEFINED
+#define SkDrawDiscrete_DEFINED
+
+#include "SkPaintParts.h"
+
+class SkDiscrete : public SkDrawPathEffect {
+       DECLARE_MEMBER_INFO(Discrete);
+       SkDiscrete();
+       virtual SkPathEffect* getPathEffect();
+private:
+       SkScalar deviation;
+       SkScalar segLength;
+};
+
+#endif //SkDrawDiscrete_DEFINED
diff --git a/libs/graphics/animator/SkDrawEmboss.cpp b/libs/graphics/animator/SkDrawEmboss.cpp
new file mode 100644 (file)
index 0000000..f0aee87
--- /dev/null
@@ -0,0 +1,25 @@
+#include "SkDrawEmboss.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawEmboss::fInfo[] = {
+       SK_MEMBER(ambient, Float),
+       SK_MEMBER_ARRAY(direction, Float),
+       SK_MEMBER(radius, Float),
+       SK_MEMBER(specular, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawEmboss);
+
+SkDrawEmboss::SkDrawEmboss() : radius(-1) { 
+       direction.setCount(3);
+}
+
+SkMaskFilter* SkDrawEmboss::getMaskFilter() {
+       if (radius < 0 || direction.count() !=3)
+               return nil;
+    return SkBlurMaskFilter::CreateEmboss(direction.begin(), ambient, specular, radius);
+}
+
diff --git a/libs/graphics/animator/SkDrawEmboss.h b/libs/graphics/animator/SkDrawEmboss.h
new file mode 100644 (file)
index 0000000..8014f45
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef SkDrawEmboss_DEFINED
+#define SkDrawEmboss_DEFINED
+
+#include "SkDrawBlur.h"
+
+class SkDrawEmboss : public SkDrawMaskFilter {
+       DECLARE_DRAW_MEMBER_INFO(Emboss);
+       SkDrawEmboss();
+       virtual SkMaskFilter* getMaskFilter();
+protected:
+       SkTDScalarArray direction;
+       SkScalar radius, ambient, specular;
+};
+
+#endif // SkDrawEmboss_DEFINED
+
diff --git a/libs/graphics/animator/SkDrawExtraPathEffect.cpp b/libs/graphics/animator/SkDrawExtraPathEffect.cpp
new file mode 100644 (file)
index 0000000..b008643
--- /dev/null
@@ -0,0 +1,499 @@
+#include "SkDrawExtraPathEffect.h"
+#include "SkDrawPath.h"
+#include "Sk1DPathEffect.h"
+#include "Sk2DPathEffect.h"
+#include "SkMemberInfo.h"
+#include "SkPaintParts.h"
+#include "SkPathEffect.h"
+#include "SkCornerPathEffect.h"
+
+#include "SkDashPathEffect.h"
+
+class SkDrawShapePathEffect : public SkDrawPathEffect {
+       DECLARE_PRIVATE_MEMBER_INFO(DrawShapePathEffect);
+       SkDrawShapePathEffect();
+       virtual ~SkDrawShapePathEffect();
+       virtual bool add(SkAnimateMaker& , SkDisplayable* );
+       virtual SkPathEffect* getPathEffect();
+protected:
+       SkDrawable* addPath;
+       SkDrawable* addMatrix;
+       SkDrawPath* path;
+       SkPathEffect* fPathEffect;
+       friend class SkShape1DPathEffect;
+       friend class SkShape2DPathEffect;
+};
+
+class SkDrawShape1DPathEffect : public SkDrawShapePathEffect {
+       DECLARE_EXTRAS_MEMBER_INFO(SkDrawShape1DPathEffect);
+       SkDrawShape1DPathEffect(SkDisplayTypes );
+       virtual ~SkDrawShape1DPathEffect();
+       virtual void onEndElement(SkAnimateMaker& );
+private:
+       SkString phase;
+       SkString spacing;
+       friend class SkShape1DPathEffect;
+       typedef SkDrawShapePathEffect INHERITED;
+};
+
+class SkDrawShape2DPathEffect : public SkDrawShapePathEffect {
+       DECLARE_EXTRAS_MEMBER_INFO(SkDrawShape2DPathEffect);
+       SkDrawShape2DPathEffect(SkDisplayTypes );
+       virtual ~SkDrawShape2DPathEffect();
+       virtual void onEndElement(SkAnimateMaker& );
+private:
+       SkDrawMatrix* matrix;
+       friend class SkShape2DPathEffect;
+       typedef SkDrawShapePathEffect INHERITED;
+};
+
+class SkDrawComposePathEffect : public SkDrawPathEffect {
+       DECLARE_EXTRAS_MEMBER_INFO(SkDrawComposePathEffect);
+       SkDrawComposePathEffect(SkDisplayTypes );
+       virtual ~SkDrawComposePathEffect();
+       virtual bool add(SkAnimateMaker& , SkDisplayable* );
+       virtual SkPathEffect* getPathEffect();
+       virtual bool isPaint() const; 
+private:
+       SkDrawPathEffect* effect1;
+       SkDrawPathEffect* effect2;
+};
+
+class SkDrawCornerPathEffect : public SkDrawPathEffect {
+    DECLARE_EXTRAS_MEMBER_INFO(SkDrawCornerPathEffect);
+    SkDrawCornerPathEffect(SkDisplayTypes );
+    virtual ~SkDrawCornerPathEffect();
+    virtual SkPathEffect* getPathEffect();
+private:
+    SkScalar radius;
+};
+
+//////////// SkShape1DPathEffect
+
+#include "SkAnimateMaker.h"
+#include "SkAnimatorScript.h"
+#include "SkDisplayApply.h"
+#include "SkDrawMatrix.h"
+#include "SkPaint.h"
+
+class SkShape1DPathEffect : public Sk1DPathEffect {
+public:
+       SkShape1DPathEffect(SkDrawShape1DPathEffect* draw, SkAnimateMaker* maker) :
+               fDraw(draw), fMaker(maker) {
+       }
+
+protected:
+       virtual SkScalar begin(SkScalar contourLength)
+       {
+               SkScriptValue value;
+               SkAnimatorScript engine(*fMaker, nil, SkType_Float);
+               engine.propertyCallBack(GetContourLength, &contourLength);
+               value.fOperand.fScalar = 0;
+               engine.evaluate(fDraw->phase.c_str(), &value, SkType_Float);
+               return value.fOperand.fScalar;
+       }
+
+       virtual SkScalar next(SkScalar distance, const SkMatrix& mat, SkPath* dst)
+       {
+               fMaker->setExtraPropertyCallBack(fDraw->fType, GetDistance, &distance);
+               SkDrawPath* drawPath = nil;
+               if (fDraw->addPath->isPath()) {
+                       drawPath = (SkDrawPath*) fDraw->addPath;
+               } else {
+                       SkApply* apply = (SkApply*) fDraw->addPath;
+                       apply->refresh(*fMaker);
+                       apply->activate(*fMaker);
+                       apply->interpolate(*fMaker, SkScalarMulRound(distance, 1000));
+                       drawPath = (SkDrawPath*) apply->getScope();
+               }
+               SkMatrix m(mat);
+               if (fDraw->addMatrix) {
+                       SkDrawMatrix* matrix;
+                       if (fDraw->addMatrix->getType() == SkType_Matrix) 
+                               matrix = (SkDrawMatrix*) fDraw->addMatrix;
+                       else {
+                               SkApply* apply = (SkApply*) fDraw->addMatrix;
+                               apply->refresh(*fMaker);
+                               apply->activate(*fMaker);
+                               apply->interpolate(*fMaker, SkScalarMulRound(distance, 1000));
+                               matrix = (SkDrawMatrix*) apply->getScope();
+                       }
+               }
+               SkScalar result = 0;
+               SkAnimatorScript::EvaluateFloat(*fMaker, nil, fDraw->spacing.c_str(), &result);
+               if (drawPath)
+                       dst->addPath(drawPath->getPath(), m);
+               fMaker->clearExtraPropertyCallBack(fDraw->fType);
+               return result;
+       }
+
+private:
+
+       static bool GetContourLength(const char* token, size_t len, void* clen, SkScriptValue* value) {
+               if (SK_LITERAL_STR_EQUAL("contourLength", token, len)) {
+                       value->fOperand.fScalar = *(SkScalar*) clen;
+                       value->fType = SkType_Float;
+                       return true;
+               }
+               return false;
+       }
+
+       static bool GetDistance(const char* token, size_t len, void* dist, SkScriptValue* value) {
+               if (SK_LITERAL_STR_EQUAL("distance", token, len)) {
+                       value->fOperand.fScalar = *(SkScalar*) dist;
+                       value->fType = SkType_Float;
+                       return true;
+               }
+               return false;
+       }
+
+       SkDrawShape1DPathEffect* fDraw;
+       SkAnimateMaker* fMaker;
+};
+
+//////////// SkDrawShapePathEffect
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawShapePathEffect::fInfo[] = {
+       SK_MEMBER(addMatrix, Drawable), // either matrix or apply
+       SK_MEMBER(addPath, Drawable),   // either path or apply
+       SK_MEMBER(path, Path),
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawShapePathEffect);
+
+SkDrawShapePathEffect::SkDrawShapePathEffect() : 
+       addPath(nil), addMatrix(nil), path(nil), fPathEffect(nil) {
+}
+
+SkDrawShapePathEffect::~SkDrawShapePathEffect() {
+       fPathEffect->safeUnref();
+}
+
+bool SkDrawShapePathEffect::add(SkAnimateMaker& , SkDisplayable* child) {
+       path = (SkDrawPath*) child;
+       return true;
+}
+
+SkPathEffect* SkDrawShapePathEffect::getPathEffect() {
+       fPathEffect->ref();
+       return fPathEffect;
+}
+
+//////////// SkDrawShape1DPathEffect
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawShape1DPathEffect::fInfo[] = {
+       SK_MEMBER_INHERITED,
+       SK_MEMBER(phase, String),
+       SK_MEMBER(spacing, String),
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawShape1DPathEffect);
+
+SkDrawShape1DPathEffect::SkDrawShape1DPathEffect(SkDisplayTypes type) : fType(type) {
+}
+
+SkDrawShape1DPathEffect::~SkDrawShape1DPathEffect() {
+}
+
+void SkDrawShape1DPathEffect::onEndElement(SkAnimateMaker& maker) {
+       if (addPath == nil || (addPath->isPath() == false && addPath->isApply() == false))
+               maker.setErrorCode(SkDisplayXMLParserError::kUnknownError); // !!! add error
+       else
+               fPathEffect = new SkShape1DPathEffect(this, &maker);
+}
+
+////////// SkShape2DPathEffect
+
+class SkShape2DPathEffect : public Sk2DPathEffect {
+public:
+       SkShape2DPathEffect(SkDrawShape2DPathEffect* draw, SkAnimateMaker* maker, 
+               const SkMatrix& matrix) : Sk2DPathEffect(matrix), fDraw(draw), fMaker(maker) {
+       }
+
+protected:
+       virtual void begin(const SkRect16& uvBounds, SkPath* )
+       {
+               fUVBounds.set(SkIntToScalar(uvBounds.fLeft), SkIntToScalar(uvBounds.fTop),
+                       SkIntToScalar(uvBounds.fRight), SkIntToScalar(uvBounds.fBottom));
+       }
+
+       virtual void next(const SkPoint& loc, int u, int v, SkPath* dst)
+       {
+               fLoc = loc;
+               fU = u;
+               fV = v;
+               SkDrawPath* drawPath;
+               fMaker->setExtraPropertyCallBack(fDraw->fType, Get2D, this);
+               if (fDraw->addPath->isPath()) {
+                       drawPath = (SkDrawPath*) fDraw->addPath;
+               } else {
+                       SkApply* apply = (SkApply*) fDraw->addPath;
+                       apply->refresh(*fMaker);
+                       apply->activate(*fMaker);
+                       apply->interpolate(*fMaker, v);
+                       drawPath = (SkDrawPath*) apply->getScope();
+               }
+               if (drawPath == nil)
+                       goto clearCallBack;
+               if (fDraw->matrix) {
+                       SkDrawMatrix* matrix;
+                       if (fDraw->matrix->getType() == SkType_Matrix) 
+                               matrix = (SkDrawMatrix*) fDraw->matrix;
+                       else {
+                               SkApply* apply = (SkApply*) fDraw->matrix;
+                               apply->activate(*fMaker);
+                               apply->interpolate(*fMaker, v);
+                               matrix = (SkDrawMatrix*) apply->getScope();
+                       }
+                       if (matrix) {
+                               dst->addPath(drawPath->getPath(), matrix->getMatrix());
+                               goto clearCallBack;
+                       }
+               }
+               dst->addPath(drawPath->getPath());
+clearCallBack:
+               fMaker->clearExtraPropertyCallBack(fDraw->fType);
+       }
+
+private:
+
+       static bool Get2D(const char* token, size_t len, void* s2D, SkScriptValue* value) {
+               static const char match[] = "locX|locY|left|top|right|bottom|u|v" ;
+               SkShape2DPathEffect* shape2D = (SkShape2DPathEffect*) s2D;
+               int index;
+               if (SkAnimatorScript::MapEnums(match, token, len, &index) == false)
+                       return false;
+               SkASSERT((sizeof(SkPoint) +     sizeof(SkRect)) / sizeof(SkScalar) == 6);
+               if (index < 6) {
+                       value->fType = SkType_Float;
+                       value->fOperand.fScalar = (&shape2D->fLoc.fX)[index];
+               } else {
+                       value->fType = SkType_Int;
+                       value->fOperand.fS32 = (&shape2D->fU)[index - 6];
+               }
+               return true;
+       }
+       
+       SkPoint fLoc;
+       SkRect fUVBounds;
+       S32 fU;
+       S32 fV;
+       SkDrawShape2DPathEffect* fDraw;
+       SkAnimateMaker* fMaker;
+
+       // illegal
+       SkShape2DPathEffect(const SkShape2DPathEffect&);
+       SkShape2DPathEffect& operator=(const SkShape2DPathEffect&);
+};
+
+////////// SkDrawShape2DPathEffect
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawShape2DPathEffect::fInfo[] = {
+       SK_MEMBER_INHERITED,
+       SK_MEMBER(matrix, Matrix)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawShape2DPathEffect);
+
+SkDrawShape2DPathEffect::SkDrawShape2DPathEffect(SkDisplayTypes type) : fType(type) {
+}
+
+SkDrawShape2DPathEffect::~SkDrawShape2DPathEffect() {
+}
+
+void SkDrawShape2DPathEffect::onEndElement(SkAnimateMaker& maker) {
+       if (addPath == nil || (addPath->isPath() == false && addPath->isApply() == false) ||
+                       matrix == nil)
+               maker.setErrorCode(SkDisplayXMLParserError::kUnknownError); // !!! add error
+       else
+               fPathEffect = new SkShape2DPathEffect(this, &maker, matrix->getMatrix());
+}
+
+////////// SkDrawComposePathEffect
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawComposePathEffect::fInfo[] = {
+       SK_MEMBER(effect1, PathEffect),
+       SK_MEMBER(effect2, PathEffect)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawComposePathEffect);
+
+SkDrawComposePathEffect::SkDrawComposePathEffect(SkDisplayTypes type) : fType(type),
+       effect1(nil), effect2(nil) {
+}
+
+SkDrawComposePathEffect::~SkDrawComposePathEffect() {
+       delete effect1;
+       delete effect2;
+}
+
+bool SkDrawComposePathEffect::add(SkAnimateMaker& , SkDisplayable* child) {
+       if (effect1 == nil)
+               effect1 = (SkDrawPathEffect*) child;
+       else
+               effect2 = (SkDrawPathEffect*) child;
+       return true;
+}
+
+SkPathEffect* SkDrawComposePathEffect::getPathEffect() {
+       SkPathEffect* e1 = effect1->getPathEffect();
+       SkPathEffect* e2 = effect2->getPathEffect();
+       SkPathEffect* composite = new SkComposePathEffect(e1, e2);
+       e1->unref();
+       e2->unref();
+       return composite;
+}
+
+bool SkDrawComposePathEffect::isPaint() const {
+       return true;
+}
+
+//////////// SkDrawCornerPathEffect
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawCornerPathEffect::fInfo[] = {
+    SK_MEMBER(radius, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawCornerPathEffect);
+
+SkDrawCornerPathEffect::SkDrawCornerPathEffect(SkDisplayTypes type):
+    fType(type), radius(0) {
+}
+
+SkDrawCornerPathEffect::~SkDrawCornerPathEffect() {
+}
+
+SkPathEffect* SkDrawCornerPathEffect::getPathEffect() {
+    return new SkCornerPathEffect(radius);
+}
+
+/////////
+
+#include "SkExtras.h"
+
+const char kDrawShape1DPathEffectName[] = "pathEffect:shape1D";
+const char kDrawShape2DPathEffectName[] = "pathEffect:shape2D";
+const char kDrawComposePathEffectName[] = "pathEffect:compose";
+const char kDrawCornerPathEffectName[]  = "pathEffect:corner";
+
+class SkExtraPathEffects : public SkExtras {
+public:
+       SkExtraPathEffects(SkAnimator* animator) : 
+                       skDrawShape1DPathEffectType(SkType_Unknown),
+                       skDrawShape2DPathEffectType(SkType_Unknown),
+                       skDrawComposePathEffectType(SkType_Unknown),
+            skDrawCornerPathEffectType(SkType_Unknown) {
+       }
+       
+       virtual SkDisplayable* createInstance(SkDisplayTypes type) {
+               SkDisplayable* result = nil;
+               if (skDrawShape1DPathEffectType == type)
+                       result = new SkDrawShape1DPathEffect(type);
+               else if (skDrawShape2DPathEffectType == type)
+                       result = new SkDrawShape2DPathEffect(type);
+               else if (skDrawComposePathEffectType == type)
+                       result = new SkDrawComposePathEffect(type);
+        else if (skDrawCornerPathEffectType == type)
+            result = new SkDrawCornerPathEffect(type);
+               return result;
+       }
+
+       virtual bool definesType(SkDisplayTypes type) {
+               return type == skDrawShape1DPathEffectType || 
+                       type == skDrawShape2DPathEffectType || 
+                       type == skDrawComposePathEffectType ||
+            type == skDrawCornerPathEffectType;
+       }
+
+#if SK_USE_CONDENSED_INFO == 0
+       virtual const SkMemberInfo* getMembers(SkDisplayTypes type, int* infoCountPtr) {
+               const SkMemberInfo* info = nil;
+               int infoCount = 0;
+               if (skDrawShape1DPathEffectType == type) {
+                       info = SkDrawShape1DPathEffect::fInfo;
+                       infoCount = SkDrawShape1DPathEffect::fInfoCount;
+               } else if (skDrawShape2DPathEffectType == type) {
+                       info = SkDrawShape2DPathEffect::fInfo;
+                       infoCount = SkDrawShape2DPathEffect::fInfoCount;
+               } else if (skDrawComposePathEffectType == type) {
+                       info = SkDrawComposePathEffect::fInfo;
+                       infoCount = SkDrawShape1DPathEffect::fInfoCount;
+               } else if (skDrawCornerPathEffectType == type) {
+            info = SkDrawCornerPathEffect::fInfo;
+            infoCount = SkDrawCornerPathEffect::fInfoCount;
+        }
+               if (infoCountPtr)
+                       *infoCountPtr = infoCount;
+               return info;
+       }
+#endif
+
+#ifdef SK_DEBUG
+       virtual const char* getName(SkDisplayTypes type) {
+        if (skDrawShape1DPathEffectType == type)
+                       return kDrawShape1DPathEffectName;
+               else if (skDrawShape2DPathEffectType == type)
+                       return kDrawShape2DPathEffectName;
+               else if (skDrawComposePathEffectType == type)
+                       return kDrawComposePathEffectName;
+        else if (skDrawCornerPathEffectType == type)
+            return kDrawCornerPathEffectName;
+        return NULL;
+       }
+#endif
+
+       virtual SkDisplayTypes getType(const char name[], size_t len ) {
+               SkDisplayTypes* type = nil;
+               if (SK_LITERAL_STR_EQUAL(kDrawShape1DPathEffectName, name, len))
+                       type = &skDrawShape1DPathEffectType;
+               else if (SK_LITERAL_STR_EQUAL(kDrawShape2DPathEffectName, name, len))
+                       type = &skDrawShape2DPathEffectType;
+               else if (SK_LITERAL_STR_EQUAL(kDrawComposePathEffectName, name, len))
+                       type = &skDrawComposePathEffectType;
+        else if (SK_LITERAL_STR_EQUAL(kDrawCornerPathEffectName, name, len))
+            type = &skDrawCornerPathEffectType;
+               if (type) {
+                       if (*type == SkType_Unknown)
+                               *type = SkDisplayType::RegisterNewType();
+                       return *type;
+               }
+               return SkType_Unknown;
+       }
+
+private:
+       SkDisplayTypes skDrawShape1DPathEffectType;
+       SkDisplayTypes skDrawShape2DPathEffectType;
+       SkDisplayTypes skDrawComposePathEffectType;
+    SkDisplayTypes skDrawCornerPathEffectType;
+};
+
+
+void InitializeSkExtraPathEffects(SkAnimator* animator) {
+       animator->addExtras(new SkExtraPathEffects(animator));
+}
+
+////////////////
+
+
+SkExtras::SkExtras() : fExtraCallBack(nil), fExtraStorage(nil) {
+}
diff --git a/libs/graphics/animator/SkDrawFull.cpp b/libs/graphics/animator/SkDrawFull.cpp
new file mode 100644 (file)
index 0000000..3bf27d9
--- /dev/null
@@ -0,0 +1,10 @@
+#include "SkDrawFull.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+
+bool SkFull::draw(SkAnimateMaker& maker) {
+       SkBoundableAuto boundable(this, maker);
+       maker.fCanvas->drawPaint(*maker.fPaint);
+       return false;
+}
+
diff --git a/libs/graphics/animator/SkDrawFull.h b/libs/graphics/animator/SkDrawFull.h
new file mode 100644 (file)
index 0000000..8822b02
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef SkDrawFull_DEFINED
+#define SkDrawFull_DEFINED
+
+#include "SkBoundable.h"
+
+class SkFull : public SkBoundable {
+       DECLARE_EMPTY_MEMBER_INFO(Full);
+       virtual bool draw(SkAnimateMaker& );
+private:
+       typedef SkBoundable INHERITED;
+};
+
+#endif // SkDrawFull_DEFINED
diff --git a/libs/graphics/animator/SkDrawGradient.cpp b/libs/graphics/animator/SkDrawGradient.cpp
new file mode 100644 (file)
index 0000000..ae40728
--- /dev/null
@@ -0,0 +1,214 @@
+#include "SkDrawGradient.h"
+#include "SkAnimateMaker.h"
+#include "SkAnimatorScript.h"
+#include "SkGradientShader.h"
+#include "SkUnitMapper.h"
+
+SkScalar SkUnitToScalar(U16CPU x) {
+#ifdef SK_SCALAR_IS_FLOAT
+       return x / 65535.0f;
+#else
+       return x + (x >> 8);
+#endif
+}
+
+U16CPU SkScalarToUnit(SkScalar x) {
+       SkScalar pin =  SkScalarPin(x, 0, SK_Scalar1);
+#ifdef SK_SCALAR_IS_FLOAT
+       return (int) (pin * 65535.0f);
+#else
+       return pin - (pin >= 32768);
+#endif
+}
+
+class SkGradientUnitMapper : public SkUnitMapper {
+public:
+       SkGradientUnitMapper(SkAnimateMaker* maker, const char* script) : fMaker(maker), fScript(script) {
+       }
+protected:
+       virtual U16CPU mapUnit16(U16CPU x) {
+               fUnit = SkUnitToScalar(x);
+               SkScriptValue value;
+               SkAnimatorScript engine(*fMaker, nil, SkType_Float);
+               engine.propertyCallBack(GetUnitValue, &fUnit);
+               if (engine.evaluate(fScript, &value, SkType_Float)) 
+                       x = SkScalarToUnit(value.fOperand.fScalar);
+               return x;
+       }
+
+       static bool GetUnitValue(const char* token, size_t len, void* unitPtr, SkScriptValue* value) {
+               if (SK_LITERAL_STR_EQUAL("unit", token, len)) {
+                       value->fOperand.fScalar = *(SkScalar*) unitPtr;
+                       value->fType = SkType_Float;
+                       return true;
+               }
+               return false;
+       }
+
+       SkAnimateMaker* fMaker;
+       const char* fScript;
+       SkScalar fUnit;
+};
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkGradient::fInfo[] = {
+       SK_MEMBER_INHERITED,
+       SK_MEMBER_ARRAY(offsets, Float),
+       SK_MEMBER(unitMapper, String)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkGradient);
+
+SkGradient::SkGradient() : fUnitMapper(nil) {
+}
+
+SkGradient::~SkGradient() {
+       for (int index = 0; index < fDrawColors.count(); index++) 
+               delete fDrawColors[index];
+       delete fUnitMapper;
+}
+
+bool SkGradient::add(SkAnimateMaker& , SkDisplayable* child) {
+       SkASSERT(child);
+       if (child->isColor()) {
+               SkDrawColor* color = (SkDrawColor*) child;
+               *fDrawColors.append() = color;
+               return true;
+       }
+       return false;
+}
+
+int SkGradient::addPrelude() {
+       int count = fDrawColors.count();
+       fColors.setCount(count);
+       for (int index = 0; index < count; index++) 
+               fColors[index] = fDrawColors[index]->color;
+       return count;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkGradient::dumpRest(SkAnimateMaker* maker) {
+    dumpAttrs(maker);
+    //can a gradient have no colors?
+    bool closedYet = false;
+    SkDisplayList::fIndent += 4;
+    for (SkDrawColor** ptr = fDrawColors.begin(); ptr < fDrawColors.end(); ptr++) {
+        if (closedYet == false) {
+            SkDebugf(">\n");
+            closedYet = true;
+        }
+        SkDrawColor* color = *ptr;
+        color->dump(maker);
+    }
+    SkDisplayList::fIndent -= 4;    
+    dumpChildren(maker, closedYet); //dumps the matrix if it has one
+}
+#endif
+
+void SkGradient::onEndElement(SkAnimateMaker& maker) {
+    if (offsets.count() != 0) {
+        if (offsets.count() != fDrawColors.count()) {
+            maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsDontMatchColors);
+            return;
+        }
+        if (offsets[0] != 0) {
+            maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustStartWithZero);
+            return;
+        }
+        if (offsets[offsets.count()-1] != SK_Scalar1) {
+            maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustEndWithOne);
+            return;
+        }
+        for (int i = 1; i < offsets.count(); i++) {
+            if (offsets[i] <= offsets[i-1]) {
+                maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustIncrease);
+                return;
+            }
+            if (offsets[i] > SK_Scalar1) {
+                maker.setErrorCode(SkDisplayXMLParserError::kGradientOffsetsMustBeNoMoreThanOne);
+                return;
+            }
+        }
+    }
+       if (unitMapper.size() > 0) 
+               fUnitMapper = new SkGradientUnitMapper(&maker, unitMapper.c_str());
+       INHERITED::onEndElement(maker);
+}
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkLinearGradient::fInfo[] = {
+       SK_MEMBER_INHERITED,
+    SK_MEMBER_ARRAY(points, Float),
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkLinearGradient);
+
+SkLinearGradient::SkLinearGradient() { 
+}
+
+void SkLinearGradient::onEndElement(SkAnimateMaker& maker)
+{
+    if (points.count() != 4)
+        maker.setErrorCode(SkDisplayXMLParserError::kGradientPointsLengthMustBeFour);
+    INHERITED::onEndElement(maker);
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkLinearGradient::dump(SkAnimateMaker* maker) {
+    dumpBase(maker);
+    dumpRest(maker);
+    }
+#endif
+
+SkShader* SkLinearGradient::getShader() {
+       if (addPrelude() == 0 || points.count() != 4)
+               return nil;
+       SkShader* shader = SkGradientShader::CreateLinear((SkPoint*)points.begin(),
+               fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode, fUnitMapper);
+       SkAutoTDelete<SkShader> autoDel(shader);
+       addPostlude(shader);
+       (void)autoDel.detach();
+       return shader;
+}
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkRadialGradient::fInfo[] = {
+       SK_MEMBER_INHERITED,
+       SK_MEMBER(center, Point),
+       SK_MEMBER(radius, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkRadialGradient);
+
+SkRadialGradient::SkRadialGradient() : radius(0) { 
+       center.set(0, 0); 
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkRadialGradient::dump(SkAnimateMaker* maker) {
+    dumpBase(maker);
+    dumpRest(maker);
+}
+#endif
+
+SkShader* SkRadialGradient::getShader() {
+       if (addPrelude() == 0)
+               return nil;
+       SkShader* shader = SkGradientShader::CreateRadial(center,
+               radius, fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode, fUnitMapper);
+       SkAutoTDelete<SkShader> autoDel(shader);
+       addPostlude(shader);
+       (void)autoDel.detach();
+       return shader;
+}
diff --git a/libs/graphics/animator/SkDrawGradient.h b/libs/graphics/animator/SkDrawGradient.h
new file mode 100644 (file)
index 0000000..2940b76
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef SkDrawGradient_DEFINED
+#define SkDrawGradient_DEFINED
+
+#include "SkDrawColor.h"
+#include "SkDrawShader.h"
+#include "SkIntArray.h"
+
+class SkUnitMapper;
+
+class SkGradient : public SkDrawShader {
+       DECLARE_PRIVATE_MEMBER_INFO(Gradient);
+       SkGradient();
+       virtual ~SkGradient();
+       virtual bool add(SkAnimateMaker& , SkDisplayable* child);
+#ifdef SK_DUMP_ENABLED
+    virtual void dumpRest(SkAnimateMaker*);
+#endif    
+       virtual void onEndElement(SkAnimateMaker& );
+protected:
+       SkTDScalarArray offsets;
+       SkString unitMapper;
+       SkTDColorArray fColors;
+       SkTDDrawColorArray fDrawColors;
+       SkUnitMapper* fUnitMapper;
+       int addPrelude();
+private:
+       typedef SkDrawShader INHERITED;
+};
+
+class SkLinearGradient : public SkGradient {
+       DECLARE_MEMBER_INFO(LinearGradient);
+       SkLinearGradient();
+    virtual void onEndElement(SkAnimateMaker& );
+#ifdef SK_DUMP_ENABLED
+    virtual void dump(SkAnimateMaker*);
+#endif
+       virtual SkShader* getShader();
+protected:
+    SkTDScalarArray points;
+private:
+       typedef SkGradient INHERITED;
+};
+
+class SkRadialGradient : public SkGradient {
+       DECLARE_MEMBER_INFO(RadialGradient);
+       SkRadialGradient();
+#ifdef SK_DUMP_ENABLED
+    virtual void dump(SkAnimateMaker*);
+#endif    
+       virtual SkShader* getShader();
+protected:
+       SkPoint center;
+       SkScalar radius;
+private:
+       typedef SkGradient INHERITED;
+};
+
+#endif // SkDrawGradient_DEFINED
+
diff --git a/libs/graphics/animator/SkDrawGroup.cpp b/libs/graphics/animator/SkDrawGroup.cpp
new file mode 100644 (file)
index 0000000..89232dd
--- /dev/null
@@ -0,0 +1,314 @@
+#include "SkDrawGroup.h"
+#include "SkAnimateMaker.h"
+#include "SkAnimatorScript.h"
+#include "SkCanvas.h"
+#include "SkDisplayApply.h"
+#include "SkPaint.h"
+#ifdef SK_DEBUG
+#include "SkDisplayList.h"
+#endif
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkGroup::fInfo[] = {
+       SK_MEMBER(condition, String),
+       SK_MEMBER(enableCondition, String)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkGroup);
+
+SkGroup::SkGroup() : fParentList(nil), fOriginal(nil) {
+}
+
+SkGroup::~SkGroup() {
+       if (fOriginal)  // has been copied
+               return;
+       int index = 0;
+       int max = fCopies.count() << 5;
+       for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               if (index >= max || markedForDelete(index))
+                       delete *ptr;
+//             else {
+//                     SkApply* apply = (SkApply*) *ptr;
+//                     SkASSERT(apply->isApply());
+//                     SkASSERT(apply->getScope());
+//                     delete apply->getScope();
+//             }
+               index++;
+       }
+}
+
+bool SkGroup::add(SkAnimateMaker& , SkDisplayable* child) {
+       SkASSERT(child); 
+//     SkASSERT(child->isDrawable());
+       *fChildren.append() = (SkDrawable*) child;
+       if (child->isGroup()) {
+               SkGroup* groupie = (SkGroup*) child;
+               SkASSERT(groupie->fParentList == nil);
+               groupie->fParentList = &fChildren;
+       }
+       return true;
+}
+
+bool SkGroup::contains(SkDisplayable* match) {
+       for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               SkDrawable* drawable = *ptr;
+               if (drawable == match || drawable->contains(match))
+                       return true;
+       }
+       return false;
+}
+
+SkGroup* SkGroup::copy() {
+       SkGroup* result = new SkGroup();
+       result->fOriginal = this;
+       result->fChildren = fChildren;
+       return result;
+}
+
+SkBool SkGroup::copySet(int index) {
+       return (fCopies[index >> 5] & 1 << (index & 0x1f)) != 0;
+}
+
+SkDisplayable* SkGroup::deepCopy(SkAnimateMaker* maker) {
+    SkDisplayable* copy = INHERITED::deepCopy(maker);
+    for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+        SkDisplayable* displayable = (SkDisplayable*)*ptr;
+        SkDisplayable* deeperCopy = displayable->deepCopy(maker);
+        ((SkGroup*)copy)->add(*maker, deeperCopy);
+    }
+    return copy;
+}
+
+bool SkGroup::doEvent(SkDisplayEvent::Kind kind, SkEventState* state) {
+       bool handled = false;
+       for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               SkDrawable* drawable = *ptr;
+               if (drawable->isDrawable() == false)
+                       continue;
+               handled |= drawable->doEvent(kind, state);
+       }
+       return handled;
+}
+
+bool SkGroup::draw(SkAnimateMaker& maker) {
+       bool conditionTrue = ifCondition(maker, this, condition);
+       bool result = false;
+       for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               SkDrawable* drawable = *ptr;
+               if (drawable->isDrawable() == false)
+                       continue;
+               if (conditionTrue == false) {
+                       if (drawable->isApply())
+                               ((SkApply*) drawable)->disable();
+                       continue;
+               }
+               maker.validate();
+               result |= drawable->draw(maker);
+               maker.validate();
+       }
+       return result;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkGroup::dump(SkAnimateMaker* maker) {
+       dumpBase(maker);
+       if (condition.size() > 0)
+               SkDebugf("condition=\"%s\" ", condition.c_str());
+    if (enableCondition.size() > 0)
+               SkDebugf("enableCondition=\"%s\" ", enableCondition.c_str());
+    dumpDrawables(maker);
+}
+
+void SkGroup::dumpDrawables(SkAnimateMaker* maker) {
+    SkDisplayList::fIndent += 4;
+       int save = SkDisplayList::fDumpIndex;
+       SkDisplayList::fDumpIndex = 0;
+    bool closedYet = false;
+       for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+        if (closedYet == false) {
+            closedYet = true;
+            SkDebugf(">\n");
+        }
+               SkDrawable* drawable = *ptr;
+               drawable->dump(maker);
+               SkDisplayList::fDumpIndex++;
+       }
+       SkDisplayList::fIndent -= 4;
+       SkDisplayList::fDumpIndex = save;
+    if (closedYet) //we had children, now it's time to close the group
+        dumpEnd(maker);
+    else    //no children
+        SkDebugf("/>\n");
+}
+
+void SkGroup::dumpEvents() {
+       for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               SkDrawable* drawable = *ptr;
+               drawable->dumpEvents();
+       }
+}
+#endif
+
+bool SkGroup::enable(SkAnimateMaker& maker ) {
+       reset();
+       for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               SkDrawable* drawable = *ptr;
+               if (ifCondition(maker, drawable, enableCondition) == false)
+                       continue;
+               drawable->enable(maker);
+       }
+       return true;    // skip add; already added so that scope is findable by children
+}
+
+int SkGroup::findGroup(SkDrawable* match,  SkTDDrawableArray** list,
+                                SkGroup** parent, SkGroup** found, SkTDDrawableArray** grandList) {
+       *list = &fChildren;
+       for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               SkDrawable* drawable = *ptr;
+               if (drawable->isGroup()) {
+                       SkGroup* childGroup = (SkGroup*) drawable;
+                       if (childGroup->fOriginal == match)
+                               goto foundMatch;
+               }
+               if (drawable == match) {
+foundMatch:
+                       *parent = this;
+                       return (int) (ptr - fChildren.begin());
+               }
+       }
+       *grandList = &fChildren;
+       return SkDisplayList::SearchForMatch(match, list, parent, found, grandList);
+}
+
+bool SkGroup::hasEnable() const {
+       return true;
+}
+
+bool SkGroup::ifCondition(SkAnimateMaker& maker, SkDrawable* drawable,
+               SkString& conditionString) {
+       if (conditionString.size() == 0)
+               return true;
+       int32_t result;
+       bool success = SkAnimatorScript::EvaluateInt(maker, this, conditionString.c_str(), &result);
+#ifdef SK_DUMP_ENABLED
+       if (maker.fDumpGConditions) {
+               SkDebugf("group: ");
+               dumpBase(&maker);
+               SkDebugf("condition=%s ", conditionString.c_str());
+               if (success == false)
+                       SkDebugf("(script failed)\n");
+               else
+                       SkDebugf("success=%s\n", result != 0 ? "true" : "false");
+       }
+#endif
+       return success && result != 0;
+}
+
+void SkGroup::initialize() {
+       for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               SkDrawable* drawable = *ptr;
+               if (drawable->isDrawable() == false)
+                       continue;
+               drawable->initialize();
+       }
+}
+
+void SkGroup::markCopyClear(int index) {
+       if (index < 0)
+               index = fChildren.count();
+       fCopies[index >> 5] &= ~(1 << (index & 0x1f));
+}
+
+void SkGroup::markCopySet(int index) {
+       if (index < 0)
+               index = fChildren.count();
+       fCopies[index >> 5] |= 1 << (index & 0x1f);
+}
+
+void SkGroup::markCopySize(int index) {
+       if (index < 0)
+               index = fChildren.count() + 1;
+       int oldLongs = fCopies.count();
+       int newLongs = (index >> 5) + 1;
+       if (oldLongs < newLongs) {
+               fCopies.setCount(newLongs);
+               memset(&fCopies[oldLongs], 0, (newLongs - oldLongs) << 2);
+       }
+}
+
+void SkGroup::reset() {
+       if (fOriginal)  // has been copied
+               return;
+       int index = 0;
+       int max = fCopies.count() << 5;
+       for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               if (index >= max || copySet(index) == false)
+                       continue;
+               SkApply* apply = (SkApply*) *ptr;
+               SkASSERT(apply->isApply());
+               SkASSERT(apply->getScope());
+               *ptr = apply->getScope();
+               markCopyClear(index);
+               index++;
+       }
+}
+
+bool SkGroup::resolveIDs(SkAnimateMaker& maker, SkDisplayable* orig, SkApply* apply) {
+       SkGroup* original = (SkGroup*) orig;
+       SkTDDrawableArray& originalChildren = original->fChildren;
+       SkDrawable** originalPtr = originalChildren.begin();
+       SkDrawable** ptr = fChildren.begin();
+       SkDrawable** end = fChildren.end();
+       SkDrawable** origChild = ((SkGroup*) orig)->fChildren.begin();
+       while (ptr < end) {
+               SkDrawable* drawable = *ptr++;
+               maker.resolveID(drawable, *origChild++);
+               if (drawable->resolveIDs(maker, *originalPtr++, apply) == true)
+                       return true; // failed
+       }
+       return false;
+}
+
+void SkGroup::setSteps(int steps) {
+       for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               SkDrawable* drawable = *ptr;
+               if (drawable->isDrawable() == false)
+                       continue;
+               drawable->setSteps(steps);
+       }
+}
+
+#ifdef SK_DEBUG
+void SkGroup::validate() {
+       for (SkDrawable** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               SkDrawable* drawable = *ptr;
+               drawable->validate();
+       }
+}
+#endif
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkSave::fInfo[] = {
+       SK_MEMBER_INHERITED
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkSave);
+
+bool SkSave::draw(SkAnimateMaker& maker) {
+       maker.fCanvas->save();
+       SkPaint* save = maker.fPaint;
+       SkPaint local = SkPaint(*maker.fPaint);
+       maker.fPaint = &local;
+       bool result = INHERITED::draw(maker);
+       maker.fPaint = save;
+       maker.fCanvas->restore();
+       return result;
+}
+
+
diff --git a/libs/graphics/animator/SkDrawGroup.h b/libs/graphics/animator/SkDrawGroup.h
new file mode 100644 (file)
index 0000000..45e3a43
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef SkDrawGroup_DEFINED
+#define SkDrawGroup_DEFINED
+
+#include "SkDrawable.h"
+#include "SkIntArray.h"
+#include "SkMemberInfo.h"
+
+class SkGroup : public SkDrawable {    //interface for schema element <g>
+public:
+       DECLARE_MEMBER_INFO(Group);
+       SkGroup();
+       virtual ~SkGroup();
+       virtual bool add(SkAnimateMaker& , SkDisplayable* child);
+       virtual bool contains(SkDisplayable* );
+       SkGroup* copy();
+       SkBool copySet(int index);
+    virtual SkDisplayable* deepCopy(SkAnimateMaker* );
+       virtual bool doEvent(SkDisplayEvent::Kind , SkEventState* state );
+       virtual bool draw(SkAnimateMaker& );
+#ifdef SK_DUMP_ENABLED
+       virtual void dump(SkAnimateMaker* );
+    virtual void dumpDrawables(SkAnimateMaker* );
+       virtual void dumpEvents();
+#endif
+       int findGroup(SkDrawable* drawable,  SkTDDrawableArray** list,
+               SkGroup** parent, SkGroup** found, SkTDDrawableArray** grandList);
+       virtual bool enable(SkAnimateMaker& );
+       SkTDDrawableArray* getChildren() { return &fChildren; }
+       SkGroup* getOriginal() { return fOriginal; }
+       virtual bool hasEnable() const;
+       virtual void initialize();
+       SkBool isACopy() { return fOriginal != nil; }
+       void markCopyClear(int index);
+       void markCopySet(int index);
+       void markCopySize(int index);
+    bool markedForDelete(int index) const { return (fCopies[index >> 5] & 1 << (index & 0x1f)) == 0; }
+       void reset();
+       bool resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* );
+       virtual void setSteps(int steps);
+#ifdef SK_DEBUG
+       virtual void validate();
+#endif
+protected:
+       bool ifCondition(SkAnimateMaker& maker, SkDrawable* drawable,
+               SkString& conditionString);
+       SkString condition;
+       SkString enableCondition;
+       SkTDDrawableArray fChildren;
+       SkTDDrawableArray* fParentList;
+       SkTDIntArray fCopies;
+       SkGroup* fOriginal;
+private:
+       typedef SkDrawable INHERITED;
+};
+
+class SkSave: public SkGroup {
+       DECLARE_MEMBER_INFO(Save);
+       virtual bool draw(SkAnimateMaker& );
+private:
+       typedef SkGroup INHERITED;
+};
+
+#endif // SkDrawGroup_DEFINED
diff --git a/libs/graphics/animator/SkDrawLine.cpp b/libs/graphics/animator/SkDrawLine.cpp
new file mode 100644 (file)
index 0000000..3c38fbe
--- /dev/null
@@ -0,0 +1,28 @@
+#include "SkDrawLine.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkLine::fInfo[] = {
+       SK_MEMBER(x1, Float),
+       SK_MEMBER(x2, Float),
+       SK_MEMBER(y1, Float),
+       SK_MEMBER(y2, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkLine);
+
+SkLine::SkLine() : x1(0), x2(0), y1(0), y2(0) { 
+}
+
+bool SkLine::draw(SkAnimateMaker& maker) {
+       SkPoint start = {x1, y1};
+       SkPoint stop = {x2, y2};
+       SkBoundableAuto boundable(this, maker);
+       maker.fCanvas->drawLine(start, stop, *maker.fPaint);
+       return false;
+}
diff --git a/libs/graphics/animator/SkDrawLine.h b/libs/graphics/animator/SkDrawLine.h
new file mode 100644 (file)
index 0000000..682c7ee
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef SkDrawLine_DEFINED
+#define SkDrawLine_DEFINED
+
+#include "SkBoundable.h"
+#include "SkMemberInfo.h"
+
+class SkLine : public SkBoundable {
+       DECLARE_MEMBER_INFO(Line);
+       SkLine();
+       virtual bool draw(SkAnimateMaker& );
+private:
+       SkScalar x1;
+       SkScalar x2;
+       SkScalar y1;
+       SkScalar y2;
+       typedef SkBoundable INHERITED;
+};
+
+#endif // SkDrawLine_DEFINED
+
diff --git a/libs/graphics/animator/SkDrawMatrix.cpp b/libs/graphics/animator/SkDrawMatrix.cpp
new file mode 100644 (file)
index 0000000..18b30e6
--- /dev/null
@@ -0,0 +1,273 @@
+#include "SkDrawMatrix.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkParse.h"
+#include "SkMatrixParts.h"
+#include "SkScript.h"
+#include "SkTypedArray.h"
+
+enum SkDrawMatrix_Properties {
+       SK_PROPERTY(perspectX),
+       SK_PROPERTY(perspectY),
+       SK_PROPERTY(rotate),
+       SK_PROPERTY(scale),
+       SK_PROPERTY(scaleX),
+       SK_PROPERTY(scaleY),
+       SK_PROPERTY(skewX),
+       SK_PROPERTY(skewY),
+       SK_PROPERTY(translate),
+       SK_PROPERTY(translateX),
+       SK_PROPERTY(translateY)
+};
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawMatrix::fInfo[] = {
+       SK_MEMBER_ARRAY(matrix, Float),
+       SK_MEMBER_PROPERTY(perspectX, Float),
+       SK_MEMBER_PROPERTY(perspectY, Float),
+       SK_MEMBER_PROPERTY(rotate, Float),
+       SK_MEMBER_PROPERTY(scale, Float),
+       SK_MEMBER_PROPERTY(scaleX, Float),
+       SK_MEMBER_PROPERTY(scaleY, Float),
+       SK_MEMBER_PROPERTY(skewX, Float),
+       SK_MEMBER_PROPERTY(skewY, Float),
+       SK_MEMBER_PROPERTY(translate, Point),
+       SK_MEMBER_PROPERTY(translateX, Float),
+       SK_MEMBER_PROPERTY(translateY, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawMatrix);
+
+SkDrawMatrix::SkDrawMatrix() : fChildHasID(false), fDirty(false) { 
+       fConcat.reset();
+       fMatrix.reset(); 
+}
+
+SkDrawMatrix::~SkDrawMatrix() {
+       for (SkMatrixPart** part = fParts.begin(); part < fParts.end();  part++)
+               delete *part;
+}
+
+bool SkDrawMatrix::add(SkAnimateMaker& maker, SkDisplayable* child) {
+       SkASSERT(child && child->isMatrixPart());
+       SkMatrixPart* part = (SkMatrixPart*) child;
+       *fParts.append() = part;
+       if (part->add())
+               maker.setErrorCode(SkDisplayXMLParserError::kErrorAddingToMatrix); 
+       return true;
+}
+
+bool SkDrawMatrix::childrenNeedDisposing() const { 
+       return false;
+}
+
+SkDisplayable* SkDrawMatrix::deepCopy(SkAnimateMaker* maker) {
+       SkDrawMatrix* copy = (SkDrawMatrix*)
+               SkDisplayType::CreateInstance(maker, SkType_Matrix);
+       SkASSERT(fParts.count() == 0);
+       copy->fMatrix = fMatrix;
+       copy->fConcat = fConcat;
+       return copy;
+}
+
+void SkDrawMatrix::dirty() { 
+       fDirty = true; 
+}
+
+bool SkDrawMatrix::draw(SkAnimateMaker& maker) {
+       SkMatrix& concat = getMatrix();
+       maker.fCanvas->concat(concat);
+       return false;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkDrawMatrix::dump(SkAnimateMaker* maker) {
+       dumpBase(maker);
+       if (fMatrix.isIdentity()) {
+               SkDebugf("matrix=\"identity\"/>\n");
+               return;
+       }
+       SkScalar result;
+       result = fMatrix.getScaleX();
+       if (result != SK_Scalar1)
+               SkDebugf("sx=\"%g\" ", SkScalarToFloat(result));
+       result = fMatrix.getScaleY();
+       if (result != SK_Scalar1)
+               SkDebugf("sy=\"%g\" ", SkScalarToFloat(result));
+       result = fMatrix.getSkewX();
+       if (result)
+               SkDebugf("skew-x=\"%g\" ", SkScalarToFloat(result));
+       result = fMatrix.getSkewY();
+       if (result)
+               SkDebugf("skew-y=\"%g\" ", SkScalarToFloat(result));
+       result = fMatrix.getTranslateX();
+       if (result)
+               SkDebugf("tx=\"%g\" ", SkScalarToFloat(result));
+       result = fMatrix.getTranslateY();
+       if (result)
+               SkDebugf("ty=\"%g\" ", SkScalarToFloat(result));
+       result = fMatrix.getPerspX();
+       if (result)
+               SkDebugf("perspect-x=\"%g\" ", SkScalarToFloat(result));
+       result = fMatrix.getPerspY();
+       if (result)
+               SkDebugf("perspect-y=\"%g\" ", SkScalarToFloat(result));
+       SkDebugf("/>\n");
+}
+#endif
+
+SkMatrix& SkDrawMatrix::getMatrix() {
+       if (fDirty == false)
+               return fConcat;
+       fMatrix.reset();
+       for (SkMatrixPart** part = fParts.begin(); part < fParts.end();  part++) {
+               (*part)->add();
+               fConcat = fMatrix;
+       }
+       fDirty = false;
+       return fConcat;
+}
+
+bool SkDrawMatrix::getProperty(int index, SkScriptValue* value) const {
+       value->fType = SkType_Float;
+       SkScalar result;
+       switch (index) {
+               case SK_PROPERTY(perspectX):
+                       result = fMatrix.getPerspX();
+                       break;
+               case SK_PROPERTY(perspectY):
+                       result = fMatrix.getPerspY();
+                       break;
+               case SK_PROPERTY(scaleX):
+                       result = fMatrix.getScaleX();
+                       break;
+               case SK_PROPERTY(scaleY):
+                       result = fMatrix.getScaleY();
+                       break;
+               case SK_PROPERTY(skewX):
+                       result = fMatrix.getSkewX();
+                       break;
+               case SK_PROPERTY(skewY):
+                       result = fMatrix.getSkewY();
+                       break;
+               case SK_PROPERTY(translateX):
+                       result = fMatrix.getTranslateX();
+                       break;
+               case SK_PROPERTY(translateY):
+                       result = fMatrix.getTranslateY();
+                       break;
+               default:
+//                     SkASSERT(0);
+                       return false;
+       }
+       value->fOperand.fScalar = result;
+       return true;
+}
+
+void SkDrawMatrix::initialize() {
+       fConcat = fMatrix;
+}
+
+void SkDrawMatrix::onEndElement(SkAnimateMaker& ) {
+       if (matrix.count() > 0) {
+               SkScalar* vals = matrix.begin();
+               fMatrix.setScaleX(vals[0]);
+               fMatrix.setSkewX(vals[1]);
+               fMatrix.setTranslateX(vals[2]);
+               fMatrix.setSkewY(vals[3]);
+               fMatrix.setScaleY(vals[4]);
+               fMatrix.setTranslateY(vals[5]);
+#ifdef SK_SCALAR_IS_FIXED
+               fMatrix.setPerspX(SkFixedToFract(vals[6]));
+               fMatrix.setPerspY(SkFixedToFract(vals[7]));
+#else
+               fMatrix.setPerspX(vals[6]);
+               fMatrix.setPerspY(vals[7]);
+#endif
+//             fMatrix.setPerspW(vals[8]);
+               goto setConcat;
+       }
+       if (fChildHasID == false) {
+               {
+                       for (SkMatrixPart** part = fParts.begin(); part < fParts.end();  part++)
+                               delete *part;
+               }
+               fParts.reset();
+setConcat:
+               fConcat = fMatrix;
+               fDirty = false;
+       }
+}
+
+void SkDrawMatrix::setChildHasID() { 
+       fChildHasID = true; 
+}
+
+bool SkDrawMatrix::setProperty(int index, SkScriptValue& scriptValue) {
+       SkScalar number = scriptValue.fOperand.fScalar;
+       switch (index) {
+               case SK_PROPERTY(translate):
+       //              SkScalar xy[2];
+                       SkASSERT(scriptValue.fType == SkType_Array);
+                       SkASSERT(scriptValue.fOperand.fArray->getType() == SkType_Float);
+                       SkASSERT(scriptValue.fOperand.fArray->count() == 2);
+       //              SkParse::FindScalars(scriptValue.fOperand.fString->c_str(), xy, 2);
+                       fMatrix.setTranslateX((*scriptValue.fOperand.fArray)[0].fScalar);
+                       fMatrix.setTranslateY((*scriptValue.fOperand.fArray)[1].fScalar);
+                       return true;
+               case SK_PROPERTY(perspectX):
+#ifdef SK_SCALAR_IS_FIXED
+                       fMatrix.setPerspX(SkFixedToFract(number));
+#else
+                       fMatrix.setPerspX(number);
+#endif 
+                       break;
+               case SK_PROPERTY(perspectY):
+#ifdef SK_SCALAR_IS_FIXED
+                       fMatrix.setPerspY(SkFixedToFract(number));
+#else
+                       fMatrix.setPerspY(number);
+#endif 
+                       break;
+               case SK_PROPERTY(rotate): {
+                       SkMatrix temp;
+                       temp.setRotate(number, 0, 0);
+                       fMatrix.setScaleX(temp.getScaleX());
+                       fMatrix.setScaleY(temp.getScaleY());
+                       fMatrix.setSkewX(temp.getSkewX());
+                       fMatrix.setSkewY(temp.getSkewY());
+                       } break;
+               case SK_PROPERTY(scale):
+                       fMatrix.setScaleX(number);
+                       fMatrix.setScaleY(number);
+                       break;
+               case SK_PROPERTY(scaleX):
+                       fMatrix.setScaleX(number);
+                       break;
+               case SK_PROPERTY(scaleY):
+                       fMatrix.setScaleY(number);
+                       break;
+               case SK_PROPERTY(skewX):
+                       fMatrix.setSkewX(number);
+                       break;
+               case SK_PROPERTY(skewY):
+                       fMatrix.setSkewY(number);
+                       break;
+               case SK_PROPERTY(translateX):
+                       fMatrix.setTranslateX(number);
+                       break;
+               case SK_PROPERTY(translateY):
+                       fMatrix.setTranslateY(number);
+                       break;
+               default:
+                       SkASSERT(0);
+                       return false;
+       }
+       fConcat = fMatrix;
+       return true;
+}
+
diff --git a/libs/graphics/animator/SkDrawMatrix.h b/libs/graphics/animator/SkDrawMatrix.h
new file mode 100644 (file)
index 0000000..df55292
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef SkDrawMatrix_DEFINED
+#define SkDrawMatrix_DEFINED
+
+#include "SkDrawable.h"
+#include "SkMatrix.h"
+#include "SkMemberInfo.h"
+#include "SkIntArray.h"
+
+class SkMatrixPart;
+
+class SkDrawMatrix : public SkDrawable {
+       DECLARE_DRAW_MEMBER_INFO(Matrix);
+       SkDrawMatrix();
+       virtual ~SkDrawMatrix();
+       virtual bool add(SkAnimateMaker& , SkDisplayable* child);
+       virtual bool childrenNeedDisposing() const;
+       virtual void dirty();
+       virtual bool draw(SkAnimateMaker& );
+#ifdef SK_DUMP_ENABLED
+       virtual void dump(SkAnimateMaker* );
+#endif
+       SkMatrix& getMatrix();
+       virtual bool getProperty(int index, SkScriptValue* value) const;
+       virtual void initialize();
+       virtual void onEndElement(SkAnimateMaker& );
+       virtual void setChildHasID();
+       virtual bool setProperty(int index, SkScriptValue& );
+
+       void concat(SkMatrix& inMatrix) {
+               fConcat.preConcat(inMatrix);
+       }
+
+       virtual SkDisplayable* deepCopy(SkAnimateMaker* );
+
+
+       void rotate(SkScalar degrees, SkPoint& center) {
+               fMatrix.preRotate(degrees, center.fX, center.fY);
+       }
+
+       void set(SkMatrix& src) {
+               fMatrix.preConcat(src);
+       }
+
+       void scale(SkScalar scaleX, SkScalar scaleY, SkPoint& center) {
+               fMatrix.preScale(scaleX, scaleY, center.fX, center.fY);
+       }
+
+       void skew(SkScalar skewX, SkScalar skewY, SkPoint& center) {
+               fMatrix.preSkew(skewX, skewY, center.fX, center.fY);
+       }
+
+       void translate(SkScalar x, SkScalar y) {
+               fMatrix.preTranslate(x, y);
+       }
+private:
+       SkTDScalarArray matrix;
+       SkMatrix fConcat;
+       SkMatrix fMatrix;
+       SkTDMatrixPartArray fParts;
+       SkBool8 fChildHasID;
+       SkBool8 fDirty;
+       typedef SkDrawable INHERITED;
+};
+
+#endif // SkDrawMatrix_DEFINED
diff --git a/libs/graphics/animator/SkDrawOval.cpp b/libs/graphics/animator/SkDrawOval.cpp
new file mode 100644 (file)
index 0000000..11614eb
--- /dev/null
@@ -0,0 +1,20 @@
+#include "SkDrawOval.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkOval::fInfo[] = {
+       SK_MEMBER_INHERITED,
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkOval);
+
+bool SkOval::draw(SkAnimateMaker& maker) {
+       SkBoundableAuto boundable(this, maker);
+       maker.fCanvas->drawOval(fRect, *maker.fPaint);
+       return false;
+}
+
diff --git a/libs/graphics/animator/SkDrawOval.h b/libs/graphics/animator/SkDrawOval.h
new file mode 100644 (file)
index 0000000..e91576a
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef SkDrawOval_DEFINED
+#define SkDrawOval_DEFINED
+
+#include "SkDrawRectangle.h"
+
+class SkOval : public SkDrawRect {
+       DECLARE_MEMBER_INFO(Oval);
+       virtual bool draw(SkAnimateMaker& );
+private:
+       typedef SkDrawRect INHERITED;
+};
+
+#endif // SkDrawOval_DEFINED
+
diff --git a/libs/graphics/animator/SkDrawPaint.cpp b/libs/graphics/animator/SkDrawPaint.cpp
new file mode 100644 (file)
index 0000000..1f13091
--- /dev/null
@@ -0,0 +1,260 @@
+#include "SkDrawPaint.h"
+#include "SkAnimateMaker.h"
+#include "SkDrawColor.h"
+#include "SkDrawShader.h"
+#include "SkMaskFilter.h"
+#include "SkPaintParts.h"
+#include "SkPathEffect.h"
+
+enum SkPaint_Functions {
+       SK_FUNCTION(measureText)
+};
+
+enum SkPaint_Properties {
+       SK_PROPERTY(ascent),
+       SK_PROPERTY(descent)
+};
+
+// !!! in the future, this could be compiled by build-condensed-info into an array of parameters
+// with a lookup table to find the first parameter -- for now, it is iteratively searched through
+const SkFunctionParamType SkDrawPaint::fFunctionParameters[] = {
+       (SkFunctionParamType) SkType_String,
+       (SkFunctionParamType) 0 // terminator for parameter list (there may be multiple parameter lists)
+};
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawPaint::fInfo[] = {
+       SK_MEMBER(antiAlias, Boolean),
+       SK_MEMBER_PROPERTY(ascent, Float),
+       SK_MEMBER(color, Color),
+       SK_MEMBER_PROPERTY(descent, Float),
+       SK_MEMBER(fakeBold, Boolean),
+       SK_MEMBER(filterType, FilterType),
+       SK_MEMBER(linearText, Boolean),
+       SK_MEMBER(maskFilter, MaskFilter),
+       SK_MEMBER_FUNCTION(measureText, Float),
+       SK_MEMBER(pathEffect, PathEffect),
+       SK_MEMBER(shader, Shader),
+       SK_MEMBER(strikeThru, Boolean),
+       SK_MEMBER(stroke, Boolean),
+       SK_MEMBER(strokeCap, Cap),
+       SK_MEMBER(strokeJoin, Join),
+       SK_MEMBER(strokeMiter, Float),
+       SK_MEMBER(strokeWidth, Float),
+       SK_MEMBER(style, Style),
+       SK_MEMBER(textAlign, Align),
+       SK_MEMBER(textScaleX, Float),
+       SK_MEMBER(textSize, Float),
+       SK_MEMBER(textSkewX, Float),
+       SK_MEMBER(typeface, Typeface),
+       SK_MEMBER(underline, Boolean),
+       SK_MEMBER(xfermode, Xfermode)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawPaint);
+
+SkDrawPaint::SkDrawPaint() : antiAlias(-1), color(NULL), fakeBold(-1), filterType((SkPaint::FilterType) -1),
+       linearText(-1), maskFilter((SkDrawMaskFilter*) -1), pathEffect((SkDrawPathEffect*) -1),
+       shader((SkDrawShader*) -1), strikeThru(-1), stroke(-1),
+       strokeCap((SkPaint::Cap) -1), strokeJoin((SkPaint::Join) -1), strokeMiter(SK_ScalarNaN), 
+       strokeWidth(SK_ScalarNaN), style((SkPaint::Style) -1),
+       textAlign((SkPaint::Align) -1), textScaleX(SK_ScalarNaN), textSize(SK_ScalarNaN), 
+       textSkewX(SK_ScalarNaN), typeface((SkDrawTypeface*) -1),
+       underline(-1), xfermode((SkPorterDuff::Mode) -1), fOwnsColor(false), fOwnsMaskFilter(false), 
+       fOwnsPathEffect(false), fOwnsShader(false), fOwnsTypeface(false) {
+}
+
+SkDrawPaint::~SkDrawPaint() {
+       if (fOwnsColor)
+               delete color;
+       if (fOwnsMaskFilter)
+               delete maskFilter;
+       if (fOwnsPathEffect)
+               delete pathEffect;
+       if (fOwnsShader)
+               delete shader;
+       if (fOwnsTypeface)
+               delete typeface;
+}
+
+bool SkDrawPaint::add(SkAnimateMaker& maker, SkDisplayable* child) {
+       SkASSERT(child && child->isPaintPart());
+       SkPaintPart* part = (SkPaintPart*) child;
+       if (part->add())
+               maker.setErrorCode(SkDisplayXMLParserError::kErrorAddingToPaint); 
+       return true;
+}
+
+SkDisplayable* SkDrawPaint::deepCopy(SkAnimateMaker* maker) {
+       SkDrawColor* tempColor = color;
+       color = NULL;
+       SkDrawPaint* copy = (SkDrawPaint*) INHERITED::deepCopy(maker);
+       color = tempColor;
+       tempColor = (SkDrawColor*) color->deepCopy(maker);
+       tempColor->setParent(copy);
+       tempColor->add();
+       copy->fOwnsColor = true;
+       return copy;
+}
+
+bool SkDrawPaint::draw(SkAnimateMaker& maker) {
+       SkPaint* paint = maker.fPaint;
+       setupPaint(paint);
+       return false;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkDrawPaint::dump(SkAnimateMaker* maker) {
+       dumpBase(maker);
+    dumpAttrs(maker);
+    bool closedYet = false;
+    SkDisplayList::fIndent +=4;
+    //should i say if (maskFilter && ...?
+    if (maskFilter != (SkDrawMaskFilter*)-1) {
+        SkDebugf(">\n");
+        maskFilter->dump(maker);
+        closedYet = true;
+    }
+    if (pathEffect != (SkDrawPathEffect*) -1) {
+        if (closedYet == false) {
+            SkDebugf(">\n");
+            closedYet = true;
+        }
+        pathEffect->dump(maker);
+    }
+    if (fOwnsTypeface) {
+        if (closedYet == false) {
+            SkDebugf(">\n");
+            closedYet = true;
+        }
+        typeface->dump(maker);
+    }
+    SkDisplayList::fIndent -= 4;
+    dumpChildren(maker, closedYet);
+}
+#endif
+    
+void SkDrawPaint::executeFunction(SkDisplayable* target, int index, 
+               SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type,
+               SkScriptValue* scriptValue) {
+               if (scriptValue == NULL)
+                       return;
+       SkASSERT(target == this);
+       switch (index) {
+               case SK_FUNCTION(measureText): {
+                       SkASSERT(parameters.count() == 1);
+                       SkASSERT(type == SkType_Float);
+                       SkPaint paint;
+                       setupPaint(&paint);
+                       scriptValue->fType = SkType_Float;
+                       SkASSERT(parameters[0].fType == SkType_String);
+                       scriptValue->fOperand.fScalar = paint.measureText(parameters[0].fOperand.fString->c_str(), 
+                               parameters[0].fOperand.fString->size()); 
+//                     SkDebugf("measureText: %s = %g\n", parameters[0].fOperand.fString->c_str(), 
+//                             scriptValue->fOperand.fScalar / 65536.0f);
+                       } break;
+               default:
+                       SkASSERT(0);
+       }
+}
+
+const SkFunctionParamType* SkDrawPaint::getFunctionsParameters() {
+       return fFunctionParameters;
+}
+
+bool SkDrawPaint::getProperty(int index, SkScriptValue* value) const {
+       SkScalar above, below;
+       SkPaint paint;
+       setupPaint(&paint);
+       paint.measureText("", 0, &above, &below);
+       switch (index) {
+               case SK_PROPERTY(ascent):
+                       value->fOperand.fScalar = above;
+                       break;
+               case SK_PROPERTY(descent):
+                       value->fOperand.fScalar = below;
+                       break;
+               default:
+                       SkASSERT(0);
+                       return false;
+       }
+       value->fType = SkType_Float;
+       return true;
+}
+
+bool SkDrawPaint::resolveIDs(SkAnimateMaker& maker, SkDisplayable* origDisp, SkApply* ) {
+       SkASSERT(origDisp->isPaint());
+       SkDrawPaint* original = (SkDrawPaint*) origDisp;
+       if (fOwnsColor && maker.resolveID(color, original->color) == false)
+               return true;
+       if (fOwnsMaskFilter && maker.resolveID(maskFilter, original->maskFilter) == false)
+               return true;
+       if (fOwnsPathEffect && maker.resolveID(pathEffect, original->pathEffect) == false)
+               return true;
+       if (fOwnsShader && maker.resolveID(shader, original->shader) == false)
+               return true;
+       if (fOwnsTypeface && maker.resolveID(typeface, original->typeface) == false)
+               return true;
+       return false; // succeeded 
+}
+
+void SkDrawPaint::setupPaint(SkPaint* paint) const {
+       if (antiAlias != -1)
+               paint->setAntiAliasOn(SkToBool(antiAlias));
+       if (color != NULL)
+               paint->setColor(color->getColor());
+       if (fakeBold != -1)
+               paint->setFakeBoldTextOn(SkToBool(fakeBold));
+       if (filterType != (SkPaint::FilterType) -1)
+               paint->setFilterType((SkPaint::FilterType) filterType);
+       //      stroke is legacy; style setting if present overrides stroke
+       if (stroke != -1)
+               paint->setStyle(SkToBool(stroke) ? SkPaint::kStroke_Style : SkPaint::kFill_Style);
+       if (style != (SkPaint::Style) -1)
+               paint->setStyle((SkPaint::Style) style);
+       if (linearText != -1)
+               paint->setLinearTextOn(SkToBool(linearText));
+       if (maskFilter == NULL)
+               paint->setMaskFilter(NULL);
+       else if (maskFilter != (SkDrawMaskFilter*) -1)
+               paint->setMaskFilter(maskFilter->getMaskFilter())->safeUnref();
+       if (pathEffect == NULL)
+               paint->setPathEffect(NULL);
+       else if (pathEffect != (SkDrawPathEffect*) -1)
+               paint->setPathEffect(pathEffect->getPathEffect())->safeUnref();
+       if (shader == NULL)
+               paint->setShader(NULL);
+       else if (shader != (SkDrawShader*) -1)
+               paint->setShader(shader->getShader())->safeUnref();
+       if (strikeThru != -1)
+               paint->setStrikeThruTextOn(SkToBool(strikeThru));
+       if (strokeCap != (SkPaint::Cap) -1)
+               paint->setStrokeCap((SkPaint::Cap) strokeCap);
+       if (strokeJoin != (SkPaint::Join) -1)
+               paint->setStrokeJoin((SkPaint::Join) strokeJoin);
+       if (SkScalarIsNaN(strokeMiter) == false)
+               paint->setStrokeMiter(strokeMiter);
+       if (SkScalarIsNaN(strokeWidth) == false)
+               paint->setStrokeWidth(strokeWidth);
+       if (textAlign != (SkPaint::Align) -1)
+               paint->setTextAlign((SkPaint::Align) textAlign);
+       if (SkScalarIsNaN(textScaleX) == false)
+               paint->setTextScaleX(textScaleX);
+       if (SkScalarIsNaN(textSize) == false)
+               paint->setTextSize(textSize);
+       if (SkScalarIsNaN(textSkewX) == false)
+               paint->setTextSkewX(textSkewX);
+       if (typeface == NULL)
+               paint->setTypeface(NULL);
+       else if (typeface != (SkDrawTypeface*) -1)
+               paint->setTypeface(typeface->getTypeface())->safeUnref();
+       if (underline != -1)
+               paint->setUnderlineTextOn(SkToBool(underline));
+       if (xfermode != (SkPorterDuff::Mode) -1) 
+               paint->setPorterDuffXfermode((SkPorterDuff::Mode) xfermode);
+}
+
diff --git a/libs/graphics/animator/SkDrawPaint.h b/libs/graphics/animator/SkDrawPaint.h
new file mode 100644 (file)
index 0000000..3ae0ffa
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef SkDrawPaint_DEFINED
+#define SkDrawPaint_DEFINED
+
+#include "SkDrawable.h"
+#include "SkIntArray.h"
+#include "SkMemberInfo.h"
+#include "SkPaint.h"
+#include "SkXfermode.h"
+
+class SkDrawMaskFilter;
+class SkDrawPathEffect;
+class SkDrawShader;
+class SkTransferMode;
+class SkDrawTypeface;
+
+class SkDrawPaint : public SkDrawable {
+       DECLARE_DRAW_MEMBER_INFO(Paint);
+       SkDrawPaint();
+       virtual ~SkDrawPaint();
+       virtual bool add(SkAnimateMaker& , SkDisplayable* child);
+       virtual SkDisplayable* deepCopy(SkAnimateMaker* );
+       virtual bool draw(SkAnimateMaker& );
+#ifdef SK_DUMP_ENABLED
+       virtual void dump(SkAnimateMaker* );
+#endif
+       virtual void executeFunction(SkDisplayable* target, int index, 
+               SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type,
+               SkScriptValue* );
+       virtual const SkFunctionParamType* getFunctionsParameters();
+       virtual bool getProperty(int index, SkScriptValue* value) const;
+       virtual bool resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* apply);
+protected:
+       static const SkFunctionParamType fFunctionParameters[];
+       void setupPaint(SkPaint* paint) const;
+public:
+       SkBool antiAlias;
+       SkDrawColor* color;
+    SkBool fakeBold;
+       int /*SkPaint::FilterType*/ filterType;
+       SkBool linearText;
+       SkDrawMaskFilter* maskFilter;
+       SkDrawPathEffect* pathEffect;
+       SkDrawShader* shader;
+       SkBool strikeThru;
+       SkBool stroke;
+       int /*SkPaint::Cap*/ strokeCap;
+       int /*SkPaint::Join */ strokeJoin;
+       SkScalar strokeMiter;
+       SkScalar strokeWidth;
+       int /* SkPaint::Style */ style;
+       int /* SkPaint::Align */ textAlign;
+       SkScalar textScaleX;
+       SkScalar textSize;
+       SkScalar textSkewX;
+       SkDrawTypeface* typeface;
+       SkBool underline;
+       int /*SkXfermode::Modes*/ xfermode;
+       SkBool8 fOwnsColor;
+       SkBool8 fOwnsMaskFilter;
+       SkBool8 fOwnsPathEffect;
+       SkBool8 fOwnsShader;
+       SkBool8 fOwnsTransferMode;
+       SkBool8 fOwnsTypeface;
+private:
+       typedef SkDrawable INHERITED;
+       friend class SkTextToPath;
+    friend class SkSaveLayer;
+};
+
+#endif // SkDrawPaint_DEFINED
+
diff --git a/libs/graphics/animator/SkDrawPath.cpp b/libs/graphics/animator/SkDrawPath.cpp
new file mode 100644 (file)
index 0000000..3024600
--- /dev/null
@@ -0,0 +1,212 @@
+#include "SkDrawPath.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+#include "SkMath.h"
+#include "SkMatrixParts.h"
+#include "SkPaint.h"
+#include "SkPathParts.h"
+
+enum SkPath_Properties {
+       SK_PROPERTY(fillType),
+       SK_PROPERTY(length)
+};
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawPath::fInfo[] = {
+       SK_MEMBER(d, String),
+       SK_MEMBER_PROPERTY(fillType, FillType),
+       SK_MEMBER_PROPERTY(length, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawPath);
+
+SkDrawPath::SkDrawPath()
+{
+       fParent = nil;
+       fLength = SK_ScalarNaN;
+       fChildHasID = false;
+       fDirty = false;
+}
+
+SkDrawPath::~SkDrawPath() {
+       for (SkPathPart** part = fParts.begin(); part < fParts.end();  part++)
+               delete *part;
+}
+
+bool SkDrawPath::add(SkAnimateMaker& maker, SkDisplayable* child) {
+       SkASSERT(child && child->isPathPart());
+       SkPathPart* part = (SkPathPart*) child;
+       *fParts.append() = part;
+       if (part->add())
+               maker.setErrorCode(SkDisplayXMLParserError::kErrorAddingToPath); 
+       fDirty = false;
+       return true;
+}
+
+bool SkDrawPath::childrenNeedDisposing() const { 
+       return false; 
+}
+
+void SkDrawPath::dirty() { 
+       fDirty = true; 
+       fLength = SK_ScalarNaN;
+       if (fParent)
+               fParent->dirty();
+}
+
+bool SkDrawPath::draw(SkAnimateMaker& maker) {
+       SkPath& path = getPath();
+       SkBoundableAuto boundable(this, maker);
+       maker.fCanvas->drawPath(path, *maker.fPaint);
+       return false;
+}
+
+SkDisplayable* SkDrawPath::getParent() const {
+       return fParent;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkDrawPath::dump(SkAnimateMaker* maker) {
+    dumpBase(maker);
+    dumpAttrs(maker);
+    bool closedYet = false;
+    SkDisplayList::fIndent += 4;
+    for(SkPathPart** part = fParts.begin(); part < fParts.end(); part++) {
+        if (closedYet == false) {
+            SkDebugf(">\n");
+            closedYet = true;
+        }
+        (*part)->dump(maker);
+    }
+    SkDisplayList::fIndent -= 4;
+    if (closedYet)
+        dumpEnd(maker);
+    else
+        SkDebugf("/>\n");
+}
+#endif
+
+SkPath& SkDrawPath::getPath() {
+       if (fDirty == false)
+               return fPath;
+    if (d.size() > 0)
+    {
+        parseSVG();
+        d.reset();
+    }
+    else
+    {
+        fPath.reset();
+        for (SkPathPart** part = fParts.begin(); part < fParts.end();  part++)
+            (*part)->add();
+    }
+       fDirty = false;
+       return fPath;
+}
+       
+void SkDrawPath::onEndElement(SkAnimateMaker& ) {
+       if (d.size() > 0) {
+               parseSVG();
+               d.reset();
+        fDirty = false;
+        return;
+       }
+       if (fChildHasID == false) {
+               for (SkPathPart** part = fParts.begin(); part < fParts.end();  part++)
+                       delete *part;
+               fParts.reset();
+               fDirty = false;
+       }
+}
+
+bool SkDrawPath::getProperty(int index, SkScriptValue* value) const {
+       switch (index) {
+               case SK_PROPERTY(length):
+                       if (SkScalarIsNaN(fLength)) {
+                               const SkPath& path = ((SkDrawPath*) this)->getPath();
+                               SkPathMeasure pathMeasure(path, false);
+                               fLength = pathMeasure.getLength();
+                       }
+                       value->fType = SkType_Float;
+                       value->fOperand.fScalar = fLength;
+                       break;
+        case SK_PROPERTY(fillType):
+            value->fType = SkType_FillType;
+            value->fOperand.fS32 = (int) fPath.getFillType();
+            break;
+               default:
+                       SkASSERT(0);
+                       return false;
+       }
+       return true;
+}
+
+void SkDrawPath::setChildHasID() { 
+       fChildHasID = true; 
+}
+
+bool SkDrawPath::setParent(SkDisplayable* parent) {
+       fParent = parent;
+       return false;
+}
+
+bool SkDrawPath::setProperty(int index, SkScriptValue& value)
+{
+       switch (index) {
+               case SK_PROPERTY(fillType):
+                       SkASSERT(value.fType == SkType_FillType);
+                       SkASSERT(value.fOperand.fS32 >= SkPath::kWinding_FillType &&
+                               value.fOperand.fS32 <= SkPath::kEvenOdd_FillType);
+                       fPath.setFillType((SkPath::FillType) value.fOperand.fS32);
+                       break;
+               default:
+                       SkASSERT(0);
+                       return false;
+       }
+       return true;
+}
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkPolyline::fInfo[] = {
+       SK_MEMBER_ARRAY(points, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkPolyline);
+
+bool SkPolyline::add(SkAnimateMaker& , SkDisplayable*) const {
+       return false; 
+}
+
+void SkPolyline::onEndElement(SkAnimateMaker& maker) {
+       INHERITED::onEndElement(maker);
+       if (points.count() <= 0)
+               return;
+       fPath.reset();
+       fPath.moveTo(points[0], points[1]);
+       int count = points.count();
+       for (int index = 2; index < count; index += 2)
+               fPath.lineTo(points[index], points[index+1]);
+}
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkPolygon::fInfo[] = {
+       SK_MEMBER_INHERITED
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkPolygon);
+
+void SkPolygon::onEndElement(SkAnimateMaker& maker) {
+       INHERITED::onEndElement(maker);
+       fPath.close();
+}
+
diff --git a/libs/graphics/animator/SkDrawPath.h b/libs/graphics/animator/SkDrawPath.h
new file mode 100644 (file)
index 0000000..3c005a5
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef SkDrawPath_DEFINED
+#define SkDrawPath_DEFINED
+
+#include "SkBoundable.h"
+#include "SkIntArray.h"
+#include "SkMemberInfo.h"
+#include "SkPath.h"
+
+class SkDrawPath : public SkBoundable {
+       DECLARE_DRAW_MEMBER_INFO(Path);
+       SkDrawPath();
+       virtual ~SkDrawPath();
+       virtual bool add(SkAnimateMaker& , SkDisplayable* child);
+       bool childHasID() { return SkToBool(fChildHasID); }
+       virtual bool childrenNeedDisposing() const;
+       virtual void dirty();
+       virtual bool draw(SkAnimateMaker& );
+       virtual SkDisplayable* getParent() const;
+#ifdef SK_DUMP_ENABLED
+    virtual void dump(SkAnimateMaker* );
+#endif
+       SkPath& getPath();
+       virtual bool getProperty(int index, SkScriptValue* value) const;
+       virtual bool setProperty(int index, SkScriptValue& value);
+       virtual void onEndElement(SkAnimateMaker& );
+       virtual void setChildHasID();
+       virtual bool setParent(SkDisplayable* parent);
+       virtual bool isPath() const { return true; }
+public:
+       SkPath fPath;
+protected:
+       void parseSVG();
+       SkString d;
+       SkTDPathPartArray fParts;
+       mutable SkScalar fLength;
+       SkDisplayable* fParent; // SkPolyToPoly or SkFromPath, for instance
+       SkBool8 fChildHasID;
+       SkBool8 fDirty;
+private:
+       typedef SkBoundable INHERITED;
+};
+
+class SkPolyline : public SkDrawPath {
+       DECLARE_MEMBER_INFO(Polyline);
+       virtual bool add(SkAnimateMaker& , SkDisplayable*) const;
+       virtual void onEndElement(SkAnimateMaker& );
+protected:
+       SkTDScalarArray points;
+private:
+       typedef SkDrawPath INHERITED;
+};
+
+class SkPolygon : public SkPolyline {
+       DECLARE_MEMBER_INFO(Polygon);
+       virtual void onEndElement(SkAnimateMaker& );
+private:
+       typedef SkPolyline INHERITED;
+};
+
+#endif // SkDrawPath_DEFINED
diff --git a/libs/graphics/animator/SkDrawPoint.cpp b/libs/graphics/animator/SkDrawPoint.cpp
new file mode 100644 (file)
index 0000000..4bbd006
--- /dev/null
@@ -0,0 +1,37 @@
+#include "SkDrawPoint.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo Sk_Point::fInfo[] = {
+       SK_MEMBER_ALIAS(x, fPoint.fX, Float),
+       SK_MEMBER_ALIAS(y, fPoint.fY, Float)
+};
+
+#endif
+
+DEFINE_NO_VIRTUALS_GET_MEMBER(Sk_Point);
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawPoint::fInfo[] = {
+       SK_MEMBER_ALIAS(x, fPoint.fX, Float),
+       SK_MEMBER_ALIAS(y, fPoint.fY, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawPoint);
+
+SkDrawPoint::SkDrawPoint() { 
+       fPoint.set(0, 0);       
+}
+
+void SkDrawPoint::getBounds(SkRect* rect ) {
+       rect->fLeft = rect->fRight = fPoint.fX;
+       rect->fTop = rect->fBottom = fPoint.fY;
+}
+
+
diff --git a/libs/graphics/animator/SkDrawPoint.h b/libs/graphics/animator/SkDrawPoint.h
new file mode 100644 (file)
index 0000000..c59c78a
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef SkDrawPoint_DEFINED
+#define SkDrawPoint_DEFINED
+
+#include "SkBoundable.h"
+#include "SkMemberInfo.h"
+#include "SkPoint.h"
+
+struct Sk_Point {
+       DECLARE_NO_VIRTUALS_MEMBER_INFO(_Point);
+       Sk_Point();
+private:
+       SkPoint fPoint;
+};
+
+class SkDrawPoint : public SkDisplayable {
+       DECLARE_MEMBER_INFO(DrawPoint);
+       SkDrawPoint();
+       virtual void getBounds(SkRect*  );
+private:
+       SkPoint fPoint;
+       typedef SkDisplayable INHERITED;
+};
+
+#endif // SkDrawPoint_DEFINED
diff --git a/libs/graphics/animator/SkDrawRectangle.cpp b/libs/graphics/animator/SkDrawRectangle.cpp
new file mode 100644 (file)
index 0000000..3ccb347
--- /dev/null
@@ -0,0 +1,136 @@
+#include "SkDrawRectangle.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+#include "SkMatrixParts.h"
+#include "SkPaint.h"
+#include "SkScript.h"
+
+enum SkRectangle_Properties {
+       SK_PROPERTY(height),
+       SK_PROPERTY(needsRedraw),
+       SK_PROPERTY(width)
+};
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawRect::fInfo[] = {
+       SK_MEMBER_ALIAS(bottom, fRect.fBottom, Float),
+       SK_MEMBER_PROPERTY(height, Float),
+       SK_MEMBER_ALIAS(left, fRect.fLeft, Float),
+       SK_MEMBER_PROPERTY(needsRedraw, Boolean),
+       SK_MEMBER_ALIAS(right, fRect.fRight, Float),
+       SK_MEMBER_ALIAS(top, fRect.fTop, Float),
+       SK_MEMBER_PROPERTY(width, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawRect);
+
+SkDrawRect::SkDrawRect() : fParent(nil) { 
+       fRect.setEmpty(); 
+}
+
+void SkDrawRect::dirty() {
+       if (fParent)
+               fParent->dirty();
+}
+
+bool SkDrawRect::draw(SkAnimateMaker& maker) {
+       SkBoundableAuto boundable(this, maker);
+       maker.fCanvas->drawRect(fRect, *maker.fPaint);
+       return false;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkDrawRect::dump(SkAnimateMaker* maker) {
+    dumpBase(maker);
+    SkDebugf("left=\"%g\" top=\"%g\" right=\"%g\" bottom=\"%g\" />\n",
+        SkScalarToFloat(fRect.fLeft), SkScalarToFloat(fRect.fTop), SkScalarToFloat(fRect.fRight),
+        SkScalarToFloat(fRect.fBottom));
+}
+#endif
+
+SkDisplayable* SkDrawRect::getParent() const {
+       return fParent;
+}
+
+bool SkDrawRect::getProperty(int index, SkScriptValue* value) const {
+       SkScalar result;
+       switch (index) {
+               case SK_PROPERTY(height):
+                       result = fRect.height();
+                       break;
+               case SK_PROPERTY(needsRedraw):
+                       value->fType = SkType_Boolean;
+                       value->fOperand.fS32 = fBounds.isEmpty() == false;
+                       return true;
+               case SK_PROPERTY(width):
+                       result = fRect.width();
+                       break;
+               default:
+                       SkASSERT(0);
+                       return false;
+       }
+       value->fType = SkType_Float;
+       value->fOperand.fScalar = result;
+       return true;
+}
+
+
+bool SkDrawRect::setParent(SkDisplayable* parent) {
+       fParent = parent;
+       return false;
+}
+
+bool SkDrawRect::setProperty(int index, SkScriptValue& value) {
+       SkScalar scalar = value.fOperand.fScalar;
+       switch (index) {
+               case SK_PROPERTY(height):
+               SkASSERT(value.fType == SkType_Float);
+                       fRect.fBottom = scalar + fRect.fTop;
+                       return true;
+        case SK_PROPERTY(needsRedraw):
+            return false;
+               case SK_PROPERTY(width):
+               SkASSERT(value.fType == SkType_Float);
+                       fRect.fRight = scalar + fRect.fLeft;
+                       return true;
+               default:
+                       SkASSERT(0);
+       }
+       return false;
+}
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkRoundRect::fInfo[] = {
+       SK_MEMBER_INHERITED,
+       SK_MEMBER(rx, Float),
+       SK_MEMBER(ry, Float),
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkRoundRect);
+
+SkRoundRect::SkRoundRect() : rx(0), ry(0) {
+}
+
+bool SkRoundRect::draw(SkAnimateMaker& maker) {
+       SkBoundableAuto boundable(this, maker);
+       maker.fCanvas->drawRoundRect(fRect, rx, ry, *maker.fPaint);
+       return false;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkRoundRect::dump(SkAnimateMaker* maker) {
+    dumpBase(maker);
+    SkDebugf("left=\"%g\" top=\"%g\" right=\"%g\" bottom=\"%g\" rx=\"%g\" ry=\"%g\" />\n",
+            SkScalarToFloat(fRect.fLeft), SkScalarToFloat(fRect.fTop), SkScalarToFloat(fRect.fRight),
+            SkScalarToFloat(fRect.fBottom), SkScalarToFloat(rx), SkScalarToFloat(ry));
+}
+#endif
+
+
+
diff --git a/libs/graphics/animator/SkDrawRectangle.h b/libs/graphics/animator/SkDrawRectangle.h
new file mode 100644 (file)
index 0000000..6abb6e4
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef SkDrawRectangle_DEFINED
+#define SkDrawRectangle_DEFINED
+
+#include "SkBoundable.h"
+#include "SkMemberInfo.h"
+#include "SkRect.h"
+
+class SkRectToRect;
+
+class SkDrawRect : public SkBoundable {
+       DECLARE_DRAW_MEMBER_INFO(Rect);
+       SkDrawRect();
+       virtual void dirty();
+       virtual bool draw(SkAnimateMaker& );
+#ifdef SK_DUMP_ENABLED
+    virtual void dump(SkAnimateMaker* );
+#endif
+       virtual SkDisplayable* getParent() const;
+       virtual bool getProperty(int index, SkScriptValue* value) const;
+       virtual bool setParent(SkDisplayable* parent);
+       virtual bool setProperty(int index, SkScriptValue& );
+protected:
+       SkRect fRect;
+       SkDisplayable* fParent;
+private:
+       friend class SkDrawClip;
+       friend class SkRectToRect;
+    friend class SkSaveLayer;
+       typedef SkBoundable INHERITED;
+};
+
+class SkRoundRect : public SkDrawRect {
+       DECLARE_MEMBER_INFO(RoundRect);
+       SkRoundRect();
+       virtual bool draw(SkAnimateMaker& );
+#ifdef SK_DUMP_ENABLED
+    virtual void dump(SkAnimateMaker* );
+#endif    
+protected:
+       SkScalar rx;
+       SkScalar ry;
+private:
+       typedef SkDrawRect INHERITED;
+};
+
+#endif // SkDrawRectangle_DEFINED
+
diff --git a/libs/graphics/animator/SkDrawSaveLayer.cpp b/libs/graphics/animator/SkDrawSaveLayer.cpp
new file mode 100644 (file)
index 0000000..c6addb8
--- /dev/null
@@ -0,0 +1,67 @@
+#include "SkDrawSaveLayer.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+#include "SkDrawPaint.h"
+#include "SkDrawRectangle.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkSaveLayer::fInfo[] = {
+    SK_MEMBER(bounds, Rect),
+    SK_MEMBER(paint, Paint)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkSaveLayer);
+
+SkSaveLayer::SkSaveLayer() : paint(NULL), bounds(NULL) {
+}
+
+SkSaveLayer::~SkSaveLayer(){
+}
+
+bool SkSaveLayer::draw(SkAnimateMaker& maker)
+{
+    if (!bounds) {
+        return false;
+    }
+    SkPaint* save = maker.fPaint;   
+    //paint is an SkDrawPaint
+    if (paint)
+    {
+        SkPaint realPaint;
+        paint->setupPaint(&realPaint);
+        maker.fCanvas->saveLayer(bounds->fRect, realPaint);
+    }
+    else
+        maker.fCanvas->saveLayer(bounds->fRect, *save);
+    SkPaint local = SkPaint(*maker.fPaint);
+    maker.fPaint = &local;
+    bool result = INHERITED::draw(maker);
+    maker.fPaint = save;
+    maker.fCanvas->restore();
+    return result;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkSaveLayer::dump(SkAnimateMaker* maker)
+{
+    dumpBase(maker);
+    //would dump enabled be defined but not debug?
+#ifdef SK_DEBUG
+    if (paint)
+        SkDebugf("paint=\"%s\" ", paint->id);
+    if (bounds)
+        SkDebugf("bounds=\"%s\" ", bounds->id);
+#endif
+    dumpDrawables(maker);
+}
+#endif
+
+void SkSaveLayer::onEndElement(SkAnimateMaker& maker)
+{
+    if (!bounds)
+        maker.setErrorCode(SkDisplayXMLParserError::kSaveLayerNeedsBounds);
+    INHERITED::onEndElement(maker);
+}
\ No newline at end of file
diff --git a/libs/graphics/animator/SkDrawSaveLayer.h b/libs/graphics/animator/SkDrawSaveLayer.h
new file mode 100644 (file)
index 0000000..9644457
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef SkDrawSaveLayer_DEFINED
+#define SkDrawSaveLayer_DEFINED
+
+#include "SkDrawGroup.h"
+#include "SkMemberInfo.h"
+
+class SkDrawPaint;
+class SkDrawRect;
+
+class SkSaveLayer : public SkGroup {
+    DECLARE_MEMBER_INFO(SaveLayer);
+    SkSaveLayer();
+    virtual ~SkSaveLayer();
+    virtual bool draw(SkAnimateMaker& );
+#ifdef SK_DUMP_ENABLED
+    virtual void dump(SkAnimateMaker* );
+#endif
+    virtual void onEndElement(SkAnimateMaker& );
+protected:
+    SkDrawPaint* paint;
+    SkDrawRect* bounds;
+private:
+    typedef SkGroup INHERITED;
+
+};
+
+#endif //SkDrawSaveLayer_DEFINED
diff --git a/libs/graphics/animator/SkDrawShader.cpp b/libs/graphics/animator/SkDrawShader.cpp
new file mode 100644 (file)
index 0000000..4b071a1
--- /dev/null
@@ -0,0 +1,74 @@
+#include "SkDrawShader.h"
+#include "SkDrawBitmap.h"
+#include "SkDrawMatrix.h"
+#include "SkDrawPaint.h"
+#include "SkTemplates.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawShader::fInfo[] = {
+       SK_MEMBER(matrix, Matrix),
+       SK_MEMBER(tileMode, TileMode)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawShader);
+
+SkDrawShader::SkDrawShader() : matrix(nil), 
+       tileMode(SkShader::kClamp_TileMode) {
+}
+
+bool SkDrawShader::add() {
+       if (fPaint->shader != (SkDrawShader*) -1)
+               return true;
+       fPaint->shader = this;
+       fPaint->fOwnsShader = true;
+       return false;
+}
+
+void SkDrawShader::addPostlude(SkShader* shader) {
+       if (matrix)
+               shader->setLocalMatrix(matrix->getMatrix());
+}
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawBitmapShader::fInfo[] = {
+       SK_MEMBER_INHERITED,
+       SK_MEMBER(filterType, FilterType),
+       SK_MEMBER(image, BaseBitmap)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawBitmapShader);
+
+SkDrawBitmapShader::SkDrawBitmapShader() : filterType(SkPaint::kNo_FilterType), image(nil) {}
+
+bool SkDrawBitmapShader::add() {
+       if (fPaint->shader != (SkDrawShader*) -1)
+               return true;
+       fPaint->shader = this;
+       fPaint->fOwnsShader = true;
+       return false;
+}
+
+SkShader* SkDrawBitmapShader::getShader() {
+       if (image == NULL)
+               return NULL;
+    
+    // note: bitmap shader now supports independent tile modes for X and Y
+    // we pass the same to both, but later we should extend this flexibility
+    // to the xml (e.g. tileModeX="repeat" tileModeY="clmap")
+    // <reed>
+       SkShader* shader  = SkShader::CreateBitmapShader(image->fBitmap, false, 
+                                                    (SkPaint::FilterType) filterType,
+                                                    (SkShader::TileMode) tileMode,
+                                                    (SkShader::TileMode) tileMode);
+       SkAutoTDelete<SkShader> autoDel(shader);
+       addPostlude(shader);
+       (void)autoDel.detach();
+       return shader;
+}
+
diff --git a/libs/graphics/animator/SkDrawShader.h b/libs/graphics/animator/SkDrawShader.h
new file mode 100644 (file)
index 0000000..8601405
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef SkDrawShader_DEFINED
+#define SkDrawShader_DEFINED
+
+#include "SkPaintParts.h"
+#include "SkShader.h"
+
+class SkBaseBitmap;
+
+class SkDrawBitmapShader : public SkDrawShader {
+       DECLARE_DRAW_MEMBER_INFO(BitmapShader);
+       SkDrawBitmapShader();
+       virtual bool add();
+       virtual SkShader* getShader();
+protected:
+       int /*SkPaint::FilterType*/ filterType;
+       SkBaseBitmap* image;
+private:
+       typedef SkDrawShader INHERITED;
+};
+
+#endif // SkDrawShader_DEFINED
diff --git a/libs/graphics/animator/SkDrawText.cpp b/libs/graphics/animator/SkDrawText.cpp
new file mode 100644 (file)
index 0000000..093e7e4
--- /dev/null
@@ -0,0 +1,47 @@
+#include "SkDrawText.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+
+enum SkText_Properties {
+       SK_PROPERTY(length)
+};
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkText::fInfo[] = {
+       SK_MEMBER_PROPERTY(length, Int),
+       SK_MEMBER(text, String),
+       SK_MEMBER(x, Float),
+       SK_MEMBER(y, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkText);
+
+SkText::SkText() : x(0), y(0) {
+}
+
+SkText::~SkText() {
+}
+
+bool SkText::draw(SkAnimateMaker& maker) {
+       SkBoundableAuto boundable(this, maker);
+       maker.fCanvas->drawText(text.c_str(), text.size(), x, y, *maker.fPaint);
+       return false;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkText::dump(SkAnimateMaker* maker) {
+       INHERITED::dump(maker);
+}
+#endif
+
+bool SkText::getProperty(int index, SkScriptValue* value) const {
+       SkASSERT(index == SK_PROPERTY(length));
+       value->fType = SkType_Int;
+       value->fOperand.fS32 = (S32) text.size();
+       return true;
+}
+
diff --git a/libs/graphics/animator/SkDrawText.h b/libs/graphics/animator/SkDrawText.h
new file mode 100644 (file)
index 0000000..2cc8c86
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef SkDrawText_DEFINED
+#define SkDrawText_DEFINED
+
+#include "SkBoundable.h"
+#include "SkMemberInfo.h"
+
+class SkText : public SkBoundable {
+       DECLARE_MEMBER_INFO(Text);
+       SkText();
+       virtual ~SkText();
+       virtual bool draw(SkAnimateMaker& );
+#ifdef SK_DUMP_ENABLED
+       virtual void dump(SkAnimateMaker* );
+#endif
+       virtual bool getProperty(int index, SkScriptValue* value) const ; 
+       const char* getText() { return text.c_str(); }
+       size_t getSize() { return text.size(); }
+protected:
+       SkString text;
+       SkScalar x;
+       SkScalar y;
+private:
+       friend class SkTextToPath;
+       typedef SkBoundable INHERITED;
+};
+
+#endif // SkDrawText_DEFINED
diff --git a/libs/graphics/animator/SkDrawTextBox.cpp b/libs/graphics/animator/SkDrawTextBox.cpp
new file mode 100644 (file)
index 0000000..204d398
--- /dev/null
@@ -0,0 +1,73 @@
+#include "SkDrawTextBox.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+
+enum SkDrawTextBox_Properties {
+       foo = 100,
+       SK_PROPERTY(spacingAlign),
+       SK_PROPERTY(mode)
+};
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawTextBox::fInfo[] = {
+       SK_MEMBER_INHERITED,
+       SK_MEMBER(mode, TextBoxMode),
+       SK_MEMBER_ALIAS(spacingAdd, fSpacingAdd, Float),
+       SK_MEMBER(spacingAlign, TextBoxAlign),
+       SK_MEMBER_ALIAS(spacingMul, fSpacingMul, Float),
+       SK_MEMBER_ALIAS(text, fText, String)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawTextBox);
+
+SkDrawTextBox::SkDrawTextBox()
+{
+       fSpacingMul             = SK_Scalar1;
+       fSpacingAdd             = 0;
+       spacingAlign    = SkTextBox::kStart_SpacingAlign;
+       mode                    = SkTextBox::kLineBreak_Mode;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkDrawTextBox::dump(SkAnimateMaker* maker)
+{
+    dumpBase(maker);
+    dumpAttrs(maker);
+    if (mode == 0) 
+        SkDebugf("mode=\"oneLine\" ");
+    if (spacingAlign == 1)
+        SkDebugf("spacingAlign=\"center\" ");
+    else if (spacingAlign == 2)
+        SkDebugf("spacingAlign=\"end\" ");
+    SkDebugf("/>\n");
+}
+#endif
+
+bool SkDrawTextBox::getProperty(int index, SkScriptValue* value) const
+{
+       return this->INHERITED::getProperty(index, value);
+}
+
+bool SkDrawTextBox::setProperty(int index, SkScriptValue& scriptValue)
+{
+       return this->INHERITED::setProperty(index, scriptValue);
+}
+
+bool SkDrawTextBox::draw(SkAnimateMaker& maker)
+{
+       SkTextBox       box;
+       box.setMode((SkTextBox::Mode) mode);
+       box.setSpacingAlign((SkTextBox::SpacingAlign) spacingAlign);
+       box.setBox(fRect);
+       box.setSpacing(fSpacingMul, fSpacingAdd);
+       SkBoundableAuto boundable(this, maker);
+       box.draw(maker.fCanvas, fText.c_str(), fText.size(), *maker.fPaint);
+       return false;
+}
+
+
diff --git a/libs/graphics/animator/SkDrawTextBox.h b/libs/graphics/animator/SkDrawTextBox.h
new file mode 100644 (file)
index 0000000..20bb14c
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef SkDrawTextBox_DEFINED
+#define SkDrawTextBox_DEFINED
+
+#include "SkDrawRectangle.h"
+#include "SkTextBox.h"
+
+class SkDrawTextBox : public SkDrawRect {
+       DECLARE_DRAW_MEMBER_INFO(TextBox);
+       SkDrawTextBox();
+
+       // overrides
+       virtual bool draw(SkAnimateMaker& );
+#ifdef SK_DUMP_ENABLED
+    virtual void dump(SkAnimateMaker* );
+#endif
+       virtual bool getProperty(int index, SkScriptValue* value) const;
+       virtual bool setProperty(int index, SkScriptValue& );
+
+private:
+       SkString fText;
+       SkScalar fSpacingMul;
+       SkScalar fSpacingAdd;
+       int /*SkTextBox::Mode*/  mode;
+       int /*SkTextBox::SpacingAlign*/ spacingAlign;
+
+       typedef SkDrawRect INHERITED;
+};
+
+#endif // SkDrawTextBox_DEFINED
+
diff --git a/libs/graphics/animator/SkDrawTo.cpp b/libs/graphics/animator/SkDrawTo.cpp
new file mode 100644 (file)
index 0000000..2019c4b
--- /dev/null
@@ -0,0 +1,47 @@
+#include "SkDrawTo.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+#include "SkDrawBitmap.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawTo::fInfo[] = {
+       SK_MEMBER(drawOnce, Boolean),
+       SK_MEMBER(use, Bitmap)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawTo);
+
+SkDrawTo::SkDrawTo() : drawOnce(false), use(nil), fDrawnOnce(false) {
+}
+
+#if 0
+SkDrawTo::~SkDrawTo() {
+       SkASSERT(0);
+}
+#endif
+
+bool SkDrawTo::draw(SkAnimateMaker& maker) {
+       if (fDrawnOnce)
+               return false;
+       SkCanvas canvas(use->fBitmap);
+       SkCanvas* save = maker.fCanvas;
+       maker.fCanvas = &canvas;
+       INHERITED::draw(maker);
+       maker.fCanvas = save;
+       fDrawnOnce = drawOnce;
+       return false;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkDrawTo::dump(SkAnimateMaker* maker) {
+    dumpBase(maker);
+    dumpAttrs(maker);
+    if (use)
+        SkDebugf("use=\"%s\" ", use->id);
+    dumpDrawables(maker);
+}
+#endif
+
diff --git a/libs/graphics/animator/SkDrawTo.h b/libs/graphics/animator/SkDrawTo.h
new file mode 100644 (file)
index 0000000..403ced6
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef SkDrawTo_DEFINED
+#define SkDrawTo_DEFINED
+
+#include "SkDrawGroup.h"
+#include "SkMemberInfo.h"
+
+class SkDrawBitmap;
+
+class SkDrawTo : public SkGroup {
+       DECLARE_MEMBER_INFO(DrawTo);
+       SkDrawTo();
+//     virtual ~SkDrawTo();
+       virtual bool draw(SkAnimateMaker& );
+#ifdef SK_DUMP_ENABLED
+    virtual void dump(SkAnimateMaker* );
+#endif
+protected:
+       SkBool drawOnce;
+       SkDrawBitmap* use;
+private:
+       typedef SkGroup INHERITED;
+       SkBool fDrawnOnce;
+};
+
+#endif // SkDrawTo_DEFINED
diff --git a/libs/graphics/animator/SkDrawTransparentShader.cpp b/libs/graphics/animator/SkDrawTransparentShader.cpp
new file mode 100644 (file)
index 0000000..c71fb37
--- /dev/null
@@ -0,0 +1,7 @@
+#include "SkDrawTransparentShader.h"
+#include "SkTransparentShader.h"
+
+SkShader* SkDrawTransparentShader::getShader() {
+       return new SkTransparentShader();
+}
+
diff --git a/libs/graphics/animator/SkDrawTransparentShader.h b/libs/graphics/animator/SkDrawTransparentShader.h
new file mode 100644 (file)
index 0000000..0659937
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef SkDrawTransparentShader_DEFINED
+#define SkDrawTransparentShader_DEFINED
+
+#include "SkPaintParts.h"
+
+class SkDrawTransparentShader : public SkDrawShader {
+       DECLARE_EMPTY_MEMBER_INFO(TransparentShader);
+       virtual SkShader* getShader();
+};
+
+#endif // SkDrawTransparentShader_DEFINED
+
diff --git a/libs/graphics/animator/SkDrawable.cpp b/libs/graphics/animator/SkDrawable.cpp
new file mode 100644 (file)
index 0000000..e3e3662
--- /dev/null
@@ -0,0 +1,16 @@
+#include "SkDrawable.h"
+
+bool SkDrawable::doEvent(SkDisplayEvent::Kind , SkEventState* ) {
+       return false;
+}
+
+bool SkDrawable::isDrawable() const { 
+       return true; 
+}
+
+void SkDrawable::initialize() {
+}
+
+void SkDrawable::setSteps(int steps) {
+}
+
diff --git a/libs/graphics/animator/SkDrawable.h b/libs/graphics/animator/SkDrawable.h
new file mode 100644 (file)
index 0000000..6c62b15
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef SkDrawable_DEFINED
+#define SkDrawable_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkDisplayEvent.h"
+#include "SkMath.h"
+
+struct SkEventState;
+
+class SkDrawable :  public SkDisplayable {
+public:
+       virtual bool doEvent(SkDisplayEvent::Kind , SkEventState* state );
+       virtual bool draw(SkAnimateMaker& ) = 0; 
+       virtual void initialize();
+       virtual bool isDrawable() const;
+       virtual void setSteps(int steps);
+};
+
+#endif // SkDrawable_DEFINED
diff --git a/libs/graphics/animator/SkDump.cpp b/libs/graphics/animator/SkDump.cpp
new file mode 100644 (file)
index 0000000..cd7dcf0
--- /dev/null
@@ -0,0 +1,141 @@
+#include "SkDump.h"
+
+#ifdef SK_DUMP_ENABLED
+
+#include "SkAnimateMaker.h"
+#include "SkAnimatorScript.h"
+#include "SkDisplayEvents.h"
+#include "SkDisplayList.h"
+#include "SkString.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDump::fInfo[] = {
+       SK_MEMBER(displayList, Boolean),
+       SK_MEMBER(eventList, Boolean),
+       SK_MEMBER(events, Boolean),
+       SK_MEMBER(groups, Boolean),
+       SK_MEMBER(name, String),
+       SK_MEMBER(posts, Boolean),
+    SK_MEMBER(script, String)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDump);
+
+SkDump::SkDump() : displayList(-1), eventList(-1), events(-1), groups(-1), posts(-1) {
+}
+
+bool SkDump::enable(SkAnimateMaker& maker ) {
+       if (script.size() > 0)
+        return evaluate(maker);
+       bool hasAttr = false;
+       if (events > 0)
+               hasAttr |= maker.fDumpEvents = true;
+       if (posts > 0)
+               hasAttr |= maker.fDumpPosts = true;
+       if (groups > 0)
+               hasAttr |= maker.fDumpGConditions = true;
+       if ((hasAttr |= (eventList > 0)) == true)
+               maker.fEvents.dump(maker);
+       if ((hasAttr |= (name.size() > 0)) == true)
+               maker.dump(name.c_str());
+    if (displayList > 0 || displayList != 0 && hasAttr == false)
+               maker.fDisplayList.dump(&maker);
+       return true;
+}
+
+bool SkDump::evaluate(SkAnimateMaker &maker) {
+    SkAnimatorScript scriptEngine(maker, nil, SkType_Int);
+    SkScriptValue value;
+    const char* cScript = script.c_str();
+    bool success = scriptEngine.evaluateScript(&cScript, &value);
+    SkDebugf("%*s<dump script=\"%s\" answer=\" ", SkDisplayList::fIndent, "", script.c_str());
+    if (success == false) {
+        SkDebugf("INVALID\" />\n");
+        return false;
+    }
+    switch (value.fType) {
+        case SkType_Float:
+            SkDebugf("%g\" />\n", SkScalarToFloat(value.fOperand.fScalar));
+            break;
+        case SkType_Int:
+            SkDebugf("%d\" />\n", value.fOperand.fS32);
+            break;
+        case SkType_String:
+            SkDebugf("%s\" />\n", value.fOperand.fString->c_str());
+            break;
+        default:
+            return false;
+    }
+    return true;
+}
+
+bool SkDump::hasEnable() const {
+       return true;
+}
+
+void SkDump::GetEnumString(SkDisplayTypes type, int index, SkString* result) {
+    int badEnum = index;
+       const SkDisplayEnumMap& map = SkAnimatorScript::GetEnumValues(type);
+       const char* str  = map.fValues;
+       while (--index >= 0) {
+               str = strchr(str, '|');
+        if (str == nil) {
+            result->reset();
+            result->appendS32(badEnum);
+            return;
+        }
+        str += 1;
+    }
+       const char* end = strchr(str, '|');
+       if (end == nil)
+               end = str + strlen(str);
+       result->set(str, end - str);
+}
+
+#else
+
+// in the release version, <dump> is allowed, and its attributes are defined, but
+// are not stored and have no effect
+
+#if SK_USE_CONDENSED_INFO == 0
+
+enum SkDump_Properties {
+       SK_PROPERTY(displayList),
+       SK_PROPERTY(eventList),
+       SK_PROPERTY(events),
+       SK_PROPERTY(groups),
+       SK_PROPERTY(name),
+       SK_PROPERTY(posts),
+    SK_PROPERTY(script)
+};
+
+const SkMemberInfo SkDump::fInfo[] = {
+       SK_MEMBER_PROPERTY(displayList, Boolean),
+       SK_MEMBER_PROPERTY(eventList, Boolean),
+       SK_MEMBER_PROPERTY(events, Boolean),
+       SK_MEMBER_PROPERTY(groups, Boolean),
+       SK_MEMBER_PROPERTY(name, String),
+       SK_MEMBER_PROPERTY(posts, Boolean),
+    SK_MEMBER_PROPERTY(script, String)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDump);
+
+bool SkDump::enable(SkAnimateMaker& maker ) {
+       return true;
+}
+
+bool SkDump::hasEnable() const {
+       return true;
+}
+
+bool SkDump::setProperty(int index, SkScriptValue& ) {
+       return index <= SK_PROPERTY(posts); 
+}
+
+#endif
diff --git a/libs/graphics/animator/SkDump.h b/libs/graphics/animator/SkDump.h
new file mode 100644 (file)
index 0000000..2d9c99f
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef SkDump_DEFINED
+#define SkDump_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkMemberInfo.h"
+
+class SkAnimateMaker;
+class SkString;
+
+class SkDump : public SkDisplayable {
+       DECLARE_MEMBER_INFO(Dump);
+#ifdef SK_DUMP_ENABLED
+       SkDump();
+       virtual bool enable(SkAnimateMaker & );
+    bool evaluate(SkAnimateMaker &);
+       virtual bool hasEnable() const;
+       static void GetEnumString(SkDisplayTypes , int index, SkString* result);
+       SkBool displayList;
+       SkBool eventList;
+       SkBool events;
+       SkString name;
+       SkBool groups;
+       SkBool posts;
+    SkString script;
+#else
+       virtual bool enable(SkAnimateMaker & );
+       virtual bool hasEnable() const;
+       virtual bool setProperty(int index, SkScriptValue& );
+#endif
+};
+
+
+#endif // SkDump_DEFINED
+
diff --git a/libs/graphics/animator/SkExtraPathEffects.xsd b/libs/graphics/animator/SkExtraPathEffects.xsd
new file mode 100644 (file)
index 0000000..9592443
--- /dev/null
@@ -0,0 +1,33 @@
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"\r
+xmlns:Sk="urn:screenplay"\r
+xmlns:extra="urn:extraPathEffects" targetNamespace="urn:extraPathEffects" >\r
+       <xs:import namespace="urn:screenplay"\r
+               schemaLocation="SkAnimateSchema.xsd" />\r
+               \r
+       <xs:element name="composePathEffect" >\r
+               <xs:complexType>\r
+                       <xs:choice maxOccurs="1">\r
+                               <xs:element ref="Sk:dash"/>\r
+                               <xs:element ref="extra:shape1DPathEffect"/>\r
+                       </xs:choice>\r
+                       <xs:attribute name="id" type="xs:ID"/>\r
+               </xs:complexType>\r
+       </xs:element>\r
+\r
+       <xs:element name="shape1DPathEffect" >\r
+               <xs:complexType>\r
+                       <xs:choice maxOccurs="1">\r
+                               <xs:element ref="Sk:matrix"/>\r
+                               <xs:element ref="Sk:path"/>\r
+                       </xs:choice>\r
+                       <xs:attribute name="addPath" type="Sk:DynamicString" />\r
+                       <xs:attribute name="matrix" type="Sk:DynamicString" />\r
+                       <xs:attribute name="path" type="Sk:Path" />\r
+                       <xs:attribute name="phase" type="Sk:DynamicString"/>\r
+                       <xs:attribute name="spacing" type="Sk:DynamicString"/>\r
+                       <xs:attribute name="id" type="xs:ID"/>\r
+               </xs:complexType>\r
+       </xs:element>\r
+               \r
+</xs:schema>\r
+
diff --git a/libs/graphics/animator/SkExtras.h b/libs/graphics/animator/SkExtras.h
new file mode 100644 (file)
index 0000000..f8af4c5
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef SkExtras_DEFINED
+#define SkExtras_DEFINED
+
+#include "SkScript.h"
+
+class SkExtras {
+public:
+            SkExtras();
+    virtual ~SkExtras() {}
+
+       virtual SkDisplayable* createInstance(SkDisplayTypes type) = 0;
+       virtual bool definesType(SkDisplayTypes type) = 0;
+#if SK_USE_CONDENSED_INFO == 0
+       virtual const SkMemberInfo* getMembers(SkDisplayTypes type, int* infoCountPtr) = 0;
+#endif
+#ifdef SK_DEBUG
+       virtual const char* getName(SkDisplayTypes type) = 0;
+#endif
+       virtual SkDisplayTypes getType(const char match[], size_t len ) = 0;
+
+       SkScriptEngine::_propertyCallBack fExtraCallBack;
+       void* fExtraStorage;
+};
+
+#endif // SkExtras_DEFINED
diff --git a/libs/graphics/animator/SkGetCondensedInfo.cpp b/libs/graphics/animator/SkGetCondensedInfo.cpp
new file mode 100644 (file)
index 0000000..28290fd
--- /dev/null
@@ -0,0 +1,113 @@
+#include "SkMemberInfo.h"
+
+#if SK_USE_CONDENSED_INFO == 1
+
+// SkCondensed.cpp is auto-generated
+// To generate it, execute SkDisplayType::BuildCondensedInfo()
+#ifdef SK_DEBUG
+#include "SkCondensedDebug.cpp"
+#else
+#include "SkCondensedRelease.cpp"
+#endif
+
+static int _searchByName(const unsigned char* lengths, int count, const char* strings, const char target[]) {
+       int     lo = 0;
+       int     hi = count - 1;
+       while (lo < hi) {
+               int mid = (hi + lo) >> 1;
+               if (strcmp(&strings[lengths[mid << 2]], target) < 0)
+                       lo = mid + 1;
+               else 
+                       hi = mid;
+       }
+       if (strcmp(&strings[lengths[hi << 2]], target) != 0)
+               return -1;
+       return hi;
+}
+
+static int _searchByType(SkDisplayTypes type) {
+       unsigned char match = (unsigned char) type;
+       int     lo = 0;
+       int     hi = kTypeIDs - 1;
+       while (lo < hi) {
+               int mid = (hi + lo) >> 1;
+               if (gTypeIDs[mid] < match)
+                       lo = mid + 1;
+               else
+                       hi = mid;
+       }
+       if (gTypeIDs[hi] != type)
+               return -1;
+       return hi;
+}
+
+const SkMemberInfo* SkDisplayType::GetMembers(SkAnimateMaker* , SkDisplayTypes type, int* infoCountPtr) {
+       int lookup = _searchByType(type);
+       if (lookup < 0)
+               return nil;
+       if (infoCountPtr)
+               *infoCountPtr = gInfoCounts[lookup];
+       return gInfoTables[lookup];
+}
+
+// !!! replace with inline
+const SkMemberInfo* SkDisplayType::GetMember(SkAnimateMaker* , SkDisplayTypes type, const char** matchPtr ) {
+       const SkMemberInfo* info = SkMemberInfo::Find(type, matchPtr);
+       SkASSERT(info);
+       return info;
+}
+
+static const SkMemberInfo* _lookup(int lookup, const char** matchPtr) {
+       int count = gInfoCounts[lookup];
+       const SkMemberInfo* info = gInfoTables[lookup];
+       if (info->fType == SkType_BaseClassInfo) {
+               int baseTypeLookup = info->fOffset;
+               const SkMemberInfo* result = _lookup(baseTypeLookup, matchPtr);
+               if (result != nil)
+                       return result;
+               if (--count == 0)
+                       return nil;
+               info++;
+       }
+       SkASSERT(info->fType != SkType_BaseClassInfo);
+       const char* match = *matchPtr;
+       const char* strings = gInfoNames[lookup];
+       int index = _searchByName(&info->fName, count, strings, match);
+       if (index < 0)
+               return nil;
+       return &info[index];
+}
+
+const SkMemberInfo* SkMemberInfo::Find(SkDisplayTypes type, int* index) {
+       int count = gInfoCounts[lookup];
+       const SkMemberInfo* info = gInfoTables[lookup];
+       if (info->fType == SkType_BaseClassInfo) {
+               int baseTypeLookup = info->fOffset;
+               const SkMemberInfo* result = Find(baseTypeLookup, index);
+               if (result != nil)
+                       return result;
+               if (--count == 0)
+                       return nil;
+               info++;
+       }
+       SkASSERT(info->fType != SkType_BaseClassInfo);
+       if (*index >= count) {
+               *index -= count;
+               return nil;
+       }
+       return &info[index];
+}
+
+const SkMemberInfo* SkMemberInfo::Find(SkDisplayTypes type, const char** matchPtr) {
+       int lookup = _searchByType(type);
+       SkASSERT(lookup >= 0);
+       return _lookup(lookup, matchPtr);
+}
+
+const SkMemberInfo* SkMemberInfo::getInherited() const {
+       int baseTypeLookup = fOffset;
+       return gInfoTables[baseTypeLookup];
+}
+
+#endif
+
diff --git a/libs/graphics/animator/SkHitClear.cpp b/libs/graphics/animator/SkHitClear.cpp
new file mode 100644 (file)
index 0000000..6d90a5a
--- /dev/null
@@ -0,0 +1,24 @@
+#include "SkHitClear.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkHitClear::fInfo[] = {
+       SK_MEMBER_ARRAY(targets, Displayable)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkHitClear);
+
+bool SkHitClear::enable(SkAnimateMaker& maker) {
+       for (int tIndex = 0; tIndex < targets.count(); tIndex++) {
+               SkDisplayable* target = targets[tIndex];
+               target->clearBounder();
+       }
+       return true;
+}
+
+bool SkHitClear::hasEnable() const {
+       return true;
+}
+
diff --git a/libs/graphics/animator/SkHitClear.h b/libs/graphics/animator/SkHitClear.h
new file mode 100644 (file)
index 0000000..57bc6b5
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef SkHitClear_DEFINED
+#define SkHitClear_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkMemberInfo.h"
+#include "SkTypedArray.h"
+
+class SkHitClear : public SkDisplayable {
+       DECLARE_MEMBER_INFO(HitClear);
+       virtual bool enable(SkAnimateMaker& );
+       virtual bool hasEnable() const;
+private:
+       SkTDDisplayableArray targets;
+};
+
+#endif // SkHitClear_DEFINED
diff --git a/libs/graphics/animator/SkHitTest.cpp b/libs/graphics/animator/SkHitTest.cpp
new file mode 100644 (file)
index 0000000..7e48adb
--- /dev/null
@@ -0,0 +1,66 @@
+#include "SkHitTest.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkHitTest::fInfo[] = {
+       SK_MEMBER_ARRAY(bullets, Displayable),
+       SK_MEMBER_ARRAY(hits, Int),
+       SK_MEMBER_ARRAY(targets, Displayable),
+       SK_MEMBER(value, Boolean)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkHitTest);
+
+SkHitTest::SkHitTest() : value(false) {
+}
+
+bool SkHitTest::draw(SkAnimateMaker& maker) {
+       hits.setCount(bullets.count());
+       value = false;
+       int bulletCount = bullets.count();
+       int targetCount = targets.count();
+       for (int bIndex = 0; bIndex < bulletCount; bIndex++) {
+               SkDisplayable* bullet = bullets[bIndex];
+               SkRect bBounds;
+               bullet->getBounds(&bBounds);
+               hits[bIndex] = -1;
+               if (bBounds.fLeft == (S16)0x8000U)
+                       continue;
+               for (int tIndex = 0; tIndex < targetCount; tIndex++) {
+                       SkDisplayable* target = targets[tIndex];
+                       SkRect tBounds;
+                       target->getBounds(&tBounds);
+                       if (bBounds.intersect(tBounds)) {
+                               hits[bIndex] = tIndex;
+                               value = true;
+                               break;
+                       }
+               }
+       }
+       return false;
+}
+
+bool SkHitTest::enable(SkAnimateMaker& maker) {
+       for (int bIndex = 0; bIndex < bullets.count(); bIndex++) {
+               SkDisplayable* bullet = bullets[bIndex];
+               bullet->enableBounder();
+       }
+       for (int tIndex = 0; tIndex < targets.count(); tIndex++) {
+               SkDisplayable* target = targets[tIndex];
+               target->enableBounder();
+       }
+       return false;
+}
+
+bool SkHitTest::hasEnable() const {
+       return true;
+}
+
+const SkMemberInfo* SkHitTest::preferredChild(SkDisplayTypes type) {
+       if (bullets.count() == 0)
+               return getMember("bullets");
+       return getMember("targets"); // !!! cwap! need to refer to member through enum like kScope instead
+}
+
diff --git a/libs/graphics/animator/SkHitTest.h b/libs/graphics/animator/SkHitTest.h
new file mode 100644 (file)
index 0000000..a8c9fa4
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef SkHitTest_DEFINED
+#define SkHitTest_DEFINED
+
+#include "SkDrawable.h"
+#include "SkTypedArray.h"
+
+class SkHitTest : public SkDrawable {
+       DECLARE_MEMBER_INFO(HitTest);
+       SkHitTest();
+       virtual bool draw(SkAnimateMaker& );
+       virtual bool enable(SkAnimateMaker& );
+       virtual bool hasEnable() const;
+       virtual const SkMemberInfo* preferredChild(SkDisplayTypes type);
+private:
+       SkTDDisplayableArray bullets;
+       SkTDIntArray hits;
+       SkTDDisplayableArray targets;
+       SkBool value;
+};
+
+#endif // SkHitTest_DEFINED
diff --git a/libs/graphics/animator/SkIntArray.h b/libs/graphics/animator/SkIntArray.h
new file mode 100644 (file)
index 0000000..f1824a1
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef SkIntArray_DEFINED
+#define SkIntArray_DEFINED
+
+#include "SkColor.h"
+#include "SkDisplayType.h"
+#include "SkMath.h"
+#include "SkTDArray_Experimental.h"
+
+class SkActive;
+class SkAnimateBase;
+class SkData;
+class SkDisplayable;
+class SkDisplayEvent;
+class SkDrawable;
+class SkDrawColor;
+class SkMatrixPart;
+struct SkMemberInfo;
+class SkPathPart;
+class SkPaintPart;
+class SkTypedArray;
+class SkString;
+union SkOperand;
+
+typedef SkIntArray(int) SkTDIntArray;
+typedef SkIntArray(SkColor) SkTDColorArray;
+typedef SkIntArray(SkDisplayTypes) SkTDDisplayTypesArray;
+typedef SkIntArray(SkMSec) SkTDMSecArray;
+typedef SkIntArray(SkScalar) SkTDScalarArray;
+
+typedef SkLongArray(SkActive*) SkTDActiveArray; 
+typedef SkLongArray(SkAnimateBase*) SkTDAnimateArray; 
+typedef SkLongArray(SkData*) SkTDDataArray; 
+typedef SkLongArray(SkDisplayable*) SkTDDisplayableArray; 
+typedef SkLongArray(SkDisplayEvent*) SkTDDisplayEventArray; 
+typedef SkLongArray(SkDrawable*) SkTDDrawableArray; 
+typedef SkLongArray(SkDrawColor*) SkTDDrawColorArray; 
+typedef SkLongArray(SkMatrixPart*) SkTDMatrixPartArray; 
+typedef SkLongArray(const SkMemberInfo*) SkTDMemberInfoArray;
+typedef SkLongArray(SkPaintPart*) SkTDPaintPartArray; 
+typedef SkLongArray(SkPathPart*) SkTDPathPartArray; 
+typedef SkLongArray(SkTypedArray*) SkTDTypedArrayArray; 
+typedef SkLongArray(SkString*) SkTDStringArray; 
+typedef SkLongArray(SkOperand) SkTDOperandArray; 
+typedef SkLongArray(SkOperand*) SkTDOperandPtrArray; 
+
+#endif // SkIntArray_DEFINED
+
+
+
diff --git a/libs/graphics/animator/SkInterpolator.cpp b/libs/graphics/animator/SkInterpolator.cpp
new file mode 100644 (file)
index 0000000..f151bd4
--- /dev/null
@@ -0,0 +1,252 @@
+#include "SkInterpolator.h"
+#include "SkTSearch.h"
+
+SkInterpolatorBase::SkInterpolatorBase()
+{
+       fStorage        = nil;
+       fTimes          = nil;
+       SkDEBUGCODE(fTimesArray = nil;)
+}
+
+SkInterpolatorBase::~SkInterpolatorBase()
+{
+       if (fStorage)
+               sk_free(fStorage);
+}
+
+void SkInterpolatorBase::reset(int elemCount, int frameCount)
+{
+       fFlags = 0;
+       fElemCount = SkToU8(elemCount);
+       fFrameCount = SkToS16(frameCount);
+       fRepeat = SK_Scalar1;
+       if (fStorage) {
+               sk_free(fStorage);
+               fStorage = nil;
+               fTimes = nil;
+               SkDEBUGCODE(fTimesArray = nil);
+       }
+}
+
+/*     Each value[] run is formated as:
+               <time (in msec)>
+               <blend>
+               <data[fElemCount]>
+
+       Totaling fElemCount+2 entries per keyframe
+*/
+
+bool SkInterpolatorBase::getDuration(SkMSec* startTime, SkMSec* endTime) const
+{
+       if (fFrameCount == 0)
+               return false;
+
+       if (startTime)
+               *startTime = fTimes[0].fTime;
+       if (endTime)
+               *endTime = fTimes[fFrameCount - 1].fTime;
+       return true;
+}
+
+SkScalar SkInterpolatorBase::ComputeRelativeT(SkMSec time, SkMSec prevTime, SkMSec nextTime, SkScalar blend)
+{
+       SkASSERT(time > prevTime && time < nextTime);
+       SkASSERT(blend >= 0);
+
+       SkScalar        t = SkScalarDiv((SkScalar)(time - prevTime), (SkScalar)(nextTime - prevTime));
+       return Blend(t, blend);
+}
+
+SkScalar SkInterpolatorBase::Blend(SkScalar t, SkScalar blend)
+{
+       // f(t) = -2(1-blend)t^3 + 3(1 - blend)t^2 + blend*t
+       return SkScalarMul(SkScalarMul(SkScalarMul(-2*(SK_Scalar1 - blend), t) + 3*(SK_Scalar1 - blend), t) + blend, t);
+}
+
+SkInterpolatorBase::Result SkInterpolatorBase::timeToT(SkMSec time, SkScalar* T, int* indexPtr, SkBool* exactPtr) const
+{
+       SkASSERT(fFrameCount > 0);
+       Result  result = kNormal_Result;
+       if (fRepeat != SK_Scalar1)
+       {
+               SkMSec startTime, endTime;
+               this->getDuration(&startTime, &endTime);
+               SkMSec totalTime = endTime - startTime;
+               SkMSec offsetTime = time - startTime;
+               endTime = SkScalarMulFloor(fRepeat, totalTime);
+               if (offsetTime >= endTime)
+               {
+                       SkScalar fraction = SkScalarFraction(fRepeat);
+                       offsetTime = fraction == 0 && fRepeat > 0 ? totalTime :
+                               SkScalarMulFloor(fraction, totalTime);
+                       result = kFreezeEnd_Result;
+               }
+               else
+               {
+                       int mirror = fFlags & kMirror;
+                       offsetTime = offsetTime % (totalTime << mirror);
+                       if (offsetTime > totalTime)     // can only be true if fMirror is true
+                               offsetTime = (totalTime << 1) - offsetTime;
+               }
+               time = offsetTime + startTime;
+       }
+
+       int index = SkTSearch<SkMSec>(&fTimes[0].fTime, fFrameCount, time, sizeof(SkTimeCode));
+
+       bool    exact = true;
+
+       if (index < 0)
+       {
+               index = ~index;
+               if (index == 0)
+                       result = kFreezeStart_Result;
+               else if (index == fFrameCount)
+               {
+                       if (fFlags & kReset)
+                               index = 0;
+                       else
+                               index -= 1;
+                       result = kFreezeEnd_Result;
+               }
+               else
+                       exact = false;
+       }
+       SkASSERT(index < fFrameCount);
+       const SkTimeCode* nextTime = &fTimes[index];
+       SkMSec   nextT = nextTime[0].fTime;
+       if (exact)
+               *T = 0;
+       else {
+               SkMSec prevT = nextTime[-1].fTime;
+               *T = ComputeRelativeT(time, prevT, nextT, nextTime[-1].fBlend);
+       }
+       *indexPtr = index;
+       *exactPtr = exact;
+       return result;
+}
+
+
+SkInterpolator::SkInterpolator() {
+       INHERITED::reset(0, 0);
+       fValues = nil;
+       SkDEBUGCODE(fScalarsArray = nil;)
+}
+
+SkInterpolator::SkInterpolator(int elemCount, int frameCount)
+{
+       SkASSERT(elemCount > 0);
+       this->reset(elemCount, frameCount);
+}
+
+void SkInterpolator::reset(int elemCount, int frameCount) {
+       INHERITED::reset(elemCount, frameCount);
+       fStorage = sk_malloc_throw((sizeof(SkScalar) * elemCount + sizeof(SkTimeCode)) * frameCount);
+       fTimes = (SkTimeCode*) fStorage;
+       fValues = (SkScalar*) ((char*) fStorage + sizeof(SkTimeCode) * frameCount);
+#ifdef SK_DEBUG
+       fTimesArray = (SkTimeCode(*)[10]) fTimes;
+       fScalarsArray = (SkScalar(*)[10]) fValues;
+#endif
+}
+
+bool SkInterpolator::setKeyFrame(int index, SkMSec time, const SkScalar values[], SkScalar blend)
+{
+       SkASSERT(values != nil);
+       blend = SkScalarPin(blend, 0, SK_Scalar1);
+
+       bool success = ~index == SkTSearch<SkMSec>(&fTimes->fTime, index, time, sizeof(SkTimeCode));
+       SkASSERT(success);
+       if (success) {
+               SkTimeCode* timeCode = &fTimes[index];
+               timeCode->fTime = time;
+               timeCode->fBlend = blend;
+               SkScalar* dst = &fValues[fElemCount * index];
+               memcpy(dst, values, fElemCount * sizeof(SkScalar));
+       }
+       return success;
+}
+
+SkInterpolator::Result SkInterpolator::timeToValues(SkMSec time, SkScalar values[]) const
+{
+       SkScalar T;
+       int index;
+       SkBool exact;
+       Result result = timeToT(time, &T, &index, &exact);
+       if (values)
+       {
+               const SkScalar* nextSrc = &fValues[index * fElemCount];
+
+               if (exact)
+                       memcpy(values, nextSrc, fElemCount * sizeof(SkScalar));
+               else
+               {
+                       SkASSERT(index > 0);
+
+                       const SkScalar* prevSrc = nextSrc - fElemCount;
+
+                       for (int i = fElemCount - 1; i >= 0; --i)
+                               values[i] = SkScalarInterp(prevSrc[i], nextSrc[i], T);
+               }
+       }
+       return result;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+#ifdef SK_SUPPORT_UNITTEST
+       static SkScalar* iset(SkScalar array[3], int a, int b, int c)
+       {
+               array[0] = SkIntToScalar(a);
+               array[1] = SkIntToScalar(b);
+               array[2] = SkIntToScalar(c);
+               return array;
+       }
+#endif
+
+void SkInterpolator::UnitTest()
+{
+#ifdef SK_SUPPORT_UNITTEST
+       SkInterpolator  inter(3, 2);
+       SkScalar                v1[3], v2[3], v[3], vv[3];
+       Result                  result;
+
+       inter.setKeyFrame(0, 100, iset(v1, 10, 20, 30), 0);
+       inter.setKeyFrame(1, 200, iset(v2, 110, 220, 330));
+
+       result = inter.timeToValues(0, v);
+       SkASSERT(result == kFreezeStart_Result);
+       SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
+
+       result = inter.timeToValues(99, v);
+       SkASSERT(result == kFreezeStart_Result);
+       SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
+
+       result = inter.timeToValues(100, v);
+       SkASSERT(result == kNormal_Result);
+       SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
+
+       result = inter.timeToValues(200, v);
+       SkASSERT(result == kNormal_Result);
+       SkASSERT(memcmp(v, v2, sizeof(v)) == 0);
+
+       result = inter.timeToValues(201, v);
+       SkASSERT(result == kFreezeEnd_Result);
+       SkASSERT(memcmp(v, v2, sizeof(v)) == 0);
+
+       result = inter.timeToValues(150, v);
+       SkASSERT(result == kNormal_Result);
+       SkASSERT(memcmp(v, iset(vv, 60, 120, 180), sizeof(v)) == 0);
+
+       result = inter.timeToValues(125, v);
+       SkASSERT(result == kNormal_Result);
+       result = inter.timeToValues(175, v);
+       SkASSERT(result == kNormal_Result);
+#endif
+}
+
+#endif
+
diff --git a/libs/graphics/animator/SkMatrixParts.cpp b/libs/graphics/animator/SkMatrixParts.cpp
new file mode 100644 (file)
index 0000000..b9a0633
--- /dev/null
@@ -0,0 +1,284 @@
+#include "SkMatrixParts.h"
+#include "SkAnimateMaker.h"
+#include "SkDrawMatrix.h"
+#include "SkDrawRectangle.h"
+#include "SkDrawPath.h"
+
+SkMatrixPart::SkMatrixPart() : fMatrix(nil) {
+}
+
+void SkMatrixPart::dirty() { 
+       fMatrix->dirty(); 
+}
+
+SkDisplayable* SkMatrixPart::getParent() const {
+       return fMatrix;
+}
+
+bool SkMatrixPart::setParent(SkDisplayable* parent) {
+       SkASSERT(parent != nil);
+       if (parent->isMatrix() == false)
+               return true;
+       fMatrix = (SkDrawMatrix*) parent;
+       return false;
+}
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkRotate::fInfo[] = {
+       SK_MEMBER(center, Point),
+       SK_MEMBER(degrees, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkRotate);
+
+SkRotate::SkRotate() : degrees(0) { 
+       center.fX = center.fY = 0; 
+}
+
+bool SkRotate::add() {
+       fMatrix->rotate(degrees, center);
+       return false;
+}
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkScale::fInfo[] = {
+       SK_MEMBER(center, Point),
+       SK_MEMBER(x, Float),
+       SK_MEMBER(y, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkScale);
+
+SkScale::SkScale() : x(SK_Scalar1), y(SK_Scalar1) { 
+       center.fX = center.fY = 0; 
+}
+
+bool SkScale::add() {
+       fMatrix->scale(x, y, center);   
+       return false;
+}
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkSkew::fInfo[] = {
+       SK_MEMBER(center, Point),
+       SK_MEMBER(x, Float),
+       SK_MEMBER(y, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkSkew);
+
+SkSkew::SkSkew() : x(0), y(0) { 
+       center.fX = center.fY = 0; 
+}
+
+bool SkSkew::add() {
+       fMatrix->skew(x, y, center);    
+       return false;
+}
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkTranslate::fInfo[] = {
+       SK_MEMBER(x, Float),
+       SK_MEMBER(y, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkTranslate);
+
+SkTranslate::SkTranslate() : x(0), y(0) {
+}
+
+bool SkTranslate::add() {
+       fMatrix->translate(x, y);       
+       return false;
+}
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkFromPath::fInfo[] = {
+       SK_MEMBER(mode, FromPathMode),
+       SK_MEMBER(offset, Float),
+       SK_MEMBER(path, Path)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkFromPath);
+
+SkFromPath::SkFromPath() : 
+       mode(0), offset(0), path(nil) {
+}
+
+SkFromPath::~SkFromPath() {
+}
+
+bool SkFromPath::add() {
+       if (path == nil)
+               return true;
+       static const U8 gFlags[] = {
+               SkPathMeasure::kGetPosAndTan_MatrixFlag,        // normal
+               SkPathMeasure::kGetTangent_MatrixFlag,          // angle
+               SkPathMeasure::kGetPosition_MatrixFlag          // position
+       };
+       if ((unsigned)mode >= SK_ARRAY_COUNT(gFlags))
+               return true;
+       SkMatrix result;
+       fPathMeasure.setPath(&path->getPath(), false);
+       if (fPathMeasure.getMatrix(offset, &result, (SkPathMeasure::MatrixFlags)gFlags[mode]))
+               fMatrix->set(result);
+       return false;
+}
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkRectToRect::fInfo[] = {
+       SK_MEMBER(destination, Rect),
+       SK_MEMBER(source, Rect)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkRectToRect);
+
+SkRectToRect::SkRectToRect() : 
+       source(nil), destination(nil) {
+}
+
+SkRectToRect::~SkRectToRect() {
+}
+
+bool SkRectToRect::add() {
+       if (source == nil || destination == nil)
+               return true;
+       SkMatrix temp;
+       temp.setRectToRect(source->fRect, destination->fRect);
+       fMatrix->set(temp);
+       return false;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkRectToRect::dump(SkAnimateMaker* maker) {
+    dumpBase(maker);
+    SkDebugf("/>\n");
+    SkDisplayList::fIndent += 4;
+    if (source) {
+        SkDebugf("%*s<source>\n", SkDisplayList::fIndent, "");
+        SkDisplayList::fIndent += 4;
+        source->dump(maker);
+        SkDisplayList::fIndent -= 4;
+        SkDebugf("%*s</source>\n", SkDisplayList::fIndent, "");
+    }
+    if (destination) {
+        SkDebugf("%*s<destination>\n", SkDisplayList::fIndent, "");
+        SkDisplayList::fIndent += 4;
+        destination->dump(maker);
+        SkDisplayList::fIndent -= 4;
+        SkDebugf("%*s</destination>\n", SkDisplayList::fIndent, "");        
+    }
+    SkDisplayList::fIndent -= 4;
+    dumpEnd(maker);
+}
+#endif
+
+const SkMemberInfo* SkRectToRect::preferredChild(SkDisplayTypes ) {
+       if (source == nil)
+               return getMember("source"); // !!! cwap! need to refer to member through enum like kScope instead
+       else {
+               SkASSERT(destination == nil);
+               return getMember("destination");
+       }
+}
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkPolyToPoly::fInfo[] = {
+       SK_MEMBER(destination, Polygon),
+       SK_MEMBER(source, Polygon)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkPolyToPoly);
+
+SkPolyToPoly::SkPolyToPoly() : source(nil), destination(nil) {
+}
+
+SkPolyToPoly::~SkPolyToPoly() {
+}
+
+bool SkPolyToPoly::add() {
+       SkASSERT(source);
+       SkASSERT(destination);
+       SkPoint src[4];
+       SkPoint dst[4];
+       SkPath& sourcePath = source->getPath();
+       int srcPts = sourcePath.getPoints(src, 4);
+       SkPath& destPath = destination->getPath();
+       int dstPts = destPath.getPoints(dst, 4);
+       if (srcPts != dstPts)
+               return true;
+       SkMatrix temp;
+       temp.setPolyToPoly(dst, src, srcPts);
+       fMatrix->set(temp);
+       return false;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkPolyToPoly::dump(SkAnimateMaker* maker) {
+    dumpBase(maker);
+    SkDebugf("/>\n");
+    SkDisplayList::fIndent += 4;
+    if (source) {
+        SkDebugf("%*s<source>\n", SkDisplayList::fIndent, "");
+        SkDisplayList::fIndent += 4;
+        source->dump(maker);
+        SkDisplayList::fIndent -= 4;
+        SkDebugf("%*s</source>\n", SkDisplayList::fIndent, "");
+    }
+    if (destination) {
+        SkDebugf("%*s<destination>\n", SkDisplayList::fIndent, "");
+        SkDisplayList::fIndent += 4;
+        destination->dump(maker);
+        SkDisplayList::fIndent -= 4;
+        SkDebugf("%*s</destination>\n", SkDisplayList::fIndent, "");        
+    }
+    SkDisplayList::fIndent -= 4;
+    dumpEnd(maker);
+}
+#endif
+
+void SkPolyToPoly::onEndElement(SkAnimateMaker& ) {
+       SkASSERT(source);
+       SkASSERT(destination);
+       if (source->childHasID() || destination->childHasID())
+               fMatrix->setChildHasID();
+}
+
+const SkMemberInfo* SkPolyToPoly::preferredChild(SkDisplayTypes ) {
+       if (source == nil)
+               return getMember("source"); // !!! cwap! need to refer to member through enum like kScope instead
+       else {
+               SkASSERT(destination == nil);
+               return getMember("destination");
+       }
+}
+
+
diff --git a/libs/graphics/animator/SkMatrixParts.h b/libs/graphics/animator/SkMatrixParts.h
new file mode 100644 (file)
index 0000000..9535355
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef SkMatrixParts_DEFINED
+#define SkMatrixParts_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkMemberInfo.h"
+#include "SkPathMeasure.h"
+
+class SkDrawPath;
+class SkDrawRect;
+class SkPolygon;
+
+class SkDrawMatrix;
+// class SkMatrix;
+
+class SkMatrixPart : public SkDisplayable {
+public:
+       SkMatrixPart();
+       virtual bool add() = 0;
+       virtual void dirty();
+       virtual SkDisplayable* getParent() const;
+       virtual bool setParent(SkDisplayable* parent);
+#ifdef SK_DEBUG
+       virtual bool isMatrixPart() const { return true; }
+#endif
+protected:
+       SkDrawMatrix* fMatrix;
+};
+
+class SkRotate : public SkMatrixPart {
+       DECLARE_MEMBER_INFO(Rotate);
+       SkRotate();
+protected:
+       virtual bool add();
+       SkScalar degrees;
+       SkPoint center;
+};
+
+class SkScale : public SkMatrixPart {
+       DECLARE_MEMBER_INFO(Scale);
+       SkScale();
+protected:
+       virtual bool add();
+       SkScalar x;
+       SkScalar y;
+       SkPoint center;
+};
+
+class SkSkew : public SkMatrixPart {
+       DECLARE_MEMBER_INFO(Skew);
+       SkSkew();
+protected:
+       virtual bool add();
+       SkScalar x;
+       SkScalar y;
+       SkPoint center;
+};
+
+class SkTranslate : public SkMatrixPart {
+       DECLARE_MEMBER_INFO(Translate);
+       SkTranslate();
+protected:
+       virtual bool add();
+       SkScalar x;
+       SkScalar y;
+};
+
+class SkFromPath : public SkMatrixPart {
+       DECLARE_MEMBER_INFO(FromPath);
+       SkFromPath();
+       virtual ~SkFromPath();
+protected:
+       virtual bool add();
+       S32 mode;
+       SkScalar offset;
+       SkDrawPath* path;
+       SkPathMeasure fPathMeasure;
+};
+
+class SkRectToRect : public SkMatrixPart {
+       DECLARE_MEMBER_INFO(RectToRect);
+       SkRectToRect();
+       virtual ~SkRectToRect();
+#ifdef SK_DUMP_ENABLED
+    virtual void dump(SkAnimateMaker* );
+#endif
+       virtual const SkMemberInfo* preferredChild(SkDisplayTypes type);
+protected:
+       virtual bool add();
+       SkDrawRect* source;
+       SkDrawRect* destination;
+};
+
+class SkPolyToPoly : public SkMatrixPart {
+       DECLARE_MEMBER_INFO(PolyToPoly);
+       SkPolyToPoly();
+       virtual ~SkPolyToPoly();
+#ifdef SK_DUMP_ENABLED
+    virtual void dump(SkAnimateMaker* );
+#endif
+       virtual void onEndElement(SkAnimateMaker& );
+       virtual const SkMemberInfo* preferredChild(SkDisplayTypes type);
+protected:
+       virtual bool add();
+       SkPolygon* source;
+       SkPolygon* destination;
+};
+
+// !!! add concat matrix ? 
+
+#endif // SkMatrixParts_DEFINED
diff --git a/libs/graphics/animator/SkMemberInfo.cpp b/libs/graphics/animator/SkMemberInfo.cpp
new file mode 100644 (file)
index 0000000..9ad26d6
--- /dev/null
@@ -0,0 +1,551 @@
+#include "SkMemberInfo.h"
+#include "SkAnimateMaker.h"
+#include "SkAnimatorScript.h"
+#include "SkBase64.h"
+#include "SkCamera.h"
+#include "SkDisplayable.h"
+#include "SkDisplayTypes.h"
+#include "SkDraw3D.h"
+#include "SkDrawColor.h"
+#include "SkParse.h"
+#include "SkScript.h"
+#include "SkTSearch.h"
+#include "SkTypedArray.h"
+
+size_t SkMemberInfo::GetSize(SkDisplayTypes type) {    // size of simple types only
+       size_t byteSize;
+       switch (type) {
+               case SkType_ARGB:
+                       byteSize = sizeof(SkColor);
+                       break;
+               case SkType_AddMode:
+               case SkType_Align:
+               case SkType_ApplyMode:
+               case SkType_ApplyTransition:
+               case SkType_BitmapEncoding:
+               case SkType_Boolean:
+               case SkType_Cap:
+               case SkType_EventCode:
+               case SkType_EventKind:
+               case SkType_EventMode:
+               case SkType_FilterType:
+        case SkType_FontStyle:
+               case SkType_FromPathMode:
+               case SkType_Join:
+               case SkType_MaskFilterBlurStyle:
+               case SkType_PathDirection:
+               case SkType_Style:
+               case SkType_TileMode:
+               case SkType_Xfermode:
+                       byteSize = sizeof(int);
+                       break;
+               case SkType_Base64: // assume base64 data is always const, copied by ref
+               case SkType_Displayable:
+               case SkType_Drawable:
+               case SkType_Matrix:
+                       byteSize = sizeof(void*); 
+                       break;
+               case SkType_MSec:
+                       byteSize = sizeof(SkMSec);
+                       break;
+               case SkType_Point:
+                       byteSize = sizeof(SkPoint);
+                       break;
+               case SkType_3D_Point:
+                       byteSize = sizeof(Sk3D_Point);
+                       break;
+               case SkType_Int:
+                       byteSize = sizeof(S32);
+                       break;
+               case SkType_Float:
+                       byteSize = sizeof(SkScalar);
+                       break;
+               case SkType_DynamicString:
+               case SkType_String:
+                       byteSize = sizeof(SkString);    // assume we'll copy by reference, not value
+                       break;
+               default:
+//                     SkASSERT(0);
+                       byteSize = 0;
+       }
+       return byteSize;
+}
+
+bool SkMemberInfo::getArrayValue(const SkDisplayable* displayable, int index, SkOperand* value) const {
+       SkASSERT(fType != SkType_String && fType != SkType_MemberProperty);
+       char* valuePtr = (char*) *(SkOperand**) memberData(displayable);
+       SkDisplayTypes type = (SkDisplayTypes) 0;
+       if (displayable->getType() == SkType_Array) {
+               SkDisplayArray* dispArray = (SkDisplayArray*) displayable;
+               if (dispArray->values.count() <= index)
+                       return false;
+               type = dispArray->values.getType();
+       } else
+               SkASSERT(0); // incomplete
+       size_t byteSize = GetSize(type);
+       memcpy(value, valuePtr + index * byteSize, byteSize);
+       return true;
+}
+
+size_t SkMemberInfo::getSize(const SkDisplayable* displayable) const {
+       size_t byteSize;
+       switch (fType) {
+               case SkType_MemberProperty:
+                       byteSize = GetSize(propertyType());
+                       break;
+               case SkType_Array: {
+                       SkDisplayTypes type;
+                       if (displayable == nil)
+                               return sizeof(int);
+                       if (displayable->getType() == SkType_Array) {
+                               SkDisplayArray* dispArray = (SkDisplayArray*) displayable;
+                               type = dispArray->values.getType();
+                       } else
+                               type = propertyType();
+                       SkTDOperandArray* array = (SkTDOperandArray*) memberData(displayable);
+                       byteSize = GetSize(type) * array->count();
+                       } break;
+               default:
+                       byteSize = GetSize((SkDisplayTypes) fType);
+       }
+       return byteSize;
+}
+
+void SkMemberInfo::getString(const SkDisplayable* displayable, SkString** string) const {
+       if (fType == SkType_MemberProperty) {
+               SkScriptValue value;
+               displayable->getProperty(propertyIndex(), &value);
+               SkASSERT(value.fType == SkType_String);
+               *string = value.fOperand.fString;
+               return;
+       }
+       SkASSERT(fCount == sizeof(SkString) / sizeof(SkScalar));
+       SkASSERT(fType == SkType_String || fType == SkType_DynamicString);
+       void* valuePtr = memberData(displayable);
+       *string = (SkString*) valuePtr;
+}
+
+void SkMemberInfo::getValue(const SkDisplayable* displayable, SkOperand value[], int count) const {
+       SkASSERT(fType != SkType_String && fType != SkType_MemberProperty);
+       SkASSERT(count == fCount);      
+       void* valuePtr = memberData(displayable);
+       size_t byteSize = getSize(displayable);
+       SkASSERT(sizeof(value[0].fScalar) == sizeof(value[0])); // no support for 64 bit pointers, yet
+       memcpy(value, valuePtr, byteSize);
+}
+
+void SkMemberInfo::setString(SkDisplayable* displayable, SkString* value) const {
+       SkString* string = (SkString*) memberData(displayable);
+       string->set(*value);
+       displayable->dirty();
+}
+
+void SkMemberInfo::setValue(SkDisplayable* displayable, const SkOperand values[], 
+                                                       int count) const {
+       SkASSERT(sizeof(values[0].fScalar) == sizeof(values[0]));       // no support for 64 bit pointers, yet
+       char* dst = (char*) memberData(displayable);
+       if (fType == SkType_Array) {
+               SkTDScalarArray* array = (SkTDScalarArray* ) dst;
+               array->setCount(count);
+               dst = (char*) array->begin();
+       }
+       memcpy(dst, values, count * sizeof(SkOperand));
+       displayable->dirty();
+}
+
+                                                       
+static inline bool is_between(int c, int min, int max)
+{
+       return (unsigned)(c - min) <= (unsigned)(max - min);
+}
+
+static inline bool is_hex(int c)
+{
+       if (is_between(c, '0', '9'))
+               return true;
+       c |= 0x20;      // make us lower-case
+       if (is_between(c, 'a', 'f'))
+               return true;
+       return false;
+}
+
+
+bool SkMemberInfo::setValue(SkAnimateMaker& maker, SkTDOperandArray* arrayStorage, 
+       int storageOffset, int maxStorage, SkDisplayable* displayable, SkDisplayTypes outType,
+       const char rawValue[], size_t rawValueLen) const 
+{
+       SkString valueStr(rawValue, rawValueLen);
+       SkScriptValue scriptValue;
+       scriptValue.fType = SkType_Unknown;
+       scriptValue.fOperand.fS32 = 0;
+       SkDisplayTypes type = getType();
+       SkAnimatorScript engine(maker, displayable, type);
+       if (arrayStorage)
+               displayable = nil;
+       bool success = true;
+       void* untypedStorage = nil;
+       if (displayable && fType != SkType_MemberProperty && fType != SkType_MemberFunction)
+               untypedStorage = (SkTDOperandArray*) memberData(displayable);
+
+       if (type == SkType_ARGB) {
+               // for both SpiderMonkey and SkiaScript, substitute any #xyz or #xxyyzz first
+                       // it's enough to expand the colors into 0xFFxxyyzz
+               const char* poundPos;
+               while ((poundPos = strchr(valueStr.c_str(), '#')) != nil) {
+                       size_t offset = poundPos - valueStr.c_str();
+                       if (valueStr.size() - offset < 4)
+                               break;
+                       char r = poundPos[1];
+                       char g = poundPos[2];
+                       char b = poundPos[3];
+                       if (is_hex(r) == false || is_hex(g) == false || is_hex(b) == false)
+                               break;
+                       char hex = poundPos[4];
+                       if (is_hex(hex) == false) {
+                               valueStr.insertUnichar(offset + 1, r);
+                               valueStr.insertUnichar(offset + 3, g);
+                               valueStr.insertUnichar(offset + 5, b);
+                       }
+                       *(char*) poundPos = '0'; // overwrite '#'
+                       valueStr.insert(offset + 1, "xFF");
+               } 
+       }
+       if (SkDisplayType::IsDisplayable(&maker, type) || SkDisplayType::IsEnum(&maker, type) || type == SkType_ARGB)
+               goto scriptCommon;
+       switch (type) {
+               case SkType_String:
+#if 0
+                       if (displayable && displayable->isAnimate()) {
+                               
+                               goto noScriptString;
+                       } 
+                       if (strncmp(rawValue, "#string:", sizeof("#string:") - 1) == 0) {
+                               SkASSERT(sizeof("string") == sizeof("script"));
+                               char* stringHeader = valueStr.writable_str();
+                               memcpy(&stringHeader[1], "script", sizeof("script") - 1);
+                               rawValue = valueStr.c_str();
+                               goto noScriptString;
+                       } else 
+#endif
+                       if (strncmp(rawValue, "#script:", sizeof("#script:") - 1) != 0)
+                               goto noScriptString;
+                       valueStr.remove(0, 8);
+               case SkType_Unknown:
+               case SkType_Int: 
+               case SkType_MSec:  // for the purposes of script, MSec is treated as a Scalar
+               case SkType_Point:
+               case SkType_3D_Point:
+               case SkType_Float:
+               case SkType_Array:
+scriptCommon: {
+                               const char* script = valueStr.c_str();
+                               success = engine.evaluateScript(&script, &scriptValue);
+                               if (success == false) {
+                                       maker.setScriptError(engine);
+                                       return false;
+                               }
+                       }
+                       SkASSERT(success);
+                       if (scriptValue.fType == SkType_Displayable) {
+                               if (type == SkType_String) {
+                                       const char* charPtr;
+                                       maker.findKey(scriptValue.fOperand.fDisplayable, &charPtr);
+                                       scriptValue.fOperand.fString = new SkString(charPtr);
+                                       scriptValue.fType = SkType_String;
+                                       engine.SkScriptEngine::track(scriptValue.fOperand.fString);
+                                       break;
+                               }
+                               SkASSERT(SkDisplayType::IsDisplayable(&maker, type));
+                               if (displayable)
+                                       displayable->setReference(this, scriptValue.fOperand.fDisplayable);
+                               else
+                                       arrayStorage->begin()[0].fDisplayable = scriptValue.fOperand.fDisplayable;
+                               return true;
+                       }
+                       if (type != scriptValue.fType) {
+                               if (scriptValue.fType == SkType_Array) {
+                                       engine.forget(scriptValue.getArray());
+                                       goto writeStruct; // real structs have already been written by script
+                               }
+                               switch (type) {
+                                       case SkType_String:
+                                               success = engine.convertTo(SkType_String, &scriptValue);
+                                               break;
+                                       case SkType_MSec:
+                                       case SkType_Float:
+                                               success = engine.convertTo(SkType_Float, &scriptValue);
+                                               break;
+                                       case SkType_Int:
+                                               success = engine.convertTo(SkType_Int, &scriptValue);
+                                               break;
+                                       case SkType_Array:
+                                               success = engine.convertTo(arrayType(), &scriptValue);
+                                               // !!! incomplete; create array of appropriate type and add scriptValue to it
+                                               SkASSERT(0);
+                                               break;
+                                       case SkType_Displayable:
+                                       case SkType_Drawable:
+                                               return false;   // no way to convert other types to this
+                                       default:        // to avoid warnings
+                                               break;
+                               }
+                               if (success == false)
+                                       return false;
+                       }
+                       if (type == SkType_MSec)
+                               scriptValue.fOperand.fMSec = SkScalarMulRound(scriptValue.fOperand.fScalar, 1000);
+                       scriptValue.fType = type;
+               break;
+               noScriptString:
+               case SkType_DynamicString:
+                       if (fType == SkType_MemberProperty && displayable) {
+                               SkString string(rawValue, rawValueLen);
+                               SkScriptValue scriptValue;
+                               scriptValue.fOperand.fString = &string;
+                               scriptValue.fType = SkType_String;
+                               displayable->setProperty(propertyIndex(), scriptValue);
+                       } else if (displayable) {
+                               SkString* string = (SkString*) memberData(displayable);
+                               string->set(rawValue, rawValueLen);
+                       } else {
+                               SkASSERT(arrayStorage->count() == 1);
+                               arrayStorage->begin()->fString->set(rawValue, rawValueLen);
+                       }
+                       goto dirty;
+               case SkType_Base64: {
+                       SkBase64 base64;
+                       base64.decode(rawValue, rawValueLen);
+                       *(SkBase64* ) untypedStorage = base64;
+                       } goto dirty;
+               default:
+                       SkASSERT(0);
+                       break;
+       }
+//     if (SkDisplayType::IsStruct(type) == false) 
+       {
+writeStruct:
+               if (writeValue(displayable, arrayStorage, storageOffset, maxStorage, 
+                               untypedStorage, outType, scriptValue)) {
+                                       maker.setErrorCode(SkDisplayXMLParserError::kUnexpectedType);
+                       return false;
+               }
+       }
+dirty:
+       if (displayable)
+               displayable->dirty();
+       return true;
+}
+
+bool SkMemberInfo::setValue(SkAnimateMaker& maker, SkTDOperandArray* arrayStorage, 
+               int storageOffset, int maxStorage, SkDisplayable* displayable, SkDisplayTypes outType,
+               SkString& raw) const {
+       return setValue(maker, arrayStorage, storageOffset, maxStorage, displayable, outType, raw.c_str(),
+               raw.size());
+}
+
+bool SkMemberInfo::writeValue(SkDisplayable* displayable, SkTDOperandArray* arrayStorage, 
+       int storageOffset, int maxStorage, void* untypedStorage, SkDisplayTypes outType, 
+       SkScriptValue& scriptValue) const
+{
+       SkOperand* storage = untypedStorage ? (SkOperand*) untypedStorage : arrayStorage ? 
+               arrayStorage->begin() : nil;
+       if (storage)
+               storage += storageOffset;
+       SkDisplayTypes type = getType();
+       if (fType == SkType_MemberProperty) {
+               if(displayable)
+                       displayable->setProperty(propertyIndex(), scriptValue);
+               else {
+                       SkASSERT(storageOffset < arrayStorage->count());
+                       switch (scriptValue.fType) {
+                               case SkType_Boolean:
+                               case SkType_Float:
+                               case SkType_Int:
+                                       memcpy(&storage->fScalar, &scriptValue.fOperand.fScalar, sizeof(SkScalar));
+                                       break;
+                               case SkType_Array:
+                                       memcpy(&storage->fScalar, scriptValue.fOperand.fArray->begin(), scriptValue.fOperand.fArray->count() * sizeof(SkScalar));
+                                       break;
+                               case SkType_String:
+                                       storage->fString->set(*scriptValue.fOperand.fString);
+                                       break;
+                               default:
+                                       SkASSERT(0);    // type isn't handled yet
+                       }
+               }
+       } else if (fType == SkType_MemberFunction) {
+               SkASSERT(scriptValue.fType == SkType_Array);
+               if (displayable)
+                       displayable->executeFunction(displayable, this, scriptValue.fOperand.fArray, nil);
+               else {
+                       int count = scriptValue.fOperand.fArray->count();
+       //              SkASSERT(maxStorage == 0 || count == maxStorage);
+                       if (arrayStorage->count() == 2)
+                               arrayStorage->setCount(2 * count);
+                       else {
+                               storageOffset *= count;
+                               SkASSERT(count + storageOffset <= arrayStorage->count());
+                       }
+                       memcpy(&(*arrayStorage)[storageOffset], scriptValue.fOperand.fArray->begin(), count * sizeof(SkOperand));
+               }
+
+       } else if (fType == SkType_Array) {
+               SkTypedArray* destArray = (SkTypedArray*) (untypedStorage ? untypedStorage : arrayStorage);
+               SkASSERT(destArray);
+       //      destArray->setCount(0);
+               if (scriptValue.fType != SkType_Array) {
+                       SkASSERT(type == scriptValue.fType);
+       //              SkASSERT(storageOffset + 1 <= maxStorage);
+                       destArray->setCount(storageOffset + 1);
+                       (*destArray)[storageOffset] = scriptValue.fOperand;
+               } else {
+                       if (type == SkType_Unknown) {
+                               type = scriptValue.fOperand.fArray->getType();
+                               destArray->setType(type);
+                       }
+                       SkASSERT(type == scriptValue.fOperand.fArray->getType());
+                       int count = scriptValue.fOperand.fArray->count();
+       //              SkASSERT(storageOffset + count <= maxStorage);
+                       destArray->setCount(storageOffset + count);
+                       memcpy(destArray->begin() + storageOffset, scriptValue.fOperand.fArray->begin(), sizeof(SkOperand) * count);
+               }
+       } else if (type == SkType_String) {
+               SkString* string = untypedStorage ? (SkString*) untypedStorage : (*arrayStorage)[storageOffset].fString;
+               string->set(*scriptValue.fOperand.fString);
+       } else if (type == SkType_ARGB && outType == SkType_Float) {
+               SkTypedArray* array = scriptValue.fOperand.fArray;
+               SkASSERT(scriptValue.fType == SkType_Int || scriptValue.fType == SkType_ARGB || 
+                       scriptValue.fType == SkType_Array);
+               SkASSERT(scriptValue.fType != SkType_Array || (array != nil &&
+                       array->getType() == SkType_Int));
+               int numberOfColors = scriptValue.fType == SkType_Array ? array->count() : 1;
+               int numberOfComponents = numberOfColors * 4;
+       //      SkASSERT(maxStorage == 0 || maxStorage == numberOfComponents);
+               if (maxStorage == 0)
+                       arrayStorage->setCount(numberOfComponents);
+               for (int index = 0; index < numberOfColors; index++) {
+                       SkColor color = scriptValue.fType == SkType_Array ? 
+                               (SkColor) array->begin()[index].fS32 : (SkColor) scriptValue.fOperand.fS32;
+                       storage[0].fScalar = SkIntToScalar(SkColorGetA(color));
+                       storage[1].fScalar = SkIntToScalar(SkColorGetR(color));
+                       storage[2].fScalar = SkIntToScalar(SkColorGetG(color));
+                       storage[3].fScalar = SkIntToScalar(SkColorGetB(color));
+                       storage += 4;
+               }
+       } else if (SkDisplayType::IsStruct(nil /* !!! maker*/, type)) {
+               if (scriptValue.fType != SkType_Array)
+                       return true;    // error
+               SkASSERT(sizeof(SkScalar) == sizeof(SkOperand)); // !!! no 64 bit pointer support yet
+               int count = scriptValue.fOperand.fArray->count();
+               if (count > 0) {
+                       SkASSERT(fCount == count);
+                       memcpy(storage, scriptValue.fOperand.fArray->begin(), count * sizeof(SkOperand));
+               }
+       } else if (scriptValue.fType == SkType_Array) {
+               SkASSERT(scriptValue.fOperand.fArray->getType() == type);
+               SkASSERT(scriptValue.fOperand.fArray->count() == getCount());
+               memcpy(storage, scriptValue.fOperand.fArray->begin(), getCount() * sizeof(SkOperand));
+       } else {
+               memcpy(storage, &scriptValue.fOperand, sizeof(SkOperand));
+       }
+       return false;
+}
+
+
+//void SkMemberInfo::setValue(SkDisplayable* displayable, const char value[], const char name[]) const {
+//     void* valuePtr = (void*) ((char*) displayable + fOffset);
+//     switch (fType) {
+//             case SkType_Point3D: {
+//                     static const char xyz[] = "x|y|z";
+//                     int index = find_one(xyz, name);
+//                     SkASSERT(index >= 0);
+//                     valuePtr = (void*) ((char*) valuePtr + index * sizeof(SkScalar));
+//                     } break;
+//             default:
+//                     SkASSERT(0);
+//     }
+//     SkParse::FindScalar(value, (SkScalar*) valuePtr);
+//     displayable->dirty();
+//}
+
+#if SK_USE_CONDENSED_INFO == 0
+
+// Find Nth memberInfo
+const SkMemberInfo* SkMemberInfo::Find(const SkMemberInfo info[], int count, int* index) {
+       SkASSERT(*index >= 0);
+       if (info->fType == SkType_BaseClassInfo) {
+               const SkMemberInfo* inherited = (SkMemberInfo*) info->fName;
+               const SkMemberInfo* result = SkMemberInfo::Find(inherited, info->fCount, index);
+               if (result != nil)
+                       return result;
+               if (--count == 0)
+                       return nil;
+               info++;
+       }
+       SkASSERT(info->fName);
+       SkASSERT(info->fType != SkType_BaseClassInfo);
+       if (*index >= count) {
+               *index -= count;
+               return nil;
+       }
+       return &info[*index];
+}
+
+// Find named memberinfo
+const SkMemberInfo* SkMemberInfo::Find(const SkMemberInfo info[], int count, const char** matchPtr) {
+       const char* match = *matchPtr;
+       if (info->fType == SkType_BaseClassInfo) {
+               const SkMemberInfo* inherited = (SkMemberInfo*) info->fName;
+               const SkMemberInfo* result = SkMemberInfo::Find(inherited, info->fCount, matchPtr);
+               if (result != nil)
+                       return result;
+               if (--count == 0)
+                       return nil;
+               info++;
+       }
+       SkASSERT(info->fName);
+       SkASSERT(info->fType != SkType_BaseClassInfo);
+       int index = SkStrSearch(&info->fName, count, match, sizeof(*info));
+       if (index < 0 || index >= count)
+               return nil;
+       return &info[index];
+}
+
+const SkMemberInfo* SkMemberInfo::getInherited() const {
+       return (SkMemberInfo*) fName;
+}
+
+#endif // SK_USE_CONDENSED_INFO == 0
+
+#if 0
+bool SkMemberInfo::SetValue(void* valuePtr, const char value[], SkDisplayTypes type, 
+                                                       int count) {
+       switch (type) {
+               case SkType_Animate:
+               case SkType_BaseBitmap: 
+               case SkType_Bitmap:
+               case SkType_Dash:
+               case SkType_Displayable:
+               case SkType_Drawable:
+               case SkType_Matrix:
+               case SkType_Path:
+               case SkType_Text:
+               case SkType_3D_Patch:
+                       return false; // ref to object; caller must resolve
+               case SkType_MSec: {
+                       SkParse::FindMSec(value, (SkMSec*) valuePtr);
+                       } break;
+               case SkType_3D_Point:
+               case SkType_Point:
+       //      case SkType_PointArray:
+               case SkType_ScalarArray: 
+                       SkParse::FindScalars(value, (SkScalar*) valuePtr, count);
+                       break;
+               default:
+                       SkASSERT(0);
+       }
+       return true;
+}
+#endif
+
+
diff --git a/libs/graphics/animator/SkMemberInfo.h b/libs/graphics/animator/SkMemberInfo.h
new file mode 100644 (file)
index 0000000..ec66846
--- /dev/null
@@ -0,0 +1,266 @@
+#ifndef SkMemberInfo_DEFINED
+#define SkMemberInfo_DEFINED
+
+#if defined SK_BUILD_CONDENSED
+       #define SK_USE_CONDENSED_INFO 0
+#elif defined  SK_BUILD_FOR_BREW
+       #define SK_USE_CONDENSED_INFO 1 /* required by BREW to handle its lack of writable globals */
+#else
+       #define SK_USE_CONDENSED_INFO 0 /* optional, but usually 1 unless Cary is testing something */
+#endif
+
+#include "SkDisplayType.h"
+#include "SkScript.h"
+#include "SkString.h"
+#include "SkIntArray.h"
+
+class SkAnimateMaker;
+class SkDisplayable;
+class SkScriptEngine;
+
+// temporary hacks until name change is more complete
+#define SkFloat SkScalar
+#define SkInt SkS32
+
+struct SkMemberInfo {
+       //!!! alternative:
+       // if fCount == 0, record is member property
+       // then fType can be type, so caller doesn't have to check
+#if SK_USE_CONDENSED_INFO == 0
+       const char* fName;      // may be nil for anonymous functions
+       size_t fOffset; // if negative, is index into member pointer table (for properties and functions)
+       SkDisplayTypes fType;
+       int fCount;                     // for properties, actual type (count is always assumed to be 1)
+#else
+       unsigned char fName;
+       signed char fOffset;
+       unsigned char fType;
+       signed char fCount;
+#endif
+       SkDisplayTypes arrayType() const {
+               SkASSERT(fType == SkType_Array);
+               return (SkDisplayTypes) fCount;  // hack, but worth it?
+       }
+       int functionIndex() const {
+               SkASSERT(fType == SkType_MemberFunction);
+               return (signed) fOffset > 0 ? -1 + (int) fOffset : -1 - (int) fOffset;
+       }
+       bool getArrayValue(const SkDisplayable* displayable, int index, SkOperand* value) const;
+       int getCount() const {
+               return fType == SkType_MemberProperty || fType == SkType_Array ||
+                       fType == SkType_MemberFunction ? 1 : fCount;
+       }
+       const SkMemberInfo* getInherited() const;
+       size_t getSize(const SkDisplayable* ) const;
+       void getString(const SkDisplayable* , SkString** string) const;
+       SkDisplayTypes getType() const {
+               return fType == SkType_MemberProperty || fType == SkType_Array ||
+                       fType == SkType_MemberFunction ? (SkDisplayTypes) fCount : (SkDisplayTypes) fType;
+       }
+       void getValue(const SkDisplayable* , SkOperand values[], int count) const;
+       bool isEnum() const;
+       const char* mapEnums(const char* match, int* value) const;
+       void* memberData(const SkDisplayable* displayable) const {
+               SkASSERT(fType != SkType_MemberProperty &&      fType != SkType_MemberFunction);
+               return (void*) ((const char*) displayable + fOffset);
+       }
+       int propertyIndex() const {
+               SkASSERT(fType == SkType_MemberProperty);
+               return (signed) fOffset > 0 ? -1 + (int) fOffset : -1 - (int) fOffset;
+       }
+       SkDisplayTypes propertyType() const {
+               SkASSERT(fType == SkType_MemberProperty || fType == SkType_Array);
+               return (SkDisplayTypes) fCount;  // hack, but worth it?
+       }
+       void setMemberData(SkDisplayable* displayable, const void* child, size_t size) const {
+               SkASSERT(fType != SkType_MemberProperty &&      fType != SkType_MemberFunction);
+               memcpy((char*) displayable + fOffset, child, size);
+       }
+       void setString(SkDisplayable* , SkString* ) const;
+       void setValue(SkDisplayable* , const SkOperand values[], int count) const;
+       bool setValue(SkAnimateMaker& , SkTDOperandArray* storage, 
+               int storageOffset, int maxStorage, SkDisplayable* , 
+               SkDisplayTypes outType, const char value[], size_t len) const;
+       bool setValue(SkAnimateMaker& , SkTDOperandArray* storage, 
+               int storageOffset, int maxStorage, SkDisplayable* , 
+               SkDisplayTypes outType, SkString& str) const;
+//     void setValue(SkDisplayable* , const char value[], const char name[]) const;
+       bool writeValue(SkDisplayable* displayable, SkTDOperandArray* arrayStorage, 
+               int storageOffset, int maxStorage, void* untypedStorage, SkDisplayTypes outType, 
+               SkScriptValue& scriptValue) const;
+#if SK_USE_CONDENSED_INFO == 0
+       static const SkMemberInfo* Find(const SkMemberInfo [], int count, int* index);
+       static const SkMemberInfo* Find(const SkMemberInfo [], int count, const char** name);
+#else
+       static const SkMemberInfo* Find(SkDisplayTypes type, int* index);
+       static const SkMemberInfo* Find(SkDisplayTypes type, const char** name);
+#endif
+       static size_t GetSize(SkDisplayTypes type);     // size of simple types only
+//     static bool SetValue(void* value, const char* name, SkDisplayTypes , int count);
+};
+
+#define SK_MEMBER(_member, _type) \
+       { #_member, SK_OFFSETOF(BASE_CLASS, _member), SkType_##_type, \
+       sizeof(((BASE_CLASS*) 1)->_member) / sizeof(SkScalar) }
+
+#define SK_MEMBER_ALIAS(_member, _alias, _type) \
+       { #_member, SK_OFFSETOF(BASE_CLASS, _alias), SkType_##_type, \
+       sizeof(((BASE_CLASS*) 1)->_alias) / sizeof(SkScalar) }
+
+#define SK_MEMBER_ARRAY(_member, _type) \
+       { #_member, SK_OFFSETOF(BASE_CLASS, _member), SkType_Array, \
+       (int) SkType_##_type }
+
+#define SK_MEMBER_INHERITED \
+       { (const char*) INHERITED::fInfo, 0, SkType_BaseClassInfo, INHERITED::fInfoCount }
+
+// #define SK_MEMBER_KEY_TYPE(_member, _type) 
+//     {#_member, (size_t) -1, SkType_##_type, 0}
+
+#define SK_FUNCTION(_member) \
+       k_##_member##Function
+
+#define SK_PROPERTY(_member) \
+       k_##_member##Property
+
+#define SK_MEMBER_DYNAMIC_FUNCTION(_member, _type) \
+       {#_member, (size_t) (+1 + SK_FUNCTION(_member)), SkType_MemberFunction, \
+       (int) SkType_##_type }
+
+#define SK_MEMBER_DYNAMIC_PROPERTY(_member, _type) \
+       {#_member, (size_t) (1 + SK_PROPERTY(_member)), SkType_MemberProperty, \
+       (int) SkType_##_type }
+
+#define SK_MEMBER_FUNCTION(_member, _type) \
+       {#_member, (size_t) (-1 - SK_FUNCTION(_member)), SkType_MemberFunction, \
+       (int) SkType_##_type }
+
+#define SK_MEMBER_PROPERTY(_member, _type) \
+       {#_member, (size_t) (-1 - SK_PROPERTY(_member)), SkType_MemberProperty, \
+       (int) SkType_##_type }
+
+#if SK_USE_CONDENSED_INFO == 0
+
+#define DECLARE_PRIVATE_MEMBER_INFO(_type) \
+public: \
+       static const SkMemberInfo fInfo[]; \
+       static const int fInfoCount; \
+       virtual const SkMemberInfo* getMember(int index); \
+       virtual const SkMemberInfo* getMember(const char name[]); \
+       typedef Sk##_type BASE_CLASS
+
+#define DECLARE_MEMBER_INFO(_type) \
+public: \
+       static const SkMemberInfo fInfo[]; \
+       static const int fInfoCount; \
+       virtual const SkMemberInfo* getMember(int index); \
+       virtual const SkMemberInfo* getMember(const char name[]); \
+       virtual SkDisplayTypes getType() const { return SkType_##_type; } \
+       typedef Sk##_type BASE_CLASS
+
+#define DECLARE_DRAW_MEMBER_INFO(_type) \
+public: \
+       static const SkMemberInfo fInfo[]; \
+       static const int fInfoCount; \
+       virtual const SkMemberInfo* getMember(int index); \
+       virtual const SkMemberInfo* getMember(const char name[]); \
+       virtual SkDisplayTypes getType() const { return SkType_##_type; } \
+       typedef SkDraw##_type BASE_CLASS
+
+#define DECLARE_DISPLAY_MEMBER_INFO(_type) \
+public: \
+       static const SkMemberInfo fInfo[]; \
+       static const int fInfoCount; \
+       virtual const SkMemberInfo* getMember(int index); \
+       virtual const SkMemberInfo* getMember(const char name[]); \
+       virtual SkDisplayTypes getType() const { return SkType_##_type; } \
+       typedef SkDisplay##_type BASE_CLASS
+
+#define DECLARE_EMPTY_MEMBER_INFO(_type) \
+public: \
+       virtual SkDisplayTypes getType() const { return SkType_##_type; }
+       
+#define DECLARE_EXTRAS_MEMBER_INFO(_type) \
+public: \
+       static const SkMemberInfo fInfo[]; \
+       static const int fInfoCount; \
+       virtual const SkMemberInfo* getMember(int index); \
+       virtual const SkMemberInfo* getMember(const char name[]); \
+       SkDisplayTypes fType; \
+       virtual SkDisplayTypes getType() const { return fType; } \
+       typedef _type BASE_CLASS
+
+#define DECLARE_NO_VIRTUALS_MEMBER_INFO(_type) \
+public: \
+       static const SkMemberInfo fInfo[]; \
+       static const int fInfoCount; \
+       typedef Sk##_type BASE_CLASS
+
+#define DEFINE_GET_MEMBER(_class) \
+       const SkMemberInfo* _class::getMember(int index) { \
+               const SkMemberInfo* result = SkMemberInfo::Find(fInfo, SK_ARRAY_COUNT(fInfo), &index); \
+               return result; \
+       } \
+       const SkMemberInfo* _class::getMember(const char name[]) { \
+               const SkMemberInfo* result = SkMemberInfo::Find(fInfo, SK_ARRAY_COUNT(fInfo), &name); \
+               return result; \
+       } \
+       const int _class::fInfoCount = SK_ARRAY_COUNT(fInfo)
+
+#define DEFINE_NO_VIRTUALS_GET_MEMBER(_class) \
+       const int _class::fInfoCount = SK_ARRAY_COUNT(fInfo)
+
+#else
+
+#define DECLARE_PRIVATE_MEMBER_INFO(_type) \
+public: \
+       typedef Sk##_type BASE_CLASS
+
+#define DECLARE_MEMBER_INFO(_type) \
+public: \
+       virtual const SkMemberInfo* getMember(int index) { \
+               return SkDisplayType::GetMember(nil, SkType_##_type, &index); } \
+       virtual const SkMemberInfo* getMember(const char name[]) { \
+               return SkDisplayType::GetMember(nil, SkType_##_type, &name); } \
+       virtual SkDisplayTypes getType() const { return SkType_##_type; } \
+       typedef Sk##_type BASE_CLASS
+
+#define DECLARE_DRAW_MEMBER_INFO(_type) \
+public: \
+       virtual const SkMemberInfo* getMember(int index) { \
+               return SkDisplayType::GetMember(nil, SkType_##_type, &index); } \
+       virtual const SkMemberInfo* getMember(const char name[]) { \
+               return SkDisplayType::GetMember(nil, SkType_##_type, &name); } \
+       virtual SkDisplayTypes getType() const { return SkType_##_type; } \
+       typedef SkDraw##_type BASE_CLASS
+
+#define DECLARE_DISPLAY_MEMBER_INFO(_type) \
+public: \
+       virtual const SkMemberInfo* getMember(int index) { \
+               return SkDisplayType::GetMember(nil, SkType_##_type, &index); } \
+       virtual const SkMemberInfo* getMember(const char name[]) { \
+               return SkDisplayType::GetMember(nil, SkType_##_type, &name); } \
+       virtual SkDisplayTypes getType() const { return SkType_##_type; } \
+       typedef SkDisplay##_type BASE_CLASS
+
+#define DECLARE_EXTRAS_MEMBER_INFO(_type) \
+public: \
+       virtual const SkMemberInfo* getMember(int index) { \
+               return SkDisplayType::GetMember(nil, SkType_##_type, &index); } \
+       virtual const SkMemberInfo* getMember(const char name[]) { \
+               return SkDisplayType::GetMember(nil, fType, &name); } \
+       SkDisplayTypes fType; \
+       virtual SkDisplayTypes getType() const { return fType; } \
+       typedef _type BASE_CLASS
+
+#define DECLARE_NO_VIRTUALS_MEMBER_INFO(_type) \
+public: \
+       typedef Sk##_type BASE_CLASS
+
+#define DEFINE_GET_MEMBER(_class)
+#define DEFINE_NO_VIRTUALS_GET_MEMBER(_class)
+
+#endif
+
+#endif // SkMemberInfo_DEFINED
+
diff --git a/libs/graphics/animator/SkOpArray.cpp b/libs/graphics/animator/SkOpArray.cpp
new file mode 100755 (executable)
index 0000000..c6c9ae9
--- /dev/null
@@ -0,0 +1,16 @@
+#include "SkOpArray.h"\r
+\r
+SkOpArray::SkOpArray() : fType(SkOperand2::kNoType) {\r
+}\r
+\r
+SkOpArray::SkOpArray(SkOperand2::OpType type) : fType(type) {\r
+}\r
+\r
+bool SkOpArray::getIndex(int index, SkOperand2* operand) {\r
+       if (index >= count()) {\r
+               SkASSERT(0);\r
+               return false;\r
+       }\r
+       *operand = begin()[index];\r
+       return true;\r
+}\r
diff --git a/libs/graphics/animator/SkOpArray.h b/libs/graphics/animator/SkOpArray.h
new file mode 100755 (executable)
index 0000000..19ae968
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef SkOpArray_DEFINED\r
+#define SkOpArray_DEFINED\r
+\r
+#include "SkOperand2.h"\r
+#include "SkTDArray_Experimental.h"\r
+\r
+typedef SkLongArray(SkOperand2) SkTDOperand2Array; \r
+\r
+class SkOpArray : public SkTDOperand2Array {\r
+public:\r
+       SkOpArray();\r
+       SkOpArray(SkOperand2::OpType type);\r
+       bool getIndex(int index, SkOperand2* operand);\r
+       SkOperand2::OpType getType() { return fType; }\r
+       void setType(SkOperand2::OpType type) { \r
+               fType = type;\r
+       }\r
+protected:\r
+       SkOperand2::OpType fType;\r
+};\r
+\r
+#endif // SkOpArray_DEFINED\r
diff --git a/libs/graphics/animator/SkOperand.h b/libs/graphics/animator/SkOperand.h
new file mode 100644 (file)
index 0000000..547cdbd
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef SkOperand_DEFINED
+#define SkOperand_DEFINED
+
+#include "SkDisplayType.h"
+
+class SkTypedArray;
+class SkDisplayable;
+class SkDrawable;
+class SkString;
+
+union SkOperand {
+//     SkOperand() {}
+//     SkOperand(SkScalar scalar) : fScalar(scalar) {}
+       SkTypedArray* fArray;
+       SkDisplayable* fDisplayable;
+       SkDrawable* fDrawable;
+       void* fObject;
+       int32_t fS32;
+       SkMSec fMSec;
+       SkScalar fScalar;
+       SkString* fString;
+};
+
+struct SkScriptValue {
+       SkOperand fOperand;
+       SkDisplayTypes fType;
+       SkTypedArray* getArray() { SkASSERT(fType == SkType_Array); return fOperand.fArray; }
+       SkDisplayable* getDisplayable() { SkASSERT(fType == SkType_Displayable); return fOperand.fDisplayable; }
+       SkDrawable* getDrawable() { SkASSERT(fType == SkType_Drawable); return fOperand.fDrawable; }
+       int32_t getS32(SkAnimateMaker* maker) { SkASSERT(fType == SkType_Int || fType == SkType_Boolean ||
+               SkDisplayType::IsEnum(maker, fType)); return fOperand.fS32; }
+       SkMSec getMSec() { SkASSERT(fType == SkType_MSec); return fOperand.fMSec; }
+       SkScalar getScalar() { SkASSERT(fType == SkType_Float); return fOperand.fScalar; }
+       SkString* getString() { SkASSERT(fType == SkType_String); return fOperand.fString; }
+};
+
+#endif // SkOperand_DEFINED
diff --git a/libs/graphics/animator/SkOperand2.h b/libs/graphics/animator/SkOperand2.h
new file mode 100755 (executable)
index 0000000..f482e66
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef SkOperand2_DEFINED
+#define SkOperand2_DEFINED
+
+#include "SkScalar.h"
+
+class SkOpArray;
+class SkString;
+
+union SkOperand2 {
+       enum OpType {
+               kNoType,
+               kS32 = 1,
+               kScalar = 2,
+               kString = 4,
+               kArray = 8,
+               kObject = 16
+       };
+       SkOpArray* fArray;
+       void* fObject;
+       size_t fReference;
+       int32_t fS32;
+       SkScalar fScalar;
+       SkString* fString;
+};
+
+struct SkScriptValue2 {
+       enum IsConstant {
+               kConstant,
+               kVariable
+       };
+       enum IsWritten {
+               kUnwritten,
+               kWritten
+       };
+       SkOperand2 fOperand;
+       SkOperand2::OpType fType : 8;
+       IsConstant fIsConstant : 8;
+       IsWritten fIsWritten : 8;
+       SkOpArray* getArray() { SkASSERT(fType == SkOperand2::kArray); return fOperand.fArray; }
+       void* getObject() { SkASSERT(fType == SkOperand2::kObject); return fOperand.fObject; }
+       int32_t getS32() { SkASSERT(fType == SkOperand2::kS32); return fOperand.fS32; }
+       SkScalar getScalar() { SkASSERT(fType == SkOperand2::kScalar); return fOperand.fScalar; }
+       SkString* getString() { SkASSERT(fType == SkOperand2::kString); return fOperand.fString; }
+        bool isConstant() const { return fIsConstant == kConstant; }
+};
+
+#endif // SkOperand2_DEFINED
diff --git a/libs/graphics/animator/SkOperandInterpolator.h b/libs/graphics/animator/SkOperandInterpolator.h
new file mode 100644 (file)
index 0000000..c6e38c2
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef SkOperandInterpolator_DEFINED
+#define SkOperandInterpolator_DEFINED
+
+#include "SkDisplayType.h"
+#include "SkInterpolator.h"
+#include "SkOperand.h"
+
+class SkOperandInterpolator : public SkInterpolatorBase {
+public:
+       SkOperandInterpolator();
+       SkOperandInterpolator(int elemCount, int frameCount, SkDisplayTypes type);
+       SkOperand* getValues() { return fValues; }
+       int getValuesCount() { return fFrameCount * fElemCount; }
+       void    reset(int elemCount, int frameCount, SkDisplayTypes type);
+
+       /**     Add or replace a key frame, copying the values[] data into the interpolator.
+               @param index    The index of this frame (frames must be ordered by time)
+               @param time     The millisecond time for this frame
+               @param values   The array of values [elemCount] for this frame. The data is copied
+                                               into the interpolator.
+               @param blend    A positive scalar specifying how to blend between this and the next key frame.
+                                               [0...1) is a cubic lag/log/lag blend (slow to change at the beginning and end)
+                                               1 is a linear blend (default)
+                                               (1...inf) is a cubic log/lag/log blend (fast to change at the beginning and end)
+       */
+       bool    setKeyFrame(int index, SkMSec time, const SkOperand values[], SkScalar blend = SK_Scalar1);
+       Result timeToValues(SkMSec time, SkOperand values[]) const;
+       SkDEBUGCODE(static void UnitTest();)
+private:
+       SkDisplayTypes fType;
+       SkOperand* fValues;     // pointer into fStorage
+#ifdef SK_DEBUG
+       SkOperand(* fValuesArray)[10];
+#endif
+       typedef SkInterpolatorBase INHERITED;
+};
+
+#endif // SkOperandInterpolator_DEFINED
+
diff --git a/libs/graphics/animator/SkOperandIterpolator.cpp b/libs/graphics/animator/SkOperandIterpolator.cpp
new file mode 100644 (file)
index 0000000..8d9f449
--- /dev/null
@@ -0,0 +1,139 @@
+#include "SkOperandInterpolator.h"
+#include "SkScript.h"
+
+SkOperandInterpolator::SkOperandInterpolator() {
+       INHERITED::reset(0, 0);
+       fType = SkType_Unknown;
+}
+
+SkOperandInterpolator::SkOperandInterpolator(int elemCount, int frameCount, 
+                                                                                        SkDisplayTypes type)
+{
+       this->reset(elemCount, frameCount, type);
+}
+
+void SkOperandInterpolator::reset(int elemCount, int frameCount, SkDisplayTypes type)
+{
+//     SkASSERT(type == SkType_String || type == SkType_Float || type == SkType_Int ||
+//             type == SkType_Displayable || type == SkType_Drawable);
+       INHERITED::reset(elemCount, frameCount);
+       fType = type;
+       fStorage = sk_malloc_throw((sizeof(SkOperand) * elemCount + sizeof(SkTimeCode)) * frameCount);
+       fTimes = (SkTimeCode*) fStorage;
+       fValues = (SkOperand*) ((char*) fStorage + sizeof(SkTimeCode) * frameCount);
+#ifdef SK_DEBUG
+       fTimesArray = (SkTimeCode(*)[10]) fTimes;
+       fValuesArray = (SkOperand(*)[10]) fValues;
+#endif
+}
+
+bool SkOperandInterpolator::setKeyFrame(int index, SkMSec time, const SkOperand values[], SkScalar blend)
+{
+       SkASSERT(values != nil);
+       blend = SkScalarPin(blend, 0, SK_Scalar1);
+
+       bool success = ~index == SkTSearch<SkMSec>(&fTimes->fTime, index, time, sizeof(SkTimeCode));
+       SkASSERT(success);
+       if (success) {
+               SkTimeCode* timeCode = &fTimes[index];
+               timeCode->fTime = time;
+               timeCode->fBlend = blend;
+               SkOperand* dst = &fValues[fElemCount * index];
+               memcpy(dst, values, fElemCount * sizeof(SkOperand));
+       }
+       return success;
+}
+
+SkInterpolatorBase::Result SkOperandInterpolator::timeToValues(SkMSec time, SkOperand values[]) const
+{
+       SkScalar T;
+       int index;
+       SkBool exact;
+       Result result = timeToT(time, &T, &index, &exact);
+       if (values)
+       {
+               const SkOperand* nextSrc = &fValues[index * fElemCount];
+
+               if (exact)
+                       memcpy(values, nextSrc, fElemCount * sizeof(SkScalar));
+               else
+               {
+                       SkASSERT(index > 0);
+
+                       const SkOperand* prevSrc = nextSrc - fElemCount;
+
+                       if (fType == SkType_Float || fType == SkType_3D_Point) {
+                               for (int i = fElemCount - 1; i >= 0; --i)
+                                       values[i].fScalar = SkScalarInterp(prevSrc[i].fScalar, nextSrc[i].fScalar, T);
+                       } else if (fType == SkType_Int || fType == SkType_MSec) {
+                               for (int i = fElemCount - 1; i >= 0; --i) {
+                                       S32 a = prevSrc[i].fS32;
+                                       S32 b = nextSrc[i].fS32;
+                                       values[i].fS32 = a + SkScalarRound((b - a) * T);
+                               }
+                       } else
+                               memcpy(values, prevSrc, sizeof(SkOperand) * fElemCount);
+               }
+       }
+       return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+#ifdef SK_SUPPORT_UNITTEST
+       static SkOperand* iset(SkOperand array[3], int a, int b, int c)
+       {
+               array[0].fScalar = SkIntToScalar(a);
+               array[1].fScalar = SkIntToScalar(b);
+               array[2].fScalar = SkIntToScalar(c);
+               return array;
+       }
+#endif
+
+void SkOperandInterpolator::UnitTest()
+{
+#ifdef SK_SUPPORT_UNITTEST
+       SkOperandInterpolator   inter(3, 2, SkType_Float);
+       SkOperand               v1[3], v2[3], v[3], vv[3];
+       Result                  result;
+
+       inter.setKeyFrame(0, 100, iset(v1, 10, 20, 30), 0);
+       inter.setKeyFrame(1, 200, iset(v2, 110, 220, 330));
+
+       result = inter.timeToValues(0, v);
+       SkASSERT(result == kFreezeStart_Result);
+       SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
+
+       result = inter.timeToValues(99, v);
+       SkASSERT(result == kFreezeStart_Result);
+       SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
+
+       result = inter.timeToValues(100, v);
+       SkASSERT(result == kNormal_Result);
+       SkASSERT(memcmp(v, v1, sizeof(v)) == 0);
+
+       result = inter.timeToValues(200, v);
+       SkASSERT(result == kNormal_Result);
+       SkASSERT(memcmp(v, v2, sizeof(v)) == 0);
+
+       result = inter.timeToValues(201, v);
+       SkASSERT(result == kFreezeEnd_Result);
+       SkASSERT(memcmp(v, v2, sizeof(v)) == 0);
+
+       result = inter.timeToValues(150, v);
+       SkASSERT(result == kNormal_Result);
+       SkASSERT(memcmp(v, iset(vv, 60, 120, 180), sizeof(v)) == 0);
+
+       result = inter.timeToValues(125, v);
+       SkASSERT(result == kNormal_Result);
+       result = inter.timeToValues(175, v);
+       SkASSERT(result == kNormal_Result);
+#endif
+}
+
+#endif
+
+
diff --git a/libs/graphics/animator/SkPaintParts.cpp b/libs/graphics/animator/SkPaintParts.cpp
new file mode 100644 (file)
index 0000000..b45a125
--- /dev/null
@@ -0,0 +1,94 @@
+#include "SkPaintParts.h"
+#include "SkDrawPaint.h"
+#ifdef SK_DUMP_ENABLED
+#include "SkDisplayList.h"
+#include "SkDump.h"
+#endif
+
+SkPaintPart::SkPaintPart() : fPaint(nil) {
+}
+
+SkDisplayable* SkPaintPart::getParent() const {
+       return fPaint;
+}
+
+bool SkPaintPart::setParent(SkDisplayable* parent) {
+       SkASSERT(parent != nil);
+       if (parent->isPaint() == false)
+               return true;
+       fPaint = (SkDrawPaint*) parent;
+       return false;
+}
+
+
+// SkDrawMaskFilter
+bool SkDrawMaskFilter::add() {
+       if (fPaint->maskFilter != (SkDrawMaskFilter*) -1)
+               return true;
+       fPaint->maskFilter = this;
+       fPaint->fOwnsMaskFilter = true;
+       return false;
+}
+
+SkMaskFilter* SkDrawMaskFilter::getMaskFilter() {
+       return nil;
+}
+
+
+// SkDrawPathEffect
+bool SkDrawPathEffect::add() {
+       if (fPaint->isPaint()) {
+               if (fPaint->pathEffect != (SkDrawPathEffect*) -1)
+                       return true;
+               fPaint->pathEffect = this;
+               fPaint->fOwnsPathEffect = true;
+               return false;
+       }
+       fPaint->add(*(SkAnimateMaker*) nil, this);
+       return false;
+}
+
+SkPathEffect* SkDrawPathEffect::getPathEffect() {
+       return nil;
+}
+
+
+// SkDrawShader
+SkShader* SkDrawShader::getShader() {
+       return nil;
+}
+
+
+// Typeface
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkDrawTypeface::fInfo[] = {
+       SK_MEMBER(fontName, String),
+    SK_MEMBER(style, FontStyle)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkDrawTypeface);
+
+SkDrawTypeface::SkDrawTypeface() : style (SkTypeface::kNormal){
+}
+
+bool SkDrawTypeface::add() {
+       if (fPaint->typeface != (SkDrawTypeface*) -1)
+               return true;
+       fPaint->typeface = this;
+       fPaint->fOwnsTypeface = true;
+       return false;
+}
+
+#ifdef SK_DUMP_ENABLED
+void SkDrawTypeface::dump(SkAnimateMaker* maker) {
+    SkDebugf("%*s<typeface fontName=\"%s\" ", SkDisplayList::fIndent, "", fontName.c_str());
+    SkString string;
+    SkDump::GetEnumString(SkType_FontStyle, style, &string);
+    SkDebugf("style=\"%s\" />\n", string.c_str());
+}
+#endif
+
+
diff --git a/libs/graphics/animator/SkPaintParts.h b/libs/graphics/animator/SkPaintParts.h
new file mode 100644 (file)
index 0000000..c0f84da
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef SkPaintParts_DEFINED
+#define SkPaintParts_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkMemberInfo.h"
+#include "SkPaint.h"
+#include "SkShader.h"
+#include "SkTypeface.h"
+#include "SkXfermode.h"
+
+class SkDrawPaint;
+class SkDrawMatrix;
+
+class SkPaintPart : public SkDisplayable {
+public:
+       SkPaintPart();
+       virtual bool add() = 0;
+       virtual SkDisplayable* getParent() const;
+       virtual bool setParent(SkDisplayable* parent);
+#ifdef SK_DEBUG
+       virtual bool isPaintPart() const { return true; }
+#endif
+protected:
+       SkDrawPaint* fPaint;
+};
+
+class SkDrawMaskFilter : public SkPaintPart {
+       DECLARE_EMPTY_MEMBER_INFO(MaskFilter);
+       virtual SkMaskFilter* getMaskFilter();
+protected:
+       virtual bool add();
+};
+
+class SkDrawPathEffect : public SkPaintPart {
+       DECLARE_EMPTY_MEMBER_INFO(PathEffect);
+       virtual SkPathEffect* getPathEffect();
+protected:
+       virtual bool add();
+};
+
+class SkDrawShader : public SkPaintPart {
+       DECLARE_DRAW_MEMBER_INFO(Shader);
+       SkDrawShader();
+       virtual SkShader* getShader();
+protected:
+       virtual bool add();
+       void addPostlude(SkShader* shader);
+       SkDrawMatrix* matrix;
+       int /*SkShader::TileMode*/ tileMode;
+};
+
+class SkDrawTypeface  : public SkPaintPart {
+       DECLARE_DRAW_MEMBER_INFO(Typeface);
+       SkDrawTypeface();
+#ifdef SK_DUMP_ENABLED
+    virtual void dump(SkAnimateMaker *);
+#endif
+       SkTypeface* getTypeface() {
+               return SkTypeface::Create(fontName.c_str(), style); }
+protected:
+       virtual bool add();
+       SkString fontName;
+    SkTypeface::Style style;
+};
+
+#endif // SkPaintParts_DEFINED
diff --git a/libs/graphics/animator/SkPathParts.cpp b/libs/graphics/animator/SkPathParts.cpp
new file mode 100644 (file)
index 0000000..537a32d
--- /dev/null
@@ -0,0 +1,311 @@
+#include "SkPathParts.h"
+#include "SkAnimateMaker.h"
+#include "SkDrawMatrix.h"
+#include "SkDrawRectangle.h"
+#include "SkDrawPath.h"
+
+SkPathPart::SkPathPart() : fPath(nil) {
+}
+
+void SkPathPart::dirty() { 
+       fPath->dirty(); 
+}
+
+SkDisplayable* SkPathPart::getParent() const {
+       return fPath;
+}
+
+bool SkPathPart::setParent(SkDisplayable* parent) {
+       SkASSERT(parent != nil);
+       if (parent->isPath() == false)
+               return true;
+       fPath = (SkDrawPath*) parent;
+       return false;
+}
+
+// MoveTo
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkMoveTo::fInfo[] = {
+       SK_MEMBER(x, Float),
+       SK_MEMBER(y, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkMoveTo);
+
+SkMoveTo::SkMoveTo() : x(0), y(0) {
+}
+
+bool SkMoveTo::add() {
+       fPath->fPath.moveTo(x, y);
+       return false;
+}
+
+
+// RMoveTo
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkRMoveTo::fInfo[] = {
+       SK_MEMBER_INHERITED
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkRMoveTo);
+
+bool SkRMoveTo::add() {
+       fPath->fPath.rMoveTo(x, y);
+       return false;
+}
+
+
+// LineTo
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkLineTo::fInfo[] = {
+       SK_MEMBER(x, Float),
+       SK_MEMBER(y, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkLineTo);
+
+SkLineTo::SkLineTo() : x(0), y(0) {
+}
+
+bool SkLineTo::add() {
+       fPath->fPath.lineTo(x, y);      
+       return false;
+}
+
+
+// RLineTo
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkRLineTo::fInfo[] = {
+       SK_MEMBER_INHERITED
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkRLineTo);
+
+bool SkRLineTo::add() {
+       fPath->fPath.rLineTo(x, y);     
+       return false;
+}
+
+
+// QuadTo
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkQuadTo::fInfo[] = {
+       SK_MEMBER(x1, Float),
+       SK_MEMBER(x2, Float),
+       SK_MEMBER(y1, Float),
+       SK_MEMBER(y2, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkQuadTo);
+
+SkQuadTo::SkQuadTo() : x1(0), y1(0), x2(0), y2(0) {
+}
+
+bool SkQuadTo::add() {
+       fPath->fPath.quadTo(x1, y1, x2, y2);
+       return false;
+}
+
+
+// RQuadTo
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkRQuadTo::fInfo[] = {
+       SK_MEMBER_INHERITED
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkRQuadTo);
+
+bool SkRQuadTo::add() {
+       fPath->fPath.rQuadTo(x1, y1, x2, y2);
+       return false;
+}
+
+
+// CubicTo
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkCubicTo::fInfo[] = {
+       SK_MEMBER(x1, Float),
+       SK_MEMBER(x2, Float),
+       SK_MEMBER(x3, Float),
+       SK_MEMBER(y1, Float),
+       SK_MEMBER(y2, Float),
+       SK_MEMBER(y3, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkCubicTo);
+
+SkCubicTo::SkCubicTo() : x1(0), y1(0), x2(0), y2(0), x3(0), y3(0) {
+}
+
+bool SkCubicTo::add() {
+       fPath->fPath.cubicTo(x1, y1, x2, y2, x3, y3);
+       return false;
+}
+
+
+// RCubicTo
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkRCubicTo::fInfo[] = {
+       SK_MEMBER_INHERITED
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkRCubicTo);
+
+bool SkRCubicTo::add() {
+       fPath->fPath.rCubicTo(x1, y1, x2, y2, x3, y3);
+       return false;
+}
+
+
+// SkClose
+bool SkClose::add() {
+       fPath->fPath.close();
+       return false;
+}
+
+
+// SkAddGeom
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkAddGeom::fInfo[] = {
+       SK_MEMBER(direction, PathDirection)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkAddGeom);
+
+SkAddGeom::SkAddGeom() : direction(SkPath::kCCW_Direction) {
+}
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkAddRect::fInfo[] = {
+       SK_MEMBER_INHERITED,
+       SK_MEMBER_ALIAS(bottom, fRect.fBottom, Float),
+       SK_MEMBER_ALIAS(left, fRect.fLeft, Float),
+       SK_MEMBER_ALIAS(right, fRect.fRight, Float),
+       SK_MEMBER_ALIAS(top, fRect.fTop, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkAddRect);
+
+SkAddRect::SkAddRect() { 
+       fRect.setEmpty(); 
+}
+
+bool SkAddRect::add() {
+       fPath->fPath.addRect(fRect, (SkPath::Direction) direction);
+       return false;
+}
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkAddOval::fInfo[] = {
+       SK_MEMBER_INHERITED
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkAddOval);
+
+bool SkAddOval::add() {
+       fPath->fPath.addOval(fRect,  (SkPath::Direction) direction);
+       return false;
+}
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkAddCircle::fInfo[] = {
+       SK_MEMBER_INHERITED,
+       SK_MEMBER(radius, Float),
+       SK_MEMBER(x, Float),
+       SK_MEMBER(y, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkAddCircle);
+
+SkAddCircle::SkAddCircle() : radius(0), x(0), y(0) {
+}
+
+bool SkAddCircle::add() {
+       fPath->fPath.addCircle(x, y, radius,  (SkPath::Direction) direction);
+       return false;
+}
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkAddRoundRect::fInfo[] = {
+       SK_MEMBER_INHERITED,
+       SK_MEMBER(rx, Float),
+       SK_MEMBER(ry, Float)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkAddRoundRect);
+
+SkAddRoundRect::SkAddRoundRect() : rx(0), ry(0) {
+}
+
+bool SkAddRoundRect::add() {
+       fPath->fPath.addRoundRect(fRect, rx, ry,  (SkPath::Direction) direction);
+       return false;
+}
+
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkAddPath::fInfo[] = {
+       SK_MEMBER(matrix, Matrix),
+       SK_MEMBER(path, Path)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkAddPath);
+
+SkAddPath::SkAddPath() : matrix(nil), path(nil) {
+}
+
+bool SkAddPath::add() {
+       SkASSERT (path != nil); 
+       if (matrix)
+               fPath->fPath.addPath(path->fPath, matrix->getMatrix());
+       else
+               fPath->fPath.addPath(path->fPath);
+       return false;
+}
+
+
diff --git a/libs/graphics/animator/SkPathParts.h b/libs/graphics/animator/SkPathParts.h
new file mode 100644 (file)
index 0000000..ed78c92
--- /dev/null
@@ -0,0 +1,156 @@
+#ifndef SkPathParts_DEFINED
+#define SkPathParts_DEFINED
+
+#include "SkDisplayable.h"
+#include "SkMemberInfo.h"
+#include "SkPath.h"
+
+class SkDrawPath;
+class SkDrawMatrix;
+
+class SkPathPart : public SkDisplayable {
+public:
+       SkPathPart();
+       virtual bool add() = 0;
+       virtual void dirty();
+       virtual SkDisplayable* getParent() const;
+       virtual bool setParent(SkDisplayable* parent);
+#ifdef SK_DEBUG
+       virtual bool isPathPart() const { return true; }
+#endif
+protected:
+       SkDrawPath* fPath;
+};
+
+class SkMoveTo : public SkPathPart {
+       DECLARE_MEMBER_INFO(MoveTo);
+       SkMoveTo();
+       virtual bool add();
+protected:
+       SkScalar x;
+       SkScalar y;
+};
+
+class SkRMoveTo : public SkMoveTo {
+       DECLARE_MEMBER_INFO(RMoveTo);
+       virtual bool add();
+private:
+       typedef SkMoveTo INHERITED;
+};
+
+class SkLineTo : public SkPathPart {
+       DECLARE_MEMBER_INFO(LineTo);
+       SkLineTo();
+       virtual bool add();
+protected:
+       SkScalar x;
+       SkScalar y;
+};
+
+class SkRLineTo : public SkLineTo {
+       DECLARE_MEMBER_INFO(RLineTo);
+       virtual bool add();
+private:
+       typedef SkLineTo INHERITED;
+};
+
+class SkQuadTo : public SkPathPart {
+       DECLARE_MEMBER_INFO(QuadTo);
+       SkQuadTo();
+       virtual bool add();
+protected:
+       SkScalar x1;
+       SkScalar y1;
+       SkScalar x2;
+       SkScalar y2;
+};
+
+class SkRQuadTo : public SkQuadTo {
+       DECLARE_MEMBER_INFO(RQuadTo);
+       virtual bool add();
+private:
+       typedef SkQuadTo INHERITED;
+};
+
+class SkCubicTo : public SkPathPart {
+       DECLARE_MEMBER_INFO(CubicTo);
+       SkCubicTo();
+       virtual bool add();
+protected:
+       SkScalar x1;
+       SkScalar y1;
+       SkScalar x2;
+       SkScalar y2;
+       SkScalar x3;
+       SkScalar y3;
+};
+
+class SkRCubicTo : public SkCubicTo {
+       DECLARE_MEMBER_INFO(RCubicTo);
+       virtual bool add();
+private:
+       typedef SkCubicTo INHERITED;
+};
+
+class SkClose : public SkPathPart {
+       DECLARE_EMPTY_MEMBER_INFO(Close);
+       virtual bool add();
+};
+
+class SkAddGeom : public SkPathPart {
+       DECLARE_PRIVATE_MEMBER_INFO(AddGeom);
+       SkAddGeom();
+protected:
+       int /*SkPath::Direction*/ direction;
+};
+
+class SkAddRect : public SkAddGeom {
+       DECLARE_MEMBER_INFO(AddRect);
+       SkAddRect();
+       virtual bool add();
+protected:
+       SkRect fRect;
+private:
+       typedef SkAddGeom INHERITED;
+};
+
+class SkAddOval : public SkAddRect {
+       DECLARE_MEMBER_INFO(AddOval);
+       virtual bool add();
+private:
+       typedef SkAddRect INHERITED;
+};
+
+class SkAddCircle : public SkAddGeom {
+       DECLARE_MEMBER_INFO(AddCircle);
+       SkAddCircle();
+       virtual bool add();
+private:
+       SkScalar radius;
+       SkScalar x;
+       SkScalar y;
+       typedef SkAddGeom INHERITED;
+};
+
+class SkAddRoundRect : public SkAddRect {
+       DECLARE_MEMBER_INFO(AddRoundRect);
+       SkAddRoundRect();
+       virtual bool add();
+private:
+       SkScalar rx;
+       SkScalar ry;
+       typedef SkAddRect INHERITED;
+};
+
+class SkAddPath : public SkPathPart {
+       DECLARE_MEMBER_INFO(AddPath);
+       SkAddPath();
+       virtual bool add();
+private:
+       typedef SkPathPart INHERITED;
+       SkDrawMatrix* matrix;
+       SkDrawPath* path;
+};
+
+#endif // SkPathParts_DEFINED
+
diff --git a/libs/graphics/animator/SkPostParts.cpp b/libs/graphics/animator/SkPostParts.cpp
new file mode 100644 (file)
index 0000000..3782e47
--- /dev/null
@@ -0,0 +1,48 @@
+#include "SkPostParts.h"
+#include "SkDisplayPost.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkData::fInfo[] = {
+       SK_MEMBER_INHERITED
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkData);
+
+SkData::SkData() : fParent(nil) {}
+
+bool SkData::add() {
+       SkASSERT(name.size() > 0);
+       const char* dataName = name.c_str();
+       if (fInt != (int) SK_NaN32)
+               fParent->fEvent.setS32(dataName, fInt);
+       else if (SkScalarIsNaN(fFloat) == false)
+               fParent->fEvent.setScalar(dataName, fFloat);
+       else if (string.size() > 0) 
+               fParent->fEvent.setString(dataName, string);
+//     else
+//             SkASSERT(0);
+       return false;
+}
+
+void SkData::dirty() {
+       fParent->dirty();
+}
+
+SkDisplayable* SkData::getParent() const {
+       return fParent;
+}
+
+bool SkData::setParent(SkDisplayable* displayable) {
+       if (displayable->isPost() == false)
+               return true;
+       fParent = (SkPost*) displayable;
+       return false;
+}
+
+void SkData::onEndElement(SkAnimateMaker&) {
+       add();
+}
+
diff --git a/libs/graphics/animator/SkPostParts.h b/libs/graphics/animator/SkPostParts.h
new file mode 100644 (file)
index 0000000..4aca6c0
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef SkPostParts_DEFINED
+#define SkPostParts_DEFINED
+
+#include "SkDisplayInput.h"
+
+class SkPost;
+
+class SkData: public SkInput {
+       DECLARE_MEMBER_INFO(Data);
+       SkData();
+       bool add();
+       virtual void dirty();
+       virtual SkDisplayable* getParent() const;
+       virtual void onEndElement(SkAnimateMaker& );
+       virtual bool setParent(SkDisplayable* );
+protected:
+       SkPost* fParent;
+       typedef SkInput INHERITED;
+       friend class SkPost;
+};
+
+#endif // SkPostParts_DEFINED
diff --git a/libs/graphics/animator/SkSVGPath.cpp b/libs/graphics/animator/SkSVGPath.cpp
new file mode 100644 (file)
index 0000000..e3c4083
--- /dev/null
@@ -0,0 +1,226 @@
+#include <ctype.h>
+#include "SkDrawPath.h"
+#include "SkParse.h"
+#include "SkPoint.h"
+#include "SkUtils.h"
+#define QUADRATIC_APPROXIMATION 1
+
+#if QUADRATIC_APPROXIMATION
+////////////////////////////////////////////////////////////////////////////////////
+//functions to approximate a cubic using two quadratics
+
+//             midPt sets the first argument to be the midpoint of the other two
+//             it is used by quadApprox
+static inline void midPt(SkPoint& dest,const SkPoint& a,const SkPoint& b)
+{
+       dest.set(SkScalarAve(a.fX, b.fX),SkScalarAve(a.fY, b.fY));
+}
+//             quadApprox - makes an approximation, which we hope is faster
+static void quadApprox(SkPath &fPath, const SkPoint &p0, const SkPoint &p1, const SkPoint &p2)
+{
+       //divide the cubic up into two cubics, then convert them into quadratics
+       //define our points
+       SkPoint c,j,k,l,m,n,o,p,q, mid;
+       fPath.getLastPt(&c);
+       midPt(j, p0, c);
+       midPt(k, p0, p1);
+       midPt(l, p1, p2);
+       midPt(o, j, k);
+       midPt(p, k, l);
+       midPt(q, o, p);
+       //compute the first half
+       m.set(SkScalarHalf(3*j.fX - c.fX), SkScalarHalf(3*j.fY - c.fY));
+       n.set(SkScalarHalf(3*o.fX -q.fX), SkScalarHalf(3*o.fY - q.fY));
+       midPt(mid,m,n);
+       fPath.quadTo(mid,q);
+       c = q;
+       //compute the second half
+       m.set(SkScalarHalf(3*p.fX - c.fX), SkScalarHalf(3*p.fY - c.fY));
+       n.set(SkScalarHalf(3*l.fX -p2.fX),SkScalarHalf(3*l.fY -p2.fY));
+       midPt(mid,m,n);
+       fPath.quadTo(mid,p2);
+}
+#endif
+
+
+static inline bool is_between(int c, int min, int max)
+{
+       return (unsigned)(c - min) <= (unsigned)(max - min);
+}
+
+static inline bool is_ws(int c)
+{
+       return is_between(c, 1, 32);
+}
+
+static inline bool is_digit(int c)
+{
+       return is_between(c, '0', '9');
+}
+
+static inline bool is_sep(int c)
+{
+       return is_ws(c) || c == ',';
+}
+
+static const char* skip_ws(const char str[])
+{
+       SkASSERT(str);
+       while (is_ws(*str))
+               str++;
+       return str;
+}
+
+static const char* skip_sep(const char str[])
+{
+       SkASSERT(str);
+       while (is_sep(*str))
+               str++;
+       return str;
+}
+
+static const char* find_points(const char str[], SkPoint value[], int count,
+        bool isRelative, SkPoint* relative)
+{
+       str = SkParse::FindScalars(str, &value[0].fX, count * 2);
+       if (isRelative) {
+               for (int index = 0; index < count; index++) {
+                       value[index].fX += relative->fX;
+                       value[index].fY += relative->fY;
+               }
+       }
+       return str;
+}
+
+static const char* find_scalar(const char str[], SkScalar* value, 
+       bool isRelative, SkScalar relative)
+{
+       str = SkParse::FindScalar(str, value);
+       if (isRelative)
+               *value += relative;
+       return str;
+}
+
+void SkDrawPath::parseSVG() {
+    fPath.reset();
+       const char* data = d.c_str();
+       SkPoint f = {0, 0};
+       SkPoint c = {0, 0};
+       SkPoint lastc = {0, 0};
+       SkPoint points[3];
+       char op = '\0';
+       char previousOp = '\0';
+       bool relative = false;
+       do {
+               data = skip_ws(data);
+               if (data[0] == '\0')
+                       break;
+               char ch = data[0];
+               if (is_digit(ch) || ch == '-' || ch == '+') {
+                       if (op == '\0')
+                               return;
+               }
+               else {
+                       op = ch;
+                       relative = false;
+                       if (islower(op)) {
+                               op = (char) toupper(op);
+                               relative = true;
+                       }
+                       data++;
+                       data = skip_sep(data);
+               }
+               switch (op) {
+                       case 'M':
+                               data = find_points(data, points, 1, relative, &c);
+                               fPath.moveTo(points[0]);
+                               op = 'L';
+                               c = points[0];
+                               break;
+                       case 'L': 
+                               data = find_points(data, points, 1, relative, &c);
+                               fPath.lineTo(points[0]);
+                               c = points[0];
+                               break;
+                       case 'H': {
+                               SkScalar x;
+                               data = find_scalar(data, &x, relative, c.fX);
+                               fPath.lineTo(x, c.fY);
+                               c.fX = x;
+                       }
+                               break;
+                       case 'V': {
+                               SkScalar y;
+                               data = find_scalar(data, &y, relative, c.fY);
+                               fPath.lineTo(c.fX, y);
+                               c.fY = y;
+                       }
+                               break;
+                       case 'C': 
+                               data = find_points(data, points, 3, relative, &c);
+                               goto cubicCommon;
+                       case 'S': 
+                               data = find_points(data, &points[1], 2, relative, &c);
+                               points[0] = c;
+                               if (previousOp == 'C' || previousOp == 'S') {
+                                       points[0].fX -= lastc.fX - c.fX;
+                                       points[0].fY -= lastc.fY - c.fY;
+                               }
+                       cubicCommon:
+       //                      if (data[0] == '\0')
+       //                              return;
+#if QUADRATIC_APPROXIMATION
+                                       quadApprox(fPath, points[0], points[1], points[2]);
+#else  //this way just does a boring, slow old cubic
+                                       fPath.cubicTo(points[0], points[1], points[2]);
+#endif
+               //if we are using the quadApprox, lastc is what it would have been if we had used
+               //cubicTo
+                                       lastc = points[1];
+                                       c = points[2];
+                               break;
+                       case 'Q':  // Quadratic Bezier Curve
+                               data = find_points(data, points, 2, relative, &c);
+                               goto quadraticCommon;
+                       case 'T':
+                               data = find_points(data, &points[1], 1, relative, &c);
+                               points[0] = points[1];
+                               if (previousOp == 'Q' || previousOp == 'T') {
+                                       points[0].fX = c.fX * 2 - lastc.fX;
+                                       points[0].fY = c.fY * 2 - lastc.fY;
+                               }
+                       quadraticCommon:
+                               fPath.quadTo(points[0], points[1]);
+                               lastc = points[0];
+                               c = points[1];
+                               break;
+                       case 'Z':
+                               fPath.close();
+#if 0  // !!! still a bug?
+                               if (fPath.isEmpty() && (f.fX != 0 || f.fY != 0)) {
+                                       c.fX -= SkScalar.Epsilon;       // !!! enough?
+                                       fPath.moveTo(c);
+                                       fPath.lineTo(f);
+                                       fPath.close();
+                               }
+#endif
+                               c = f;
+                               op = '\0';
+                               break;
+                       case '~': {
+                               SkPoint args[2];
+                               data = find_points(data, args, 2, false, nil);
+                               fPath.moveTo(args[0].fX, args[0].fY);
+                               fPath.lineTo(args[1].fX, args[1].fY);
+                       }
+                               break;
+                       default:
+                               SkASSERT(0);
+                               return;
+               }
+               if (previousOp == 0)
+                       f = c;
+               previousOp = op;
+       } while (data[0] > 0);
+}
+
diff --git a/libs/graphics/animator/SkScript.cpp b/libs/graphics/animator/SkScript.cpp
new file mode 100644 (file)
index 0000000..136e1fd
--- /dev/null
@@ -0,0 +1,1901 @@
+#include "SkScript.h"
+#include "SkMath.h"
+#include "SkParse.h"
+#include "SkString.h"
+#include "SkTypedArray.h"
+
+/* things to do
+       ? re-enable support for struct literals (e.g., for initializing points or rects)
+               {x:1, y:2}
+       ? use standard XML / script notation like document.getElementById("canvas");  
+       finish support for typed arrays
+               ? allow indexing arrays by string
+                       this could map to the 'name' attribute of a given child of an array
+               ? allow multiple types in the array
+       remove SkDisplayType.h  // from SkOperand.h
+       merge type and operand arrays into scriptvalue array
+*/
+
+#ifdef SK_DEBUG
+static const char* errorStrings[] = {
+               "array index of out bounds", // kArrayIndexOutOfBounds
+               "could not find reference id", // kCouldNotFindReferencedID
+               "dot operator expects object", // kDotOperatorExpectsObject
+               "error in array index", // kErrorInArrrayIndex
+               "error in function parameters", // kErrorInFunctionParameters
+               "expected array", // kExpectedArray
+               "expected boolean expression", // kExpectedBooleanExpression
+               "expected field name", // kExpectedFieldName
+               "expected hex", // kExpectedHex
+               "expected int for condition operator", // kExpectedIntForConditionOperator
+               "expected number", // kExpectedNumber
+               "expected number for array index", // kExpectedNumberForArrayIndex
+               "expected operator", // kExpectedOperator
+               "expected token", // kExpectedToken
+               "expected token before dot operator", // kExpectedTokenBeforeDotOperator
+               "expected value", // kExpectedValue
+               "handle member failed", // kHandleMemberFailed
+               "handle member function failed", // kHandleMemberFunctionFailed
+               "handle unbox failed", // kHandleUnboxFailed
+               "index out of range", // kIndexOutOfRange
+               "mismatched array brace", // kMismatchedArrayBrace
+               "mismatched brackets", // kMismatchedBrackets
+               "no function handler found", // kNoFunctionHandlerFound
+               "premature end", // kPrematureEnd
+               "too many parameters", // kTooManyParameters
+               "type conversion failed", // kTypeConversionFailed
+               "unterminated string" // kUnterminatedString
+};
+#endif
+
+const SkScriptEngine::SkOperatorAttributes SkScriptEngine::gOpAttributes[] = {
+       { kNoType, kNoType, kNoBias }, //       kUnassigned,
+       { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsString },     // kAdd
+       // kAddInt = kAdd,
+       { kNoType, kNoType, kNoBias },  // kAddScalar,
+       { kNoType, kNoType, kNoBias },  // kAddString,
+       { kNoType, kNoType, kNoBias },  // kArrayOp,
+       { kInt, kInt, kNoBias }, // kBitAnd
+       { kNoType, kInt, kNoBias }, // kBitNot
+       { kInt, kInt, kNoBias }, // kBitOr
+       { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kDivide
+       // kDivideInt = kDivide
+       { kNoType, kNoType, kNoBias },  // kDivideScalar
+       { kNoType, kNoType, kNoBias },  // kElse
+       { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsNumber }, // kEqual
+       // kEqualInt = kEqual
+       { kNoType, kNoType, kNoBias },  // kEqualScalar
+       { kNoType, kNoType, kNoBias },  // kEqualString
+       { kInt, kNoType, kNoBias },     // kFlipOps
+       { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsNumber }, // kGreaterEqual
+       // kGreaterEqualInt = kGreaterEqual
+       { kNoType, kNoType, kNoBias },  // kGreaterEqualScalar
+       { kNoType, kNoType, kNoBias },  // kGreaterEqualString
+       { kNoType, kNoType, kNoBias },  // kIf
+       { kNoType, kInt, kNoBias }, // kLogicalAnd      (really, ToBool)
+       { kNoType, kInt, kNoBias }, // kLogicalNot
+       { kInt, kInt, kNoBias }, // kLogicalOr
+       { kNoType, SkOpType(kInt | kScalar), kNoBias }, // kMinus
+       // kMinusInt = kMinus
+       { kNoType, kNoType, kNoBias },  // kMinusScalar
+       { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kModulo
+       // kModuloInt = kModulo
+       { kNoType, kNoType, kNoBias },  // kModuloScalar
+       { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kMultiply
+       // kMultiplyInt = kMultiply
+       { kNoType, kNoType, kNoBias },  // kMultiplyScalar
+       { kNoType, kNoType, kNoBias },  // kParen
+       { kInt, kInt, kNoBias }, // kShiftLeft
+       { kInt, kInt, kNoBias }, // kShiftRight
+       { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kSubtract
+       // kSubtractInt = kSubtract
+       { kNoType, kNoType, kNoBias },  // kSubtractScalar
+       { kInt, kInt, kNoBias } // kXor
+};
+
+// Note that the real precedence for () [] is '2'
+// but here, precedence means 'while an equal or smaller precedence than the current operator
+// is on the stack, process it. This allows 3+5*2 to defer the add until after the multiply
+// is preformed, since the add precedence is not smaller than multiply.
+// But, (3*4 does not process the '(', since brackets are greater than all other precedences
+#define kBracketPrecedence 16
+#define kIfElsePrecedence 15
+
+const signed char SkScriptEngine::gPrecedence[] = {
+               -1, //  kUnassigned,
+               6, // kAdd,
+               // kAddInt = kAdd,
+               6, // kAddScalar,
+               6, // kAddString,       // string concat
+               kBracketPrecedence, // kArrayOp,
+               10, // kBitAnd,
+               4, // kBitNot,
+               12, // kBitOr,
+               5, // kDivide,
+               // kDivideInt = kDivide,
+               5, // kDivideScalar,
+               kIfElsePrecedence, // kElse,
+               9, // kEqual,
+               // kEqualInt = kEqual,
+               9, // kEqualScalar,
+               9, // kEqualString,
+               -1, // kFlipOps,
+               8, // kGreaterEqual,
+               // kGreaterEqualInt = kGreaterEqual,
+               8, // kGreaterEqualScalar,
+               8, // kGreaterEqualString,
+               kIfElsePrecedence, // kIf,
+               13, // kLogicalAnd,
+               4, // kLogicalNot,
+               14, // kLogicalOr,
+               4, // kMinus,
+               // kMinusInt = kMinus,
+               4, // kMinusScalar,
+               5, // kModulo,
+               // kModuloInt = kModulo,
+               5, // kModuloScalar,
+               5, // kMultiply,
+               // kMultiplyInt = kMultiply,
+               5, // kMultiplyScalar,
+               kBracketPrecedence, // kParen,
+               7, // kShiftLeft,
+               7, // kShiftRight,      // signed
+               6, // kSubtract,
+               // kSubtractInt = kSubtract,
+               6, // kSubtractScalar,
+               11, // kXor
+};
+
+static inline bool is_between(int c, int min, int max)
+{
+       return (unsigned)(c - min) <= (unsigned)(max - min);
+}
+
+static inline bool is_ws(int c)
+{
+       return is_between(c, 1, 32);
+}
+
+static int token_length(const char* start) {
+       char ch = start[0];
+       if (! is_between(ch, 'a' , 'z') &&  ! is_between(ch, 'A', 'Z') && ch != '_' && ch != '$')
+               return -1;
+       int length = 0;
+       do
+               ch = start[++length];
+       while (is_between(ch, 'a' , 'z') || is_between(ch, 'A', 'Z') || is_between(ch, '0', '9') ||
+               ch == '_' || ch == '$');
+       return length;
+}
+
+SkScriptEngine::SkScriptEngine(SkOpType returnType) :
+       fTokenLength(0), fReturnType(returnType), fError(kNoError)
+{
+       SkSuppress noInitialSuppress;
+       noInitialSuppress.fOperator = kUnassigned;
+       noInitialSuppress.fOpStackDepth = 0;
+       noInitialSuppress.fSuppress = false;
+       fSuppressStack.push(noInitialSuppress);
+       *fOpStack.push() = kParen;
+       fTrackArray.appendClear();
+       fTrackString.appendClear();
+}
+
+SkScriptEngine::~SkScriptEngine() {
+       for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++)
+               delete *stringPtr;
+       for (SkTypedArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++)
+               delete *arrayPtr;
+}
+
+int SkScriptEngine::arithmeticOp(char ch, char nextChar, bool lastPush) {
+       SkOp op = kUnassigned;
+       bool reverseOperands = false;
+       bool negateResult = false;
+       int advance = 1;
+       switch (ch) {
+               case '+':
+                       // !!! ignoring unary plus as implemented here has the side effect of
+                       // suppressing errors like +"hi"
+                       if (lastPush == false)  // unary plus, don't push an operator
+                               goto returnAdv;
+                       op = kAdd;
+                       break;
+               case '-':
+                       op = lastPush ? kSubtract : kMinus;
+                       break;
+               case '*':
+                       op = kMultiply;
+                       break;
+               case '/':
+                       op = kDivide;
+                       break;
+               case '>':
+                       if (nextChar == '>') {
+                               op = kShiftRight;
+                               goto twoChar;
+                       } 
+                       op = kGreaterEqual;
+                       if (nextChar == '=')
+                               goto twoChar;
+                       reverseOperands = negateResult = true;
+                       break;
+               case '<':
+                       if (nextChar == '<') {
+                               op = kShiftLeft;
+                               goto twoChar;
+                       }
+                       op = kGreaterEqual;
+                       reverseOperands = nextChar == '=';
+                       negateResult = ! reverseOperands;
+                       advance += reverseOperands;
+                       break;
+               case '=':
+                       if (nextChar == '=') {
+                               op = kEqual;
+                               goto twoChar;
+                       }
+                       break;
+               case '!':
+                       if (nextChar == '=') {
+                               op = kEqual;
+                               negateResult = true;
+twoChar:
+                               advance++;
+                               break;
+                       } 
+                       op = kLogicalNot;
+                       break;
+               case '?':
+                       op = kIf;
+                       break;
+               case ':':
+                       op = kElse;
+                       break;
+               case '^':
+                       op = kXor;
+                       break;
+               case '(':
+                       *fOpStack.push() = kParen;      // push even if eval is suppressed
+                       goto returnAdv;
+               case '&':
+                       SkASSERT(nextChar != '&');
+                       op = kBitAnd;
+                       break;
+               case '|':
+                       SkASSERT(nextChar != '|');
+                       op = kBitOr;
+                       break;
+               case '%':
+                       op = kModulo;
+                       break;
+               case '~':
+                       op = kBitNot;
+                       break;
+       }
+       if (op == kUnassigned)
+               return 0;
+       if (fSuppressStack.top().fSuppress == false) {
+               signed char precedence = gPrecedence[op];
+               do {
+                       int idx = 0;
+                       SkOp compare;
+                       do {
+                               compare = fOpStack.index(idx);
+                               if ((compare & kArtificialOp) == 0)
+                                       break;
+                               idx++;
+                       } while (true);
+                       signed char topPrecedence = gPrecedence[compare];
+                       SkASSERT(topPrecedence != -1);
+                       if (topPrecedence > precedence || topPrecedence == precedence && 
+                                       gOpAttributes[op].fLeftType == kNoType) {
+                               break;
+                       }
+                       if (processOp() == false)
+                               return 0;       // error
+               } while (true);
+               if (negateResult)
+                       *fOpStack.push() = (SkOp) (kLogicalNot | kArtificialOp);
+               fOpStack.push(op);
+               if (reverseOperands)
+                       *fOpStack.push() = (SkOp) (kFlipOps | kArtificialOp);
+       }
+returnAdv:
+       return advance;
+}
+
+void SkScriptEngine::boxCallBack(_boxCallBack func, void* userStorage) {
+       UserCallBack callBack;
+       callBack.fBoxCallBack = func;
+       commonCallBack(kBox, callBack, userStorage);
+}
+
+void SkScriptEngine::commonCallBack(CallBackType type, UserCallBack& callBack, void* userStorage) {
+       callBack.fCallBackType = type;
+       callBack.fUserStorage = userStorage;
+       *fUserCallBacks.prepend() = callBack;
+}
+
+bool SkScriptEngine::convertParams(SkTDArray<SkScriptValue>& params, 
+               const SkFunctionParamType* paramTypes, int paramCount) {
+       if (params.count() > paramCount) {
+               fError = kTooManyParameters;
+               return false;   // too many parameters passed
+       }
+       for (int index = 0; index < params.count(); index++) {
+               if (convertTo((SkDisplayTypes) paramTypes[index], &params[index]) == false)
+                       return false;
+       }
+       return true;
+}
+
+bool SkScriptEngine::convertTo(SkDisplayTypes toType, SkScriptValue* value ) {
+       SkDisplayTypes type = value->fType;
+       if (type == toType)
+               return true;
+       if (ToOpType(type) == kObject) {
+#if 0  // !!! I want object->string to get string from displaystringtype, not id
+               if (ToOpType(toType) == kString) {
+                       bool success = handleObjectToString(value->fOperand.fObject);
+                       if (success == false)
+                               return false;
+                       SkOpType type;
+                       fTypeStack.pop(&type);
+                       value->fType = ToDisplayType(type);
+                       fOperandStack.pop(&value->fOperand);
+                       return true;
+               }
+#endif
+               if (handleUnbox(value) == false) {
+                       fError = kHandleUnboxFailed;
+                       return false;
+               }
+               return convertTo(toType, value);
+       }
+       return ConvertTo(this, toType, value);
+}
+
+bool SkScriptEngine::evaluateDot(const char*& script, bool suppressed) { 
+       size_t fieldLength = token_length(++script);            // skip dot
+       if (fieldLength == 0) {
+               fError = kExpectedFieldName;
+               return false;
+       }
+       const char* field = script;
+       script += fieldLength;
+       bool success = handleProperty(suppressed);
+       if (success == false) {
+               fError = kCouldNotFindReferencedID;     // note: never generated by standard animator plugins
+               return false;
+       }
+       return evaluateDotParam(script, suppressed, field, fieldLength);
+}
+
+bool SkScriptEngine::evaluateDotParam(const char*& script, bool suppressed, 
+               const char* field, size_t fieldLength) { 
+       void* object;
+       if (suppressed)
+               object = nil;
+       else {
+               if (fTypeStack.top() != kObject) {
+                       fError = kDotOperatorExpectsObject;
+                       return false;
+               }
+               object = fOperandStack.top().fObject;
+               fTypeStack.pop();
+               fOperandStack.pop();
+       }
+       char ch; // see if it is a simple member or a function
+       while (is_ws(ch = script[0])) 
+               script++;
+       bool success = true;
+       if (ch != '(') {
+                       if (suppressed == false) {
+                               if ((success = handleMember(field, fieldLength, object)) == false)
+                                       fError = kHandleMemberFailed;
+                       }
+       } else {
+               SkTDArray<SkScriptValue> params;
+               *fBraceStack.push() = kFunctionBrace;
+               success = functionParams(&script, params);
+               if (success && suppressed == false &&
+                               (success = handleMemberFunction(field, fieldLength, object, params)) == false) 
+                       fError = kHandleMemberFunctionFailed;           
+       }
+       return success; 
+}
+
+bool SkScriptEngine::evaluateScript(const char** scriptPtr, SkScriptValue* value) {
+#ifdef SK_DEBUG
+       const char** original = scriptPtr;
+#endif
+       bool success;
+       const char* inner;
+       if (strncmp(*scriptPtr, "#script:", sizeof("#script:") - 1) == 0) {
+               *scriptPtr += sizeof("#script:") - 1;
+               if (fReturnType == kNoType || fReturnType == kString) {
+                       success = innerScript(scriptPtr, value);
+                       if (success == false)
+                               goto end;
+                       inner = value->fOperand.fString->c_str();
+                       scriptPtr = &inner;
+               }
+       }
+       {
+               success = innerScript(scriptPtr, value);
+               if (success == false)
+                       goto end;
+               const char* script = *scriptPtr;
+               char ch;
+               while (is_ws(ch = script[0]))
+                       script++;
+               if (ch != '\0') {
+                       // error may trigger on scripts like "50,0" that were intended to be written as "[50, 0]"
+                       fError = kPrematureEnd;
+                       success = false;
+               }
+       }
+end:
+#ifdef SK_DEBUG
+       if (success == false) {
+               SkDebugf("script failed: %s", *original);
+               if (fError)
+                       SkDebugf(" %s", errorStrings[fError - 1]);
+               SkDebugf("\n");
+       }
+#endif
+       return success;
+}
+
+void SkScriptEngine::forget(SkTypedArray* array) {
+       if (array->getType() == SkType_String) {
+               for (int index = 0; index < array->count(); index++) {
+                       SkString* string = (*array)[index].fString;
+                       int found = fTrackString.find(string);
+                       if (found >= 0)
+                               fTrackString.remove(found);
+               }
+               return;
+       }
+       if (array->getType() == SkType_Array) {
+               for (int index = 0; index < array->count(); index++) {
+                       SkTypedArray* child = (*array)[index].fArray;
+                       forget(child);  // forgets children of child
+                       int found = fTrackArray.find(child);
+                       if (found >= 0)
+                               fTrackArray.remove(found);
+               }
+       }
+}
+
+void SkScriptEngine::functionCallBack(_functionCallBack func, void* userStorage) {
+       UserCallBack callBack;
+       callBack.fFunctionCallBack = func;
+       commonCallBack(kFunction, callBack, userStorage);
+}
+
+bool SkScriptEngine::functionParams(const char** scriptPtr, SkTDArray<SkScriptValue>& params) {
+       (*scriptPtr)++; // skip open paren
+       *fOpStack.push() = kParen;
+       *fBraceStack.push() = kFunctionBrace;
+       SkBool suppressed = fSuppressStack.top().fSuppress;
+       do {
+               SkScriptValue value;
+               bool success = innerScript(scriptPtr, suppressed ? nil : &value);
+               if (success == false) {
+                       fError = kErrorInFunctionParameters;
+                       return false;
+               }
+               if (suppressed)
+                       continue;
+               *params.append() = value;
+       } while ((*scriptPtr)[-1] == ',');
+       fBraceStack.pop();
+       fOpStack.pop(); // pop paren
+       (*scriptPtr)++; // advance beyond close paren
+       return true;
+}
+
+#ifdef SK_DEBUG
+bool SkScriptEngine::getErrorString(SkString* str) const {
+       if (fError)
+               str->set(errorStrings[fError - 1]);
+       return fError != 0;
+}
+#endif
+
+bool SkScriptEngine::innerScript(const char** scriptPtr, SkScriptValue* value) {
+       const char* script = *scriptPtr;
+       char ch;
+       bool lastPush = false;
+       bool success = true;
+       int opBalance = fOpStack.count();
+       int baseBrace = fBraceStack.count();
+       int suppressBalance = fSuppressStack.count();
+       while ((ch = script[0]) != '\0') {
+               if (is_ws(ch)) {
+                       script++;
+                       continue;
+               }
+               SkBool suppressed = fSuppressStack.top().fSuppress;
+               SkOperand operand;
+               const char* dotCheck;
+               if (fBraceStack.count() > baseBrace) {
+#if 0  // disable support for struct brace
+                       if (ch == ':') {
+                               SkASSERT(fTokenLength > 0);
+                               SkASSERT(fBraceStack.top() == kStructBrace);
+                               ++script;
+                               SkASSERT(fDisplayable);
+                               SkString token(fToken, fTokenLength);
+                               fTokenLength = 0;
+                               const char* tokenName = token.c_str();
+                               const SkMemberInfo* tokenInfo SK_INIT_TO_AVOID_WARNING;
+                               if (suppressed == false) {
+                                       SkDisplayTypes type = fInfo->getType();
+                                       tokenInfo = SkDisplayType::GetMember(type, &tokenName);
+                                       SkASSERT(tokenInfo);
+                               }
+                               SkScriptValue tokenValue;
+                               success = innerScript(&script, &tokenValue);    // terminate and return on comma, close brace
+                               SkASSERT(success);
+                               if (suppressed == false) {
+                                       if (tokenValue.fType == SkType_Displayable) {
+                                               SkASSERT(SkDisplayType::IsDisplayable(tokenInfo->getType()));
+                                               fDisplayable->setReference(tokenInfo, tokenValue.fOperand.fDisplayable);
+                                       } else {
+                                               if (tokenValue.fType != tokenInfo->getType()) {
+                                                       if (convertTo(tokenInfo->getType(), &tokenValue) == false)
+                                                               return false;
+                                               }
+                                               tokenInfo->writeValue(fDisplayable, nil, 0, 0, 
+                                                       (void*) ((char*) fInfo->memberData(fDisplayable) + tokenInfo->fOffset + fArrayOffset),
+                                                       tokenInfo->getType(), tokenValue);
+                                       }
+                               }
+                               lastPush = false;
+                               continue;
+                       } else 
+#endif                         
+                       if (fBraceStack.top() == kArrayBrace) {
+                               SkScriptValue tokenValue;
+                               success = innerScript(&script, &tokenValue);    // terminate and return on comma, close brace
+                               if (success == false) {
+                                       fError = kErrorInArrrayIndex;
+                                       return false;
+                               }
+                               if (suppressed == false) {
+#if 0 // no support for structures for now
+                                       if (tokenValue.fType == SkType_Structure) {
+                                               fArrayOffset += (int) fInfo->getSize(fDisplayable);
+                                       } else 
+#endif
+                                       {
+                                               SkDisplayTypes type = ToDisplayType(fReturnType);
+                                               if (fReturnType == kNoType) {
+                                                       // !!! short sighted; in the future, allow each returned array component to carry 
+                                                       // its own type, and let caller do any needed conversions
+                                                       if (value->fOperand.fArray->count() == 0)
+                                                               value->fOperand.fArray->setType(type = tokenValue.fType);
+                                                       else
+                                                               type = value->fOperand.fArray->getType();
+                                               }
+                                               if (tokenValue.fType != type) {
+                                                       if (convertTo(type, &tokenValue) == false)
+                                                               return false;
+                                               }
+                                               *value->fOperand.fArray->append() = tokenValue.fOperand;
+                                       }
+                               }
+                               lastPush = false;
+                               continue;
+                       } else {
+                               if (token_length(script) == 0) {
+                                       fError = kExpectedToken;
+                                       return false;
+                               }
+                       }
+               }
+               if (lastPush != false && fTokenLength > 0) {
+                       if (ch == '(') {
+                               *fBraceStack.push() = kFunctionBrace;
+                               if (handleFunction(&script, SkToBool(suppressed)) == false)
+                                       return false;
+                               lastPush = true;
+                               continue;
+                       } else if (ch == '[') {
+                               if (handleProperty(SkToBool(suppressed)) == false)
+                                       return false;   // note: never triggered by standard animator plugins
+                               if (handleArrayIndexer(&script, SkToBool(suppressed)) == false)
+                                       return false;
+                               lastPush = true;
+                               continue;
+                       } else if (ch != '.') {
+                               if (handleProperty(SkToBool(suppressed)) == false)
+                                       return false;   // note: never triggered by standard animator plugins
+                               lastPush = true;
+                               continue;
+                       }
+               }
+               if (ch == '0' && (script[1] & ~0x20) == 'X') {
+                       if (lastPush != false) {
+                               fError = kExpectedOperator;
+                               return false;
+                       }
+                       script += 2;
+                       script = SkParse::FindHex(script, (uint32_t*)&operand.fS32);
+                       if (script == nil) {
+                               fError = kExpectedHex;
+                               return false;
+                       }
+                       goto intCommon;
+               }
+               if (lastPush == false && ch == '.')
+                       goto scalarCommon;
+               if (ch >= '0' && ch <= '9') {
+                       if (lastPush != false) {
+                               fError = kExpectedOperator;
+                               return false;
+                       }
+                       dotCheck = SkParse::FindS32(script, &operand.fS32);
+                       if (dotCheck[0] != '.') {
+                               script = dotCheck;
+intCommon:
+                               if (suppressed == false)
+                                       *fTypeStack.push() = kInt;
+                       } else {
+scalarCommon:
+                               script = SkParse::FindScalar(script, &operand.fScalar);
+                               if (suppressed == false)
+                                       *fTypeStack.push() = kScalar;
+                       }
+                       if (suppressed == false)
+                               fOperandStack.push(operand);
+                       lastPush = true;
+                       continue;
+               }
+               int length = token_length(script);
+               if (length > 0) {
+                       if (lastPush != false) {
+                               fError = kExpectedOperator;
+                               return false;
+                       }
+                       fToken = script;
+                       fTokenLength = length;
+                       script += length;
+                       lastPush = true;
+                       continue;
+               }
+               char startQuote = ch;
+               if (startQuote == '\'' || startQuote == '\"') {
+                       if (lastPush != false) {
+                               fError = kExpectedOperator;
+                               return false;
+                       }
+                       operand.fString = new SkString();
+                       track(operand.fString);
+                       ++script;
+
+                       // <mrr> this is a lot of calls to append() one char at at time
+                       // how hard to preflight script so we know how much to grow fString by?
+                       do {
+                               if (script[0] == '\\')
+                                       ++script;
+                               operand.fString->append(script, 1);
+                               ++script;
+                               if (script[0] == '\0') {
+                                       fError = kUnterminatedString;
+                                       return false;
+                               }
+                       } while (script[0] != startQuote);
+                       ++script;
+                       if (suppressed == false) {
+                               *fTypeStack.push() = kString;
+                               fOperandStack.push(operand);
+                       }
+                       lastPush = true;
+                       continue;
+               }
+               ;
+               if (ch ==  '.') {
+                       if (fTokenLength == 0) {
+                               SkScriptValue scriptValue;
+                               SkDEBUGCODE(scriptValue.fOperand.fObject = nil);
+                               int tokenLength = token_length(++script);
+                               const char* token = script;
+                               script += tokenLength;
+                               if (suppressed == false) {
+                                       if (fTypeStack.count() == 0) {
+                                               fError = kExpectedTokenBeforeDotOperator;
+                                               return false;
+                                       }
+                                       SkOpType topType;
+                                       fTypeStack.pop(&topType);
+                                       fOperandStack.pop(&scriptValue.fOperand);
+                                       scriptValue.fType = ToDisplayType(topType);
+                                       handleBox(&scriptValue);
+                               }
+                               success = evaluateDotParam(script, SkToBool(suppressed), token, tokenLength);
+                               if (success == false)
+                                       return false;
+                               lastPush = true;
+                               continue; 
+                       }
+                       // get next token, and evaluate immediately
+                       success = evaluateDot(script, SkToBool(suppressed));
+                       if (success == false)                           
+                               return false;
+                       lastPush = true;
+                       continue;
+               }
+               if (ch == '[') {
+                       if (lastPush == false) {
+                               script++;
+                               *fBraceStack.push() = kArrayBrace;
+                               if (suppressed)
+                                       continue;
+                               operand.fArray = value->fOperand.fArray = new SkTypedArray(ToDisplayType(fReturnType));
+                               track(value->fOperand.fArray);
+                               *fTypeStack.push() = (SkOpType) kArray;
+                               fOperandStack.push(operand);
+                               continue;
+                       }
+                       if (handleArrayIndexer(&script, SkToBool(suppressed)) == false)
+                               return false;
+                       lastPush = true;
+                       continue;
+               }
+#if 0 // structs not supported for now
+               if (ch == '{') {
+                       if (lastPush == false) {
+                               script++;
+                               *fBraceStack.push() = kStructBrace;
+                               if (suppressed)
+                                       continue;
+                               operand.fS32 = 0;
+                               *fTypeStack.push() = (SkOpType) kStruct;
+                               fOperandStack.push(operand);
+                               continue;
+                       }
+                       SkASSERT(0); // braces in other contexts aren't supported yet
+               }
+#endif
+               if (ch == ')' && fBraceStack.count() > 0) {
+                       SkBraceStyle braceStyle = fBraceStack.top(); 
+                       if (braceStyle == kFunctionBrace) {
+                               fBraceStack.pop();
+                               break;
+                       }
+               }
+               if (ch == ',' || ch == ']') {
+                       if (ch != ',') {
+                               SkBraceStyle match;
+                               fBraceStack.pop(&match);
+                               if (match != kArrayBrace) {
+                                       fError = kMismatchedArrayBrace;
+                                       return false;
+                               }
+                       }
+                       script++;
+                       // !!! see if brace or bracket is correct closer
+                       break;
+               }
+               char nextChar = script[1];
+               int advance = logicalOp(ch, nextChar);
+               if (advance < 0)         // error
+                       return false;
+               if (advance == 0) 
+                       advance = arithmeticOp(ch, nextChar, lastPush);
+               if (advance == 0) // unknown token
+                       return false;
+               if (advance > 0)
+                       script += advance;
+               lastPush = ch == ']' || ch == ')';
+       }
+       bool suppressed = SkToBool(fSuppressStack.top().fSuppress);
+       if (fTokenLength > 0) {
+               success = handleProperty(suppressed);
+               if (success == false)
+                       return false;   // note: never triggered by standard animator plugins
+       }
+       while (fOpStack.count() > opBalance) {   // leave open paren
+               if ((fError = opError()) != kNoError)
+                       return false;
+               if (processOp() == false)
+                       return false;
+       }       
+       SkOpType topType = fTypeStack.count() > 0 ? fTypeStack.top() : kNoType;
+       if (suppressed == false && topType != fReturnType &&
+                       topType == kString && fReturnType != kNoType) { // if result is a string, give handle property a chance to convert it to the property value
+               SkString* string = fOperandStack.top().fString;
+               fToken = string->c_str();
+               fTokenLength = string->size();
+               fOperandStack.pop();
+               fTypeStack.pop();
+               success = handleProperty(SkToBool(fSuppressStack.top().fSuppress));
+               if (success == false) { // if it couldn't convert, return string (error?)
+                       SkOperand operand;
+                       operand.fS32 = 0;
+                       *fTypeStack.push() = kString;
+                       operand.fString = string;
+                       fOperandStack.push(operand);
+               }
+       }
+       if (value) {
+               if (fOperandStack.count() == 0)
+                       return false;
+               SkASSERT(fOperandStack.count() >= 1);
+               SkASSERT(fTypeStack.count() >= 1);
+               fOperandStack.pop(&value->fOperand);
+               SkOpType type;
+               fTypeStack.pop(&type);
+               value->fType = ToDisplayType(type);
+//             SkASSERT(value->fType != SkType_Unknown);
+               if (topType != fReturnType && topType == kObject && fReturnType != kNoType) {
+                       if (convertTo(ToDisplayType(fReturnType), value) == false)
+                               return false;
+               }
+       }
+       while (fSuppressStack.count() > suppressBalance)
+               fSuppressStack.pop();
+       *scriptPtr = script;
+       return true; // no error
+}
+
+void SkScriptEngine::memberCallBack(_memberCallBack member , void* userStorage) {
+       UserCallBack callBack;
+       callBack.fMemberCallBack = member;
+       commonCallBack(kMember, callBack, userStorage);
+}
+
+void SkScriptEngine::memberFunctionCallBack(_memberFunctionCallBack func, void* userStorage) {
+       UserCallBack callBack;
+       callBack.fMemberFunctionCallBack = func;
+       commonCallBack(kMemberFunction, callBack, userStorage);
+}
+
+#if 0
+void SkScriptEngine::objectToStringCallBack(_objectToStringCallBack func, void* userStorage) {
+       UserCallBack callBack;
+       callBack.fObjectToStringCallBack = func;
+       commonCallBack(kObjectToString, callBack, userStorage);
+}
+#endif
+
+bool SkScriptEngine::handleArrayIndexer(const char** scriptPtr, bool suppressed) {
+       SkScriptValue scriptValue;
+       (*scriptPtr)++;
+       *fOpStack.push() = kParen;
+       *fBraceStack.push() = kArrayBrace;
+       SkOpType saveType = fReturnType;
+       fReturnType = kInt;
+       bool success = innerScript(scriptPtr, suppressed == false ? &scriptValue : nil);
+       if (success == false)
+               return false;
+       fReturnType = saveType;
+       if (suppressed == false) {
+               if (convertTo(SkType_Int, &scriptValue) == false)
+                       return false;
+               int index = scriptValue.fOperand.fS32;
+               SkScriptValue scriptValue;
+               SkOpType type;
+               fTypeStack.pop(&type);
+               fOperandStack.pop(&scriptValue.fOperand);
+               scriptValue.fType = ToDisplayType(type);
+               if (type == kObject) {
+                       success = handleUnbox(&scriptValue);
+                       if (success == false)
+                               return false;
+                       if (ToOpType(scriptValue.fType) != kArray) {
+                               fError = kExpectedArray;
+                               return false;
+                       }
+               }
+               *fTypeStack.push() = scriptValue.fOperand.fArray->getOpType();
+//             SkASSERT(index >= 0);
+               if ((unsigned) index >= (unsigned) scriptValue.fOperand.fArray->count()) {
+                       fError = kArrayIndexOutOfBounds;
+                       return false;
+               }
+               scriptValue.fOperand = scriptValue.fOperand.fArray->begin()[index];
+               fOperandStack.push(scriptValue.fOperand);
+       }
+       fOpStack.pop(); // pop paren
+       return success;
+}
+
+bool SkScriptEngine::handleBox(SkScriptValue* scriptValue) {
+       bool success = true;
+       for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
+               if (callBack->fCallBackType != kBox)
+                       continue;
+               success = (*callBack->fBoxCallBack)(callBack->fUserStorage, scriptValue);
+               if (success) {
+                       fOperandStack.push(scriptValue->fOperand);
+                       *fTypeStack.push() = ToOpType(scriptValue->fType);
+                       goto done;
+               }
+       }
+done:
+       return success;
+}
+
+bool SkScriptEngine::handleFunction(const char** scriptPtr, bool suppressed) {
+       SkScriptValue callbackResult;
+       SkTDArray<SkScriptValue> params;
+       SkString functionName(fToken, fTokenLength);
+       fTokenLength = 0;
+       bool success = functionParams(scriptPtr, params);
+       if (success == false)
+               goto done;
+       if (suppressed == true)
+               return true;
+       {
+               for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
+                       if (callBack->fCallBackType != kFunction)
+                               continue;
+                       success = (*callBack->fFunctionCallBack)(functionName.c_str(), functionName.size(), params, 
+                               callBack->fUserStorage, &callbackResult);
+                       if (success) {
+                               fOperandStack.push(callbackResult.fOperand);
+                               *fTypeStack.push() = ToOpType(callbackResult.fType);
+                               goto done;
+                       }
+               }
+       }
+       fError = kNoFunctionHandlerFound;
+       return false;
+done:
+       return success;
+}
+
+bool SkScriptEngine::handleMember(const char* field, size_t len, void* object) {
+       SkScriptValue callbackResult;
+       bool success = true;
+       for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
+               if (callBack->fCallBackType != kMember)
+                       continue;
+               success = (*callBack->fMemberCallBack)(field, len, object, callBack->fUserStorage, &callbackResult);
+               if (success) {
+                       if (callbackResult.fType == SkType_String)
+                               track(callbackResult.fOperand.fString);
+                       fOperandStack.push(callbackResult.fOperand);
+                       *fTypeStack.push() = ToOpType(callbackResult.fType);
+                       goto done;
+               }
+       }
+       return false;
+done:
+       return success;
+}
+
+bool SkScriptEngine::handleMemberFunction(const char* field, size_t len, void* object, SkTDArray<SkScriptValue>& params) {
+       SkScriptValue callbackResult;
+       bool success = true;
+       for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
+               if (callBack->fCallBackType != kMemberFunction)
+                       continue;
+               success = (*callBack->fMemberFunctionCallBack)(field, len, object, params, 
+                       callBack->fUserStorage, &callbackResult);
+               if (success) {
+                       if (callbackResult.fType == SkType_String)
+                               track(callbackResult.fOperand.fString);
+                       fOperandStack.push(callbackResult.fOperand);
+                       *fTypeStack.push() = ToOpType(callbackResult.fType);
+                       goto done;
+               }
+       }
+       return false;
+done:
+       return success;
+}
+
+#if 0
+bool SkScriptEngine::handleObjectToString(void* object) {
+       SkScriptValue callbackResult;
+       bool success = true;
+       for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
+               if (callBack->fCallBackType != kObjectToString)
+                       continue;
+               success = (*callBack->fObjectToStringCallBack)(object, 
+                       callBack->fUserStorage, &callbackResult);
+               if (success) {
+                       if (callbackResult.fType == SkType_String)
+                               track(callbackResult.fOperand.fString);
+                       fOperandStack.push(callbackResult.fOperand);
+                       *fTypeStack.push() = ToOpType(callbackResult.fType);
+                       goto done;
+               }
+       }
+       return false;
+done:
+       return success;
+}
+#endif
+
+bool SkScriptEngine::handleProperty(bool suppressed) {
+       SkScriptValue callbackResult;
+       bool success = true;
+       if (suppressed) 
+               goto done;
+       success = false; // note that with standard animator-script plugins, callback never returns false
+       {
+               for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
+                       if (callBack->fCallBackType != kProperty)
+                               continue;
+                       success = (*callBack->fPropertyCallBack)(fToken, fTokenLength, 
+                               callBack->fUserStorage, &callbackResult);
+                       if (success) {
+                               if (callbackResult.fType == SkType_String && callbackResult.fOperand.fString == nil) {
+                                       callbackResult.fOperand.fString = new SkString(fToken, fTokenLength);
+                                       track(callbackResult.fOperand.fString);
+                               }
+                               fOperandStack.push(callbackResult.fOperand);
+                               *fTypeStack.push() = ToOpType(callbackResult.fType);
+                               goto done;
+                       }
+               }
+       }
+done:
+       fTokenLength = 0;
+       return success;
+}
+
+bool SkScriptEngine::handleUnbox(SkScriptValue* scriptValue) {
+       bool success = true;
+       for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
+               if (callBack->fCallBackType != kUnbox)
+                       continue;
+               success = (*callBack->fUnboxCallBack)(callBack->fUserStorage, scriptValue);
+               if (success) {
+                       if (scriptValue->fType == SkType_String)
+                               track(scriptValue->fOperand.fString);
+                       goto done;
+               }
+       }
+       return false;
+done:
+       return success;
+}
+
+// note that entire expression is treated as if it were enclosed in parens
+// an open paren is always the first thing in the op stack
+
+int SkScriptEngine::logicalOp(char ch, char nextChar) {
+       int advance = 1;
+       SkOp match;
+       signed char precedence;
+       switch (ch) {
+               case ')':
+                       match = kParen;
+                       break;
+               case ']':
+                       match = kArrayOp;
+                       break;
+               case '?':
+                       match = kIf;
+                       break;
+               case ':':
+                       match = kElse;
+                       break;
+               case '&':
+                       if (nextChar != '&')
+                               goto noMatch;
+                       match = kLogicalAnd;
+                       advance = 2;
+                       break;
+               case '|':
+                       if (nextChar != '|')
+                               goto noMatch;
+                       match = kLogicalOr;
+                       advance = 2;
+                       break;
+               default:
+noMatch:
+                       return 0;
+       }
+       SkSuppress suppress;
+       precedence = gPrecedence[match];
+       if (fSuppressStack.top().fSuppress) {
+               if (fSuppressStack.top().fOpStackDepth < fOpStack.count()) {
+                       SkOp topOp = fOpStack.top();
+                       if (gPrecedence[topOp] <= precedence)
+                               fOpStack.pop();
+                       goto goHome;
+               }
+               bool changedPrecedence = gPrecedence[fSuppressStack.top().fOperator] < precedence;
+               if (changedPrecedence)
+                       fSuppressStack.pop();
+               if (precedence == kIfElsePrecedence) {
+                       if (match == kIf) {
+                               if (changedPrecedence)
+                                       fOpStack.pop();
+                               else
+                                       *fOpStack.push() = kIf;
+                       } else {
+                               if (fSuppressStack.top().fOpStackDepth == fOpStack.count()) {
+                                       goto flipSuppress;
+                               }
+                               fOpStack.pop();
+                       }
+               }
+               if (changedPrecedence == false)
+                       goto goHome;
+       }
+       while (gPrecedence[fOpStack.top() & ~kArtificialOp] < precedence) {
+               if (processOp() == false)
+                       return false;
+       }
+       if (fSuppressStack.top().fOpStackDepth > fOpStack.count())
+               fSuppressStack.pop();
+       switch (match) {
+               case kParen:
+               case kArrayOp:
+                       if (fOpStack.count() <= 1 || fOpStack.top() != match) {
+                               fError = kMismatchedBrackets;
+                               return -1;
+                       }
+                       if (match == kParen) 
+                               fOpStack.pop();
+                       else {
+                               SkOpType indexType;
+                               fTypeStack.pop(&indexType);
+                               if (indexType != kInt && indexType != kScalar) {
+                                       fError = kExpectedNumberForArrayIndex; // (although, could permit strings eventually)
+                                       return -1;
+                               }
+                               SkOperand indexOperand;
+                               fOperandStack.pop(&indexOperand);
+                               int index = indexType == kScalar ? SkScalarFloor(indexOperand.fScalar) : 
+                                       indexOperand.fS32;
+                               SkOpType arrayType;
+                               fTypeStack.pop(&arrayType);
+                               if ((unsigned)arrayType != (unsigned)kArray) {
+                                       fError = kExpectedArray;
+                                       return -1;
+                               }
+                               SkOperand arrayOperand;
+                               fOperandStack.pop(&arrayOperand);
+                               SkTypedArray* array = arrayOperand.fArray;
+                               SkOperand operand;
+                               if (array->getIndex(index, &operand) == false) {
+                                       fError = kIndexOutOfRange;
+                                       return -1;
+                               }
+                               SkOpType resultType = array->getOpType();
+                               fTypeStack.push(resultType);
+                               fOperandStack.push(operand);
+                       }
+                       break;
+               case kIf: {
+                       SkScriptValue ifValue;
+                       SkOpType ifType;
+                       fTypeStack.pop(&ifType);
+                       ifValue.fType = ToDisplayType(ifType);
+                       fOperandStack.pop(&ifValue.fOperand);
+                       if (convertTo(SkType_Int, &ifValue) == false)
+                               return -1;
+                       if (ifValue.fType != SkType_Int) {
+                               fError = kExpectedIntForConditionOperator;
+                               return -1;
+                       }
+                       suppress.fSuppress = ifValue.fOperand.fS32 == 0;
+                       suppress.fOperator = kIf;
+                       suppress.fOpStackDepth = fOpStack.count(); 
+                       suppress.fElse = false;
+                       fSuppressStack.push(suppress);
+                       // if left is true, do only up to colon
+                       // if left is false, do only after colon
+                       } break;
+               case kElse:
+flipSuppress:
+                       if (fSuppressStack.top().fElse == true)
+                               fSuppressStack.pop();
+                       fSuppressStack.top().fElse = true;
+                       fSuppressStack.top().fSuppress ^= true;
+                       // flip last do / don't do consideration from last '?'
+                       break;
+               case kLogicalAnd:
+               case kLogicalOr: {
+                       if (fTypeStack.top() != kInt) {
+                               fError = kExpectedBooleanExpression;
+                               return -1;
+                       }
+                       S32 topInt = fOperandStack.top().fS32;
+                       if (fOpStack.top() != kLogicalAnd)
+                               *fOpStack.push() = kLogicalAnd; // really means 'to bool', and is appropriate for 'or'
+                       if (match == kLogicalOr ? topInt != 0 : topInt == 0) {
+                               suppress.fSuppress = true;
+                               suppress.fOperator = match;
+                               suppress.fOpStackDepth = fOpStack.count(); 
+                               fSuppressStack.push(suppress);
+                       } else {
+                               fTypeStack.pop();
+                               fOperandStack.pop();
+                       }
+               }       break;
+               default:
+                       SkASSERT(0);
+       }
+goHome:
+       return advance;
+}
+
+SkScriptEngine::Error SkScriptEngine::opError() {
+       int opCount = fOpStack.count();
+       int operandCount = fOperandStack.count();
+       if (opCount == 0) {
+               if (operandCount != 1)
+                       return kExpectedOperator;
+               return kNoError;
+       }
+       SkOp op = (SkOp) (fOpStack.top() & ~kArtificialOp);
+       const SkOperatorAttributes* attributes = &gOpAttributes[op];
+       if (attributes->fLeftType != kNoType && operandCount < 2)
+               return kExpectedValue;
+       if (attributes->fLeftType == kNoType && operandCount < 1)
+               return kExpectedValue;
+       return kNoError;
+}
+
+bool SkScriptEngine::processOp() {
+       SkOp op;
+       fOpStack.pop(&op);
+       op = (SkOp) (op & ~kArtificialOp);
+       const SkOperatorAttributes* attributes = &gOpAttributes[op];
+       SkOpType type2;
+       fTypeStack.pop(&type2);
+       SkOpType type1 = type2;
+       SkOperand operand2;
+       fOperandStack.pop(&operand2);
+       SkOperand operand1 = operand2; // !!! not really needed, suppresses warning
+       if (attributes->fLeftType != kNoType) {
+               fTypeStack.pop(&type1);
+               fOperandStack.pop(&operand1);
+               if (op == kFlipOps) {
+                       SkTSwap(type1, type2);
+                       SkTSwap(operand1, operand2);
+                       fOpStack.pop(&op);
+                       op = (SkOp) (op & ~kArtificialOp);
+                       attributes = &gOpAttributes[op];
+               }
+               if (type1 == kObject && (type1 & attributes->fLeftType) == 0) {
+                       SkScriptValue val;
+                       val.fType = ToDisplayType(type1);
+                       val.fOperand = operand1;
+                       bool success = handleUnbox(&val);
+                       if (success == false)
+                               return false;
+                       type1 = ToOpType(val.fType);
+                       operand1 = val.fOperand;
+               }
+       }
+       if (type2 == kObject && (type2 & attributes->fLeftType) == 0) {
+               SkScriptValue val;
+               val.fType = ToDisplayType(type2);
+               val.fOperand = operand2;
+               bool success = handleUnbox(&val);
+               if (success == false)
+                       return false;
+               type2 = ToOpType(val.fType);
+               operand2 = val.fOperand;
+       }
+       if (attributes->fLeftType != kNoType) {
+               if (type1 != type2) {
+                       if ((attributes->fLeftType & kString) && attributes->fBias & kTowardsString && ((type1 | type2) & kString)) {
+                               if (type1 == kInt || type1 == kScalar) {
+                                       convertToString(operand1, type1 == kInt ? SkType_Int : SkType_Float);
+                                       type1 = kString;
+                               }
+                               if (type2 == kInt || type2 == kScalar) {
+                                       convertToString(operand2, type2 == kInt ? SkType_Int : SkType_Float);
+                                       type2 = kString;
+                               }
+                       } else if (attributes->fLeftType & kScalar && ((type1 | type2) & kScalar)) {
+                               if (type1 == kInt) {
+                                       operand1.fScalar = IntToScalar(operand1.fS32);
+                                       type1 = kScalar;
+                               }
+                               if (type2 == kInt) {
+                                       operand2.fScalar = IntToScalar(operand2.fS32);
+                                        type2 = kScalar;
+                               }
+                       }
+               }
+               if ((type1 & attributes->fLeftType) == 0 || type1 != type2) {
+                       if (type1 == kString) {
+                               const char* result = SkParse::FindScalar(operand1.fString->c_str(), &operand1.fScalar);
+                               if (result == nil) {
+                                       fError = kExpectedNumber;
+                                       return false;
+                               }
+                               type1 = kScalar;
+                       }
+                       if (type1 == kScalar && (attributes->fLeftType == kInt || type2 == kInt)) {
+                               operand1.fS32 = SkScalarFloor(operand1.fScalar);
+                               type1 = kInt;
+                       }
+               }
+       }
+       if ((type2 & attributes->fRightType) == 0 || type1 != type2) {
+               if (type2 == kString) {
+                       const char* result = SkParse::FindScalar(operand2.fString->c_str(), &operand2.fScalar);
+                       if (result == nil) {
+                               fError = kExpectedNumber;
+                               return false;
+                       }
+                       type2 = kScalar;
+               }
+               if (type2 == kScalar && (attributes->fRightType == kInt || type1 == kInt)) {
+                       operand2.fS32 = SkScalarFloor(operand2.fScalar);
+                       type2 = kInt;
+               }
+       }
+       if (type2 == kScalar)
+               op = (SkOp) (op + 1);
+       else if (type2 == kString)
+               op = (SkOp) (op + 2);
+       switch(op) {
+               case kAddInt:
+                       operand2.fS32 += operand1.fS32;
+                       break;
+               case kAddScalar:
+                       operand2.fScalar += operand1.fScalar;
+                       break;
+               case kAddString:
+                       if (fTrackString.find(operand1.fString) < 0) {
+                               operand1.fString = SkNEW_ARGS(SkString, (*operand1.fString));
+                               track(operand1.fString);
+                       }
+                       operand1.fString->append(*operand2.fString);
+                       operand2 = operand1;
+                       break;
+               case kBitAnd:
+                       operand2.fS32 &= operand1.fS32;
+                       break;
+               case kBitNot:
+                       operand2.fS32 = ~operand2.fS32;
+                       break;
+               case kBitOr:
+                       operand2.fS32 |= operand1.fS32;
+                       break;
+               case kDivideInt:
+                       if (operand2.fS32 == 0) {
+                               operand2.fS32 = operand1.fS32 == 0 ? SK_NaN32 : operand1.fS32 > 0 ? SK_MaxS32 : -SK_MaxS32;
+                               break;
+                       } else {
+                               S32 original = operand2.fS32;
+                               operand2.fS32 = operand1.fS32 / operand2.fS32;
+                               if (original * operand2.fS32 == operand1.fS32)
+                                       break;    // integer divide was good enough
+                               operand2.fS32 = original;
+                               type2 = kScalar;
+                       }
+               case kDivideScalar:
+                       if (operand2.fScalar == 0)
+                               operand2.fScalar = operand1.fScalar == 0 ? SK_ScalarNaN : operand1.fScalar > 0 ? SK_ScalarMax : -SK_ScalarMax;
+                       else
+                               operand2.fScalar = SkScalarDiv(operand1.fScalar, operand2.fScalar);
+                       break;
+               case kEqualInt:
+                       operand2.fS32 = operand1.fS32 == operand2.fS32;
+                       break;
+               case kEqualScalar:
+                       operand2.fS32 = operand1.fScalar == operand2.fScalar;
+                       type2 = kInt;
+                       break;
+               case kEqualString:
+                       operand2.fS32 = *operand1.fString == *operand2.fString;
+                       type2 = kInt;
+                       break;
+               case kGreaterEqualInt:
+                       operand2.fS32 = operand1.fS32 >= operand2.fS32;
+                       break;
+               case kGreaterEqualScalar:
+                       operand2.fS32 = operand1.fScalar >= operand2.fScalar;
+                       type2 = kInt;
+                       break;
+               case kGreaterEqualString:
+                       operand2.fS32 = strcmp(operand1.fString->c_str(), operand2.fString->c_str()) >= 0;
+                       type2 = kInt;
+                       break;
+               case kLogicalAnd:
+                       operand2.fS32 = !! operand2.fS32;       // really, ToBool
+                       break;
+               case kLogicalNot:
+                       operand2.fS32 = ! operand2.fS32;
+                       break;
+               case kLogicalOr:
+                       SkASSERT(0);    // should have already been processed
+                       break;
+               case kMinusInt:
+                       operand2.fS32 = -operand2.fS32;
+                       break;
+               case kMinusScalar:
+                       operand2.fScalar = -operand2.fScalar;
+                       break;
+               case kModuloInt:
+                       operand2.fS32 = operand1.fS32 % operand2.fS32;
+                       break;
+               case kModuloScalar:
+                       operand2.fScalar = SkScalarMod(operand1.fScalar, operand2.fScalar);
+                       break;
+               case kMultiplyInt:
+                       operand2.fS32 *= operand1.fS32;
+                       break;
+               case kMultiplyScalar:
+                       operand2.fScalar = SkScalarMul(operand1.fScalar, operand2.fScalar);
+                       break;
+               case kShiftLeft:
+                       operand2.fS32 = operand1.fS32 << operand2.fS32;
+                       break;
+               case kShiftRight:
+                       operand2.fS32 = operand1.fS32 >> operand2.fS32;
+                       break;
+               case kSubtractInt:
+                       operand2.fS32 = operand1.fS32 - operand2.fS32;
+                       break;
+               case kSubtractScalar:
+                       operand2.fScalar = operand1.fScalar - operand2.fScalar;
+                       break;
+               case kXor:
+                       operand2.fS32 ^= operand1.fS32;
+                       break;
+               default:
+                       SkASSERT(0);
+       }
+       fTypeStack.push(type2);
+       fOperandStack.push(operand2);
+       return true;
+}
+
+void SkScriptEngine::propertyCallBack(_propertyCallBack prop, void* userStorage) {
+       UserCallBack callBack;
+       callBack.fPropertyCallBack = prop;
+       commonCallBack(kProperty, callBack, userStorage);
+}
+
+void SkScriptEngine::track(SkTypedArray* array) { 
+       SkASSERT(fTrackArray.find(array) < 0);  
+       *(fTrackArray.end() - 1) = array; 
+       fTrackArray.appendClear(); 
+}
+
+void SkScriptEngine::track(SkString* string) { 
+       SkASSERT(fTrackString.find(string) < 0);  
+       *(fTrackString.end() - 1) = string; 
+       fTrackString.appendClear(); 
+}
+
+void SkScriptEngine::unboxCallBack(_unboxCallBack func, void* userStorage) {
+       UserCallBack callBack;
+       callBack.fUnboxCallBack = func;
+       commonCallBack(kUnbox, callBack, userStorage);
+}
+
+bool SkScriptEngine::ConvertTo(SkScriptEngine* engine, SkDisplayTypes toType, SkScriptValue* value ) {
+       SkASSERT(value);
+       if (SkDisplayType::IsEnum(nil /* fMaker */, toType))
+               toType = SkType_Int;
+       if (toType == SkType_Point || toType == SkType_3D_Point)
+               toType = SkType_Float;
+       if (toType == SkType_Drawable)
+               toType = SkType_Displayable;
+       SkDisplayTypes type = value->fType;
+       if (type == toType) 
+               return true;
+       SkOperand& operand = value->fOperand;
+       bool success = true;
+       switch (toType) {
+               case SkType_Int:
+                       if (type == SkType_Boolean)
+                               break;
+                       if (type == SkType_Float)
+                               operand.fS32 = SkScalarFloor(operand.fScalar);
+                       else {
+                               if (type != SkType_String) {
+                                       success = false;
+                                       break; // error
+                               }
+                               success = SkParse::FindS32(operand.fString->c_str(), &operand.fS32) != nil;
+                       }
+                       break;
+               case SkType_Float:
+                       if (type == SkType_Int) {
+                               if ((uint32_t)operand.fS32 == SK_NaN32)
+                                       operand.fScalar = SK_ScalarNaN;
+                               else if (SkAbs32(operand.fS32) == SK_MaxS32)
+                                       operand.fScalar = SkSign32(operand.fS32) * SK_ScalarMax;
+                               else
+                                       operand.fScalar = SkIntToScalar(operand.fS32);
+                       } else {
+                               if (type != SkType_String) {
+                                       success = false;
+                                       break; // error
+                               }
+                               success = SkParse::FindScalar(operand.fString->c_str(), &operand.fScalar) != nil;
+                       }
+                       break;
+               case SkType_String: {
+                       SkString* strPtr = new SkString();
+                       SkASSERT(engine);
+                       engine->track(strPtr);
+                       if (type == SkType_Int)
+                               strPtr->appendS32(operand.fS32);
+                       else if (type == SkType_Displayable) 
+                               SkASSERT(0); // must call through instance version instead of static version
+                       else {
+                               if (type != SkType_Float) {
+                                       success = false;
+                                       break;
+                               }
+                               strPtr->appendScalar(operand.fScalar);
+                       }
+                       operand.fString = strPtr;
+                       } break;
+               case SkType_Array: {
+                       SkTypedArray* array = new SkTypedArray(type);
+                       *array->append() = operand;
+                       engine->track(array);
+                       operand.fArray = array;
+                       } break;
+               default:
+                       SkASSERT(0);
+       }
+       value->fType = toType;
+       if (success == false)
+               engine->fError = kTypeConversionFailed;
+       return success;
+}
+
+SkScalar SkScriptEngine::IntToScalar(S32 s32) {
+       SkScalar scalar;
+       if ((uint32_t)s32 == SK_NaN32)
+               scalar = SK_ScalarNaN;
+       else if (SkAbs32(s32) == SK_MaxS32)
+               scalar = SkSign32(s32) * SK_ScalarMax;
+       else
+               scalar = SkIntToScalar(s32);
+       return scalar;
+}
+
+SkDisplayTypes SkScriptEngine::ToDisplayType(SkOpType type) {
+       int val = type;
+       switch (val) {
+               case kNoType:
+                       return SkType_Unknown;
+               case kInt:
+                       return SkType_Int;
+               case kScalar:
+                       return SkType_Float;
+               case kString:
+                       return SkType_String;
+               case kArray:
+                       return SkType_Array;
+               case kObject:
+                       return SkType_Displayable;
+//             case kStruct:
+//                     return SkType_Structure;
+               default:
+                       SkASSERT(0);
+                       return SkType_Unknown;
+       }
+}
+
+SkScriptEngine::SkOpType SkScriptEngine::ToOpType(SkDisplayTypes type) {
+       if (SkDisplayType::IsDisplayable(nil /* fMaker */, type))
+               return (SkOpType) kObject;
+       if (SkDisplayType::IsEnum(nil /* fMaker */, type))
+               return kInt;
+       switch (type) {
+               case SkType_ARGB:
+               case SkType_MSec:
+               case SkType_Int:
+                       return kInt;
+               case SkType_Float:
+               case SkType_Point:
+               case SkType_3D_Point:
+                       return kScalar;
+               case SkType_Base64:
+               case SkType_DynamicString:
+               case SkType_String:
+                       return kString;
+               case SkType_Array:
+                       return (SkOpType) kArray;
+               case SkType_Unknown:
+                       return kNoType;
+               default:
+                       SkASSERT(0);
+                       return kNoType;
+       }
+}
+
+bool SkScriptEngine::ValueToString(SkScriptValue value, SkString* string) {
+       switch (value.fType) {
+               case kInt:
+                       string->reset();
+                       string->appendS32(value.fOperand.fS32);
+                       break;
+               case kScalar:
+                       string->reset();
+                       string->appendScalar(value.fOperand.fScalar);
+                       break;
+               case kString:
+                       string->set(*value.fOperand.fString);
+                       break;
+               default:
+                       SkASSERT(0);
+                       return false;
+       }
+       return true; // no error
+}
+
+#ifdef SK_SUPPORT_UNITTEST
+
+#ifdef SK_CAN_USE_FLOAT
+    #include "SkFloatingPoint.h"
+#endif
+
+#define DEF_SCALAR_ANSWER   0
+#define DEF_STRING_ANSWER   NULL
+
+#define testInt(expression) { #expression, SkType_Int, expression, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }
+#ifdef SK_SCALAR_IS_FLOAT
+    #define testScalar(expression) { #expression, SkType_Float, 0, (float) expression, DEF_STRING_ANSWER }
+    #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkType_Float, 0, sk_float_mod(exp1, exp2), DEF_STRING_ANSWER }
+#else
+       #ifdef SK_CAN_USE_FLOAT
+               #define testScalar(expression) { #expression, SkType_Float, 0, (int) ((expression) * 65536.0f), DEF_STRING_ANSWER }
+               #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkType_Float, 0, (int) (sk_float_mod(exp1, exp2)  * 65536.0f), DEF_STRING_ANSWER }
+       #endif
+#endif
+#define testTrue(expression) { #expression, SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }
+#define testFalse(expression) { #expression, SkType_Int, 0, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }
+
+#if !defined(SK_BUILD_FOR_BREW)
+static const SkScriptNAnswer scriptTests[]  = {
+       testInt(1>1/2),
+       testInt((6+7)*8),
+       testInt(0&&1?2:3),
+       testInt(3*(4+5)),
+#ifdef SK_CAN_USE_FLOAT
+       testScalar(1.0+2.0), 
+       testScalar(1.0+5), 
+       testScalar(3.0-1.0), 
+       testScalar(6-1.0), 
+       testScalar(- -5.5- -1.5), 
+       testScalar(2.5*6.), 
+       testScalar(0.5*4), 
+       testScalar(4.5/.5), 
+       testScalar(9.5/19), 
+       testRemainder(9.5, 0.5), 
+       testRemainder(9.,2), 
+       testRemainder(9,2.5),
+       testRemainder(-9,2.5),
+       testTrue(-9==-9.0),
+       testTrue(-9.==-4.0-5),
+       testTrue(-9.*1==-4-5),
+       testFalse(-9!=-9.0),
+       testFalse(-9.!=-4.0-5),
+       testFalse(-9.*1!=-4-5),
+#endif
+       testInt(0x123),
+       testInt(0XABC),
+       testInt(0xdeadBEEF),
+       {       "'123'+\"456\"", SkType_String, 0, 0, "123456" },
+       {       "123+\"456\"", SkType_String, 0, 0, "123456" },
+       {       "'123'+456", SkType_String, 0, 0, "123456" },
+       {       "'123'|\"456\"", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
+       {       "123|\"456\"", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
+       {       "'123'|456", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
+       {       "'2'<11", SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
+       {       "2<'11'", SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
+       {       "'2'<'11'", SkType_Int, 0, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
+       testInt(123),
+       testInt(-345),
+       testInt(+678),
+       testInt(1+2+3),
+       testInt(3*4+5),
+       testInt(6+7*8),
+       testInt(-1-2-8/4),
+       testInt(-9%4),
+       testInt(9%-4),
+       testInt(-9%-4),
+       testInt(123|978),
+       testInt(123&978),
+       testInt(123^978),
+       testInt(2<<4),
+       testInt(99>>3),
+       testInt(~55),
+       testInt(~~55),
+       testInt(!55),
+       testInt(!!55),
+       // both int
+       testInt(2<2),
+       testInt(2<11),
+       testInt(20<11),
+       testInt(2<=2),
+       testInt(2<=11),
+       testInt(20<=11),
+       testInt(2>2),
+       testInt(2>11),
+       testInt(20>11),
+       testInt(2>=2),
+       testInt(2>=11),
+       testInt(20>=11),
+       testInt(2==2),
+       testInt(2==11),
+       testInt(20==11),
+       testInt(2!=2),
+       testInt(2!=11),
+       testInt(20!=11),
+#ifdef SK_CAN_USE_FLOAT
+       // left int, right scalar
+       testInt(2<2.),
+       testInt(2<11.),
+       testInt(20<11.),
+       testInt(2<=2.),
+       testInt(2<=11.),
+       testInt(20<=11.),
+       testInt(2>2.),
+       testInt(2>11.),
+       testInt(20>11.),
+       testInt(2>=2.),
+       testInt(2>=11.),
+       testInt(20>=11.),
+       testInt(2==2.),
+       testInt(2==11.),
+       testInt(20==11.),
+       testInt(2!=2.),
+       testInt(2!=11.),
+       testInt(20!=11.),
+       // left scalar, right int
+               testInt(2.<2),
+       testInt(2.<11),
+       testInt(20.<11),
+       testInt(2.<=2),
+       testInt(2.<=11),
+       testInt(20.<=11),
+       testInt(2.>2),
+       testInt(2.>11),
+       testInt(20.>11),
+       testInt(2.>=2),
+       testInt(2.>=11),
+       testInt(20.>=11),
+       testInt(2.==2),
+       testInt(2.==11),
+       testInt(20.==11),
+       testInt(2.!=2),
+       testInt(2.!=11),
+       testInt(20.!=11),
+       // both scalar
+       testInt(2.<11.),
+       testInt(20.<11.),
+       testInt(2.<=2.),
+       testInt(2.<=11.),
+       testInt(20.<=11.),
+       testInt(2.>2.),
+       testInt(2.>11.),
+       testInt(20.>11.),
+       testInt(2.>=2.),
+       testInt(2.>=11.),
+       testInt(20.>=11.),
+       testInt(2.==2.),
+       testInt(2.==11.),
+       testInt(20.==11.),
+       testInt(2.!=2.),
+       testInt(2.!=11.),
+       testInt(20.!=11.),
+#endif
+       // int, string (string is int)
+       testFalse(2<'2'),
+       testTrue(2<'11'),
+       testFalse(20<'11'),
+       testTrue(2<='2'),
+       testTrue(2<='11'),
+       testFalse(20<='11'),
+       testFalse(2>'2'),
+       testFalse(2>'11'),
+       testTrue(20>'11'),
+       testTrue(2>='2'),
+       testFalse(2>='11'),
+       testTrue(20>='11'),
+       testTrue(2=='2'),
+       testFalse(2=='11'),
+       testFalse(2!='2'),
+       testTrue(2!='11'),
+       // int, string (string is scalar)
+       testFalse(2<'2.'),
+       testTrue(2<'11.'),
+       testFalse(20<'11.'),
+       testTrue(2=='2.'),
+       testFalse(2=='11.'),
+#ifdef SK_CAN_USE_FLOAT
+       // scalar, string
+       testFalse(2.<'2.'),
+       testTrue(2.<'11.'),
+       testFalse(20.<'11.'),
+       testTrue(2.=='2.'),
+       testFalse(2.=='11.'),
+       // string, int
+       testFalse('2'<2),
+       testTrue('2'<11),
+       testFalse('20'<11),
+       testTrue('2'==2),
+       testFalse('2'==11),
+       // string, scalar
+       testFalse('2'<2.),
+       testTrue('2'<11.),
+       testFalse('20'<11.),
+       testTrue('2'==2.),
+       testFalse('2'==11.),
+#endif
+       // string, string
+       testFalse('2'<'2'),
+       testFalse('2'<'11'),
+       testFalse('20'<'11'),
+       testTrue('2'=='2'),
+       testFalse('2'=='11'),
+       // logic
+       testInt(1?2:3),
+       testInt(0?2:3),
+       testInt(1&&2||3),
+       testInt(1&&0||3),
+       testInt(1&&0||0),
+       testInt(1||0&&3),
+       testInt(0||0&&3),
+       testInt(0||1&&3),
+       testInt(1?(2?3:4):5),
+       testInt(0?(2?3:4):5),
+       testInt(1?(0?3:4):5),
+       testInt(0?(0?3:4):5),
+       testInt(1?2?3:4:5),
+       testInt(0?2?3:4:5),
+       testInt(1?0?3:4:5),
+       testInt(0?0?3:4:5),
+       
+       testInt(1?2:(3?4:5)),
+       testInt(0?2:(3?4:5)),
+       testInt(1?0:(3?4:5)),
+       testInt(0?0:(3?4:5)),
+       testInt(1?2:3?4:5),
+       testInt(0?2:3?4:5),
+       testInt(1?0:3?4:5),
+       testInt(0?0:3?4:5)
+#ifdef SK_CAN_USE_FLOAT
+       , {     "123.5", SkType_Float, 0, SkIntToScalar(123) + SK_Scalar1/2, DEF_STRING_ANSWER }
+#endif
+};
+#endif // build for brew
+
+#define SkScriptNAnswer_testCount      SK_ARRAY_COUNT(scriptTests)
+
+void SkScriptEngine::UnitTest() {
+#if !defined(SK_BUILD_FOR_BREW)
+       for (unsigned index = 0; index < SkScriptNAnswer_testCount; index++) {
+               SkScriptEngine engine(SkScriptEngine::ToOpType(scriptTests[index].fType));
+               SkScriptValue value;
+               const char* script = scriptTests[index].fScript;
+               SkASSERT(engine.evaluateScript(&script, &value) == true);
+               SkASSERT(value.fType == scriptTests[index].fType);
+               SkScalar error;
+               switch (value.fType) {
+                       case SkType_Int:
+                               SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer);
+                               break;
+                       case SkType_Float:
+                               error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer);
+                               SkASSERT(error < SK_Scalar1 / 10000);
+                               break;
+                       case SkType_String:
+                               SkASSERT(strcmp(value.fOperand.fString->c_str(), scriptTests[index].fStringAnswer) == 0);
+                               break;
+                       default:
+                               SkASSERT(0);
+               }
+       }
+#endif
+}
+#endif
+
diff --git a/libs/graphics/animator/SkScript.h b/libs/graphics/animator/SkScript.h
new file mode 100644 (file)
index 0000000..e172c9e
--- /dev/null
@@ -0,0 +1,257 @@
+#ifndef SkScript_DEFINED
+#define SkScript_DEFINED
+
+#include "SkOperand.h"
+#include "SkIntArray.h"
+#include "SkTDict.h"
+#include "SkTDStack.h"
+
+class SkAnimateMaker;
+
+class SkScriptEngine {
+public:
+       enum Error {
+               kNoError,
+               kArrayIndexOutOfBounds,
+               kCouldNotFindReferencedID,
+               kDotOperatorExpectsObject,
+               kErrorInArrrayIndex,
+               kErrorInFunctionParameters,
+               kExpectedArray,
+               kExpectedBooleanExpression,
+               kExpectedFieldName,
+               kExpectedHex,
+               kExpectedIntForConditionOperator,
+               kExpectedNumber,
+               kExpectedNumberForArrayIndex,
+               kExpectedOperator,
+               kExpectedToken,
+               kExpectedTokenBeforeDotOperator,
+               kExpectedValue,
+               kHandleMemberFailed,
+               kHandleMemberFunctionFailed,
+               kHandleUnboxFailed,
+               kIndexOutOfRange,
+               kMismatchedArrayBrace,
+               kMismatchedBrackets,
+               kNoFunctionHandlerFound,
+               kPrematureEnd,
+               kTooManyParameters,
+               kTypeConversionFailed,
+               kUnterminatedString
+       };
+
+       enum SkOpType {
+               kNoType,
+               kInt = 1,
+               kScalar = 2,
+               kString = 4,
+               kArray = 8,
+               kObject = 16
+//             kStruct = 32
+       };
+
+       typedef bool (*_boxCallBack)(void* userStorage, SkScriptValue* result);
+       typedef bool (*_functionCallBack)(const char* func, size_t len, SkTDArray<SkScriptValue>& params,
+               void* userStorage, SkScriptValue* result);
+       typedef bool (*_memberCallBack)(const char* member, size_t len, void* object, 
+               void* userStorage, SkScriptValue* result);
+       typedef bool (*_memberFunctionCallBack)(const char* member, size_t len, void* object, 
+               SkTDArray<SkScriptValue>& params, void* userStorage, SkScriptValue* result);
+//     typedef bool (*_objectToStringCallBack)(void* object, void* userStorage, SkScriptValue* result);
+       typedef bool (*_propertyCallBack)(const char* prop, size_t len, void* userStorage, SkScriptValue* result);
+       typedef bool (*_unboxCallBack)(void* userStorage, SkScriptValue* result);
+       SkScriptEngine(SkOpType returnType);
+       ~SkScriptEngine();
+       void boxCallBack(_boxCallBack func, void* userStorage);
+       bool convertTo(SkDisplayTypes , SkScriptValue* );
+       bool evaluateScript(const char** script, SkScriptValue* value);
+       void forget(SkTypedArray* array);
+       void functionCallBack(_functionCallBack func, void* userStorage);
+       Error getError() const { return fError; }
+#ifdef SK_DEBUG
+       bool getErrorString(SkString* err) const;
+#endif
+       void memberCallBack(_memberCallBack , void* userStorage);
+       void memberFunctionCallBack(_memberFunctionCallBack , void* userStorage);
+//     void objectToStringCallBack(_objectToStringCallBack , void* userStorage);
+       void propertyCallBack(_propertyCallBack prop, void* userStorage);
+       void track(SkTypedArray* array);
+       void track(SkString* string);
+       void unboxCallBack(_unboxCallBack func, void* userStorage);
+       static bool ConvertTo(SkScriptEngine* , SkDisplayTypes toType, SkScriptValue* value);
+       static SkScalar IntToScalar(S32 );
+       static SkDisplayTypes ToDisplayType(SkOpType type);
+       static SkOpType ToOpType(SkDisplayTypes type);
+       static bool ValueToString(SkScriptValue value, SkString* string);
+
+       enum CallBackType {
+               kBox,
+               kFunction,
+               kMember,
+               kMemberFunction,
+       //      kObjectToString,
+               kProperty,
+               kUnbox
+       };
+
+       struct UserCallBack {
+               CallBackType fCallBackType;
+               void* fUserStorage;
+               union {
+                       _boxCallBack fBoxCallBack;
+                       _functionCallBack fFunctionCallBack;
+                       _memberCallBack fMemberCallBack;
+                       _memberFunctionCallBack fMemberFunctionCallBack;
+       //              _objectToStringCallBack fObjectToStringCallBack;
+                       _propertyCallBack fPropertyCallBack;
+                       _unboxCallBack fUnboxCallBack;
+               };
+       };
+
+       enum SkOp {
+               kUnassigned,
+               kAdd,
+               kAddInt = kAdd,
+               kAddScalar,
+               kAddString,     // string concat
+               kArrayOp,
+               kBitAnd,
+               kBitNot,
+               kBitOr,
+               kDivide,
+               kDivideInt = kDivide,
+               kDivideScalar,
+               kElse,
+               kEqual,
+               kEqualInt = kEqual,
+               kEqualScalar,
+               kEqualString,
+               kFlipOps,
+               kGreaterEqual,
+               kGreaterEqualInt = kGreaterEqual,
+               kGreaterEqualScalar,
+               kGreaterEqualString,
+               kIf,
+               kLogicalAnd,
+               kLogicalNot,
+               kLogicalOr,
+               kMinus,
+               kMinusInt = kMinus,
+               kMinusScalar,
+               kModulo,
+               kModuloInt = kModulo,
+               kModuloScalar,
+               kMultiply,
+               kMultiplyInt = kMultiply,
+               kMultiplyScalar,
+               kParen,
+               kShiftLeft,
+               kShiftRight,    // signed
+               kSubtract,
+               kSubtractInt = kSubtract,
+               kSubtractScalar,
+               kXor,
+               kArtificialOp = 0x40
+       };
+
+       enum SkOpBias {
+               kNoBias,
+               kTowardsNumber = 0,
+               kTowardsString
+       };
+       
+protected:
+
+       struct SkOperatorAttributes {
+               unsigned int fLeftType : 3;     // SkOpType, but only lower values
+               unsigned int fRightType : 3;     // SkOpType, but only lower values
+               SkOpBias fBias : 1;
+       };
+
+       struct SkSuppress {     // !!! could be compressed to a long
+               SkOp fOperator; // operand which enabled suppression
+               int fOpStackDepth; // depth when suppression operator was found
+               SkBool8 fSuppress; // set if suppression happens now, as opposed to later
+               SkBool8 fElse; // set on the : half of ? :
+       };
+
+       static const SkOperatorAttributes gOpAttributes[];
+       static const signed char gPrecedence[];
+       int arithmeticOp(char ch, char nextChar, bool lastPush);
+       void commonCallBack(CallBackType type, UserCallBack& callBack, void* userStorage);
+       bool convertParams(SkTDArray<SkScriptValue>&, const SkFunctionParamType* ,
+                                                                       int paramTypeCount);
+       void convertToString(SkOperand& operand, SkDisplayTypes type) {
+               SkScriptValue scriptValue;
+               scriptValue.fOperand = operand;
+               scriptValue.fType = type;
+               convertTo(SkType_String, &scriptValue);
+               operand = scriptValue.fOperand;
+       }
+       bool evaluateDot(const char*& script, bool suppressed);
+       bool evaluateDotParam(const char*& script, bool suppressed, const char* field, size_t fieldLength);
+       bool functionParams(const char** scriptPtr, SkTDArray<SkScriptValue>& params);
+       bool handleArrayIndexer(const char** scriptPtr, bool suppressed);
+       bool handleBox(SkScriptValue* value);
+       bool handleFunction(const char** scriptPtr, bool suppressed);
+       bool handleMember(const char* field, size_t len, void* object);
+       bool handleMemberFunction(const char* field, size_t len, void* object, SkTDArray<SkScriptValue>& params);
+//     bool handleObjectToString(void* object);
+       bool handleProperty(bool suppressed);
+       bool handleUnbox(SkScriptValue* scriptValue);
+       bool innerScript(const char** scriptPtr, SkScriptValue* value);
+       int logicalOp(char ch, char nextChar);
+       Error opError();
+       bool processOp();
+       void setAnimateMaker(SkAnimateMaker* maker) { fMaker = maker; }
+       bool setError(Error , const char* pos);
+       enum SkBraceStyle {
+       //      kStructBrace,
+               kArrayBrace,
+               kFunctionBrace
+       };
+
+#if 0
+       SkIntArray(SkBraceStyle) fBraceStack;           // curly, square, function paren
+       SkIntArray(SkOp) fOpStack;
+       SkIntArray(SkOpType) fTypeStack;
+       SkTDOperandArray fOperandStack;
+       SkTDArray<SkSuppress> fSuppressStack;
+#else
+       SkTDStack<SkBraceStyle> fBraceStack;            // curly, square, function paren
+       SkTDStack<SkOp> fOpStack;
+       SkTDStack<SkOpType> fTypeStack;
+       SkTDStack<SkOperand> fOperandStack;
+       SkTDStack<SkSuppress> fSuppressStack;
+#endif
+       SkAnimateMaker* fMaker;
+       SkTDTypedArrayArray fTrackArray;
+       SkTDStringArray fTrackString;
+       const char* fToken; // one-deep stack
+       size_t fTokenLength;
+       SkTDArray<UserCallBack> fUserCallBacks;
+       SkOpType fReturnType;
+       Error fError;
+       int fErrorPosition;
+private:
+       friend class SkTypedArray;
+#ifdef SK_SUPPORT_UNITTEST
+public:
+       static void UnitTest();
+#endif
+};
+
+#ifdef SK_SUPPORT_UNITTEST
+
+struct SkScriptNAnswer {
+       const char* fScript;
+       SkDisplayTypes fType;
+       S32 fIntAnswer;
+       SkScalar fScalarAnswer;
+       const char* fStringAnswer;
+};
+
+#endif
+
+#endif // SkScript_DEFINED
diff --git a/libs/graphics/animator/SkScript2.h b/libs/graphics/animator/SkScript2.h
new file mode 100755 (executable)
index 0000000..2443d82
--- /dev/null
@@ -0,0 +1,285 @@
+#ifndef SkScript2_DEFINED
+#define SkScript2_DEFINED
+
+#include "SkOperand2.h"
+#include "SkStream.h"
+#include "SkTDArray.h"
+#include "SkTDArray_Experimental.h"
+#include "SkTDict.h"
+#include "SkTDStack.h"
+
+typedef SkLongArray(SkString*) SkTDStringArray; 
+
+class SkAnimateMaker;
+class SkScriptCallBack;
+
+class SkScriptEngine2 {
+public:
+       enum Error {
+               kNoError,
+               kArrayIndexOutOfBounds,
+               kCouldNotFindReferencedID,
+               kFunctionCallFailed,
+               kMemberOpFailed,
+               kPropertyOpFailed
+       };
+
+       enum Attrs {
+               kConstant,
+               kVariable
+       };
+
+       SkScriptEngine2(SkOperand2::OpType returnType);
+       ~SkScriptEngine2();
+       bool convertTo(SkOperand2::OpType , SkScriptValue2* );
+       bool evaluateScript(const char** script, SkScriptValue2* value);
+       void forget(SkOpArray* array);
+       Error getError() { return fError; }
+       SkOperand2::OpType getReturnType() { return fReturnType; }
+       void track(SkOpArray* array) { 
+               SkASSERT(fTrackArray.find(array) < 0);  
+               *fTrackArray.append() = array; }
+       void track(SkString* string) { 
+               SkASSERT(fTrackString.find(string) < 0);  
+               *fTrackString.append() = string; 
+       }
+       static bool ConvertTo(SkScriptEngine2* , SkOperand2::OpType toType, SkScriptValue2* value);
+       static SkScalar IntToScalar(S32 );
+       static bool ValueToString(const SkScriptValue2& value, SkString* string);
+
+       enum Op {               // used by tokenizer attribute table
+               kUnassigned,
+               kAdd,
+               kBitAnd,
+               kBitNot,
+               kBitOr,
+               kDivide,
+               kEqual,
+               kFlipOps,
+               kGreaterEqual,
+               kLogicalAnd,
+               kLogicalNot,
+               kLogicalOr,
+               kMinus,
+               kModulo,
+               kMultiply,
+               kShiftLeft,
+               kShiftRight,    // signed
+               kSubtract,
+               kXor,
+// following not in attribute table
+               kArrayOp,
+               kElse,
+               kIf,
+               kParen,
+               kLastLogicalOp,
+               kArtificialOp = 0x20
+       };
+
+       enum TypeOp {   // generated by tokenizer
+               kNop, // should never get generated
+               kAccumulatorPop,
+               kAccumulatorPush,
+               kAddInt,
+               kAddScalar,
+               kAddString,     // string concat
+               kArrayIndex,
+               kArrayParam,
+               kArrayToken,
+               kBitAndInt,
+               kBitNotInt,
+               kBitOrInt,
+               kBoxToken,
+               kCallback,
+               kDivideInt,
+               kDivideScalar,
+               kDotOperator,
+               kElseOp,
+               kEnd,
+               kEqualInt,
+               kEqualScalar,
+               kEqualString,
+               kFunctionCall,
+               kFlipOpsOp,
+               kFunctionToken,
+               kGreaterEqualInt,
+               kGreaterEqualScalar,
+               kGreaterEqualString,
+               kIfOp,
+               kIntToScalar,
+               kIntToScalar2,
+               kIntToString,
+               kIntToString2,
+               kIntegerAccumulator,
+               kIntegerOperand,
+               kLogicalAndInt,
+               kLogicalNotInt,
+               kLogicalOrInt,
+               kMemberOp,
+               kMinusInt,
+               kMinusScalar,
+               kModuloInt,
+               kModuloScalar,
+               kMultiplyInt,
+               kMultiplyScalar,
+               kPropertyOp,
+               kScalarAccumulator,
+               kScalarOperand,
+               kScalarToInt,
+               kScalarToInt2,
+               kScalarToString,
+               kScalarToString2,
+               kShiftLeftInt,
+               kShiftRightInt, // signed
+               kStringAccumulator,
+               kStringOperand,
+               kStringToInt,
+               kStringToScalar,
+               kStringToScalar2,
+               kStringTrack,
+               kSubtractInt,
+               kSubtractScalar,
+               kToBool,
+               kUnboxToken,
+               kUnboxToken2,
+               kXorInt,
+               kLastTypeOp
+       };
+
+       enum OpBias {
+               kNoBias,
+               kTowardsNumber = 0,
+               kTowardsString
+       };
+
+protected:
+
+       enum BraceStyle {
+       //      kStructBrace,
+               kArrayBrace,
+               kFunctionBrace
+       };
+
+       enum AddTokenRegister {
+               kAccumulator,
+               kOperand
+       };
+       
+       enum ResultIsBoolean {
+               kResultIsNotBoolean,
+               kResultIsBoolean
+       };
+
+       struct OperatorAttributes {
+               unsigned int fLeftType : 3;     // SkOpType union, but only lower values
+               unsigned int fRightType : 3;     // SkOpType union, but only lower values
+               OpBias fBias : 1;
+               ResultIsBoolean fResultIsBoolean : 1;
+       };
+       
+       struct Branch {
+               Branch() {
+               }
+               
+               Branch(Op op, int depth, unsigned offset) : fOffset(offset), fOpStackDepth(depth), fOperator(op),
+                       fPrimed(kIsNotPrimed), fDone(kIsNotDone) {
+               }
+
+               enum Primed {
+                       kIsNotPrimed,
+                       kIsPrimed
+               };
+
+               enum Done {
+                       kIsNotDone,
+                       kIsDone,
+               };
+
+               unsigned fOffset : 16; // offset in generated stream where branch needs to go
+               int fOpStackDepth : 7; // depth when operator was found
+               Op fOperator : 6; // operand which generated branch
+               mutable Primed fPrimed : 1;     // mark when next instruction generates branch
+               Done fDone : 1; // mark when branch is complete
+               void prime() { fPrimed = kIsPrimed; }
+               void resolve(SkDynamicMemoryWStream* , size_t offset);
+       };
+
+       static const OperatorAttributes gOpAttributes[];
+       static const signed char gPrecedence[];
+       static const TypeOp gTokens[];
+       void addToken(TypeOp );
+       void addTokenConst(SkScriptValue2* , AddTokenRegister , SkOperand2::OpType , TypeOp );
+       void addTokenInt(int );
+       void addTokenScalar(SkScalar );
+       void addTokenString(const SkString& );
+       void addTokenValue(const SkScriptValue2& , AddTokenRegister );
+       int arithmeticOp(char ch, char nextChar, bool lastPush);
+       bool convertParams(SkTDArray<SkScriptValue2>* ,
+               const SkOperand2::OpType* paramTypes, int paramTypeCount);
+       void convertToString(SkOperand2* operand, SkOperand2::OpType type) {
+               SkScriptValue2 scriptValue;
+               scriptValue.fOperand = *operand;
+               scriptValue.fType = type;
+               convertTo(SkOperand2::kString, &scriptValue);
+               *operand = scriptValue.fOperand;
+       }
+       bool evaluateDot(const char*& script);
+       bool evaluateDotParam(const char*& script, const char* field, size_t fieldLength);
+       bool functionParams(const char** scriptPtr, SkTDArray<SkScriptValue2>* params);
+       size_t getTokenOffset();
+       SkOperand2::OpType getUnboxType(SkOperand2 scriptValue);
+       bool handleArrayIndexer(const char** scriptPtr);
+       bool handleFunction(const char** scriptPtr);
+       bool handleMember(const char* field, size_t len, void* object);
+       bool handleMemberFunction(const char* field, size_t len, void* object, 
+               SkTDArray<SkScriptValue2>* params);
+       bool handleProperty();
+       bool handleUnbox(SkScriptValue2* scriptValue);
+       bool innerScript(const char** scriptPtr, SkScriptValue2* value);
+       int logicalOp(char ch, char nextChar);
+       void processLogicalOp(Op op);
+       bool processOp();
+       void resolveBranch(Branch& );
+//     void setAnimateMaker(SkAnimateMaker* maker) { fMaker = maker; }
+       SkDynamicMemoryWStream fStream;
+       SkDynamicMemoryWStream* fActiveStream;
+       SkTDStack<BraceStyle> fBraceStack;              // curly, square, function paren
+       SkTDStack<Branch> fBranchStack;  // logical operators, slot to store forward branch
+       SkLongArray(SkScriptCallBack*) fCallBackArray;
+       SkTDStack<Op> fOpStack;
+       SkTDStack<SkScriptValue2> fValueStack;
+//     SkAnimateMaker* fMaker;
+       SkLongArray(SkOpArray*) fTrackArray;
+       SkTDStringArray fTrackString;
+       const char* fToken; // one-deep stack
+       size_t fTokenLength;
+       SkOperand2::OpType fReturnType;
+       Error fError;
+       SkOperand2::OpType fAccumulatorType;    // tracking for code generation
+       SkBool fBranchPopAllowed;
+       SkBool fConstExpression;
+       SkBool fOperandInUse;
+private:
+#ifdef SK_DEBUG
+public:
+       void decompile(const unsigned char* , size_t );
+       static void UnitTest();
+       static void ValidateDecompileTable();
+#endif
+};
+
+#ifdef SK_DEBUG
+
+struct SkScriptNAnswer2 {
+       const char* fScript;
+       SkOperand2::OpType fType;
+       S32 fIntAnswer;
+       SkScalar fScalarAnswer;
+       const char* fStringAnswer;
+};
+
+#endif
+
+
+#endif // SkScript2_DEFINED
+
diff --git a/libs/graphics/animator/SkScriptCallBack.h b/libs/graphics/animator/SkScriptCallBack.h
new file mode 100755 (executable)
index 0000000..4b25105
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef SkScriptCallBack_DEFINED\r
+#define SkScriptCallBack_DEFINED\r
+\r
+#include "SkOperand2.h"\r
+#include "SkTDArray_Experimental.h"\r
+\r
+class SkScriptCallBack {\r
+public:\r
+       enum Type {\r
+               kBox,\r
+               kFunction,\r
+               kMember,\r
+               kMemberFunction,\r
+               kProperty,\r
+               kUnbox\r
+       };\r
+\r
+       virtual bool getReference(const char* , size_t len, SkScriptValue2* result) {  return false; }\r
+       virtual SkOperand2::OpType getReturnType(size_t ref, SkOperand2*) { \r
+               return SkOperand2::kS32; }\r
+       virtual Type getType() const = 0;\r
+};\r
+\r
+class SkScriptCallBackConvert : public SkScriptCallBack {\r
+public:\r
+       virtual bool convert(SkOperand2::OpType type, SkOperand2* operand) = 0;\r
+};\r
+\r
+class SkScriptCallBackFunction : public SkScriptCallBack {\r
+public:\r
+       virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) = 0;\r
+       virtual Type getType() const { return kFunction; }\r
+       virtual bool invoke(size_t ref, SkOpArray* params, SkOperand2* value) = 0;\r
+};\r
+\r
+class SkScriptCallBackMember: public SkScriptCallBack {\r
+public:\r
+       bool getMemberReference(const char* , size_t len, void* object, SkScriptValue2* ref);\r
+       virtual Type getType() const { return kMember; }\r
+       virtual bool invoke(size_t ref, void* object, SkOperand2* value) = 0;\r
+};\r
+\r
+class SkScriptCallBackMemberFunction : public SkScriptCallBack {\r
+public:\r
+       bool getMemberReference(const char* , size_t len, void* object, SkScriptValue2* ref);\r
+       virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) = 0;\r
+       virtual Type getType() const { return kMemberFunction; }\r
+       virtual bool invoke(size_t ref, void* object, SkOpArray* params, SkOperand2* value) = 0;\r
+};\r
+\r
+class SkScriptCallBackProperty : public SkScriptCallBack {\r
+public:\r
+       virtual bool getConstValue(const char* name, size_t len, SkOperand2* value) { return false; }\r
+       virtual bool getResult(size_t ref, SkOperand2* answer) { return false; }\r
+       virtual Type getType() const { return kProperty; }\r
+};\r
+\r
+#endif // SkScriptCallBack_DEFINED\r
diff --git a/libs/graphics/animator/SkScriptDecompile.cpp b/libs/graphics/animator/SkScriptDecompile.cpp
new file mode 100644 (file)
index 0000000..a9f25b7
--- /dev/null
@@ -0,0 +1,204 @@
+#include "SkScript2.h"
+
+#ifdef SK_DEBUG
+
+#define TypeOpName(op) {SkScriptEngine2::op, #op }
+
+static const struct OpName {
+       SkScriptEngine2::TypeOp fOp;
+       const char* fName;
+} gOpNames[] = {
+       TypeOpName(kNop), // should never get generated
+       TypeOpName(kAccumulatorPop),
+       TypeOpName(kAccumulatorPush),
+       TypeOpName(kAddInt),
+       TypeOpName(kAddScalar),
+       TypeOpName(kAddString), // string concat
+       TypeOpName(kArrayIndex),
+       TypeOpName(kArrayParam),
+       TypeOpName(kArrayToken),
+       TypeOpName(kBitAndInt),
+       TypeOpName(kBitNotInt),
+       TypeOpName(kBitOrInt),
+       TypeOpName(kBoxToken),
+       TypeOpName(kCallback),
+       TypeOpName(kDivideInt),
+       TypeOpName(kDivideScalar),
+       TypeOpName(kDotOperator),
+       TypeOpName(kElseOp),
+       TypeOpName(kEnd),
+       TypeOpName(kEqualInt),
+       TypeOpName(kEqualScalar),
+       TypeOpName(kEqualString),
+       TypeOpName(kFunctionCall),
+       TypeOpName(kFlipOpsOp),
+       TypeOpName(kFunctionToken),
+       TypeOpName(kGreaterEqualInt),
+       TypeOpName(kGreaterEqualScalar),
+       TypeOpName(kGreaterEqualString),
+       TypeOpName(kIfOp),
+       TypeOpName(kIntToScalar),
+       TypeOpName(kIntToScalar2),
+       TypeOpName(kIntToString),
+       TypeOpName(kIntToString2),
+       TypeOpName(kIntegerAccumulator),
+       TypeOpName(kIntegerOperand),
+       TypeOpName(kLogicalAndInt),
+       TypeOpName(kLogicalNotInt),
+       TypeOpName(kLogicalOrInt),
+       TypeOpName(kMemberOp),
+       TypeOpName(kMinusInt),
+       TypeOpName(kMinusScalar),
+       TypeOpName(kModuloInt),
+       TypeOpName(kModuloScalar),
+       TypeOpName(kMultiplyInt),
+       TypeOpName(kMultiplyScalar),
+       TypeOpName(kPropertyOp),
+       TypeOpName(kScalarAccumulator),
+       TypeOpName(kScalarOperand),
+       TypeOpName(kScalarToInt),
+       TypeOpName(kScalarToInt2),
+       TypeOpName(kScalarToString),
+       TypeOpName(kScalarToString2),
+       TypeOpName(kShiftLeftInt),
+       TypeOpName(kShiftRightInt),     // signed
+       TypeOpName(kStringAccumulator),
+       TypeOpName(kStringOperand),
+       TypeOpName(kStringToInt),
+       TypeOpName(kStringToScalar),
+       TypeOpName(kStringToScalar2),
+       TypeOpName(kStringTrack),
+       TypeOpName(kSubtractInt),
+       TypeOpName(kSubtractScalar),
+       TypeOpName(kToBool),
+       TypeOpName(kUnboxToken),
+       TypeOpName(kUnboxToken2),
+       TypeOpName(kXorInt)
+};
+
+static size_t gOpNamesSize = sizeof(gOpNames) / sizeof(gOpNames[0]);
+
+#define OperandName(op) {SkOperand2::op, #op }
+
+static const struct OperName {
+       SkOperand2::OpType fType;
+       const char* fName;
+} gOperandNames[] = {
+       OperandName(kNoType),
+       OperandName(kS32),
+       OperandName(kScalar),
+       OperandName(kString),
+       OperandName(kArray),
+       OperandName(kObject)
+};     
+
+static size_t gOperandNamesSize = sizeof(gOperandNames) / sizeof(gOperandNames[0]);
+
+// check to see that there are no missing or duplicate entries
+void SkScriptEngine2::ValidateDecompileTable() {
+       SkScriptEngine2::TypeOp op = SkScriptEngine2::kNop;
+       int index;
+       for (index = 0; index < gOpNamesSize; index++) {
+               SkASSERT(gOpNames[index].fOp == op);
+               op = (SkScriptEngine2::TypeOp) (op + 1);
+       }
+       index = 0;
+       SkOperand2::OpType type = SkOperand2::kNoType;
+       SkASSERT(gOperandNames[index].fType == type);
+       for (; index < gOperandNamesSize - 1; ) {
+               type = (SkOperand2::OpType) (1 << index);
+               SkASSERT(gOperandNames[++index].fType == type);
+       }
+}
+
+void SkScriptEngine2::decompile(const unsigned char* start, size_t length) {
+       SkASSERT(length > 0);
+       const unsigned char* opCode = start;
+       do {
+               SkASSERT(opCode - start < length);
+               SkScriptEngine2::TypeOp op = (SkScriptEngine2::TypeOp) *opCode++;
+               SkASSERT(op < gOpNamesSize);
+               SkDebugf("%d: %s", opCode - start - 1, gOpNames[op].fName);
+               switch (op) {
+               case SkScriptEngine2::kCallback: {
+                       int index;
+                       memcpy(&index, opCode, sizeof(index));
+                       opCode += sizeof(index);
+                       SkDebugf(" index: %d", index);
+                       } break;
+               case SkScriptEngine2::kFunctionCall: 
+               case SkScriptEngine2::kMemberOp:
+               case SkScriptEngine2::kPropertyOp: {
+                       size_t ref;
+                       memcpy(&ref, opCode, sizeof(ref));
+                       opCode += sizeof(ref);
+                       SkDebugf(" ref: %d", ref);
+                       } break;
+               case SkScriptEngine2::kIntegerAccumulator:
+               case SkScriptEngine2::kIntegerOperand: {
+                       S32 integer;
+                       memcpy(&integer, opCode, sizeof(integer));
+                       opCode += sizeof(S32);
+                       SkDebugf(" integer: %d", integer);
+                       } break;
+               case SkScriptEngine2::kScalarAccumulator:
+               case SkScriptEngine2::kScalarOperand: {
+                       SkScalar scalar;
+                       memcpy(&scalar, opCode, sizeof(scalar));
+                       opCode += sizeof(SkScalar);
+#ifdef SK_CAN_USE_FLOAT
+                       SkDebugf(" scalar: %g", SkScalarToFloat(scalar));
+#else
+                       SkDebugf(" scalar: %x", scalar);
+#endif
+                       } break;
+               case SkScriptEngine2::kStringAccumulator:
+               case SkScriptEngine2::kStringOperand: {
+                       int size;
+                       SkString* strPtr = new SkString();
+                       memcpy(&size, opCode, sizeof(size));
+                       opCode += sizeof(size);
+                       strPtr->set((char*) opCode, size);
+                       opCode += size;
+                       SkDebugf(" string: %s", strPtr->c_str());
+                       delete strPtr;
+                       } break;
+               case SkScriptEngine2::kBoxToken: {
+                       SkOperand2::OpType type;
+                       memcpy(&type, opCode, sizeof(type));
+                       opCode += sizeof(type);
+                       int index = 0;
+                       if (type == 0)
+                               SkDebugf(" type: %s", gOperandNames[index].fName);
+                       else {
+                               while (type != 0) {
+                                       SkASSERT(index + 1 < gOperandNamesSize);
+                                       if (type & (1 << index)) {
+                                               type = (SkOperand2::OpType) (type & ~(1 << index));
+                                               SkDebugf(" type: %s", gOperandNames[index + 1].fName);
+                                       }
+                                       index++;
+                               }
+                       }
+                       } break;
+               case SkScriptEngine2::kIfOp:
+               case SkScriptEngine2::kLogicalAndInt:
+               case SkScriptEngine2::kElseOp:
+               case SkScriptEngine2::kLogicalOrInt: {
+                       int size;
+                       memcpy(&size, opCode, sizeof(size));
+                       opCode += sizeof(size);
+                       SkDebugf(" offset (address): %d (%d)", size, opCode - start + size);
+                       } break;
+               case SkScriptEngine2::kEnd:
+                       goto done;
+               case SkScriptEngine2::kNop:
+                               SkASSERT(0);
+       }
+       SkDebugf("\n");
+       } while (true);
+done:
+       SkDebugf("\n");
+}
+
+#endif
diff --git a/libs/graphics/animator/SkScriptRuntime.cpp b/libs/graphics/animator/SkScriptRuntime.cpp
new file mode 100755 (executable)
index 0000000..1851b00
--- /dev/null
@@ -0,0 +1,342 @@
+#include "SkScriptRuntime.h"
+#include "SkScript2.h"
+#include "SkParse.h"
+#include "SkScriptCallBack.h"
+#include "SkString.h"
+#include "SkOpArray.h"
+
+// script tokenizer
+
+// turn text into token string
+// turn number literals into inline UTF8-style values
+// process operators to turn standard notation into stack notation
+
+// defer processing until the tokens can all be resolved
+// then, turn token strings into indices into the appropriate tables / dictionaries
+
+// consider: const evaluation?
+
+// replace script string with script tokens preceeded by special value
+
+// need second version of script plugins that return private index of found value?
+       // then would need in script index of plugin, private index
+
+// encode brace stack push/pop as opcodes
+
+// should token script enocde type where possible?
+
+// current flow:
+       // strip whitespace
+       // if in array brace [ recurse, continue
+       // if token, handle function, or array, or property (continue)
+       // parse number, continue
+       // parse token, continue
+       // parse string literal, continue
+       // if dot operator, handle dot, continue
+       // if [ , handle array literal or accessor, continue
+       // if ), pop (if function, break)
+       // if ], pop ; if ',' break
+       // handle logical ops
+       // or, handle arithmetic ops
+       // loop
+
+// !!! things to do
+       // add separate processing loop to advance while suppressed
+       // or, include jump offset to skip suppressed code?
+
+SkScriptRuntime::~SkScriptRuntime() {
+       for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++)
+               delete *stringPtr;
+       for (SkOpArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++)
+               delete *arrayPtr;
+}
+
+bool SkScriptRuntime::executeTokens(unsigned char* opCode) {
+       SkOperand2 operand[2];  // 1=accumulator and 2=operand
+       SkScriptEngine2::TypeOp op;
+       size_t ref;
+       int index, size;
+       int registerLoad;
+       SkScriptCallBack* callBack SK_INIT_TO_AVOID_WARNING;
+       do {
+       switch ((op = (SkScriptEngine2::TypeOp) *opCode++)) {
+               case SkScriptEngine2::kArrayToken:      // create an array
+                       operand[0].fArray = new SkOpArray(SkOperand2::kNoType /*fReturnType*/);
+                       break;
+               case SkScriptEngine2::kArrayIndex:      // array accessor
+                       index = operand[1].fS32;
+                       if (index >= operand[0].fArray->count()) {
+                               fError = kArrayIndexOutOfBounds;
+                               return false;
+                       }
+                       operand[0] = operand[0].fArray->begin()[index];
+                       break;
+               case SkScriptEngine2::kArrayParam:      // array initializer, or function param
+                       *operand[0].fArray->append() = operand[1];
+                       break;
+               case SkScriptEngine2::kCallback:
+                       memcpy(&index, opCode, sizeof(index));
+                       opCode += sizeof(index);
+                       callBack = fCallBackArray[index];
+                       break;
+               case SkScriptEngine2::kFunctionCall: {
+                       memcpy(&ref, opCode, sizeof(ref));
+                       opCode += sizeof(ref);
+                       SkScriptCallBackFunction* callBackFunction = (SkScriptCallBackFunction*) callBack;
+                       if (callBackFunction->invoke(ref, operand[0].fArray, /* params */
+                                       &operand[0] /* result */) == false) {
+                               fError = kFunctionCallFailed;
+                               return false;
+                       }
+                       } break;
+               case SkScriptEngine2::kMemberOp: {
+                       memcpy(&ref, opCode, sizeof(ref));
+                       opCode += sizeof(ref);
+                       SkScriptCallBackMember* callBackMember = (SkScriptCallBackMember*) callBack;
+                       if (callBackMember->invoke(ref, operand[0].fObject, &operand[0]) == false) {
+                               fError = kMemberOpFailed;
+                               return false;
+                       }
+                       } break;
+               case SkScriptEngine2::kPropertyOp: {
+                       memcpy(&ref, opCode, sizeof(ref));
+                       opCode += sizeof(ref);
+                       SkScriptCallBackProperty* callBackProperty = (SkScriptCallBackProperty*) callBack;
+                       if (callBackProperty->getResult(ref, &operand[0])== false) {
+                               fError = kPropertyOpFailed;
+                               return false;
+                       }
+                       } break;
+               case SkScriptEngine2::kAccumulatorPop:
+                       fRunStack.pop(&operand[0]);
+                       break;
+               case SkScriptEngine2::kAccumulatorPush:
+                       *fRunStack.push() = operand[0];
+                       break;
+               case SkScriptEngine2::kIntegerAccumulator:
+               case SkScriptEngine2::kIntegerOperand:
+                       registerLoad = op - SkScriptEngine2::kIntegerAccumulator;
+                       memcpy(&operand[registerLoad].fS32, opCode, sizeof(S32));
+                       opCode += sizeof(S32);
+                       break;
+               case SkScriptEngine2::kScalarAccumulator:
+               case SkScriptEngine2::kScalarOperand:
+                       registerLoad = op - SkScriptEngine2::kScalarAccumulator;
+                       memcpy(&operand[registerLoad].fScalar, opCode, sizeof(SkScalar));
+                       opCode += sizeof(SkScalar);
+                       break;
+               case SkScriptEngine2::kStringAccumulator:
+               case SkScriptEngine2::kStringOperand: {
+                       SkString* strPtr = new SkString();
+                       track(strPtr);
+                       registerLoad = op - SkScriptEngine2::kStringAccumulator;
+                       memcpy(&size, opCode, sizeof(size));
+                       opCode += sizeof(size);
+                       strPtr->set((char*) opCode, size);
+                       opCode += size;
+                       operand[registerLoad].fString = strPtr;
+                       } break;
+               case SkScriptEngine2::kStringTrack: // call after kObjectToValue
+                       track(operand[0].fString);
+                       break;
+               case SkScriptEngine2::kBoxToken: {
+                       SkOperand2::OpType type;
+                       memcpy(&type, opCode, sizeof(type));
+                       opCode += sizeof(type);
+                       SkScriptCallBackConvert* callBackBox = (SkScriptCallBackConvert*) callBack;
+                       if (callBackBox->convert(type, &operand[0]) == false)
+                               return false;
+                       } break;
+               case SkScriptEngine2::kUnboxToken:
+               case SkScriptEngine2::kUnboxToken2: {
+                       SkScriptCallBackConvert* callBackUnbox = (SkScriptCallBackConvert*) callBack;
+                       if (callBackUnbox->convert(SkOperand2::kObject, &operand[0]) == false)
+                               return false;
+                       } break;
+               case SkScriptEngine2::kIfOp:
+               case SkScriptEngine2::kLogicalAndInt:
+                       memcpy(&size, opCode, sizeof(size));
+                       opCode += sizeof(size);
+                       if (operand[0].fS32 == 0)
+                               opCode += size; // skip to else (or end of if predicate)
+                       break;
+               case SkScriptEngine2::kElseOp:
+                       memcpy(&size, opCode, sizeof(size));
+                       opCode += sizeof(size);
+                       opCode += size; // if true: after predicate, always skip to end of else
+                       break;
+               case SkScriptEngine2::kLogicalOrInt:
+                       memcpy(&size, opCode, sizeof(size));
+                       opCode += sizeof(size);
+                       if (operand[0].fS32 != 0)
+                               opCode += size; // skip to kToBool opcode after || predicate
+                       break;
+               // arithmetic conversion ops
+               case SkScriptEngine2::kFlipOpsOp:
+                       SkTSwap(operand[0], operand[1]);
+                       break;
+               case SkScriptEngine2::kIntToString: 
+               case SkScriptEngine2::kIntToString2: 
+               case SkScriptEngine2::kScalarToString:
+               case SkScriptEngine2::kScalarToString2:{
+                       SkString* strPtr = new SkString();
+                       track(strPtr);
+                       if (op == SkScriptEngine2::kIntToString || op == SkScriptEngine2::kIntToString2)
+                               strPtr->appendS32(operand[op - SkScriptEngine2::kIntToString].fS32);
+                       else
+                               strPtr->appendScalar(operand[op - SkScriptEngine2::kScalarToString].fScalar);
+                       operand[0].fString = strPtr;
+                       } break;
+               case SkScriptEngine2::kIntToScalar:
+               case SkScriptEngine2::kIntToScalar2:
+                       operand[0].fScalar = SkScriptEngine2::IntToScalar(operand[op - SkScriptEngine2::kIntToScalar].fS32);
+                       break;
+               case SkScriptEngine2::kStringToInt:
+                       if (SkParse::FindS32(operand[0].fString->c_str(), &operand[0].fS32) == false)
+                               return false; 
+                       break;
+               case SkScriptEngine2::kStringToScalar:
+               case SkScriptEngine2::kStringToScalar2:
+                       if (SkParse::FindScalar(operand[0].fString->c_str(), 
+                                       &operand[op - SkScriptEngine2::kStringToScalar].fScalar) == false) 
+                               return false; 
+                       break;
+               case SkScriptEngine2::kScalarToInt:
+                       operand[0].fS32 = SkScalarFloor(operand[0].fScalar);
+                       break;
+               // arithmetic ops
+               case SkScriptEngine2::kAddInt:
+                       operand[0].fS32 += operand[1].fS32;
+                       break;
+               case SkScriptEngine2::kAddScalar:
+                       operand[0].fScalar += operand[1].fScalar;
+                       break;
+               case SkScriptEngine2::kAddString:
+//                     if (fTrackString.find(operand[1].fString) < 0) {
+//                             operand[1].fString = SkNEW_ARGS(SkString, (*operand[1].fString));
+//                             track(operand[1].fString);
+//                     }
+                       operand[0].fString->append(*operand[1].fString);
+                       break;
+               case SkScriptEngine2::kBitAndInt:
+                       operand[0].fS32 &= operand[1].fS32;
+                       break;
+               case SkScriptEngine2::kBitNotInt:
+                       operand[0].fS32 = ~operand[0].fS32;
+                       break;
+               case SkScriptEngine2::kBitOrInt:
+                       operand[0].fS32 |= operand[1].fS32;
+                       break;
+               case SkScriptEngine2::kDivideInt:
+                       SkASSERT(operand[1].fS32 != 0);
+                       if (operand[1].fS32 == 0)
+                               operand[0].fS32 = operand[0].fS32 == 0 ? SK_NaN32 : 
+                                       operand[0].fS32 > 0 ? SK_MaxS32 : -SK_MaxS32;
+                       else
+                       if (operand[1].fS32 != 0) // throw error on divide by zero?
+                               operand[0].fS32 /= operand[1].fS32;
+                       break;
+               case SkScriptEngine2::kDivideScalar:
+                       if (operand[1].fScalar == 0)
+                               operand[0].fScalar = operand[0].fScalar == 0 ? SK_ScalarNaN : 
+                                       operand[0].fScalar > 0 ? SK_ScalarMax : -SK_ScalarMax;
+                       else
+                               operand[0].fScalar = SkScalarDiv(operand[0].fScalar, operand[1].fScalar);
+                       break;
+               case SkScriptEngine2::kEqualInt:
+                       operand[0].fS32 = operand[0].fS32 == operand[1].fS32;
+                       break;
+               case SkScriptEngine2::kEqualScalar:
+                       operand[0].fS32 = operand[0].fScalar == operand[1].fScalar;
+                       break;
+               case SkScriptEngine2::kEqualString:
+                       operand[0].fS32 = *operand[0].fString == *operand[1].fString;
+                       break;
+               case SkScriptEngine2::kGreaterEqualInt:
+                       operand[0].fS32 = operand[0].fS32 >= operand[1].fS32;
+                       break;
+               case SkScriptEngine2::kGreaterEqualScalar:
+                       operand[0].fS32 = operand[0].fScalar >= operand[1].fScalar;
+                       break;
+               case SkScriptEngine2::kGreaterEqualString:
+                       operand[0].fS32 = strcmp(operand[0].fString->c_str(), operand[1].fString->c_str()) >= 0;
+                       break;
+               case SkScriptEngine2::kToBool:
+                       operand[0].fS32 = !! operand[0].fS32;
+                       break;
+               case SkScriptEngine2::kLogicalNotInt:
+                       operand[0].fS32 = ! operand[0].fS32;
+                       break;
+               case SkScriptEngine2::kMinusInt:
+                       operand[0].fS32 = -operand[0].fS32;
+                       break;
+               case SkScriptEngine2::kMinusScalar:
+                       operand[0].fScalar = -operand[0].fScalar;
+                       break;
+               case SkScriptEngine2::kModuloInt:
+                       operand[0].fS32 %= operand[1].fS32;
+                       break;
+               case SkScriptEngine2::kModuloScalar:
+                       operand[0].fScalar = SkScalarMod(operand[0].fScalar, operand[1].fScalar);
+                       break;
+               case SkScriptEngine2::kMultiplyInt:
+                       operand[0].fS32 *= operand[1].fS32;
+                       break;
+               case SkScriptEngine2::kMultiplyScalar:
+                       operand[0].fScalar = SkScalarMul(operand[0].fScalar, operand[1].fScalar);
+                       break;
+               case SkScriptEngine2::kShiftLeftInt:
+                       operand[0].fS32 <<= operand[1].fS32;
+                       break;
+               case SkScriptEngine2::kShiftRightInt:
+                       operand[0].fS32 >>= operand[1].fS32;
+                       break;
+               case SkScriptEngine2::kSubtractInt:
+                       operand[0].fS32 -= operand[1].fS32;
+                       break;
+               case SkScriptEngine2::kSubtractScalar:
+                       operand[0].fScalar -= operand[1].fScalar;
+                       break;
+               case SkScriptEngine2::kXorInt:
+                       operand[0].fS32 ^= operand[1].fS32;
+                       break;
+               case SkScriptEngine2::kEnd:
+                       goto done;
+               case SkScriptEngine2::kNop:
+                               SkASSERT(0);
+       }
+       } while (true);
+done:
+       fRunStack.push(operand[0]);
+       return true;
+}
+
+bool SkScriptRuntime::getResult(SkOperand2* result) {
+       if (fRunStack.count() == 0)
+               return false;
+       fRunStack.pop(result);
+       return true;
+}
+
+void SkScriptRuntime::track(SkOpArray* array) { 
+       SkASSERT(fTrackArray.find(array) < 0);  
+       *fTrackArray.append() = array; 
+}
+
+void SkScriptRuntime::track(SkString* string) { 
+       SkASSERT(fTrackString.find(string) < 0);  
+       *fTrackString.append() = string; 
+}
+
+void SkScriptRuntime::untrack(SkOpArray* array) {
+       int index = fTrackArray.find(array);
+       SkASSERT(index >= 0);
+       fTrackArray.begin()[index] = nil;
+}
+
+void SkScriptRuntime::untrack(SkString* string) {
+       int index = fTrackString.find(string);
+       SkASSERT(index >= 0);
+       fTrackString.begin()[index] = nil;
+}
+
diff --git a/libs/graphics/animator/SkScriptRuntime.h b/libs/graphics/animator/SkScriptRuntime.h
new file mode 100755 (executable)
index 0000000..75bf7db
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef SkScriptRuntime_DEFINED\r
+#define SkScriptRuntime_DEFINED\r
+\r
+#include "SkOperand2.h"\r
+#include "SkTDArray_Experimental.h"\r
+#include "SkTDStack.h"\r
+\r
+class SkScriptCallBack;\r
+\r
+typedef SkLongArray(SkString*) SkTDStringArray; \r
+typedef SkLongArray(SkScriptCallBack*) SkTDScriptCallBackArray; \r
+\r
+class SkScriptRuntime {\r
+public:\r
+       enum SkError {\r
+               kNoError,\r
+               kArrayIndexOutOfBounds,\r
+               kCouldNotFindReferencedID,\r
+               kFunctionCallFailed,\r
+               kMemberOpFailed,\r
+               kPropertyOpFailed\r
+       };\r
+\r
+       SkScriptRuntime(SkTDScriptCallBackArray& callBackArray) : fCallBackArray(callBackArray)\r
+               {  }\r
+       ~SkScriptRuntime();\r
+       bool executeTokens(unsigned char* opCode);\r
+       bool getResult(SkOperand2* result);\r
+       void untrack(SkOpArray* array);\r
+       void untrack(SkString* string);\r
+private:\r
+       void track(SkOpArray* array);\r
+       void track(SkString* string);\r
+       SkTDScriptCallBackArray& fCallBackArray;\r
+       SkError fError;\r
+       SkTDStack<SkOperand2> fRunStack;\r
+       SkLongArray(SkOpArray*) fTrackArray;\r
+       SkTDStringArray fTrackString;\r
+       // illegal\r
+       SkScriptRuntime& operator=(const SkScriptRuntime&);\r
+};\r
+\r
+#endif // SkScriptRuntime_DEFINED
\ No newline at end of file
diff --git a/libs/graphics/animator/SkScriptTokenizer.cpp b/libs/graphics/animator/SkScriptTokenizer.cpp
new file mode 100755 (executable)
index 0000000..e854807
--- /dev/null
@@ -0,0 +1,1513 @@
+#include "SkScript2.h"
+#include "SkMath.h"
+#include "SkParse.h"
+#include "SkScriptCallBack.h"
+#include "SkScriptRuntime.h"
+#include "SkString.h"
+#include "SkOpArray.h"
+
+const SkScriptEngine2::OperatorAttributes SkScriptEngine2::gOpAttributes[] = {
+{ SkOperand2::kNoType },
+{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), 
+    SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), kTowardsString },    // kAdd
+{ SkOperand2::kS32, SkOperand2::kS32, kNoBias }, // kBitAnd
+{ SkOperand2::kNoType, SkOperand2::kS32, kNoBias }, // kBitNot
+{ SkOperand2::kS32, SkOperand2::kS32, kNoBias }, // kBitOr
+{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), 
+    SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias }, // kDivide
+{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), 
+    SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar |SkOperand2:: kString), kTowardsNumber, 
+    kResultIsBoolean }, // kEqual
+{ SkOperand2::kS32 },     // kFlipOps
+{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), 
+    SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), kTowardsNumber,
+    kResultIsBoolean }, // kGreaterEqual
+{ SkOperand2::kNoType, SkOperand2::kS32, kNoBias }, // kLogicalAnd    (really, ToBool)
+{ SkOperand2::kNoType, SkOperand2::kS32, kNoBias }, // kLogicalNot
+{ SkOperand2::kS32, SkOperand2::kS32, kNoBias }, // kLogicalOr
+{ SkOperand2::kNoType, SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias }, // kMinus
+{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), 
+    SkOperand2::OpType(SkOperand2::kS32 |SkOperand2:: kScalar), kNoBias }, // kModulo
+{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), 
+    SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias }, // kMultiply
+{ SkOperand2::kS32, SkOperand2::kS32, kNoBias }, // kShiftLeft
+{ SkOperand2::kS32, SkOperand2::kS32, kNoBias }, // kShiftRight
+{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), 
+    SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias }, // kSubtract
+{ SkOperand2::kS32, SkOperand2::kS32, kNoBias } // kXor
+};
+
+#define kBracketPrecedence 16
+#define kIfElsePrecedence 15
+
+const signed char SkScriptEngine2::gPrecedence[] = {
+    17, // kUnassigned,
+    6, // kAdd,
+    10, // kBitAnd,
+    4, // kBitNot,
+    12, // kBitOr,
+    5, // kDivide,
+    9, // kEqual,
+    -1, // kFlipOps,
+    8, // kGreaterEqual,
+    13, // kLogicalAnd,
+    4, // kLogicalNot,
+    14, // kLogicalOr,
+    4, // kMinus,
+    5, // kModulo,
+    5, // kMultiply,
+    7, // kShiftLeft,
+    7, // kShiftRight,    // signed
+    6, // kSubtract,
+    11, // kXor
+    kBracketPrecedence, // kArrayOp
+    kIfElsePrecedence, // kElse
+    kIfElsePrecedence, // kIf
+    kBracketPrecedence, // kParen
+};
+
+const SkScriptEngine2::TypeOp SkScriptEngine2::gTokens[] = {
+    kNop, // unassigned
+    kAddInt, // kAdd,
+    kBitAndInt, // kBitAnd,
+    kBitNotInt, // kBitNot,
+    kBitOrInt, // kBitOr,
+    kDivideInt, // kDivide,
+    kEqualInt, // kEqual,
+    kFlipOpsOp, // kFlipOps,
+    kGreaterEqualInt, // kGreaterEqual,
+    kLogicalAndInt, // kLogicalAnd,
+    kLogicalNotInt, // kLogicalNot,
+    kLogicalOrInt, // kLogicalOr,
+    kMinusInt, // kMinus,
+    kModuloInt, // kModulo,
+    kMultiplyInt, // kMultiply,
+    kShiftLeftInt, // kShiftLeft,
+    kShiftRightInt, // kShiftRight,    // signed
+    kSubtractInt, // kSubtract,
+    kXorInt // kXor
+};
+
+static inline bool is_between(int c, int min, int max)
+{
+    return (unsigned)(c - min) <= (unsigned)(max - min);
+}
+
+static inline bool is_ws(int c)
+{
+    return is_between(c, 1, 32);
+}
+
+static int token_length(const char* start) {
+    char ch = start[0];
+    if (! is_between(ch, 'a' , 'z') &&  ! is_between(ch, 'A', 'Z') && ch != '_' && ch != '$')
+        return -1;
+    int length = 0;
+    do
+        ch = start[++length];
+    while (is_between(ch, 'a' , 'z') || is_between(ch, 'A', 'Z') || is_between(ch, '0', '9') ||
+           ch == '_' || ch == '$');
+    return length;
+}
+
+SkScriptEngine2::SkScriptEngine2(SkOperand2::OpType returnType) : fActiveStream(&fStream),
+fTokenLength(0), fReturnType(returnType), fError(kNoError), 
+fAccumulatorType(SkOperand2::kNoType),
+fBranchPopAllowed(true), fConstExpression(true), fOperandInUse(false)
+{
+    Branch branch(kUnassigned, 0, 0);
+    fBranchStack.push(branch);
+    *fOpStack.push() = (Op) kParen;
+}
+
+SkScriptEngine2::~SkScriptEngine2() {
+    for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++)
+        delete *stringPtr;
+    for (SkOpArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++)
+        delete *arrayPtr;
+}
+
+void SkScriptEngine2::addToken(SkScriptEngine2::TypeOp op) {
+    int limit = fBranchStack.count() - 1;
+    for (int index = 0; index < limit; index++) {
+        Branch& branch = fBranchStack.index(index);
+        if (branch.fPrimed == Branch::kIsPrimed)
+            resolveBranch(branch);
+    }
+    if (fBranchPopAllowed) {
+        while (fBranchStack.top().fDone == Branch::kIsDone)
+            fBranchStack.pop();
+    }
+    unsigned char charOp = (unsigned char) op;
+    fActiveStream->write(&charOp, sizeof(charOp));
+}
+
+void SkScriptEngine2::addTokenConst(SkScriptValue2* value, AddTokenRegister reg, 
+                                    SkOperand2::OpType toType, SkScriptEngine2::TypeOp op) {
+    if (value->fIsConstant == SkScriptValue2::kConstant && convertTo(toType, value))
+        return;
+    addTokenValue(*value, reg);
+    addToken(op);
+    value->fIsWritten = SkScriptValue2::kWritten;
+    value->fType = toType;
+}
+
+void SkScriptEngine2::addTokenInt(int integer) {
+    fActiveStream->write(&integer, sizeof(integer));
+}
+
+void SkScriptEngine2::addTokenScalar(SkScalar scalar) {
+    fActiveStream->write(&scalar, sizeof(scalar));
+}
+
+void SkScriptEngine2::addTokenString(const SkString& string) {
+    int size = string.size();
+    addTokenInt(size);
+    fActiveStream->write(string.c_str(), size);
+}
+
+void SkScriptEngine2::addTokenValue(const SkScriptValue2& value, AddTokenRegister reg) {
+    if (value.isConstant() == false) {
+        if (reg == kAccumulator) {
+            if (fAccumulatorType == SkOperand2::kNoType)
+                addToken(kAccumulatorPop);
+        } else {
+            ; // !!! incomplete?
+        }
+        return;
+    }
+    if (reg == kAccumulator && fAccumulatorType != SkOperand2::kNoType)
+        addToken(kAccumulatorPush);
+    switch (value.fType) {
+        case SkOperand2::kS32:
+            addToken(reg == kAccumulator ? kIntegerAccumulator : kIntegerOperand);
+            addTokenInt(value.fOperand.fS32);
+            if (reg == kAccumulator)
+                fAccumulatorType = SkOperand2::kS32;
+            else
+                fOperandInUse = true;
+            break;
+        case SkOperand2::kScalar:
+            addToken(reg == kAccumulator ? kScalarAccumulator : kScalarOperand);
+            addTokenScalar(value.fOperand.fScalar);
+            if (reg == kAccumulator)
+                fAccumulatorType = SkOperand2::kScalar;
+            else
+                fOperandInUse = true;
+            break;
+        case SkOperand2::kString:
+            addToken(reg == kAccumulator ? kStringAccumulator : kStringOperand);
+            addTokenString(*value.fOperand.fString);
+            if (reg == kAccumulator)
+                fAccumulatorType = SkOperand2::kString;
+            else
+                fOperandInUse = true;
+            break;
+        default:
+            SkASSERT(0); //!!! not implemented yet
+    }
+}
+
+int SkScriptEngine2::arithmeticOp(char ch, char nextChar, bool lastPush) {
+    Op op = kUnassigned;
+    bool reverseOperands = false;
+    bool negateResult = false;
+    int advance = 1;
+    switch (ch) {
+        case '+':
+            // !!! ignoring unary plus as implemented here has the side effect of
+            // suppressing errors like +"hi"
+            if (lastPush == false)    // unary plus, don't push an operator
+                goto returnAdv;
+            op = kAdd;
+            break;
+        case '-':
+            op = lastPush ? kSubtract : kMinus;
+            break;
+        case '*':
+            op = kMultiply;
+            break;
+        case '/':
+            op = kDivide;
+            break;
+        case '>':
+            if (nextChar == '>') {
+                op = kShiftRight;
+                goto twoChar;
+            } 
+            op = kGreaterEqual;
+            if (nextChar == '=')
+                goto twoChar;
+                reverseOperands = negateResult = true;
+            break;
+        case '<':
+            if (nextChar == '<') {
+                op = kShiftLeft;
+                goto twoChar;
+            }
+            op = kGreaterEqual;
+            reverseOperands = nextChar == '=';
+            negateResult = ! reverseOperands;
+            advance += reverseOperands;
+            break;
+        case '=':
+            if (nextChar == '=') {
+                op = kEqual;
+                goto twoChar;
+            }
+            break;
+        case '!':
+            if (nextChar == '=') {
+                op = kEqual;
+                negateResult = true;
+twoChar:
+                    advance++;
+                break;
+            } 
+            op = kLogicalNot;
+            break;
+        case '?':
+            op =(Op)  kIf;
+            break;
+        case ':':
+            op = (Op) kElse;
+            break;
+        case '^':
+            op = kXor;
+            break;
+        case '(':
+            *fOpStack.push() = (Op) kParen;
+            goto returnAdv;
+        case '&':
+            SkASSERT(nextChar != '&');
+            op = kBitAnd;
+            break;
+        case '|':
+            SkASSERT(nextChar != '|');
+            op = kBitOr;
+            break;
+        case '%':
+            op = kModulo;
+            break;
+        case '~':
+            op = kBitNot;
+            break;
+    }
+    if (op == kUnassigned)
+        return 0;
+    signed char precedence = gPrecedence[op];
+    do {
+        int idx = 0;
+        Op compare;
+        do {
+            compare = fOpStack.index(idx);
+            if ((compare & kArtificialOp) == 0)
+                break;
+            idx++;
+        } while (true);
+        signed char topPrecedence = gPrecedence[compare];
+        SkASSERT(topPrecedence != -1);
+        if (topPrecedence > precedence || topPrecedence == precedence && 
+            gOpAttributes[op].fLeftType == SkOperand2::kNoType) {
+            break;
+        }
+        processOp();
+    } while (true);
+    if (negateResult)
+        *fOpStack.push() = (Op) (kLogicalNot | kArtificialOp);
+    fOpStack.push(op);
+    if (reverseOperands)
+        *fOpStack.push() = (Op) (kFlipOps | kArtificialOp);
+returnAdv:
+        return advance;
+}
+
+bool SkScriptEngine2::convertParams(SkTDArray<SkScriptValue2>* params, 
+                                    const SkOperand2::OpType* paramTypes, int paramCount) {
+    int count = params->count();
+    if (count > paramCount) {
+        SkASSERT(0);
+        return false;    // too many parameters passed
+    }
+    for (int index = 0; index < count; index++) 
+        convertTo(paramTypes[index], &(*params)[index]);
+    return true;
+}
+
+bool SkScriptEngine2::convertTo(SkOperand2::OpType toType, SkScriptValue2* value ) {
+    SkOperand2::OpType type = value->fType;
+    if (type == toType)
+        return true;
+    if (type == SkOperand2::kObject) {
+        if (handleUnbox(value) == false)
+            return false;
+        return convertTo(toType, value);
+    }
+    return ConvertTo(this, toType, value);
+}
+
+bool SkScriptEngine2::evaluateDot(const char*& script) { 
+    size_t fieldLength = token_length(++script);        // skip dot
+    SkASSERT(fieldLength > 0); // !!! add error handling
+    const char* field = script;
+    script += fieldLength;
+    bool success = handleProperty();
+    if (success == false) {
+        fError = kCouldNotFindReferencedID;
+        goto error;
+    }
+    return evaluateDotParam(script, field, fieldLength);
+error:
+        return false;
+}
+
+bool SkScriptEngine2::evaluateDotParam(const char*& script, const char* field, size_t fieldLength) { 
+    SkScriptValue2& top = fValueStack.top();
+    if (top.fType != SkOperand2::kObject)
+        return false;
+    void* object = top.fOperand.fObject;
+    fValueStack.pop();
+    char ch; // see if it is a simple member or a function
+    while (is_ws(ch = script[0])) 
+        script++;
+    bool success = true;
+    if (ch != '(')
+        success = handleMember(field, fieldLength, object);
+    else {
+        SkTDArray<SkScriptValue2> params;
+        *fBraceStack.push() = kFunctionBrace;
+        success = functionParams(&script, &params);
+        if (success)
+            success = handleMemberFunction(field, fieldLength, object, &params);
+    }
+    return success; 
+}
+
+bool SkScriptEngine2::evaluateScript(const char** scriptPtr, SkScriptValue2* value) {
+    //    fArrayOffset = 0;        // no support for structures for now
+    bool success;
+    const char* inner;
+    if (strncmp(*scriptPtr, "#script:", sizeof("#script:") - 1) == 0) {
+        *scriptPtr += sizeof("#script:") - 1;
+        if (fReturnType == SkOperand2::kNoType || fReturnType == SkOperand2::kString) {
+            success = innerScript(scriptPtr, value);
+            SkASSERT(success);
+            inner = value->fOperand.fString->c_str();
+            scriptPtr = &inner;
+        }
+    }
+    success = innerScript(scriptPtr, value);
+    const char* script = *scriptPtr;
+    char ch;
+    while (is_ws(ch = script[0]))
+        script++;
+    if (ch != '\0') {
+        // error may trigger on scripts like "50,0" that were intended to be written as "[50, 0]"
+        return false;
+    }
+    return success;
+}
+
+void SkScriptEngine2::forget(SkOpArray* array) {
+    if (array->getType() == SkOperand2::kString) {
+        for (int index = 0; index < array->count(); index++) {
+            SkString* string = (*array)[index].fString;
+            int found = fTrackString.find(string);
+            if (found >= 0)
+                fTrackString.remove(found);
+        }
+        return;
+    }
+    if (array->getType() == SkOperand2::kArray) {
+        for (int index = 0; index < array->count(); index++) {
+            SkOpArray* child = (*array)[index].fArray;
+            forget(child);    // forgets children of child
+            int found = fTrackArray.find(child);
+            if (found >= 0)
+                fTrackArray.remove(found);
+        }
+    }
+}
+
+bool SkScriptEngine2::functionParams(const char** scriptPtr, SkTDArray<SkScriptValue2>* params) {
+    (*scriptPtr)++; // skip open paren
+    *fOpStack.push() = (Op) kParen;
+    *fBraceStack.push() = kFunctionBrace;
+    do {
+        SkScriptValue2 value;
+        bool success = innerScript(scriptPtr, &value);
+        SkASSERT(success);
+        if (success == false)
+            return false;
+        *params->append() = value;
+    } while ((*scriptPtr)[-1] == ',');
+    fBraceStack.pop();
+    fOpStack.pop(); // pop paren
+    (*scriptPtr)++; // advance beyond close paren
+    return true;
+}
+
+size_t SkScriptEngine2::getTokenOffset() {
+    return fActiveStream->getOffset();
+}
+
+SkOperand2::OpType SkScriptEngine2::getUnboxType(SkOperand2 scriptValue) {
+    for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
+        if ((*callBack)->getType() != SkScriptCallBack::kUnbox)
+            continue;
+        return (*callBack)->getReturnType(0, &scriptValue);
+    }
+    return SkOperand2::kObject;
+}
+
+bool SkScriptEngine2::innerScript(const char** scriptPtr, SkScriptValue2* value) {
+    const char* script = *scriptPtr;
+    char ch;
+    bool lastPush = false;
+    bool success = true;
+    int opBalance = fOpStack.count();
+    int baseBrace = fBraceStack.count();
+    int branchBalance = fBranchStack.count();
+    while ((ch = script[0]) != '\0') {
+        if (is_ws(ch)) {
+            script++;
+            continue;
+        }
+        SkScriptValue2 operand;
+        const char* dotCheck;
+        if (fBraceStack.count() > baseBrace) {
+            if (fBraceStack.top() == kArrayBrace) {
+                SkScriptValue2 tokenValue;
+                success = innerScript(&script, &tokenValue);    // terminate and return on comma, close brace
+                SkASSERT(success);
+                {
+                    SkOperand2::OpType type = fReturnType;
+                    if (fReturnType == SkOperand2::kNoType) {
+                        // !!! short sighted; in the future, allow each returned array component to carry 
+                        // its own type, and let caller do any needed conversions
+                        if (value->fOperand.fArray->count() == 0)
+                            value->fOperand.fArray->setType(type = tokenValue.fType);
+                        else
+                            type = value->fOperand.fArray->getType();
+                    }
+                    if (tokenValue.fType != type)
+                        convertTo(type, &tokenValue);
+                    *value->fOperand.fArray->append() = tokenValue.fOperand;
+                }
+                lastPush = false;
+                continue;
+            } else
+                SkASSERT(token_length(script) > 0);
+        }
+        if (lastPush != false && fTokenLength > 0) {
+            if (ch == '(') {
+                *fBraceStack.push() = kFunctionBrace;
+                SkString functionName(fToken, fTokenLength);
+                
+                if (handleFunction(&script) == false)
+                    return false;
+                lastPush = true;
+                continue;
+            } else if (ch == '[') {
+                if (handleProperty() == false) {
+                    SkASSERT(0);
+                    return false;
+                }
+                if (handleArrayIndexer(&script) == false)
+                    return false;
+                lastPush = true;
+                continue;
+            } else if (ch != '.') {
+                if (handleProperty() == false) {
+                    SkASSERT(0);
+                    return false;
+                }
+                lastPush = true;
+                continue;
+            }
+        }
+        if (ch == '0' && (script[1] & ~0x20) == 'X') {
+            SkASSERT(lastPush == false);
+            script += 2;
+            script = SkParse::FindHex(script, (uint32_t*) &operand.fOperand.fS32);
+            SkASSERT(script);
+            goto intCommon;
+        }
+        if (lastPush == false && ch == '.')
+            goto scalarCommon;
+        if (ch >= '0' && ch <= '9') {
+            SkASSERT(lastPush == false);
+            dotCheck = SkParse::FindS32(script, &operand.fOperand.fS32);
+            if (dotCheck[0] != '.') {
+                script = dotCheck;
+intCommon:
+                operand.fType = SkOperand2::kS32;
+            } else {
+scalarCommon:
+                script = SkParse::FindScalar(script, &operand.fOperand.fScalar);
+                operand.fType = SkOperand2::kScalar;
+            }
+            operand.fIsConstant = SkScriptValue2::kConstant;
+            fValueStack.push(operand);
+            lastPush = true;
+            continue;
+        }
+        int length = token_length(script);
+        if (length > 0) {
+            SkASSERT(lastPush == false);
+            fToken = script;
+            fTokenLength = length;
+            script += length;
+            lastPush = true;
+            continue;
+        }
+        char startQuote = ch;
+        if (startQuote == '\'' || startQuote == '\"') {
+            SkASSERT(lastPush == false);
+            operand.fOperand.fString = new SkString();
+            ++script;
+            const char* stringStart = script;
+            do {    // measure string
+                if (script[0] == '\\')
+                    ++script;
+                ++script;
+                SkASSERT(script[0]); // !!! throw an error
+            } while (script[0] != startQuote);
+            operand.fOperand.fString->set(stringStart, script - stringStart);
+            script = stringStart;
+            char* stringWrite = operand.fOperand.fString->writable_str();
+            do {    // copy string
+                if (script[0] == '\\')
+                    ++script;
+                *stringWrite++ = script[0];
+                ++script;
+                SkASSERT(script[0]); // !!! throw an error
+            } while (script[0] != startQuote);
+            ++script;
+            track(operand.fOperand.fString);
+            operand.fType = SkOperand2::kString;
+            operand.fIsConstant = SkScriptValue2::kConstant;
+            fValueStack.push(operand);
+            lastPush = true;
+            continue;
+        }
+        if (ch ==  '.') {
+            if (fTokenLength == 0) {
+                SkScriptValue2 scriptValue;
+                SkDEBUGCODE(scriptValue.fOperand.fObject = nil);
+                int tokenLength = token_length(++script);
+                const char* token = script;
+                script += tokenLength;
+                SkASSERT(fValueStack.count() > 0); // !!! add error handling
+                SkScriptValue2 top;
+                fValueStack.pop(&top);
+                
+                addTokenInt(top.fType);
+                addToken(kBoxToken);
+                top.fType = SkOperand2::kObject;
+                top.fIsConstant = SkScriptValue2::kVariable;
+                fConstExpression = false;
+                fValueStack.push(top);
+                success = evaluateDotParam(script, token, tokenLength);
+                SkASSERT(success);
+                lastPush = true;
+                continue; 
+            }
+            // get next token, and evaluate immediately
+            success = evaluateDot(script);
+            if (success == false) {
+                //                SkASSERT(0);
+                return false;
+            }
+            lastPush = true;
+            continue;
+        }
+        if (ch == '[') {
+            if (lastPush == false) {
+                script++;
+                *fBraceStack.push() = kArrayBrace;
+                operand.fOperand.fArray = value->fOperand.fArray = new SkOpArray(fReturnType);
+                track(value->fOperand.fArray);
+                
+                operand.fType = SkOperand2::kArray;
+                operand.fIsConstant = SkScriptValue2::kVariable;
+                fValueStack.push(operand);
+                continue;
+            }
+            if (handleArrayIndexer(&script) == false)
+                return false;
+            lastPush = true;
+            continue;
+        }
+#if 0 // structs not supported for now
+        if (ch == '{') {
+            if (lastPush == false) {
+                script++;
+                *fBraceStack.push() = kStructBrace;
+                operand.fS32 = 0;
+                *fTypeStack.push() = (SkOpType) kStruct;
+                fOperandStack.push(operand);
+                continue;
+            }
+            SkASSERT(0); // braces in other contexts aren't supported yet
+        }
+#endif
+        if (ch == ')' && fBraceStack.count() > 0) {
+            BraceStyle braceStyle = fBraceStack.top(); 
+            if (braceStyle == kFunctionBrace) {
+                fBraceStack.pop();
+                break;
+            }
+        }
+        if (ch == ',' || ch == ']') {
+            if (ch != ',') {
+                BraceStyle match;
+                fBraceStack.pop(&match);
+                SkASSERT(match == kArrayBrace);
+            }
+            script++;
+            // !!! see if brace or bracket is correct closer
+            break;
+        }
+        char nextChar = script[1];
+        int advance = logicalOp(ch, nextChar);
+        if (advance == 0) 
+            advance = arithmeticOp(ch, nextChar, lastPush);
+        if (advance == 0) // unknown token
+            return false;
+        if (advance > 0)
+            script += advance;
+        lastPush = ch == ']' || ch == ')';
+    }
+    if (fTokenLength > 0) {
+        success = handleProperty();
+        SkASSERT(success);
+    }
+    int branchIndex = 0;
+    branchBalance = fBranchStack.count() - branchBalance;
+    fBranchPopAllowed = false;
+    while (branchIndex < branchBalance) {
+        Branch& branch = fBranchStack.index(branchIndex++);
+        if (branch.fPrimed == Branch::kIsPrimed)
+            break;
+        Op branchOp = branch.fOperator;
+        SkOperand2::OpType lastType = fValueStack.top().fType;
+        addTokenValue(fValueStack.top(), kAccumulator);
+        fValueStack.pop();
+        if (branchOp == kLogicalAnd || branchOp == kLogicalOr) {
+            if (branch.fOperator == kLogicalAnd)
+                branch.prime();
+            addToken(kToBool);
+        } else {
+            resolveBranch(branch);
+            SkScriptValue2 operand;
+            operand.fType = lastType;
+            // !!! note that many branching expressions could be constant
+            // today, we always evaluate branches as returning variables
+            operand.fIsConstant = SkScriptValue2::kVariable;
+            fValueStack.push(operand);
+        }
+        if (branch.fDone == Branch::kIsNotDone)
+            branch.prime();
+    }
+    fBranchPopAllowed = true;
+    while (fBranchStack.top().fDone == Branch::kIsDone)
+        fBranchStack.pop();
+    while (fOpStack.count() > opBalance) {     // leave open paren
+        if (processOp() == false)
+            return false;
+    }
+    SkOperand2::OpType topType = fValueStack.count() > 0 ? fValueStack.top().fType : SkOperand2::kNoType;
+    if (topType != fReturnType &&
+        topType == SkOperand2::kString && fReturnType != SkOperand2::kNoType) { // if result is a string, give handle property a chance to convert it to the property value
+        SkString* string = fValueStack.top().fOperand.fString;
+        fToken = string->c_str();
+        fTokenLength = string->size();
+        fValueStack.pop();
+        success = handleProperty();
+        if (success == false) {    // if it couldn't convert, return string (error?)
+            SkScriptValue2 operand;
+            operand.fType = SkOperand2::kString;
+            operand.fOperand.fString = string;
+            operand.fIsConstant = SkScriptValue2::kVariable;     // !!! ?
+            fValueStack.push(operand);
+        }
+    }
+    if (fStream.getOffset() > 0) {
+        addToken(kEnd);
+#ifdef SK_DEBUG
+        decompile((const unsigned char*)fStream.getStream(), fStream.getOffset());
+#endif
+        SkScriptRuntime runtime(fCallBackArray);
+        runtime.executeTokens((unsigned char*) fStream.getStream());
+        SkScriptValue2 value1;
+        runtime.getResult(&value1.fOperand);
+        value1.fType = fReturnType;
+        fValueStack.push(value1);
+    }
+    if (value) {
+        if (fValueStack.count() == 0)
+            return false;
+        fValueStack.pop(value);
+        if (value->fType != fReturnType && value->fType == SkOperand2::kObject && 
+            fReturnType != SkOperand2::kNoType)
+            convertTo(fReturnType, value);
+    }
+    //    if (fBranchStack.top().fOpStackDepth > fOpStack.count())
+    //        resolveBranch();
+    *scriptPtr = script;
+    return true; // no error
+}
+
+bool SkScriptEngine2::handleArrayIndexer(const char** scriptPtr) {
+    SkScriptValue2 scriptValue;
+    (*scriptPtr)++;
+    *fOpStack.push() = (Op) kParen;
+    *fBraceStack.push() = kArrayBrace;
+    SkOperand2::OpType saveType = fReturnType;
+    fReturnType = SkOperand2::kS32;
+    bool success = innerScript(scriptPtr, &scriptValue);
+    fReturnType = saveType;
+    SkASSERT(success);
+    success = convertTo(SkOperand2::kS32, &scriptValue);
+    SkASSERT(success);
+    int index = scriptValue.fOperand.fS32;
+    fValueStack.pop(&scriptValue);
+    if (scriptValue.fType == SkOperand2::kObject) {
+        success = handleUnbox(&scriptValue);
+        SkASSERT(success);
+        SkASSERT(scriptValue.fType == SkOperand2::kArray);
+    }
+    scriptValue.fType = scriptValue.fOperand.fArray->getType();
+    //    SkASSERT(index >= 0);
+    if ((unsigned) index >= (unsigned) scriptValue.fOperand.fArray->count()) {
+        fError = kArrayIndexOutOfBounds;
+        return false;
+    }
+    scriptValue.fOperand = scriptValue.fOperand.fArray->begin()[index];
+    scriptValue.fIsConstant = SkScriptValue2::kVariable;
+    fValueStack.push(scriptValue);
+    fOpStack.pop(); // pop paren
+    return success;
+}
+
+bool SkScriptEngine2::handleFunction(const char** scriptPtr) {
+    const char* functionName = fToken;
+    size_t functionNameLen = fTokenLength;
+    fTokenLength = 0;
+    SkTDArray<SkScriptValue2> params;
+    bool success = functionParams(scriptPtr, &params);
+    if (success == false)
+        goto done;
+    {
+        for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
+            if ((*callBack)->getType() != SkScriptCallBack::kFunction)
+                continue;
+            SkScriptValue2 callbackResult;
+            success = (*callBack)->getReference(functionName, functionNameLen, &callbackResult);
+            if (success) {
+                callbackResult.fType = (*callBack)->getReturnType(callbackResult.fOperand.fReference, nil);
+                callbackResult.fIsConstant = SkScriptValue2::kVariable;
+                fValueStack.push(callbackResult);
+                goto done;
+            }
+        }
+    }
+    return false;
+done:
+        fOpStack.pop();
+    return success;
+}
+
+bool SkScriptEngine2::handleMember(const char* field, size_t len, void* object) {
+    bool success = true;
+    for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
+        if ((*callBack)->getType() != SkScriptCallBack::kMember)
+            continue;
+        SkScriptValue2 callbackResult;
+        success = (*callBack)->getReference(field, len, &callbackResult);
+        if (success) {
+            if (callbackResult.fType == SkOperand2::kString)
+                track(callbackResult.fOperand.fString);
+            callbackResult.fIsConstant = SkScriptValue2::kVariable;
+            fValueStack.push(callbackResult);
+            goto done;
+        }
+    }
+    return false;
+done:
+        return success;
+}
+
+bool SkScriptEngine2::handleMemberFunction(const char* field, size_t len, void* object, 
+                                           SkTDArray<SkScriptValue2>* params) {
+    bool success = true;
+    for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
+        if ((*callBack)->getType() != SkScriptCallBack::kMemberFunction)
+            continue;
+        SkScriptValue2 callbackResult;
+        success = (*callBack)->getReference(field, len, &callbackResult);
+        if (success) {
+            if (callbackResult.fType == SkOperand2::kString)
+                track(callbackResult.fOperand.fString);
+            callbackResult.fIsConstant = SkScriptValue2::kVariable;
+            fValueStack.push(callbackResult);
+            goto done;
+        }
+    }
+    return false;
+done:
+        return success;
+}
+
+bool SkScriptEngine2::handleProperty() {
+    bool success = true;
+    for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
+        if ((*callBack)->getType() != SkScriptCallBack::kProperty)
+            continue;
+        SkScriptValue2 callbackResult;
+        success = (*callBack)->getReference(fToken, fTokenLength, &callbackResult);
+        if (success) {
+            if (callbackResult.fType == SkOperand2::kString && callbackResult.fOperand.fString == nil) {
+                callbackResult.fOperand.fString = new SkString(fToken, fTokenLength);
+                track(callbackResult.fOperand.fString);
+            }
+            callbackResult.fIsConstant = SkScriptValue2::kVariable;
+            fValueStack.push(callbackResult);
+            goto done;
+        }
+    }
+done:
+        fTokenLength = 0;
+    return success;
+}
+
+bool SkScriptEngine2::handleUnbox(SkScriptValue2* scriptValue) {
+    bool success = true;
+    for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
+        if ((*callBack)->getType() != SkScriptCallBack::kUnbox)
+            continue;
+        SkScriptCallBackConvert* callBackConvert = (SkScriptCallBackConvert*) *callBack;
+        success = callBackConvert->convert(scriptValue->fType, &scriptValue->fOperand);
+        if (success) {
+            if (scriptValue->fType == SkOperand2::kString)
+                track(scriptValue->fOperand.fString);
+            goto done;
+        }
+    }
+    return false;
+done:
+        return success;
+}
+
+// note that entire expression is treated as if it were enclosed in parens
+// an open paren is always the first thing in the op stack
+
+int SkScriptEngine2::logicalOp(char ch, char nextChar) {
+    int advance = 1;
+    Op op;
+    signed char precedence;
+    switch (ch) {
+        case ')':
+            op = (Op) kParen;
+            break;
+        case ']':
+            op = (Op) kArrayOp;
+            break;
+        case '?':
+            op = (Op) kIf;
+            break;
+        case ':':
+            op = (Op) kElse;
+            break;
+        case '&':
+            if (nextChar != '&')
+                goto noMatch;
+            op = kLogicalAnd;
+            advance = 2;
+            break;
+        case '|':
+            if (nextChar != '|')
+                goto noMatch;
+            op = kLogicalOr;
+            advance = 2;
+            break;
+        default:
+            noMatch:
+            return 0;
+    }
+    precedence = gPrecedence[op];
+    int branchIndex = 0;
+    fBranchPopAllowed = false;
+    do {
+        while (gPrecedence[fOpStack.top() & ~kArtificialOp] < precedence)
+            processOp();
+        Branch& branch = fBranchStack.index(branchIndex++);
+        Op branchOp = branch.fOperator;
+        if (gPrecedence[branchOp] >= precedence)
+            break;
+        addTokenValue(fValueStack.top(), kAccumulator);
+        fValueStack.pop();
+        if (branchOp == kLogicalAnd || branchOp == kLogicalOr) {
+            if (branch.fOperator == kLogicalAnd)
+                branch.prime();
+            addToken(kToBool);
+        } else
+            resolveBranch(branch);
+        if (branch.fDone == Branch::kIsNotDone)
+            branch.prime();
+    } while (true);
+    fBranchPopAllowed = true;
+    while (fBranchStack.top().fDone == Branch::kIsDone)
+        fBranchStack.pop();
+    processLogicalOp(op);
+    return advance;
+}
+
+void SkScriptEngine2::processLogicalOp(Op op) {
+    switch (op) {
+        case kParen:
+        case kArrayOp:
+            SkASSERT(fOpStack.count() > 1 && fOpStack.top() == op);    // !!! add error handling
+            if (op == kParen) 
+                fOpStack.pop();
+            else {
+                SkScriptValue2 value;
+                fValueStack.pop(&value);
+                SkASSERT(value.fType == SkOperand2::kS32 || value.fType == SkOperand2::kScalar); // !!! add error handling (although, could permit strings eventually)
+                int index = value.fType == SkOperand2::kScalar ? SkScalarFloor(value.fOperand.fScalar) : 
+                    value.fOperand.fS32;
+                SkScriptValue2 arrayValue;
+                fValueStack.pop(&arrayValue);
+                SkASSERT(arrayValue.fType == SkOperand2::kArray);  // !!! add error handling
+                SkOpArray* array = arrayValue.fOperand.fArray;
+                SkOperand2 operand;
+                bool success = array->getIndex(index, &operand);
+                SkASSERT(success); // !!! add error handling
+                SkScriptValue2 resultValue;
+                resultValue.fType = array->getType();
+                resultValue.fOperand = operand;
+                resultValue.fIsConstant = SkScriptValue2::kVariable;
+                fValueStack.push(resultValue);
+            }
+                break;
+        case kIf: {
+            if (fAccumulatorType == SkOperand2::kNoType) {
+                addTokenValue(fValueStack.top(), kAccumulator);
+                fValueStack.pop();
+            }
+            SkASSERT(fAccumulatorType != SkOperand2::kString); // !!! add error handling
+            addToken(kIfOp);
+            Branch branch(op, fOpStack.count(), getTokenOffset());
+            *fBranchStack.push() = branch;
+            addTokenInt(0); // placeholder for future branch
+            fAccumulatorType = SkOperand2::kNoType;
+        } break;
+        case kElse: {
+            addTokenValue(fValueStack.top(), kAccumulator);
+            fValueStack.pop();
+            addToken(kElseOp);
+            size_t newOffset = getTokenOffset();
+            addTokenInt(0); // placeholder for future branch
+            Branch& branch = fBranchStack.top();
+            resolveBranch(branch);
+            branch.fOperator = op;
+            branch.fDone = Branch::kIsNotDone;
+            SkASSERT(branch.fOpStackDepth == fOpStack.count());
+            branch.fOffset = newOffset;
+            fAccumulatorType = SkOperand2::kNoType;
+        } break;
+        case kLogicalAnd:
+        case kLogicalOr: {
+            Branch& oldTop = fBranchStack.top();
+            Branch::Primed wasPrime = oldTop.fPrimed;
+            Branch::Done wasDone = oldTop.fDone;
+            oldTop.fPrimed = Branch::kIsNotPrimed;
+            oldTop.fDone = Branch::kIsNotDone;
+            if (fAccumulatorType == SkOperand2::kNoType) {
+                SkASSERT(fValueStack.top().fType == SkOperand2::kS32); // !!! add error handling, and conversion to int?
+                addTokenValue(fValueStack.top(), kAccumulator);
+                fValueStack.pop();
+            } else
+                SkASSERT(fAccumulatorType == SkOperand2::kS32);
+            // if 'and', write beq goto opcode after end of predicate (after to bool)
+            // if 'or', write bne goto to bool
+            addToken(op == kLogicalAnd ? kLogicalAndInt : kLogicalOrInt);
+            Branch branch(op, fOpStack.count(), getTokenOffset());
+            addTokenInt(0); // placeholder for future branch            
+            oldTop.fPrimed = wasPrime;
+            oldTop.fDone = wasDone;
+            *fBranchStack.push() = branch;
+            fAccumulatorType = SkOperand2::kNoType;
+        }    break;
+        default:
+            SkASSERT(0);
+    }
+}
+
+bool SkScriptEngine2::processOp() {
+    Op op;
+    fOpStack.pop(&op);
+    op = (Op) (op & ~kArtificialOp);
+    const OperatorAttributes* attributes = &gOpAttributes[op];
+    SkScriptValue2 value1 = { 0 };
+    SkScriptValue2 value2;
+    fValueStack.pop(&value2);
+    value2.fIsWritten = SkScriptValue2::kUnwritten;
+    //    SkScriptEngine2::SkTypeOp convert1[3];
+    //    SkScriptEngine2::SkTypeOp convert2[3];
+    //    SkScriptEngine2::SkTypeOp* convert2Ptr = convert2;
+    bool constantOperands = value2.fIsConstant == SkScriptValue2::kConstant;
+    if (attributes->fLeftType != SkOperand2::kNoType) {
+        fValueStack.pop(&value1);
+        constantOperands &= value1.fIsConstant == SkScriptValue2::kConstant; 
+        value1.fIsWritten = SkScriptValue2::kUnwritten;
+        if (op == kFlipOps) {
+            SkTSwap(value1, value2);
+            fOpStack.pop(&op);
+            op = (Op) (op & ~kArtificialOp);
+            attributes = &gOpAttributes[op];
+            if (constantOperands == false)
+                addToken(kFlipOpsOp);
+        }
+        if (value1.fType == SkOperand2::kObject && (value1.fType & attributes->fLeftType) == 0) {
+            value1.fType = getUnboxType(value1.fOperand);
+            addToken(kUnboxToken);
+        }
+    }
+    if (value2.fType == SkOperand2::kObject && (value2.fType & attributes->fLeftType) == 0) {
+        value1.fType = getUnboxType(value2.fOperand);
+        addToken(kUnboxToken2);
+    }
+    if (attributes->fLeftType != SkOperand2::kNoType) {
+        if (value1.fType != value2.fType) {
+            if ((attributes->fLeftType & SkOperand2::kString) && attributes->fBias & kTowardsString && 
+                ((value1.fType | value2.fType) & SkOperand2::kString)) {
+                if (value1.fType == SkOperand2::kS32 || value1.fType == SkOperand2::kScalar) {
+                    addTokenConst(&value1, kAccumulator, SkOperand2::kString, 
+                                  value1.fType == SkOperand2::kS32 ? kIntToString : kScalarToString);
+                }
+                if (value2.fType == SkOperand2::kS32 || value2.fType == SkOperand2::kScalar) {
+                    addTokenConst(&value2, kOperand, SkOperand2::kString, 
+                                  value2.fType == SkOperand2::kS32 ? kIntToString2 : kScalarToString2);
+                }
+            } else if (attributes->fLeftType & SkOperand2::kScalar && ((value1.fType | value2.fType) & 
+                                                                       SkOperand2::kScalar)) {
+                if (value1.fType == SkOperand2::kS32)
+                    addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kIntToScalar);
+                if (value2.fType == SkOperand2::kS32)
+                    addTokenConst(&value2, kOperand, SkOperand2::kScalar, kIntToScalar2);
+            }
+        }
+        if ((value1.fType & attributes->fLeftType) == 0 || value1.fType != value2.fType) {
+            if (value1.fType == SkOperand2::kString)
+                addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kStringToScalar);
+            if (value1.fType == SkOperand2::kScalar && (attributes->fLeftType == SkOperand2::kS32 || 
+                                                        value2.fType == SkOperand2::kS32))
+                addTokenConst(&value1, kAccumulator, SkOperand2::kS32, kScalarToInt);
+        }
+    }
+    AddTokenRegister rhRegister = attributes->fLeftType != SkOperand2::kNoType ?
+        kOperand : kAccumulator;
+    if ((value2.fType & attributes->fRightType) == 0 || value1.fType != value2.fType) {
+        if (value2.fType == SkOperand2::kString)
+            addTokenConst(&value2, rhRegister, SkOperand2::kScalar, kStringToScalar2);
+        if (value2.fType == SkOperand2::kScalar && (attributes->fRightType == SkOperand2::kS32 || 
+                                                    value1.fType == SkOperand2::kS32))
+            addTokenConst(&value2, rhRegister, SkOperand2::kS32, kScalarToInt2);
+    }
+    TypeOp typeOp = gTokens[op];
+    if (value2.fType == SkOperand2::kScalar)
+        typeOp = (TypeOp) (typeOp + 1);
+    else if (value2.fType == SkOperand2::kString)
+        typeOp = (TypeOp) (typeOp + 2);
+    SkDynamicMemoryWStream stream;
+    SkOperand2::OpType saveType;
+    SkBool saveOperand;
+    if (constantOperands) {
+        fActiveStream = &stream;
+        saveType = fAccumulatorType;
+        saveOperand = fOperandInUse;
+        fAccumulatorType = SkOperand2::kNoType;
+        fOperandInUse = false;
+    }
+    if (attributes->fLeftType != SkOperand2::kNoType) {    // two operands
+        if (value1.fIsWritten == SkScriptValue2::kUnwritten)
+            addTokenValue(value1, kAccumulator);
+    }
+    if (value2.fIsWritten == SkScriptValue2::kUnwritten)
+        addTokenValue(value2, rhRegister);
+    addToken(typeOp);
+    if (constantOperands) {
+        addToken(kEnd);
+#ifdef SK_DEBUG        
+        decompile((const unsigned char*) stream.getStream(), stream.getOffset());
+#endif
+        SkScriptRuntime runtime(fCallBackArray);
+        runtime.executeTokens((unsigned char*) stream.getStream());
+        runtime.getResult(&value1.fOperand);
+        if (attributes->fResultIsBoolean == kResultIsBoolean)
+            value1.fType = SkOperand2::kS32;
+        else if (attributes->fLeftType == SkOperand2::kNoType) // unary operand
+            value1.fType = value2.fType;
+        fValueStack.push(value1);
+        if (value1.fType == SkOperand2::kString)
+            runtime.untrack(value1.fOperand.fString);
+        else if (value1.fType == SkOperand2::kArray)
+            runtime.untrack(value1.fOperand.fArray);
+        fActiveStream = &fStream;
+        fAccumulatorType = saveType;
+        fOperandInUse = saveOperand;
+        return true;
+    }
+    value2.fIsConstant = SkScriptValue2::kVariable;
+    fValueStack.push(value2);
+    return true;
+}
+
+void SkScriptEngine2::Branch::resolve(SkDynamicMemoryWStream* stream, size_t off) {
+    SkASSERT(fDone == kIsNotDone);
+    fPrimed = kIsNotPrimed;
+    fDone = kIsDone;
+    SkASSERT(off > fOffset + sizeof(size_t));
+    size_t offset = off - fOffset - sizeof(offset);
+    stream->write(&offset, fOffset, sizeof(offset));
+}
+
+void SkScriptEngine2::resolveBranch(SkScriptEngine2::Branch& branch) {
+    branch.resolve(fActiveStream, getTokenOffset());
+}
+
+bool SkScriptEngine2::ConvertTo(SkScriptEngine2* engine, SkOperand2::OpType toType, SkScriptValue2* value ) {
+    SkASSERT(value);
+    SkOperand2::OpType type = value->fType;
+    if (type == toType) 
+        return true;
+    SkOperand2& operand = value->fOperand;
+    bool success = true;
+    switch (toType) {
+        case SkOperand2::kS32:
+            if (type == SkOperand2::kScalar)
+                operand.fS32 = SkScalarFloor(operand.fScalar);
+            else {
+                SkASSERT(type == SkOperand2::kString);
+                success = SkParse::FindS32(operand.fString->c_str(), &operand.fS32) != nil;
+            }
+                break;
+        case SkOperand2::kScalar:
+            if (type == SkOperand2::kS32)
+                operand.fScalar = IntToScalar(operand.fS32);
+            else {
+                SkASSERT(type == SkOperand2::kString);
+                success = SkParse::FindScalar(operand.fString->c_str(), &operand.fScalar) != nil;
+            }
+                break;
+        case SkOperand2::kString: {
+            SkString* strPtr = new SkString();
+            SkASSERT(engine);
+            engine->track(strPtr);
+            if (type == SkOperand2::kS32)
+                strPtr->appendS32(operand.fS32);
+            else {
+                SkASSERT(type == SkOperand2::kScalar);
+                strPtr->appendScalar(operand.fScalar);
+            }
+            operand.fString = strPtr;
+        } break;
+        case SkOperand2::kArray: {
+            SkOpArray* array = new SkOpArray(type);
+            *array->append() = operand;
+            engine->track(array);
+            operand.fArray = array;
+        } break;
+        default:
+            SkASSERT(0);
+    }
+    value->fType = toType;
+    return success;
+}
+
+SkScalar SkScriptEngine2::IntToScalar(S32 s32) {
+    SkScalar scalar;
+    if (s32 == SK_NaN32)
+        scalar = SK_ScalarNaN;
+    else if (SkAbs32(s32) == SK_MaxS32)
+        scalar = SkSign32(s32) * SK_ScalarMax;
+    else
+        scalar = SkIntToScalar(s32);
+    return scalar;
+}
+
+bool SkScriptEngine2::ValueToString(const SkScriptValue2& value, SkString* string) {
+    switch (value.fType) {
+        case SkOperand2::kS32:
+            string->reset();
+            string->appendS32(value.fOperand.fS32);
+            break;
+        case SkOperand2::kScalar:
+            string->reset();
+            string->appendScalar(value.fOperand.fScalar);
+            break;
+        case SkOperand2::kString:
+            string->set(*value.fOperand.fString);
+            break;
+        default:
+            SkASSERT(0);
+            return false;
+    }
+    return true; // no error
+}
+
+#ifdef SK_DEBUG
+
+#define testInt(expression) { #expression, SkOperand2::kS32, expression }
+#ifdef SK_SCALAR_IS_FLOAT
+#define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (float) expression }
+#define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, fmodf(exp1, exp2) }
+#else
+#ifdef SK_CAN_USE_FLOAT
+#define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (int) ((expression) * 65536.0f) }
+#define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, (int) (fmod(exp1, exp2)  * 65536.0f) }
+#endif
+#endif
+#define testTrue(expression) { #expression, SkOperand2::kS32, 1 }
+#define testFalse(expression) { #expression, SkOperand2::kS32, 0 }
+
+#if !defined(SK_BUILD_FOR_BREW)
+static const SkScriptNAnswer2 scriptTests[]  = {
+    testInt(1||0&&3),
+#ifdef SK_CAN_USE_FLOAT
+    testScalar(- -5.5- -1.5),
+    testScalar(1.0+5), 
+#endif
+    testInt((6+7)*8),
+    testInt(3*(4+5)),
+#ifdef SK_CAN_USE_FLOAT
+    testScalar(1.0+2.0),
+    testScalar(3.0-1.0), 
+    testScalar(6-1.0), 
+    testScalar(2.5*6.), 
+    testScalar(0.5*4), 
+    testScalar(4.5/.5), 
+    testScalar(9.5/19), 
+    testRemainder(9.5, 0.5), 
+    testRemainder(9.,2), 
+    testRemainder(9,2.5),
+    testRemainder(-9,2.5),
+    testTrue(-9==-9.0),
+    testTrue(-9.==-4.0-5),
+    testTrue(-9.*1==-4-5),
+    testFalse(-9!=-9.0),
+    testFalse(-9.!=-4.0-5),
+    testFalse(-9.*1!=-4-5),
+#endif
+    testInt(0x123),
+    testInt(0XABC),
+    testInt(0xdeadBEEF),
+    {    "'123'+\"456\"", SkOperand2::kString, 0, 0, "123456" },
+    {    "123+\"456\"", SkOperand2::kString, 0, 0, "123456" },
+    {    "'123'+456", SkOperand2::kString, 0, 0, "123456" },
+    {    "'123'|\"456\"", SkOperand2::kS32, 123|456 },
+    {    "123|\"456\"", SkOperand2::kS32, 123|456 },
+    {    "'123'|456", SkOperand2::kS32, 123|456 },
+    {    "'2'<11", SkOperand2::kS32, 1 },
+    {    "2<'11'", SkOperand2::kS32, 1 },
+    {    "'2'<'11'", SkOperand2::kS32, 0 },
+    testInt(123),
+    testInt(-345),
+    testInt(+678),
+    testInt(1+2+3),
+    testInt(3*4+5),
+    testInt(6+7*8),
+    testInt(-1-2-8/4),
+    testInt(-9%4),
+    testInt(9%-4),
+    testInt(-9%-4),
+    testInt(123|978),
+    testInt(123&978),
+    testInt(123^978),
+    testInt(2<<4),
+    testInt(99>>3),
+    testInt(~55),
+    testInt(~~55),
+    testInt(!55),
+    testInt(!!55),
+    // both int
+    testInt(2<2),
+    testInt(2<11),
+    testInt(20<11),
+    testInt(2<=2),
+    testInt(2<=11),
+    testInt(20<=11),
+    testInt(2>2),
+    testInt(2>11),
+    testInt(20>11),
+    testInt(2>=2),
+    testInt(2>=11),
+    testInt(20>=11),
+    testInt(2==2),
+    testInt(2==11),
+    testInt(20==11),
+    testInt(2!=2),
+    testInt(2!=11),
+    testInt(20!=11),
+#ifdef SK_CAN_USE_FLOAT
+    // left int, right scalar
+    testInt(2<2.),
+    testInt(2<11.),
+    testInt(20<11.),
+    testInt(2<=2.),
+    testInt(2<=11.),
+    testInt(20<=11.),
+    testInt(2>2.),
+    testInt(2>11.),
+    testInt(20>11.),
+    testInt(2>=2.),
+    testInt(2>=11.),
+    testInt(20>=11.),
+    testInt(2==2.),
+    testInt(2==11.),
+    testInt(20==11.),
+    testInt(2!=2.),
+    testInt(2!=11.),
+    testInt(20!=11.),
+    // left scalar, right int
+    testInt(2.<2),
+    testInt(2.<11),
+    testInt(20.<11),
+    testInt(2.<=2),
+    testInt(2.<=11),
+    testInt(20.<=11),
+    testInt(2.>2),
+    testInt(2.>11),
+    testInt(20.>11),
+    testInt(2.>=2),
+    testInt(2.>=11),
+    testInt(20.>=11),
+    testInt(2.==2),
+    testInt(2.==11),
+    testInt(20.==11),
+    testInt(2.!=2),
+    testInt(2.!=11),
+    testInt(20.!=11),
+    // both scalar
+    testInt(2.<11.),
+    testInt(20.<11.),
+    testInt(2.<=2.),
+    testInt(2.<=11.),
+    testInt(20.<=11.),
+    testInt(2.>2.),
+    testInt(2.>11.),
+    testInt(20.>11.),
+    testInt(2.>=2.),
+    testInt(2.>=11.),
+    testInt(20.>=11.),
+    testInt(2.==2.),
+    testInt(2.==11.),
+    testInt(20.==11.),
+    testInt(2.!=2.),
+    testInt(2.!=11.),
+    testInt(20.!=11.),
+#endif
+    // int, string (string is int)
+    testFalse(2<'2'),
+    testTrue(2<'11'),
+    testFalse(20<'11'),
+    testTrue(2<='2'),
+    testTrue(2<='11'),
+    testFalse(20<='11'),
+    testFalse(2>'2'),
+    testFalse(2>'11'),
+    testTrue(20>'11'),
+    testTrue(2>='2'),
+    testFalse(2>='11'),
+    testTrue(20>='11'),
+    testTrue(2=='2'),
+    testFalse(2=='11'),
+    testFalse(2!='2'),
+    testTrue(2!='11'),
+    // int, string (string is scalar)
+    testFalse(2<'2.'),
+    testTrue(2<'11.'),
+    testFalse(20<'11.'),
+    testTrue(2=='2.'),
+    testFalse(2=='11.'),
+#ifdef SK_CAN_USE_FLOAT
+    // scalar, string
+    testFalse(2.<'2.'),
+    testTrue(2.<'11.'),
+    testFalse(20.<'11.'),
+    testTrue(2.=='2.'),
+    testFalse(2.=='11.'),
+    // string, int
+    testFalse('2'<2),
+    testTrue('2'<11),
+    testFalse('20'<11),
+    testTrue('2'==2),
+    testFalse('2'==11),
+    // string, scalar
+    testFalse('2'<2.),
+    testTrue('2'<11.),
+    testFalse('20'<11.),
+    testTrue('2'==2.),
+    testFalse('2'==11.),
+#endif
+    // string, string
+    testFalse('2'<'2'),
+    testFalse('2'<'11'),
+    testFalse('20'<'11'),
+    testTrue('2'=='2'),
+    testFalse('2'=='11'),
+    // logic
+    testInt(1?2:3),
+    testInt(0?2:3),
+    testInt(1&&2||3),
+    testInt(1&&0||3),
+    testInt(1&&0||0),
+    testInt(1||0&&3),
+    testInt(0||0&&3),
+    testInt(0||1&&3),
+    testInt(0&&1?2:3)
+#ifdef SK_CAN_USE_FLOAT
+    , {    "123.5", SkOperand2::kScalar, 0, SkIntToScalar(123) + SK_Scalar1/2 }
+#endif
+};
+#endif // build for brew
+
+#define SkScriptNAnswer_testCount    SK_ARRAY_COUNT(scriptTests)
+
+void SkScriptEngine2::UnitTest() {
+#if !defined(SK_BUILD_FOR_BREW) && defined(SK_SUPPORT_UNITTEST)
+    ValidateDecompileTable();
+    for (int index = 0; index < SkScriptNAnswer_testCount; index++) {
+        SkScriptEngine2 engine(scriptTests[index].fType);
+        SkScriptValue2 value;
+        const char* script = scriptTests[index].fScript;
+        const char* scriptPtr = script;
+        SkASSERT(engine.evaluateScript(&scriptPtr, &value) == true);
+        SkASSERT(value.fType == scriptTests[index].fType);
+        SkScalar error;
+        switch (value.fType) {
+            case SkOperand2::kS32:
+                if (value.fOperand.fS32 != scriptTests[index].fIntAnswer)
+                    SkDEBUGF(("script '%s' == value %d != expected answer %d\n", script, value.fOperand.fS32, scriptTests[index].fIntAnswer));
+                SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer);
+                break;
+            case SkOperand2::kScalar:
+                error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer);
+#ifdef SK_CAN_USE_FLOAT
+                if (error >= SK_Scalar1 / 10000)
+                    SkDEBUGF(("script '%s' == value %g != expected answer %g\n", script, value.fOperand.fScalar / (1.0f * SK_Scalar1), scriptTests[index].fScalarAnswer / (1.0f * SK_Scalar1)));
+#endif
+                SkASSERT(error < SK_Scalar1 / 10000);
+                break;
+            case SkOperand2::kString:
+                SkASSERT(value.fOperand.fString->equals(scriptTests[index].fStringAnswer));
+                break;
+            default:
+                SkASSERT(0);
+        }
+    }
+#endif
+}
+#endif
diff --git a/libs/graphics/animator/SkSnapshot.cpp b/libs/graphics/animator/SkSnapshot.cpp
new file mode 100644 (file)
index 0000000..9bb74e6
--- /dev/null
@@ -0,0 +1,54 @@
+#include "SkTypes.h"
+
+#ifdef SK_SUPPORT_IMAGE_ENCODE
+
+#include "SkSnapshot.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkSnapshot::fInfo[] = {
+       SK_MEMBER(filename, String),
+       SK_MEMBER(quality, Float),
+       SK_MEMBER(sequence, Boolean),
+       SK_MEMBER(type, BitmapEncoding)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkSnapshot);
+
+SkSnapshot::SkSnapshot()
+{
+       quality         = 100 * SK_Scalar1;
+       type            = (SkImageEncoder::Type) -1;
+       sequence        = false;
+       fSeqVal         = 0;
+}
+
+bool SkSnapshot::draw(SkAnimateMaker& maker) {
+       SkASSERT(type >= 0);
+       SkASSERT(filename.size() > 0);
+       SkImageEncoder* encoder = SkImageEncoder::Create((SkImageEncoder::Type) type);
+       SkBitmap bitmap;
+       maker.fCanvas->getPixels(&bitmap);
+       SkString name(filename);
+       if (sequence) {
+               char num[4] = "000";
+               num[0] = (char) (num[0] + fSeqVal / 100);
+               num[1] = (char) (num[1] + fSeqVal / 10 % 10);
+               num[2] = (char) (num[2] + fSeqVal % 10);
+               name.append(num);
+               if (++fSeqVal > 999)
+                       sequence = false;
+       }
+       if (type == SkImageEncoder::kJPEG_Type)
+               name.append(".jpg");
+       else if (type == SkImageEncoder::kPNG_Type)
+               name.append(".png");
+       encoder->encodeFile(name.c_str(), bitmap, SkScalarFloor(quality));
+       return false;
+}
+
+#endif
diff --git a/libs/graphics/animator/SkSnapshot.h b/libs/graphics/animator/SkSnapshot.h
new file mode 100644 (file)
index 0000000..941df79
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef SkSnapShot_DEFINED
+#define SkSnapShot_DEFINED
+
+#ifdef SK_SUPPORT_IMAGE_ENCODE
+
+#include "SkDrawable.h"
+#include "SkImageDecoder.h"
+#include "SkMemberInfo.h"
+#include "SkString.h"
+
+class SkSnapshot: public SkDrawable {
+       DECLARE_MEMBER_INFO(Snapshot);
+       SkSnapshot();
+       virtual bool draw(SkAnimateMaker& );
+       private:
+       SkString filename;
+       SkScalar quality;
+       SkBool sequence;
+       int /*SkImageEncoder::Type*/    type;
+       int fSeqVal;
+};
+
+#endif // SK_SUPPORT_IMAGE_ENCODE
+#endif // SkSnapShot_DEFINED
+
diff --git a/libs/graphics/animator/SkTDArray_Experimental.h b/libs/graphics/animator/SkTDArray_Experimental.h
new file mode 100644 (file)
index 0000000..9511d4e
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef SkTDArray_Experimental_DEFINED
+#define SkTDArray_Experimental_DEFINED
+
+#include "SkTypes.h"
+
+#ifdef SK_BUILD_FOR_UNIX
+#define SK_BUILD_FOR_ADS_12
+#endif
+
+#ifndef SK_BUILD_FOR_ADS_12
+#define SK_SMALLER_ARRAY_TEMPLATE_EXPERIMENT 1
+#else
+#define SK_SMALLER_ARRAY_TEMPLATE_EXPERIMENT 0
+#endif
+
+#if SK_SMALLER_ARRAY_TEMPLATE_EXPERIMENT == 0
+#include "SkTDArray.h"
+#define SkIntArray(type) SkTDArray<type>
+#define SkLongArray(type) SkTDArray<type>
+#else
+
+class SkDS32Array {
+protected:
+       SkDS32Array();
+       SkDS32Array(const SkDS32Array& src);
+       SkDS32Array(const int32_t src[], U16CPU count);
+       SkDS32Array& operator=(const SkDS32Array& src);
+       friend int operator==(const SkDS32Array& a, const SkDS32Array& b);
+       int32_t* append() { return this->append(1, nil); }
+       int32_t* append(U16CPU count, const int32_t* src = nil);
+
+       int32_t* appendClear() 
+       { 
+               int32_t* result = this->append(); 
+               *result = 0;
+               return result;
+       }
+
+       int find(const int32_t& elem) const;
+       int32_t* insert(U16CPU index, U16CPU count, const int32_t* src);
+       int rfind(const int32_t& elem) const;
+       void swap(SkDS32Array& other);
+public:
+       bool isEmpty() const { return fCount == 0; }
+       int     count() const { return fCount; }
+
+       void remove(U16CPU index, U16CPU count = 1)
+       {
+               SkASSERT(index + count <= fCount);
+               fCount = SkToU16(fCount - count);
+               memmove(fArray + index, fArray + index + count, sizeof(int32_t) * (fCount - index));
+       }
+
+       void reset()
+       {
+               if (fArray)
+               {
+                       sk_free(fArray);
+                       fArray = nil;
+#ifdef SK_DEBUG
+                       fData = nil;
+#endif
+                       fReserve = fCount = 0;
+               }
+               else
+               {
+                       SkASSERT(fReserve == 0 && fCount == 0);
+               }
+       }
+
+       void setCount(U16CPU count)
+       {
+               if (count > fReserve)
+                       this->growBy(count - fCount);
+               else
+                       fCount = SkToU16(count);
+       }
+protected:
+#ifdef SK_DEBUG
+    enum {
+        kDebugArraySize = 24
+    };
+       int32_t(* fData)[kDebugArraySize];
+#endif
+       int32_t*        fArray;
+       uint16_t        fReserve, fCount;
+       void growBy(U16CPU extra);
+};
+
+#ifdef SK_DEBUG
+       #define SYNC() fTData = (T (*)[kDebugArraySize]) fArray
+#else
+       #define SYNC()
+#endif
+
+template <typename T> class SkTDS32Array : public SkDS32Array {
+public:
+       SkTDS32Array() { SkDEBUGCODE(fTData=nil); SkASSERT(sizeof(T) == sizeof(int32_t)); }
+       SkTDS32Array(const SkTDS32Array<T>& src) : SkDS32Array(src) {}
+       ~SkTDS32Array() { sk_free(fArray); }
+       T&      operator[](int index) const { SYNC(); SkASSERT((unsigned)index < fCount); return ((T*) fArray)[index]; }
+       SkTDS32Array<T>& operator=(const SkTDS32Array<T>& src) { 
+               return (SkTDS32Array<T>&) SkDS32Array::operator=(src); }
+       friend int operator==(const SkTDS32Array<T>& a, const SkTDS32Array<T>& b) { 
+               return operator==((const SkDS32Array&) a, (const SkDS32Array&) b); }
+       T* append() { return (T*) SkDS32Array::append(); }
+       T* appendClear() { return (T*) SkDS32Array::appendClear(); }
+       T* append(U16CPU count, const T* src = nil) { return (T*) SkDS32Array::append(count, (const int32_t*) src); }
+       T*      begin() const { SYNC(); return (T*) fArray; }
+       T*      end() const { return (T*) (fArray ? fArray + fCount : nil); }
+       int find(const T& elem) const { return SkDS32Array::find((const int32_t&) elem); }
+       T* insert(U16CPU index) { return this->insert(index, 1, nil); }
+       T* insert(U16CPU index, U16CPU count, const T* src = nil) {
+               return (T*) SkDS32Array::insert(index, count, (const int32_t*) src); }
+       int rfind(const T& elem) const { return SkDS32Array::rfind((const int32_t&) elem); }
+       T*                      push() { return this->append(); }
+       void            push(T& elem) { *this->append() = elem; }
+       const T&        top() const { return (*this)[fCount - 1]; }
+       T&                      top() { return (*this)[fCount - 1]; }
+       void            pop(T* elem) { if (elem) *elem = (*this)[fCount - 1]; --fCount; }
+       void            pop() { --fCount; }
+private:
+#ifdef SK_DEBUG
+       mutable T(* fTData)[kDebugArraySize];
+#endif
+};
+
+#define SkIntArray(type) SkTDS32Array<type>    // holds 32 bit data types
+#define SkLongArray(type) SkTDS32Array<type>   // holds 32/64 bit data types depending on pointer size
+
+#endif // SK_SMALLER_ARRAY_TEMPLATE_EXPERIMENT
+
+#endif // SkTDArray_Experimental_DEFINED
diff --git a/libs/graphics/animator/SkTextOnPath.cpp b/libs/graphics/animator/SkTextOnPath.cpp
new file mode 100644 (file)
index 0000000..c0e9917
--- /dev/null
@@ -0,0 +1,30 @@
+#include "SkTextOnPath.h"
+#include "SkAnimateMaker.h"
+#include "SkCanvas.h"
+#include "SkDrawPath.h"
+#include "SkDrawText.h"
+#include "SkPaint.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkTextOnPath::fInfo[] = {
+       SK_MEMBER(offset, Float),
+       SK_MEMBER(path, Path),
+       SK_MEMBER(text, Text)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkTextOnPath);
+
+SkTextOnPath::SkTextOnPath() : offset(0), path(nil), text(nil) {
+}
+
+bool SkTextOnPath::draw(SkAnimateMaker& maker) {
+       SkASSERT(text);
+       SkASSERT(path);
+       SkBoundableAuto boundable(this, maker);
+       maker.fCanvas->drawTextOnPath(text->getText(), text->getSize(), 
+               path->getPath(), offset, *maker.fPaint);
+       return false;
+}
diff --git a/libs/graphics/animator/SkTextOnPath.h b/libs/graphics/animator/SkTextOnPath.h
new file mode 100644 (file)
index 0000000..c818aed
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef SkTextOnPath_DEFINED
+#define SkTextOnPath_DEFINED
+
+#include "SkBoundable.h"
+#include "SkMemberInfo.h"
+
+class SkDrawPath;
+class SkText;
+
+class SkTextOnPath : public SkBoundable {
+       DECLARE_MEMBER_INFO(TextOnPath);
+       SkTextOnPath();
+       virtual bool draw(SkAnimateMaker& );
+private:
+       SkScalar offset;
+       SkDrawPath* path;
+       SkText* text;
+       typedef SkBoundable INHERITED;
+};
+
+#endif // SkTextOnPath_DEFINED
diff --git a/libs/graphics/animator/SkTextToPath.cpp b/libs/graphics/animator/SkTextToPath.cpp
new file mode 100644 (file)
index 0000000..d259c69
--- /dev/null
@@ -0,0 +1,39 @@
+#include "SkTextToPath.h"
+#include "SkAnimateMaker.h"
+#include "SkDrawPaint.h"
+#include "SkDrawPath.h"
+#include "SkDrawText.h"
+#include "SkPaint.h"
+
+#if SK_USE_CONDENSED_INFO == 0
+
+const SkMemberInfo SkTextToPath::fInfo[] = {
+       SK_MEMBER(paint, Paint),
+       SK_MEMBER(path, Path),
+       SK_MEMBER(text, Text)
+};
+
+#endif
+
+DEFINE_GET_MEMBER(SkTextToPath);
+
+SkTextToPath::SkTextToPath() : paint(nil), path(nil), text(nil) {
+}
+
+bool SkTextToPath::draw(SkAnimateMaker& maker) {
+       path->draw(maker);
+       return false;
+}
+
+void SkTextToPath::onEndElement(SkAnimateMaker& maker) {
+       if (paint == nil || path == nil || text == nil) {
+               // !!! add error message here
+               maker.setErrorCode(SkDisplayXMLParserError::kErrorInAttributeValue);
+               return;
+       }
+       SkPaint realPaint;
+       paint->setupPaint(&realPaint);
+       realPaint.getTextPath(text->getText(), text->getSize(), text->x, 
+               text->y, &path->getPath());
+}
+
diff --git a/libs/graphics/animator/SkTextToPath.h b/libs/graphics/animator/SkTextToPath.h
new file mode 100644 (file)
index 0000000..e36083f
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef SkTextToPath_DEFINED
+#define SkTextToPath_DEFINED
+
+#include "SkDrawPath.h"
+#include "SkMemberInfo.h"
+
+class SkDrawPaint;
+class SkDrawPath;
+class SkText;
+
+class SkTextToPath : public SkDrawable {
+       DECLARE_MEMBER_INFO(TextToPath);
+       SkTextToPath();
+       virtual bool draw(SkAnimateMaker& );
+       virtual void onEndElement(SkAnimateMaker& );
+private:
+       SkDrawPaint* paint;
+       SkDrawPath* path;
+       SkText* text;
+};
+
+#endif // SkTextToPath_DEFINED
+
diff --git a/libs/graphics/animator/SkTime.cpp b/libs/graphics/animator/SkTime.cpp
new file mode 100644 (file)
index 0000000..928480f
--- /dev/null
@@ -0,0 +1,72 @@
+#include "SkTime.h"
+
+#ifdef SK_BUILD_FOR_WIN
+
+#ifdef SK_DEBUG
+SkMSec gForceTickCount = (SkMSec) -1;
+#endif
+
+void SkTime::GetDateTime(DateTime* t)
+{
+       if (t)
+       {
+               SYSTEMTIME      syst;
+
+               ::GetLocalTime(&syst);
+               t->fYear                = SkToU16(syst.wYear);
+               t->fMonth               = SkToU8(syst.wMonth);
+               t->fDayOfWeek   = SkToU8(syst.wDayOfWeek);
+               t->fDay                 = SkToU8(syst.wDay);
+               t->fHour                = SkToU8(syst.wHour);
+               t->fMinute              = SkToU8(syst.wMinute);
+               t->fSecond              = SkToU8(syst.wSecond);
+       }
+}
+
+SkMSec SkTime::GetMSecs()
+{
+#ifdef SK_DEBUG
+       if (gForceTickCount != (SkMSec) -1)
+               return gForceTickCount;
+#endif
+       return ::GetTickCount();
+}
+
+#elif defined(xSK_BUILD_FOR_MAC)
+
+#include <time.h>
+
+void SkTime::GetDateTime(DateTime* t)
+{
+       if (t)
+       {
+               tm              syst;
+               time_t  tm;
+               
+               time(&tm);
+               localtime_r(&tm, &syst);
+               t->fYear                = SkToU16(syst.tm_year);
+               t->fMonth               = SkToU8(syst.tm_mon + 1);
+               t->fDayOfWeek   = SkToU8(syst.tm_wday);
+               t->fDay                 = SkToU8(syst.tm_mday);
+               t->fHour                = SkToU8(syst.tm_hour);
+               t->fMinute              = SkToU8(syst.tm_min);
+               t->fSecond              = SkToU8(syst.tm_sec);
+       }
+}
+
+#include "Sk64.h"
+
+SkMSec SkTime::GetMSecs()
+{
+       UnsignedWide    wide;
+       Sk64                    s;
+
+       ::Microseconds(&wide);
+       s.set(wide.hi, wide.lo);
+       s.div(1000, Sk64::kRound_DivOption);
+       return s.get32();
+}
+
+#endif
+
diff --git a/libs/graphics/animator/SkTypedArray.cpp b/libs/graphics/animator/SkTypedArray.cpp
new file mode 100644 (file)
index 0000000..f73d8aa
--- /dev/null
@@ -0,0 +1,170 @@
+#include "SkTypedArray.h"
+
+SkTypedArray::SkTypedArray() : fType(SkType_Unknown) {
+}
+
+SkTypedArray::SkTypedArray(SkDisplayTypes type) : fType(type) {
+}
+
+bool SkTypedArray::getIndex(int index, SkOperand* operand) {
+       if (index >= count()) {
+               SkASSERT(0);
+               return false;
+       }
+       *operand = begin()[index];
+       return true;
+}
+
+
+#if SK_SMALLER_ARRAY_TEMPLATE_EXPERIMENT == 1
+SkDS32Array::SkDS32Array()
+{
+       fReserve = fCount = 0;
+       fArray = nil;
+#ifdef SK_DEBUG
+       fData = nil;
+#endif
+}
+
+SkDS32Array::SkDS32Array(const SkDS32Array& src)
+{
+       fReserve = fCount = 0;
+       fArray = nil;
+#ifdef SK_DEBUG
+       fData = nil;
+#endif
+       SkDS32Array tmp(src.fArray, src.fCount);
+       this->swap(tmp);
+}
+
+SkDS32Array::SkDS32Array(const S32 src[], U16CPU count)
+{
+       SkASSERT(src || count == 0);
+
+       fReserve = fCount = 0;
+       fArray = nil;
+#ifdef SK_DEBUG
+       fData = nil;
+#endif
+       if (count)
+       {
+               fArray = (S32*)sk_malloc_throw(count * sizeof(S32));
+#ifdef SK_DEBUG
+               fData = (S32 (*)[kDebugArraySize]) fArray;
+#endif
+               memcpy(fArray, src, sizeof(S32) * count);
+               fReserve = fCount = SkToU16(count);
+       }
+}
+
+SkDS32Array& SkDS32Array::operator=(const SkDS32Array& src)
+{
+       if (this != &src)
+       {
+               if (src.fCount > fReserve)
+               {
+                       SkDS32Array tmp(src.fArray, src.fCount);
+                       this->swap(tmp);
+               }
+               else
+               {
+                       memcpy(fArray, src.fArray, sizeof(S32) * src.fCount);
+                       fCount = src.fCount;
+               }
+       }
+       return *this;
+}
+
+int operator==(const SkDS32Array& a, const SkDS32Array& b)
+{
+       return a.fCount == b.fCount &&
+                       (a.fCount == 0 || !memcmp(a.fArray, b.fArray, a.fCount * sizeof(S32)));
+}
+
+void SkDS32Array::swap(SkDS32Array& other)
+{
+       SkTSwap(fArray, other.fArray);
+#ifdef SK_DEBUG
+       SkTSwap(fData, other.fData);
+#endif
+       SkTSwap(fReserve, other.fReserve);
+       SkTSwap(fCount, other.fCount);
+}
+
+S32* SkDS32Array::append(U16CPU count, const S32* src)
+{
+       unsigned oldCount = fCount;
+       if (count)
+       {
+               SkASSERT(src == nil || fArray == nil ||
+                               src + count <= fArray || fArray + count <= src);
+
+               this->growBy(count);
+               if (src)
+                       memcpy(fArray + oldCount, src, sizeof(S32) * count);
+       }
+       return fArray + oldCount;
+}
+
+int SkDS32Array::find(const S32& elem) const
+{
+       const S32* iter = fArray;
+       const S32* stop = fArray + fCount;
+
+       for (; iter < stop; iter++)
+       {
+               if (*iter == elem)
+                       return (int) (iter - fArray);
+       }
+       return -1;
+}
+
+void SkDS32Array::growBy(U16CPU extra)
+{
+       SkASSERT(extra);
+       SkASSERT(fCount + extra <= 0xFFFF);
+
+       if (fCount + extra > fReserve)
+       {
+               size_t size = fCount + extra + 4;
+               size += size >> 2;
+               S32* array = (S32*)sk_malloc_throw(size * sizeof(S32));
+               memcpy(array, fArray, fCount * sizeof(S32));
+
+               sk_free(fArray);
+               fArray = array;
+#ifdef SK_DEBUG
+               fData = (S32 (*)[kDebugArraySize]) fArray;
+#endif
+               fReserve = SkToU16((U16CPU)size);
+       }
+       fCount = SkToU16(fCount + extra);
+}
+
+S32* SkDS32Array::insert(U16CPU index, U16CPU count, const S32* src)
+{
+       SkASSERT(count);
+       int oldCount = fCount;
+       this->growBy(count);
+       S32* dst = fArray + index;
+       memmove(dst + count, dst, sizeof(S32) * (oldCount - index));
+       if (src)
+               memcpy(dst, src, sizeof(S32) * count);
+       return dst;
+}
+
+
+       int SkDS32Array::rfind(const S32& elem) const
+       {
+               const S32* iter = fArray + fCount;
+               const S32* stop = fArray;
+
+               while (iter > stop)
+               {
+                       if (*--iter == elem)
+                               return (int) (iter - stop);
+               }
+               return -1;
+       }
+
+#endif
diff --git a/libs/graphics/animator/SkTypedArray.h b/libs/graphics/animator/SkTypedArray.h
new file mode 100644 (file)
index 0000000..96b42ac
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef SkTypedArray_DEFINED
+#define SkTypedArray_DEFINED
+
+#include "SkScript.h"
+#include "SkTDArray_Experimental.h"
+
+class SkTypedArray : public SkTDOperandArray {
+public:
+       SkTypedArray();
+       SkTypedArray(SkDisplayTypes type);
+       bool getIndex(int index, SkOperand* operand);
+       SkDisplayTypes getType() { return fType; }
+       SkScriptEngine::SkOpType getOpType() { return SkScriptEngine::ToOpType(fType); }
+       void setType(SkDisplayTypes type) { 
+       //      SkASSERT(count() == 0);
+               fType = type;
+       }
+protected:
+       SkDisplayTypes fType;
+};
+
+#endif // SkTypedArray_DEFINED
diff --git a/libs/graphics/animator/SkXMLAnimatorWriter.cpp b/libs/graphics/animator/SkXMLAnimatorWriter.cpp
new file mode 100644 (file)
index 0000000..8045fde
--- /dev/null
@@ -0,0 +1,74 @@
+#include "SkXMLAnimatorWriter.h"
+#include "SkAnimator.h"
+#include "SkAnimateMaker.h"
+#include "SkDisplayXMLParser.h"
+
+SkXMLAnimatorWriter::SkXMLAnimatorWriter(SkAnimator* animator) : fAnimator(animator)
+{
+       fParser = new SkDisplayXMLParser(*fAnimator->fMaker);
+}
+
+SkXMLAnimatorWriter::~SkXMLAnimatorWriter() {
+       delete fParser;
+}
+
+void SkXMLAnimatorWriter::onAddAttributeLen(const char name[], const char value[], size_t length)
+{
+       fParser->onAddAttributeLen(name, value, length);
+}
+
+void SkXMLAnimatorWriter::onEndElement()
+{
+       Elem* elem = getEnd();
+       fParser->onEndElement(elem->fName.c_str());
+       doEnd(elem);
+}
+
+void SkXMLAnimatorWriter::onStartElementLen(const char name[], size_t length)
+{
+       doStart(name, length);
+       fParser->onStartElementLen(name, length);
+}
+
+void SkXMLAnimatorWriter::writeHeader()
+{
+}
+
+#ifdef SK_DEBUG
+#include "SkCanvas.h"
+#include "SkPaint.h"
+
+void SkXMLAnimatorWriter::UnitTest(SkCanvas* canvas)
+{
+       SkAnimator      s;
+       SkXMLAnimatorWriter             w(&s);
+       w.startElement("screenplay");
+               w.startElement("animateField");
+                       w.addAttribute("field", "x1");
+                       w.addAttribute("id", "to100");
+                       w.addAttribute("from", "0");
+                       w.addAttribute("to", "100");
+                       w.addAttribute("dur", "1");
+               w.endElement();
+               w.startElement("event");
+                       w.addAttribute("kind", "onLoad");
+                       w.startElement("line");
+                               w.addAttribute("id", "line");
+                               w.addAttribute("x1", "-1");
+                               w.addAttribute("y1", "20");
+                               w.addAttribute("x2", "150");
+                               w.addAttribute("y2", "40");
+                       w.endElement();
+                       w.startElement("apply");
+                               w.addAttribute("animator", "to100");
+                               w.addAttribute("scope", "line");
+                       w.endElement();
+               w.endElement();
+       w.endElement();
+       SkPaint paint;
+       canvas->drawRGB(255, 255, 255);
+       s.draw(canvas, &paint, 0);
+}
+
+#endif
+
diff --git a/libs/graphics/animator/SkXMLAnimatorWriter.h b/libs/graphics/animator/SkXMLAnimatorWriter.h
new file mode 100644 (file)
index 0000000..7180dbd
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef SkXMLAnimatorWriter_DEFINED
+#define SkXMLAnimatorWriter_DEFINED
+
+#include "SkXMLWriter.h"
+
+class SkAnimator;
+class SkDisplayXMLParser;
+
+class SkXMLAnimatorWriter : public SkXMLWriter {
+public:
+       SkXMLAnimatorWriter(SkAnimator*);
+       virtual ~SkXMLAnimatorWriter();
+       virtual void    writeHeader();
+       SkDEBUGCODE(static void UnitTest(class SkCanvas* canvas);)
+protected:
+       virtual void onAddAttributeLen(const char name[], const char value[], size_t length);
+       virtual void onEndElement();
+       virtual void onStartElementLen(const char elem[], size_t length);
+private:
+       SkAnimator* fAnimator;
+       SkDisplayXMLParser* fParser;
+};
+
+#endif // SkXMLAnimatorWriter_DEFINED
+
diff --git a/libs/graphics/animator/thingstodo.txt b/libs/graphics/animator/thingstodo.txt
new file mode 100644 (file)
index 0000000..8d0d47a
--- /dev/null
@@ -0,0 +1,21 @@
+things to do:
+       figure out where endless or very deep recursion is possible
+       at these points, generate an error if actual physical stack gets too large
+       candidates are scripts
+               eval(eval(eval...       user callouts
+               (((((   operator precedence or similar making stack deep
+               groups within groups
+               very large apply create or apply immediate steps
+
+       write tests for math functions
+               looks like random takes a parameter when it should take zero parameters
+               
+       add Math, Number files to perforce for docs
+       alphabetize attributes in docs
+       
+       manually modified tools/screenplayDocs/xmlToJPEG.cpp
+       
+       fix docs where lines are stitched together (insert space)
+       
+       naked <data> outside of <post> asserts on name
+       handle errors for all element not contained by correct parents
\ No newline at end of file
diff --git a/libs/graphics/effects/Sk1DPathEffect.cpp b/libs/graphics/effects/Sk1DPathEffect.cpp
new file mode 100644 (file)
index 0000000..938858e
--- /dev/null
@@ -0,0 +1,162 @@
+#include "Sk1DPathEffect.h"
+#include "SkPathMeasure.h"
+
+bool Sk1DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
+{
+       SkPathMeasure   meas(src, false);
+       do {
+               SkScalar        length = meas.getLength();
+               SkScalar        distance = this->begin(length);
+               while (distance < length)
+               {
+                       SkScalar delta = this->next(dst, distance, meas);
+                       if (delta <= 0)
+                               break;
+                       distance += delta;
+               }
+       } while (meas.nextContour());
+       return true;
+}
+
+SkScalar Sk1DPathEffect::begin(SkScalar contourLength)
+{
+       return 0;
+}
+
+SkScalar Sk1DPathEffect::next(SkPath* dst, SkScalar distance, SkPathMeasure&)
+{
+       return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+SkPath1DPathEffect::SkPath1DPathEffect(const SkPath& path, SkScalar advance, SkScalar phase, Style style)
+    : fPath(path)
+{
+    if (advance <= 0 || path.isEmpty())
+    {
+        SkDEBUGF(("SkPath1DPathEffect can't use advance <= 0\n"));
+        fAdvance = 0;   // signals we can't draw anything
+    }
+    else
+    {
+        if (phase >= advance)
+            phase = SkScalarMod(phase, advance);
+        fAdvance = advance;
+        fPhase = phase;
+
+        if ((unsigned)style >= kStyleCount)
+            SkDEBUGF(("SkPath1DPathEffect style enum out of range %d\n", style));
+        fStyle = style;
+    }
+}
+
+bool SkPath1DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
+{
+    if (fAdvance > 0)
+    {
+        *width = -1;
+        return this->INHERITED::filterPath(dst, src, width);
+    }
+    return false;
+}
+
+static void morphpoints(SkPoint dst[], const SkPoint src[], int count,
+                                               SkPathMeasure& meas, SkScalar dist)
+{
+       for (int i = 0; i < count; i++)
+       {
+               SkPoint pos;
+               SkVector tangent;
+
+               SkScalar sx = src[i].fX;
+               SkScalar sy = src[i].fY;
+
+               meas.getPosTan(dist + sx, &pos, &tangent);
+
+               SkMatrix        matrix;
+               SkPoint         pt;
+
+               pt.set(sx, sy);
+               matrix.setSinCos(tangent.fY, tangent.fX, 0, 0);
+               matrix.preTranslate(-sx, 0);
+               matrix.postTranslate(pos.fX, pos.fY);
+               matrix.mapPoints(&dst[i], &pt, 1);
+       }
+}
+
+/*     TODO
+
+       Need differentially more subdivisions when the follow-path is curvy. Not sure how to
+       determine that, but we need it. I guess a cheap answer is let the caller tell us,
+       but that seems like a cop-out. Another answer is to get Rob Johnson to figure it out.
+*/
+static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas, SkScalar dist)
+{
+       SkPath::Iter    iter(src, false);
+       SkPoint                 srcP[4], dstP[3];
+       SkPath::Verb    verb;
+
+       while ((verb = iter.next(srcP)) != SkPath::kDone_Verb)
+       {
+               switch (verb) {
+               case SkPath::kMove_Verb:
+                       morphpoints(dstP, srcP, 1, meas, dist);
+                       dst->moveTo(dstP[0]);
+                       break;
+               case SkPath::kLine_Verb:
+                       srcP[2] = srcP[1];
+                       srcP[1].set(SkScalarAve(srcP[0].fX, srcP[2].fX),
+                                               SkScalarAve(srcP[0].fY, srcP[2].fY));
+                       // fall through to quad
+               case SkPath::kQuad_Verb:
+                       morphpoints(dstP, &srcP[1], 2, meas, dist);
+                       dst->quadTo(dstP[0], dstP[1]);
+                       break;
+               case SkPath::kCubic_Verb:
+                       morphpoints(dstP, &srcP[1], 3, meas, dist);
+                       dst->cubicTo(dstP[0], dstP[1], dstP[2]);
+                       break;
+               case SkPath::kClose_Verb:
+                       dst->close();
+                       break;
+               default:
+                       SkASSERT(!"unknown verb");
+                       break;
+               }
+       }
+}
+
+SkScalar SkPath1DPathEffect::begin(SkScalar contourLength)
+{
+    // should we offer an option to scale to a multiple of the contourLength?
+    return fPhase;
+}
+
+SkScalar SkPath1DPathEffect::next(SkPath* dst, SkScalar distance, SkPathMeasure& meas)
+{
+    switch (fStyle) {
+    case kTranslate_Style:
+        {
+            SkPoint pos;
+            meas.getPosTan(distance, &pos, nil);
+            dst->addPath(fPath, pos.fX, pos.fY);
+        }
+        break;
+    case kRotate_Style:
+        {
+            SkMatrix matrix;
+            meas.getMatrix(distance, &matrix);
+            dst->addPath(fPath, matrix);
+        }
+        break;
+    case kMorph_Style:
+        morphpath(dst, fPath, meas, distance);
+        break;
+    default:
+        SkASSERT(!"unknown Style enum");
+        break;
+    }
+    return fAdvance;
+}
+
diff --git a/libs/graphics/effects/Sk2DPathEffect.cpp b/libs/graphics/effects/Sk2DPathEffect.cpp
new file mode 100644 (file)
index 0000000..601666d
--- /dev/null
@@ -0,0 +1,89 @@
+#include "Sk2DPathEffect.h"
+#include "SkBlitter.h"
+#include "SkPath.h"
+#include "SkScan.h"
+
+class Sk2DPathEffectBlitter : public SkBlitter {
+public:
+       Sk2DPathEffectBlitter(Sk2DPathEffect* pe, SkPath* dst)
+               : fPE(pe), fDst(dst)
+       {}
+       virtual void blitH(int x, int y, int count)
+       {
+               fPE->nextSpan(x, y, count, fDst);
+       }
+private:
+       Sk2DPathEffect* fPE;
+       SkPath*                 fDst;
+};
+
+////////////////////////////////////////////////////////////////////////////////////
+
+Sk2DPathEffect::Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat)
+{
+       mat.invert(&fInverse);
+}
+
+bool Sk2DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
+{
+       Sk2DPathEffectBlitter   blitter(this, dst);
+       SkPath                                  tmp;
+       SkRect                                  bounds;
+       SkRect16                                r;
+
+       src.transform(fInverse, &tmp);
+       tmp.computeBounds(&bounds, SkPath::kExact_BoundsType);
+       bounds.round(&r);
+       if (!r.isEmpty())
+       {
+               this->begin(r, dst);
+               SkScan::FillPath(tmp, nil, &blitter);
+               this->end(dst);
+       }
+       return true;
+}
+
+void Sk2DPathEffect::nextSpan(int x, int y, int count, SkPath* path)
+{
+       const SkMatrix& mat = this->getMatrix();
+       SkPoint src, dst;
+
+       src.set(SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf);
+       do {
+               mat.mapPoints(&dst, &src, 1);
+               this->next(dst, x++, y, path);
+               src.fX += SK_Scalar1;
+       } while (--count > 0);
+}
+
+void Sk2DPathEffect::begin(const SkRect16& uvBounds, SkPath* dst) {}
+void Sk2DPathEffect::next(const SkPoint& loc, int u, int v, SkPath* dst) {}
+void Sk2DPathEffect::end(SkPath* dst) {}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void Sk2DPathEffect::flatten(SkWBuffer& buffer)
+{
+    this->INHERITED::flatten(buffer);
+
+    buffer.write(&fMatrix, sizeof(fMatrix));
+}
+
+Sk2DPathEffect::Sk2DPathEffect(SkRBuffer& buffer) : SkPathEffect(buffer)
+{
+    buffer.read(&fMatrix, sizeof(fMatrix));
+       fMatrix.invert(&fInverse);
+}
+
+SkFlattenable::Factory Sk2DPathEffect::getFactory()
+{
+    return CreateProc;
+}
+
+SkFlattenable* Sk2DPathEffect::CreateProc(SkRBuffer& buffer)
+{
+    return SkNEW_ARGS(Sk2DPathEffect, (buffer));
+}
+
+
+
diff --git a/libs/graphics/effects/SkAvoidXfermode.cpp b/libs/graphics/effects/SkAvoidXfermode.cpp
new file mode 100644 (file)
index 0000000..80f0310
--- /dev/null
@@ -0,0 +1,131 @@
+#include "SkAvoidXfermode.h"
+#include "SkColorPriv.h"
+
+SkAvoidXfermode::SkAvoidXfermode(SkColor opColor, U8CPU tolerance, bool reverse)
+{    
+    if (tolerance > 255)
+        tolerance = 255;
+
+    fOpColor = opColor;
+    fDistMul = (256 << 14) / (tolerance + 1);
+    fReverse = reverse;
+}
+
+static unsigned color_dist16(uint16_t c, unsigned r, unsigned g, unsigned b)
+{
+    unsigned dr = SkAbs32(SkPacked16ToR32(c) - r);
+    unsigned dg = SkAbs32(SkPacked16ToG32(c) - g);
+    unsigned db = SkAbs32(SkPacked16ToB32(c) - b);
+    
+    return SkMax32(dr, SkMax32(dg, db));
+}
+
+static unsigned color_dist32(SkPMColor c, U8CPU r, U8CPU g, U8CPU b)
+{
+    unsigned dr = SkAbs32(SkGetPackedR32(c) - r);
+    unsigned dg = SkAbs32(SkGetPackedG32(c) - g);
+    unsigned db = SkAbs32(SkGetPackedB32(c) - b);
+    
+    return SkMax32(dr, SkMax32(dg, db));
+}
+
+static float dot14tofloat(int x)
+{
+    return (float)x / (1 << 14);
+}
+
+static int scale_dist_14(int dist, uint32_t mul, uint32_t sub)
+{
+    int tmp = dist * mul - sub;
+    int result = (tmp + (1 << 13)) >> 14;
+
+    return result;
+}
+
+static SkPMColor SkFourByteInterp(SkPMColor src, SkPMColor dst, U8CPU alpha)
+{
+       unsigned scale = SkAlpha255To256(alpha);
+
+       unsigned a = SkAlphaBlend(SkGetPackedA32(src), SkGetPackedA32(dst), scale);
+       unsigned r = SkAlphaBlend(SkGetPackedR32(src), SkGetPackedR32(dst), scale);
+       unsigned g = SkAlphaBlend(SkGetPackedG32(src), SkGetPackedG32(dst), scale);
+       unsigned b = SkAlphaBlend(SkGetPackedB32(src), SkGetPackedB32(dst), scale);
+
+       return SkPackARGB32(a, r, g, b);
+}
+
+void SkAvoidXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count, const SkAlpha aa[])
+{
+       // override in subclass
+}
+
+static inline U16CPU SkBlend3216(SkPMColor src, U16CPU dst, unsigned scale)
+{
+       SkASSERT(scale <= 256);
+
+       return SkPackRGB16(     SkAlphaBlend(SkPacked32ToR16(src), SkGetPackedR16(dst), scale),
+                                               SkAlphaBlend(SkPacked32ToG16(src), SkGetPackedG16(dst), scale),
+                                               SkAlphaBlend(SkPacked32ToB16(src), SkGetPackedB16(dst), scale));
+}
+
+void SkAvoidXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count, const SkAlpha aa[])
+{
+    SkColor opColor = fOpColor;
+    unsigned    opR = SkPacked16ToR32(opColor);
+    unsigned    opG = SkPacked16ToG32(opColor);
+    unsigned    opB = SkPacked16ToB32(opColor);
+    uint32_t    mul = fDistMul;
+    uint32_t    sub = (fDistMul - (1 << 14)) << 8;
+
+    int MAX, mask;
+    
+    if (fReverse)
+    {
+        mask = -1;
+        MAX = 256;
+    }
+    else
+    {
+        mask = 0;
+        MAX = 0;
+    }
+
+    if (NULL == aa)
+        for (int i = 0; i < count; i++) {
+            int d = color_dist16(dst[i], opR, opG, opB);
+            d = SkAlpha255To256(d);
+            // now reverse d if we need to
+            d = MAX + (d ^ mask) - mask;
+            SkASSERT((unsigned)d <= 256);
+
+            d = scale_dist_14(d, mul, sub);
+            SkASSERT(d <= 256);
+
+            if (d > 0)
+                dst[i] = SkBlend3216(src[i], dst[i], d);
+        }
+    else
+        for (int i = 0; i < count; i++) {
+            unsigned antialias = aa[i];
+            if (0 == antialias)
+                continue;
+
+            int d = color_dist16(dst[i], opR, opG, opB);
+            d = SkAlpha255To256(d);
+            // now reverse d if we need to
+            d = MAX + (d ^ mask) - mask;
+            SkASSERT((unsigned)d <= 256);
+
+            d = scale_dist_14(d, mul, sub);
+            SkASSERT(d <= 256);
+
+            if (d > 0)
+                dst[i] = SkBlend3216(src[i], dst[i], SkAlphaMul(antialias, d));
+        }
+}
+
+void SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count, const SkAlpha aa[])
+{
+       // override in subclass
+}
+
diff --git a/libs/graphics/effects/SkBlurMask.cpp b/libs/graphics/effects/SkBlurMask.cpp
new file mode 100644 (file)
index 0000000..8502342
--- /dev/null
@@ -0,0 +1,308 @@
+#include "SkBlurMask.h"
+#include "SkTemplates.h"
+
+static void build_sum_buffer(uint32_t dst[], int w, int h, const uint8_t src[])
+{
+       int     x, y;
+
+       // special case first row
+       uint32_t X = 0;
+       for (x = w - 1; x >= 0; --x)
+       {
+               X = *src++ + X;
+               *dst++ = X;
+       }
+       // now do the rest of the rows
+       for (y = h - 1; y > 0; --y)
+       {
+               uint32_t L = 0;
+               uint32_t C = 0;
+               for (x = w - 1; x >= 0; --x)
+               {
+                       uint32_t T = dst[-w];
+                       X = *src++ + L + T - C;
+                       *dst++ = X;
+                       L = X;
+                       C = T;
+               }
+       }
+}
+
+static void apply_kernel(uint8_t dst[], int rx, int ry, const uint32_t src[], int sw, int sh)
+{
+       uint32_t scale = (1 << 24) / ((2*rx + 1)*(2*ry + 1));
+
+       int rowBytes = sw;
+
+       int     dw = sw + 2*rx;
+       int dh = sh + 2*ry;
+
+       sw -= 1;        // now it is max_x
+       sh -= 1;        // now it is max_y
+
+       int     prev_y = -ry - 1        -ry;
+       int     next_y = ry                     -ry;
+
+       for (int y = 0; y < dh; y++)
+       {
+               int py = SkClampPos(prev_y) * rowBytes;
+               int     ny = SkFastMin32(next_y, sh) * rowBytes;
+
+               int prev_x = -rx - 1    -rx;
+               int next_x = rx                 -rx;
+
+               for (int x = 0; x < dw; x++)
+               {
+                       int px = SkClampPos(prev_x);
+                       int     nx = SkFastMin32(next_x, sw);
+
+                       uint32_t sum = src[px+py] + src[nx+ny] - src[nx+py] - src[px+ny];
+                       *dst++ = SkToU8(sum * scale >> 24);
+
+                       prev_x += 1;
+                       next_x += 1;
+               }
+               prev_y += 1;
+               next_y += 1;
+       }
+}
+
+static void apply_kernel_interp(uint8_t dst[], int rx, int ry, const uint32_t src[], int sw, int sh, U8CPU outer_weight)
+{
+       SkASSERT(rx > 0 && ry > 0);
+       SkASSERT(outer_weight <= 255);
+
+       int inner_weight = 255 - outer_weight;
+
+       // round these guys up if they're bigger than 127
+       outer_weight += outer_weight >> 7;
+       inner_weight += inner_weight >> 7;
+
+       uint32_t outer_scale = (outer_weight << 16) / ((2*rx + 1)*(2*ry + 1));
+       uint32_t inner_scale = (inner_weight << 16) / ((2*rx - 1)*(2*ry - 1));
+
+       int rowBytes = sw;
+
+       int     dw = sw + 2*rx;
+       int dh = sh + 2*ry;
+
+       sw -= 1;        // now it is max_x
+       sh -= 1;        // now it is max_y
+
+       int     prev_y = -ry - 1        -ry;
+       int     next_y = ry                     -ry;
+
+       for (int y = 0; y < dh; y++)
+       {
+               int py = SkClampPos(prev_y) * rowBytes;
+               int     ny = SkFastMin32(next_y, sh) * rowBytes;
+
+               int ipy = SkClampPos(prev_y + 1) * rowBytes;
+               int     iny = SkClampMax(next_y - 1, sh) * rowBytes;
+
+               int prev_x = -rx - 1    -rx;
+               int next_x = rx                 -rx;
+
+               for (int x = 0; x < dw; x++)
+               {
+                       int px = SkClampPos(prev_x);
+                       int     nx = SkFastMin32(next_x, sw);
+
+                       int ipx = SkClampPos(prev_x + 1);
+                       int     inx = SkClampMax(next_x - 1, sw);
+
+                       uint32_t outer_sum = src[px+py] + src[nx+ny] - src[nx+py] - src[px+ny];
+                       uint32_t inner_sum = src[ipx+ipy] + src[inx+iny] - src[inx+ipy] - src[ipx+iny];
+                       *dst++ = SkToU8((outer_sum * outer_scale + inner_sum * inner_scale) >> 24);
+
+                       prev_x += 1;
+                       next_x += 1;
+               }
+               prev_y += 1;
+               next_y += 1;
+       }
+}
+
+#include "SkColorPriv.h"
+
+static void merge_src_with_blur(uint8_t dst[],
+                                                               const uint8_t src[], int sw, int sh,
+                                                               const uint8_t blur[], int blurRowBytes)
+{
+       while (--sh >= 0)
+       {
+               for (int x = sw - 1; x >= 0; --x)
+               {
+                       *dst = SkToU8(SkAlphaMul(*blur, SkAlpha255To256(*src)));
+                       dst += 1;
+                       src += 1;
+                       blur += 1;
+               }
+               blur += blurRowBytes - sw;
+       }
+}
+
+static void clamp_with_orig(uint8_t dst[], int dstRowBytes,
+                                                       const uint8_t src[], int sw, int sh,
+                                                       SkBlurMask::Style style)
+{
+       int     x;
+       while (--sh >= 0)
+       {
+               switch (style) {
+               case SkBlurMask::kSolid_Style:
+                       for (x = sw - 1; x >= 0; --x)
+                       {
+                               *dst = SkToU8(*src + SkAlphaMul(*dst, SkAlpha255To256(255 - *src)));
+                               dst += 1;
+                               src += 1;
+                       }
+                       break;
+               case SkBlurMask::kOuter_Style:
+                       for (x = sw - 1; x >= 0; --x)
+                       {
+                               if (*src)
+                                       *dst = SkToU8(SkAlphaMul(*dst, SkAlpha255To256(255 - *src)));
+                               dst += 1;
+                               src += 1;
+                       }
+                       break;
+               default:
+                       SkASSERT(!"Unexpected blur style here");
+                       break;
+               }
+               dst += dstRowBytes - sw;
+       }
+}
+
+////////////////////////////////////////////////////////////////////////
+
+// we use a local funciton to wrap the class static method to work around
+// a bug in gcc98
+void SkMask_FreeImage(uint8_t* image);
+void SkMask_FreeImage(uint8_t* image)
+{
+    SkMask::FreeImage(image);
+}
+
+bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
+                                         SkScalar radius, Style style)
+{
+       if (src.fFormat != SkMask::kA8_Format)
+               return false;
+
+       int     rx = SkScalarCeil(radius);
+       int     outer_weight = 255 - SkScalarRound((SkIntToScalar(rx) - radius) * 255);
+
+       SkASSERT(rx >= 0);
+       SkASSERT((unsigned)outer_weight <= 255);
+
+       if (rx == 0)
+               return false;
+
+       int ry = rx;    // only do square blur for now
+
+       dst->fBounds.set(src.fBounds.fLeft - rx, src.fBounds.fTop - ry,
+                                               src.fBounds.fRight + rx, src.fBounds.fBottom + ry);
+       dst->fRowBytes = SkToU16(dst->fBounds.width());
+       dst->fFormat = SkMask::kA8_Format;
+       dst->fImage     = nil;
+
+       if (src.fImage)
+       {
+               int             sw = src.fBounds.width();
+               int             sh = src.fBounds.height();
+               const uint8_t*  sp = src.fImage;
+               uint8_t*        dp = SkMask::AllocImage(dst->computeImageSize());
+
+               SkAutoTCallProc<uint8_t, SkMask_FreeImage> autoCall(dp);
+
+               // build the blurry destination
+               {
+            SkAutoTMalloc<uint32_t> storage(sw * sh);
+                       uint32_t*               sumBuffer = storage.get();
+
+                       build_sum_buffer(sumBuffer, sw, sh, sp);
+                       if (outer_weight == 255)
+                               apply_kernel(dp, rx, ry, sumBuffer, sw, sh);
+                       else
+                               apply_kernel_interp(dp, rx, ry, sumBuffer, sw, sh, outer_weight);
+               }
+
+               dst->fImage = dp;
+               // if need be, alloc the "real" dst (same size as src) and copy/merge
+               // the blur into it (applying the src)
+               if (style == kInner_Style)
+               {
+                       dst->fImage = SkMask::AllocImage(src.computeImageSize());
+                       merge_src_with_blur(dst->fImage, sp, sw, sh,
+                                                               dp + rx + ry*dst->fBounds.width(),
+                                                               dst->fBounds.width());
+                       SkMask::FreeImage(dp);
+               }
+               else if (style != kNormal_Style)
+               {
+                       clamp_with_orig(dp + rx + ry*dst->fBounds.width(),
+                                                       dst->fBounds.width(),
+                                                       sp, sw, sh,
+                                                       style);
+               }
+               (void)autoCall.detach();
+       }
+
+       if (style == kInner_Style)
+       {
+               dst->fBounds = src.fBounds;     // restore trimmed bounds
+               dst->fRowBytes = SkToU16(dst->fBounds.width());
+       }
+
+#if 0
+       if (gamma && dst->fImage)
+       {
+               uint8_t*        image = dst->fImage;
+               uint8_t*        stop = image + dst->computeImageSize();
+
+               for (; image < stop; image += 1)
+                       *image = gamma[*image];
+       }
+#endif
+       return true;
+}
+
+#if 0
+void SkBlurMask::BuildSqrtGamma(uint8_t gamma[256], SkScalar percent)
+{
+       SkASSERT(gamma);
+       SkASSERT(percent >= 0 && percent <= SK_Scalar1);
+
+       int     scale = SkScalarRound(percent * 256);
+
+       for (int i = 0; i < 256; i++)
+       {
+               SkFixed n = i * 257;
+               n += n >> 15;
+               SkASSERT(n >= 0 && n <= SK_Fixed1);
+               n = SkFixedSqrt(n);
+               n = n * 255 >> 16;
+               n = SkAlphaBlend(n, i, scale);
+               gamma[i] = SkToU8(n);
+       }
+}
+
+void SkBlurMask::BuildSqrGamma(uint8_t gamma[256], SkScalar percent)
+{
+       SkASSERT(gamma);
+       SkASSERT(percent >= 0 && percent <= SK_Scalar1);
+
+       int             scale = SkScalarRound(percent * 256);
+       SkFixed div255 = SK_Fixed1 / 255;
+
+       for (int i = 0; i < 256; i++)
+       {
+               int square = i * i;
+               int linear = i * 255;
+               int n = SkAlphaBlend(square, linear, scale);
+               gamma[i] = SkToU8(n * div255 >> 16);
+       }
+}
+#endif
diff --git a/libs/graphics/effects/SkBlurMask.h b/libs/graphics/effects/SkBlurMask.h
new file mode 100644 (file)
index 0000000..40cea94
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef SkBlurMask_DEFINED
+#define SkBlurMask_DEFINED
+
+#include "SkShader.h"
+
+class SkBlurMask {
+public:
+       enum Style {
+               kNormal_Style,  //!< fuzzy inside and outside
+               kSolid_Style,   //!< solid inside, fuzzy outside
+               kOuter_Style,   //!< nothing inside, fuzzy outside
+               kInner_Style,   //!< fuzzy inside, nothing outside
+
+               kStyleCount
+       };
+
+       static bool Blur(SkMask* dst, const SkMask& src, SkScalar radius, Style);
+};
+
+#endif
+
+
+
diff --git a/libs/graphics/effects/SkBlurMaskFilter.cpp b/libs/graphics/effects/SkBlurMaskFilter.cpp
new file mode 100644 (file)
index 0000000..8073bc5
--- /dev/null
@@ -0,0 +1,96 @@
+#include "SkBlurMaskFilter.h"
+#include "SkBlurMask.h"
+#include "SkBuffer.h"
+
+class SkBlurMaskFilterImpl : public SkMaskFilter {
+public:
+       SkBlurMaskFilterImpl(SkScalar radius, SkBlurMaskFilter::BlurStyle style);
+
+       // overrides from SkMaskFilter
+       virtual SkMask::Format getFormat();
+       virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkPoint16* margin);
+
+       // overrides from SkFlattenable
+    // This method is not exported to java.
+       virtual Factory getFactory();
+    // This method is not exported to java.
+       virtual void flatten(SkWBuffer&);
+
+private:
+       SkScalar                    fRadius;
+       SkBlurMaskFilter::BlurStyle     fBlurStyle;
+
+       static SkFlattenable* CreateProc(SkRBuffer&);
+    SkBlurMaskFilterImpl(SkRBuffer&);
+    
+    typedef SkMaskFilter INHERITED;
+};
+
+SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius, SkBlurMaskFilter::BlurStyle style)
+{
+    if (radius <= 0 || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount)
+        return NULL;
+
+    return SkNEW_ARGS(SkBlurMaskFilterImpl, (radius, style));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar radius, SkBlurMaskFilter::BlurStyle style)
+       : fRadius(radius), fBlurStyle(style)
+{
+#if 0
+       fGamma = NULL;
+       if (gammaScale)
+       {
+               fGamma = new U8[256];
+               if (gammaScale > 0)
+                       SkBlurMask::BuildSqrGamma(fGamma, gammaScale);
+               else
+                       SkBlurMask::BuildSqrtGamma(fGamma, -gammaScale);
+       }
+#endif
+       SkASSERT(radius >= 0);
+       SkASSERT((unsigned)style < SkBlurMaskFilter::kBlurStyleCount);
+}
+
+SkMask::Format SkBlurMaskFilterImpl::getFormat()
+{
+       return SkMask::kA8_Format;
+}
+
+bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkPoint16* margin)
+{
+       SkScalar radius = matrix.mapRadius(fRadius);
+
+       if (margin)
+               margin->set(SkScalarCeil(radius), SkScalarCeil(radius));
+
+       return SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle);
+}
+
+SkFlattenable* SkBlurMaskFilterImpl::CreateProc(SkRBuffer& buffer)
+{
+    return SkNEW_ARGS(SkBlurMaskFilterImpl, (buffer));
+}
+
+SkFlattenable::Factory SkBlurMaskFilterImpl::getFactory()
+{
+       return CreateProc;
+}
+
+SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkRBuffer& buffer) : SkMaskFilter(buffer)
+{
+    fRadius = buffer.readScalar();
+    fBlurStyle = (SkBlurMaskFilter::BlurStyle)buffer.readS32();
+       SkASSERT(fRadius >= 0);
+       SkASSERT((unsigned)fBlurStyle < SkBlurMaskFilter::kBlurStyleCount);
+}
+
+void SkBlurMaskFilterImpl::flatten(SkWBuffer& buffer)
+{
+    this->INHERITED::flatten(buffer);
+    buffer.writeScalar(fRadius);
+    buffer.write32(fBlurStyle);
+}
+
diff --git a/libs/graphics/effects/SkCamera.cpp b/libs/graphics/effects/SkCamera.cpp
new file mode 100644 (file)
index 0000000..fcebf44
--- /dev/null
@@ -0,0 +1,251 @@
+#include "SkCamera.h"
+
+static SkScalar VectorMultiplyDivide(int count, const SkScalar a[], int step_a,
+                                                                        const SkScalar b[], int step_b, SkScalar denom)
+{
+#ifdef SK_SCALAR_IS_FLOAT
+       float prod = 0;
+       for (int i = 0; i < count; i++)
+       {
+               prod += a[0] * b[0];
+               a += step_a;
+               b += step_b;
+       }
+       if (denom)      // denom == 0 is a formal signal to not divide
+               prod /= denom;
+       return prod;
+#else
+       Sk64    prod, tmp;
+
+       prod.set(0);
+       for (int i = 0; i < count; i++)
+       {
+               tmp.setMul(a[0], b[0]);
+               prod.add(tmp);
+               a += step_a;
+               b += step_b;
+       }
+       if (denom)
+       {
+               prod.div(denom, Sk64::kRound_DivOption);
+               return prod.get32();
+       }
+       else    // denom == 0 is a formal signal to treat the product as a fixed (i.e. denom = SK_Fixed1)
+               return prod.getFixed();
+#endif
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+SkUnitScalar SkPoint3D::normalize(SkUnit3D* unit) const
+{
+#ifdef SK_SCALAR_IS_FLOAT
+       float mag = sk_float_sqrt(fX*fX + fY*fY + fZ*fZ);
+       if (mag)
+       {
+               float scale = 1.0f / mag;
+               unit->fX = fX * scale;
+               unit->fY = fY * scale;
+               unit->fZ = fZ * scale;
+       }
+#else
+       Sk64    tmp1, tmp2;
+
+       tmp1.setMul(fX, fX);
+       tmp2.setMul(fY, fY);
+       tmp1.add(tmp2);
+       tmp2.setMul(fZ, fZ);
+       tmp1.add(tmp2);
+
+       SkFixed mag = tmp1.getSqrt();
+       if (mag)
+       {
+               // what if mag < SK_Fixed1 ??? we will underflow the fixdiv
+               SkFixed scale = SkFixedDiv(SK_Fract1, mag);
+               unit->fX = SkFixedMul(fX, scale);
+               unit->fY = SkFixedMul(fY, scale);
+               unit->fZ = SkFixedMul(fZ, scale);
+       }
+#endif
+       return mag;
+}
+
+SkUnitScalar SkUnit3D::Dot(const SkUnit3D& a, const SkUnit3D& b)
+{
+       return  SkUnitScalarMul(a.fX, b.fX) +
+                       SkUnitScalarMul(a.fY, b.fY) +
+                       SkUnitScalarMul(a.fZ, b.fZ);
+}
+
+void SkUnit3D::Cross(const SkUnit3D& a, const SkUnit3D& b, SkUnit3D* cross)
+{
+       SkASSERT(cross);
+
+       // use x,y,z, in case &a == cross or &b == cross
+
+
+       SkScalar x = SkUnitScalarMul(a.fY, b.fZ) - SkUnitScalarMul(a.fZ, b.fY);
+       SkScalar y = SkUnitScalarMul(a.fZ, b.fX) - SkUnitScalarMul(a.fX, b.fY);
+       SkScalar z = SkUnitScalarMul(a.fX, b.fY) - SkUnitScalarMul(a.fY, b.fX);
+
+       cross->set(x, y, z);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+SkPatch3D::SkPatch3D()
+{
+       this->reset();
+}
+
+void SkPatch3D::reset()
+{
+       fOrigin.set(0, 0, 0);
+       fU.set(SK_Scalar1, 0, 0);
+       fV.set(0, -SK_Scalar1, 0);
+}
+
+struct SkMatrix3D {
+       SkScalar        fMat[3][3];
+
+       void set(int row, SkScalar a, SkScalar b, SkScalar c)
+       {
+               fMat[row][0] = a;
+               fMat[row][1] = b;
+               fMat[row][2] = c;
+       }
+       void setConcat(const SkMatrix3D& a, const SkMatrix3D& b)
+       {
+               SkMatrix3D      tmp;
+               SkMatrix3D*     c = this;
+
+               if (this == &a || this == &b)
+                       c = &tmp;
+
+               for (int i = 0; i < 3; i++)
+                       for (int j = 0; j < 3; j++)
+                               c->fMat[i][j] = VectorMultiplyDivide(3, &a.fMat[i][0], 1, &b.fMat[0][j], 3, 0);
+
+               if (c == &tmp)
+                       *this = tmp;
+       }
+
+       void map(SkPoint3D* v) const
+       {
+               SkScalar x = VectorMultiplyDivide(3, &fMat[0][0], 1, &v->fX, 1, 0);
+               SkScalar y = VectorMultiplyDivide(3, &fMat[1][0], 1, &v->fX, 1, 0);
+               SkScalar z = VectorMultiplyDivide(3, &fMat[2][0], 1, &v->fX, 1, 0);
+               v->set(x, y, z);
+       }
+};
+
+void SkPatch3D::rotate(SkScalar radX, SkScalar radY, SkScalar radZ)
+{
+       SkScalar        s, c;
+       SkMatrix3D      mx, my, mz, m;
+
+       s = SkScalarSinCos(radX, &c);
+       mx.set(0, SK_Scalar1, 0, 0);
+       mx.set(1, 0, c, -s);
+       mx.set(2, 0, s, c);
+
+       s = SkScalarSinCos(radY, &c);
+       my.set(0, c, 0, -s);
+       my.set(1, 0, SK_Scalar1, 0);
+       my.set(2, s, 0, c);
+
+       s = SkScalarSinCos(radZ, &c);
+       mz.set(0, c, -s, 0);
+       mz.set(1, s, c, 0);
+       mz.set(2, 0, 0, SK_Scalar1);
+
+       m.setConcat(mx, my);
+       m.setConcat(m, mz);
+
+       m.map(&fU);
+       m.map(&fV);
+}
+
+SkScalar SkPatch3D::dotWith(SkScalar dx, SkScalar dy, SkScalar dz) const
+{
+       SkUnit3D        normal;
+
+       SkUnit3D::Cross(*(SkUnit3D*)&fU, *(SkUnit3D*)&fV, &normal);
+       return  SkUnitScalarMul(normal.fX, dx) +
+                       SkUnitScalarMul(normal.fY, dy) +
+                       SkUnitScalarMul(normal.fZ, dz);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+SkCamera3D::SkCamera3D()
+{
+    fLocation.set(0, 0, -SkIntToScalar(1440)); // 20 inches backward
+       fAxis.set(0, 0, SK_Scalar1);                            // forward
+       fZenith.set(0, -SK_Scalar1, 0);                         // up
+       fObserver.set(0, 0, -SkIntToScalar(1440));      // 20 inches backward
+
+       this->update();
+}
+
+void SkCamera3D::update()
+{
+       SkUnit3D        axis, zenith, cross;
+
+       fAxis.normalize(&axis);
+
+       {
+               SkScalar dot = SkUnit3D::Dot(*(SkUnit3D*)&fZenith, axis);
+
+               zenith.fX = fZenith.fX - SkUnitScalarMul(dot, axis.fX);
+               zenith.fY = fZenith.fY - SkUnitScalarMul(dot, axis.fY);
+               zenith.fZ = fZenith.fZ - SkUnitScalarMul(dot, axis.fZ);
+
+               (void)((SkPoint3D*)&zenith)->normalize(&zenith);
+       }
+
+       SkUnit3D::Cross(axis, zenith, &cross);
+
+       {
+               SkScalar* destPtr = (SkScalar*)&fOrientation;
+               SkScalar x = fObserver.fX;
+               SkScalar y = fObserver.fY;
+               SkScalar z = fObserver.fZ;
+
+               destPtr[0] = SkUnitScalarMul(x, axis.fX) - SkUnitScalarMul(z, cross.fX);
+               destPtr[1] = SkUnitScalarMul(x, axis.fY) - SkUnitScalarMul(z, cross.fY);
+               destPtr[2] = SkUnitScalarMul(x, axis.fZ) - SkUnitScalarMul(z, cross.fZ);
+               destPtr[3] = SkUnitScalarMul(y, axis.fX) - SkUnitScalarMul(z, zenith.fX);
+               destPtr[4] = SkUnitScalarMul(y, axis.fY) - SkUnitScalarMul(z, zenith.fY);
+               destPtr[5] = SkUnitScalarMul(y, axis.fZ) - SkUnitScalarMul(z, zenith.fZ);
+               memcpy(&destPtr[6], &axis, sizeof(axis));
+    }
+}
+
+void SkCamera3D::computeMatrix(const SkPatch3D& quilt, SkMatrix* matrix) const
+{
+       SkScalar*               destPtr = (SkScalar*)matrix;
+       const SkScalar* mapPtr = (const SkScalar*)&fOrientation;
+       const SkScalar* patchPtr;
+       SkPoint3D               diff;
+       SkScalar                dot;
+
+       diff.fX = quilt.fOrigin.fX - fLocation.fX;
+       diff.fY = quilt.fOrigin.fY - fLocation.fY;
+       diff.fZ = quilt.fOrigin.fZ - fLocation.fZ;
+
+       dot = SkUnit3D::Dot(*(const SkUnit3D*)&diff, *(const SkUnit3D*)((const SkScalar*)&fOrientation + 6));
+
+       patchPtr = (const SkScalar*)&quilt;
+       destPtr[0] = VectorMultiplyDivide(3, patchPtr, 1, mapPtr, 1, dot);
+       destPtr[3] = VectorMultiplyDivide(3, patchPtr, 1, mapPtr+3, 1, dot);
+       destPtr[6] = VectorMultiplyDivide(3, patchPtr, 1, mapPtr+6, 1, dot);
+       patchPtr += 3;
+       destPtr[1] = VectorMultiplyDivide(3, patchPtr, 1, mapPtr, 1, dot);
+       destPtr[4] = VectorMultiplyDivide(3, patchPtr, 1, mapPtr+3, 1, dot);
+       destPtr[7] = VectorMultiplyDivide(3, patchPtr, 1, mapPtr+6, 1, dot);
+       patchPtr = (const SkScalar*)&diff;
+       destPtr[2] = VectorMultiplyDivide(3, patchPtr, 1, mapPtr, 1, dot);
+       destPtr[5] = VectorMultiplyDivide(3, patchPtr, 1, mapPtr+3, 1, dot);
+       destPtr[8] = SK_UnitScalar1;
+}
diff --git a/libs/graphics/effects/SkColorFilters.cpp b/libs/graphics/effects/SkColorFilters.cpp
new file mode 100644 (file)
index 0000000..0809f0f
--- /dev/null
@@ -0,0 +1,264 @@
+#include "SkColorFilter.h"
+#include "SkColorPriv.h"
+#include "SkPorterDuff.h"
+#include "SkUtils.h"
+
+class SkSrc_XfermodeColorFilter : public SkColorFilter {
+public:
+    SkSrc_XfermodeColorFilter(SkColor color) : fColor(SkPreMultiplyColor(color)) {}
+
+    virtual void filterSpan(const SkPMColor shader[], int count, SkPMColor result[])
+    {
+        sk_memset32(result, fColor, count);
+    }
+
+private:
+    SkPMColor   fColor;
+};
+
+class SkSrcOver_XfermodeColorFilter : public SkColorFilter {
+public:
+    SkSrcOver_XfermodeColorFilter(SkColor color) : fColor(SkPreMultiplyColor(color)) {}
+
+    virtual void filterSpan(const SkPMColor shader[], int count, SkPMColor result[])
+    {
+        SkPMColor   src = fColor;
+        unsigned    scale = SkAlpha255To256(255 - SkGetPackedA32(src));
+        
+        for (int i = 0; i < count; i++)
+            result[i] = src + SkAlphaMulQ(shader[i], scale);
+    }
+
+private:
+    SkPMColor   fColor;
+};
+
+class SkXfermodeColorFilter : public SkColorFilter {
+public:
+    SkXfermodeColorFilter(SkColor color, SkXfermodeProc proc)
+    {
+        fColor = SkPreMultiplyColor(color);
+        fProc = proc;
+    }
+
+    virtual void filterSpan(const SkPMColor shader[], int count, SkPMColor result[])
+    {
+        SkPMColor       color = fColor;
+        SkXfermodeProc  proc = fProc;
+        
+        for (int i = 0; i < count; i++)
+            result[i] = proc(color, shader[i]);
+    }
+
+private:
+    SkPMColor       fColor;
+    SkXfermodeProc  fProc;
+};
+
+SkColorFilter* SkColorFilter::CreatXfermodeFilter(SkColor color, SkXfermodeProc proc)
+{
+    return proc ? SkNEW_ARGS(SkXfermodeColorFilter, (color, proc)) : NULL;
+}
+
+SkColorFilter* SkColorFilter::CreatePorterDuffFilter(SkColor color, SkPorterDuff::Mode mode)
+{
+    // first collaps some modes if possible
+
+    if (SkPorterDuff::kClear_Mode == mode)
+    {
+        color = 0;
+        mode = SkPorterDuff::kSrc_Mode;
+    }
+    else if (SkPorterDuff::kSrcOver_Mode == mode)
+    {
+        unsigned alpha = SkColorGetA(color);
+
+        if (0 == alpha)
+            mode = SkPorterDuff::kDst_Mode;
+        else if (255 == alpha)
+            mode = SkPorterDuff::kSrc_Mode;
+        // else just stay srcover
+    }
+
+    switch (mode) {
+    case SkPorterDuff::kSrc_Mode:
+        return SkNEW_ARGS(SkSrc_XfermodeColorFilter, (color));
+    case SkPorterDuff::kDst_Mode:
+        return SkNEW(SkColorFilter);
+    case SkPorterDuff::kSrcOver_Mode:
+        return SkNEW_ARGS(SkSrcOver_XfermodeColorFilter, (color));
+    default:
+        return SkColorFilter::CreatXfermodeFilter(color, SkPorterDuff::GetXfermodeProc(mode));
+    }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+static inline unsigned pin(unsigned value, unsigned max)
+{
+    if (value > max)
+        value = max;
+    return value;
+}
+
+static inline unsigned SkUClampMax(unsigned value, unsigned max)
+{
+       SkASSERT((S32)value >= 0);
+       SkASSERT((S32)max >= 0);
+
+       int     diff = max - value;
+       // clear diff if diff is positive
+       diff &= diff >> 31;
+
+       return value + diff;
+}
+
+class SkLightingColorFilter : public SkColorFilter {
+public:
+    SkLightingColorFilter(SkColor mul, SkColor add) : fMul(mul), fAdd(add) {}
+
+    virtual void filterSpan(const SkPMColor shader[], int count, SkPMColor result[])
+    {
+        unsigned scaleR = SkAlpha255To256(SkColorGetR(fMul));
+        unsigned scaleG = SkAlpha255To256(SkColorGetG(fMul));
+        unsigned scaleB = SkAlpha255To256(SkColorGetB(fMul));
+        
+        unsigned addR = SkColorGetR(fAdd);
+        unsigned addG = SkColorGetG(fAdd);
+        unsigned addB = SkColorGetB(fAdd);
+
+        for (int i = 0; i < count; i++)
+        {
+            SkPMColor c = shader[i];
+            if (c)
+            {
+                unsigned a = SkGetPackedA32(c);
+                unsigned scaleA = SkAlpha255To256(a);                
+                unsigned r = pin(SkAlphaMul(SkGetPackedR32(c), scaleR) + SkAlphaMul(addR, scaleA), a);
+                unsigned g = pin(SkAlphaMul(SkGetPackedG32(c), scaleG) + SkAlphaMul(addG, scaleA), a);
+                unsigned b = pin(SkAlphaMul(SkGetPackedB32(c), scaleB) + SkAlphaMul(addB, scaleA), a);
+                c = SkPackARGB32(a, r, g, b);
+            }
+            result[i] = c;
+        }
+    }
+
+protected:
+    SkColor fMul, fAdd;
+};
+
+class SkLightingColorFilter_JustAdd : public SkColorFilter {
+public:
+    SkLightingColorFilter_JustAdd(SkColor add) : fAdd(add) {}
+
+    virtual void filterSpan(const SkPMColor shader[], int count, SkPMColor result[])
+    {
+        unsigned addR = SkColorGetR(fAdd);
+        unsigned addG = SkColorGetG(fAdd);
+        unsigned addB = SkColorGetB(fAdd);
+
+        for (int i = 0; i < count; i++)
+        {
+            SkPMColor c = shader[i];
+            if (c)
+            {
+                unsigned a = SkGetPackedA32(c);
+                unsigned scaleA = SkAlpha255To256(a);                
+                unsigned r = pin(SkGetPackedR32(c) + SkAlphaMul(addR, scaleA), a);
+                unsigned g = pin(SkGetPackedG32(c) + SkAlphaMul(addG, scaleA), a);
+                unsigned b = pin(SkGetPackedB32(c) + SkAlphaMul(addB, scaleA), a);
+                c = SkPackARGB32(a, r, g, b);
+            }
+            result[i] = c;
+        }
+    }
+
+private:
+    SkColor fAdd;
+};
+
+class SkLightingColorFilter_JustMul : public SkColorFilter {
+public:
+    SkLightingColorFilter_JustMul(SkColor mul) : fMul(mul) {}
+
+    virtual void filterSpan(const SkPMColor shader[], int count, SkPMColor result[])
+    {
+        unsigned scaleR = SkAlpha255To256(SkColorGetR(fMul));
+        unsigned scaleG = SkAlpha255To256(SkColorGetG(fMul));
+        unsigned scaleB = SkAlpha255To256(SkColorGetB(fMul));
+        
+        for (int i = 0; i < count; i++)
+        {
+            SkPMColor c = shader[i];
+            if (c)
+            {
+                unsigned a = SkGetPackedA32(c);
+                unsigned r = SkAlphaMul(SkGetPackedR32(c), scaleR);
+                unsigned g = SkAlphaMul(SkGetPackedG32(c), scaleG);
+                unsigned b = SkAlphaMul(SkGetPackedB32(c), scaleB);
+                c = SkPackARGB32(a, r, g, b);
+            }
+            result[i] = c;
+        }
+    }
+
+private:
+    SkColor fMul;
+};
+
+class SkLightingColorFilter_NoPin : public SkLightingColorFilter {
+public:
+    SkLightingColorFilter_NoPin(SkColor mul, SkColor add)
+        : SkLightingColorFilter(mul, add) {}
+
+    virtual void filterSpan(const SkPMColor shader[], int count, SkPMColor result[])
+    {
+        unsigned scaleR = SkAlpha255To256(SkColorGetR(fMul));
+        unsigned scaleG = SkAlpha255To256(SkColorGetG(fMul));
+        unsigned scaleB = SkAlpha255To256(SkColorGetB(fMul));
+        
+        unsigned addR = SkColorGetR(fAdd);
+        unsigned addG = SkColorGetG(fAdd);
+        unsigned addB = SkColorGetB(fAdd);
+
+        for (int i = 0; i < count; i++)
+        {
+            SkPMColor c = shader[i];
+            if (c)
+            {
+                unsigned a = SkGetPackedA32(c);
+                unsigned scaleA = SkAlpha255To256(a);                
+                unsigned r = SkAlphaMul(SkGetPackedR32(c), scaleR) + SkAlphaMul(addR, scaleA);
+                unsigned g = SkAlphaMul(SkGetPackedG32(c), scaleG) + SkAlphaMul(addG, scaleA);
+                unsigned b = SkAlphaMul(SkGetPackedB32(c), scaleB) + SkAlphaMul(addB, scaleA);
+                c = SkPackARGB32(a, r, g, b);
+            }
+            result[i] = c;
+        }
+    }
+};
+
+SkColorFilter* SkColorFilter::CreateLightingFilter(SkColor mul, SkColor add)
+{
+    mul &= 0x00FFFFFF;
+    add &= 0x00FFFFFF;
+
+    if (0xFFFFFF == mul)
+    {
+        if (0 == add)
+            return SkNEW(SkColorFilter);   // no change to the colors
+        else
+            return SkNEW_ARGS(SkLightingColorFilter_JustAdd, (add));
+    }
+
+    if (0 == add)
+        return SkNEW_ARGS(SkLightingColorFilter_JustMul, (mul));
+
+    if (SkColorGetR(mul) + SkColorGetR(add) <= 255 &&
+        SkColorGetG(mul) + SkColorGetG(add) <= 255 &&
+        SkColorGetB(mul) + SkColorGetB(add) <= 255)
+        return SkNEW_ARGS(SkLightingColorFilter_NoPin, (mul, add));
+
+    return SkNEW_ARGS(SkLightingColorFilter, (mul, add));
+}
+
diff --git a/libs/graphics/effects/SkCornerPathEffect.cpp b/libs/graphics/effects/SkCornerPathEffect.cpp
new file mode 100644 (file)
index 0000000..fdc36d4
--- /dev/null
@@ -0,0 +1,117 @@
+#include "SkCornerPathEffect.h"
+#include "SkPath.h"
+#include "SkPoint.h"
+#include "SkBuffer.h"
+
+SkCornerPathEffect::SkCornerPathEffect(SkScalar radius) : fRadius(radius)
+{
+}
+
+SkCornerPathEffect::~SkCornerPathEffect()
+{
+}
+
+static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius, SkPoint* step)
+{
+    SkScalar dist = SkPoint::Distance(a, b);
+
+    step->set(b.fX - a.fX, b.fY - a.fY);
+    
+    if (dist <= radius * 2) {
+        step->scale(SK_ScalarHalf);
+        return false;
+    }
+    else {
+        step->scale(SkScalarDiv(radius, dist));
+        return true;
+    }
+}
+
+bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
+{
+    if (fRadius == 0)
+        return false;
+
+    SkPath::Iter    iter(src, false);
+    SkPath::Verb    verb, prevVerb = (SkPath::Verb)-1;
+    SkPoint         pts[4];
+
+    bool        closed;
+    SkPoint     moveTo, lastCorner;
+    SkVector    firstStep, step;
+    bool        prevIsValid = true;
+
+    for (;;) {
+        switch (verb = iter.next(pts)) {
+        case SkPath::kMove_Verb:
+            closed = iter.isClosedContour();
+            if (closed) {
+                moveTo = pts[0];
+                prevIsValid = false;
+            }
+            else {
+                dst->moveTo(pts[0]);
+                prevIsValid = true;
+            }
+            break;
+        case SkPath::kLine_Verb:
+            {
+                bool drawSegment = ComputeStep(pts[0], pts[1], fRadius, &step);
+                // prev corner
+                if (!prevIsValid) {
+                    dst->moveTo(moveTo + step);
+                    prevIsValid = true;
+                }
+                else {
+                    dst->quadTo(pts[0].fX, pts[0].fY, pts[0].fX + step.fX, pts[0].fY + step.fY);
+                }
+                if (drawSegment) {
+                    dst->lineTo(pts[1].fX - step.fX, pts[1].fY - step.fY);
+                }
+                lastCorner = pts[1];
+                prevIsValid = true;
+            }
+            break;
+        case SkPath::kQuad_Verb:
+            // TBD
+            break;
+        case SkPath::kCubic_Verb:
+            // TBD
+            break;
+        case SkPath::kClose_Verb:
+            dst->quadTo(lastCorner.fX, lastCorner.fY, lastCorner.fX + firstStep.fX, lastCorner.fY + firstStep.fY);
+            dst->close();
+            break;
+        case SkPath::kDone_Verb:
+            goto DONE;
+        }
+
+        if (SkPath::kMove_Verb == prevVerb)
+            firstStep = step;
+        prevVerb = verb;
+    }
+DONE:
+       return true;
+}
+
+SkFlattenable::Factory SkCornerPathEffect::getFactory()
+{
+       return CreateProc;
+}
+
+void SkCornerPathEffect::flatten(SkWBuffer& buffer)
+{
+    this->INHERITED::flatten(buffer);
+    buffer.writeScalar(fRadius);
+}
+
+SkFlattenable* SkCornerPathEffect::CreateProc(SkRBuffer& buffer)
+{
+    return SkNEW_ARGS(SkCornerPathEffect, (buffer));
+}
+
+SkCornerPathEffect::SkCornerPathEffect(SkRBuffer& buffer) : SkPathEffect(buffer)
+{
+    fRadius = buffer.readScalar();
+}
+
diff --git a/libs/graphics/effects/SkCullPoints.cpp b/libs/graphics/effects/SkCullPoints.cpp
new file mode 100644 (file)
index 0000000..6d004fa
--- /dev/null
@@ -0,0 +1,141 @@
+#include "SkCullPoints.h"
+#include "Sk64.h"
+
+static bool cross_product_is_neg(const SkPoint32& v, int dx, int dy)
+{
+#if 0
+    return v.fX * dy - v.fY * dx < 0;
+#else
+    Sk64   tmp0, tmp1;
+    
+    tmp0.setMul(v.fX, dy);
+    tmp1.setMul(dx, v.fY);
+    tmp0.sub(tmp1);
+    return tmp0.isNeg();
+#endif
+}
+
+bool SkCullPoints::sect_test(int x0, int y0, int x1, int y1) const
+{
+    const SkRect16& r = fR;
+
+    if (x0 < r.fLeft    && x1 < r.fLeft ||
+        x0 > r.fRight   && x1 > r.fRight ||
+        y0 < r.fTop     && y1 < r.fTop ||
+        y0 > r.fBottom  && y1 > r.fBottom)
+        return false;
+
+    // since the crossprod test is a little expensive, check for easy-in cases first    
+    if (r.contains(x0, y0) || r.contains(x1, y1))
+        return true;
+
+    // At this point we're not sure, so we do a crossprod test
+    SkPoint32           vec;
+    const SkPoint16*    rAsQuad = fAsQuad;
+    
+    vec.set(x1 - x0, y1 - y0);
+    bool isNeg = cross_product_is_neg(vec, x0 - rAsQuad[0].fX, y0 - rAsQuad[0].fY);
+    for (int i = 1; i < 4; i++) {
+        if (cross_product_is_neg(vec, x0 - rAsQuad[i].fX, y0 - rAsQuad[i].fY) != isNeg)
+        {
+            return true;
+        }
+    }
+    return false;   // we didn't intersect
+}
+
+static void toQuad(const SkRect16& r, SkPoint16 quad[4])
+{
+       SkASSERT(quad);
+
+       quad[0].set(r.fLeft, r.fTop);
+       quad[1].set(r.fRight, r.fTop);
+       quad[2].set(r.fRight, r.fBottom);
+       quad[3].set(r.fLeft, r.fBottom);
+}
+
+SkCullPoints::SkCullPoints()
+{
+    SkRect16    r;
+    r.setEmpty();
+    this->reset(r);
+}
+
+SkCullPoints::SkCullPoints(const SkRect16& r)
+{
+    this->reset(r);
+}
+
+void SkCullPoints::reset(const SkRect16& r)
+{
+    fR = r;
+    toQuad(fR, fAsQuad);
+    fPrevPt.set(0, 0);
+}
+
+void SkCullPoints::moveTo(int x, int y)
+{
+    fPrevPt.set(x, y);
+}
+
+SkCullPoints::LineToResult SkCullPoints::lineTo(int x, int y, SkPoint16 result[])
+{
+    SkASSERT(result != NULL);
+
+    int x0 = fPrevPt.fX;
+    int y0 = fPrevPt.fY;
+    fPrevPt.set(x, y);
+    
+    // need to upgrade sect_test to chop the result
+    // and to correctly return kLineTo_Result when the result is connected
+    // to the previous call-out
+    if (this->sect_test(x0, y0, x, y))
+    {
+        result[0].set(x0, y0);
+        result[1].set(x, y);
+        return kMoveToLineTo_Result;
+    }
+    return kNo_Result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkPath.h"
+
+SkCullPointsPath::SkCullPointsPath()
+    : fCP(), fPath(NULL)
+{
+}
+
+SkCullPointsPath::SkCullPointsPath(const SkRect16& r, SkPath* dst)
+    : fCP(r), fPath(dst)
+{
+}
+
+void SkCullPointsPath::reset(const SkRect16& r, SkPath* dst)
+{
+    fCP.reset(r);
+    fPath = dst;
+}
+    
+void SkCullPointsPath::moveTo(int x, int y)
+{
+    fCP.moveTo(x, y);
+}
+
+void SkCullPointsPath::lineTo(int x, int y)
+{
+    SkPoint16   pts[2];
+    
+    switch (fCP.lineTo(x, y, pts)) {
+    case SkCullPoints::kMoveToLineTo_Result:
+        fPath->moveTo(SkIntToScalar(pts[0].fX), SkIntToScalar(pts[0].fY));
+        // fall through to the lineto case
+    case SkCullPoints::kLineTo_Result:
+        fPath->lineTo(SkIntToScalar(pts[1].fX), SkIntToScalar(pts[1].fY));
+        break;
+    default:
+        break;
+    }
+}
+
diff --git a/libs/graphics/effects/SkDashPathEffect.cpp b/libs/graphics/effects/SkDashPathEffect.cpp
new file mode 100644 (file)
index 0000000..782cf2d
--- /dev/null
@@ -0,0 +1,163 @@
+#include "SkDashPathEffect.h"
+#include "SkBuffer.h"
+#include "SkPathMeasure.h"
+
+static inline int is_even(int x)
+{
+       return (~x) << 31;
+}
+
+static SkScalar FindFirstInterval(const SkScalar intervals[], SkScalar phase, int32_t* index)
+{
+       int i;
+
+       for (i = 0; phase > intervals[i]; i++)
+               phase -= intervals[i];
+       *index = i;
+       return intervals[i] - phase;
+}
+
+SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count, SkScalar phase, bool scaleToFit)
+       : fScaleToFit(scaleToFit)
+{
+       SkASSERT(intervals);
+       SkASSERT(count > 1 && SkAlign2(count) == count);
+
+       fIntervals = (SkScalar*)sk_malloc_throw(sizeof(SkScalar) * count);
+       fCount = count;
+
+       SkScalar len = 0;
+       for (int i = 0; i < count; i++)
+       {
+               SkASSERT(intervals[i] >= 0);
+               fIntervals[i] = intervals[i];
+               len += intervals[i];
+       }
+       fIntervalLength = len;
+
+       if (len > 0)    // we don't handle 0 length dash arrays
+       {
+               if (phase < 0)
+               {
+                       phase = -phase;
+                       if (phase > len)
+                               phase = SkScalarMod(phase, len);
+                       phase = len - phase;
+               }
+               else if (phase >= len)
+                       phase = SkScalarMod(phase, len);
+
+               SkASSERT(phase >= 0 && phase < len);
+               fInitialDashLength = FindFirstInterval(intervals, phase, &fInitialDashIndex);
+
+               SkASSERT(fInitialDashLength >= 0);
+               SkASSERT(fInitialDashIndex >= 0 && fInitialDashIndex < fCount);
+       }
+       else
+               fInitialDashLength = -1;        // signal bad dash intervals
+}
+
+SkDashPathEffect::~SkDashPathEffect()
+{
+       sk_free(fIntervals);
+}
+
+bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
+{
+       // we do nothing if the src wants to be filled, or if our dashlength is 0
+       if (*width < 0 || fInitialDashLength < 0)
+               return false;
+
+       SkPathMeasure   meas(src, false);
+       const SkScalar* intervals = fIntervals;
+
+       do {
+               bool            skipFirstSegment = meas.isClosed();
+               bool            addedSegment = false;
+               SkScalar        length = meas.getLength();
+               int                     index = fInitialDashIndex;
+               SkScalar        scale = SK_Scalar1;
+
+               if (fScaleToFit)
+               {
+                       if (fIntervalLength >= length)
+                               scale = SkScalarDiv(length, fIntervalLength);
+                       else
+                       {
+                               SkScalar div = SkScalarDiv(length, fIntervalLength);
+                               int n = SkScalarFloor(div);
+                               scale = SkScalarDiv(length, n * fIntervalLength);
+                       }
+               }
+
+               SkScalar        distance = 0;
+               SkScalar        dlen = SkScalarMul(fInitialDashLength, scale);
+
+               while (distance < length)
+               {
+                       SkASSERT(dlen >= 0);
+                       addedSegment = false;
+                       if (is_even(index) && dlen > 0 && !skipFirstSegment)
+                       {
+                               addedSegment = true;
+                               meas.getSegment(distance, distance + dlen, dst, true);
+                       }
+                       distance += dlen;
+
+                       // clear this so we only respect it the first time around
+                       skipFirstSegment = false;
+
+                       // wrap around our intervals array if necessary
+                       index += 1;
+                       SkASSERT(index <= fCount);
+                       if (index == fCount)
+                               index = 0;
+
+                       // fetch our next dlen
+                       dlen = SkScalarMul(intervals[index], scale);
+               }
+
+               // extend if we ended on a segment and we need to join up with the (skipped) initial segment
+               if (meas.isClosed() && is_even(fInitialDashIndex) && fInitialDashLength > 0)
+                       meas.getSegment(0, SkScalarMul(fInitialDashLength, scale), dst, !addedSegment);
+       } while (meas.nextContour());
+       return true;
+}
+
+SkFlattenable::Factory SkDashPathEffect::getFactory()
+{
+       return fInitialDashLength < 0 ? nil : CreateProc;
+}
+
+void SkDashPathEffect::flatten(SkWBuffer& buffer)
+{
+    this->INHERITED::flatten(buffer);
+    
+    SkASSERT(fInitialDashLength >= 0);
+
+    buffer.write32(fCount);
+    buffer.write32(fInitialDashIndex);
+    buffer.writeScalar(fInitialDashLength);
+    buffer.writeScalar(fIntervalLength);
+    buffer.write32(fScaleToFit);
+    buffer.write(fIntervals, fCount * sizeof(fIntervals[0]));
+}
+
+SkFlattenable* SkDashPathEffect::CreateProc(SkRBuffer& buffer)
+{
+       return SkNEW_ARGS(SkDashPathEffect, (buffer));
+}
+
+SkDashPathEffect::SkDashPathEffect(SkRBuffer& buffer) : SkPathEffect(buffer)
+{
+    fCount = buffer.readS32();
+    fInitialDashIndex = buffer.readS32();
+    fInitialDashLength = buffer.readScalar();
+    fIntervalLength = buffer.readScalar();
+    fScaleToFit = (buffer.readS32() != 0);
+    
+       fIntervals = (SkScalar*)sk_malloc_throw(sizeof(SkScalar) * fCount);
+    buffer.read(fIntervals, fCount * sizeof(fIntervals[0]));
+}
+
+
diff --git a/libs/graphics/effects/SkDiscretePathEffect.cpp b/libs/graphics/effects/SkDiscretePathEffect.cpp
new file mode 100644 (file)
index 0000000..78d17d0
--- /dev/null
@@ -0,0 +1,89 @@
+#include "SkDiscretePathEffect.h"
+#include "SkBuffer.h"
+#include "SkPathMeasure.h"
+#include "SkRandom.h"
+
+static void Perterb(SkPoint* p, const SkVector& tangent, SkScalar scale)
+{
+       SkVector normal = tangent;
+       normal.rotateCCW();
+       normal.setLength(scale);
+       *p += normal;
+}
+
+
+SkDiscretePathEffect::SkDiscretePathEffect(SkScalar segLength, SkScalar deviation)
+       : fSegLength(segLength), fPerterb(deviation)
+{
+}
+
+bool SkDiscretePathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
+{
+       bool doFill = *width < 0;
+
+       SkPathMeasure   meas(src, doFill);
+       U32                             seed = SkScalarRound(meas.getLength());
+       SkRandom                rand(seed ^ ((seed << 16) | (seed >> 16)));
+       SkScalar                scale = fPerterb;
+       SkPoint                 p;
+       SkVector                v;
+
+       do {
+               SkScalar        length = meas.getLength();
+
+               if (fSegLength * (2 + doFill) > length)
+               {
+                       meas.getSegment(0, length, dst, true);  // to short for us to mangle
+               }
+               else
+               {
+                       int                     n = SkScalarRound(SkScalarDiv(length, fSegLength));
+                       SkScalar        delta = length / n;
+                       SkScalar        distance = 0;
+
+                       if (meas.isClosed())
+                       {
+                               n -= 1;
+                               distance += delta/2;
+                       }
+                       meas.getPosTan(distance, &p, &v);
+                       Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale));
+                       dst->moveTo(p);
+                       while (--n >= 0)
+                       {
+                               distance += delta;
+                               meas.getPosTan(distance, &p, &v);
+                               Perterb(&p, v, SkScalarMul(rand.nextSScalar1(), scale));
+                               dst->lineTo(p);
+                       }
+                       if (meas.isClosed())
+                               dst->close();
+               }
+       } while (meas.nextContour());
+       return true;
+}
+
+SkFlattenable::Factory SkDiscretePathEffect::getFactory()
+{
+       return CreateProc;
+}
+
+SkFlattenable* SkDiscretePathEffect::CreateProc(SkRBuffer& buffer)
+{
+       return SkNEW_ARGS(SkDiscretePathEffect, (buffer));
+}
+
+void SkDiscretePathEffect::flatten(SkWBuffer& buffer)
+{
+    this->INHERITED::flatten(buffer);
+    buffer.writeScalar(fSegLength);
+    buffer.writeScalar(fPerterb);
+}
+
+SkDiscretePathEffect::SkDiscretePathEffect(SkRBuffer& buffer) : SkPathEffect(buffer)
+{
+    fSegLength = buffer.readScalar();
+    fPerterb = buffer.readScalar();
+}
+
+
diff --git a/libs/graphics/effects/SkEmbossMask.cpp b/libs/graphics/effects/SkEmbossMask.cpp
new file mode 100644 (file)
index 0000000..b47305f
--- /dev/null
@@ -0,0 +1,165 @@
+#include "SkEmbossMask.h"
+
+static inline int nonzero_to_one(int x)
+{
+#if 0
+       return x != 0;
+#else
+       return ((unsigned)(x | -x)) >> 31;
+#endif
+}
+
+static inline int neq_to_one(int x, int max)
+{
+#if 0
+       return x != max;
+#else
+       SkASSERT(x >= 0 && x <= max);
+       return ((unsigned)(x - max)) >> 31;
+#endif
+}
+
+static inline int neq_to_mask(int x, int max)
+{
+#if 0
+       return -(x != max);
+#else
+       SkASSERT(x >= 0 && x <= max);
+       return (x - max) >> 31;
+#endif
+}
+
+static inline unsigned div255(unsigned x)
+{
+       SkASSERT(x <= (255*255));
+       return x * ((1 << 24) / 255) >> 24;
+}
+
+#define kDelta 32      // small enough to show off angle differences
+
+#include "SkEmbossMask_Table.h"
+
+#if defined(SK_BUILD_FOR_WIN32) && defined(SK_DEBUG)
+
+#include <stdio.h>
+
+void SkEmbossMask_BuildTable()
+{
+       // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fixed" table
+
+       FILE* file = ::fopen("SkEmbossMask_Table.h", "w");
+       SkASSERT(file);
+       ::fprintf(file, "#include \"SkTypes.h\"\n\n");
+       ::fprintf(file, "static const U16 gInvSqrtTable[128 * 128] = {\n");
+       for (int dx = 0; dx <= 255/2; dx++)
+       {
+               for (int dy = 0; dy <= 255/2; dy++)
+               {
+                       if ((dy & 15) == 0)
+                               ::fprintf(file, "\t");
+
+                       U16 value = SkToU16((1 << 15) / SkSqrt32(dx * dx + dy * dy + kDelta*kDelta/4));
+
+                       ::fprintf(file, "0x%04X", value);
+                       if (dx * 128 + dy < 128*128-1)
+                               ::fprintf(file, ", ");
+                       if ((dy & 15) == 15)
+                               ::fprintf(file, "\n");
+               }
+       }
+       ::fprintf(file, "};\n#define kDeltaUsedToBuildTable\t%d\n", kDelta);
+       ::fclose(file);
+}
+
+#endif
+
+void SkEmbossMask::Emboss(SkMask* mask, const SkEmbossMaskFilter::Light& light)
+{
+       SkASSERT(kDelta == kDeltaUsedToBuildTable);
+
+       SkASSERT(mask->fFormat == SkMask::k3D_Format);
+
+       int             specular = light.fSpecular;
+       int             ambient = light.fAmbient;
+       SkFixed lx = SkScalarToFixed(light.fDirection[0]);
+       SkFixed ly = SkScalarToFixed(light.fDirection[1]);
+       SkFixed lz = SkScalarToFixed(light.fDirection[2]);
+       SkFixed lz_dot_nz = lz * kDelta;
+       int             lz_dot8 = lz >> 8;
+
+       size_t          planeSize = mask->computeImageSize();
+       U8*                     alpha = mask->fImage;
+       U8*                     multiply = (U8*)alpha + planeSize;
+       U8*                     additive = multiply + planeSize;
+
+       int     rowBytes = mask->fRowBytes;
+       int     maxy = mask->fBounds.height() - 1;
+       int     maxx = mask->fBounds.width() - 1;
+
+       int     prev_row = 0;
+       for (int y = 0; y <= maxy; y++)
+       {
+               int     next_row = neq_to_mask(y, maxy) & rowBytes;
+
+               for (int x = 0; x <= maxx; x++)
+               {
+                       if (alpha[x])
+                       {
+                               int     nx = alpha[x + neq_to_one(x, maxx)] - alpha[x - nonzero_to_one(x)];
+                               int ny = alpha[x + next_row] - alpha[x - prev_row];
+
+                               SkFixed numer = lx * nx + ly * ny + lz_dot_nz;
+                               int             mul = ambient;
+                               int             add = 0;
+
+                               if (numer > 0)  // preflight when numer/denom will be <= 0
+                               {
+#if 0
+                                       int     denom = SkSqrt32(nx * nx + ny * ny + kDelta*kDelta);
+                                       SkFixed dot = numer / denom;
+                                       dot >>= 8;      // now dot is 2^8 instead of 2^16
+#else
+                                       // can use full numer, but then we need to call SkFixedMul, since
+                                       // numer is 24 bits, and our table is 12 bits
+
+                                       // SkFixed dot = SkFixedMul(numer, gTable[]) >> 8
+                                       SkFixed dot = (unsigned)(numer >> 4) * gInvSqrtTable[(SkAbs32(nx) >> 1 << 7) | (SkAbs32(ny) >> 1)] >> 20;
+#endif
+                                       mul = SkFastMin32(mul + dot, 255);
+
+                                       // now for the reflection
+
+                                       //      R = 2 (Light * Normal) Normal - Light
+                                       //      hilite = R * Eye(0, 0, 1)
+
+                                       int hilite = (2 * dot - lz_dot8) * lz_dot8 >> 8;
+                                       if (hilite > 0)
+                                       {
+                                               // pin hilite to 255, since our fast math is also a little sloppy
+                                               hilite = SkClampMax(hilite, 255);
+
+                                               // specular is 4.4
+                                               // would really like to compute the fractional part of this
+                                               // and then possibly cache a 256 table for a given specular
+                                               // value in the light, and just pass that in to this function.
+                                               add = hilite;
+                                               for (int i = specular >> 4; i > 0; --i)
+                                                       add = div255(add * hilite);
+                                       }
+                               }
+                               multiply[x] = SkToU8(mul);
+                               additive[x] = SkToU8(add);
+
+                       //      multiply[x] = 0xFF;
+                       //      additive[x] = 0;
+                       //      ((U8*)alpha)[x] = alpha[x] * multiply[x] >> 8;
+                       }
+               }
+               alpha += rowBytes;
+               multiply += rowBytes;
+               additive += rowBytes;
+               prev_row = rowBytes;
+       }
+}
+
+
diff --git a/libs/graphics/effects/SkEmbossMask.h b/libs/graphics/effects/SkEmbossMask.h
new file mode 100644 (file)
index 0000000..0e2ecbe
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef SkEmbossMask_DEFINED
+#define SkEmbossMask_DEFINED
+
+#include "SkEmbossMaskFilter.h"
+
+class SkEmbossMask {
+public:
+       static void Emboss(SkMask* mask, const SkEmbossMaskFilter::Light&);
+};
+
+#endif
+
diff --git a/libs/graphics/effects/SkEmbossMaskFilter.cpp b/libs/graphics/effects/SkEmbossMaskFilter.cpp
new file mode 100644 (file)
index 0000000..248eab9
--- /dev/null
@@ -0,0 +1,116 @@
+#include "SkEmbossMaskFilter.h"
+#include "SkBlurMaskFilter.h"
+#include "SkBlurMask.h"
+#include "SkEmbossMask.h"
+#include "SkBuffer.h"
+
+SkMaskFilter* SkBlurMaskFilter::CreateEmboss(const SkScalar direction[3],
+                                             SkScalar ambient, SkScalar specular,
+                                             SkScalar blurRadius)
+{
+    if (direction == NULL)
+        return NULL;
+
+    // ambient should be 0...1 as a scalar
+    int am = SkScalarToFixed(ambient) >> 8;
+    if (am < 0) am = 0;
+    else if (am > 0xFF) am = 0xFF;
+
+    // specular should be 0..15.99 as a scalar
+    int sp = SkScalarToFixed(specular) >> 12;
+    if (sp < 0) sp = 0;
+    else if (sp > 0xFF) sp = 0xFF;
+
+    SkEmbossMaskFilter::Light   light;
+    
+    memcpy(light.fDirection, direction, sizeof(light.fDirection));
+    light.fAmbient = SkToU8(am);
+    light.fSpecular = SkToU8(sp);
+    
+    return SkNEW_ARGS(SkEmbossMaskFilter, (light, blurRadius));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+
+static void normalize(SkScalar v[3])
+{
+       SkScalar mag = SkScalarSquare(v[0]) + SkScalarSquare(v[1]) + SkScalarSquare(v[2]);
+       mag = SkScalarSqrt(mag);
+
+       for (int i = 0; i < 3; i++)
+               v[i] = SkScalarDiv(v[i], mag);
+}
+
+SkEmbossMaskFilter::SkEmbossMaskFilter(const Light& light, SkScalar blurRadius)
+               : fLight(light), fBlurRadius(blurRadius)
+{
+       normalize(fLight.fDirection);
+}
+
+SkMask::Format SkEmbossMaskFilter::getFormat()
+{
+       return SkMask::k3D_Format;
+}
+
+bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkPoint16* margin)
+{
+       SkScalar radius = matrix.mapRadius(fBlurRadius);
+
+       SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style);
+
+       dst->fFormat = SkMask::k3D_Format;
+       if (src.fImage == NULL)
+               return true;
+
+       // create a larger buffer for the other two channels (should force fBlur to do this for us)
+
+       {
+               U8*             alphaPlane = dst->fImage;
+               size_t  planeSize = dst->computeImageSize();
+
+               dst->fImage = SkMask::AllocImage(planeSize * 3);
+               memcpy(dst->fImage, alphaPlane, planeSize);
+               SkMask::FreeImage(alphaPlane);
+       }
+
+       // run the light direction through the matrix...
+       Light   light = fLight;
+       matrix.mapVectors((SkVector*)light.fDirection, (SkVector*)fLight.fDirection, 1);
+       // now restore the length of the XY component
+       ((SkVector*)light.fDirection)->setLength(light.fDirection[0], light.fDirection[1],
+                                                                                       SkPoint::Length(fLight.fDirection[0], fLight.fDirection[1]));
+
+       SkEmbossMask::Emboss(dst, light);
+
+       // restore original alpha
+       memcpy(dst->fImage, src.fImage, src.computeImageSize());
+
+       return true;
+}
+
+SkFlattenable* SkEmbossMaskFilter::CreateProc(SkRBuffer& buffer)
+{
+    return SkNEW_ARGS(SkEmbossMaskFilter, (buffer));
+}
+
+SkFlattenable::Factory SkEmbossMaskFilter::getFactory()
+{
+       return CreateProc;
+}
+
+SkEmbossMaskFilter::SkEmbossMaskFilter(SkRBuffer& buffer) : SkMaskFilter(buffer)
+{
+    buffer.read(&fLight, sizeof(fLight));
+    SkASSERT(fLight.fPad == 0);        // for the font-cache lookup to be clean
+    fBlurRadius = buffer.readScalar();
+}
+
+void SkEmbossMaskFilter::flatten(SkWBuffer& buffer)
+{
+    this->INHERITED::flatten(buffer);
+
+    fLight.fPad = 0;   // for the font-cache lookup to be clean
+    buffer.write(&fLight, sizeof(fLight));
+    buffer.writeScalar(fBlurRadius);
+}
+
diff --git a/libs/graphics/effects/SkEmbossMask_Table.h b/libs/graphics/effects/SkEmbossMask_Table.h
new file mode 100644 (file)
index 0000000..40b3e73
--- /dev/null
@@ -0,0 +1,1029 @@
+#include "SkTypes.h"
+
+static const U16 gInvSqrtTable[128 * 128] = {
+       0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0787, 0x0787, 0x0787, 0x071C, 0x071C, 0x06BC, 0x0666, 0x0666, 0x0618, 0x0618, 
+       0x05D1, 0x0590, 0x0555, 0x0555, 0x051E, 0x04EC, 0x04BD, 0x0492, 0x0492, 0x0469, 0x0444, 0x0421, 0x0400, 0x03E0, 0x03C3, 0x03C3, 
+       0x03A8, 0x038E, 0x0375, 0x035E, 0x0348, 0x0333, 0x031F, 0x030C, 0x02FA, 0x02E8, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 
+       0x028F, 0x0282, 0x0276, 0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 
+       0x01F8, 0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 
+       0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 
+       0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 
+       0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 
+       0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0787, 0x0787, 0x0787, 0x071C, 0x071C, 0x06BC, 0x0666, 0x0666, 0x0618, 0x0618, 
+       0x05D1, 0x0590, 0x0555, 0x0555, 0x051E, 0x04EC, 0x04BD, 0x0492, 0x0492, 0x0469, 0x0444, 0x0421, 0x0400, 0x03E0, 0x03C3, 0x03C3, 
+       0x03A8, 0x038E, 0x0375, 0x035E, 0x0348, 0x0333, 0x031F, 0x030C, 0x02FA, 0x02E8, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 
+       0x028F, 0x0282, 0x0276, 0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 
+       0x01F8, 0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 
+       0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 
+       0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 
+       0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 
+       0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0787, 0x0787, 0x071C, 0x071C, 0x071C, 0x06BC, 0x0666, 0x0666, 0x0618, 0x05D1, 
+       0x05D1, 0x0590, 0x0555, 0x0555, 0x051E, 0x04EC, 0x04BD, 0x0492, 0x0492, 0x0469, 0x0444, 0x0421, 0x0400, 0x03E0, 0x03C3, 0x03C3, 
+       0x03A8, 0x038E, 0x0375, 0x035E, 0x0348, 0x0333, 0x031F, 0x030C, 0x02FA, 0x02E8, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 
+       0x028F, 0x0282, 0x0276, 0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 
+       0x01F0, 0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 
+       0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 
+       0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 
+       0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 
+       0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0787, 0x0787, 0x0787, 0x071C, 0x071C, 0x06BC, 0x06BC, 0x0666, 0x0666, 0x0618, 0x05D1, 
+       0x05D1, 0x0590, 0x0555, 0x051E, 0x051E, 0x04EC, 0x04BD, 0x0492, 0x0469, 0x0469, 0x0444, 0x0421, 0x0400, 0x03E0, 0x03C3, 0x03A8, 
+       0x03A8, 0x038E, 0x0375, 0x035E, 0x0348, 0x0333, 0x031F, 0x030C, 0x02FA, 0x02E8, 0x02D8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 
+       0x028F, 0x0282, 0x0276, 0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 
+       0x01F0, 0x01E9, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 
+       0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 
+       0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 
+       0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 
+       0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0787, 0x0787, 0x0787, 0x071C, 0x071C, 0x06BC, 0x06BC, 0x0666, 0x0618, 0x0618, 0x05D1, 
+       0x05D1, 0x0590, 0x0555, 0x051E, 0x051E, 0x04EC, 0x04BD, 0x0492, 0x0469, 0x0469, 0x0444, 0x0421, 0x0400, 0x03E0, 0x03C3, 0x03A8, 
+       0x038E, 0x038E, 0x0375, 0x035E, 0x0348, 0x0333, 0x031F, 0x030C, 0x02FA, 0x02E8, 0x02D8, 0x02C8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 
+       0x028F, 0x0282, 0x0276, 0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 
+       0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 
+       0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 
+       0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 
+       0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 
+       0x0800, 0x0800, 0x0800, 0x0787, 0x0787, 0x0787, 0x0787, 0x071C, 0x071C, 0x06BC, 0x06BC, 0x0666, 0x0666, 0x0618, 0x0618, 0x05D1, 
+       0x0590, 0x0590, 0x0555, 0x051E, 0x04EC, 0x04EC, 0x04BD, 0x0492, 0x0469, 0x0444, 0x0444, 0x0421, 0x0400, 0x03E0, 0x03C3, 0x03A8, 
+       0x038E, 0x0375, 0x0375, 0x035E, 0x0348, 0x0333, 0x031F, 0x030C, 0x02FA, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x02AA, 0x029C, 
+       0x028F, 0x0282, 0x0276, 0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 
+       0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 
+       0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 
+       0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 
+       0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 
+       0x0787, 0x0787, 0x0787, 0x0787, 0x0787, 0x0787, 0x071C, 0x071C, 0x071C, 0x06BC, 0x06BC, 0x0666, 0x0666, 0x0618, 0x05D1, 0x05D1, 
+       0x0590, 0x0555, 0x0555, 0x051E, 0x04EC, 0x04BD, 0x04BD, 0x0492, 0x0469, 0x0444, 0x0421, 0x0421, 0x0400, 0x03E0, 0x03C3, 0x03A8, 
+       0x038E, 0x0375, 0x035E, 0x035E, 0x0348, 0x0333, 0x031F, 0x030C, 0x02FA, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 0x028F, 
+       0x028F, 0x0282, 0x0276, 0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 
+       0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 
+       0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 
+       0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 
+       0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 
+       0x0787, 0x0787, 0x0787, 0x0787, 0x0787, 0x071C, 0x071C, 0x071C, 0x06BC, 0x06BC, 0x0666, 0x0666, 0x0618, 0x0618, 0x05D1, 0x0590, 
+       0x0590, 0x0555, 0x051E, 0x051E, 0x04EC, 0x04BD, 0x0492, 0x0492, 0x0469, 0x0444, 0x0421, 0x0400, 0x03E0, 0x03E0, 0x03C3, 0x03A8, 
+       0x038E, 0x0375, 0x035E, 0x0348, 0x0333, 0x0333, 0x031F, 0x030C, 0x02FA, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 0x028F, 
+       0x0282, 0x0276, 0x0276, 0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 
+       0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A9, 0x01A4, 0x019E, 0x0199, 
+       0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 
+       0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 
+       0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 
+       0x0787, 0x0787, 0x071C, 0x071C, 0x071C, 0x071C, 0x071C, 0x06BC, 0x06BC, 0x0666, 0x0666, 0x0618, 0x0618, 0x05D1, 0x05D1, 0x0590, 
+       0x0555, 0x0555, 0x051E, 0x04EC, 0x04EC, 0x04BD, 0x0492, 0x0469, 0x0469, 0x0444, 0x0421, 0x0400, 0x03E0, 0x03C3, 0x03C3, 0x03A8, 
+       0x038E, 0x0375, 0x035E, 0x0348, 0x0333, 0x031F, 0x030C, 0x030C, 0x02FA, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 0x028F, 
+       0x0282, 0x0276, 0x026A, 0x025E, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 
+       0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 
+       0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 
+       0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 
+       0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 
+       0x071C, 0x071C, 0x071C, 0x071C, 0x071C, 0x06BC, 0x06BC, 0x06BC, 0x0666, 0x0666, 0x0666, 0x0618, 0x0618, 0x05D1, 0x0590, 0x0590, 
+       0x0555, 0x051E, 0x051E, 0x04EC, 0x04BD, 0x04BD, 0x0492, 0x0469, 0x0444, 0x0421, 0x0421, 0x0400, 0x03E0, 0x03C3, 0x03A8, 0x038E, 
+       0x038E, 0x0375, 0x035E, 0x0348, 0x0333, 0x031F, 0x030C, 0x02FA, 0x02E8, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 0x028F, 
+       0x0282, 0x0276, 0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 
+       0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 
+       0x018F, 0x018A, 0x0186, 0x0181, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 
+       0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 
+       0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 
+       0x071C, 0x071C, 0x071C, 0x06BC, 0x06BC, 0x06BC, 0x06BC, 0x0666, 0x0666, 0x0666, 0x0618, 0x0618, 0x05D1, 0x05D1, 0x0590, 0x0555, 
+       0x0555, 0x051E, 0x04EC, 0x04EC, 0x04BD, 0x0492, 0x0492, 0x0469, 0x0444, 0x0421, 0x0400, 0x0400, 0x03E0, 0x03C3, 0x03A8, 0x038E, 
+       0x0375, 0x035E, 0x035E, 0x0348, 0x0333, 0x031F, 0x030C, 0x02FA, 0x02E8, 0x02D8, 0x02C8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 0x028F, 
+       0x0282, 0x0276, 0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 
+       0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 
+       0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 
+       0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 
+       0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 
+       0x06BC, 0x06BC, 0x06BC, 0x06BC, 0x06BC, 0x0666, 0x0666, 0x0666, 0x0618, 0x0618, 0x0618, 0x05D1, 0x05D1, 0x0590, 0x0590, 0x0555, 
+       0x051E, 0x051E, 0x04EC, 0x04BD, 0x04BD, 0x0492, 0x0469, 0x0444, 0x0444, 0x0421, 0x0400, 0x03E0, 0x03C3, 0x03C3, 0x03A8, 0x038E, 
+       0x0375, 0x035E, 0x0348, 0x0333, 0x0333, 0x031F, 0x030C, 0x02FA, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 0x029C, 0x028F, 
+       0x0282, 0x0276, 0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x0200, 0x01F8, 
+       0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 
+       0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0158, 0x0155, 
+       0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 
+       0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 
+       0x0666, 0x0666, 0x0666, 0x0666, 0x0666, 0x0666, 0x0666, 0x0618, 0x0618, 0x0618, 0x05D1, 0x05D1, 0x0590, 0x0590, 0x0555, 0x051E, 
+       0x051E, 0x04EC, 0x04EC, 0x04BD, 0x0492, 0x0469, 0x0469, 0x0444, 0x0421, 0x0400, 0x0400, 0x03E0, 0x03C3, 0x03A8, 0x038E, 0x038E, 
+       0x0375, 0x035E, 0x0348, 0x0333, 0x031F, 0x030C, 0x030C, 0x02FA, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 0x028F, 0x0282, 
+       0x0276, 0x0276, 0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F0, 
+       0x01E9, 0x01E1, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 
+       0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 
+       0x014E, 0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 
+       0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 
+       0x0666, 0x0666, 0x0666, 0x0666, 0x0618, 0x0618, 0x0618, 0x0618, 0x05D1, 0x05D1, 0x05D1, 0x0590, 0x0590, 0x0555, 0x0555, 0x051E, 
+       0x04EC, 0x04EC, 0x04BD, 0x0492, 0x0492, 0x0469, 0x0444, 0x0444, 0x0421, 0x0400, 0x03E0, 0x03E0, 0x03C3, 0x03A8, 0x038E, 0x0375, 
+       0x035E, 0x035E, 0x0348, 0x0333, 0x031F, 0x030C, 0x02FA, 0x02E8, 0x02D8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 0x028F, 0x0282, 
+       0x0276, 0x026A, 0x025E, 0x0253, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F0, 
+       0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 
+       0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 
+       0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 
+       0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 
+       0x0618, 0x0618, 0x0618, 0x0618, 0x0618, 0x0618, 0x05D1, 0x05D1, 0x05D1, 0x0590, 0x0590, 0x0590, 0x0555, 0x0555, 0x051E, 0x04EC, 
+       0x04EC, 0x04BD, 0x04BD, 0x0492, 0x0469, 0x0469, 0x0444, 0x0421, 0x0400, 0x0400, 0x03E0, 0x03C3, 0x03A8, 0x03A8, 0x038E, 0x0375, 
+       0x035E, 0x0348, 0x0333, 0x0333, 0x031F, 0x030C, 0x02FA, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02B9, 0x02AA, 0x029C, 0x028F, 0x0282, 
+       0x0276, 0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F0, 
+       0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 
+       0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 
+       0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 
+       0x011F, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 
+       0x0618, 0x0618, 0x05D1, 0x05D1, 0x05D1, 0x05D1, 0x05D1, 0x0590, 0x0590, 0x0590, 0x0555, 0x0555, 0x051E, 0x051E, 0x04EC, 0x04EC, 
+       0x04BD, 0x04BD, 0x0492, 0x0469, 0x0469, 0x0444, 0x0421, 0x0421, 0x0400, 0x03E0, 0x03C3, 0x03C3, 0x03A8, 0x038E, 0x0375, 0x0375, 
+       0x035E, 0x0348, 0x0333, 0x031F, 0x030C, 0x02FA, 0x02FA, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 0x028F, 0x028F, 0x0282, 
+       0x0276, 0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F0, 
+       0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x0194, 
+       0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 
+       0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 
+       0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 
+       0x05D1, 0x05D1, 0x05D1, 0x05D1, 0x05D1, 0x0590, 0x0590, 0x0590, 0x0555, 0x0555, 0x0555, 0x051E, 0x051E, 0x04EC, 0x04EC, 0x04BD, 
+       0x04BD, 0x0492, 0x0492, 0x0469, 0x0444, 0x0444, 0x0421, 0x0400, 0x0400, 0x03E0, 0x03C3, 0x03A8, 0x038E, 0x038E, 0x0375, 0x035E, 
+       0x0348, 0x0333, 0x0333, 0x031F, 0x030C, 0x02FA, 0x02E8, 0x02D8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 0x028F, 0x0282, 0x0276, 
+       0x026A, 0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F0, 0x01F0, 
+       0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 
+       0x018A, 0x0186, 0x0181, 0x017D, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 
+       0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 
+       0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 
+       0x0590, 0x0590, 0x0590, 0x0590, 0x0590, 0x0590, 0x0555, 0x0555, 0x0555, 0x051E, 0x051E, 0x051E, 0x04EC, 0x04EC, 0x04BD, 0x04BD, 
+       0x0492, 0x0492, 0x0469, 0x0444, 0x0444, 0x0421, 0x0400, 0x0400, 0x03E0, 0x03C3, 0x03C3, 0x03A8, 0x038E, 0x0375, 0x035E, 0x035E, 
+       0x0348, 0x0333, 0x031F, 0x030C, 0x030C, 0x02FA, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x02AA, 0x029C, 0x028F, 0x0282, 0x0276, 
+       0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F0, 0x01E9, 
+       0x01E1, 0x01DA, 0x01D4, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 
+       0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 
+       0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 
+       0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 
+       0x0555, 0x0555, 0x0555, 0x0555, 0x0555, 0x0555, 0x0555, 0x051E, 0x051E, 0x051E, 0x04EC, 0x04EC, 0x04EC, 0x04BD, 0x04BD, 0x0492, 
+       0x0492, 0x0469, 0x0444, 0x0444, 0x0421, 0x0421, 0x0400, 0x03E0, 0x03C3, 0x03C3, 0x03A8, 0x038E, 0x038E, 0x0375, 0x035E, 0x0348, 
+       0x0333, 0x0333, 0x031F, 0x030C, 0x02FA, 0x02E8, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 0x028F, 0x0282, 0x0282, 0x0276, 
+       0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F0, 0x01E9, 
+       0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 
+       0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 
+       0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 
+       0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 
+       0x0555, 0x0555, 0x0555, 0x051E, 0x051E, 0x051E, 0x051E, 0x051E, 0x04EC, 0x04EC, 0x04EC, 0x04BD, 0x04BD, 0x0492, 0x0492, 0x0469, 
+       0x0469, 0x0444, 0x0444, 0x0421, 0x0421, 0x0400, 0x03E0, 0x03E0, 0x03C3, 0x03A8, 0x03A8, 0x038E, 0x0375, 0x035E, 0x035E, 0x0348, 
+       0x0333, 0x031F, 0x030C, 0x030C, 0x02FA, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02B9, 0x02AA, 0x029C, 0x028F, 0x0282, 0x0276, 0x026A, 
+       0x025E, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x0200, 0x01F8, 0x01F0, 0x01E9, 
+       0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x019E, 0x0199, 0x0194, 0x018F, 
+       0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 
+       0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 
+       0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 
+       0x051E, 0x051E, 0x051E, 0x051E, 0x051E, 0x04EC, 0x04EC, 0x04EC, 0x04EC, 0x04BD, 0x04BD, 0x04BD, 0x0492, 0x0492, 0x0469, 0x0469, 
+       0x0444, 0x0444, 0x0421, 0x0421, 0x0400, 0x03E0, 0x03E0, 0x03C3, 0x03A8, 0x03A8, 0x038E, 0x0375, 0x0375, 0x035E, 0x0348, 0x0333, 
+       0x0333, 0x031F, 0x030C, 0x02FA, 0x02E8, 0x02D8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 0x028F, 0x028F, 0x0282, 0x0276, 0x026A, 
+       0x025E, 0x0253, 0x0249, 0x023E, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F0, 0x01E9, 0x01E1, 
+       0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 0x018A, 
+       0x0186, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 
+       0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0129, 0x0127, 0x0124, 0x0121, 
+       0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 
+       0x04EC, 0x04EC, 0x04EC, 0x04EC, 0x04EC, 0x04EC, 0x04BD, 0x04BD, 0x04BD, 0x04BD, 0x0492, 0x0492, 0x0469, 0x0469, 0x0469, 0x0444, 
+       0x0444, 0x0421, 0x0421, 0x0400, 0x03E0, 0x03E0, 0x03C3, 0x03A8, 0x03A8, 0x038E, 0x0375, 0x0375, 0x035E, 0x0348, 0x0348, 0x0333, 
+       0x031F, 0x030C, 0x02FA, 0x02FA, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02B9, 0x02AA, 0x029C, 0x028F, 0x0282, 0x0276, 0x026A, 0x026A, 
+       0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F0, 0x01E9, 0x01E1, 
+       0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 0x018A, 
+       0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 
+       0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 
+       0x011C, 0x011A, 0x0118, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 
+       0x04BD, 0x04BD, 0x04BD, 0x04BD, 0x04BD, 0x04BD, 0x04BD, 0x0492, 0x0492, 0x0492, 0x0492, 0x0469, 0x0469, 0x0444, 0x0444, 0x0421, 
+       0x0421, 0x0400, 0x0400, 0x03E0, 0x03E0, 0x03C3, 0x03C3, 0x03A8, 0x038E, 0x038E, 0x0375, 0x035E, 0x0348, 0x0348, 0x0333, 0x031F, 
+       0x030C, 0x030C, 0x02FA, 0x02E8, 0x02D8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 0x028F, 0x028F, 0x0282, 0x0276, 0x026A, 0x025E, 
+       0x0253, 0x0249, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x0200, 0x01F8, 0x01F0, 0x01E9, 0x01E1, 
+       0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 0x018A, 
+       0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 
+       0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 
+       0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 
+       0x0492, 0x0492, 0x0492, 0x0492, 0x0492, 0x0492, 0x0492, 0x0492, 0x0469, 0x0469, 0x0469, 0x0444, 0x0444, 0x0444, 0x0421, 0x0421, 
+       0x0400, 0x0400, 0x03E0, 0x03E0, 0x03C3, 0x03A8, 0x03A8, 0x038E, 0x038E, 0x0375, 0x035E, 0x035E, 0x0348, 0x0333, 0x031F, 0x031F, 
+       0x030C, 0x02FA, 0x02E8, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x02AA, 0x029C, 0x028F, 0x0282, 0x0276, 0x026A, 0x026A, 0x025E, 
+       0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F0, 0x01E9, 0x01E1, 0x01E1, 
+       0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x0194, 0x018F, 0x018A, 
+       0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 
+       0x0147, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 
+       0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 
+       0x0492, 0x0492, 0x0492, 0x0469, 0x0469, 0x0469, 0x0469, 0x0469, 0x0469, 0x0444, 0x0444, 0x0444, 0x0421, 0x0421, 0x0400, 0x0400, 
+       0x0400, 0x03E0, 0x03C3, 0x03C3, 0x03A8, 0x03A8, 0x038E, 0x038E, 0x0375, 0x035E, 0x035E, 0x0348, 0x0333, 0x0333, 0x031F, 0x030C, 
+       0x02FA, 0x02FA, 0x02E8, 0x02D8, 0x02C8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 0x028F, 0x028F, 0x0282, 0x0276, 0x026A, 0x025E, 0x0253, 
+       0x0249, 0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F0, 0x01E9, 0x01E1, 0x01DA, 
+       0x01D4, 0x01CD, 0x01C7, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 0x018A, 0x0186, 
+       0x0181, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 
+       0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 
+       0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 
+       0x0469, 0x0469, 0x0469, 0x0469, 0x0469, 0x0444, 0x0444, 0x0444, 0x0444, 0x0421, 0x0421, 0x0421, 0x0400, 0x0400, 0x0400, 0x03E0, 
+       0x03E0, 0x03C3, 0x03C3, 0x03A8, 0x03A8, 0x038E, 0x038E, 0x0375, 0x035E, 0x035E, 0x0348, 0x0333, 0x0333, 0x031F, 0x030C, 0x030C, 
+       0x02FA, 0x02E8, 0x02D8, 0x02D8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 0x029C, 0x028F, 0x0282, 0x0276, 0x026A, 0x026A, 0x025E, 0x0253, 
+       0x0249, 0x023E, 0x0234, 0x022B, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F0, 0x01F0, 0x01E9, 0x01E1, 0x01DA, 
+       0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 0x018A, 0x0186, 
+       0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 
+       0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0124, 0x0121, 0x011F, 
+       0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 
+       0x0444, 0x0444, 0x0444, 0x0444, 0x0444, 0x0444, 0x0421, 0x0421, 0x0421, 0x0421, 0x0400, 0x0400, 0x0400, 0x03E0, 0x03E0, 0x03C3, 
+       0x03C3, 0x03C3, 0x03A8, 0x03A8, 0x038E, 0x0375, 0x0375, 0x035E, 0x035E, 0x0348, 0x0333, 0x0333, 0x031F, 0x030C, 0x030C, 0x02FA, 
+       0x02E8, 0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02B9, 0x02AA, 0x029C, 0x028F, 0x0282, 0x0282, 0x0276, 0x026A, 0x025E, 0x0253, 0x0249, 
+       0x0249, 0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 
+       0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0199, 0x0194, 0x018F, 0x018A, 0x0186, 
+       0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 
+       0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 
+       0x011A, 0x0118, 0x0115, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 
+       0x0421, 0x0421, 0x0421, 0x0421, 0x0421, 0x0421, 0x0421, 0x0400, 0x0400, 0x0400, 0x0400, 0x03E0, 0x03E0, 0x03E0, 0x03C3, 0x03C3, 
+       0x03A8, 0x03A8, 0x038E, 0x038E, 0x0375, 0x0375, 0x035E, 0x035E, 0x0348, 0x0333, 0x0333, 0x031F, 0x030C, 0x030C, 0x02FA, 0x02E8, 
+       0x02E8, 0x02D8, 0x02C8, 0x02B9, 0x02B9, 0x02AA, 0x029C, 0x028F, 0x028F, 0x0282, 0x0276, 0x026A, 0x025E, 0x025E, 0x0253, 0x0249, 
+       0x023E, 0x0234, 0x022B, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F8, 0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 
+       0x01CD, 0x01C7, 0x01C0, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 
+       0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 0x0147, 
+       0x0144, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 
+       0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 
+       0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03C3, 0x03C3, 0x03C3, 0x03A8, 0x03A8, 
+       0x038E, 0x038E, 0x038E, 0x0375, 0x0375, 0x035E, 0x0348, 0x0348, 0x0333, 0x0333, 0x031F, 0x030C, 0x030C, 0x02FA, 0x02E8, 0x02E8, 
+       0x02D8, 0x02C8, 0x02C8, 0x02B9, 0x02AA, 0x029C, 0x029C, 0x028F, 0x0282, 0x0276, 0x0276, 0x026A, 0x025E, 0x0253, 0x0249, 0x023E, 
+       0x023E, 0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01DA, 0x01D4, 
+       0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 
+       0x017D, 0x0178, 0x0174, 0x0170, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 0x0147, 
+       0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 
+       0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 
+       0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03C3, 0x03C3, 0x03C3, 0x03C3, 0x03A8, 0x03A8, 0x03A8, 0x038E, 
+       0x038E, 0x0375, 0x0375, 0x035E, 0x035E, 0x0348, 0x0348, 0x0333, 0x0333, 0x031F, 0x030C, 0x030C, 0x02FA, 0x02E8, 0x02E8, 0x02D8, 
+       0x02C8, 0x02C8, 0x02B9, 0x02AA, 0x02AA, 0x029C, 0x028F, 0x0282, 0x0282, 0x0276, 0x026A, 0x025E, 0x0253, 0x0253, 0x0249, 0x023E, 
+       0x0234, 0x022B, 0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F8, 0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 
+       0x01C7, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 
+       0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 0x0147, 
+       0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0124, 0x0121, 0x011F, 0x011C, 
+       0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 
+       0x03C3, 0x03C3, 0x03C3, 0x03C3, 0x03C3, 0x03C3, 0x03C3, 0x03C3, 0x03C3, 0x03A8, 0x03A8, 0x03A8, 0x038E, 0x038E, 0x038E, 0x0375, 
+       0x0375, 0x035E, 0x035E, 0x035E, 0x0348, 0x0348, 0x0333, 0x031F, 0x031F, 0x030C, 0x030C, 0x02FA, 0x02E8, 0x02E8, 0x02D8, 0x02C8, 
+       0x02C8, 0x02B9, 0x02AA, 0x02AA, 0x029C, 0x028F, 0x028F, 0x0282, 0x0276, 0x026A, 0x025E, 0x025E, 0x0253, 0x0249, 0x023E, 0x0234, 
+       0x0234, 0x022B, 0x0222, 0x0219, 0x0210, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F0, 0x01E9, 0x01E1, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 
+       0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 
+       0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 0x014A, 0x0147, 
+       0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 
+       0x0118, 0x0115, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 
+       0x03C3, 0x03C3, 0x03C3, 0x03A8, 0x03A8, 0x03A8, 0x03A8, 0x03A8, 0x03A8, 0x038E, 0x038E, 0x038E, 0x038E, 0x0375, 0x0375, 0x0375, 
+       0x035E, 0x035E, 0x0348, 0x0348, 0x0333, 0x0333, 0x031F, 0x031F, 0x030C, 0x030C, 0x02FA, 0x02E8, 0x02E8, 0x02D8, 0x02C8, 0x02C8, 
+       0x02B9, 0x02AA, 0x02AA, 0x029C, 0x028F, 0x028F, 0x0282, 0x0276, 0x026A, 0x026A, 0x025E, 0x0253, 0x0249, 0x0249, 0x023E, 0x0234, 
+       0x022B, 0x0222, 0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F8, 0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 
+       0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0199, 0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 
+       0x0178, 0x0174, 0x0170, 0x016C, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 
+       0x0141, 0x013E, 0x013B, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 
+       0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 
+       0x03A8, 0x03A8, 0x03A8, 0x03A8, 0x038E, 0x038E, 0x038E, 0x038E, 0x038E, 0x038E, 0x0375, 0x0375, 0x0375, 0x035E, 0x035E, 0x035E, 
+       0x0348, 0x0348, 0x0333, 0x0333, 0x0333, 0x031F, 0x030C, 0x030C, 0x02FA, 0x02FA, 0x02E8, 0x02E8, 0x02D8, 0x02C8, 0x02C8, 0x02B9, 
+       0x02AA, 0x02AA, 0x029C, 0x028F, 0x028F, 0x0282, 0x0276, 0x0276, 0x026A, 0x025E, 0x0253, 0x0253, 0x0249, 0x023E, 0x0234, 0x022B, 
+       0x022B, 0x0222, 0x0219, 0x0210, 0x0208, 0x0208, 0x0200, 0x01F8, 0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 
+       0x01C0, 0x01BA, 0x01B4, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 0x018A, 0x0186, 0x0186, 0x0181, 0x017D, 
+       0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 
+       0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 
+       0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 
+       0x038E, 0x038E, 0x038E, 0x038E, 0x038E, 0x0375, 0x0375, 0x0375, 0x0375, 0x0375, 0x035E, 0x035E, 0x035E, 0x035E, 0x0348, 0x0348, 
+       0x0333, 0x0333, 0x0333, 0x031F, 0x031F, 0x030C, 0x030C, 0x02FA, 0x02FA, 0x02E8, 0x02E8, 0x02D8, 0x02C8, 0x02C8, 0x02B9, 0x02AA, 
+       0x02AA, 0x029C, 0x028F, 0x028F, 0x0282, 0x0276, 0x0276, 0x026A, 0x025E, 0x0253, 0x0253, 0x0249, 0x023E, 0x0234, 0x0234, 0x022B, 
+       0x0222, 0x0219, 0x0210, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F0, 0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C7, 
+       0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x019E, 0x0199, 0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 
+       0x0174, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 0x014A, 0x0147, 0x0144, 
+       0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011C, 0x011A, 
+       0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 
+       0x0375, 0x0375, 0x0375, 0x0375, 0x0375, 0x0375, 0x035E, 0x035E, 0x035E, 0x035E, 0x035E, 0x0348, 0x0348, 0x0348, 0x0333, 0x0333, 
+       0x0333, 0x031F, 0x031F, 0x030C, 0x030C, 0x02FA, 0x02FA, 0x02E8, 0x02E8, 0x02D8, 0x02D8, 0x02C8, 0x02C8, 0x02B9, 0x02AA, 0x02AA, 
+       0x029C, 0x028F, 0x028F, 0x0282, 0x0276, 0x0276, 0x026A, 0x025E, 0x025E, 0x0253, 0x0249, 0x023E, 0x023E, 0x0234, 0x022B, 0x0222, 
+       0x0222, 0x0219, 0x0210, 0x0208, 0x0200, 0x0200, 0x01F8, 0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 
+       0x01BA, 0x01B4, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 
+       0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 
+       0x013E, 0x013B, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 
+       0x0115, 0x0113, 0x0111, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 
+       0x035E, 0x035E, 0x035E, 0x035E, 0x035E, 0x035E, 0x035E, 0x0348, 0x0348, 0x0348, 0x0348, 0x0333, 0x0333, 0x0333, 0x0333, 0x031F, 
+       0x031F, 0x030C, 0x030C, 0x030C, 0x02FA, 0x02FA, 0x02E8, 0x02E8, 0x02D8, 0x02D8, 0x02C8, 0x02B9, 0x02B9, 0x02AA, 0x02AA, 0x029C, 
+       0x028F, 0x028F, 0x0282, 0x0276, 0x0276, 0x026A, 0x025E, 0x025E, 0x0253, 0x0249, 0x0249, 0x023E, 0x0234, 0x022B, 0x022B, 0x0222, 
+       0x0219, 0x0210, 0x0208, 0x0208, 0x0200, 0x01F8, 0x01F0, 0x01E9, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C7, 0x01C0, 
+       0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x019E, 0x0199, 0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x017D, 0x0178, 
+       0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0155, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 
+       0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 
+       0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 
+       0x0348, 0x0348, 0x0348, 0x0348, 0x0348, 0x0348, 0x0348, 0x0333, 0x0333, 0x0333, 0x0333, 0x0333, 0x031F, 0x031F, 0x031F, 0x030C, 
+       0x030C, 0x030C, 0x02FA, 0x02FA, 0x02E8, 0x02E8, 0x02D8, 0x02D8, 0x02C8, 0x02C8, 0x02B9, 0x02B9, 0x02AA, 0x02AA, 0x029C, 0x028F, 
+       0x028F, 0x0282, 0x0276, 0x0276, 0x026A, 0x025E, 0x025E, 0x0253, 0x0249, 0x0249, 0x023E, 0x0234, 0x022B, 0x022B, 0x0222, 0x0219, 
+       0x0210, 0x0210, 0x0208, 0x0200, 0x01F8, 0x01F0, 0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 
+       0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 
+       0x0170, 0x016C, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 
+       0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011F, 0x011C, 0x011A, 0x0118, 
+       0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F8, 
+       0x0333, 0x0333, 0x0333, 0x0333, 0x0333, 0x0333, 0x0333, 0x0333, 0x031F, 0x031F, 0x031F, 0x031F, 0x030C, 0x030C, 0x030C, 0x02FA, 
+       0x02FA, 0x02FA, 0x02E8, 0x02E8, 0x02D8, 0x02D8, 0x02D8, 0x02C8, 0x02C8, 0x02B9, 0x02B9, 0x02AA, 0x029C, 0x029C, 0x028F, 0x028F, 
+       0x0282, 0x0276, 0x0276, 0x026A, 0x025E, 0x025E, 0x0253, 0x0249, 0x0249, 0x023E, 0x0234, 0x0234, 0x022B, 0x0222, 0x0219, 0x0219, 
+       0x0210, 0x0208, 0x0200, 0x01F8, 0x01F8, 0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01C0, 0x01BA, 
+       0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x019E, 0x0199, 0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x017D, 0x0178, 0x0174, 
+       0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 
+       0x013B, 0x0138, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 
+       0x0113, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 
+       0x031F, 0x031F, 0x031F, 0x031F, 0x031F, 0x031F, 0x031F, 0x031F, 0x030C, 0x030C, 0x030C, 0x030C, 0x030C, 0x02FA, 0x02FA, 0x02FA, 
+       0x02E8, 0x02E8, 0x02E8, 0x02D8, 0x02D8, 0x02C8, 0x02C8, 0x02B9, 0x02B9, 0x02AA, 0x02AA, 0x029C, 0x029C, 0x028F, 0x028F, 0x0282, 
+       0x0276, 0x0276, 0x026A, 0x025E, 0x025E, 0x0253, 0x0249, 0x0249, 0x023E, 0x0234, 0x0234, 0x022B, 0x0222, 0x0219, 0x0219, 0x0210, 
+       0x0208, 0x0200, 0x0200, 0x01F8, 0x01F0, 0x01E9, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 
+       0x01AF, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 
+       0x016C, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 
+       0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 
+       0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 
+       0x030C, 0x030C, 0x030C, 0x030C, 0x030C, 0x030C, 0x030C, 0x030C, 0x030C, 0x02FA, 0x02FA, 0x02FA, 0x02FA, 0x02E8, 0x02E8, 0x02E8, 
+       0x02D8, 0x02D8, 0x02D8, 0x02C8, 0x02C8, 0x02B9, 0x02B9, 0x02AA, 0x02AA, 0x029C, 0x029C, 0x028F, 0x028F, 0x0282, 0x0282, 0x0276, 
+       0x0276, 0x026A, 0x025E, 0x025E, 0x0253, 0x0249, 0x0249, 0x023E, 0x0234, 0x0234, 0x022B, 0x0222, 0x0222, 0x0219, 0x0210, 0x0208, 
+       0x0208, 0x0200, 0x01F8, 0x01F0, 0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01BA, 0x01B4, 
+       0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0199, 0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x017D, 0x0178, 0x0174, 0x0170, 
+       0x016C, 0x0168, 0x0164, 0x0160, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013E, 
+       0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011C, 0x011A, 0x0118, 0x0115, 
+       0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 
+       0x02FA, 0x02FA, 0x02FA, 0x02FA, 0x02FA, 0x02FA, 0x02FA, 0x02FA, 0x02FA, 0x02E8, 0x02E8, 0x02E8, 0x02E8, 0x02D8, 0x02D8, 0x02D8, 
+       0x02D8, 0x02C8, 0x02C8, 0x02B9, 0x02B9, 0x02B9, 0x02AA, 0x02AA, 0x029C, 0x029C, 0x028F, 0x028F, 0x0282, 0x0282, 0x0276, 0x026A, 
+       0x026A, 0x025E, 0x025E, 0x0253, 0x0249, 0x0249, 0x023E, 0x0234, 0x0234, 0x022B, 0x0222, 0x0222, 0x0219, 0x0210, 0x0208, 0x0208, 
+       0x0200, 0x01F8, 0x01F0, 0x01F0, 0x01E9, 0x01E1, 0x01DA, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 
+       0x01A9, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 0x018A, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x0170, 
+       0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 
+       0x0138, 0x0135, 0x0132, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 
+       0x0111, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 
+       0x02E8, 0x02E8, 0x02E8, 0x02E8, 0x02E8, 0x02E8, 0x02E8, 0x02E8, 0x02E8, 0x02E8, 0x02D8, 0x02D8, 0x02D8, 0x02D8, 0x02C8, 0x02C8, 
+       0x02C8, 0x02B9, 0x02B9, 0x02B9, 0x02AA, 0x02AA, 0x029C, 0x029C, 0x028F, 0x028F, 0x0282, 0x0282, 0x0276, 0x0276, 0x026A, 0x026A, 
+       0x025E, 0x0253, 0x0253, 0x0249, 0x0249, 0x023E, 0x0234, 0x0234, 0x022B, 0x0222, 0x0222, 0x0219, 0x0210, 0x0210, 0x0208, 0x0200, 
+       0x01F8, 0x01F8, 0x01F0, 0x01E9, 0x01E1, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01AF, 
+       0x01A9, 0x01A4, 0x019E, 0x0199, 0x0194, 0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 
+       0x0168, 0x0164, 0x0160, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013B, 
+       0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 
+       0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 
+       0x02E8, 0x02E8, 0x02E8, 0x02D8, 0x02D8, 0x02D8, 0x02D8, 0x02D8, 0x02D8, 0x02D8, 0x02C8, 0x02C8, 0x02C8, 0x02C8, 0x02B9, 0x02B9, 
+       0x02B9, 0x02AA, 0x02AA, 0x02AA, 0x029C, 0x029C, 0x028F, 0x028F, 0x028F, 0x0282, 0x0282, 0x0276, 0x0276, 0x026A, 0x025E, 0x025E, 
+       0x0253, 0x0253, 0x0249, 0x0249, 0x023E, 0x0234, 0x0234, 0x022B, 0x0222, 0x0222, 0x0219, 0x0210, 0x0210, 0x0208, 0x0200, 0x01F8, 
+       0x01F8, 0x01F0, 0x01E9, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01CD, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 
+       0x01A4, 0x019E, 0x019E, 0x0199, 0x0194, 0x018F, 0x018A, 0x0186, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x016C, 
+       0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 
+       0x0135, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x011A, 0x0118, 0x0115, 0x0113, 
+       0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 
+       0x02D8, 0x02D8, 0x02D8, 0x02D8, 0x02C8, 0x02C8, 0x02C8, 0x02C8, 0x02C8, 0x02C8, 0x02C8, 0x02B9, 0x02B9, 0x02B9, 0x02B9, 0x02AA, 
+       0x02AA, 0x02AA, 0x029C, 0x029C, 0x028F, 0x028F, 0x028F, 0x0282, 0x0282, 0x0276, 0x0276, 0x026A, 0x026A, 0x025E, 0x025E, 0x0253, 
+       0x0253, 0x0249, 0x023E, 0x023E, 0x0234, 0x0234, 0x022B, 0x0222, 0x0222, 0x0219, 0x0210, 0x0210, 0x0208, 0x0200, 0x0200, 0x01F8, 
+       0x01F0, 0x01E9, 0x01E9, 0x01E1, 0x01DA, 0x01D4, 0x01D4, 0x01CD, 0x01C7, 0x01C0, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A9, 
+       0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 
+       0x0164, 0x0160, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 
+       0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 
+       0x010E, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 
+       0x02C8, 0x02C8, 0x02C8, 0x02C8, 0x02C8, 0x02B9, 0x02B9, 0x02B9, 0x02B9, 0x02B9, 0x02B9, 0x02AA, 0x02AA, 0x02AA, 0x02AA, 0x029C, 
+       0x029C, 0x029C, 0x028F, 0x028F, 0x028F, 0x0282, 0x0282, 0x0276, 0x0276, 0x026A, 0x026A, 0x025E, 0x025E, 0x0253, 0x0253, 0x0249, 
+       0x0249, 0x023E, 0x023E, 0x0234, 0x022B, 0x022B, 0x0222, 0x0222, 0x0219, 0x0210, 0x0210, 0x0208, 0x0200, 0x0200, 0x01F8, 0x01F0, 
+       0x01E9, 0x01E9, 0x01E1, 0x01DA, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A4, 
+       0x019E, 0x0199, 0x0199, 0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x016C, 0x0168, 
+       0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0138, 
+       0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 
+       0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 
+       0x02B9, 0x02B9, 0x02B9, 0x02B9, 0x02B9, 0x02AA, 0x02AA, 0x02AA, 0x02AA, 0x02AA, 0x02AA, 0x029C, 0x029C, 0x029C, 0x029C, 0x028F, 
+       0x028F, 0x028F, 0x0282, 0x0282, 0x0282, 0x0276, 0x0276, 0x026A, 0x026A, 0x026A, 0x025E, 0x025E, 0x0253, 0x0253, 0x0249, 0x0249, 
+       0x023E, 0x0234, 0x0234, 0x022B, 0x022B, 0x0222, 0x0219, 0x0219, 0x0210, 0x0210, 0x0208, 0x0200, 0x0200, 0x01F8, 0x01F0, 0x01E9, 
+       0x01E9, 0x01E1, 0x01DA, 0x01DA, 0x01D4, 0x01CD, 0x01C7, 0x01C7, 0x01C0, 0x01BA, 0x01B4, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x019E, 
+       0x019E, 0x0199, 0x0194, 0x018F, 0x018A, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 
+       0x0160, 0x015C, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 
+       0x0132, 0x012F, 0x012C, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0113, 0x0111, 
+       0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 
+       0x02AA, 0x02AA, 0x02AA, 0x02AA, 0x02AA, 0x02AA, 0x029C, 0x029C, 0x029C, 0x029C, 0x029C, 0x029C, 0x028F, 0x028F, 0x028F, 0x028F, 
+       0x0282, 0x0282, 0x0282, 0x0276, 0x0276, 0x026A, 0x026A, 0x026A, 0x025E, 0x025E, 0x0253, 0x0253, 0x0249, 0x0249, 0x023E, 0x023E, 
+       0x0234, 0x0234, 0x022B, 0x022B, 0x0222, 0x0219, 0x0219, 0x0210, 0x0208, 0x0208, 0x0200, 0x0200, 0x01F8, 0x01F0, 0x01F0, 0x01E9, 
+       0x01E1, 0x01DA, 0x01DA, 0x01D4, 0x01CD, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x01A4, 0x019E, 
+       0x0199, 0x0194, 0x018F, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0168, 0x0164, 
+       0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x013B, 0x0138, 0x0135, 
+       0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 
+       0x010C, 0x010A, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 
+       0x029C, 0x029C, 0x029C, 0x029C, 0x029C, 0x029C, 0x028F, 0x028F, 0x028F, 0x028F, 0x028F, 0x028F, 0x0282, 0x0282, 0x0282, 0x0282, 
+       0x0276, 0x0276, 0x0276, 0x026A, 0x026A, 0x026A, 0x025E, 0x025E, 0x0253, 0x0253, 0x0249, 0x0249, 0x023E, 0x023E, 0x0234, 0x0234, 
+       0x022B, 0x022B, 0x0222, 0x0222, 0x0219, 0x0219, 0x0210, 0x0208, 0x0208, 0x0200, 0x01F8, 0x01F8, 0x01F0, 0x01E9, 0x01E9, 0x01E1, 
+       0x01DA, 0x01DA, 0x01D4, 0x01CD, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01BA, 0x01B4, 0x01AF, 0x01A9, 0x01A9, 0x01A4, 0x019E, 0x0199, 
+       0x0194, 0x0194, 0x018F, 0x018A, 0x0186, 0x0181, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 
+       0x015C, 0x0158, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 
+       0x012F, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 
+       0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 
+       0x028F, 0x028F, 0x028F, 0x028F, 0x028F, 0x028F, 0x028F, 0x0282, 0x0282, 0x0282, 0x0282, 0x0282, 0x0276, 0x0276, 0x0276, 0x0276, 
+       0x026A, 0x026A, 0x026A, 0x025E, 0x025E, 0x025E, 0x0253, 0x0253, 0x0249, 0x0249, 0x0249, 0x023E, 0x023E, 0x0234, 0x0234, 0x022B, 
+       0x022B, 0x0222, 0x0222, 0x0219, 0x0210, 0x0210, 0x0208, 0x0208, 0x0200, 0x01F8, 0x01F8, 0x01F0, 0x01E9, 0x01E9, 0x01E1, 0x01DA, 
+       0x01DA, 0x01D4, 0x01CD, 0x01CD, 0x01C7, 0x01C0, 0x01BA, 0x01BA, 0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x0199, 0x0199, 
+       0x0194, 0x018F, 0x018A, 0x018A, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0164, 0x0160, 
+       0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x013B, 0x0138, 0x0135, 0x0132, 
+       0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010E, 
+       0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 
+       0x0282, 0x0282, 0x0282, 0x0282, 0x0282, 0x0282, 0x0282, 0x0276, 0x0276, 0x0276, 0x0276, 0x0276, 0x0276, 0x026A, 0x026A, 0x026A, 
+       0x026A, 0x025E, 0x025E, 0x025E, 0x0253, 0x0253, 0x0249, 0x0249, 0x0249, 0x023E, 0x023E, 0x0234, 0x0234, 0x022B, 0x022B, 0x0222, 
+       0x0222, 0x0219, 0x0219, 0x0210, 0x0210, 0x0208, 0x0200, 0x0200, 0x01F8, 0x01F8, 0x01F0, 0x01E9, 0x01E9, 0x01E1, 0x01DA, 0x01DA, 
+       0x01D4, 0x01CD, 0x01CD, 0x01C7, 0x01C0, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A4, 0x019E, 0x019E, 0x0199, 0x0194, 
+       0x018F, 0x018F, 0x018A, 0x0186, 0x0181, 0x017D, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0168, 0x0164, 0x0160, 0x015C, 
+       0x0158, 0x0155, 0x0155, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 
+       0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 
+       0x010A, 0x0108, 0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 
+       0x0276, 0x0276, 0x0276, 0x0276, 0x0276, 0x0276, 0x0276, 0x0276, 0x026A, 0x026A, 0x026A, 0x026A, 0x026A, 0x025E, 0x025E, 0x025E, 
+       0x025E, 0x0253, 0x0253, 0x0253, 0x0249, 0x0249, 0x0249, 0x023E, 0x023E, 0x0234, 0x0234, 0x022B, 0x022B, 0x022B, 0x0222, 0x0222, 
+       0x0219, 0x0210, 0x0210, 0x0208, 0x0208, 0x0200, 0x0200, 0x01F8, 0x01F0, 0x01F0, 0x01E9, 0x01E9, 0x01E1, 0x01DA, 0x01DA, 0x01D4, 
+       0x01CD, 0x01CD, 0x01C7, 0x01C0, 0x01C0, 0x01BA, 0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A4, 0x01A4, 0x019E, 0x0199, 0x0194, 0x018F, 
+       0x018F, 0x018A, 0x0186, 0x0181, 0x0181, 0x017D, 0x0178, 0x0174, 0x0170, 0x0170, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x015C, 
+       0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0138, 0x0135, 0x0132, 0x012F, 
+       0x012C, 0x0129, 0x0127, 0x0124, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x0111, 0x010E, 0x010C, 
+       0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 
+       0x026A, 0x026A, 0x026A, 0x026A, 0x026A, 0x026A, 0x026A, 0x026A, 0x025E, 0x025E, 0x025E, 0x025E, 0x025E, 0x0253, 0x0253, 0x0253, 
+       0x0253, 0x0249, 0x0249, 0x0249, 0x023E, 0x023E, 0x023E, 0x0234, 0x0234, 0x022B, 0x022B, 0x022B, 0x0222, 0x0222, 0x0219, 0x0219, 
+       0x0210, 0x0210, 0x0208, 0x0208, 0x0200, 0x01F8, 0x01F8, 0x01F0, 0x01F0, 0x01E9, 0x01E9, 0x01E1, 0x01DA, 0x01DA, 0x01D4, 0x01CD, 
+       0x01CD, 0x01C7, 0x01C0, 0x01C0, 0x01BA, 0x01B4, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x01A4, 0x019E, 0x0199, 0x0194, 0x0194, 0x018F, 
+       0x018A, 0x0186, 0x0186, 0x0181, 0x017D, 0x0178, 0x0174, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0164, 0x0160, 0x015C, 0x0158, 
+       0x0155, 0x0151, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 
+       0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 
+       0x0108, 0x0106, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00EF, 
+       0x025E, 0x025E, 0x025E, 0x025E, 0x025E, 0x025E, 0x025E, 0x025E, 0x025E, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0249, 0x0249, 
+       0x0249, 0x023E, 0x023E, 0x023E, 0x023E, 0x0234, 0x0234, 0x022B, 0x022B, 0x022B, 0x0222, 0x0222, 0x0219, 0x0219, 0x0210, 0x0210, 
+       0x0208, 0x0208, 0x0200, 0x0200, 0x01F8, 0x01F8, 0x01F0, 0x01F0, 0x01E9, 0x01E1, 0x01E1, 0x01DA, 0x01DA, 0x01D4, 0x01CD, 0x01CD, 
+       0x01C7, 0x01C0, 0x01C0, 0x01BA, 0x01B4, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x01A4, 0x019E, 0x0199, 0x0199, 0x0194, 0x018F, 0x018A, 
+       0x0186, 0x0186, 0x0181, 0x017D, 0x0178, 0x0178, 0x0174, 0x0170, 0x016C, 0x0168, 0x0168, 0x0164, 0x0160, 0x015C, 0x0158, 0x0158, 
+       0x0155, 0x0151, 0x014E, 0x014A, 0x0147, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0135, 0x0132, 0x012F, 0x012C, 
+       0x0129, 0x0127, 0x0124, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x0111, 0x010E, 0x010C, 0x010A, 
+       0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00ED, 
+       0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0253, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x023E, 0x023E, 
+       0x023E, 0x023E, 0x0234, 0x0234, 0x0234, 0x022B, 0x022B, 0x022B, 0x0222, 0x0222, 0x0219, 0x0219, 0x0210, 0x0210, 0x0210, 0x0208, 
+       0x0208, 0x0200, 0x0200, 0x01F8, 0x01F0, 0x01F0, 0x01E9, 0x01E9, 0x01E1, 0x01E1, 0x01DA, 0x01D4, 0x01D4, 0x01CD, 0x01CD, 0x01C7, 
+       0x01C0, 0x01C0, 0x01BA, 0x01B4, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x01A4, 0x019E, 0x0199, 0x0199, 0x0194, 0x018F, 0x018A, 0x018A, 
+       0x0186, 0x0181, 0x017D, 0x017D, 0x0178, 0x0174, 0x0170, 0x016C, 0x016C, 0x0168, 0x0164, 0x0160, 0x015C, 0x015C, 0x0158, 0x0155, 
+       0x0151, 0x014E, 0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x012C, 
+       0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 
+       0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00ED, 
+       0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x023E, 0x023E, 0x023E, 0x023E, 0x023E, 0x0234, 0x0234, 
+       0x0234, 0x0234, 0x022B, 0x022B, 0x022B, 0x0222, 0x0222, 0x0222, 0x0219, 0x0219, 0x0210, 0x0210, 0x0210, 0x0208, 0x0208, 0x0200, 
+       0x0200, 0x01F8, 0x01F8, 0x01F0, 0x01F0, 0x01E9, 0x01E9, 0x01E1, 0x01DA, 0x01DA, 0x01D4, 0x01D4, 0x01CD, 0x01C7, 0x01C7, 0x01C0, 
+       0x01BA, 0x01BA, 0x01B4, 0x01B4, 0x01AF, 0x01A9, 0x01A4, 0x01A4, 0x019E, 0x0199, 0x0199, 0x0194, 0x018F, 0x018A, 0x018A, 0x0186, 
+       0x0181, 0x017D, 0x017D, 0x0178, 0x0174, 0x0170, 0x0170, 0x016C, 0x0168, 0x0164, 0x0164, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 
+       0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x0132, 0x012F, 0x012C, 0x0129, 
+       0x0127, 0x0124, 0x0121, 0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 
+       0x0106, 0x0104, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00ED, 0x00ED, 
+       0x023E, 0x023E, 0x023E, 0x023E, 0x023E, 0x023E, 0x023E, 0x023E, 0x023E, 0x023E, 0x0234, 0x0234, 0x0234, 0x0234, 0x0234, 0x022B, 
+       0x022B, 0x022B, 0x0222, 0x0222, 0x0222, 0x0219, 0x0219, 0x0219, 0x0210, 0x0210, 0x0210, 0x0208, 0x0208, 0x0200, 0x0200, 0x01F8, 
+       0x01F8, 0x01F0, 0x01F0, 0x01E9, 0x01E9, 0x01E1, 0x01E1, 0x01DA, 0x01DA, 0x01D4, 0x01CD, 0x01CD, 0x01C7, 0x01C7, 0x01C0, 0x01BA, 
+       0x01BA, 0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A4, 0x01A4, 0x019E, 0x0199, 0x0199, 0x0194, 0x018F, 0x018F, 0x018A, 0x0186, 0x0181, 
+       0x0181, 0x017D, 0x0178, 0x0174, 0x0174, 0x0170, 0x016C, 0x0168, 0x0164, 0x0164, 0x0160, 0x015C, 0x0158, 0x0158, 0x0155, 0x0151, 
+       0x014E, 0x014A, 0x0147, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0129, 
+       0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0108, 
+       0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 
+       0x0234, 0x0234, 0x0234, 0x0234, 0x0234, 0x0234, 0x0234, 0x0234, 0x0234, 0x0234, 0x022B, 0x022B, 0x022B, 0x022B, 0x022B, 0x0222, 
+       0x0222, 0x0222, 0x0222, 0x0219, 0x0219, 0x0219, 0x0210, 0x0210, 0x0210, 0x0208, 0x0208, 0x0200, 0x0200, 0x01F8, 0x01F8, 0x01F8, 
+       0x01F0, 0x01F0, 0x01E9, 0x01E9, 0x01E1, 0x01DA, 0x01DA, 0x01D4, 0x01D4, 0x01CD, 0x01CD, 0x01C7, 0x01C7, 0x01C0, 0x01BA, 0x01BA, 
+       0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A4, 0x01A4, 0x019E, 0x0199, 0x0199, 0x0194, 0x018F, 0x018F, 0x018A, 0x0186, 0x0181, 0x0181, 
+       0x017D, 0x0178, 0x0174, 0x0174, 0x0170, 0x016C, 0x0168, 0x0168, 0x0164, 0x0160, 0x015C, 0x015C, 0x0158, 0x0155, 0x0151, 0x014E, 
+       0x014E, 0x014A, 0x0147, 0x0144, 0x0141, 0x013E, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012F, 0x012C, 0x0129, 0x0127, 
+       0x0124, 0x0121, 0x011F, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 
+       0x0104, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 
+       0x022B, 0x022B, 0x022B, 0x022B, 0x022B, 0x022B, 0x022B, 0x022B, 0x022B, 0x022B, 0x0222, 0x0222, 0x0222, 0x0222, 0x0222, 0x0219, 
+       0x0219, 0x0219, 0x0219, 0x0210, 0x0210, 0x0210, 0x0208, 0x0208, 0x0208, 0x0200, 0x0200, 0x01F8, 0x01F8, 0x01F8, 0x01F0, 0x01F0, 
+       0x01E9, 0x01E9, 0x01E1, 0x01E1, 0x01DA, 0x01DA, 0x01D4, 0x01D4, 0x01CD, 0x01C7, 0x01C7, 0x01C0, 0x01C0, 0x01BA, 0x01BA, 0x01B4, 
+       0x01AF, 0x01AF, 0x01A9, 0x01A4, 0x01A4, 0x019E, 0x0199, 0x0199, 0x0194, 0x018F, 0x018F, 0x018A, 0x0186, 0x0181, 0x0181, 0x017D, 
+       0x0178, 0x0178, 0x0174, 0x0170, 0x016C, 0x016C, 0x0168, 0x0164, 0x0160, 0x0160, 0x015C, 0x0158, 0x0155, 0x0151, 0x0151, 0x014E, 
+       0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0127, 
+       0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 
+       0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 
+       0x0222, 0x0222, 0x0222, 0x0222, 0x0222, 0x0222, 0x0222, 0x0222, 0x0222, 0x0222, 0x0222, 0x0219, 0x0219, 0x0219, 0x0219, 0x0210, 
+       0x0210, 0x0210, 0x0210, 0x0208, 0x0208, 0x0208, 0x0200, 0x0200, 0x0200, 0x01F8, 0x01F8, 0x01F8, 0x01F0, 0x01F0, 0x01E9, 0x01E9, 
+       0x01E1, 0x01E1, 0x01DA, 0x01DA, 0x01D4, 0x01D4, 0x01CD, 0x01CD, 0x01C7, 0x01C7, 0x01C0, 0x01C0, 0x01BA, 0x01B4, 0x01B4, 0x01AF, 
+       0x01AF, 0x01A9, 0x01A4, 0x01A4, 0x019E, 0x0199, 0x0199, 0x0194, 0x018F, 0x018F, 0x018A, 0x0186, 0x0186, 0x0181, 0x017D, 0x0178, 
+       0x0178, 0x0174, 0x0170, 0x016C, 0x016C, 0x0168, 0x0164, 0x0160, 0x0160, 0x015C, 0x0158, 0x0155, 0x0155, 0x0151, 0x014E, 0x014A, 
+       0x0147, 0x0147, 0x0144, 0x0141, 0x013E, 0x013B, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x012C, 0x0129, 0x0127, 0x0124, 
+       0x0121, 0x011F, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 
+       0x0102, 0x0100, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 
+       0x0219, 0x0219, 0x0219, 0x0219, 0x0219, 0x0219, 0x0219, 0x0219, 0x0219, 0x0219, 0x0219, 0x0210, 0x0210, 0x0210, 0x0210, 0x0210, 
+       0x0208, 0x0208, 0x0208, 0x0200, 0x0200, 0x0200, 0x0200, 0x01F8, 0x01F8, 0x01F0, 0x01F0, 0x01F0, 0x01E9, 0x01E9, 0x01E1, 0x01E1, 
+       0x01DA, 0x01DA, 0x01DA, 0x01D4, 0x01D4, 0x01CD, 0x01CD, 0x01C7, 0x01C0, 0x01C0, 0x01BA, 0x01BA, 0x01B4, 0x01B4, 0x01AF, 0x01A9, 
+       0x01A9, 0x01A4, 0x01A4, 0x019E, 0x0199, 0x0199, 0x0194, 0x018F, 0x018F, 0x018A, 0x0186, 0x0186, 0x0181, 0x017D, 0x0178, 0x0178, 
+       0x0174, 0x0170, 0x0170, 0x016C, 0x0168, 0x0164, 0x0164, 0x0160, 0x015C, 0x0158, 0x0158, 0x0155, 0x0151, 0x014E, 0x014A, 0x014A, 
+       0x0147, 0x0144, 0x0141, 0x013E, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0124, 
+       0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 
+       0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00EA, 
+       0x0210, 0x0210, 0x0210, 0x0210, 0x0210, 0x0210, 0x0210, 0x0210, 0x0210, 0x0210, 0x0210, 0x0208, 0x0208, 0x0208, 0x0208, 0x0208, 
+       0x0200, 0x0200, 0x0200, 0x0200, 0x01F8, 0x01F8, 0x01F8, 0x01F0, 0x01F0, 0x01F0, 0x01E9, 0x01E9, 0x01E1, 0x01E1, 0x01E1, 0x01DA, 
+       0x01DA, 0x01D4, 0x01D4, 0x01CD, 0x01CD, 0x01C7, 0x01C7, 0x01C0, 0x01C0, 0x01BA, 0x01BA, 0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A9, 
+       0x01A4, 0x019E, 0x019E, 0x0199, 0x0199, 0x0194, 0x018F, 0x018F, 0x018A, 0x0186, 0x0186, 0x0181, 0x017D, 0x0178, 0x0178, 0x0174, 
+       0x0170, 0x0170, 0x016C, 0x0168, 0x0164, 0x0164, 0x0160, 0x015C, 0x0158, 0x0158, 0x0155, 0x0151, 0x014E, 0x014E, 0x014A, 0x0147, 
+       0x0144, 0x0141, 0x0141, 0x013E, 0x013B, 0x0138, 0x0135, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0129, 0x0127, 0x0124, 0x0121, 
+       0x011F, 0x011C, 0x011A, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 
+       0x0100, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 
+       0x0208, 0x0208, 0x0208, 0x0208, 0x0208, 0x0208, 0x0208, 0x0208, 0x0208, 0x0208, 0x0208, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 
+       0x01F8, 0x01F8, 0x01F8, 0x01F8, 0x01F0, 0x01F0, 0x01F0, 0x01E9, 0x01E9, 0x01E9, 0x01E1, 0x01E1, 0x01DA, 0x01DA, 0x01DA, 0x01D4, 
+       0x01D4, 0x01CD, 0x01CD, 0x01C7, 0x01C7, 0x01C0, 0x01C0, 0x01BA, 0x01BA, 0x01B4, 0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A4, 0x01A4, 
+       0x019E, 0x019E, 0x0199, 0x0194, 0x0194, 0x018F, 0x018A, 0x018A, 0x0186, 0x0181, 0x0181, 0x017D, 0x0178, 0x0178, 0x0174, 0x0170, 
+       0x0170, 0x016C, 0x0168, 0x0164, 0x0164, 0x0160, 0x015C, 0x015C, 0x0158, 0x0155, 0x0151, 0x0151, 0x014E, 0x014A, 0x0147, 0x0144, 
+       0x0144, 0x0141, 0x013E, 0x013B, 0x0138, 0x0138, 0x0135, 0x0132, 0x012F, 0x012C, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 
+       0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0106, 0x0104, 0x0102, 
+       0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 
+       0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x01F8, 0x01F8, 0x01F8, 0x01F8, 
+       0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01E9, 0x01E9, 0x01E9, 0x01E1, 0x01E1, 0x01E1, 0x01DA, 0x01DA, 0x01DA, 0x01D4, 0x01D4, 0x01CD, 
+       0x01CD, 0x01C7, 0x01C7, 0x01C7, 0x01C0, 0x01C0, 0x01BA, 0x01BA, 0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A9, 0x01A4, 0x01A4, 0x019E, 
+       0x0199, 0x0199, 0x0194, 0x0194, 0x018F, 0x018A, 0x018A, 0x0186, 0x0181, 0x0181, 0x017D, 0x0178, 0x0178, 0x0174, 0x0170, 0x0170, 
+       0x016C, 0x0168, 0x0168, 0x0164, 0x0160, 0x015C, 0x015C, 0x0158, 0x0155, 0x0151, 0x0151, 0x014E, 0x014A, 0x0147, 0x0147, 0x0144, 
+       0x0141, 0x013E, 0x013B, 0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0124, 0x0121, 0x011F, 
+       0x011C, 0x011A, 0x0118, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 
+       0x00FE, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 0x00E6, 
+       0x01F8, 0x01F8, 0x01F8, 0x01F8, 0x01F8, 0x01F8, 0x01F8, 0x01F8, 0x01F8, 0x01F8, 0x01F8, 0x01F8, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 
+       0x01F0, 0x01E9, 0x01E9, 0x01E9, 0x01E1, 0x01E1, 0x01E1, 0x01E1, 0x01DA, 0x01DA, 0x01D4, 0x01D4, 0x01D4, 0x01CD, 0x01CD, 0x01C7, 
+       0x01C7, 0x01C7, 0x01C0, 0x01C0, 0x01BA, 0x01BA, 0x01B4, 0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A9, 0x01A4, 0x019E, 0x019E, 0x0199, 
+       0x0199, 0x0194, 0x018F, 0x018F, 0x018A, 0x018A, 0x0186, 0x0181, 0x0181, 0x017D, 0x0178, 0x0178, 0x0174, 0x0170, 0x0170, 0x016C, 
+       0x0168, 0x0168, 0x0164, 0x0160, 0x015C, 0x015C, 0x0158, 0x0155, 0x0151, 0x0151, 0x014E, 0x014A, 0x0147, 0x0147, 0x0144, 0x0141, 
+       0x013E, 0x013E, 0x013B, 0x0138, 0x0135, 0x0132, 0x0132, 0x012F, 0x012C, 0x0129, 0x0127, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 
+       0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 
+       0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E6, 
+       0x01F8, 0x01F8, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01F0, 0x01E9, 0x01E9, 0x01E9, 0x01E9, 
+       0x01E9, 0x01E1, 0x01E1, 0x01E1, 0x01E1, 0x01DA, 0x01DA, 0x01DA, 0x01D4, 0x01D4, 0x01D4, 0x01CD, 0x01CD, 0x01C7, 0x01C7, 0x01C7, 
+       0x01C0, 0x01C0, 0x01BA, 0x01BA, 0x01B4, 0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A9, 0x01A4, 0x01A4, 0x019E, 0x019E, 0x0199, 0x0194, 
+       0x0194, 0x018F, 0x018F, 0x018A, 0x0186, 0x0186, 0x0181, 0x0181, 0x017D, 0x0178, 0x0178, 0x0174, 0x0170, 0x0170, 0x016C, 0x0168, 
+       0x0168, 0x0164, 0x0160, 0x015C, 0x015C, 0x0158, 0x0155, 0x0155, 0x0151, 0x014E, 0x014A, 0x014A, 0x0147, 0x0144, 0x0141, 0x0141, 
+       0x013E, 0x013B, 0x0138, 0x0135, 0x0135, 0x0132, 0x012F, 0x012C, 0x012C, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011F, 0x011C, 
+       0x011A, 0x0118, 0x0115, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 
+       0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 
+       0x01F0, 0x01F0, 0x01F0, 0x01E9, 0x01E9, 0x01E9, 0x01E9, 0x01E9, 0x01E9, 0x01E9, 0x01E9, 0x01E9, 0x01E1, 0x01E1, 0x01E1, 0x01E1, 
+       0x01E1, 0x01DA, 0x01DA, 0x01DA, 0x01DA, 0x01D4, 0x01D4, 0x01D4, 0x01CD, 0x01CD, 0x01CD, 0x01C7, 0x01C7, 0x01C7, 0x01C0, 0x01C0, 
+       0x01BA, 0x01BA, 0x01B4, 0x01B4, 0x01AF, 0x01AF, 0x01AF, 0x01A9, 0x01A9, 0x01A4, 0x019E, 0x019E, 0x0199, 0x0199, 0x0194, 0x0194, 
+       0x018F, 0x018F, 0x018A, 0x0186, 0x0186, 0x0181, 0x017D, 0x017D, 0x0178, 0x0178, 0x0174, 0x0170, 0x0170, 0x016C, 0x0168, 0x0168, 
+       0x0164, 0x0160, 0x015C, 0x015C, 0x0158, 0x0155, 0x0155, 0x0151, 0x014E, 0x014A, 0x014A, 0x0147, 0x0144, 0x0141, 0x0141, 0x013E, 
+       0x013B, 0x0138, 0x0138, 0x0135, 0x0132, 0x012F, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 
+       0x0118, 0x0118, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0102, 0x0100, 0x00FE, 
+       0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 
+       0x01E9, 0x01E9, 0x01E9, 0x01E9, 0x01E1, 0x01E1, 0x01E1, 0x01E1, 0x01E1, 0x01E1, 0x01E1, 0x01E1, 0x01E1, 0x01DA, 0x01DA, 0x01DA, 
+       0x01DA, 0x01D4, 0x01D4, 0x01D4, 0x01D4, 0x01CD, 0x01CD, 0x01CD, 0x01C7, 0x01C7, 0x01C7, 0x01C0, 0x01C0, 0x01C0, 0x01BA, 0x01BA, 
+       0x01B4, 0x01B4, 0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A9, 0x01A4, 0x01A4, 0x019E, 0x019E, 0x0199, 0x0199, 0x0194, 0x018F, 0x018F, 
+       0x018A, 0x018A, 0x0186, 0x0186, 0x0181, 0x017D, 0x017D, 0x0178, 0x0174, 0x0174, 0x0170, 0x0170, 0x016C, 0x0168, 0x0168, 0x0164, 
+       0x0160, 0x015C, 0x015C, 0x0158, 0x0155, 0x0155, 0x0151, 0x014E, 0x014E, 0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013B, 
+       0x013B, 0x0138, 0x0135, 0x0132, 0x012F, 0x012F, 0x012C, 0x0129, 0x0127, 0x0127, 0x0124, 0x0121, 0x011F, 0x011C, 0x011C, 0x011A, 
+       0x0118, 0x0115, 0x0113, 0x0111, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 
+       0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E3, 
+       0x01E1, 0x01E1, 0x01E1, 0x01E1, 0x01DA, 0x01DA, 0x01DA, 0x01DA, 0x01DA, 0x01DA, 0x01DA, 0x01DA, 0x01DA, 0x01D4, 0x01D4, 0x01D4, 
+       0x01D4, 0x01D4, 0x01CD, 0x01CD, 0x01CD, 0x01C7, 0x01C7, 0x01C7, 0x01C7, 0x01C0, 0x01C0, 0x01C0, 0x01BA, 0x01BA, 0x01B4, 0x01B4, 
+       0x01B4, 0x01AF, 0x01AF, 0x01A9, 0x01A9, 0x01A4, 0x01A4, 0x019E, 0x019E, 0x0199, 0x0199, 0x0194, 0x0194, 0x018F, 0x018F, 0x018A, 
+       0x018A, 0x0186, 0x0181, 0x0181, 0x017D, 0x017D, 0x0178, 0x0174, 0x0174, 0x0170, 0x016C, 0x016C, 0x0168, 0x0164, 0x0164, 0x0160, 
+       0x015C, 0x015C, 0x0158, 0x0155, 0x0155, 0x0151, 0x014E, 0x014E, 0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013B, 0x013B, 
+       0x0138, 0x0135, 0x0132, 0x0132, 0x012F, 0x012C, 0x0129, 0x0129, 0x0127, 0x0124, 0x0121, 0x011F, 0x011F, 0x011C, 0x011A, 0x0118, 
+       0x0115, 0x0115, 0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FC, 
+       0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E3, 
+       0x01DA, 0x01DA, 0x01DA, 0x01DA, 0x01DA, 0x01D4, 0x01D4, 0x01D4, 0x01D4, 0x01D4, 0x01D4, 0x01D4, 0x01D4, 0x01CD, 0x01CD, 0x01CD, 
+       0x01CD, 0x01CD, 0x01C7, 0x01C7, 0x01C7, 0x01C7, 0x01C0, 0x01C0, 0x01C0, 0x01BA, 0x01BA, 0x01BA, 0x01B4, 0x01B4, 0x01AF, 0x01AF, 
+       0x01AF, 0x01A9, 0x01A9, 0x01A4, 0x01A4, 0x019E, 0x019E, 0x0199, 0x0199, 0x0194, 0x0194, 0x018F, 0x018F, 0x018A, 0x018A, 0x0186, 
+       0x0186, 0x0181, 0x0181, 0x017D, 0x0178, 0x0178, 0x0174, 0x0174, 0x0170, 0x016C, 0x016C, 0x0168, 0x0164, 0x0164, 0x0160, 0x015C, 
+       0x015C, 0x0158, 0x0155, 0x0155, 0x0151, 0x014E, 0x014E, 0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013E, 0x013B, 0x0138, 
+       0x0135, 0x0135, 0x0132, 0x012F, 0x012C, 0x0129, 0x0129, 0x0127, 0x0124, 0x0121, 0x0121, 0x011F, 0x011C, 0x011A, 0x0118, 0x0118, 
+       0x0115, 0x0113, 0x0111, 0x010E, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 
+       0x00F8, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E3, 0x00E3, 
+       0x01D4, 0x01D4, 0x01D4, 0x01D4, 0x01D4, 0x01CD, 0x01CD, 0x01CD, 0x01CD, 0x01CD, 0x01CD, 0x01CD, 0x01CD, 0x01C7, 0x01C7, 0x01C7, 
+       0x01C7, 0x01C7, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01BA, 0x01BA, 0x01BA, 0x01B4, 0x01B4, 0x01B4, 0x01AF, 0x01AF, 0x01AF, 0x01A9, 
+       0x01A9, 0x01A4, 0x01A4, 0x019E, 0x019E, 0x019E, 0x0199, 0x0199, 0x0194, 0x0194, 0x018F, 0x018F, 0x018A, 0x018A, 0x0186, 0x0181, 
+       0x0181, 0x017D, 0x017D, 0x0178, 0x0178, 0x0174, 0x0170, 0x0170, 0x016C, 0x016C, 0x0168, 0x0164, 0x0164, 0x0160, 0x015C, 0x015C, 
+       0x0158, 0x0155, 0x0155, 0x0151, 0x014E, 0x014E, 0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013E, 0x013B, 0x0138, 0x0135, 
+       0x0135, 0x0132, 0x012F, 0x012C, 0x012C, 0x0129, 0x0127, 0x0124, 0x0124, 0x0121, 0x011F, 0x011C, 0x011A, 0x011A, 0x0118, 0x0115, 
+       0x0113, 0x0111, 0x0111, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FA, 
+       0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E5, 0x00E3, 0x00E1, 
+       0x01CD, 0x01CD, 0x01CD, 0x01CD, 0x01CD, 0x01CD, 0x01C7, 0x01C7, 0x01C7, 0x01C7, 0x01C7, 0x01C7, 0x01C7, 0x01C7, 0x01C0, 0x01C0, 
+       0x01C0, 0x01C0, 0x01BA, 0x01BA, 0x01BA, 0x01BA, 0x01B4, 0x01B4, 0x01B4, 0x01AF, 0x01AF, 0x01AF, 0x01A9, 0x01A9, 0x01A9, 0x01A4, 
+       0x01A4, 0x019E, 0x019E, 0x019E, 0x0199, 0x0199, 0x0194, 0x0194, 0x018F, 0x018F, 0x018A, 0x018A, 0x0186, 0x0186, 0x0181, 0x0181, 
+       0x017D, 0x017D, 0x0178, 0x0174, 0x0174, 0x0170, 0x0170, 0x016C, 0x0168, 0x0168, 0x0164, 0x0164, 0x0160, 0x015C, 0x015C, 0x0158, 
+       0x0155, 0x0155, 0x0151, 0x014E, 0x014E, 0x014A, 0x0147, 0x0147, 0x0144, 0x0141, 0x013E, 0x013E, 0x013B, 0x0138, 0x0135, 0x0135, 
+       0x0132, 0x012F, 0x012F, 0x012C, 0x0129, 0x0127, 0x0124, 0x0124, 0x0121, 0x011F, 0x011C, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 
+       0x0113, 0x0111, 0x010E, 0x010C, 0x010A, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 
+       0x00F6, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E3, 0x00E1, 0x00E1, 
+       0x01C7, 0x01C7, 0x01C7, 0x01C7, 0x01C7, 0x01C7, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01BA, 0x01BA, 
+       0x01BA, 0x01BA, 0x01BA, 0x01B4, 0x01B4, 0x01B4, 0x01AF, 0x01AF, 0x01AF, 0x01AF, 0x01A9, 0x01A9, 0x01A9, 0x01A4, 0x01A4, 0x019E, 
+       0x019E, 0x019E, 0x0199, 0x0199, 0x0194, 0x0194, 0x018F, 0x018F, 0x018A, 0x018A, 0x0186, 0x0186, 0x0181, 0x0181, 0x017D, 0x017D, 
+       0x0178, 0x0178, 0x0174, 0x0174, 0x0170, 0x016C, 0x016C, 0x0168, 0x0168, 0x0164, 0x0160, 0x0160, 0x015C, 0x015C, 0x0158, 0x0155, 
+       0x0155, 0x0151, 0x014E, 0x014E, 0x014A, 0x0147, 0x0147, 0x0144, 0x0141, 0x013E, 0x013E, 0x013B, 0x0138, 0x0138, 0x0135, 0x0132, 
+       0x012F, 0x012F, 0x012C, 0x0129, 0x0127, 0x0127, 0x0124, 0x0121, 0x011F, 0x011F, 0x011C, 0x011A, 0x0118, 0x0115, 0x0115, 0x0113, 
+       0x0111, 0x010E, 0x010C, 0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 
+       0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E3, 0x00E1, 0x00E0, 
+       0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01C0, 0x01BA, 0x01BA, 0x01BA, 0x01BA, 0x01BA, 0x01BA, 0x01BA, 0x01BA, 0x01B4, 0x01B4, 
+       0x01B4, 0x01B4, 0x01B4, 0x01AF, 0x01AF, 0x01AF, 0x01AF, 0x01A9, 0x01A9, 0x01A9, 0x01A4, 0x01A4, 0x01A4, 0x019E, 0x019E, 0x0199, 
+       0x0199, 0x0199, 0x0194, 0x0194, 0x018F, 0x018F, 0x018F, 0x018A, 0x018A, 0x0186, 0x0186, 0x0181, 0x0181, 0x017D, 0x017D, 0x0178, 
+       0x0174, 0x0174, 0x0170, 0x0170, 0x016C, 0x016C, 0x0168, 0x0164, 0x0164, 0x0160, 0x0160, 0x015C, 0x0158, 0x0158, 0x0155, 0x0151, 
+       0x0151, 0x014E, 0x014E, 0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013E, 0x013B, 0x0138, 0x0138, 0x0135, 0x0132, 0x012F, 
+       0x012F, 0x012C, 0x0129, 0x0127, 0x0127, 0x0124, 0x0121, 0x011F, 0x011F, 0x011C, 0x011A, 0x0118, 0x0118, 0x0115, 0x0113, 0x0111, 
+       0x010E, 0x010E, 0x010C, 0x010A, 0x0108, 0x0106, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 
+       0x00F4, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E3, 0x00E1, 0x00E0, 0x00E0, 
+       0x01BA, 0x01BA, 0x01BA, 0x01BA, 0x01BA, 0x01BA, 0x01BA, 0x01B4, 0x01B4, 0x01B4, 0x01B4, 0x01B4, 0x01B4, 0x01B4, 0x01AF, 0x01AF, 
+       0x01AF, 0x01AF, 0x01AF, 0x01A9, 0x01A9, 0x01A9, 0x01A9, 0x01A4, 0x01A4, 0x01A4, 0x019E, 0x019E, 0x019E, 0x0199, 0x0199, 0x0199, 
+       0x0194, 0x0194, 0x018F, 0x018F, 0x018F, 0x018A, 0x018A, 0x0186, 0x0186, 0x0181, 0x0181, 0x017D, 0x017D, 0x0178, 0x0178, 0x0174, 
+       0x0174, 0x0170, 0x0170, 0x016C, 0x0168, 0x0168, 0x0164, 0x0164, 0x0160, 0x0160, 0x015C, 0x0158, 0x0158, 0x0155, 0x0151, 0x0151, 
+       0x014E, 0x014A, 0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013E, 0x013B, 0x0138, 0x0138, 0x0135, 0x0132, 0x012F, 0x012F, 
+       0x012C, 0x0129, 0x0129, 0x0127, 0x0124, 0x0121, 0x0121, 0x011F, 0x011C, 0x011A, 0x011A, 0x0118, 0x0115, 0x0113, 0x0111, 0x0111, 
+       0x010E, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 
+       0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E1, 0x00E0, 0x00DE, 
+       0x01B4, 0x01B4, 0x01B4, 0x01B4, 0x01B4, 0x01B4, 0x01B4, 0x01AF, 0x01AF, 0x01AF, 0x01AF, 0x01AF, 0x01AF, 0x01AF, 0x01AF, 0x01A9, 
+       0x01A9, 0x01A9, 0x01A9, 0x01A4, 0x01A4, 0x01A4, 0x01A4, 0x019E, 0x019E, 0x019E, 0x0199, 0x0199, 0x0199, 0x0194, 0x0194, 0x0194, 
+       0x018F, 0x018F, 0x018F, 0x018A, 0x018A, 0x0186, 0x0186, 0x0181, 0x0181, 0x017D, 0x017D, 0x0178, 0x0178, 0x0174, 0x0174, 0x0170, 
+       0x0170, 0x016C, 0x016C, 0x0168, 0x0168, 0x0164, 0x0164, 0x0160, 0x015C, 0x015C, 0x0158, 0x0158, 0x0155, 0x0151, 0x0151, 0x014E, 
+       0x014A, 0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013E, 0x013B, 0x0138, 0x0138, 0x0135, 0x0132, 0x0132, 0x012F, 0x012C, 
+       0x0129, 0x0129, 0x0127, 0x0124, 0x0121, 0x0121, 0x011F, 0x011C, 0x011A, 0x011A, 0x0118, 0x0115, 0x0113, 0x0113, 0x0111, 0x010E, 
+       0x010C, 0x010A, 0x010A, 0x0108, 0x0106, 0x0104, 0x0102, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 
+       0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E5, 0x00E3, 0x00E1, 0x00E0, 0x00E0, 0x00DE, 
+       0x01AF, 0x01AF, 0x01AF, 0x01AF, 0x01AF, 0x01AF, 0x01AF, 0x01A9, 0x01A9, 0x01A9, 0x01A9, 0x01A9, 0x01A9, 0x01A9, 0x01A9, 0x01A4, 
+       0x01A4, 0x01A4, 0x01A4, 0x019E, 0x019E, 0x019E, 0x019E, 0x0199, 0x0199, 0x0199, 0x0199, 0x0194, 0x0194, 0x0194, 0x018F, 0x018F, 
+       0x018A, 0x018A, 0x018A, 0x0186, 0x0186, 0x0181, 0x0181, 0x017D, 0x017D, 0x017D, 0x0178, 0x0178, 0x0174, 0x0174, 0x0170, 0x0170, 
+       0x016C, 0x0168, 0x0168, 0x0164, 0x0164, 0x0160, 0x0160, 0x015C, 0x015C, 0x0158, 0x0155, 0x0155, 0x0151, 0x0151, 0x014E, 0x014A, 
+       0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013E, 0x013B, 0x0138, 0x0138, 0x0135, 0x0132, 0x0132, 0x012F, 0x012C, 0x0129, 
+       0x0129, 0x0127, 0x0124, 0x0121, 0x0121, 0x011F, 0x011C, 0x011C, 0x011A, 0x0118, 0x0115, 0x0113, 0x0113, 0x0111, 0x010E, 0x010C, 
+       0x010C, 0x010A, 0x0108, 0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F4, 
+       0x00F2, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 0x00E0, 0x00DE, 0x00DD, 
+       0x01A9, 0x01A9, 0x01A9, 0x01A9, 0x01A9, 0x01A9, 0x01A9, 0x01A9, 0x01A4, 0x01A4, 0x01A4, 0x01A4, 0x01A4, 0x01A4, 0x01A4, 0x019E, 
+       0x019E, 0x019E, 0x019E, 0x019E, 0x0199, 0x0199, 0x0199, 0x0194, 0x0194, 0x0194, 0x0194, 0x018F, 0x018F, 0x018F, 0x018A, 0x018A, 
+       0x0186, 0x0186, 0x0186, 0x0181, 0x0181, 0x017D, 0x017D, 0x017D, 0x0178, 0x0178, 0x0174, 0x0174, 0x0170, 0x0170, 0x016C, 0x016C, 
+       0x0168, 0x0168, 0x0164, 0x0164, 0x0160, 0x015C, 0x015C, 0x0158, 0x0158, 0x0155, 0x0155, 0x0151, 0x014E, 0x014E, 0x014A, 0x0147, 
+       0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013E, 0x013B, 0x0138, 0x0138, 0x0135, 0x0132, 0x0132, 0x012F, 0x012C, 0x0129, 0x0129, 
+       0x0127, 0x0124, 0x0124, 0x0121, 0x011F, 0x011C, 0x011C, 0x011A, 0x0118, 0x0115, 0x0115, 0x0113, 0x0111, 0x010E, 0x010E, 0x010C, 
+       0x010A, 0x0108, 0x0106, 0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F2, 
+       0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E3, 0x00E1, 0x00E0, 0x00DE, 0x00DD, 0x00DD, 
+       0x01A4, 0x01A4, 0x01A4, 0x01A4, 0x01A4, 0x01A4, 0x01A4, 0x01A4, 0x019E, 0x019E, 0x019E, 0x019E, 0x019E, 0x019E, 0x019E, 0x0199, 
+       0x0199, 0x0199, 0x0199, 0x0199, 0x0194, 0x0194, 0x0194, 0x0194, 0x018F, 0x018F, 0x018F, 0x018A, 0x018A, 0x018A, 0x0186, 0x0186, 
+       0x0186, 0x0181, 0x0181, 0x017D, 0x017D, 0x017D, 0x0178, 0x0178, 0x0174, 0x0174, 0x0170, 0x0170, 0x016C, 0x016C, 0x0168, 0x0168, 
+       0x0164, 0x0164, 0x0160, 0x0160, 0x015C, 0x015C, 0x0158, 0x0158, 0x0155, 0x0151, 0x0151, 0x014E, 0x014E, 0x014A, 0x0147, 0x0147, 
+       0x0144, 0x0141, 0x0141, 0x013E, 0x013E, 0x013B, 0x0138, 0x0138, 0x0135, 0x0132, 0x0132, 0x012F, 0x012C, 0x0129, 0x0129, 0x0127, 
+       0x0124, 0x0124, 0x0121, 0x011F, 0x011C, 0x011C, 0x011A, 0x0118, 0x0115, 0x0115, 0x0113, 0x0111, 0x010E, 0x010E, 0x010C, 0x010A, 
+       0x0108, 0x0108, 0x0106, 0x0104, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 
+       0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DD, 0x00DB, 
+       0x019E, 0x019E, 0x019E, 0x019E, 0x019E, 0x019E, 0x019E, 0x019E, 0x0199, 0x0199, 0x0199, 0x0199, 0x0199, 0x0199, 0x0199, 0x0194, 
+       0x0194, 0x0194, 0x0194, 0x0194, 0x018F, 0x018F, 0x018F, 0x018F, 0x018A, 0x018A, 0x018A, 0x0186, 0x0186, 0x0186, 0x0181, 0x0181, 
+       0x0181, 0x017D, 0x017D, 0x017D, 0x0178, 0x0178, 0x0174, 0x0174, 0x0170, 0x0170, 0x016C, 0x016C, 0x016C, 0x0168, 0x0168, 0x0164, 
+       0x0164, 0x0160, 0x015C, 0x015C, 0x0158, 0x0158, 0x0155, 0x0155, 0x0151, 0x0151, 0x014E, 0x014A, 0x014A, 0x0147, 0x0147, 0x0144, 
+       0x0141, 0x0141, 0x013E, 0x013B, 0x013B, 0x0138, 0x0135, 0x0135, 0x0132, 0x012F, 0x012F, 0x012C, 0x0129, 0x0129, 0x0127, 0x0124, 
+       0x0124, 0x0121, 0x011F, 0x011C, 0x011C, 0x011A, 0x0118, 0x0118, 0x0115, 0x0113, 0x0111, 0x0111, 0x010E, 0x010C, 0x010A, 0x010A, 
+       0x0108, 0x0106, 0x0104, 0x0102, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F0, 
+       0x00EF, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 0x00E0, 0x00DE, 0x00DD, 0x00DB, 0x00DB, 
+       0x0199, 0x0199, 0x0199, 0x0199, 0x0199, 0x0199, 0x0199, 0x0199, 0x0194, 0x0194, 0x0194, 0x0194, 0x0194, 0x0194, 0x0194, 0x0194, 
+       0x018F, 0x018F, 0x018F, 0x018F, 0x018A, 0x018A, 0x018A, 0x018A, 0x0186, 0x0186, 0x0186, 0x0181, 0x0181, 0x0181, 0x017D, 0x017D, 
+       0x017D, 0x0178, 0x0178, 0x0178, 0x0174, 0x0174, 0x0170, 0x0170, 0x0170, 0x016C, 0x016C, 0x0168, 0x0168, 0x0164, 0x0164, 0x0160, 
+       0x0160, 0x015C, 0x015C, 0x0158, 0x0158, 0x0155, 0x0151, 0x0151, 0x014E, 0x014E, 0x014A, 0x014A, 0x0147, 0x0144, 0x0144, 0x0141, 
+       0x0141, 0x013E, 0x013B, 0x013B, 0x0138, 0x0135, 0x0135, 0x0132, 0x012F, 0x012F, 0x012C, 0x0129, 0x0129, 0x0127, 0x0124, 0x0124, 
+       0x0121, 0x011F, 0x011F, 0x011C, 0x011A, 0x0118, 0x0118, 0x0115, 0x0113, 0x0111, 0x0111, 0x010E, 0x010C, 0x010A, 0x010A, 0x0108, 
+       0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 
+       0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E3, 0x00E1, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DB, 0x00DA, 
+       0x0194, 0x0194, 0x0194, 0x0194, 0x0194, 0x0194, 0x0194, 0x0194, 0x0194, 0x018F, 0x018F, 0x018F, 0x018F, 0x018F, 0x018F, 0x018F, 
+       0x018A, 0x018A, 0x018A, 0x018A, 0x0186, 0x0186, 0x0186, 0x0186, 0x0181, 0x0181, 0x0181, 0x0181, 0x017D, 0x017D, 0x017D, 0x0178, 
+       0x0178, 0x0174, 0x0174, 0x0174, 0x0170, 0x0170, 0x016C, 0x016C, 0x016C, 0x0168, 0x0168, 0x0164, 0x0164, 0x0160, 0x0160, 0x015C, 
+       0x015C, 0x0158, 0x0158, 0x0155, 0x0155, 0x0151, 0x0151, 0x014E, 0x014E, 0x014A, 0x0147, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 
+       0x013E, 0x013B, 0x013B, 0x0138, 0x0135, 0x0135, 0x0132, 0x012F, 0x012F, 0x012C, 0x0129, 0x0129, 0x0127, 0x0124, 0x0124, 0x0121, 
+       0x011F, 0x011F, 0x011C, 0x011A, 0x0118, 0x0118, 0x0115, 0x0113, 0x0111, 0x0111, 0x010E, 0x010C, 0x010C, 0x010A, 0x0108, 0x0106, 
+       0x0106, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 
+       0x00ED, 0x00EB, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E5, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 
+       0x018F, 0x018F, 0x018F, 0x018F, 0x018F, 0x018F, 0x018F, 0x018F, 0x018F, 0x018A, 0x018A, 0x018A, 0x018A, 0x018A, 0x018A, 0x018A, 
+       0x0186, 0x0186, 0x0186, 0x0186, 0x0186, 0x0181, 0x0181, 0x0181, 0x0181, 0x017D, 0x017D, 0x017D, 0x0178, 0x0178, 0x0178, 0x0174, 
+       0x0174, 0x0174, 0x0170, 0x0170, 0x016C, 0x016C, 0x016C, 0x0168, 0x0168, 0x0164, 0x0164, 0x0160, 0x0160, 0x015C, 0x015C, 0x0158, 
+       0x0158, 0x0155, 0x0155, 0x0151, 0x0151, 0x014E, 0x014E, 0x014A, 0x014A, 0x0147, 0x0147, 0x0144, 0x0141, 0x0141, 0x013E, 0x013E, 
+       0x013B, 0x0138, 0x0138, 0x0135, 0x0135, 0x0132, 0x012F, 0x012F, 0x012C, 0x0129, 0x0129, 0x0127, 0x0124, 0x0124, 0x0121, 0x011F, 
+       0x011F, 0x011C, 0x011A, 0x0118, 0x0118, 0x0115, 0x0113, 0x0113, 0x0111, 0x010E, 0x010C, 0x010C, 0x010A, 0x0108, 0x0106, 0x0106, 
+       0x0104, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00EF, 0x00ED, 
+       0x00EB, 0x00EB, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 0x00E0, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DA, 0x00D9, 
+       0x018A, 0x018A, 0x018A, 0x018A, 0x018A, 0x018A, 0x018A, 0x018A, 0x018A, 0x0186, 0x0186, 0x0186, 0x0186, 0x0186, 0x0186, 0x0186, 
+       0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x017D, 0x017D, 0x017D, 0x017D, 0x0178, 0x0178, 0x0178, 0x0174, 0x0174, 0x0174, 0x0170, 
+       0x0170, 0x0170, 0x016C, 0x016C, 0x016C, 0x0168, 0x0168, 0x0164, 0x0164, 0x0160, 0x0160, 0x0160, 0x015C, 0x015C, 0x0158, 0x0158, 
+       0x0155, 0x0155, 0x0151, 0x0151, 0x014E, 0x014E, 0x014A, 0x0147, 0x0147, 0x0144, 0x0144, 0x0141, 0x0141, 0x013E, 0x013B, 0x013B, 
+       0x0138, 0x0138, 0x0135, 0x0132, 0x0132, 0x012F, 0x012F, 0x012C, 0x0129, 0x0129, 0x0127, 0x0124, 0x0124, 0x0121, 0x011F, 0x011F, 
+       0x011C, 0x011A, 0x0118, 0x0118, 0x0115, 0x0113, 0x0113, 0x0111, 0x010E, 0x010C, 0x010C, 0x010A, 0x0108, 0x0106, 0x0106, 0x0104, 
+       0x0102, 0x0100, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00ED, 0x00ED, 
+       0x00EB, 0x00EA, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E3, 0x00E1, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DB, 0x00DA, 0x00D9, 0x00D7, 
+       0x0186, 0x0186, 0x0186, 0x0186, 0x0186, 0x0186, 0x0186, 0x0186, 0x0186, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 
+       0x017D, 0x017D, 0x017D, 0x017D, 0x017D, 0x0178, 0x0178, 0x0178, 0x0178, 0x0174, 0x0174, 0x0174, 0x0170, 0x0170, 0x0170, 0x016C, 
+       0x016C, 0x016C, 0x0168, 0x0168, 0x0168, 0x0164, 0x0164, 0x0160, 0x0160, 0x0160, 0x015C, 0x015C, 0x0158, 0x0158, 0x0155, 0x0155, 
+       0x0151, 0x0151, 0x014E, 0x014E, 0x014A, 0x014A, 0x0147, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013E, 0x013B, 0x013B, 0x0138, 
+       0x0135, 0x0135, 0x0132, 0x0132, 0x012F, 0x012C, 0x012C, 0x0129, 0x0127, 0x0127, 0x0124, 0x0121, 0x0121, 0x011F, 0x011C, 0x011C, 
+       0x011A, 0x0118, 0x0118, 0x0115, 0x0113, 0x0113, 0x0111, 0x010E, 0x010C, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 0x0102, 
+       0x0102, 0x0100, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00EB, 
+       0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E5, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 
+       0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x017D, 0x017D, 0x017D, 0x017D, 0x017D, 0x017D, 
+       0x017D, 0x0178, 0x0178, 0x0178, 0x0178, 0x0174, 0x0174, 0x0174, 0x0174, 0x0170, 0x0170, 0x0170, 0x0170, 0x016C, 0x016C, 0x016C, 
+       0x0168, 0x0168, 0x0164, 0x0164, 0x0164, 0x0160, 0x0160, 0x0160, 0x015C, 0x015C, 0x0158, 0x0158, 0x0155, 0x0155, 0x0151, 0x0151, 
+       0x014E, 0x014E, 0x014A, 0x014A, 0x0147, 0x0147, 0x0144, 0x0144, 0x0141, 0x0141, 0x013E, 0x013E, 0x013B, 0x0138, 0x0138, 0x0135, 
+       0x0135, 0x0132, 0x012F, 0x012F, 0x012C, 0x012C, 0x0129, 0x0127, 0x0127, 0x0124, 0x0121, 0x0121, 0x011F, 0x011C, 0x011C, 0x011A, 
+       0x0118, 0x0118, 0x0115, 0x0113, 0x0113, 0x0111, 0x010E, 0x010E, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 0x0102, 0x0102, 
+       0x0100, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 
+       0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 0x00E0, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DA, 0x00D9, 0x00D7, 0x00D6, 
+       0x017D, 0x017D, 0x017D, 0x017D, 0x017D, 0x017D, 0x017D, 0x017D, 0x017D, 0x017D, 0x0178, 0x0178, 0x0178, 0x0178, 0x0178, 0x0178, 
+       0x0178, 0x0174, 0x0174, 0x0174, 0x0174, 0x0170, 0x0170, 0x0170, 0x0170, 0x016C, 0x016C, 0x016C, 0x016C, 0x0168, 0x0168, 0x0168, 
+       0x0164, 0x0164, 0x0164, 0x0160, 0x0160, 0x015C, 0x015C, 0x015C, 0x0158, 0x0158, 0x0155, 0x0155, 0x0151, 0x0151, 0x0151, 0x014E, 
+       0x014E, 0x014A, 0x014A, 0x0147, 0x0147, 0x0144, 0x0144, 0x0141, 0x013E, 0x013E, 0x013B, 0x013B, 0x0138, 0x0138, 0x0135, 0x0132, 
+       0x0132, 0x012F, 0x012F, 0x012C, 0x0129, 0x0129, 0x0127, 0x0127, 0x0124, 0x0121, 0x0121, 0x011F, 0x011C, 0x011C, 0x011A, 0x0118, 
+       0x0118, 0x0115, 0x0113, 0x0113, 0x0111, 0x010E, 0x010E, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 0x0102, 0x0102, 0x0100, 
+       0x00FE, 0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 
+       0x00E8, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E1, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DB, 0x00DA, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 
+       0x0178, 0x0178, 0x0178, 0x0178, 0x0178, 0x0178, 0x0178, 0x0178, 0x0178, 0x0178, 0x0174, 0x0174, 0x0174, 0x0174, 0x0174, 0x0174, 
+       0x0174, 0x0170, 0x0170, 0x0170, 0x0170, 0x0170, 0x016C, 0x016C, 0x016C, 0x016C, 0x0168, 0x0168, 0x0168, 0x0164, 0x0164, 0x0164, 
+       0x0160, 0x0160, 0x0160, 0x015C, 0x015C, 0x015C, 0x0158, 0x0158, 0x0155, 0x0155, 0x0151, 0x0151, 0x0151, 0x014E, 0x014E, 0x014A, 
+       0x014A, 0x0147, 0x0147, 0x0144, 0x0144, 0x0141, 0x0141, 0x013E, 0x013E, 0x013B, 0x013B, 0x0138, 0x0135, 0x0135, 0x0132, 0x0132, 
+       0x012F, 0x012F, 0x012C, 0x0129, 0x0129, 0x0127, 0x0124, 0x0124, 0x0121, 0x0121, 0x011F, 0x011C, 0x011C, 0x011A, 0x0118, 0x0118, 
+       0x0115, 0x0113, 0x0113, 0x0111, 0x010E, 0x010E, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 0x00FE, 
+       0x00FE, 0x00FC, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 
+       0x00E6, 0x00E6, 0x00E5, 0x00E3, 0x00E1, 0x00E0, 0x00E0, 0x00DE, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 0x00D6, 0x00D4, 
+       0x0174, 0x0174, 0x0174, 0x0174, 0x0174, 0x0174, 0x0174, 0x0174, 0x0174, 0x0174, 0x0170, 0x0170, 0x0170, 0x0170, 0x0170, 0x0170, 
+       0x0170, 0x016C, 0x016C, 0x016C, 0x016C, 0x016C, 0x0168, 0x0168, 0x0168, 0x0168, 0x0164, 0x0164, 0x0164, 0x0160, 0x0160, 0x0160, 
+       0x015C, 0x015C, 0x015C, 0x0158, 0x0158, 0x0158, 0x0155, 0x0155, 0x0151, 0x0151, 0x0151, 0x014E, 0x014E, 0x014A, 0x014A, 0x0147, 
+       0x0147, 0x0144, 0x0144, 0x0141, 0x0141, 0x013E, 0x013E, 0x013B, 0x013B, 0x0138, 0x0138, 0x0135, 0x0135, 0x0132, 0x012F, 0x012F, 
+       0x012C, 0x012C, 0x0129, 0x0129, 0x0127, 0x0124, 0x0124, 0x0121, 0x011F, 0x011F, 0x011C, 0x011C, 0x011A, 0x0118, 0x0118, 0x0115, 
+       0x0113, 0x0113, 0x0111, 0x010E, 0x010E, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FE, 
+       0x00FC, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 0x00E8, 
+       0x00E6, 0x00E5, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DD, 0x00DB, 0x00DB, 0x00DA, 0x00D9, 0x00D7, 0x00D6, 0x00D6, 0x00D4, 
+       0x0170, 0x0170, 0x0170, 0x0170, 0x0170, 0x0170, 0x0170, 0x0170, 0x0170, 0x0170, 0x016C, 0x016C, 0x016C, 0x016C, 0x016C, 0x016C, 
+       0x016C, 0x0168, 0x0168, 0x0168, 0x0168, 0x0168, 0x0164, 0x0164, 0x0164, 0x0164, 0x0160, 0x0160, 0x0160, 0x015C, 0x015C, 0x015C, 
+       0x015C, 0x0158, 0x0158, 0x0155, 0x0155, 0x0155, 0x0151, 0x0151, 0x0151, 0x014E, 0x014E, 0x014A, 0x014A, 0x0147, 0x0147, 0x0144, 
+       0x0144, 0x0144, 0x0141, 0x0141, 0x013E, 0x013E, 0x013B, 0x0138, 0x0138, 0x0135, 0x0135, 0x0132, 0x0132, 0x012F, 0x012F, 0x012C, 
+       0x012C, 0x0129, 0x0127, 0x0127, 0x0124, 0x0124, 0x0121, 0x011F, 0x011F, 0x011C, 0x011A, 0x011A, 0x0118, 0x0115, 0x0115, 0x0113, 
+       0x0111, 0x0111, 0x010E, 0x010C, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FE, 0x00FC, 
+       0x00FA, 0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 
+       0x00E5, 0x00E3, 0x00E3, 0x00E1, 0x00E0, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DA, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D4, 0x00D3, 
+       0x016C, 0x016C, 0x016C, 0x016C, 0x016C, 0x016C, 0x016C, 0x016C, 0x016C, 0x016C, 0x016C, 0x0168, 0x0168, 0x0168, 0x0168, 0x0168, 
+       0x0168, 0x0164, 0x0164, 0x0164, 0x0164, 0x0164, 0x0160, 0x0160, 0x0160, 0x0160, 0x015C, 0x015C, 0x015C, 0x015C, 0x0158, 0x0158, 
+       0x0158, 0x0155, 0x0155, 0x0155, 0x0151, 0x0151, 0x014E, 0x014E, 0x014E, 0x014A, 0x014A, 0x0147, 0x0147, 0x0144, 0x0144, 0x0144, 
+       0x0141, 0x0141, 0x013E, 0x013E, 0x013B, 0x013B, 0x0138, 0x0138, 0x0135, 0x0135, 0x0132, 0x0132, 0x012F, 0x012C, 0x012C, 0x0129, 
+       0x0129, 0x0127, 0x0127, 0x0124, 0x0121, 0x0121, 0x011F, 0x011F, 0x011C, 0x011A, 0x011A, 0x0118, 0x0115, 0x0115, 0x0113, 0x0111, 
+       0x0111, 0x010E, 0x010C, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FA, 
+       0x00FA, 0x00F8, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 
+       0x00E5, 0x00E3, 0x00E1, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DB, 0x00DA, 0x00D9, 0x00D9, 0x00D7, 0x00D6, 0x00D4, 0x00D3, 0x00D3, 
+       0x0168, 0x0168, 0x0168, 0x0168, 0x0168, 0x0168, 0x0168, 0x0168, 0x0168, 0x0168, 0x0168, 0x0164, 0x0164, 0x0164, 0x0164, 0x0164, 
+       0x0164, 0x0164, 0x0160, 0x0160, 0x0160, 0x0160, 0x015C, 0x015C, 0x015C, 0x015C, 0x0158, 0x0158, 0x0158, 0x0158, 0x0155, 0x0155, 
+       0x0155, 0x0151, 0x0151, 0x0151, 0x014E, 0x014E, 0x014E, 0x014A, 0x014A, 0x0147, 0x0147, 0x0144, 0x0144, 0x0144, 0x0141, 0x0141, 
+       0x013E, 0x013E, 0x013B, 0x013B, 0x0138, 0x0138, 0x0135, 0x0135, 0x0132, 0x0132, 0x012F, 0x012F, 0x012C, 0x012C, 0x0129, 0x0127, 
+       0x0127, 0x0124, 0x0124, 0x0121, 0x0121, 0x011F, 0x011C, 0x011C, 0x011A, 0x011A, 0x0118, 0x0115, 0x0115, 0x0113, 0x0111, 0x0111, 
+       0x010E, 0x010C, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00FA, 
+       0x00F8, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E5, 
+       0x00E3, 0x00E1, 0x00E0, 0x00E0, 0x00DE, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 0x00D6, 0x00D4, 0x00D4, 0x00D3, 0x00D2, 
+       0x0164, 0x0164, 0x0164, 0x0164, 0x0164, 0x0164, 0x0164, 0x0164, 0x0164, 0x0164, 0x0164, 0x0160, 0x0160, 0x0160, 0x0160, 0x0160, 
+       0x0160, 0x0160, 0x015C, 0x015C, 0x015C, 0x015C, 0x015C, 0x0158, 0x0158, 0x0158, 0x0158, 0x0155, 0x0155, 0x0155, 0x0151, 0x0151, 
+       0x0151, 0x014E, 0x014E, 0x014E, 0x014A, 0x014A, 0x014A, 0x0147, 0x0147, 0x0144, 0x0144, 0x0144, 0x0141, 0x0141, 0x013E, 0x013E, 
+       0x013B, 0x013B, 0x0138, 0x0138, 0x0135, 0x0135, 0x0132, 0x0132, 0x012F, 0x012F, 0x012C, 0x012C, 0x0129, 0x0129, 0x0127, 0x0127, 
+       0x0124, 0x0124, 0x0121, 0x011F, 0x011F, 0x011C, 0x011C, 0x011A, 0x0118, 0x0118, 0x0115, 0x0113, 0x0113, 0x0111, 0x0111, 0x010E, 
+       0x010C, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 
+       0x00F6, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E3, 
+       0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DD, 0x00DB, 0x00DB, 0x00DA, 0x00D9, 0x00D7, 0x00D6, 0x00D6, 0x00D4, 0x00D3, 0x00D2, 0x00D0, 
+       0x0160, 0x0160, 0x0160, 0x0160, 0x0160, 0x0160, 0x0160, 0x0160, 0x0160, 0x0160, 0x0160, 0x015C, 0x015C, 0x015C, 0x015C, 0x015C, 
+       0x015C, 0x015C, 0x0158, 0x0158, 0x0158, 0x0158, 0x0158, 0x0155, 0x0155, 0x0155, 0x0155, 0x0151, 0x0151, 0x0151, 0x014E, 0x014E, 
+       0x014E, 0x014A, 0x014A, 0x014A, 0x0147, 0x0147, 0x0147, 0x0144, 0x0144, 0x0144, 0x0141, 0x0141, 0x013E, 0x013E, 0x013B, 0x013B, 
+       0x013B, 0x0138, 0x0138, 0x0135, 0x0135, 0x0132, 0x0132, 0x012F, 0x012F, 0x012C, 0x012C, 0x0129, 0x0129, 0x0127, 0x0124, 0x0124, 
+       0x0121, 0x0121, 0x011F, 0x011F, 0x011C, 0x011A, 0x011A, 0x0118, 0x0118, 0x0115, 0x0113, 0x0113, 0x0111, 0x010E, 0x010E, 0x010C, 
+       0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F6, 
+       0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E3, 0x00E1, 
+       0x00E1, 0x00E0, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DA, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D4, 0x00D3, 0x00D2, 0x00D2, 0x00D0, 
+       0x015C, 0x015C, 0x015C, 0x015C, 0x015C, 0x015C, 0x015C, 0x015C, 0x015C, 0x015C, 0x015C, 0x0158, 0x0158, 0x0158, 0x0158, 0x0158, 
+       0x0158, 0x0158, 0x0155, 0x0155, 0x0155, 0x0155, 0x0155, 0x0151, 0x0151, 0x0151, 0x0151, 0x014E, 0x014E, 0x014E, 0x014A, 0x014A, 
+       0x014A, 0x014A, 0x0147, 0x0147, 0x0144, 0x0144, 0x0144, 0x0141, 0x0141, 0x0141, 0x013E, 0x013E, 0x013B, 0x013B, 0x013B, 0x0138, 
+       0x0138, 0x0135, 0x0135, 0x0132, 0x0132, 0x012F, 0x012F, 0x012C, 0x012C, 0x0129, 0x0129, 0x0127, 0x0127, 0x0124, 0x0124, 0x0121, 
+       0x011F, 0x011F, 0x011C, 0x011C, 0x011A, 0x011A, 0x0118, 0x0115, 0x0115, 0x0113, 0x0113, 0x0111, 0x010E, 0x010E, 0x010C, 0x010A, 
+       0x010A, 0x0108, 0x0106, 0x0106, 0x0104, 0x0102, 0x0102, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F6, 0x00F6, 
+       0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 
+       0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DB, 0x00DA, 0x00D9, 0x00D9, 0x00D7, 0x00D6, 0x00D4, 0x00D3, 0x00D3, 0x00D2, 0x00D0, 0x00CF, 
+       0x0158, 0x0158, 0x0158, 0x0158, 0x0158, 0x0158, 0x0158, 0x0158, 0x0158, 0x0158, 0x0158, 0x0158, 0x0155, 0x0155, 0x0155, 0x0155, 
+       0x0155, 0x0155, 0x0151, 0x0151, 0x0151, 0x0151, 0x0151, 0x014E, 0x014E, 0x014E, 0x014E, 0x014A, 0x014A, 0x014A, 0x014A, 0x0147, 
+       0x0147, 0x0147, 0x0144, 0x0144, 0x0144, 0x0141, 0x0141, 0x013E, 0x013E, 0x013E, 0x013B, 0x013B, 0x0138, 0x0138, 0x0138, 0x0135, 
+       0x0135, 0x0132, 0x0132, 0x012F, 0x012F, 0x012C, 0x012C, 0x0129, 0x0129, 0x0127, 0x0127, 0x0124, 0x0124, 0x0121, 0x0121, 0x011F, 
+       0x011F, 0x011C, 0x011C, 0x011A, 0x0118, 0x0118, 0x0115, 0x0115, 0x0113, 0x0111, 0x0111, 0x010E, 0x010E, 0x010C, 0x010A, 0x010A, 
+       0x0108, 0x0106, 0x0106, 0x0104, 0x0102, 0x0102, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 
+       0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 0x00E0, 
+       0x00DE, 0x00DE, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 0x00D6, 0x00D4, 0x00D4, 0x00D3, 0x00D2, 0x00D0, 0x00CF, 0x00CF, 
+       0x0155, 0x0155, 0x0155, 0x0155, 0x0155, 0x0155, 0x0155, 0x0155, 0x0155, 0x0155, 0x0155, 0x0155, 0x0151, 0x0151, 0x0151, 0x0151, 
+       0x0151, 0x0151, 0x014E, 0x014E, 0x014E, 0x014E, 0x014E, 0x014A, 0x014A, 0x014A, 0x014A, 0x0147, 0x0147, 0x0147, 0x0147, 0x0144, 
+       0x0144, 0x0144, 0x0141, 0x0141, 0x0141, 0x013E, 0x013E, 0x013E, 0x013B, 0x013B, 0x0138, 0x0138, 0x0138, 0x0135, 0x0135, 0x0132, 
+       0x0132, 0x012F, 0x012F, 0x012C, 0x012C, 0x012C, 0x0129, 0x0129, 0x0127, 0x0127, 0x0124, 0x0124, 0x0121, 0x011F, 0x011F, 0x011C, 
+       0x011C, 0x011A, 0x011A, 0x0118, 0x0118, 0x0115, 0x0113, 0x0113, 0x0111, 0x0111, 0x010E, 0x010C, 0x010C, 0x010A, 0x010A, 0x0108, 
+       0x0106, 0x0106, 0x0104, 0x0102, 0x0102, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F2, 
+       0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E1, 0x00E0, 0x00E0, 
+       0x00DE, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 0x00D6, 0x00D6, 0x00D4, 0x00D3, 0x00D2, 0x00D0, 0x00D0, 0x00CF, 0x00CE, 
+       0x0151, 0x0151, 0x0151, 0x0151, 0x0151, 0x0151, 0x0151, 0x0151, 0x0151, 0x0151, 0x0151, 0x0151, 0x014E, 0x014E, 0x014E, 0x014E, 
+       0x014E, 0x014E, 0x014E, 0x014A, 0x014A, 0x014A, 0x014A, 0x0147, 0x0147, 0x0147, 0x0147, 0x0144, 0x0144, 0x0144, 0x0144, 0x0141, 
+       0x0141, 0x0141, 0x013E, 0x013E, 0x013E, 0x013B, 0x013B, 0x013B, 0x0138, 0x0138, 0x0135, 0x0135, 0x0135, 0x0132, 0x0132, 0x012F, 
+       0x012F, 0x012F, 0x012C, 0x012C, 0x0129, 0x0129, 0x0127, 0x0127, 0x0124, 0x0124, 0x0121, 0x0121, 0x011F, 0x011F, 0x011C, 0x011C, 
+       0x011A, 0x0118, 0x0118, 0x0115, 0x0115, 0x0113, 0x0113, 0x0111, 0x010E, 0x010E, 0x010C, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 
+       0x0106, 0x0104, 0x0102, 0x0102, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 
+       0x00F0, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E1, 0x00E0, 0x00E0, 0x00DE, 
+       0x00DD, 0x00DB, 0x00DB, 0x00DA, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D4, 0x00D3, 0x00D2, 0x00D2, 0x00D0, 0x00CF, 0x00CE, 0x00CC, 
+       0x014E, 0x014E, 0x014E, 0x014E, 0x014E, 0x014E, 0x014E, 0x014E, 0x014E, 0x014E, 0x014E, 0x014E, 0x014A, 0x014A, 0x014A, 0x014A, 
+       0x014A, 0x014A, 0x014A, 0x0147, 0x0147, 0x0147, 0x0147, 0x0147, 0x0144, 0x0144, 0x0144, 0x0144, 0x0141, 0x0141, 0x0141, 0x013E, 
+       0x013E, 0x013E, 0x013B, 0x013B, 0x013B, 0x0138, 0x0138, 0x0138, 0x0135, 0x0135, 0x0135, 0x0132, 0x0132, 0x012F, 0x012F, 0x012F, 
+       0x012C, 0x012C, 0x0129, 0x0129, 0x0127, 0x0127, 0x0124, 0x0124, 0x0121, 0x0121, 0x011F, 0x011F, 0x011C, 0x011C, 0x011A, 0x011A, 
+       0x0118, 0x0118, 0x0115, 0x0115, 0x0113, 0x0111, 0x0111, 0x010E, 0x010E, 0x010C, 0x010A, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 
+       0x0104, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 
+       0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E1, 0x00E0, 0x00E0, 0x00DE, 0x00DD, 
+       0x00DB, 0x00DB, 0x00DA, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D4, 0x00D3, 0x00D3, 0x00D2, 0x00D0, 0x00CF, 0x00CE, 0x00CE, 0x00CC, 
+       0x014A, 0x014A, 0x014A, 0x014A, 0x014A, 0x014A, 0x014A, 0x014A, 0x014A, 0x014A, 0x014A, 0x014A, 0x0147, 0x0147, 0x0147, 0x0147, 
+       0x0147, 0x0147, 0x0147, 0x0144, 0x0144, 0x0144, 0x0144, 0x0144, 0x0141, 0x0141, 0x0141, 0x0141, 0x013E, 0x013E, 0x013E, 0x013B, 
+       0x013B, 0x013B, 0x013B, 0x0138, 0x0138, 0x0138, 0x0135, 0x0135, 0x0132, 0x0132, 0x0132, 0x012F, 0x012F, 0x012C, 0x012C, 0x012C, 
+       0x0129, 0x0129, 0x0127, 0x0127, 0x0124, 0x0124, 0x0121, 0x0121, 0x011F, 0x011F, 0x011F, 0x011C, 0x011A, 0x011A, 0x0118, 0x0118, 
+       0x0115, 0x0115, 0x0113, 0x0113, 0x0111, 0x0111, 0x010E, 0x010C, 0x010C, 0x010A, 0x010A, 0x0108, 0x0106, 0x0106, 0x0104, 0x0104, 
+       0x0102, 0x0100, 0x0100, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 
+       0x00ED, 0x00ED, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DD, 0x00DD, 
+       0x00DB, 0x00DA, 0x00D9, 0x00D9, 0x00D7, 0x00D6, 0x00D4, 0x00D4, 0x00D3, 0x00D2, 0x00D0, 0x00CF, 0x00CF, 0x00CE, 0x00CC, 0x00CB, 
+       0x0147, 0x0147, 0x0147, 0x0147, 0x0147, 0x0147, 0x0147, 0x0147, 0x0147, 0x0147, 0x0147, 0x0147, 0x0144, 0x0144, 0x0144, 0x0144, 
+       0x0144, 0x0144, 0x0144, 0x0141, 0x0141, 0x0141, 0x0141, 0x0141, 0x013E, 0x013E, 0x013E, 0x013E, 0x013B, 0x013B, 0x013B, 0x013B, 
+       0x0138, 0x0138, 0x0138, 0x0135, 0x0135, 0x0135, 0x0132, 0x0132, 0x0132, 0x012F, 0x012F, 0x012C, 0x012C, 0x012C, 0x0129, 0x0129, 
+       0x0127, 0x0127, 0x0124, 0x0124, 0x0124, 0x0121, 0x0121, 0x011F, 0x011F, 0x011C, 0x011C, 0x011A, 0x011A, 0x0118, 0x0118, 0x0115, 
+       0x0115, 0x0113, 0x0111, 0x0111, 0x010E, 0x010E, 0x010C, 0x010C, 0x010A, 0x0108, 0x0108, 0x0106, 0x0106, 0x0104, 0x0102, 0x0102, 
+       0x0100, 0x0100, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 
+       0x00ED, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 
+       0x00DA, 0x00D9, 0x00D9, 0x00D7, 0x00D6, 0x00D4, 0x00D4, 0x00D3, 0x00D2, 0x00D0, 0x00D0, 0x00CF, 0x00CE, 0x00CC, 0x00CB, 0x00CB, 
+       0x0144, 0x0144, 0x0144, 0x0144, 0x0144, 0x0144, 0x0144, 0x0144, 0x0144, 0x0144, 0x0144, 0x0144, 0x0144, 0x0141, 0x0141, 0x0141, 
+       0x0141, 0x0141, 0x0141, 0x013E, 0x013E, 0x013E, 0x013E, 0x013E, 0x013B, 0x013B, 0x013B, 0x013B, 0x0138, 0x0138, 0x0138, 0x0138, 
+       0x0135, 0x0135, 0x0135, 0x0132, 0x0132, 0x0132, 0x012F, 0x012F, 0x012F, 0x012C, 0x012C, 0x0129, 0x0129, 0x0129, 0x0127, 0x0127, 
+       0x0124, 0x0124, 0x0124, 0x0121, 0x0121, 0x011F, 0x011F, 0x011C, 0x011C, 0x011A, 0x011A, 0x0118, 0x0118, 0x0115, 0x0115, 0x0113, 
+       0x0113, 0x0111, 0x0111, 0x010E, 0x010E, 0x010C, 0x010A, 0x010A, 0x0108, 0x0108, 0x0106, 0x0104, 0x0104, 0x0102, 0x0102, 0x0100, 
+       0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00ED, 
+       0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DA, 
+       0x00DA, 0x00D9, 0x00D7, 0x00D6, 0x00D6, 0x00D4, 0x00D3, 0x00D2, 0x00D0, 0x00D0, 0x00CF, 0x00CE, 0x00CC, 0x00CC, 0x00CB, 0x00CA, 
+       0x0141, 0x0141, 0x0141, 0x0141, 0x0141, 0x0141, 0x0141, 0x0141, 0x0141, 0x0141, 0x0141, 0x0141, 0x0141, 0x013E, 0x013E, 0x013E, 
+       0x013E, 0x013E, 0x013E, 0x013B, 0x013B, 0x013B, 0x013B, 0x013B, 0x0138, 0x0138, 0x0138, 0x0138, 0x0135, 0x0135, 0x0135, 0x0135, 
+       0x0132, 0x0132, 0x0132, 0x012F, 0x012F, 0x012F, 0x012C, 0x012C, 0x012C, 0x0129, 0x0129, 0x0129, 0x0127, 0x0127, 0x0124, 0x0124, 
+       0x0124, 0x0121, 0x0121, 0x011F, 0x011F, 0x011C, 0x011C, 0x011A, 0x011A, 0x0118, 0x0118, 0x0115, 0x0115, 0x0113, 0x0113, 0x0111, 
+       0x0111, 0x010E, 0x010E, 0x010C, 0x010C, 0x010A, 0x010A, 0x0108, 0x0106, 0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 0x0100, 0x00FE, 
+       0x00FE, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 
+       0x00EA, 0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 
+       0x00D9, 0x00D7, 0x00D6, 0x00D6, 0x00D4, 0x00D3, 0x00D2, 0x00D2, 0x00D0, 0x00CF, 0x00CE, 0x00CE, 0x00CC, 0x00CB, 0x00CA, 0x00C9, 
+       0x013E, 0x013E, 0x013E, 0x013E, 0x013E, 0x013E, 0x013E, 0x013E, 0x013E, 0x013E, 0x013E, 0x013E, 0x013E, 0x013B, 0x013B, 0x013B, 
+       0x013B, 0x013B, 0x013B, 0x013B, 0x0138, 0x0138, 0x0138, 0x0138, 0x0135, 0x0135, 0x0135, 0x0135, 0x0135, 0x0132, 0x0132, 0x0132, 
+       0x012F, 0x012F, 0x012F, 0x012C, 0x012C, 0x012C, 0x0129, 0x0129, 0x0129, 0x0127, 0x0127, 0x0127, 0x0124, 0x0124, 0x0121, 0x0121, 
+       0x0121, 0x011F, 0x011F, 0x011C, 0x011C, 0x011A, 0x011A, 0x011A, 0x0118, 0x0118, 0x0115, 0x0115, 0x0113, 0x0113, 0x0111, 0x0111, 
+       0x010E, 0x010C, 0x010C, 0x010A, 0x010A, 0x0108, 0x0108, 0x0106, 0x0106, 0x0104, 0x0102, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FC, 
+       0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EA, 
+       0x00EA, 0x00E8, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 
+       0x00D7, 0x00D6, 0x00D6, 0x00D4, 0x00D3, 0x00D2, 0x00D2, 0x00D0, 0x00CF, 0x00CE, 0x00CE, 0x00CC, 0x00CB, 0x00CA, 0x00CA, 0x00C9, 
+       0x013B, 0x013B, 0x013B, 0x013B, 0x013B, 0x013B, 0x013B, 0x013B, 0x013B, 0x013B, 0x013B, 0x013B, 0x013B, 0x0138, 0x0138, 0x0138, 
+       0x0138, 0x0138, 0x0138, 0x0138, 0x0135, 0x0135, 0x0135, 0x0135, 0x0135, 0x0132, 0x0132, 0x0132, 0x0132, 0x012F, 0x012F, 0x012F, 
+       0x012C, 0x012C, 0x012C, 0x012C, 0x0129, 0x0129, 0x0129, 0x0127, 0x0127, 0x0124, 0x0124, 0x0124, 0x0121, 0x0121, 0x0121, 0x011F, 
+       0x011F, 0x011C, 0x011C, 0x011A, 0x011A, 0x011A, 0x0118, 0x0118, 0x0115, 0x0115, 0x0113, 0x0113, 0x0111, 0x0111, 0x010E, 0x010E, 
+       0x010C, 0x010C, 0x010A, 0x010A, 0x0108, 0x0106, 0x0106, 0x0104, 0x0104, 0x0102, 0x0102, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FC, 
+       0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00E8, 
+       0x00E8, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 
+       0x00D6, 0x00D6, 0x00D4, 0x00D3, 0x00D3, 0x00D2, 0x00D0, 0x00CF, 0x00CF, 0x00CE, 0x00CC, 0x00CB, 0x00CB, 0x00CA, 0x00C9, 0x00C7, 
+       0x0138, 0x0138, 0x0138, 0x0138, 0x0138, 0x0138, 0x0138, 0x0138, 0x0138, 0x0138, 0x0138, 0x0138, 0x0138, 0x0135, 0x0135, 0x0135, 
+       0x0135, 0x0135, 0x0135, 0x0135, 0x0132, 0x0132, 0x0132, 0x0132, 0x0132, 0x012F, 0x012F, 0x012F, 0x012F, 0x012C, 0x012C, 0x012C, 
+       0x012C, 0x0129, 0x0129, 0x0129, 0x0127, 0x0127, 0x0127, 0x0124, 0x0124, 0x0124, 0x0121, 0x0121, 0x011F, 0x011F, 0x011F, 0x011C, 
+       0x011C, 0x011A, 0x011A, 0x011A, 0x0118, 0x0118, 0x0115, 0x0115, 0x0113, 0x0113, 0x0111, 0x0111, 0x010E, 0x010E, 0x010C, 0x010C, 
+       0x010A, 0x010A, 0x0108, 0x0108, 0x0106, 0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 
+       0x00F8, 0x00F8, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00E8, 0x00E8, 
+       0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 0x00D7, 
+       0x00D6, 0x00D4, 0x00D3, 0x00D3, 0x00D2, 0x00D0, 0x00CF, 0x00CF, 0x00CE, 0x00CC, 0x00CB, 0x00CB, 0x00CA, 0x00C9, 0x00C7, 0x00C7, 
+       0x0135, 0x0135, 0x0135, 0x0135, 0x0135, 0x0135, 0x0135, 0x0135, 0x0135, 0x0135, 0x0135, 0x0135, 0x0135, 0x0132, 0x0132, 0x0132, 
+       0x0132, 0x0132, 0x0132, 0x0132, 0x012F, 0x012F, 0x012F, 0x012F, 0x012F, 0x012C, 0x012C, 0x012C, 0x012C, 0x0129, 0x0129, 0x0129, 
+       0x0129, 0x0127, 0x0127, 0x0127, 0x0124, 0x0124, 0x0124, 0x0121, 0x0121, 0x0121, 0x011F, 0x011F, 0x011F, 0x011C, 0x011C, 0x011A, 
+       0x011A, 0x011A, 0x0118, 0x0118, 0x0115, 0x0115, 0x0113, 0x0113, 0x0111, 0x0111, 0x010E, 0x010E, 0x010E, 0x010C, 0x010C, 0x010A, 
+       0x0108, 0x0108, 0x0106, 0x0106, 0x0104, 0x0104, 0x0102, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 
+       0x00F8, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 
+       0x00E5, 0x00E5, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 
+       0x00D4, 0x00D3, 0x00D3, 0x00D2, 0x00D0, 0x00CF, 0x00CF, 0x00CE, 0x00CC, 0x00CB, 0x00CB, 0x00CA, 0x00C9, 0x00C7, 0x00C7, 0x00C6, 
+       0x0132, 0x0132, 0x0132, 0x0132, 0x0132, 0x0132, 0x0132, 0x0132, 0x0132, 0x0132, 0x0132, 0x0132, 0x0132, 0x0132, 0x012F, 0x012F, 
+       0x012F, 0x012F, 0x012F, 0x012F, 0x012C, 0x012C, 0x012C, 0x012C, 0x012C, 0x0129, 0x0129, 0x0129, 0x0129, 0x0127, 0x0127, 0x0127, 
+       0x0127, 0x0124, 0x0124, 0x0124, 0x0121, 0x0121, 0x0121, 0x011F, 0x011F, 0x011F, 0x011C, 0x011C, 0x011C, 0x011A, 0x011A, 0x0118, 
+       0x0118, 0x0118, 0x0115, 0x0115, 0x0113, 0x0113, 0x0111, 0x0111, 0x0111, 0x010E, 0x010E, 0x010C, 0x010C, 0x010A, 0x010A, 0x0108, 
+       0x0108, 0x0106, 0x0106, 0x0104, 0x0104, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F6, 
+       0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E5, 
+       0x00E5, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D4, 
+       0x00D3, 0x00D3, 0x00D2, 0x00D0, 0x00D0, 0x00CF, 0x00CE, 0x00CC, 0x00CC, 0x00CB, 0x00CA, 0x00C9, 0x00C9, 0x00C7, 0x00C6, 0x00C5, 
+       0x012F, 0x012F, 0x012F, 0x012F, 0x012F, 0x012F, 0x012F, 0x012F, 0x012F, 0x012F, 0x012F, 0x012F, 0x012F, 0x012F, 0x012C, 0x012C, 
+       0x012C, 0x012C, 0x012C, 0x012C, 0x0129, 0x0129, 0x0129, 0x0129, 0x0129, 0x0127, 0x0127, 0x0127, 0x0127, 0x0124, 0x0124, 0x0124, 
+       0x0124, 0x0121, 0x0121, 0x0121, 0x011F, 0x011F, 0x011F, 0x011C, 0x011C, 0x011C, 0x011A, 0x011A, 0x011A, 0x0118, 0x0118, 0x0118, 
+       0x0115, 0x0115, 0x0113, 0x0113, 0x0111, 0x0111, 0x0111, 0x010E, 0x010E, 0x010C, 0x010C, 0x010A, 0x010A, 0x0108, 0x0108, 0x0106, 
+       0x0106, 0x0104, 0x0104, 0x0102, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F6, 
+       0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E5, 
+       0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D4, 0x00D3, 
+       0x00D3, 0x00D2, 0x00D0, 0x00D0, 0x00CF, 0x00CE, 0x00CC, 0x00CC, 0x00CB, 0x00CA, 0x00C9, 0x00C9, 0x00C7, 0x00C6, 0x00C5, 0x00C5, 
+       0x012C, 0x012C, 0x012C, 0x012C, 0x012C, 0x012C, 0x012C, 0x012C, 0x012C, 0x012C, 0x012C, 0x012C, 0x012C, 0x012C, 0x0129, 0x0129, 
+       0x0129, 0x0129, 0x0129, 0x0129, 0x0129, 0x0127, 0x0127, 0x0127, 0x0127, 0x0124, 0x0124, 0x0124, 0x0124, 0x0124, 0x0121, 0x0121, 
+       0x0121, 0x011F, 0x011F, 0x011F, 0x011F, 0x011C, 0x011C, 0x011C, 0x011A, 0x011A, 0x011A, 0x0118, 0x0118, 0x0115, 0x0115, 0x0115, 
+       0x0113, 0x0113, 0x0111, 0x0111, 0x0111, 0x010E, 0x010E, 0x010C, 0x010C, 0x010A, 0x010A, 0x0108, 0x0108, 0x0106, 0x0106, 0x0104, 
+       0x0104, 0x0102, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F4, 
+       0x00F2, 0x00F2, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E3, 0x00E3, 
+       0x00E1, 0x00E0, 0x00E0, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D4, 0x00D4, 0x00D3, 
+       0x00D2, 0x00D0, 0x00D0, 0x00CF, 0x00CE, 0x00CC, 0x00CC, 0x00CB, 0x00CA, 0x00CA, 0x00C9, 0x00C7, 0x00C6, 0x00C6, 0x00C5, 0x00C4, 
+       0x0129, 0x0129, 0x0129, 0x0129, 0x0129, 0x0129, 0x0129, 0x0129, 0x0129, 0x0129, 0x0129, 0x0129, 0x0129, 0x0129, 0x0127, 0x0127, 
+       0x0127, 0x0127, 0x0127, 0x0127, 0x0127, 0x0124, 0x0124, 0x0124, 0x0124, 0x0124, 0x0121, 0x0121, 0x0121, 0x0121, 0x011F, 0x011F, 
+       0x011F, 0x011C, 0x011C, 0x011C, 0x011C, 0x011A, 0x011A, 0x011A, 0x0118, 0x0118, 0x0118, 0x0115, 0x0115, 0x0113, 0x0113, 0x0113, 
+       0x0111, 0x0111, 0x0111, 0x010E, 0x010E, 0x010C, 0x010C, 0x010A, 0x010A, 0x0108, 0x0108, 0x0108, 0x0106, 0x0106, 0x0104, 0x0104, 
+       0x0102, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 
+       0x00F0, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 
+       0x00E0, 0x00E0, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D4, 0x00D4, 0x00D3, 0x00D2, 
+       0x00D0, 0x00D0, 0x00CF, 0x00CE, 0x00CE, 0x00CC, 0x00CB, 0x00CA, 0x00CA, 0x00C9, 0x00C7, 0x00C6, 0x00C6, 0x00C5, 0x00C4, 0x00C3, 
+       0x0127, 0x0127, 0x0127, 0x0127, 0x0127, 0x0127, 0x0127, 0x0127, 0x0127, 0x0127, 0x0127, 0x0127, 0x0127, 0x0127, 0x0124, 0x0124, 
+       0x0124, 0x0124, 0x0124, 0x0124, 0x0124, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x011F, 0x011F, 0x011F, 0x011F, 0x011C, 0x011C, 
+       0x011C, 0x011C, 0x011A, 0x011A, 0x011A, 0x0118, 0x0118, 0x0118, 0x0115, 0x0115, 0x0115, 0x0113, 0x0113, 0x0113, 0x0111, 0x0111, 
+       0x010E, 0x010E, 0x010E, 0x010C, 0x010C, 0x010A, 0x010A, 0x0108, 0x0108, 0x0108, 0x0106, 0x0106, 0x0104, 0x0104, 0x0102, 0x0102, 
+       0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 
+       0x00F0, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 0x00E0, 
+       0x00E0, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D4, 0x00D4, 0x00D3, 0x00D2, 0x00D0, 
+       0x00D0, 0x00CF, 0x00CE, 0x00CE, 0x00CC, 0x00CB, 0x00CA, 0x00CA, 0x00C9, 0x00C7, 0x00C6, 0x00C6, 0x00C5, 0x00C4, 0x00C3, 0x00C3, 
+       0x0124, 0x0124, 0x0124, 0x0124, 0x0124, 0x0124, 0x0124, 0x0124, 0x0124, 0x0124, 0x0124, 0x0124, 0x0124, 0x0124, 0x0121, 0x0121, 
+       0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x011F, 0x011F, 0x011F, 0x011F, 0x011F, 0x011C, 0x011C, 0x011C, 0x011C, 0x011A, 0x011A, 
+       0x011A, 0x011A, 0x0118, 0x0118, 0x0118, 0x0115, 0x0115, 0x0115, 0x0113, 0x0113, 0x0113, 0x0111, 0x0111, 0x0111, 0x010E, 0x010E, 
+       0x010E, 0x010C, 0x010C, 0x010A, 0x010A, 0x0108, 0x0108, 0x0108, 0x0106, 0x0106, 0x0104, 0x0104, 0x0102, 0x0102, 0x0100, 0x0100, 
+       0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 
+       0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00E0, 
+       0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D4, 0x00D3, 0x00D3, 0x00D2, 0x00D0, 0x00D0, 
+       0x00CF, 0x00CE, 0x00CE, 0x00CC, 0x00CB, 0x00CA, 0x00CA, 0x00C9, 0x00C7, 0x00C7, 0x00C6, 0x00C5, 0x00C4, 0x00C4, 0x00C3, 0x00C1, 
+       0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x0121, 0x011F, 0x011F, 
+       0x011F, 0x011F, 0x011F, 0x011F, 0x011F, 0x011C, 0x011C, 0x011C, 0x011C, 0x011C, 0x011A, 0x011A, 0x011A, 0x011A, 0x0118, 0x0118, 
+       0x0118, 0x0118, 0x0115, 0x0115, 0x0115, 0x0113, 0x0113, 0x0113, 0x0111, 0x0111, 0x0111, 0x010E, 0x010E, 0x010E, 0x010C, 0x010C, 
+       0x010C, 0x010A, 0x010A, 0x0108, 0x0108, 0x0108, 0x0106, 0x0106, 0x0104, 0x0104, 0x0102, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FE, 
+       0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00EF, 
+       0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DE, 
+       0x00DD, 0x00DB, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 0x00D6, 0x00D6, 0x00D4, 0x00D3, 0x00D3, 0x00D2, 0x00D0, 0x00D0, 0x00CF, 
+       0x00CE, 0x00CE, 0x00CC, 0x00CB, 0x00CA, 0x00CA, 0x00C9, 0x00C7, 0x00C7, 0x00C6, 0x00C5, 0x00C4, 0x00C4, 0x00C3, 0x00C1, 0x00C0, 
+       0x011F, 0x011F, 0x011F, 0x011F, 0x011F, 0x011F, 0x011F, 0x011F, 0x011F, 0x011F, 0x011F, 0x011F, 0x011F, 0x011F, 0x011F, 0x011C, 
+       0x011C, 0x011C, 0x011C, 0x011C, 0x011C, 0x011A, 0x011A, 0x011A, 0x011A, 0x011A, 0x0118, 0x0118, 0x0118, 0x0118, 0x0115, 0x0115, 
+       0x0115, 0x0115, 0x0113, 0x0113, 0x0113, 0x0113, 0x0111, 0x0111, 0x0111, 0x010E, 0x010E, 0x010E, 0x010C, 0x010C, 0x010A, 0x010A, 
+       0x010A, 0x0108, 0x0108, 0x0106, 0x0106, 0x0106, 0x0104, 0x0104, 0x0102, 0x0102, 0x0100, 0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FC, 
+       0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00ED, 
+       0x00EB, 0x00EB, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 
+       0x00DB, 0x00DB, 0x00DA, 0x00D9, 0x00D9, 0x00D7, 0x00D6, 0x00D6, 0x00D4, 0x00D3, 0x00D3, 0x00D2, 0x00D0, 0x00D0, 0x00CF, 0x00CE, 
+       0x00CE, 0x00CC, 0x00CB, 0x00CA, 0x00CA, 0x00C9, 0x00C7, 0x00C7, 0x00C6, 0x00C5, 0x00C4, 0x00C4, 0x00C3, 0x00C1, 0x00C0, 0x00C0, 
+       0x011C, 0x011C, 0x011C, 0x011C, 0x011C, 0x011C, 0x011C, 0x011C, 0x011C, 0x011C, 0x011C, 0x011C, 0x011C, 0x011C, 0x011C, 0x011A, 
+       0x011A, 0x011A, 0x011A, 0x011A, 0x011A, 0x0118, 0x0118, 0x0118, 0x0118, 0x0118, 0x0115, 0x0115, 0x0115, 0x0115, 0x0115, 0x0113, 
+       0x0113, 0x0113, 0x0111, 0x0111, 0x0111, 0x0111, 0x010E, 0x010E, 0x010E, 0x010C, 0x010C, 0x010C, 0x010A, 0x010A, 0x010A, 0x0108, 
+       0x0108, 0x0106, 0x0106, 0x0106, 0x0104, 0x0104, 0x0102, 0x0102, 0x0100, 0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 
+       0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00EB, 0x00EB, 
+       0x00EA, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 0x00E0, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DB, 
+       0x00DB, 0x00DA, 0x00D9, 0x00D9, 0x00D7, 0x00D6, 0x00D6, 0x00D4, 0x00D3, 0x00D3, 0x00D2, 0x00D0, 0x00D0, 0x00CF, 0x00CE, 0x00CE, 
+       0x00CC, 0x00CB, 0x00CA, 0x00CA, 0x00C9, 0x00C7, 0x00C7, 0x00C6, 0x00C5, 0x00C4, 0x00C4, 0x00C3, 0x00C1, 0x00C1, 0x00C0, 0x00BF, 
+       0x011A, 0x011A, 0x011A, 0x011A, 0x011A, 0x011A, 0x011A, 0x011A, 0x011A, 0x011A, 0x011A, 0x011A, 0x011A, 0x011A, 0x011A, 0x0118, 
+       0x0118, 0x0118, 0x0118, 0x0118, 0x0118, 0x0118, 0x0115, 0x0115, 0x0115, 0x0115, 0x0115, 0x0113, 0x0113, 0x0113, 0x0113, 0x0111, 
+       0x0111, 0x0111, 0x0111, 0x010E, 0x010E, 0x010E, 0x010C, 0x010C, 0x010C, 0x010A, 0x010A, 0x010A, 0x0108, 0x0108, 0x0108, 0x0106, 
+       0x0106, 0x0104, 0x0104, 0x0104, 0x0102, 0x0102, 0x0100, 0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 
+       0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 
+       0x00E8, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00E0, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DA, 
+       0x00DA, 0x00D9, 0x00D9, 0x00D7, 0x00D6, 0x00D6, 0x00D4, 0x00D3, 0x00D3, 0x00D2, 0x00D0, 0x00D0, 0x00CF, 0x00CE, 0x00CE, 0x00CC, 
+       0x00CB, 0x00CA, 0x00CA, 0x00C9, 0x00C7, 0x00C7, 0x00C6, 0x00C5, 0x00C5, 0x00C4, 0x00C3, 0x00C1, 0x00C1, 0x00C0, 0x00BF, 0x00BE, 
+       0x0118, 0x0118, 0x0118, 0x0118, 0x0118, 0x0118, 0x0118, 0x0118, 0x0118, 0x0118, 0x0118, 0x0118, 0x0118, 0x0118, 0x0118, 0x0115, 
+       0x0115, 0x0115, 0x0115, 0x0115, 0x0115, 0x0115, 0x0113, 0x0113, 0x0113, 0x0113, 0x0113, 0x0111, 0x0111, 0x0111, 0x0111, 0x010E, 
+       0x010E, 0x010E, 0x010E, 0x010C, 0x010C, 0x010C, 0x010A, 0x010A, 0x010A, 0x0108, 0x0108, 0x0108, 0x0106, 0x0106, 0x0106, 0x0104, 
+       0x0104, 0x0104, 0x0102, 0x0102, 0x0100, 0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F8, 0x00F8, 
+       0x00F6, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 
+       0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 
+       0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D6, 0x00D4, 0x00D3, 0x00D3, 0x00D2, 0x00D0, 0x00D0, 0x00CF, 0x00CE, 0x00CE, 0x00CC, 0x00CB, 
+       0x00CA, 0x00CA, 0x00C9, 0x00C7, 0x00C7, 0x00C6, 0x00C5, 0x00C5, 0x00C4, 0x00C3, 0x00C1, 0x00C1, 0x00C0, 0x00BF, 0x00BE, 0x00BE, 
+       0x0115, 0x0115, 0x0115, 0x0115, 0x0115, 0x0115, 0x0115, 0x0115, 0x0115, 0x0115, 0x0115, 0x0115, 0x0115, 0x0115, 0x0115, 0x0113, 
+       0x0113, 0x0113, 0x0113, 0x0113, 0x0113, 0x0113, 0x0111, 0x0111, 0x0111, 0x0111, 0x0111, 0x010E, 0x010E, 0x010E, 0x010E, 0x010C, 
+       0x010C, 0x010C, 0x010C, 0x010A, 0x010A, 0x010A, 0x0108, 0x0108, 0x0108, 0x0106, 0x0106, 0x0106, 0x0104, 0x0104, 0x0104, 0x0102, 
+       0x0102, 0x0102, 0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F8, 0x00F8, 0x00F6, 0x00F6, 
+       0x00F4, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E6, 
+       0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 0x00E0, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DB, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 
+       0x00D7, 0x00D7, 0x00D6, 0x00D4, 0x00D4, 0x00D3, 0x00D2, 0x00D2, 0x00D0, 0x00CF, 0x00CF, 0x00CE, 0x00CC, 0x00CC, 0x00CB, 0x00CA, 
+       0x00CA, 0x00C9, 0x00C7, 0x00C7, 0x00C6, 0x00C5, 0x00C5, 0x00C4, 0x00C3, 0x00C1, 0x00C1, 0x00C0, 0x00BF, 0x00BF, 0x00BE, 0x00BD, 
+       0x0113, 0x0113, 0x0113, 0x0113, 0x0113, 0x0113, 0x0113, 0x0113, 0x0113, 0x0113, 0x0113, 0x0113, 0x0113, 0x0113, 0x0113, 0x0111, 
+       0x0111, 0x0111, 0x0111, 0x0111, 0x0111, 0x0111, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010C, 0x010C, 0x010C, 0x010C, 0x010A, 
+       0x010A, 0x010A, 0x010A, 0x0108, 0x0108, 0x0108, 0x0108, 0x0106, 0x0106, 0x0106, 0x0104, 0x0104, 0x0104, 0x0102, 0x0102, 0x0100, 
+       0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F8, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F4, 
+       0x00F2, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E6, 
+       0x00E5, 0x00E3, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00E0, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DB, 0x00DA, 0x00D9, 0x00D9, 0x00D7, 
+       0x00D7, 0x00D6, 0x00D4, 0x00D4, 0x00D3, 0x00D2, 0x00D2, 0x00D0, 0x00CF, 0x00CF, 0x00CE, 0x00CC, 0x00CC, 0x00CB, 0x00CA, 0x00CA, 
+       0x00C9, 0x00C7, 0x00C7, 0x00C6, 0x00C5, 0x00C5, 0x00C4, 0x00C3, 0x00C1, 0x00C1, 0x00C0, 0x00BF, 0x00BF, 0x00BE, 0x00BD, 0x00BC, 
+       0x0111, 0x0111, 0x0111, 0x0111, 0x0111, 0x0111, 0x0111, 0x0111, 0x0111, 0x0111, 0x0111, 0x0111, 0x0111, 0x0111, 0x0111, 0x010E, 
+       0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010C, 0x010C, 0x010C, 0x010C, 0x010C, 0x010A, 0x010A, 0x010A, 0x010A, 0x0108, 
+       0x0108, 0x0108, 0x0108, 0x0106, 0x0106, 0x0106, 0x0106, 0x0104, 0x0104, 0x0104, 0x0102, 0x0102, 0x0102, 0x0100, 0x0100, 0x0100, 
+       0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F8, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F2, 
+       0x00F0, 0x00F0, 0x00EF, 0x00EF, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E5, 
+       0x00E3, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D9, 0x00D7, 0x00D6, 
+       0x00D6, 0x00D4, 0x00D4, 0x00D3, 0x00D2, 0x00D2, 0x00D0, 0x00CF, 0x00CF, 0x00CE, 0x00CC, 0x00CC, 0x00CB, 0x00CA, 0x00CA, 0x00C9, 
+       0x00C7, 0x00C7, 0x00C6, 0x00C5, 0x00C5, 0x00C4, 0x00C3, 0x00C1, 0x00C1, 0x00C0, 0x00BF, 0x00BF, 0x00BE, 0x00BD, 0x00BC, 0x00BC, 
+       0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 
+       0x010C, 0x010C, 0x010C, 0x010C, 0x010C, 0x010C, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 
+       0x0106, 0x0106, 0x0106, 0x0104, 0x0104, 0x0104, 0x0104, 0x0102, 0x0102, 0x0102, 0x0100, 0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FE, 
+       0x00FC, 0x00FC, 0x00FC, 0x00FA, 0x00FA, 0x00F8, 0x00F8, 0x00F8, 0x00F6, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00F0, 
+       0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E3, 0x00E3, 
+       0x00E1, 0x00E1, 0x00E0, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DB, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D6, 
+       0x00D4, 0x00D3, 0x00D3, 0x00D2, 0x00D0, 0x00D0, 0x00CF, 0x00CF, 0x00CE, 0x00CC, 0x00CC, 0x00CB, 0x00CA, 0x00CA, 0x00C9, 0x00C7, 
+       0x00C7, 0x00C6, 0x00C5, 0x00C5, 0x00C4, 0x00C3, 0x00C1, 0x00C1, 0x00C0, 0x00BF, 0x00BF, 0x00BE, 0x00BD, 0x00BC, 0x00BC, 0x00BB, 
+       0x010C, 0x010C, 0x010C, 0x010C, 0x010C, 0x010C, 0x010C, 0x010C, 0x010C, 0x010C, 0x010C, 0x010C, 0x010C, 0x010C, 0x010C, 0x010C, 
+       0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0106, 0x0106, 0x0106, 0x0106, 0x0106, 
+       0x0104, 0x0104, 0x0104, 0x0104, 0x0102, 0x0102, 0x0102, 0x0100, 0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FC, 
+       0x00FA, 0x00FA, 0x00FA, 0x00F8, 0x00F8, 0x00F6, 0x00F6, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00F0, 0x00F0, 0x00EF, 
+       0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 
+       0x00E1, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DB, 0x00DA, 0x00D9, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D4, 0x00D4, 
+       0x00D3, 0x00D3, 0x00D2, 0x00D0, 0x00D0, 0x00CF, 0x00CE, 0x00CE, 0x00CC, 0x00CB, 0x00CB, 0x00CA, 0x00CA, 0x00C9, 0x00C7, 0x00C7, 
+       0x00C6, 0x00C5, 0x00C4, 0x00C4, 0x00C3, 0x00C1, 0x00C1, 0x00C0, 0x00BF, 0x00BF, 0x00BE, 0x00BD, 0x00BD, 0x00BC, 0x00BB, 0x00BA, 
+       0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 
+       0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0106, 0x0106, 0x0106, 0x0106, 0x0106, 0x0104, 0x0104, 0x0104, 0x0104, 
+       0x0102, 0x0102, 0x0102, 0x0102, 0x0100, 0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FC, 0x00FA, 0x00FA, 0x00FA, 
+       0x00F8, 0x00F8, 0x00F8, 0x00F6, 0x00F6, 0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00F0, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 
+       0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 
+       0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D9, 0x00D7, 0x00D6, 0x00D6, 0x00D4, 0x00D4, 0x00D3, 
+       0x00D2, 0x00D2, 0x00D0, 0x00D0, 0x00CF, 0x00CE, 0x00CE, 0x00CC, 0x00CB, 0x00CB, 0x00CA, 0x00C9, 0x00C9, 0x00C7, 0x00C6, 0x00C6, 
+       0x00C5, 0x00C4, 0x00C4, 0x00C3, 0x00C1, 0x00C1, 0x00C0, 0x00BF, 0x00BF, 0x00BE, 0x00BD, 0x00BD, 0x00BC, 0x00BB, 0x00BA, 0x00BA, 
+       0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 
+       0x0106, 0x0106, 0x0106, 0x0106, 0x0106, 0x0106, 0x0106, 0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 0x0102, 0x0102, 0x0102, 0x0102, 
+       0x0100, 0x0100, 0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FC, 0x00FC, 0x00FA, 0x00FA, 0x00FA, 0x00F8, 0x00F8, 
+       0x00F6, 0x00F6, 0x00F6, 0x00F4, 0x00F4, 0x00F4, 0x00F2, 0x00F2, 0x00F0, 0x00F0, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 
+       0x00EB, 0x00EA, 0x00EA, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00DE, 
+       0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D6, 0x00D4, 0x00D3, 0x00D3, 0x00D2, 
+       0x00D2, 0x00D0, 0x00CF, 0x00CF, 0x00CE, 0x00CE, 0x00CC, 0x00CB, 0x00CB, 0x00CA, 0x00C9, 0x00C9, 0x00C7, 0x00C6, 0x00C6, 0x00C5, 
+       0x00C4, 0x00C4, 0x00C3, 0x00C1, 0x00C1, 0x00C0, 0x00BF, 0x00BF, 0x00BE, 0x00BD, 0x00BD, 0x00BC, 0x00BB, 0x00BA, 0x00BA, 0x00B9, 
+       0x0106, 0x0106, 0x0106, 0x0106, 0x0106, 0x0106, 0x0106, 0x0106, 0x0106, 0x0106, 0x0106, 0x0106, 0x0106, 0x0106, 0x0106, 0x0106, 
+       0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0100, 0x0100, 0x0100, 0x0100, 
+       0x00FE, 0x00FE, 0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FC, 0x00FC, 0x00FA, 0x00FA, 0x00FA, 0x00F8, 0x00F8, 0x00F8, 0x00F6, 0x00F6, 
+       0x00F6, 0x00F4, 0x00F4, 0x00F2, 0x00F2, 0x00F2, 0x00F0, 0x00F0, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 
+       0x00EA, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00E0, 0x00DE, 0x00DE, 
+       0x00DD, 0x00DD, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D4, 0x00D4, 0x00D3, 0x00D3, 0x00D2, 0x00D0, 
+       0x00D0, 0x00CF, 0x00CF, 0x00CE, 0x00CC, 0x00CC, 0x00CB, 0x00CB, 0x00CA, 0x00C9, 0x00C9, 0x00C7, 0x00C6, 0x00C6, 0x00C5, 0x00C4, 
+       0x00C4, 0x00C3, 0x00C1, 0x00C1, 0x00C0, 0x00BF, 0x00BF, 0x00BE, 0x00BD, 0x00BD, 0x00BC, 0x00BB, 0x00BA, 0x00BA, 0x00B9, 0x00B8, 
+       0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 0x0104, 
+       0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FE, 0x00FE, 
+       0x00FC, 0x00FC, 0x00FC, 0x00FC, 0x00FA, 0x00FA, 0x00FA, 0x00FA, 0x00F8, 0x00F8, 0x00F8, 0x00F6, 0x00F6, 0x00F6, 0x00F4, 0x00F4, 
+       0x00F4, 0x00F2, 0x00F2, 0x00F2, 0x00F0, 0x00F0, 0x00EF, 0x00EF, 0x00EF, 0x00ED, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00EA, 0x00EA, 
+       0x00E8, 0x00E8, 0x00E6, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DD, 
+       0x00DB, 0x00DB, 0x00DA, 0x00DA, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D6, 0x00D4, 0x00D4, 0x00D3, 0x00D2, 0x00D2, 0x00D0, 0x00D0, 
+       0x00CF, 0x00CE, 0x00CE, 0x00CC, 0x00CC, 0x00CB, 0x00CA, 0x00CA, 0x00C9, 0x00C7, 0x00C7, 0x00C6, 0x00C6, 0x00C5, 0x00C4, 0x00C4, 
+       0x00C3, 0x00C1, 0x00C1, 0x00C0, 0x00BF, 0x00BF, 0x00BE, 0x00BD, 0x00BC, 0x00BC, 0x00BB, 0x00BA, 0x00BA, 0x00B9, 0x00B8, 0x00B8, 
+       0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 
+       0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x00FE, 0x00FE, 0x00FE, 0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FC, 0x00FC, 
+       0x00FC, 0x00FA, 0x00FA, 0x00FA, 0x00F8, 0x00F8, 0x00F8, 0x00F8, 0x00F6, 0x00F6, 0x00F6, 0x00F4, 0x00F4, 0x00F4, 0x00F2, 0x00F2, 
+       0x00F2, 0x00F0, 0x00F0, 0x00F0, 0x00EF, 0x00EF, 0x00ED, 0x00ED, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00EA, 0x00EA, 0x00E8, 0x00E8, 
+       0x00E6, 0x00E6, 0x00E5, 0x00E5, 0x00E3, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00E0, 0x00E0, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DB, 
+       0x00DA, 0x00DA, 0x00D9, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D6, 0x00D4, 0x00D3, 0x00D3, 0x00D2, 0x00D2, 0x00D0, 0x00CF, 0x00CF, 
+       0x00CE, 0x00CE, 0x00CC, 0x00CB, 0x00CB, 0x00CA, 0x00CA, 0x00C9, 0x00C7, 0x00C7, 0x00C6, 0x00C5, 0x00C5, 0x00C4, 0x00C3, 0x00C3, 
+       0x00C1, 0x00C0, 0x00C0, 0x00BF, 0x00BE, 0x00BE, 0x00BD, 0x00BC, 0x00BC, 0x00BB, 0x00BA, 0x00BA, 0x00B9, 0x00B8, 0x00B8, 0x00B7, 
+       0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 
+       0x00FE, 0x00FE, 0x00FE, 0x00FE, 0x00FE, 0x00FE, 0x00FE, 0x00FC, 0x00FC, 0x00FC, 0x00FC, 0x00FC, 0x00FA, 0x00FA, 0x00FA, 0x00FA, 
+       0x00FA, 0x00F8, 0x00F8, 0x00F8, 0x00F8, 0x00F6, 0x00F6, 0x00F6, 0x00F4, 0x00F4, 0x00F4, 0x00F2, 0x00F2, 0x00F2, 0x00F0, 0x00F0, 
+       0x00F0, 0x00EF, 0x00EF, 0x00EF, 0x00ED, 0x00ED, 0x00ED, 0x00EB, 0x00EB, 0x00EA, 0x00EA, 0x00EA, 0x00E8, 0x00E8, 0x00E6, 0x00E6, 
+       0x00E5, 0x00E5, 0x00E3, 0x00E3, 0x00E3, 0x00E1, 0x00E1, 0x00E0, 0x00E0, 0x00DE, 0x00DE, 0x00DD, 0x00DD, 0x00DB, 0x00DB, 0x00DA, 
+       0x00DA, 0x00D9, 0x00D7, 0x00D7, 0x00D6, 0x00D6, 0x00D4, 0x00D4, 0x00D3, 0x00D3, 0x00D2, 0x00D0, 0x00D0, 0x00CF, 0x00CF, 0x00CE, 
+       0x00CC, 0x00CC, 0x00CB, 0x00CB, 0x00CA, 0x00C9, 0x00C9, 0x00C7, 0x00C7, 0x00C6, 0x00C5, 0x00C5, 0x00C4, 0x00C3, 0x00C3, 0x00C1, 
+       0x00C0, 0x00C0, 0x00BF, 0x00BE, 0x00BE, 0x00BD, 0x00BC, 0x00BC, 0x00BB, 0x00BA, 0x00BA, 0x00B9, 0x00B8, 0x00B8, 0x00B7, 0x00B6
+};
+#define kDeltaUsedToBuildTable 32
diff --git a/libs/graphics/effects/SkGradientShader.cpp b/libs/graphics/effects/SkGradientShader.cpp
new file mode 100644 (file)
index 0000000..ed4dacc
--- /dev/null
@@ -0,0 +1,1025 @@
+#include "SkGradientShader.h"
+#include "SkColorPriv.h"
+#include "SkUnitMapper.h"
+#include "SkUtils.h"
+
+/*
+       ToDo
+
+       - not sure we still need the full Rec struct, now that we're using a cache
+       - detect const-alpha (but not opaque) in getFlags()
+*/
+
+/* dither seems to look better, but not stuningly yet, and it slows us down a little
+       so its not on by default yet.
+*/
+#define TEST_GRADIENT_DITHER
+
+///////////////////////////////////////////////////////////////////////////
+
+typedef SkFixed (*TileProc)(SkFixed);
+
+static SkFixed clamp_tileproc(SkFixed x)
+{
+       return SkClampMax(x, 0xFFFF);
+}
+
+static SkFixed repeat_tileproc(SkFixed x)
+{
+       return x & 0xFFFF;
+}
+
+static inline SkFixed mirror_tileproc(SkFixed x)
+{
+       int s = x << 15 >> 31;
+       return (x ^ s) & 0xFFFF;
+}
+
+static const TileProc gTileProcs[] = {
+       clamp_tileproc,
+       repeat_tileproc,
+       mirror_tileproc
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static inline int repeat_6bits(int x)
+{
+       return x & 63;
+}
+
+static inline int mirror_6bits(int x)
+{
+#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
+       if (x & 64)
+               x = ~x;
+       return x & 63;
+#else
+       int s = x << 25 >> 31;
+       return (x ^ s) & 63;
+#endif
+}
+
+static inline int repeat_8bits(int x)
+{
+       return x & 0xFF;
+}
+
+static inline int mirror_8bits(int x)
+{
+#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
+       if (x & 256)
+               x = ~x;
+       return x & 255;
+#else
+       int s = x << 23 >> 31;
+       return (x ^ s) & 0xFF;
+#endif
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+class Gradient_Shader : public SkShader {
+public:
+       Gradient_Shader(const SkColor colors[], const SkScalar pos[],
+                                       int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper);
+       virtual ~Gradient_Shader();
+
+       // overrides
+       virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&);
+       virtual U32  getFlags() { return fFlags; }
+
+protected:
+       SkUnitMapper* fMapper;
+       SkMatrix        fPtsToUnit;             // set by subclass
+       SkMatrix        fDstToIndex;
+       SkMatrix::MapPtProc     fDstToIndexProc;
+       SkPMColor*      fARGB32;
+       TileProc        fTileProc;
+       uint16_t        fColorCount;
+       uint8_t         fDstToIndexClass;
+       uint8_t         fFlags;
+
+       struct Rec {
+               SkFixed     fPos;       // 0...1
+               uint32_t        fScale; // (1 << 24) / range
+       };
+       Rec*            fRecs;
+
+       enum {
+               kCache16Bits    = 6,    // seems like enough for visual accuracy
+               kCache16Count   = 1 << kCache16Bits,
+               kCache32Bits    = 8,    // pretty much should always be 8
+               kCache32Count   = 1 << kCache32Bits
+       };
+       const uint16_t*         getCache16();
+       const SkPMColor*        getCache32();
+
+private:
+       enum {
+               kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
+
+               kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec))
+       };
+       SkColor         fStorage[(kStorageSize + 3) >> 2];
+       SkColor*        fOrigColors;
+
+       uint16_t*       fCache16;       // working ptr. If this is nil, we need to recompute the cache values
+       SkPMColor*      fCache32;       // working ptr. If this is nil, we need to recompute the cache values
+
+       uint16_t*       fCache16Storage;        // storage for fCache16, allocated on demand
+       SkPMColor*      fCache32Storage;        // storage for fCache32, allocated on demand
+       unsigned        fCacheAlpha;            // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value
+
+       typedef SkShader INHERITED;
+};
+
+static inline unsigned scalarToU16(SkScalar x)
+{
+       SkASSERT(x >= 0 && x <= SK_Scalar1);
+
+#ifdef SK_SCALAR_IS_FLOAT
+       return (unsigned)(x * 0xFFFF);
+#else
+       return x - (x >> 16);   // probably should be x - (x > 0x7FFF) but that is slower
+#endif
+}
+
+Gradient_Shader::Gradient_Shader(const SkColor colors[], const SkScalar pos[], int colorCount,
+                                                                SkShader::TileMode mode, SkUnitMapper* mapper)
+{
+       SkASSERT(colorCount > 1);
+
+    fCacheAlpha = 256;  // init to a value that paint.getAlpha() can't return
+
+       fMapper = mapper;
+       mapper->safeRef();
+
+       fCache16 = fCache16Storage = nil;
+       fCache32 = fCache32Storage = nil;
+
+       fColorCount = SkToU16(colorCount);
+       if (colorCount > kColorStorageCount)
+               fOrigColors = (SkColor*)sk_malloc_throw((sizeof(SkColor) + sizeof(SkPMColor) + sizeof(Rec)) * colorCount);
+       else
+               fOrigColors = fStorage;
+       memcpy(fOrigColors, colors, colorCount * sizeof(SkColor));
+       // our premul colors point to the 2nd half of the array
+       // these are assigned each time in setContext
+       fARGB32 = fOrigColors + colorCount;
+
+       SkASSERT((unsigned)mode < SkShader::kTileModeCount);
+       SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs));
+       fTileProc = gTileProcs[mode];
+
+       fRecs = (Rec*)(fARGB32 + colorCount);
+       if (colorCount > 2)
+       {
+               Rec* recs = fRecs;
+
+               recs[0].fPos = 0;
+       //      recs[0].fScale = 0;     // unused;
+               if (pos)
+               {
+                       for (int i = 1; i < colorCount; i++)
+                       {
+                               SkASSERT(pos[i] > pos[i-1] && pos[i] <= SK_Scalar1);
+                               recs[i].fPos    = SkScalarToFixed(pos[i]);
+                               recs[i].fScale  = (1 << 24) / SkScalarToFixed(pos[i] - pos[i-1]);
+                       }
+               }
+               else    // assume even distribution
+               {
+                       SkFixed dp = SK_Fixed1 / (colorCount - 1);
+                       SkFixed p = dp;
+                       SkFixed scale = (colorCount - 1) << 8;  // (1 << 24) / dp
+                       for (int i = 1; i < colorCount; i++)
+                       {
+                               recs[i].fPos    = p;
+                               recs[i].fScale  = scale;
+                               p += dp;
+                       }
+               }
+       }
+}
+
+Gradient_Shader::~Gradient_Shader()
+{
+       if (fCache16Storage)
+               sk_free(fCache16Storage);
+       if (fCache32Storage)
+               sk_free(fCache32Storage);
+       if (fOrigColors != fStorage)
+               sk_free(fOrigColors);
+       fMapper->safeUnref();
+}
+
+bool Gradient_Shader::setContext(const SkBitmap& device,
+                                                                const SkPaint& paint,
+                                                                const SkMatrix& matrix)
+{
+       if (!this->INHERITED::setContext(device, paint, matrix))
+               return false;
+
+       const SkMatrix& inverse = this->getTotalInverse();
+
+       if (!fDstToIndex.setConcat(fPtsToUnit, inverse))
+               return false;
+
+       fDstToIndexProc = fDstToIndex.getMapPtProc();
+       fDstToIndexClass = (U8)SkShader::ComputeMatrixClass(fDstToIndex);
+
+       // now convert our colors in to PMColors
+       int pa = paint.getAlpha();
+       int     scale = SkAlpha255To256(pa);
+       int prevAlpha = -1;
+
+       for (unsigned i = 0; i < fColorCount; i++)
+       {
+               U32     src = fOrigColors[i];
+               int sa = SkAlphaMul(SkColorGetA(src), scale);
+               int localScale = SkAlpha255To256(sa);
+               pa &= sa;
+
+               if (i == 0)
+                       prevAlpha = sa;
+               else
+               {
+                       if (prevAlpha != sa)
+                               prevAlpha = -1;
+               }
+
+               fARGB32[i] = SkPackARGB32(      sa,
+                                                                       SkAlphaMul(SkColorGetR(src), localScale),
+                                                                       SkAlphaMul(SkColorGetG(src), localScale),
+                                                                       SkAlphaMul(SkColorGetB(src), localScale));
+       }
+
+       if (pa == 0xFF)
+       {
+               SkASSERT(prevAlpha >= 0);
+               fFlags = kOpaqueAlpha_Flag;
+       }
+       else if (prevAlpha >= 0)
+               fFlags = kConstAlpha_Flag;
+       else
+               fFlags = 0;
+
+       // if the new alpha differs from the previous time we were called, inval our cache
+       // this will trigger the cache to be rebuilt.
+       // we don't care about the first time, since the cache ptrs will already be nil
+       if (fCacheAlpha != paint.getAlpha())
+       {
+               fCache16 = nil;                                 // inval the cache
+               fCache32 = nil;                                 // inval the cache
+               fCacheAlpha = paint.getAlpha(); // record the new alpha
+       }
+       return true;
+}
+
+static inline int blend8(int a, int b, int scale)
+{
+       SkASSERT(a == SkToU8(a));
+       SkASSERT(b == SkToU8(b));
+       SkASSERT(scale >= 0 && scale <= 256);
+
+       return a + ((b - a) * scale >> 8);
+}
+
+static inline U32 dot8_blend_packed32(U32 s0, U32 s1, int blend)
+{
+#if 0
+       int     a = blend8(SkGetPackedA32(s0), SkGetPackedA32(s1), blend);
+       int     r = blend8(SkGetPackedR32(s0), SkGetPackedR32(s1), blend);
+       int     g = blend8(SkGetPackedG32(s0), SkGetPackedG32(s1), blend);
+       int     b = blend8(SkGetPackedB32(s0), SkGetPackedB32(s1), blend);
+
+       return SkPackARGB32(a, r, g, b);
+#else
+       int otherBlend = 256 - blend;
+
+#if 0
+       U32     t0 = (((s0 & 0xFF00FF) * blend + (s1 & 0xFF00FF) * otherBlend) >> 8) & 0xFF00FF;
+       U32     t1 = (((s0 >> 8) & 0xFF00FF) * blend + ((s1 >> 8) & 0xFF00FF) * otherBlend) & 0xFF00FF00;
+       SkASSERT((t0 & t1) == 0);
+       return t0 | t1;
+#else
+       return  ((((s0 & 0xFF00FF) * blend + (s1 & 0xFF00FF) * otherBlend) >> 8) & 0xFF00FF) |
+                       ((((s0 >> 8) & 0xFF00FF) * blend + ((s1 >> 8) & 0xFF00FF) * otherBlend) & 0xFF00FF00);
+#endif
+
+#endif
+}
+
+#define Fixed_To_Dot8(x)               (((x) + 0x80) >> 8)
+
+static void build_16bit_cache(U16 cache[], SkPMColor c0, SkPMColor c1, int count)
+{
+       SkASSERT(count > 1);
+
+       SkFixed r = SkGetPackedR32(c0);
+       SkFixed g = SkGetPackedG32(c0);
+       SkFixed b = SkGetPackedB32(c0);
+
+       SkFixed dr = SkIntToFixed(SkGetPackedR32(c1) - r) / (count - 1);
+       SkFixed dg = SkIntToFixed(SkGetPackedG32(c1) - g) / (count - 1);
+       SkFixed db = SkIntToFixed(SkGetPackedB32(c1) - b) / (count - 1);
+
+       r = SkIntToFixed(r) + 0x8000;
+       g = SkIntToFixed(g) + 0x8000;
+       b = SkIntToFixed(b) + 0x8000;
+
+       do {
+        unsigned rr = r >> 16;
+        unsigned gg = g >> 16;
+        unsigned bb = b >> 16;
+               cache[0] = SkPackRGB16(SkR32ToR16(rr), SkG32ToG16(gg), SkB32ToB16(bb));
+        cache[64] = SkDitherPack888ToRGB16(rr, gg, bb);
+               cache += 1;
+               r += dr;
+               g += dg;
+               b += db;
+       } while (--count != 0);
+}
+
+static void build_32bit_cache(SkPMColor cache[], SkPMColor c0, SkPMColor c1, int count)
+{
+       SkASSERT(count > 1);
+
+       SkFixed a = SkGetPackedA32(c0);
+       SkFixed r = SkGetPackedR32(c0);
+       SkFixed g = SkGetPackedG32(c0);
+       SkFixed b = SkGetPackedB32(c0);
+
+       SkFixed da = SkIntToFixed(SkGetPackedA32(c1) - a) / (count - 1);
+       SkFixed dr = SkIntToFixed(SkGetPackedR32(c1) - r) / (count - 1);
+       SkFixed dg = SkIntToFixed(SkGetPackedG32(c1) - g) / (count - 1);
+       SkFixed db = SkIntToFixed(SkGetPackedB32(c1) - b) / (count - 1);
+
+       a = SkIntToFixed(a) + 0x8000;
+       r = SkIntToFixed(r) + 0x8000;
+       g = SkIntToFixed(g) + 0x8000;
+       b = SkIntToFixed(b) + 0x8000;
+
+       do {
+               *cache++ = SkPackARGB32(a >> 16, r >> 16, g >> 16, b >> 16);
+               a += da;
+               r += dr;
+               g += dg;
+               b += db;
+       } while (--count != 0);
+}
+
+static inline int SkFixedToFFFF(SkFixed x)
+{
+       SkASSERT((unsigned)x <= SK_Fixed1);
+       return x - (x >> 16);
+}
+
+static inline U16CPU dot6to16(unsigned x)
+{
+       SkASSERT(x < 64);
+       return (x << 10) | (x << 4) | (x >> 2);
+}
+
+const U16* Gradient_Shader::getCache16()
+{
+       if (fCache16 == nil)
+       {
+               if (fCache16Storage == nil)     // set the storage and our working ptr
+#ifdef TEST_GRADIENT_DITHER
+                       fCache16Storage = (U16*)sk_malloc_throw(sizeof(U16) * kCache16Count * 2);
+#else
+                       fCache16Storage = (U16*)sk_malloc_throw(sizeof(U16) * kCache16Count);
+#endif
+               fCache16 = fCache16Storage;
+               if (fColorCount == 2)
+                       build_16bit_cache(fCache16, fARGB32[0], fARGB32[1], kCache16Count);
+               else
+               {
+                       Rec* rec = fRecs;
+                       int     prevIndex = 0;
+                       for (unsigned i = 1; i < fColorCount; i++)
+                       {
+                               int nextIndex = SkFixedToFFFF(rec[i].fPos) >> (16 - kCache16Bits);
+                               SkASSERT(nextIndex < kCache16Count);
+
+                               if (nextIndex > prevIndex)
+                                       build_16bit_cache(fCache16 + prevIndex, fARGB32[i-1], fARGB32[i], nextIndex - prevIndex + 1);
+                               prevIndex = nextIndex;
+                       }
+                       SkASSERT(prevIndex == kCache16Count - 1);
+               }
+
+               if (fMapper)
+               {
+#ifdef TEST_GRADIENT_DITHER
+                       fCache16Storage = (U16*)sk_malloc_throw(sizeof(U16) * kCache16Count * 2);
+#else
+                       fCache16Storage = (U16*)sk_malloc_throw(sizeof(U16) * kCache16Count);
+#endif
+                       U16* linear = fCache16;                 // just computed linear data
+                       U16* mapped = fCache16Storage;  // storage for mapped data
+                       SkUnitMapper* map = fMapper;
+                       for (int i = 0; i < 64; i++)
+                       {
+                               int index = map->mapUnit16(dot6to16(i)) >> 10;
+                               mapped[i] = linear[index];
+#ifdef TEST_GRADIENT_DITHER
+                               mapped[i + 64] = linear[index + 64];
+#endif
+                       }
+                       sk_free(fCache16);
+                       fCache16 = fCache16Storage;
+               }
+       }
+       return fCache16;
+}
+
+const SkPMColor* Gradient_Shader::getCache32()
+{
+       if (fCache32 == nil)
+       {
+               if (fCache32Storage == nil)     // set the storage and our working ptr
+                       fCache32Storage = (SkPMColor*)sk_malloc_throw(sizeof(SkPMColor) * kCache32Count);
+
+               fCache32 = fCache32Storage;
+               if (fColorCount == 2)
+                       build_32bit_cache(fCache32, fARGB32[0], fARGB32[1], kCache32Count);
+               else
+               {
+                       Rec* rec = fRecs;
+                       int     prevIndex = 0;
+                       for (unsigned i = 1; i < fColorCount; i++)
+                       {
+                               int nextIndex = SkFixedToFFFF(rec[i].fPos) >> (16 - kCache32Bits);
+                               SkASSERT(nextIndex < kCache32Count);
+
+                               if (nextIndex > prevIndex)
+                                       build_32bit_cache(fCache32 + prevIndex, fARGB32[i-1], fARGB32[i], nextIndex - prevIndex + 1);
+                               prevIndex = nextIndex;
+                       }
+                       SkASSERT(prevIndex == kCache32Count - 1);
+               }
+
+               if (fMapper)
+               {
+                       fCache32Storage = (SkPMColor*)sk_malloc_throw(sizeof(SkPMColor) * kCache32Count);
+                       SkPMColor* linear = fCache32;                   // just computed linear data
+                       SkPMColor* mapped = fCache32Storage;    // storage for mapped data
+                       SkUnitMapper* map = fMapper;
+                       for (int i = 0; i < 256; i++)
+                               mapped[i] = linear[map->mapUnit16((i << 8) | i) >> 8];
+                       sk_free(fCache32);
+                       fCache32 = fCache32Storage;
+               }
+       }
+       return fCache32;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix)
+{
+       SkVector        vec = pts[1] - pts[0];
+       SkScalar        mag = vec.length();
+       SkScalar        inv = mag ? SkScalarInvert(mag) : 0;
+
+       vec.scale(inv);
+       matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
+       matrix->postTranslate(-pts[0].fX, -pts[0].fY);
+       matrix->postScale(inv, inv, 0, 0);
+}
+
+class Linear_Gradient : public Gradient_Shader {
+public:
+       Linear_Gradient(const SkPoint pts[2],
+                                       const SkColor colors[], const SkScalar pos[], int colorCount,
+                                       SkShader::TileMode mode, SkUnitMapper* mapper)
+               : Gradient_Shader(colors, pos, colorCount, mode, mapper)
+       {
+               pts_to_unit_matrix(pts, &fPtsToUnit);
+       }
+       virtual U32  getFlags() { return this->INHERITED::getFlags() | kHasSpan16_Flag; }
+       virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count);
+       virtual void shadeSpanOpaque16(int x, int y, U16 dstC[], int count);
+
+private:
+       typedef Gradient_Shader INHERITED;
+};
+
+void Linear_Gradient::shadeSpan(int x, int y, SkPMColor dstC[], int count)
+{
+       SkASSERT(count > 0);
+
+       SkPoint                         srcPt;
+       SkMatrix::MapPtProc     dstProc = fDstToIndexProc;
+       TileProc                        proc = fTileProc;
+       const SkPMColor*        cache = this->getCache32();
+
+       if (fDstToIndexClass != kPerspective_MatrixClass)
+       {
+               dstProc(fDstToIndex, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
+               SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
+
+               if (fDstToIndexClass == kFixedStepInX_MatrixClass)
+               {
+                       SkFixed dxStorage[1];
+                       (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, nil);
+                       dx = dxStorage[0];
+               }
+               else
+               {
+                       SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
+                       dx = SkScalarToFixed(fDstToIndex.getScaleX());
+               }
+
+               if (SkFixedNearlyZero(dx))      // we're a vertical gradient, so no change in a span
+               {
+                       unsigned fi = proc(fx);
+                       SkASSERT(fi <= 0xFFFF);
+                       sk_memset32(dstC, cache[fi >> (16 - kCache32Bits)], count);
+               }
+               else if (proc == clamp_tileproc)
+               {
+                       do {
+                               unsigned fi = SkClampMax(fx >> 8, 0xFF);
+                               SkASSERT(fi <= 0xFF);
+                               fx += dx;
+                               *dstC++ = cache[fi];
+                       } while (--count != 0);
+               }
+               else if (proc == mirror_tileproc)
+               {
+                       do {
+                               unsigned fi = mirror_8bits(fx >> 8);
+                               SkASSERT(fi <= 0xFF);
+                               fx += dx;
+                               *dstC++ = cache[fi];
+                       } while (--count != 0);
+               }
+               else
+               {
+                       SkASSERT(proc == repeat_tileproc);
+                       do {
+                               unsigned fi = repeat_8bits(fx >> 8);
+                               SkASSERT(fi <= 0xFF);
+                               fx += dx;
+                               *dstC++ = cache[fi];
+                       } while (--count != 0);
+               }
+       }
+       else
+       {
+               SkScalar        dstX = SkIntToScalar(x);
+               SkScalar        dstY = SkIntToScalar(y);
+               do {
+                       dstProc(fDstToIndex, dstX, dstY, &srcPt);
+                       unsigned fi = proc(SkScalarToFixed(srcPt.fX));
+                       SkASSERT(fi <= 0xFFFF);
+                       *dstC++ = cache[fi >> (16 - kCache32Bits)];
+                       dstX += SK_Scalar1;
+               } while (--count != 0);
+       }
+}
+
+#ifdef TEST_GRADIENT_DITHER
+static void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other, int count)
+{
+    if ((unsigned)dst & 2)
+    {
+        *dst++ = value;
+        count -= 1;
+        SkTSwap(value, other);
+    }
+
+    sk_memset32((uint32_t*)dst, (value << 16) | other, count >> 1);
+    
+    if (count & 1)
+        dst[count - 1] = value;
+}
+#endif
+
+void Linear_Gradient::shadeSpanOpaque16(int x, int y, U16 dstC[], int count)
+{
+       SkASSERT(count > 0);
+       SkASSERT(this->getPaintAlpha() == 0xFF);
+
+       SkPoint                         srcPt;
+       SkMatrix::MapPtProc     dstProc = fDstToIndexProc;
+       TileProc                        proc = fTileProc;
+       const U16*                      cache = this->getCache16();
+#ifdef TEST_GRADIENT_DITHER
+       int                                     toggle = ((x ^ y) & 1) << kCache16Bits;
+#endif
+
+       if (fDstToIndexClass != kPerspective_MatrixClass)
+       {
+               dstProc(fDstToIndex, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
+               SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
+
+               if (fDstToIndexClass == kFixedStepInX_MatrixClass)
+               {
+                       SkFixed dxStorage[1];
+                       (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, nil);
+                       dx = dxStorage[0];
+               }
+               else
+               {
+                       SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
+                       dx = SkScalarToFixed(fDstToIndex.getScaleX());
+               }
+
+               if (SkFixedNearlyZero(dx))      // we're a vertical gradient, so no change in a span
+               {
+                       unsigned fi = proc(fx) >> 10;
+                       SkASSERT(fi <= 63);
+#ifdef TEST_GRADIENT_DITHER
+            dither_memset16(dstC, cache[toggle + fi], cache[(toggle ^ (1 << kCache16Bits)) + fi], count);
+#else
+                       sk_memset16(dstC, cache[fi], count);
+#endif
+               }
+               else if (proc == clamp_tileproc)
+               {
+                       do {
+                               unsigned fi = SkClampMax(fx >> 10, 63);
+                               SkASSERT(fi <= 63);
+                               fx += dx;
+#ifdef TEST_GRADIENT_DITHER
+                               *dstC++ = cache[toggle + fi];
+                               toggle ^= (1 << kCache16Bits);
+#else
+                               *dstC++ = cache[fi];
+#endif
+                       } while (--count != 0);
+               }
+               else if (proc == mirror_tileproc)
+               {
+                       do {
+                               unsigned fi = mirror_6bits(fx >> 10);
+                               SkASSERT(fi <= 0x3F);
+                               fx += dx;
+#ifdef TEST_GRADIENT_DITHER
+                               *dstC++ = cache[toggle + fi];
+                               toggle ^= (1 << kCache16Bits);
+#else
+                               *dstC++ = cache[fi];
+#endif
+                       } while (--count != 0);
+               }
+               else
+               {
+                       SkASSERT(proc == repeat_tileproc);
+                       do {
+                               unsigned fi = repeat_6bits(fx >> 10);
+                               SkASSERT(fi <= 0x3F);
+                               fx += dx;
+#ifdef TEST_GRADIENT_DITHER
+                               *dstC++ = cache[toggle + fi];
+                               toggle ^= (1 << kCache16Bits);
+#else
+                               *dstC++ = cache[fi];
+#endif
+                       } while (--count != 0);
+               }
+       }
+       else
+       {
+               SkScalar        dstX = SkIntToScalar(x);
+               SkScalar        dstY = SkIntToScalar(y);
+               do {
+                       dstProc(fDstToIndex, dstX, dstY, &srcPt);
+                       unsigned fi = proc(SkScalarToFixed(srcPt.fX));
+                       SkASSERT(fi <= 0xFFFF);
+                       *dstC++ = cache[fi >> (16 - kCache16Bits)];
+                       dstX += SK_Scalar1;
+               } while (--count != 0);
+       }
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+
+#define kSQRT_TABLE_BITS       11
+#define kSQRT_TABLE_SIZE       (1 << kSQRT_TABLE_BITS)
+
+#include "SkRadialGradient_Table.h"
+
+#if defined(SK_BUILD_FOR_WIN32) && defined(SK_DEBUG)
+
+#include <stdio.h>
+
+void SkRadialGradient_BuildTable()
+{
+       // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fixed" table
+
+       FILE* file = ::fopen("SkRadialGradient_Table.h", "w");
+       SkASSERT(file);
+       ::fprintf(file, "static const U8 gSqrt8Table[] = {\n");
+
+       for (int i = 0; i < kSQRT_TABLE_SIZE; i++)
+       {
+               if ((i & 15) == 0)
+                       ::fprintf(file, "\t");
+
+               U8 value = SkToU8(SkFixedSqrt(i * SK_Fixed1 / kSQRT_TABLE_SIZE) >> 8);
+
+               ::fprintf(file, "0x%02X", value);
+               if (i < kSQRT_TABLE_SIZE-1)
+                       ::fprintf(file, ", ");
+               if ((i & 15) == 15)
+                       ::fprintf(file, "\n");
+       }
+       ::fprintf(file, "};\n");
+       ::fclose(file);
+}
+
+#endif
+
+
+static void rad_to_unit_matrix(const SkPoint& center, SkScalar radius, SkMatrix* matrix)
+{
+       SkScalar        inv = SkScalarInvert(radius);
+
+       matrix->setTranslate(-center.fX, -center.fY);
+       matrix->postScale(inv, inv, 0, 0);
+}
+
+class Radial_Gradient : public Gradient_Shader {
+public:
+       Radial_Gradient(const SkPoint& center, SkScalar radius,
+                                       const SkColor colors[], const SkScalar pos[], int colorCount,
+                                       SkShader::TileMode mode, SkUnitMapper* mapper)
+               : Gradient_Shader(colors, pos, colorCount, mode, mapper)
+       {
+               // make sure our table is insync with our current #define for kSQRT_TABLE_SIZE
+               SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE);
+
+               rad_to_unit_matrix(center, radius, &fPtsToUnit);
+       }
+       virtual U32  getFlags() { return this->INHERITED::getFlags() | kHasSpan16_Flag; }
+       virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count)
+       {
+               SkASSERT(count > 0);
+
+               SkPoint                         srcPt;
+               SkMatrix::MapPtProc     dstProc = fDstToIndexProc;
+               TileProc                        proc = fTileProc;
+               const SkPMColor*        cache = this->getCache32();
+
+               if (fDstToIndexClass != kPerspective_MatrixClass)
+               {
+                       dstProc(fDstToIndex, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
+                       SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
+                       SkFixed dy, fy = SkScalarToFixed(srcPt.fY);
+
+                       if (fDstToIndexClass == kFixedStepInX_MatrixClass)
+                       {
+                               SkFixed storage[2];
+                               (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &storage[0], &storage[1]);
+                               dx = storage[0];
+                               dy = storage[1];
+                       }
+                       else
+                       {
+                               SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
+                               dx = SkScalarToFixed(fDstToIndex.getScaleX());
+                               dy = SkScalarToFixed(fDstToIndex.getSkewY());
+                       }
+
+                       if (proc == clamp_tileproc)
+                       {
+                               const U8* sqrt_table = gSqrt8Table;
+                               fx >>= 1;
+                               dx >>= 1;
+                               fy >>= 1;
+                               dy >>= 1;
+                               do {
+                                       unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
+                                       unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
+                                       fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
+                                       fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
+                                       *dstC++ = cache[sqrt_table[fi] >> (8 - kCache32Bits)];
+                                       fx += dx;
+                                       fy += dy;
+                               } while (--count != 0);
+                       }
+                       else if (proc == mirror_tileproc)
+                       {
+                               do {
+                                       SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
+                                       unsigned fi = mirror_tileproc(dist);
+                                       SkASSERT(fi <= 0xFFFF);
+                                       *dstC++ = cache[fi >> (16 - kCache32Bits)];
+                                       fx += dx;
+                                       fy += dy;
+                               } while (--count != 0);
+                       }
+                       else
+                       {
+                               SkASSERT(proc == repeat_tileproc);
+                               do {
+                                       SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
+                                       unsigned fi = repeat_tileproc(dist);
+                                       SkASSERT(fi <= 0xFFFF);
+                                       *dstC++ = cache[fi >> (16 - kCache32Bits)];
+                                       fx += dx;
+                                       fy += dy;
+                               } while (--count != 0);
+                       }
+               }
+               else    // perspective case
+               {
+                       SkScalar dstX = SkIntToScalar(x);
+                       SkScalar dstY = SkIntToScalar(y);
+                       do {
+                               dstProc(fDstToIndex, dstX, dstY, &srcPt);
+                               unsigned fi = proc(SkScalarToFixed(srcPt.length()));
+                               SkASSERT(fi <= 0xFFFF);
+                               *dstC++ = cache[fi >> (16 - kCache32Bits)];
+                               dstX += SK_Scalar1;
+                       } while (--count != 0);
+               }
+       }
+       virtual void shadeSpanOpaque16(int x, int y, U16 dstC[], int count)
+       {
+               SkASSERT(count > 0);
+
+               SkPoint                         srcPt;
+               SkMatrix::MapPtProc     dstProc = fDstToIndexProc;
+               TileProc                        proc = fTileProc;
+               const U16*                      cache = this->getCache16();
+#ifdef TEST_GRADIENT_DITHER
+               int                                     toggle = ((x ^ y) & 1) << kCache16Bits;
+#endif
+
+               if (fDstToIndexClass != kPerspective_MatrixClass)
+               {
+                       dstProc(fDstToIndex, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
+                       SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
+                       SkFixed dy, fy = SkScalarToFixed(srcPt.fY);
+
+                       if (fDstToIndexClass == kFixedStepInX_MatrixClass)
+                       {
+                               SkFixed storage[2];
+                               (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &storage[0], &storage[1]);
+                               dx = storage[0];
+                               dy = storage[1];
+                       }
+                       else
+                       {
+                               SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
+                               dx = SkScalarToFixed(fDstToIndex.getScaleX());
+                               dy = SkScalarToFixed(fDstToIndex.getSkewY());
+                       }
+
+                       if (proc == clamp_tileproc)
+                       {
+                               const U8* sqrt_table = gSqrt8Table;
+
+                               /* knock these down so we can pin against +- 0x7FFF, which is an immediate load,
+                                       rather than 0xFFFF which is slower. This is a compromise, since it reduces our
+                                       precision, but that appears to be visually OK. If we decide this is OK for
+                                       all of our cases, we could (it seems) put this scale-down into fDstToIndex,
+                                       to avoid having to do these extra shifts each time.
+                               */
+                               fx >>= 1;
+                               dx >>= 1;
+                               fy >>= 1;
+                               dy >>= 1;
+                               if (dy == 0)    // might perform this check for the other modes, but the win will be a smaller % of the total
+                               {
+                                       fy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
+                                       fy *= fy;
+                                       do {
+                                               unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
+                                               unsigned fi = (xx * xx + fy) >> (14 + 16 - kSQRT_TABLE_BITS);
+                                               fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
+                                               fx += dx;
+#ifdef TEST_GRADIENT_DITHER
+                                               *dstC++ = cache[toggle + (sqrt_table[fi] >> (8 - kCache16Bits))];
+                                               toggle ^= (1 << kCache16Bits);
+#else
+                                               *dstC++ = cache[sqrt_table[fi] >> (8 - kCache16Bits)];
+#endif
+                                       } while (--count != 0);
+                               }
+                               else
+                               {
+                                       do {
+                                               unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
+                                               unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
+                                               fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
+                                               fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
+                                               fx += dx;
+                                               fy += dy;
+#ifdef TEST_GRADIENT_DITHER
+                                               *dstC++ = cache[toggle + (sqrt_table[fi] >> (8 - kCache16Bits))];
+                                               toggle ^= (1 << kCache16Bits);
+#else
+                                               *dstC++ = cache[sqrt_table[fi] >> (8 - kCache16Bits)];
+#endif
+                                       } while (--count != 0);
+                               }
+                       }
+                       else if (proc == mirror_tileproc)
+                       {
+                               do {
+                                       SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
+                                       unsigned fi = mirror_tileproc(dist);
+                                       SkASSERT(fi <= 0xFFFF);
+                                       fx += dx;
+                                       fy += dy;
+#ifdef TEST_GRADIENT_DITHER
+                                       *dstC++ = cache[toggle + (fi >> (16 - kCache16Bits))];
+                                       toggle ^= (1 << kCache16Bits);
+#else
+                                       *dstC++ = cache[fi >> (16 - kCache16Bits)];
+#endif
+                               } while (--count != 0);
+                       }
+                       else
+                       {
+                               SkASSERT(proc == repeat_tileproc);
+                               do {
+                                       SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
+                                       unsigned fi = repeat_tileproc(dist);
+                                       SkASSERT(fi <= 0xFFFF);
+                                       fx += dx;
+                                       fy += dy;
+#ifdef TEST_GRADIENT_DITHER
+                                       *dstC++ = cache[toggle + (fi >> (16 - kCache16Bits))];
+                                       toggle ^= (1 << kCache16Bits);
+#else
+                                       *dstC++ = cache[fi >> (16 - kCache16Bits)];
+#endif
+                               } while (--count != 0);
+                       }
+               }
+               else    // perspective case
+               {
+                       SkScalar dstX = SkIntToScalar(x);
+                       SkScalar dstY = SkIntToScalar(y);
+                       do {
+                               dstProc(fDstToIndex, dstX, dstY, &srcPt);
+                               unsigned fi = proc(SkScalarToFixed(srcPt.length()));
+                               SkASSERT(fi <= 0xFFFF);
+                               *dstC++ = cache[fi >> (16 - kCache16Bits)];
+                               dstX += SK_Scalar1;
+                       } while (--count != 0);
+               }
+       }
+private:
+       typedef Gradient_Shader INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+
+SkDiscreteMapper::SkDiscreteMapper(unsigned segments)
+{
+       if (segments < 2)
+       {
+               fSegments = 0;
+               fScale = 0;
+       }
+       else
+       {
+               fSegments = segments;
+               fScale = SK_Fract1 / (segments - 1);
+       }
+}
+
+U16CPU SkDiscreteMapper::mapUnit16(U16CPU x)
+{
+       x = x * fSegments >> 16;
+       return x * fScale >> 14;
+}
+
+U16CPU SkFlipCosineMapper::mapUnit16(U16CPU x)
+{
+       x = SkFixedCos(x * (SK_FixedPI >> 2) >> 15);
+       x += x << 15 >> 31;     // map 0x10000 to 0xFFFF
+       x = 0xFFFF - x;
+       return x;
+}
+
+SkShader* SkGradientShader::CreateLinear(      const SkPoint pts[2],
+                                                                                       const SkColor colors[], const SkScalar pos[], int colorCount,
+                                                                                       TileMode mode, SkUnitMapper* mapper)
+{
+       SkASSERT(pts && colors && colorCount >= 2);
+
+       return SkNEW_ARGS(Linear_Gradient, (pts, colors, pos, colorCount, mode, mapper));
+}
+
+SkShader* SkGradientShader::CreateRadial(      const SkPoint& center, SkScalar radius,
+                                                                                       const SkColor colors[], const SkScalar pos[], int colorCount,
+                                                                                       TileMode mode, SkUnitMapper* mapper)
+{
+       SkASSERT(radius > 0 && colors && colorCount >= 2);
+
+       return SkNEW_ARGS(Radial_Gradient, (center, radius, colors, pos, colorCount, mode, mapper));
+}
+
diff --git a/libs/graphics/effects/SkLayerRasterizer.cpp b/libs/graphics/effects/SkLayerRasterizer.cpp
new file mode 100644 (file)
index 0000000..896c4f4
--- /dev/null
@@ -0,0 +1,251 @@
+#include "SkLayerRasterizer.h"
+#include "SkBuffer.h"
+#include "SkDraw.h"
+#include "SkMask.h"
+#include "SkMaskFilter.h"
+#include "SkPaint.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkXfermode.h"
+
+struct SkLayerRasterizer_Rec {
+    SkPaint     fPaint;
+    SkVector    fOffset;
+};
+
+SkLayerRasterizer::SkLayerRasterizer() : fLayers(sizeof(SkLayerRasterizer_Rec))
+{
+}
+
+SkLayerRasterizer::~SkLayerRasterizer()
+{
+    SkDeque::Iter           iter(fLayers);
+    SkLayerRasterizer_Rec*  rec;
+
+    while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL)
+        rec->fPaint.~SkPaint();
+}
+
+void SkLayerRasterizer::addLayer(const SkPaint& paint, SkScalar dx, SkScalar dy)
+{
+    SkLayerRasterizer_Rec* rec = (SkLayerRasterizer_Rec*)fLayers.push_back();
+
+    new (&rec->fPaint) SkPaint(paint);
+    rec->fOffset.set(dx, dy);
+}
+
+static bool compute_bounds(const SkDeque& layers, const SkPath& path, const SkMatrix& matrix,
+                           const SkRect16* clipBounds, SkRect16* bounds)
+{
+    SkDeque::Iter           iter(layers);
+    SkLayerRasterizer_Rec*  rec;
+
+    bounds->set(SK_MaxS16, SK_MaxS16, SK_MinS16, SK_MinS16);
+    
+    while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL)
+    {
+        const SkPaint&  paint = rec->fPaint;
+        SkPath          fillPath, devPath;
+        const SkPath*   p = &path;
+
+        if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style)
+        {
+            paint.getFillPath(path, &fillPath);
+            p = &fillPath;
+        }
+        if (p->isEmpty())
+            continue;
+
+        // apply the matrix and offset
+        {
+            SkMatrix m = matrix;
+            m.preTranslate(rec->fOffset.fX, rec->fOffset.fY);
+            p->transform(m, &devPath);
+        }
+
+        SkMask  mask;
+        if (!SkDraw::DrawToMask(devPath, clipBounds, paint.getMaskFilter(), &matrix,
+                                &mask, SkMask::kJustComputeBounds_CreateMode))
+            return false;
+
+        bounds->join(mask.fBounds);
+    }
+    return true;
+}
+
+bool SkLayerRasterizer::onRasterize(const SkPath& path, const SkMatrix& matrix,
+                                    const SkRect16* clipBounds,
+                                    SkMask* mask, SkMask::CreateMode mode)
+{
+    if (fLayers.empty())
+        return false;
+
+    if (SkMask::kJustRenderImage_CreateMode != mode)
+    {
+        if (!compute_bounds(fLayers, path, matrix, clipBounds, &mask->fBounds))
+            return false;
+    }
+
+    if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode)
+    {
+        mask->fFormat   = SkMask::kA8_Format;
+        mask->fRowBytes = SkToU16(mask->fBounds.width());
+        mask->fImage = SkMask::AllocImage(mask->computeImageSize());
+        memset(mask->fImage, 0, mask->computeImageSize());
+    }
+
+    if (SkMask::kJustComputeBounds_CreateMode != mode)
+    {    
+        SkBitmap device;
+        SkDraw   draw;
+        SkMatrix translatedMatrix;  // this translates us to our local pixels
+        SkMatrix drawMatrix;        // this translates the path by each layer's offset
+        SkRegion rectClip;
+        
+        rectClip.setRect(0, 0, mask->fBounds.width(), mask->fBounds.height());
+
+        translatedMatrix = matrix;
+        translatedMatrix.postTranslate(-SkIntToScalar(mask->fBounds.fLeft),
+                                       -SkIntToScalar(mask->fBounds.fTop));
+
+        device.setConfig(SkBitmap::kA8_Config, mask->fBounds.width(), mask->fBounds.height(), mask->fRowBytes);
+        device.setPixels(mask->fImage);
+
+        draw.fDevice    = &device;
+        draw.fMatrix    = &drawMatrix;
+        draw.fClip      = &rectClip;
+        // we set the matrixproc in the loop, as the matrix changes each time (potentially)
+        draw.fBounder   = NULL;
+        
+        SkDeque::Iter           iter(fLayers);
+        SkLayerRasterizer_Rec*  rec;
+
+        while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL)
+        {
+            drawMatrix = translatedMatrix;
+            drawMatrix.preTranslate(rec->fOffset.fX, rec->fOffset.fY);     
+            draw.fMapPtProc = drawMatrix.getMapPtProc();
+
+            draw.drawPath(path, rec->fPaint);
+        }
+    }
+    return true;
+}
+
+/////////// Routines for flattening /////////////////
+
+static SkFlattenable* load_flattenable(SkRBuffer& buffer)
+{
+    SkFlattenable::Factory fact = (SkFlattenable::Factory)buffer.readPtr();
+    return fact ? fact(buffer) : NULL;
+}
+
+static void write_flattenable(SkFlattenable* obj, SkWBuffer& buffer)
+{
+    if (NULL == obj)
+        buffer.writePtr(NULL);
+    else
+    {
+        SkFlattenable::Factory fact = obj->getFactory();
+        SkASSERT(fact);
+        
+        buffer.writePtr((void*)fact);
+        obj->flatten(buffer);
+    }
+}
+
+static void paint_read(SkPaint* paint, SkRBuffer& buffer)
+{
+    paint->setAntiAliasOn(buffer.readBool());
+    paint->setStyle((SkPaint::Style)buffer.readU8());
+    paint->setAlpha(buffer.readU8());
+    
+    if (paint->getStyle() != SkPaint::kFill_Style)
+    {
+        paint->setStrokeWidth(buffer.readScalar());
+        paint->setStrokeMiter(buffer.readScalar());
+        paint->setStrokeCap((SkPaint::Cap)buffer.readU8());
+        paint->setStrokeJoin((SkPaint::Join)buffer.readU8());
+    }
+
+    buffer.skipToAlign4();
+
+    paint->setMaskFilter((SkMaskFilter*)load_flattenable(buffer));
+    paint->setPathEffect((SkPathEffect*)load_flattenable(buffer));
+    paint->setRasterizer((SkRasterizer*)load_flattenable(buffer));
+    paint->setXfermode((SkXfermode*)load_flattenable(buffer));
+}
+
+static void paint_write(const SkPaint& paint, SkWBuffer& buffer)
+{
+    buffer.writeBool(paint.isAntiAliasOn());
+    buffer.write8(paint.getStyle());
+    buffer.write8(paint.getAlpha());
+    
+    if (paint.getStyle() != SkPaint::kFill_Style)
+    {
+        buffer.writeScalar(paint.getStrokeWidth());
+        buffer.writeScalar(paint.getStrokeMiter());
+        buffer.write8(paint.getStrokeCap());
+        buffer.write8(paint.getStrokeJoin());
+    }
+    
+    buffer.padToAlign4();
+
+    write_flattenable(paint.getMaskFilter(), buffer);
+    write_flattenable(paint.getPathEffect(), buffer);
+    write_flattenable(paint.getRasterizer(), buffer);
+    write_flattenable(paint.getXfermode(), buffer);
+}
+
+SkLayerRasterizer::SkLayerRasterizer(SkRBuffer& buffer)
+    : SkRasterizer(buffer), fLayers(sizeof(SkLayerRasterizer_Rec))
+{
+    int count = buffer.readS32();
+    
+    for (int i = 0; i < count; i++)
+    {
+        SkLayerRasterizer_Rec* rec = (SkLayerRasterizer_Rec*)fLayers.push_back();
+    
+#if 0
+        new (&rec->fPaint) SkPaint(buffer);
+#else
+        new (&rec->fPaint) SkPaint;
+        paint_read(&rec->fPaint, buffer);
+#endif
+        rec->fOffset.fX = buffer.readScalar();
+        rec->fOffset.fY = buffer.readScalar();
+    }
+}
+
+void SkLayerRasterizer::flatten(SkWBuffer& buffer)
+{
+    this->INHERITED::flatten(buffer);
+
+    buffer.write32(fLayers.count());
+
+    SkDeque::Iter                   iter(fLayers);
+    const SkLayerRasterizer_Rec*    rec;
+
+    while ((rec = (const SkLayerRasterizer_Rec*)iter.next()) != NULL)
+    {
+#if 0
+        rec->fPaint.flatten(buffer);
+#else
+        paint_write(rec->fPaint, buffer);
+#endif
+        buffer.writeScalar(rec->fOffset.fX);
+        buffer.writeScalar(rec->fOffset.fY);
+    }
+}
+
+SkFlattenable* SkLayerRasterizer::CreateProc(SkRBuffer& buffer)
+{
+    return SkNEW_ARGS(SkLayerRasterizer, (buffer));
+}
+
+SkFlattenable::Factory SkLayerRasterizer::getFactory()
+{
+    return CreateProc;
+}
+
diff --git a/libs/graphics/effects/SkNinePatch.cpp b/libs/graphics/effects/SkNinePatch.cpp
new file mode 100644 (file)
index 0000000..dfca76c
--- /dev/null
@@ -0,0 +1,177 @@
+#include "SkNinePatch.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+
+#define USE_TRACEx
+
+#ifdef USE_TRACE
+    static bool gTrace;
+#endif
+
+static void* getSubAddr(const SkBitmap& bm, int x, int y)
+{
+    SkASSERT((unsigned)x < bm.width());
+    SkASSERT((unsigned)y < bm.height());
+    
+    switch (bm.getConfig()) {
+    case SkBitmap::kNo_Config:
+    case SkBitmap::kA1_Config:
+        SkASSERT(!"unsupported config for ninepatch");
+        break;
+    case SkBitmap::kA8_Config:
+    case SkBitmap:: kIndex8_Config:
+        break;
+    case SkBitmap::kRGB_565_Config:
+        x <<= 1;
+        break;
+       case SkBitmap::kARGB_8888_Config:
+        x <<= 2;
+        break;
+    default:
+        break;
+    }
+    return (char*)bm.getPixels() + x + y * bm.rowBytes();
+}
+
+static void drawPatch(SkCanvas* canvas, const SkRect16& src, const SkRect& dst,
+                      const SkBitmap& bitmap, const SkPaint& paint)
+{
+#ifdef USE_TRACE
+    if (gTrace) SkDebugf("======== ninepatch src [%d %d %d,%d] dst[%g %g %g,%g]\n",
+        src.fLeft, src.fTop, src.width(), src.height(),
+        SkScalarToFloat(dst.fLeft), SkScalarToFloat(dst.fTop),
+        SkScalarToFloat(dst.width()), SkScalarToFloat(dst.height()));
+#endif
+
+    SkBitmap    tmp;
+    
+    tmp.setConfig(bitmap.getConfig(), src.width(), src.height(), bitmap.rowBytes());
+    tmp.setPixels(getSubAddr(bitmap, src.fLeft, src.fTop));
+
+    SkMatrix    matrix;
+    SkRect      tmpSrc;
+    tmpSrc.set(0, 0, SkIntToScalar(tmp.width()), SkIntToScalar(tmp.height()));
+    matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
+
+    canvas->save();
+//    canvas->clipRect(dst);    try not to use, as it will suck visually if we're rotated (and make us way-slow)
+    canvas->concat(matrix);
+    canvas->drawBitmap(tmp, 0, 0, paint);
+    canvas->restore();
+}
+
+static bool pixel_is_transparent(const SkBitmap& bm, int x, int y)
+{
+    switch (bm.getConfig()) {
+    case SkBitmap::kARGB_8888_Config:
+        return 0 == *bm.getAddr32(x, y);
+    default:
+        return false;
+    }
+}
+
+static void drawColumn(SkCanvas* canvas, SkRect16* src, SkRect* dst,
+                       const SkRect& bounds, const SkRect16& mar,
+                       const SkBitmap& bitmap, const SkPaint& paint)
+{
+// upper row
+    src->fTop = 0;
+    src->fBottom = mar.fTop;
+    dst->fTop = bounds.fTop;
+    dst->fBottom = bounds.fTop + SkIntToScalar(mar.fTop);
+    drawPatch(canvas, *src, *dst, bitmap, paint);  
+// mid row
+    src->fTop = src->fBottom;
+    src->fBottom = bitmap.height() - mar.fBottom;
+    dst->fTop = dst->fBottom;
+    dst->fBottom = bounds.fBottom - SkIntToScalar(mar.fBottom);
+    if (src->width() != 1 || src->height() != 1 ||
+        !pixel_is_transparent(bitmap, src->fLeft, src->fTop))
+    {
+        drawPatch(canvas, *src, *dst, bitmap, paint);
+    }
+    else
+    {
+    //    SkDEBUGF(("========= Skip transparent center of ninepatch\n"));
+    }
+// lower row
+    src->fTop = src->fBottom;
+    src->fBottom = bitmap.height();
+    dst->fTop = dst->fBottom;
+    dst->fBottom = bounds.fBottom;
+    drawPatch(canvas, *src, *dst, bitmap, paint);  
+}
+
+void SkNinePatch::Draw(SkCanvas* canvas, const SkRect& bounds,
+                     const SkBitmap& bitmap, const SkRect16& margin,
+                     const SkPaint* paint)
+{
+#ifdef USE_TRACE
+    if (10 == margin.fLeft) gTrace = true;
+#endif
+
+    SkASSERT(canvas);
+
+#ifdef USE_TRACE
+    if (gTrace) SkDebugf("======== ninepatch bounds [%g %g]\n", SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height()));
+    if (gTrace) SkDebugf("======== ninepatch paint bm [%d,%d]\n", bitmap.width(), bitmap.height());
+    if (gTrace) SkDebugf("======== ninepatch margin [%d,%d,%d,%d]\n", margin.fLeft, margin.fTop, margin.fRight, margin.fBottom);
+#endif
+
+
+    if (bounds.isEmpty() ||
+        bitmap.width() == 0 || bitmap.height() == 0 || bitmap.getPixels() == NULL ||
+        paint && paint->getXfermode() == NULL && paint->getAlpha() == 0)
+    {
+#ifdef USE_TRACE
+        if (gTrace) SkDebugf("======== abort ninepatch draw\n");
+#endif
+        return;
+    }
+
+    SkPaint defaultPaint;
+    if (NULL == paint)
+        paint = &defaultPaint;
+
+    SkRect      dst;
+    SkRect16    src, mar;
+
+    mar.set(SkMax32(margin.fLeft, 0), SkMax32(margin.fTop, 0),
+            SkMax32(margin.fRight, 0), SkMax32(margin.fBottom, 0));
+
+// left column
+    src.fLeft = 0;
+    src.fRight = mar.fLeft;
+    dst.fLeft = bounds.fLeft;
+    dst.fRight = bounds.fLeft + SkIntToScalar(mar.fLeft);
+    drawColumn(canvas, &src, &dst, bounds, mar, bitmap, *paint);
+// mid column
+    src.fLeft = src.fRight;
+    src.fRight = bitmap.width() - mar.fRight;
+    dst.fLeft = dst.fRight;
+    dst.fRight = bounds.fRight - SkIntToScalar(mar.fRight);
+    drawColumn(canvas, &src, &dst, bounds, mar, bitmap, *paint);
+// right column
+    src.fLeft = src.fRight;
+    src.fRight = bitmap.width();
+    dst.fLeft = dst.fRight;
+    dst.fRight = bounds.fRight;
+    drawColumn(canvas, &src, &dst, bounds, mar, bitmap, *paint);
+
+#ifdef USE_TRACE
+    gTrace = false;
+#endif
+}
+
+void SkNinePatch::Draw(SkCanvas* canvas, const SkRect& bounds,
+                     const SkBitmap& bitmap, int cx, int cy,
+                     const SkPaint* paint)
+{
+    SkRect16    marginRect;
+    
+    marginRect.set(cx, cy, bitmap.width() - cx - 1, bitmap.height() - cy - 1);
+
+    SkNinePatch::Draw(canvas, bounds, bitmap, marginRect, paint);
+}
+
diff --git a/libs/graphics/effects/SkRadialGradient_Table.h b/libs/graphics/effects/SkRadialGradient_Table.h
new file mode 100644 (file)
index 0000000..24fc715
--- /dev/null
@@ -0,0 +1,130 @@
+static const U8 gSqrt8Table[] = {
+       0x00, 0x05, 0x08, 0x09, 0x0B, 0x0C, 0x0D, 0x0E, 0x10, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x15, 
+       0x16, 0x17, 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1B, 0x1B, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 
+       0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 
+       0x27, 0x27, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2B, 0x2C, 0x2C, 0x2C, 
+       0x2D, 0x2D, 0x2D, 0x2E, 0x2E, 0x2E, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x32, 
+       0x32, 0x32, 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x37, 
+       0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x3A, 0x3A, 0x3A, 0x3B, 0x3B, 0x3B, 
+       0x3B, 0x3C, 0x3C, 0x3C, 0x3C, 0x3D, 0x3D, 0x3D, 0x3D, 0x3E, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F, 
+       0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 
+       0x43, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x46, 0x46, 0x46, 0x46, 0x47, 0x47, 
+       0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x4A, 0x4A, 0x4A, 0x4A, 
+       0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4D, 0x4D, 0x4D, 0x4D, 0x4D, 0x4E, 
+       0x4E, 0x4E, 0x4E, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, 
+       0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, 0x54, 
+       0x54, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, 0x57, 
+       0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5A, 0x5A, 
+       0x5A, 0x5A, 0x5A, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5D, 
+       0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 
+       0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 
+       0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x65, 
+       0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 
+       0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 
+       0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6C, 0x6C, 0x6C, 
+       0x6C, 0x6C, 0x6C, 0x6C, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 
+       0x6E, 0x6E, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 
+       0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 
+       0x73, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, 
+       0x75, 0x75, 0x75, 0x75, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, 
+       0x77, 0x77, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 
+       0x79, 0x79, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 
+       0x7B, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 
+       0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 
+       0x81, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 
+       0x83, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 
+       0x85, 0x85, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 
+       0x87, 0x87, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x89, 0x89, 0x89, 0x89, 0x89, 
+       0x89, 0x89, 0x89, 0x89, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8B, 0x8B, 0x8B, 0x8B, 
+       0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8D, 0x8D, 
+       0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 
+       0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 
+       0x90, 0x90, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92, 0x92, 0x92, 
+       0x92, 0x92, 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 
+       0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 
+       0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 
+       0x97, 0x97, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x99, 0x99, 0x99, 0x99, 
+       0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9B, 
+       0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 
+       0x9C, 0x9C, 0x9C, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9E, 0x9E, 0x9E, 
+       0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 
+       0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 
+       0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA3, 
+       0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 
+       0xA4, 0xA4, 0xA4, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA6, 0xA6, 
+       0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 
+       0xA7, 0xA7, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA9, 0xA9, 0xA9, 
+       0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 
+       0xAA, 0xAA, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAC, 0xAC, 0xAC, 
+       0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 
+       0xAD, 0xAD, 0xAD, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAF, 0xAF, 
+       0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 
+       0xB0, 0xB0, 0xB0, 0xB0, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB2, 
+       0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 
+       0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 
+       0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB6, 0xB6, 0xB6, 0xB6, 
+       0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 
+       0xB7, 0xB7, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB9, 0xB9, 
+       0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 
+       0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 
+       0xBB, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBD, 0xBD, 0xBD, 
+       0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 
+       0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 
+       0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC1, 0xC1, 0xC1, 
+       0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 
+       0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 
+       0xC3, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC5, 0xC5, 0xC5, 
+       0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 
+       0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 
+       0xC7, 0xC7, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC9, 
+       0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xCA, 0xCA, 0xCA, 0xCA, 
+       0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 
+       0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 
+       0xCC, 0xCC, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCE, 
+       0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCF, 0xCF, 0xCF, 0xCF, 
+       0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 
+       0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 
+       0xD1, 0xD1, 0xD1, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 
+       0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD4, 0xD4, 0xD4, 
+       0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 
+       0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 
+       0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 
+       0xD7, 0xD7, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 
+       0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xDA, 0xDA, 
+       0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 
+       0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 
+       0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 
+       0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 
+       0xDE, 0xDE, 0xDE, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 
+       0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE1, 
+       0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE2, 0xE2, 0xE2, 
+       0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 
+       0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 
+       0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 
+       0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 
+       0xE6, 0xE6, 0xE6, 0xE6, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 
+       0xE7, 0xE7, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 
+       0xE8, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 
+       0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEB, 0xEB, 
+       0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEC, 0xEC, 0xEC, 
+       0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xED, 0xED, 0xED, 0xED, 
+       0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 
+       0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 
+       0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 
+       0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 
+       0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 
+       0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 
+       0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 
+       0xF4, 0xF4, 0xF4, 0xF4, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 
+       0xF5, 0xF5, 0xF5, 0xF5, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 
+       0xF6, 0xF6, 0xF6, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 
+       0xF7, 0xF7, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 
+       0xF8, 0xF8, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 
+       0xF9, 0xF9, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 
+       0xFA, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 
+       0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 
+       0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 
+       0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 
+       0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
diff --git a/libs/graphics/effects/SkShaderExtras.cpp b/libs/graphics/effects/SkShaderExtras.cpp
new file mode 100644 (file)
index 0000000..cf8f047
--- /dev/null
@@ -0,0 +1,51 @@
+#include "SkShader.h"
+#include "SkColorFilter.h"
+#include "SkShaderExtras.h"
+
+//////////////////////////////////////////////////////////////////////////////////////
+    
+SkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkColorCombine* combine)
+{
+    fShaderA = sA;      sA->ref();
+    fShaderB = sB;      sB->ref();
+    fCombine = combine; combine->ref();
+}
+
+SkComposeShader::~SkComposeShader()
+{
+    fCombine->unref();
+    fShaderB->unref();
+    fShaderA->unref();
+}
+
+bool SkComposeShader::setContext(const SkBitmap& device,
+                                 const SkPaint& paint,
+                                 const SkMatrix& matrix)
+{
+    return  this->INHERITED::setContext(device, paint, matrix) &&
+            fShaderA->setContext(device, paint, matrix) &&
+            fShaderA->setContext(device, paint, matrix);
+}
+
+void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count)
+{
+    SkShader*       shaderA = fShaderA;
+    SkShader*       shaderB = fShaderB;
+    SkColorCombine* combine = fCombine;
+    
+    SkPMColor       tmp[COUNT];
+    do {
+        int n = count;
+        if (n > COUNT)
+            n = COUNT;
+        
+        shaderA->shadeSpan(x, y, tmp, n);
+        shaderB->shadeSpan(x, y, result, n);
+        combine->combineSpan(tmp, result, n, result);
+        
+        result += n;
+        x += n;
+        count -= n;
+    } while (count > 0);
+}
+    
diff --git a/libs/graphics/effects/SkTransparentShader.cpp b/libs/graphics/effects/SkTransparentShader.cpp
new file mode 100644 (file)
index 0000000..a20c9a5
--- /dev/null
@@ -0,0 +1,104 @@
+#include "SkTransparentShader.h"
+#include "SkColorPriv.h"
+
+bool SkTransparentShader::setContext(const SkBitmap& device,
+                                                                        const SkPaint& paint,
+                                                                        const SkMatrix& matrix)
+{
+       fDevice = device;
+       fAlpha = paint.getAlpha();
+
+       return this->INHERITED::setContext(device, paint, matrix);
+}
+
+U32 SkTransparentShader::getFlags()
+{
+       U32     flags = 0;
+
+       switch (fDevice.getConfig()) {
+       case SkBitmap::kRGB_565_Config:
+               flags |= kHasSpan16_Flag;
+               // fall through
+       case SkBitmap::kARGB_8888_Config:
+               flags |= (fAlpha == 255 ? kOpaqueAlpha_Flag : kConstAlpha_Flag);
+       default:
+               break;
+       }
+       return flags;
+}
+
+void SkTransparentShader::shadeSpan(int x, int y, SkPMColor span[], int count)
+{
+       unsigned scale = SkAlpha255To256(fAlpha);
+
+       switch (fDevice.getConfig()) {
+       case SkBitmap::kARGB_8888_Config:
+               if (scale == 256)
+                       memcpy(span, fDevice.getAddr32(x, y), count * sizeof(SkPMColor));
+               else
+               {
+                       const SkPMColor* src = fDevice.getAddr32(x, y);
+                       for (int i = count - 1; i >= 0; --i)
+                               span[i] = SkAlphaMulQ(src[i], scale);
+               }
+               break;
+       case SkBitmap::kRGB_565_Config:
+               {
+                       const U16* src = fDevice.getAddr16(x, y);
+                       if (scale == 256)
+                       {
+                               for (int i = count - 1; i >= 0; --i)
+                                       span[i] = SkPixel16ToPixel32(src[i]);
+                       }
+                       else
+                       {
+                               unsigned alpha = fAlpha;
+                               for (int i = count - 1; i >= 0; --i)
+                               {
+                                       U16              c = src[i];
+                                       unsigned r = SkPacked16ToR32(c);
+                                       unsigned g = SkPacked16ToG32(c);
+                                       unsigned b = SkPacked16ToB32(c);
+
+                                       span[i] = SkPackARGB32( alpha,
+                                                                                       SkAlphaMul(r, scale),
+                                                                                       SkAlphaMul(g, scale),
+                                                                                       SkAlphaMul(b, scale));
+                               }
+                       }
+               }
+               break;
+       case SkBitmap::kIndex8_Config:
+               SkASSERT(!"index8 not supported as a destination device");
+               break;
+       case SkBitmap::kA8_Config:
+               {
+                       const U8* src = fDevice.getAddr8(x, y);
+                       if (scale == 256)
+                       {
+                               for (int i = count - 1; i >= 0; --i)
+                                       span[i] = SkPackARGB32(src[i], 0, 0, 0);
+                       }
+                       else
+                       {
+                               for (int i = count - 1; i >= 0; --i)
+                                       span[i] = SkPackARGB32(SkAlphaMul(src[i], scale), 0, 0, 0);
+                       }
+               }
+               break;
+       case SkBitmap::kA1_Config:
+               SkASSERT(!"kA1_Config umimplemented at this time");
+               break;
+       default:        // to avoid warnings
+               break;
+       }
+}
+
+void SkTransparentShader::shadeSpanOpaque16(int x, int y, U16 span[], int count)
+{
+       SkASSERT(fAlpha == 255);
+       SkASSERT(fDevice.getConfig() == SkBitmap::kRGB_565_Config);
+
+       memcpy(span, fDevice.getAddr16(x, y), count << 1);
+}
+
diff --git a/libs/graphics/images/SkBitmapRef.cpp b/libs/graphics/images/SkBitmapRef.cpp
new file mode 100644 (file)
index 0000000..750a841
--- /dev/null
@@ -0,0 +1,121 @@
+#include "SkBitmapRefPriv.h"
+#include "SkTemplates.h"
+#include "SkThread.h"
+#include "SkString.h"
+#include "SkGlobals.h"
+#include "SkThread.h"
+
+SkGlobals::Rec* SkBitmapRef_Globals::Create()
+{
+       SkBitmapRef_Globals* rec = SkNEW(SkBitmapRef_Globals);
+       rec->fCache = nil;
+       return rec;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+SkBitmapRef::SkBitmapRef(Rec* rec) : fRec(rec)
+{
+       SkASSERT(rec);
+       rec->fRefCnt += 1;
+}
+
+SkBitmapRef::SkBitmapRef(const SkBitmap& src, bool transferOwnsPixels)
+{
+    fRec = SkNEW_ARGS(SkBitmapRef::Rec, (src));
+    fRec->fIsCache = false;
+    if (transferOwnsPixels)
+    {
+        fRec->fBM.setOwnsPixels(src.getOwnsPixels());
+        ((SkBitmap*)&src)->setOwnsPixels(false);
+    }
+}
+  
+SkBitmapRef::~SkBitmapRef()
+{
+    if (fRec->fIsCache)
+    {
+        SkBitmapRef_Globals& globals = *(SkBitmapRef_Globals*)SkGlobals::Find(kBitmapRef_GlobalsTag,
+                                                                              SkBitmapRef_Globals::Create);
+        SkAutoMutexAcquire     ac(globals.fMutex);
+
+        SkASSERT(fRec->fRefCnt > 0);
+        fRec->fRefCnt -= 1;
+    }
+    else
+    {
+        SkDEBUGF(("~SkBitmapRef[%d %d]\n", fRec->fBM.width(), fRec->fBM.height()));
+        SkDELETE(fRec);
+    }
+}
+
+const SkBitmap& SkBitmapRef::bitmap()
+{
+       return fRec->fBM;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+SkBitmapRef* SkBitmapRef::create(const SkBitmap& src, bool transferOwnsPixels)
+{
+    return SkNEW_ARGS(SkBitmapRef, (src, transferOwnsPixels));
+}
+
+void SkBitmapRef::PurgeCacheAll()
+{
+       SkBitmapRef_Globals* globals = (SkBitmapRef_Globals*)SkGlobals::Find(kBitmapRef_GlobalsTag, nil);
+       if (globals == nil)
+               return;
+
+       SkAutoMutexAcquire      ac(globals->fMutex);
+       SkBitmapRef::Rec*       rec = globals->fCache;
+    SkDEBUGCODE(int     count = 0;)
+
+       while (rec)
+       {
+        SkDEBUGCODE(count += 1;)
+               SkASSERT(rec->fRefCnt == 0);
+               Rec* next = rec->fNext;
+               SkDELETE(rec);
+               rec = next;
+       }
+       globals->fCache = nil;
+    
+    SkDEBUGF(("PurgeCacheAll freed %d bitmaps\n", count));
+}
+
+bool SkBitmapRef::PurgeCacheOne()
+{
+       SkBitmapRef_Globals* globals = (SkBitmapRef_Globals*)SkGlobals::Find(kBitmapRef_GlobalsTag, nil);
+       if (globals == nil)
+               return false;
+
+       SkAutoMutexAcquire      ac(globals->fMutex);
+       SkBitmapRef::Rec*       rec = globals->fCache;
+       SkBitmapRef::Rec*       prev = nil;
+    SkDEBUGCODE(int     count = 0;)
+
+       while (rec)
+       {
+        SkDEBUGCODE(count += 1;)
+
+               SkBitmapRef::Rec* next = rec->fNext;
+               if (rec->fRefCnt == 0)
+               {
+                       if (prev)
+                               prev = next;
+                       else
+                               globals->fCache = next;
+
+            SkDEBUGF(("PurgeCacheOne for bitmap[%d %d]\n", rec->fBM.width(), rec->fBM.height()));
+                       SkDELETE(rec);
+                       return true;
+               }
+               prev = rec;
+               rec = next;
+       }
+
+    SkDEBUGF(("PurgeCacheOne: nothing to purge from %d bitmaps\n", count));
+       return false;
+}
+
diff --git a/libs/graphics/images/SkBitmapRefPriv.h b/libs/graphics/images/SkBitmapRefPriv.h
new file mode 100644 (file)
index 0000000..24c0a2c
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef SkBitmapRefPriv_DEFINED
+#define SkBitmapRefPriv_DEFINED
+
+#include "SkBitmapRef.h"
+#include "SkGlobals.h"
+#include "SkThread.h"
+#include "SkBitmap.h"
+#include "SkString.h"
+
+#define kBitmapRef_GlobalsTag  SkSetFourByteTag('s', 'k', 'b', 'r')
+
+class SkBitmapRef_Globals : public SkGlobals::Rec {
+public:
+       SkMutex                         fMutex;
+       SkBitmapRef::Rec*       fCache;
+    
+    static Rec* Create();
+};
+
+struct SkBitmapRef::Rec {
+    Rec(bool isCache): fIsCache(isCache) {}
+    Rec(const SkBitmap& src): fBM(src) {}
+    
+    Rec*               fNext;
+    int32_t            fRefCnt;
+    SkString   fPath;
+    SkBitmap   fBM;
+    bool        fIsCache;
+};
+
+#endif
diff --git a/libs/graphics/images/SkImageDecoder.cpp b/libs/graphics/images/SkImageDecoder.cpp
new file mode 100644 (file)
index 0000000..7c76bc8
--- /dev/null
@@ -0,0 +1,175 @@
+#include "SkImageDecoder.h"
+#include "SkStream.h"
+#include "SkTemplates.h"
+
+static SkBitmap::Config gDeviceConfig = SkBitmap::kNo_Config;
+
+SkBitmap::Config SkImageDecoder::GetDeviceConfig()
+{
+       return gDeviceConfig;
+}
+
+void SkImageDecoder::SetDeviceConfig(SkBitmap::Config config)
+{
+       gDeviceConfig = config;
+}
+
+SkImageDecoder::SkImageDecoder()
+{
+}
+
+SkImageDecoder::~SkImageDecoder()
+{
+}
+
+bool SkImageDecoder::DecodeFile(const char file[], SkBitmap* bm, SkBitmap::Config pref)
+{
+       SkASSERT(file);
+       SkASSERT(bm);
+
+       SkFILEStream    stream(file);
+       return stream.isValid() && SkImageDecoder::DecodeStream(&stream, bm, pref);
+}
+
+bool SkImageDecoder::DecodeMemory(const void* buffer, size_t size, SkBitmap* bm, SkBitmap::Config pref)
+{
+       SkASSERT(buffer);
+
+       SkMemoryStream  stream(buffer, size);
+       return size && SkImageDecoder::DecodeStream(&stream, bm, pref);
+}
+
+bool SkImageDecoder::DecodeURL(const char url[], SkBitmap* bm, SkBitmap::Config pref) 
+{
+       SkASSERT(url);
+       SkASSERT(bm);
+
+       SkURLStream     stream(url);
+       return SkImageDecoder::DecodeStream(&stream, bm, pref);
+}
+
+bool SkImageDecoder::DecodeStream(SkStream* stream, SkBitmap* bm, SkBitmap::Config pref)
+{
+       SkASSERT(stream);
+       SkASSERT(bm);
+
+       SkImageDecoder* codec = SkImageDecoder::Factory(stream);
+    if (codec)
+    {
+        SkAutoTDelete<SkImageDecoder>  ad(codec);
+        SkBitmap                                               tmp;
+
+        if (codec->onDecode(stream, &tmp, pref))
+        {
+            /* We operate on a tmp bitmap until we know we succeed. This way
+                we're sure we don't change the caller's bitmap and then later
+                return false. Returning false must mean that their parameter
+                is unchanged.
+            */
+            bm->swap(tmp);
+            return true;
+        }
+    }
+       return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_SUPPORT_IMAGE_ENCODE
+
+SkImageEncoder::~SkImageEncoder()
+{
+}
+
+bool SkImageEncoder::encodeStream(SkWStream* stream, const SkBitmap& bm, int quality)
+{
+       quality = SkMin32(100, SkMax32(0, quality));
+       return this->onEncode(stream, bm, quality);
+}
+
+bool SkImageEncoder::encodeFile(const char file[], const SkBitmap& bm, int quality)
+{
+       quality = SkMin32(100, SkMax32(0, quality));
+       SkFILEWStream   stream(file);
+       return this->onEncode(&stream, bm, quality);
+}
+
+extern SkImageEncoder* sk_create_jpeg_encoder();
+extern SkImageEncoder* sk_create_png_encoder();
+
+SkImageEncoder* SkImageEncoder::Create(Type t)
+{
+    if (kJPEG_Type == t)
+        return sk_create_jpeg_encoder();
+    if (kPNG_Type == t)
+        return sk_create_png_encoder();
+    return nil;
+}
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////
+
+#include "SkBitmapRefPriv.h"
+
+SkBitmapRef* SkBitmapRef::DecodeFile(const char path[], bool forceDecode)
+{
+       SkBitmapRef_Globals& globals = *(SkBitmapRef_Globals*)SkGlobals::Find(kBitmapRef_GlobalsTag,
+                                                                          SkBitmapRef_Globals::Create);
+
+       SkAutoMutexAcquire      ac(globals.fMutex);
+       SkBitmapRef::Rec*       rec = globals.fCache;
+
+       while (rec)
+       {
+               if (rec->fPath.equals(path))
+                       return SkNEW_ARGS(SkBitmapRef, (rec));
+               rec = rec->fNext;
+       }
+
+       if (forceDecode)
+       {
+               SkAutoTDelete<Rec>      autoRec(rec = SkNEW_ARGS(Rec, (true)));
+               
+               if (SkImageDecoder::DecodeFile(path, &rec->fBM))
+               {
+                       rec->fPath.set(path);
+                       rec->fRefCnt = 0;
+                       rec->fNext = globals.fCache;
+                       globals.fCache = rec;
+
+                       (void)autoRec.detach(); // detach from autoRec, so we don't delete it
+                       return SkNEW_ARGS(SkBitmapRef, (rec));
+               }
+       }
+       return nil;
+}
+
+SkBitmapRef* SkBitmapRef::DecodeMemory(const void* bytes, size_t len)
+{
+    SkBitmapRef::Rec* rec;
+    SkAutoTDelete<Rec>  autoRec(rec = SkNEW_ARGS(Rec, (false)));
+
+    if (SkImageDecoder::DecodeMemory(bytes, len, &rec->fBM))
+    {
+        rec->fRefCnt = 0;
+        (void)autoRec.detach();
+        return SkNEW_ARGS(SkBitmapRef, (rec));
+    }
+    return nil;
+}
+
+SkBitmapRef* SkBitmapRef::DecodeStream(SkStream* stream)
+{
+    SkBitmapRef::Rec* rec;
+    SkAutoTDelete<Rec>  autoRec(rec = SkNEW_ARGS(Rec, (false)));
+
+    if (SkImageDecoder::DecodeStream(stream, &rec->fBM))
+    {
+        rec->fRefCnt = 0;
+        (void)autoRec.detach();
+        return SkNEW_ARGS(SkBitmapRef, (rec));
+    }
+    return nil;
+}    
+
diff --git a/libs/graphics/images/SkImageDecoder_libgif.cpp b/libs/graphics/images/SkImageDecoder_libgif.cpp
new file mode 100644 (file)
index 0000000..621164d
--- /dev/null
@@ -0,0 +1,123 @@
+#include "SkImageDecoder.h"
+#include "SkColor.h"
+#include "SkColorPriv.h"
+#include "SkStream.h"
+#include "SkTemplates.h"
+
+class SkGIFImageDecoder : public SkImageDecoder {
+protected:
+       virtual bool onDecode(SkStream* stream, SkBitmap* bm, SkBitmap::Config pref);
+};
+
+
+extern "C" {
+#include "gif_lib.h"
+}
+
+#define GIF_STAMP              "GIF"    /* First chars in file - GIF stamp. */
+#define GIF_STAMP_LEN  (sizeof(GIF_STAMP) - 1)
+
+SkImageDecoder* SkImageDecoder_GIF_Factory(SkStream* stream)
+{
+       char buf[GIF_STAMP_LEN];
+       if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN &&
+        memcmp(GIF_STAMP, buf, GIF_STAMP_LEN) == 0)
+    {
+        stream->rewind();
+        return SkNEW(SkGIFImageDecoder);
+    }
+    return NULL;
+}
+
+static int Decode(GifFileType* fileType, GifByteType* out, int size)
+{
+       SkStream* stream = (SkStream*) fileType->UserData;
+       return (int) stream->read(out, size);
+}
+
+bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, SkBitmap::Config prefConfig)
+{      
+       GifFileType* gif = DGifOpen( sk_stream, Decode );
+       if (gif == nil)
+               return false;
+    if (DGifSlurp(gif) != GIF_OK)
+               return false;
+    ColorMapObject* cmap = gif->SColorMap;
+    if (cmap == 0 ||
+        gif->ImageCount < 1 ||
+        cmap->ColorCount != (1 << cmap->BitsPerPixel))
+                       return false;
+    SavedImage* gif_image = gif->SavedImages + 0;
+    const int width = gif->SWidth;
+    const int height = gif->SHeight;
+       SkBitmap::Config        config = SkBitmap::kIndex8_Config;
+       bm->setConfig(config, width, height, 0);
+       bm->allocPixels();
+       
+       SkColorTable* colorTable = SkNEW(SkColorTable);
+       colorTable->setColors(cmap->ColorCount);
+       bm->setColorTable(colorTable)->unref();
+
+    int transparent = -1;
+    for (int i = 0; i < gif_image->ExtensionBlockCount; ++i) {
+      ExtensionBlock* eb = gif_image->ExtensionBlocks + i;
+      if (eb->Function == 0xF9 && 
+          eb->ByteCount == 4) {
+        bool has_transparency = ((eb->Bytes[0] & 1) == 1);
+        if (has_transparency) {
+          transparent = eb->Bytes[3];
+        }
+      }
+    }
+
+       SkPMColor* colorPtr = colorTable->lockColors();
+
+       if (transparent >= 0)
+               memset(colorPtr, 0, cmap->ColorCount * 4);
+       else
+               colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag);
+
+       for (int index = 0; index < cmap->ColorCount; index++)
+       {
+               if (transparent != index)
+                       colorPtr[index] = SkColorSetRGB(cmap->Colors[index].Red, 
+                               cmap->Colors[index].Green, cmap->Colors[index].Blue);
+       }
+       colorTable->unlockColors(true);
+
+    unsigned char* in = (unsigned char*)gif_image->RasterBits;
+    unsigned char* out = bm->getAddr8(0, 0);
+    if (gif->Image.Interlace) {
+
+      // deinterlace
+               int row;
+      // group 1 - every 8th row, starting with row 0
+      for (row = 0; row < height; row += 8) {
+        memcpy(out + width * row, in, width);
+        in += width;
+      }
+
+      // group 2 - every 8th row, starting with row 4
+      for (row = 4; row < height; row += 8) {
+        memcpy(out + width * row, in, width);
+        in += width;
+      }
+
+      // group 3 - every 4th row, starting with row 2
+      for (row = 2; row < height; row += 4) {
+        memcpy(out + width * row, in, width);
+        in += width;
+      }
+
+      for (row = 1; row < height; row += 2) {
+        memcpy(out + width * row, in, width);
+        in += width;
+      }
+
+    } else {
+      memcpy(out, in, width * height);
+    }
+
+    DGifCloseFile(gif);
+       return true;
+}
diff --git a/libs/graphics/images/SkImageDecoder_libjpeg.cpp b/libs/graphics/images/SkImageDecoder_libjpeg.cpp
new file mode 100644 (file)
index 0000000..91f019e
--- /dev/null
@@ -0,0 +1,427 @@
+#include "SkImageDecoder.h"
+#include "SkColorPriv.h"
+#include "SkStream.h"
+#include "SkTemplates.h"
+
+#include <stdio.h>
+extern "C" {
+       #include "jpeglib.h"
+}
+
+class SkJPEGImageDecoder : public SkImageDecoder {
+protected:
+       virtual bool onDecode(SkStream* stream, SkBitmap* bm, SkBitmap::Config pref);
+};
+
+SkImageDecoder* SkImageDecoder_JPEG_Factory(SkStream* stream) { 
+       // !!! unimplemented; rely on PNG test first for now
+       return SkNEW(SkJPEGImageDecoder);
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+/* our source struct for directing jpeg to our stream object
+*/
+struct sk_source_mgr : jpeg_source_mgr {
+       sk_source_mgr(SkStream* stream);
+
+       SkStream*       fStream;
+
+       enum {
+               kBufferSize = 1024
+       };
+       char    fBuffer[kBufferSize];
+};
+
+/* Automatically clean up after throwing an exception */
+struct JPEGAutoClean
+{
+       JPEGAutoClean(jpeg_decompress_struct* info): cinfo_ptr(info) {}
+       ~JPEGAutoClean()
+       {
+               jpeg_destroy_decompress(cinfo_ptr);
+       }
+private:
+       jpeg_decompress_struct* cinfo_ptr;
+};
+
+static void sk_init_source(j_decompress_ptr cinfo)
+{
+       sk_source_mgr*  src = (sk_source_mgr*)cinfo->src;
+
+       src->next_input_byte = (const JOCTET*)src->fBuffer;
+       src->bytes_in_buffer = 0;
+}
+
+static boolean sk_fill_input_buffer(j_decompress_ptr cinfo)
+{
+       sk_source_mgr*  src = (sk_source_mgr*)cinfo->src;
+       size_t                  bytes = src->fStream->read(src->fBuffer, sk_source_mgr::kBufferSize);
+       // note that JPEG is happy with less than the full read, as long as the result is non-zero
+       if (bytes == 0)
+               cinfo->err->error_exit((j_common_ptr)cinfo);
+
+       src->next_input_byte = (const JOCTET*)src->fBuffer;
+       src->bytes_in_buffer = bytes;
+       return TRUE;
+}
+
+static void sk_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
+{
+       SkASSERT(num_bytes > 0);
+
+       sk_source_mgr*  src = (sk_source_mgr*)cinfo->src;
+
+       long skip = num_bytes - src->bytes_in_buffer;
+
+       if (skip > 0)
+       {
+               size_t bytes = src->fStream->read(nil, skip);
+               if (bytes != (size_t)skip)
+                       cinfo->err->error_exit((j_common_ptr)cinfo);
+
+               src->next_input_byte = (const JOCTET*)src->fBuffer;
+               src->bytes_in_buffer = 0;
+       }
+       else
+       {
+               src->next_input_byte += num_bytes;
+               src->bytes_in_buffer -= num_bytes;
+       }
+}
+
+static boolean sk_resync_to_restart(j_decompress_ptr cinfo, int desired)
+{
+       sk_source_mgr*  src = (sk_source_mgr*)cinfo->src;
+
+       // what is the desired param for???
+
+       if (!src->fStream->rewind())
+               cinfo->err->error_exit((j_common_ptr)cinfo);
+
+       return TRUE;
+}
+
+static void sk_term_source(j_decompress_ptr /*cinfo*/)
+{
+       // nothing to do
+}
+
+sk_source_mgr::sk_source_mgr(SkStream* stream)
+       : fStream(stream)
+{
+       init_source = sk_init_source;
+       fill_input_buffer = sk_fill_input_buffer;
+       skip_input_data = sk_skip_input_data;
+       resync_to_restart = sk_resync_to_restart;
+       term_source = sk_term_source;
+}
+
+#include <setjmp.h>
+
+struct sk_error_mgr : jpeg_error_mgr {
+       jmp_buf fJmpBuf;
+};
+
+static void sk_error_exit(j_common_ptr cinfo)
+{
+       sk_error_mgr* error = (sk_error_mgr*)cinfo->err;
+
+       /* Always display the message */
+       (*error->output_message) (cinfo);
+
+       /* Let the memory manager delete any temp files before we die */
+       jpeg_destroy(cinfo);
+
+       longjmp(error->fJmpBuf, -1);
+}
+
+bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, SkBitmap::Config prefConfig)
+{
+       jpeg_decompress_struct  cinfo;
+       sk_error_mgr                    sk_err;
+       sk_source_mgr                   sk_stream(stream);
+
+       cinfo.err = jpeg_std_error(&sk_err);
+       sk_err.error_exit = sk_error_exit;
+
+       if (setjmp(sk_err.fJmpBuf))
+               return false;
+
+       jpeg_create_decompress(&cinfo);
+       JPEGAutoClean autoClean(&cinfo);
+
+       //jpeg_stdio_src(&cinfo, file);
+       cinfo.src = &sk_stream;
+
+       jpeg_read_header(&cinfo, true);
+
+       // now we know the dimensions. can call jpeg_destroy() if we wish
+
+    // check for supported formats
+    bool isRGB; // as opposed to gray8
+    if (3 == cinfo.num_components && JCS_RGB == cinfo.out_color_space)
+        isRGB = true;
+    else if (1 == cinfo.num_components && JCS_GRAYSCALE == cinfo.out_color_space)
+        isRGB = false;  // could use Index8 config if we want...
+    else {
+        SkDEBUGF(("SkJPEGImageDecoder: unsupported jpeg colorspace %d with %d components\n",
+                    cinfo.jpeg_color_space, cinfo.num_components));
+        return false;
+    }
+    
+       SkBitmap::Config config = prefConfig;
+       // if no user preference, see what the device recommends
+       if (config == SkBitmap::kNo_Config)
+               config = SkImageDecoder::GetDeviceConfig();
+
+       // only one of these two makes sense for jpegs
+       if (config != SkBitmap::kARGB_8888_Config && config != SkBitmap::kRGB_565_Config)
+               config = SkBitmap::kARGB_8888_Config;
+
+       bm->setConfig(config, cinfo.image_width, cinfo.image_height, 0);
+       bm->allocPixels();
+    bm->setIsOpaque(true);
+
+       jpeg_start_decompress(&cinfo);
+
+       SkASSERT(cinfo.output_width == bm->width());
+       SkASSERT(cinfo.output_height == bm->height());
+
+       int width = bm->width();
+
+       if (config == SkBitmap::kARGB_8888_Config)
+       {
+               for (unsigned y = 0; y < cinfo.output_height; y++)
+               {
+                       uint32_t* bmRow = bm->getAddr32(0, y);
+                       JSAMPLE* rowptr = (JSAMPLE*)bmRow;
+                       int              row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
+                       SkASSERT(row_count == 1);
+
+                       // since we want to reuse bmRow for the RGB triples and the final ARGB quads
+                       // we need to expand backwards, so we don't overwrite our src
+
+                       uint32_t*       dst = bmRow + width;
+
+            if (isRGB) {
+                const uint8_t* src = rowptr + width * 3;
+                while (dst > bmRow)
+                {
+                    src -= 3;
+                    *--dst = SkPackARGB32(0xFF, src[0], src[1], src[2]);
+                }
+            }
+            else {  // grayscale
+                const uint8_t* src = rowptr + width;
+                while (dst > bmRow)
+                {
+                    src -= 1;
+                    *--dst = SkPackARGB32(0xFF, src[0], src[0], src[0]);
+                }
+            }
+               }
+       }
+       else    // convert to 16bit
+       {
+               SkAutoMalloc    srcStorage(width * 3);
+               U8*                             srcRow = (U8*)srcStorage.get();
+
+               for (unsigned y = 0; y < cinfo.output_height; y++)
+               {
+                       U16*     dstRow = bm->getAddr16(0, y);
+                       int              row_count = jpeg_read_scanlines(&cinfo, &srcRow, 1);
+                       SkASSERT(row_count == 1);
+
+                       const U8*       src = srcRow;
+                       U16*            dstStop = dstRow + width;
+
+            if (isRGB) {
+                while (dstRow < dstStop)
+                {
+                    *dstRow++ = SkPackRGB16(src[0] >> (8 - SK_R16_BITS),
+                                            src[1] >> (8 - SK_G16_BITS),
+                                            src[2] >> (8 - SK_B16_BITS));
+                    src += 3;
+                }
+            }
+            else {  // grayscale
+                while (dstRow < dstStop)
+                {
+                    *dstRow++ = SkPackRGB16(src[0] >> (8 - SK_R16_BITS),
+                                            src[0] >> (8 - SK_G16_BITS),
+                                            src[0] >> (8 - SK_B16_BITS));
+                    src += 1;
+                }
+            }
+               }
+       }
+
+       jpeg_finish_decompress(&cinfo);
+
+       return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_SUPPORT_IMAGE_ENCODE
+
+#include "SkColorPriv.h"
+
+static void convert_to_rgb24(U8 dst[], const SkBitmap& bm, int y)
+{
+       int     width = bm.width();
+
+       switch (bm.getConfig()) {
+       case SkBitmap::kARGB_8888_Config:
+               {
+                       const uint32_t* src = bm.getAddr32(0, y);
+                       while (--width >= 0)
+                       {
+                               uint32_t c = *src++;
+                               dst[0] = SkGetPackedR32(c);
+                               dst[1] = SkGetPackedG32(c);
+                               dst[2] = SkGetPackedB32(c);
+                               dst += 3;
+                       }
+               }
+               break;
+       case SkBitmap::kRGB_565_Config: // hmmm, I should encode 16bit jpegs, not expand to 24 bit (doh!)
+               {
+                       const U16* src = bm.getAddr16(0, y);
+                       while (--width >= 0)
+                       {
+                               U16 c = *src++;
+                               dst[0] = SkPacked16ToR32(c);
+                               dst[1] = SkPacked16ToG32(c);
+                               dst[1] = SkPacked16ToB32(c);
+                               dst += 3;
+                       }
+               }
+               break;
+       default:
+               SkASSERT(!"unknown bitmap format for jpeg encode");
+       }
+}
+
+struct sk_destination_mgr : jpeg_destination_mgr
+{
+       sk_destination_mgr(SkWStream* stream);
+
+       SkWStream*      fStream;
+
+       enum {
+               kBufferSize = 1024
+       };
+       U8      fBuffer[kBufferSize];
+};
+
+static void sk_init_destination(j_compress_ptr cinfo)
+{
+       sk_destination_mgr* dest = (sk_destination_mgr*)cinfo->dest;
+
+       dest->next_output_byte = dest->fBuffer;
+       dest->free_in_buffer = sk_destination_mgr::kBufferSize;
+}
+
+static boolean sk_empty_output_buffer(j_compress_ptr cinfo)
+{
+       sk_destination_mgr* dest = (sk_destination_mgr*)cinfo->dest;
+
+//     if (!dest->fStream->write(dest->fBuffer, sk_destination_mgr::kBufferSize - dest->free_in_buffer))
+       if (!dest->fStream->write(dest->fBuffer, sk_destination_mgr::kBufferSize))
+               sk_throw();
+       //      ERREXIT(cinfo, JERR_FILE_WRITE);
+
+       dest->next_output_byte = dest->fBuffer;
+       dest->free_in_buffer = sk_destination_mgr::kBufferSize;
+       return TRUE;
+}
+
+static void sk_term_destination (j_compress_ptr cinfo)
+{
+       sk_destination_mgr* dest = (sk_destination_mgr*)cinfo->dest;
+
+       size_t size = sk_destination_mgr::kBufferSize - dest->free_in_buffer;
+       if (size > 0)
+       {
+               if (!dest->fStream->write(dest->fBuffer, size))
+                       sk_throw();
+       }
+       dest->fStream->flush();
+}
+
+sk_destination_mgr::sk_destination_mgr(SkWStream* stream)
+       : fStream(stream)
+{
+       this->init_destination = sk_init_destination;
+       this->empty_output_buffer = sk_empty_output_buffer;
+       this->term_destination = sk_term_destination;
+}
+
+
+class SkJPEGImageEncoder : public SkImageEncoder {
+protected:
+       virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality)
+       {
+               jpeg_compress_struct    cinfo;
+               sk_error_mgr                    sk_err;
+               sk_destination_mgr              sk_wstream(stream);
+
+               cinfo.err = jpeg_std_error(&sk_err);
+               sk_err.error_exit = sk_error_exit;
+               if (setjmp(sk_err.fJmpBuf))
+                       return false;
+
+               jpeg_create_compress(&cinfo);
+
+               cinfo.dest = &sk_wstream;
+               cinfo.image_width = bm.width();
+               cinfo.image_height = bm.height();
+               cinfo.input_components = 3;
+               cinfo.in_color_space = JCS_RGB;
+
+               jpeg_set_defaults(&cinfo);
+               jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
+               jpeg_start_compress(&cinfo, TRUE);
+
+               SkAutoMalloc    oneRow(bm.width() * 3);
+               U8*                             oneRowP = (U8*)oneRow.get();
+
+               while (cinfo.next_scanline < cinfo.image_height)
+               {
+                       JSAMPROW row_pointer[1];        /* pointer to JSAMPLE row[s] */
+
+                       convert_to_rgb24(oneRowP, bm, cinfo.next_scanline);
+                       row_pointer[0] = oneRowP;
+                       (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
+               }
+
+               jpeg_finish_compress(&cinfo);
+               jpeg_destroy_compress(&cinfo);
+               return true;
+       }
+};
+
+SkImageEncoder* sk_create_jpeg_encoder();
+SkImageEncoder* sk_create_jpeg_encoder()
+{
+    return SkNEW(SkJPEGImageEncoder);
+}
+
+#endif /* SK_SUPPORT_IMAGE_ENCODE */
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+void SkImageDecoder::UnitTest()
+{
+       SkBitmap        bm;
+
+       (void)SkImageDecoder::DecodeFile("logo.jpg", &bm);
+}
+
+#endif
diff --git a/libs/graphics/images/SkImageDecoder_libpng.cpp b/libs/graphics/images/SkImageDecoder_libpng.cpp
new file mode 100644 (file)
index 0000000..2dae48c
--- /dev/null
@@ -0,0 +1,605 @@
+#include "SkImageDecoder.h"
+#include "SkColor.h"
+#include "SkColorPriv.h"
+#include "SkMath.h"
+#include "SkStream.h"
+#include "SkTemplates.h"
+
+class SkPNGImageDecoder : public SkImageDecoder {
+protected:
+       virtual bool onDecode(SkStream* stream, SkBitmap* bm, SkBitmap::Config pref);
+};
+
+#define TEST_DITHER
+
+extern "C" {
+#include "png.h"
+}
+
+
+static void convert_from_32_to_16(SkBitmap* bm)
+{
+    SkBitmap    tmp;
+    unsigned    width = bm->width();
+    unsigned    height = bm->height();
+
+    tmp.setConfig(SkBitmap::kRGB_565_Config, width, height, 0);
+    tmp.allocPixels();
+
+    for (unsigned y = 0; y < height; y++) {
+        const uint32_t* src = bm->getAddr32(0, y);
+        uint16_t*       dst = tmp.getAddr16(0, y);
+        for (unsigned x = 0; x < width; x++) {
+            *dst++ = SkPixel32ToPixel16(*src++);
+        }
+    }
+    bm->swap(tmp);
+}
+
+#ifndef png_jmpbuf
+#  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
+#endif
+
+#define PNG_BYTES_TO_CHECK 4
+
+/* Automatically clean up after throwing an exception */
+struct PNGAutoClean
+{
+       PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {}
+       ~PNGAutoClean()
+       {
+               png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
+       }
+private:
+       png_structp png_ptr;
+       png_infop info_ptr;
+};
+
+SkImageDecoder* SkImageDecoder_PNG_Factory(SkStream* stream)
+{
+       char buf[PNG_BYTES_TO_CHECK];
+       if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK &&
+        !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK))
+    {
+        stream->rewind();
+        return SkNEW(SkPNGImageDecoder);
+    }
+    return NULL;
+}
+
+static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) {
+       SkStream* sk_stream = (SkStream*) png_ptr->io_ptr;
+       size_t bytes = sk_stream->read(data, length);
+       if (bytes != length)
+               png_error(png_ptr, "Read Error!");
+}
+
+bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, SkBitmap::Config prefConfig)
+{
+       /* Create and initialize the png_struct with the desired error handler
+       * functions.  If you want to use the default stderr and longjump method,
+       * you can supply NULL for the last three parameters.  We also supply the
+       * the compiler header file version, so that we know if the application
+       * was compiled with a compatible version of the library.  */
+       png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+               NULL, NULL, NULL);
+       //   png_voidp user_error_ptr, user_error_fn, user_warning_fn);
+       if (png_ptr == NULL)
+               return false; // error
+       /* Allocate/initialize the memory for image information. */
+       png_infop info_ptr = png_create_info_struct(png_ptr);
+
+       if (info_ptr == NULL)
+       {
+               png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
+               return false; // error
+       }
+       PNGAutoClean autoClean(png_ptr, info_ptr);
+       /* Set error handling if you are using the setjmp/longjmp method (this is
+       * the normal method of doing things with libpng).  REQUIRED unless you
+       * set up your own error handlers in the png_create_read_struct() earlier.
+       */
+       if (setjmp(png_jmpbuf(png_ptr)))
+       {
+               /* If we get here, we had a problem reading the file */
+               return false; // error
+       }
+       /* If you are using replacement read functions, instead of calling
+       * png_init_io() here you would call:
+       */
+       png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn);
+       /* where user_io_ptr is a structure you want available to the callbacks */
+       /* If we have already read some of the signature */
+//     png_set_sig_bytes(png_ptr, 0 /* sig_read */ );
+       /* The call to png_read_info() gives us all of the information from the
+       * PNG file before the first IDAT (image data chunk). */
+       png_read_info(png_ptr, info_ptr);
+       png_uint_32 width, height;
+       int bit_depth, color_type, interlace_type;
+       png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
+               &interlace_type, int_p_NULL, int_p_NULL);
+
+       /* tell libpng to strip 16 bit/color files down to 8 bits/color */
+       if (bit_depth == 16)
+               png_set_strip_16(png_ptr);
+
+       /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
+       * byte into separate bytes (useful for paletted and grayscale images). */
+       if (bit_depth < 8)
+               png_set_packing(png_ptr);
+
+       /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
+       if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+               png_set_gray_1_2_4_to_8(png_ptr);
+
+       /* Make a grayscale image into RGB. */
+    if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+          png_set_gray_to_rgb(png_ptr);
+
+    // record if the png claims to have alpha in one or more pixels (or palette entries)
+    bool    hasAlpha = false;
+    // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype
+    // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
+    // draw lots faster if we can flag the bitmap has being opaque
+    bool    reallyHasAlpha = false;
+
+       if (color_type == PNG_COLOR_TYPE_PALETTE)
+       {
+               int num_palette;
+               png_colorp palette;
+               png_bytep trans;
+               int num_trans;
+
+               SkColorTable* colorTable = SkNEW(SkColorTable);
+               SkAutoTDelete<SkColorTable> autoDel(colorTable);
+
+               png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
+
+               /*      BUGGY IMAGE WORKAROUND
+
+                       We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count
+                       which is a problem since we use the byte as an index. To work around this we grow
+                       the colortable by 1 (if its < 256) and duplicate the last color into that slot.
+               */
+               colorTable->setColors(num_palette + (num_palette < 256));
+
+               SkPMColor* colorPtr = colorTable->lockColors();
+        if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+        {
+                       png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
+            hasAlpha = (num_trans > 0);
+        }
+        else
+        {
+            num_trans = 0;
+            colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag);
+        }        
+        if (num_trans > num_palette)    // check for bad images that might make us crash
+            num_trans = num_palette;
+
+        int index = 0;
+        int transLessThanFF = 0;
+
+        for (; index < num_trans; index++)
+        {
+            transLessThanFF |= (int)*trans - 0xFF;
+                       *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->green, palette->blue);
+            palette++;
+        }
+        reallyHasAlpha |= (transLessThanFF < 0);
+
+        for (; index < num_palette; index++)
+        {
+                       *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue);
+            palette++;
+        }
+
+               // see BUGGY IMAGE WORKAROUND comment above
+               if (num_palette < 256)
+                       colorPtr[num_palette] = colorPtr[num_palette - 1];
+
+               colorTable->unlockColors(true);
+               bm->setColorTable(colorTable)->unref();
+               (void)autoDel.detach();
+       }
+
+       SkBitmap::Config        config;
+
+       if (color_type == PNG_COLOR_TYPE_PALETTE)
+               config = SkBitmap::kIndex8_Config;
+       else
+    {
+        png_color_16p   transColor;
+        
+               if (png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &transColor))
+        {
+            SkDEBUGF(("********************* png_get_tRNS [%d %d %d]\n", transColor->red, transColor->green, transColor->blue));
+        }
+
+        if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ||  color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+        {
+                       hasAlpha = true;
+            config = SkBitmap::kARGB_8888_Config;
+        }
+        else    // we get to choose the config
+        {
+            config = prefConfig;
+            if (config == SkBitmap::kNo_Config)
+                config = SkImageDecoder::GetDeviceConfig();
+            // only 565 or 8888 are "natural" if we have the choice
+            if (config != SkBitmap::kRGB_565_Config)
+                config = SkBitmap::kARGB_8888_Config;
+        }
+    }
+
+       bm->setConfig(config, width, height, 0);
+       bm->allocPixels();
+
+       /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
+//     if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+//             ; // png_set_swap_alpha(png_ptr);
+
+       /* swap bytes of 16 bit files to least significant byte first */
+       //   png_set_swap(png_ptr);
+
+       /* Add filler (or alpha) byte (before/after each RGB triplet) */
+       if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY)
+               png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
+
+       /* Turn on interlace handling.  REQUIRED if you are not using
+       * png_read_image().  To see how to handle interlacing passes,
+       * see the png_read_row() method below:
+       */
+       int number_passes = interlace_type != PNG_INTERLACE_NONE ? 
+               png_set_interlace_handling(png_ptr) : 1;
+
+       /* Optional call to gamma correct and add the background to the palette
+       * and update info structure.  REQUIRED if you are expecting libpng to
+       * update the palette for you (ie you selected such a transform above).
+       */
+       png_read_update_info(png_ptr, info_ptr);
+
+    uint32_t* tmpStorage = nil;
+    if (config == SkBitmap::kRGB_565_Config)
+    {
+        SkASSERT(!hasAlpha);
+        tmpStorage = (uint32_t*)sk_malloc_throw(bm->rowBytes() * 2);
+    }
+
+       /* The other way to read images - deal with interlacing: */
+       for (int pass = 0; pass < number_passes; pass++)
+       {
+               /* Read the image a single row at a time */
+               for (png_uint_32 y = 0; y < height; y++)
+               {
+                       switch (config) {
+            case SkBitmap::kRGB_565_Config: // good place to consider cary's even/odd dither
+                               {
+                                       uint32_t* tmp = tmpStorage;
+                    uint16_t* dstRow = bm->getAddr16(0, y);
+                                       png_read_rows(png_ptr, (uint8_t**)&tmp, png_bytepp_NULL, 1);
+
+                    /*  PNG's argb now needs to be set to the correct byte order for us, and match our alpha-byte
+                        convention of either 0xFF for opaque, or premul the rgb components
+                    */
+                    for (png_uint_32 x = 0; x < width; x++) {
+                        uint32_t color = tmpStorage[x];
+#ifdef TEST_DITHER
+                        if (SkShouldDitherXY(x, y)) {
+        #ifdef SK_CPU_BENDIAN
+                            unsigned r = (color >> 24) & 0xFF;
+                            unsigned g = (color >> 16) & 0xFF;
+                            unsigned b = (color >>  8) & 0xFF;
+        #else          
+                            unsigned r = (color >>  0) & 0xFF;
+                            unsigned g = (color >>  8) & 0xFF;
+                            unsigned b = (color >> 16) & 0xFF;
+        #endif
+                            dstRow[x] = SkDitherPack888ToRGB16(r, g, b);
+                        }
+                        else {  // fall through to non TEST_DITHER code
+#endif
+    #ifdef SK_CPU_BENDIAN
+                        unsigned r = (color >> 27) & 0x1F;
+                        unsigned g = (color >> 18) & 0x3F;
+                        unsigned b = (color >> 11) & 0x1F;
+    #else      
+                        unsigned r = (color >>  3) & 0x1F;
+                        unsigned g = (color >> 10) & 0x3F;
+                        unsigned b = (color >> 19) & 0x1F;
+    #endif
+                        dstRow[x] = SkPackRGB16(r, g, b);
+#ifdef TEST_DITHER
+                    }   // else clause for shouldditherxy
+#endif
+                    }   // for-loop
+                               }
+                               break;
+                       case SkBitmap::kARGB_8888_Config:
+                               {
+                                       uint32_t* bmRow = bm->getAddr32(0, y);
+                    uint32_t* origRow = bmRow;
+                                       png_read_rows(png_ptr, (uint8_t**)&bmRow, png_bytepp_NULL, 1);
+
+                    /*  PNG's argb now needs to be set to the correct byte order for us, and match our alpha-byte
+                        convention of either 0xFF for opaque, or premul the rgb components
+                    */
+
+                    if (hasAlpha) {   // premul the RGB components
+                        for (png_uint_32 x = 0; x < width; x++) {
+                            uint32_t color = origRow[x];
+                            unsigned a = (color >> 24) & 0xFF;
+                            unsigned b = (color >> 16) & 0xFF;
+                            unsigned c = (color >>  8) & 0xFF;
+                            unsigned d = (color >>  0) & 0xFF;
+                            
+#ifdef SK_CPU_BENDIAN
+                            origRow[x] = SkPreMultiplyARGB(d, a, b, c);
+                            reallyHasAlpha |= (d != 0xFF);
+#else          
+                            origRow[x] = SkPreMultiplyARGB(a, d, c, b);
+                            reallyHasAlpha |= (a != 0xFF);
+#endif
+                        }
+                    }
+                    else {  // jam in 0xFF for the alpha values
+                        for (png_uint_32 x = 0; x < width; x++) {
+                            uint32_t color = origRow[x];
+#ifdef SK_CPU_BENDIAN
+                            unsigned a = (color >> 24) & 0xFF;
+                            unsigned b = (color >> 16) & 0xFF;
+                            unsigned c = (color >>  8) & 0xFF;
+                            origRow[x] = SkPackARGB32(0xFF, a, b, c);
+#else          
+                            unsigned b = (color >> 16) & 0xFF;
+                            unsigned c = (color >>  8) & 0xFF;
+                            unsigned d = (color >>  0) & 0xFF;
+                            origRow[x] = SkPackARGB32(0xFF, d, c, b);
+#endif
+                        }
+                    }
+                               }
+                               break;
+                       case SkBitmap::kIndex8_Config:
+                               {
+                                       uint8_t*         bmRow = bm->getAddr8(0, y);
+                                       png_read_rows(png_ptr, (uint8_t**) &bmRow, png_bytepp_NULL, 1);
+                               }
+                               break;
+                       default:        // to avoid warnings
+                               break;
+                       }
+               }
+       }
+    
+    if (hasAlpha && !reallyHasAlpha) {
+        SkDEBUGF(("Image doesn't really have alpha [%d %d]\n", width, height));
+        if (config == SkBitmap::kARGB_8888_Config && prefConfig != SkBitmap::kARGB_8888_Config)
+            convert_from_32_to_16(bm);
+    }
+    bm->setIsOpaque(!reallyHasAlpha);
+
+    sk_free(tmpStorage);
+
+       /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
+       png_read_end(png_ptr, info_ptr);
+
+       return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_SUPPORT_IMAGE_ENCODE
+
+#include "SkColorPriv.h"
+
+static void sk_error_fn(png_structp png_ptr, png_const_charp msg)
+{
+    SkDEBUGF(("SkPNGImageEncoder::onEncode error: %s\n", msg));
+}
+
+static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+       SkWStream* sk_stream = (SkWStream*)png_ptr->io_ptr;
+       if (!sk_stream->write(data, length))
+        png_error(png_ptr, "sk_write_fn Error!");
+}
+
+typedef void (*transform_scanline_proc)(const char src[], int width, char dst[]);
+
+static void transform_scanline_565(const char src[], int width, char dst[])
+{
+    const uint16_t* srcP = (const uint16_t*)src;    
+    for (int i = 0; i < width; i++)
+    {
+        unsigned c = *srcP++;
+        *dst++ = SkPacked16ToR32(c);
+        *dst++ = SkPacked16ToG32(c);
+        *dst++ = SkPacked16ToB32(c);
+    }
+}
+
+static void transform_scanline_888(const char src[], int width, char dst[])
+{
+    const SkPMColor* srcP = (const SkPMColor*)src;    
+    for (int i = 0; i < width; i++)
+    {
+        SkPMColor c = *srcP++;
+        *dst++ = SkGetPackedR32(c);
+        *dst++ = SkGetPackedG32(c);
+        *dst++ = SkGetPackedB32(c);
+    }
+}
+
+static char unpremul(unsigned v, unsigned alpha)
+{
+    if (alpha == 0)
+        return 0;
+
+    if (alpha == 255)
+        return v;
+
+    return v * 255 / alpha;
+}
+
+static void transform_scanline_8888(const char src[], int width, char dst[])
+{
+    const SkPMColor* srcP = (const SkPMColor*)src;    
+    for (int i = 0; i < width; i++)
+    {
+        SkPMColor c = *srcP++;
+        unsigned alpha = SkGetPackedA32(c);
+        
+        *dst++ = unpremul(SkGetPackedR32(c), alpha);
+        *dst++ = unpremul(SkGetPackedG32(c), alpha);
+        *dst++ = unpremul(SkGetPackedB32(c), alpha);
+        *dst++ = (char)alpha;
+    }
+}
+
+static transform_scanline_proc choose_proc(SkBitmap::Config config, bool hasAlpha)
+{
+    static const struct {
+        SkBitmap::Config        fConfig;
+        bool                    fHasAlpha;
+        transform_scanline_proc fProc;
+    } gMap[] = {
+        { SkBitmap::kRGB_565_Config,    false,  transform_scanline_565 },
+        { SkBitmap::kARGB_8888_Config,  false,  transform_scanline_888 },
+        { SkBitmap::kARGB_8888_Config,  true,   transform_scanline_8888 }
+    };
+
+    for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i)
+        if (gMap[i].fConfig == config && gMap[i].fHasAlpha == hasAlpha)
+            return gMap[i].fProc;
+
+    sk_throw();
+    return nil;
+}
+
+class SkPNGImageEncoder : public SkImageEncoder {
+protected:
+       virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
+};
+
+bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, int /*quality*/)
+{
+    SkBitmap::Config config = bitmap.getConfig();
+    
+    if (config != SkBitmap::kARGB_8888_Config &&
+        config != SkBitmap::kRGB_565_Config)
+    {
+        SkDEBUGF(("SkPNGImageEncoder::onEncode can't encode %d config\n", config));
+        return false;
+    }
+
+    png_structp png_ptr;
+    png_infop info_ptr;
+
+    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn, NULL);
+    if (png_ptr == NULL)
+        return false;
+
+    info_ptr = png_create_info_struct(png_ptr);
+    if (info_ptr == NULL)
+    {
+        png_destroy_write_struct(&png_ptr,  png_infopp_NULL);
+        return false;
+    }
+
+    /* Set error handling.  REQUIRED if you aren't supplying your own
+    * error handling functions in the png_create_write_struct() call.
+    */
+    if (setjmp(png_jmpbuf(png_ptr)))
+    {
+        png_destroy_write_struct(&png_ptr, &info_ptr);
+        return false;
+    }
+
+    png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, png_flush_ptr_NULL);
+
+    /* Set the image information here.  Width and height are up to 2^31,
+    * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
+    * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
+    * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
+    * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
+    * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
+    * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
+    */
+    
+    bool hasAlpha = (config == SkBitmap::kARGB_8888_Config) && !bitmap.isOpaque();
+
+    png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(), 8,
+                 hasAlpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
+                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+#if 0
+    /* set the palette if there is one.  REQUIRED for indexed-color images */
+    palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH
+             * png_sizeof (png_color));
+    /* ... set palette colors ... */
+    png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH);
+    /* You must not free palette here, because png_set_PLTE only makes a link to
+      the palette that you malloced.  Wait until you are about to destroy
+      the png structure. */
+#endif
+
+    {
+        png_color_8 sig_bit;
+        if (config == SkBitmap::kRGB_565_Config)
+        {
+            sig_bit.red = 5;
+            sig_bit.green = 6;
+            sig_bit.blue = 5;
+        }
+        else
+        {
+            sig_bit.red = 8;
+            sig_bit.green = 8;
+            sig_bit.blue = 8;
+            if (hasAlpha)
+                sig_bit.alpha = 8;
+        }
+        png_set_sBIT(png_ptr, info_ptr, &sig_bit);
+    }
+
+    png_write_info(png_ptr, info_ptr);
+
+    const char*             srcImage = (const char*)bitmap.getPixels();
+    char*                   storage = (char*)sk_malloc_throw(bitmap.width() << 2);
+    transform_scanline_proc proc = choose_proc(config, hasAlpha);
+
+    for (unsigned y = 0; y < bitmap.height(); y++)
+    {
+        png_bytep row_ptr = (png_bytep)storage;
+        proc(srcImage, bitmap.width(), storage);
+        png_write_rows(png_ptr, &row_ptr, 1);
+        srcImage += bitmap.rowBytes();
+    }
+    sk_free(storage);
+
+    png_write_end(png_ptr, info_ptr);
+
+#if 0
+    /* If you png_malloced a palette, free it here (don't free info_ptr->palette,
+      as recommended in versions 1.0.5m and earlier of this example; if
+      libpng mallocs info_ptr->palette, libpng will free it).  If you
+      allocated it with malloc() instead of png_malloc(), use free() instead
+      of png_free(). */
+    png_free(png_ptr, palette);
+#endif
+
+    /* clean up after the write, and free any memory allocated */
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+    return true;
+}
+
+SkImageEncoder* sk_create_png_encoder();
+SkImageEncoder* sk_create_png_encoder()
+{
+    return SkNEW(SkPNGImageEncoder);
+}
+
+#endif /* SK_SUPPORT_IMAGE_ENCODE */
+
+
diff --git a/libs/graphics/images/SkStream.cpp b/libs/graphics/images/SkStream.cpp
new file mode 100644 (file)
index 0000000..49984d1
--- /dev/null
@@ -0,0 +1,585 @@
+#include "SkStream.h"
+#include "SkFixed.h"
+#include "SkString.h"
+#include "SkOSFile.h"
+
+const char* SkStream::getFileName()
+{
+       // override in subclass if you represent a file
+       return NULL;
+}
+
+static const char gPrefix[] = "file:\0" "http:\0" "https:\0" "ftp:\0"  ;
+
+bool SkStream::IsAbsoluteURI(const char path[])
+{
+       int prefix = SkStrStartsWithOneOf(path, gPrefix);
+       if (prefix >= 0)
+               return true;
+       return path[0] != '.';
+}
+
+SkStream* SkStream::GetURIStream(const char prefix[], const char path[])
+{
+       int index = SkStrStartsWithOneOf(path, gPrefix);
+       if (prefix && prefix[0] && index < 0)
+       {
+               SkString fullPath(prefix);
+               fullPath.append(path);
+               return GetURIStream(NULL, fullPath.c_str());
+       }
+       if (index > 0)
+         return SkNEW_ARGS(SkURLStream, (path));
+       if (index == 0)
+               path += 5;
+    return SkNEW_ARGS(SkFILEStream, (path));   
+}
+
+SkWStream::~SkWStream()
+{
+}
+
+void SkWStream::newline()
+{
+       this->write("\n", 1);
+}
+
+void SkWStream::flush()
+{
+}
+
+bool SkWStream::writeText(const char text[])
+{
+       SkASSERT(text);
+       return this->write(text, strlen(text));
+}
+
+bool SkWStream::writeDecAsText(S32 dec)
+{
+       SkString        tmp;
+       tmp.appendS32(dec);
+       return this->write(tmp.c_str(), tmp.size());
+}
+
+bool SkWStream::writeHexAsText(U32 hex, int digits)
+{
+       SkString        tmp;
+       tmp.appendHex(hex, digits);
+       return this->write(tmp.c_str(), tmp.size());
+}
+
+bool SkWStream::writeScalarAsText(SkScalar value)
+{
+       SkString        tmp;
+       tmp.appendScalar(value);
+       return this->write(tmp.c_str(), tmp.size());
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+SkFILEStream::SkFILEStream(const char file[]) : fName(file)
+{
+#ifdef SK_BUILD_FOR_BREW
+       if (SkStrEndsWith(fName.c_str(), ".xml"))
+               fName.writable_str()[fName.size()-3] = 'b';
+#endif
+
+       fFILE = file ? sk_fopen(fName.c_str(), kRead_SkFILE_Flag) : NULL;
+}
+
+SkFILEStream::~SkFILEStream()
+{
+       if (fFILE)
+               sk_fclose(fFILE);
+}
+
+void SkFILEStream::setPath(const char path[])
+{
+       fName.set(path);
+#ifdef SK_BUILD_FOR_BREW
+       if (SkStrEndsWith(fName.c_str(), ".xml"))
+               fName.writable_str()[fName.size()-3] = 'b';
+#endif
+
+       if (fFILE)
+       {
+               sk_fclose(fFILE);
+               fFILE = NULL;
+       }
+       if (path)
+               fFILE = sk_fopen(fName.c_str(), kRead_SkFILE_Flag);
+}
+
+const char* SkFILEStream::getFileName()
+{
+       return fName.c_str();
+}
+
+bool SkFILEStream::rewind()
+{
+       if (fFILE)
+       {
+               if (sk_frewind(fFILE))
+                       return true;
+               // we hit an error
+               sk_fclose(fFILE);
+               fFILE = NULL;
+       }
+       return false;
+}
+
+size_t SkFILEStream::read(void* buffer, size_t size)
+{
+       if (fFILE)
+       {
+#if 1
+               if (buffer == NULL && size == 0)        // funny, they want the size I think
+                       return sk_fgetsize(fFILE);
+               return sk_fread(buffer, size, fFILE);
+#else
+               if (buffer)
+               {
+                       size_t bytes = sk_fread(buffer, size, fFILE);
+                       if (ferror(fFILE) == 0)
+                               return bytes;
+               }
+               else
+               {
+                       if (size == 0 && ::fseek(fFILE, 0, SEEK_END) == 0) 
+                       {
+                               size = ::ftell(fFILE);
+                               ::fseek(fFILE, 0, SEEK_SET);
+                               return size;
+                       } 
+                       else if (::fseek(fFILE, (long)size, SEEK_CUR) == 0)
+                               return size;
+               }
+#endif
+       }
+       return 0;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+SkMemoryStream::SkMemoryStream(const void* src, size_t size)
+       : fSrc(src), fSize(size)
+{
+       fOffset = 0;
+}
+
+bool SkMemoryStream::rewind()
+{
+       fOffset = 0;
+       return true;
+}
+
+size_t SkMemoryStream::read(void* buffer, size_t size)
+{
+    // if buffer is NULL, seek ahead by size
+
+       if (size == 0)
+               return 0;
+       if (size > fSize - fOffset)
+               size = fSize - fOffset;
+       if (buffer) {
+        memcpy(buffer, (const char*)fSrc + fOffset, size);
+    }
+       fOffset += size;
+       return size;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+SkBufferStream::SkBufferStream(SkStream& proxy, size_t bufferSize)
+       : fProxy(proxy)
+{
+       SkASSERT(&proxy != NULL);
+       this->init(NULL, bufferSize);
+}
+
+SkBufferStream::SkBufferStream(SkStream& proxy, void* buffer, size_t bufferSize)
+       : fProxy(proxy)
+{
+       SkASSERT(&proxy != NULL);
+       SkASSERT(buffer == NULL || bufferSize != 0);    // init(addr, 0) makes no sense, we must know how big their buffer is
+
+       this->init(buffer, bufferSize);
+}
+
+void SkBufferStream::init(void* buffer, size_t bufferSize)
+{
+       if (bufferSize == 0)
+               bufferSize = kDefaultBufferSize;
+
+       fOrigBufferSize = bufferSize;
+       fBufferSize = bufferSize;
+       fBufferOffset = bufferSize;     // to trigger a reload on the first read()
+
+       if (buffer == NULL)
+       {
+               fBuffer = (char*)sk_malloc_throw(fBufferSize);
+               fWeOwnTheBuffer = true;
+       }
+       else
+       {
+               fBuffer = (char*)buffer;
+               fWeOwnTheBuffer = false;
+       }
+}
+
+SkBufferStream::~SkBufferStream()
+{
+       if (fWeOwnTheBuffer)
+               sk_free(fBuffer);
+}
+
+bool SkBufferStream::rewind()
+{
+       fBufferOffset = fBufferSize = fOrigBufferSize;
+       return fProxy.rewind();
+}
+
+const char* SkBufferStream::getFileName()
+{
+       return fProxy.getFileName();
+}
+
+#ifdef SK_DEBUG
+//     #define SK_TRACE_BUFFERSTREAM
+#endif
+
+size_t SkBufferStream::read(void* buffer, size_t size)
+{
+#ifdef SK_TRACE_BUFFERSTREAM
+       SkDebugf("Request %d", size);
+#endif
+       if (buffer == NULL || size == 0)
+       {
+               fBufferOffset += size;
+               return fProxy.read(buffer, size);
+       }
+
+       size_t s = size;
+       size_t actuallyRead = 0;
+
+       // flush what we can from our fBuffer
+       if (fBufferOffset < fBufferSize)
+       {
+               if (s > fBufferSize - fBufferOffset)
+                       s = fBufferSize - fBufferOffset;
+               memcpy(buffer, fBuffer + fBufferOffset, s);
+#ifdef SK_TRACE_BUFFERSTREAM
+               SkDebugf(" flush %d", s);
+#endif
+               size -= s;
+               fBufferOffset += s;
+               buffer = (char*)buffer + s;
+               actuallyRead = s;
+       }
+
+       // check if there is more to read
+       if (size)
+       {
+               SkASSERT(fBufferOffset >= fBufferSize); // need to refill our fBuffer
+
+               if (size < fBufferSize) // lets try to read more than the request
+               {
+                       s = fProxy.read(fBuffer, fBufferSize);
+#ifdef SK_TRACE_BUFFERSTREAM
+                       SkDebugf(" read %d into fBuffer", s);
+#endif
+                       if (size > s)   // they asked for too much
+                               size = s;
+                       if (size)
+                       {
+                               memcpy(buffer, fBuffer, size);
+                               actuallyRead += size;
+#ifdef SK_TRACE_BUFFERSTREAM
+                               SkDebugf(" memcpy %d into dst", size);
+#endif
+                       }
+
+                       fBufferOffset = size;
+                       fBufferSize = s;                // record the (possibly smaller) size for the buffer
+               }
+               else    // just do a direct read
+               {
+                       actuallyRead += fProxy.read(buffer, size);
+#ifdef SK_TRACE_BUFFERSTREAM
+                       SkDebugf(" direct read %d", size);
+#endif
+               }
+       }
+#ifdef SK_TRACE_BUFFERSTREAM
+       SkDebugf("\n");
+#endif
+       return actuallyRead;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+SkFILEWStream::SkFILEWStream(const char path[])
+{
+       fFILE = sk_fopen(path, kWrite_SkFILE_Flag);
+}
+
+SkFILEWStream::~SkFILEWStream()
+{
+       if (fFILE)
+               sk_fclose(fFILE);
+}
+
+bool SkFILEWStream::write(const void* buffer, size_t size)
+{
+       if (fFILE == NULL)
+               return false;
+
+       if (sk_fwrite(buffer, size, fFILE) != size)
+       {
+               SkDEBUGCODE(SkDebugf("SkFILEWStream failed writing %d bytes\n", size);)
+               sk_fclose(fFILE);
+               fFILE = NULL;
+               return false;
+       }
+       return true;
+}
+
+void SkFILEWStream::flush()
+{
+       if (fFILE)
+               sk_fflush(fFILE);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+SkMemoryWStream::SkMemoryWStream(void* buffer, size_t size)
+    : fBuffer((char*)buffer), fMaxLength(size), fBytesWritten(0)
+{
+}
+
+bool SkMemoryWStream::write(const void* buffer, size_t size)
+{
+    size = SkMin32(size, fMaxLength - fBytesWritten);
+    if (size > 0)
+    {
+        memcpy(fBuffer + fBytesWritten, buffer, size);
+        fBytesWritten += size;
+        return true;
+    }
+    return false;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+#define SkDynamicMemoryWStream_MinBlockSize   256
+
+struct SkDynamicMemoryWStream::Block {
+    Block*  fNext;
+    char*   fCurr;
+    char*   fStop;
+
+    const char* start() const { return (const char*)(this + 1); }
+    char*   start() { return (char*)(this + 1); }
+    size_t  avail() const { return fStop - fCurr; }
+    size_t  written() const { return fCurr - this->start(); }
+    
+    void init(size_t size)
+    {
+        fNext = NULL;
+        fCurr = this->start();
+        fStop = this->start() + size;
+    }
+    
+    const void* append(const void* data, size_t size)
+    {
+        SkASSERT((size_t)(fStop - fCurr) >= size);
+        memcpy(fCurr, data, size);
+        fCurr += size;
+        return (const void*)((const char*)data + size);
+    }
+};
+
+SkDynamicMemoryWStream::SkDynamicMemoryWStream() : fHead(NULL), fTail(NULL), fBytesWritten(0), fCopyToCache(NULL)
+{
+}
+
+SkDynamicMemoryWStream::~SkDynamicMemoryWStream()
+{
+    sk_free(fCopyToCache);
+
+    Block*  block = fHead;
+    
+    while (block != NULL) {
+        Block*  next = block->fNext;
+        sk_free(block);
+        block = next;
+    }
+}
+
+bool SkDynamicMemoryWStream::write(const void* buffer, size_t count)
+{
+    if (count > 0) {
+
+        if (fCopyToCache) {
+            sk_free(fCopyToCache);
+            fCopyToCache = NULL;
+        }
+        fBytesWritten += count;
+        
+        size_t  size;
+        
+        if (fTail != NULL && fTail->avail() > 0) {
+            size = SkMin32(fTail->avail(), count);
+            buffer = fTail->append(buffer, size);
+            SkASSERT(count >= size);
+            count -= size;        
+            if (count == 0)
+                return true;
+        }
+            
+        size = SkMax32(count, SkDynamicMemoryWStream_MinBlockSize);
+        Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size);
+        block->init(size);
+        block->append(buffer, count);
+        
+        if (fTail != NULL)
+            fTail->fNext = block;
+        else
+            fHead = fTail = block;
+        fTail = block;
+    }
+       return true;
+}
+
+bool SkDynamicMemoryWStream::write(const void* buffer, size_t offset, size_t count)
+{
+    if (offset + count > fBytesWritten)
+        return false; // test does not partially modify
+    Block* block = fHead;
+    while (block != NULL) {
+        size_t size = block->written();
+        if (offset < size) {
+            size_t part = offset + count > size ? size - offset : count;
+            memcpy(block->start() + offset, buffer, part);
+            if (count <= part)
+                return true;
+            count -= part;
+            buffer = (const void*) ((char* ) buffer + part);
+        }
+        offset = offset > size ? offset - size : 0;
+        block = block->fNext;
+    }
+    return false;
+}
+
+void SkDynamicMemoryWStream::copyTo(void* dst) const
+{
+    Block* block = fHead;
+    
+    while (block != NULL) {
+        size_t size = block->written();
+        memcpy(dst, block->start(), size);
+        dst = (void*)((char*)dst + size);
+        block = block->fNext;
+    }
+}
+
+const char* SkDynamicMemoryWStream::getStream() const
+{
+    if (fCopyToCache == NULL) {
+        fCopyToCache = (char*)sk_malloc_throw(fBytesWritten);
+        this->copyTo(fCopyToCache);
+    }
+    return fCopyToCache;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void SkDebugWStream::newline()
+{
+#ifdef SK_DEBUG
+       SkDebugf("\n");
+#endif
+}
+
+bool SkDebugWStream::write(const void* buffer, size_t size)
+{
+#ifdef SK_DEBUG
+       char* s = new char[size+1];
+       memcpy(s, buffer, size);
+       s[size] = 0;
+       SkDebugf("%s", s);
+       delete[] s;
+#endif
+       return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+#include "SkRandom.h"
+
+void SkWStream::UnitTest()
+{
+#ifdef SK_SUPPORT_UNITTEST
+       {
+               static const char s[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+               char                    copy[sizeof(s)];
+               SkRandom                rand;
+
+               for (int i = 0; i < 65; i++)
+               {
+                       char*                   copyPtr = copy;
+                       SkMemoryStream  mem(s, sizeof(s));
+                       SkBufferStream  buff(mem, i);
+
+                       do {
+                               copyPtr += buff.read(copyPtr, rand.nextU() & 15);
+                       } while (copyPtr < copy + sizeof(s));
+                       SkASSERT(copyPtr == copy + sizeof(s));
+                       SkASSERT(memcmp(s, copy, sizeof(s)) == 0);
+               }
+       }
+       {
+               SkDebugWStream  s;
+
+               s.writeText("testing wstream helpers\n");
+               s.writeText("compare: 0 ");                     s.writeDecAsText(0);    s.newline();
+               s.writeText("compare: 591 ");           s.writeDecAsText(591);  s.newline();
+               s.writeText("compare: -9125 ");         s.writeDecAsText(-9125);        s.newline();
+               s.writeText("compare: 0 ");                     s.writeHexAsText(0, 0); s.newline();
+               s.writeText("compare: 03FA ");          s.writeHexAsText(0x3FA, 4);     s.newline();
+               s.writeText("compare: DEADBEEF ");      s.writeHexAsText(0xDEADBEEF, 4);        s.newline();
+               s.writeText("compare: 0 ");                     s.writeScalarAsText(SkIntToScalar(0));  s.newline();
+               s.writeText("compare: 27 ");            s.writeScalarAsText(SkIntToScalar(27)); s.newline();
+               s.writeText("compare: -119 ");          s.writeScalarAsText(SkIntToScalar(-119));       s.newline();
+               s.writeText("compare: 851.3333 ");      s.writeScalarAsText(SkIntToScalar(851) + SK_Scalar1/3); s.newline();
+               s.writeText("compare: -0.08 ");         s.writeScalarAsText(-SK_Scalar1*8/100); s.newline();
+       }
+
+    {
+        SkDynamicMemoryWStream  ds;
+        const char s[] = "abcdefghijklmnopqrstuvwxyz";
+        int i;
+        for (i = 0; i < 100; i++) {
+            bool result = ds.write(s, 26);
+            SkASSERT(result);
+        }
+        SkASSERT(ds.getOffset() == 100 * 26);
+        char* dst = new char[100 * 26 + 1];
+        dst[100*26] = '*';
+        ds.copyTo(dst);
+        SkASSERT(dst[100*26] == '*');
+   //     char* p = dst;
+        for (i = 0; i < 100; i++)
+            SkASSERT(memcmp(&dst[i * 26], s, 26) == 0);
+        SkASSERT(memcmp(dst, ds.getStream(), 100*26) == 0);
+        delete[] dst;
+    }
+#endif
+}
+
+#endif
diff --git a/libs/graphics/ports/SkFontHost.cpp b/libs/graphics/ports/SkFontHost.cpp
new file mode 100644 (file)
index 0000000..3a7998a
--- /dev/null
@@ -0,0 +1,272 @@
+#include "SkFontHost.h"
+#include "SkDescriptor.h"
+#include "SkString.h"
+#include <stdio.h>
+
+#ifdef ANDROID
+    #define kFontFilePrefix          "/fonts/"
+#else
+    // this is for our test apps that look directly into the src directory for the fonts
+    #define kFontFilePrefix          "../fonts/"
+#endif
+
+struct FontFaceRec {
+    const char* fFileName;    
+    uint8_t     fFamilyIndex;
+    SkBool8     fBold;
+    SkBool8     fItalic;
+
+    static const FontFaceRec& FindFace(const FontFaceRec rec[], int count, int isBold, int isItalic);
+};
+
+struct FontFamilyRec {
+    const FontFaceRec*  fFaces;
+    int                 fFaceCount;
+};
+
+// export for scalercontext subclass using freetype
+void FontFaceRec_getFileName(const FontFaceRec* face, SkString* name);
+void FontFaceRec_getFileName(const FontFaceRec* face, SkString* name)
+{
+    name->set(getenv("ANDROID_ROOT"));
+    name->append(kFontFilePrefix);
+    name->append(face->fFileName);
+}
+
+const FontFaceRec& FontFaceRec::FindFace(const FontFaceRec rec[], int count, int isBold, int isItalic)
+{
+    SkASSERT(count > 0);
+    
+    int i;
+
+    // look for an exact match
+    for (i = 0; i < count; i++) {
+        if (rec[i].fBold == isBold && rec[i].fItalic == isItalic)
+            return rec[i];
+    }
+    // look for a match in the bold field
+    for (i = 0; i < count; i++) {
+        if (rec[i].fBold == isBold)
+            return rec[i];
+    }
+    // look for a normal/regular face
+    for (i = 0; i < count; i++) {
+        if (!rec[i].fBold && !rec[i].fItalic)
+            return rec[i];
+    }
+    // give up
+    return rec[0];
+}
+
+enum {
+    SANS_FAMILY_INDEX,
+    CJK_FAMILY_INDEX,
+    MONO_FAMILY_INDEX,
+    SERIF_FAMILY_INDEX,
+    DROID_FAMILY_INDEX,
+       DROID_MORE_FAMILY_INDEX,
+       
+    FAMILY_INDEX_COUNT
+};
+
+
+
+static const FontFaceRec gSansFaces[] = {
+//    { "DejaVuSansCondensed.ttf",        SANS_FAMILY_INDEX, 0,  0 },
+//    { "DejaVuSansCondensed-Bold.ttf",   SANS_FAMILY_INDEX, 1,  0 }
+    { "DroidSans_bd100.ttf",        SANS_FAMILY_INDEX, 0,  0 },
+    { "DroidSans-Bold_bd100.ttf",   SANS_FAMILY_INDEX, 1,  0 }
+};
+
+static const FontFaceRec gCJKFaces[] = {
+    { "HeiTBig5_J.otf", CJK_FAMILY_INDEX, 0,  0 }
+};
+
+static const FontFaceRec gSerifFaces[] = {
+    { "DejaVuSerifCondensed.ttf",               SERIF_FAMILY_INDEX, 0,  0 },
+    { "DejaVuSerifCondensed-Bold.ttf",          SERIF_FAMILY_INDEX, 1,  0 },
+    { "DejaVuSerifCondensed-Oblique.ttf",       SERIF_FAMILY_INDEX, 0,  1 },
+    { "DejaVuSerifCondensed-BoldOblique.ttf",   SERIF_FAMILY_INDEX, 1,  1 }
+};
+
+static const FontFaceRec gMonoFaces[] = {
+    { "DejaVuSansMono.ttf", MONO_FAMILY_INDEX, 0,  0 }
+};
+
+static const FontFaceRec gDroidFaces[] = {
+       { "DroidSansLight.ttf",  DROID_FAMILY_INDEX, 0,  0 },
+    { "DroidSans.ttf",        DROID_FAMILY_INDEX, 1,  0 },
+    { "DroidSansDemiBold.ttf",  DROID_FAMILY_INDEX, 0,  1 },
+       { "DroidSans-SemiBold.ttf",   DROID_FAMILY_INDEX, 1,  1 }
+};
+
+static const FontFaceRec gDroidMoreFaces[] = {
+    { "DroidSans-Bold.ttf",   DROID_MORE_FAMILY_INDEX, 0,  0 },
+       { "DroidSansBlack.ttf",  DROID_MORE_FAMILY_INDEX, 1,  0 },
+       { "DroidSerifScotch.ttf", DROID_MORE_FAMILY_INDEX, 0,  1 }
+};
+
+// This table must be in the same order as the ..._FAMILY_INDEX enum specifies
+static const FontFamilyRec gFamilies[] = {
+    { gSansFaces,     SK_ARRAY_COUNT(gSansFaces)  },
+    { gCJKFaces,      SK_ARRAY_COUNT(gCJKFaces)   },
+    { gMonoFaces,     SK_ARRAY_COUNT(gMonoFaces)  },
+    { gSerifFaces,    SK_ARRAY_COUNT(gSerifFaces) },
+       { gDroidFaces,    SK_ARRAY_COUNT(gDroidFaces) },
+       { gDroidMoreFaces,    SK_ARRAY_COUNT(gDroidMoreFaces) }
+};
+
+#define DEFAULT_FAMILY_INDEX            SANS_FAMILY_INDEX
+#define DEFAULT_FAMILY_FACE_INDEX       0
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+/* map common "web" font names to our font list */
+
+struct FontFamilyMatchRec {
+    const char* fLCName;
+    int         fFamilyIndex;
+};
+
+/*  This is a table of synonyms for collapsing font names
+    down to their pseudo-equivalents (i.e. in terms of fonts
+    we actually have.)
+    Keep this sorted by the first field so we can do a binary search.
+    If this gets big, we could switch to a hash...
+*/
+static const FontFamilyMatchRec gMatches[] = {
+    { "arial",              SANS_FAMILY_INDEX },
+    { "courier",            MONO_FAMILY_INDEX },
+    { "courier new",        MONO_FAMILY_INDEX },
+    { "cursive",            SERIF_FAMILY_INDEX },
+    { "dejavu mono",        MONO_FAMILY_INDEX },
+    { "dejavu sans",        SANS_FAMILY_INDEX },
+    { "dejavu serif",       SANS_FAMILY_INDEX },
+       { "droid more",         DROID_MORE_FAMILY_INDEX },
+       { "droid sans",         SANS_FAMILY_INDEX },
+    { "fantasy",            SERIF_FAMILY_INDEX },
+    { "goudy",              SERIF_FAMILY_INDEX },
+    { "helvetica",          SANS_FAMILY_INDEX },
+    { "lucida grande",      SANS_FAMILY_INDEX },
+    { "lucida grande",      MONO_FAMILY_INDEX },
+    { "palatino",           SERIF_FAMILY_INDEX },
+    { "tahoma",             SANS_FAMILY_INDEX },
+    { "sans-serif",         SANS_FAMILY_INDEX },
+    { "serif",              SERIF_FAMILY_INDEX },
+    { "times",              SERIF_FAMILY_INDEX },
+    { "times new roman",    SERIF_FAMILY_INDEX },
+    { "verdana",            SANS_FAMILY_INDEX }
+};
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkTSearch.h"
+
+const FontFamilyRec* find_family_rec(const char target[])
+{
+    size_t  targetLen = strlen(target);
+    int     index;
+
+    // Search for the font by matching the entire name
+    index = SkStrLCSearch(&gMatches[0].fLCName, SK_ARRAY_COUNT(gMatches), target, targetLen, sizeof(gMatches[0]));
+    if (index >= 0)
+        return &gFamilies[gMatches[index].fFamilyIndex];
+
+    // Sniff for key words...
+    // If we converted target to lower-case, these would be simpler/faster...
+
+    if (strstr(target, "sans") || strstr(target, "Sans"))
+        return &gFamilies[SANS_FAMILY_INDEX];
+
+    if (strstr(target, "serif") || strstr(target, "Serif"))
+        return &gFamilies[SERIF_FAMILY_INDEX];
+
+    if (strstr(target, "mono") || strstr(target, "Mono"))
+        return &gFamilies[MONO_FAMILY_INDEX];
+
+    // we give up, just give them the default font
+    return &gFamilies[DEFAULT_FAMILY_INDEX];
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+class FontFaceRec_Typeface : public SkTypeface {
+public:
+    FontFaceRec_Typeface(const FontFaceRec& face) : fFace(face)
+    {
+        int style = 0;
+        if (face.fBold)
+            style |= SkTypeface::kBold;
+        if (face.fItalic)
+            style |= SkTypeface::kItalic;
+        this->setStyle((SkTypeface::Style)style);
+    }
+
+    const FontFaceRec& fFace;
+};
+
+SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, const char familyName[], SkTypeface::Style style)
+{
+    const FontFamilyRec* family;
+    
+    if (familyFace)
+        family = &gFamilies[((FontFaceRec_Typeface*)familyFace)->fFace.fFamilyIndex];
+    else if (familyName)
+        family = find_family_rec(familyName);
+    else
+        family = &gFamilies[DEFAULT_FAMILY_INDEX];
+
+    const FontFaceRec& face = FontFaceRec::FindFace(family->fFaces, family->fFaceCount,
+                                                    (style & SkTypeface::kBold) != 0,
+                                                    (style & SkTypeface::kItalic) != 0);
+
+    // if we're returning our input parameter, no need to create a new instance
+    if (familyFace != nil && &((FontFaceRec_Typeface*)familyFace)->fFace == &face)
+    {
+        familyFace->ref();
+        return (SkTypeface*)familyFace;
+    }
+    return SkNEW_ARGS(FontFaceRec_Typeface, (face));
+}
+
+uint32_t SkFontHost::FlattenTypeface(const SkTypeface* tface, void* buffer)
+{
+    const FontFaceRec* face;
+    
+    if (tface)
+        face = &((const FontFaceRec_Typeface*)tface)->fFace;
+    else
+       face = &gFamilies[DEFAULT_FAMILY_INDEX].fFaces[DEFAULT_FAMILY_FACE_INDEX];
+
+    size_t  size = sizeof(face);
+    if (buffer)
+        memcpy(buffer, &face, size);
+    return size;
+}
+
+SkFontHost::ScalerContextID SkFontHost::FindScalerContextIDForUnichar(int32_t unichar)
+{
+    // when we have more than one fall-back font, will have to do a search based on unichar
+    // to know what index to return (0 means no fall-back can help)
+    
+    // we return the family index+1 to indicate succes, or 0 for failure (no fall-back font)
+    return (ScalerContextID)(CJK_FAMILY_INDEX + 1);
+}
+
+SkScalerContext* SkFontHost::CreateScalerContextFromID(ScalerContextID id, const SkScalerContext::Rec& rec)
+{
+    SkASSERT((int)id > 0 && (int)id < FAMILY_INDEX_COUNT);
+
+    const FontFaceRec* face = &gFamilies[(int)id - 1].fFaces[0];
+
+       SkAutoDescriptor        ad(sizeof(rec) + sizeof(face) + SkDescriptor::ComputeOverhead(2));
+       SkDescriptor*           desc = ad.getDesc();
+
+       desc->init();
+       desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
+    desc->addEntry(kTypeface_SkDescriptorTag, sizeof(face), &face);
+       desc->computeChecksum();
+
+    return SkFontHost::CreateScalerContext(desc);
+}
+
diff --git a/libs/graphics/ports/SkFontHost_FONTPATH.cpp b/libs/graphics/ports/SkFontHost_FONTPATH.cpp
new file mode 100644 (file)
index 0000000..b8a8c5c
--- /dev/null
@@ -0,0 +1,85 @@
+#include "SkFontHost.h"
+#include "SkString.h"
+#include <stdio.h>
+
+//#define SK_FONTPATH "the complete file name for our font"
+
+struct FontFaceRec {
+    const char* fFileName;    
+    uint8_t     fFamilyIndex;
+    SkBool8     fBold;
+    SkBool8     fItalic;
+};
+
+struct FontFamilyRec {
+    const char*         fLCName;
+    const FontFaceRec*  fFaces;
+    int                 fFaceCount;
+};
+
+// export for scalercontext subclass using freetype
+void FontFaceRec_getFileName(const FontFaceRec* face, SkString* name);
+void FontFaceRec_getFileName(const FontFaceRec* face, SkString* name)
+{
+    name->set(SK_FONTPATH);
+}
+
+static const FontFaceRec gArialFaces[] = {
+    { SK_FONTPATH,        0, 0,  0 }
+};
+
+static const FontFamilyRec gFamilies[] = {
+    { "font",  gArialFaces, SK_ARRAY_COUNT(gArialFaces) },
+};
+
+#define DEFAULT_FAMILY_INDEX            0
+#define DEFAULT_FAMILY_FACE_INDEX       0
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+class FontFaceRec_Typeface : public SkTypeface {
+public:
+    FontFaceRec_Typeface(const FontFaceRec& face) : fFace(face)
+    {
+        int style = 0;
+        if (face.fBold)
+            style |= SkTypeface::kBold;
+        if (face.fItalic)
+            style |= SkTypeface::kItalic;
+        this->setStyle((SkTypeface::Style)style);
+    }
+
+    const FontFaceRec& fFace;
+};
+
+SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, const char familyName[], SkTypeface::Style style)
+{
+    return SkNEW_ARGS(FontFaceRec_Typeface, (gFamilies[DEFAULT_FAMILY_INDEX].fFaces[DEFAULT_FAMILY_FACE_INDEX]));
+}
+
+uint32_t SkFontHost::FlattenTypeface(const SkTypeface* tface, void* buffer)
+{
+    const FontFaceRec* face;
+    
+    if (tface)
+        face = &((const FontFaceRec_Typeface*)tface)->fFace;
+    else
+       face = &gFamilies[DEFAULT_FAMILY_INDEX].fFaces[DEFAULT_FAMILY_FACE_INDEX];
+
+    size_t  size = sizeof(face);
+    if (buffer)
+        memcpy(buffer, &face, size);
+    return size;
+}
+
+SkFontHost::ScalerContextID SkFontHost::FindScalerContextIDForUnichar(int32_t unichar)
+{
+    return kMissing_ScalerContextID;   // don't do any font-chaining when we only have 1 font
+}
+
+SkScalerContext* SkFontHost::CreateScalerContextFromID(ScalerContextID, const SkScalerContext::Rec&)
+{
+    SkASSERT(!"Should not be called, since we always return kMissing_ScalerContextID");
+    return NULL;
+}
+
diff --git a/libs/graphics/ports/SkFontHost_FreeType.cpp b/libs/graphics/ports/SkFontHost_FreeType.cpp
new file mode 100644 (file)
index 0000000..418dcd9
--- /dev/null
@@ -0,0 +1,633 @@
+#include "SkScalerContext.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkDescriptor.h"
+#include "SkFDot6.h"
+#include "SkFontHost.h"
+#include "SkString.h"
+#include "SkThread.h"
+#include "SkTemplates.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+#include FT_SIZES_H
+
+//#define ENABLE_GLYPH_SPEW     // for tracing calls to generateMetrics/generateImage
+
+#ifdef SK_DEBUG
+    #define SkASSERT_CONTINUE(pred)                                                         \
+        do {                                                                                \
+            if (!(pred))                                                                    \
+                SkDebugf("file %s:%d: assert failed '" #pred "'\n", __FILE__, __LINE__);    \
+        } while (false)
+#else
+    #define SkASSERT_CONTINUE(pred)
+#endif
+
+//////////////////////////////////////////////////////////////////////////
+
+struct SkFaceRec;
+
+static SkMutex         gFTMutex;
+static int                     gFTCount;
+static FT_Library      gFTLibrary;
+static SkFaceRec*      gFaceRecHead;
+
+/////////////////////////////////////////////////////////////////////////
+
+class SkScalerContext_FreeType : public SkScalerContext {
+public:
+       SkScalerContext_FreeType(const SkDescriptor* desc);
+       virtual ~SkScalerContext_FreeType();
+
+protected:
+       virtual void generateMetrics(SkGlyph* glyph);
+       virtual void generateImage(const SkGlyph& glyph);
+       virtual void generatePath(const SkGlyph& glyph, SkPath* path);
+       virtual void generateLineHeight(SkPoint* ascent, SkPoint* descent);
+
+private:
+    SkFaceRec*  fFaceRec;
+       FT_Face     fFace;              // reference to shared face in gFaceRecHead
+    FT_Size     fFTSize;            // our own copy
+       SkFixed     fScaleX, fScaleY;
+       SkFixed     fMatrix22[2][2];
+    uint32_t    fLoadGlyphFlags;
+
+       FT_Error setupSize();
+};
+
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+
+#include "SkStream.h"
+
+struct SkFaceRec {
+       SkFaceRec*      fNext;
+       FT_Face         fFace;
+       FT_StreamRec    fFTStream;
+       SkFILEStream    fSkStream;
+       uint32_t        fRefCnt;
+       SkString        fFileName;
+
+       SkFaceRec(const char filename[]);    
+    ~SkFaceRec()
+    {
+//        SkDEBUGF(("~SkFaceRec: closing %s\n", fFileName.c_str()));
+    }
+};
+
+extern "C" {
+    static unsigned long sk_stream_read(FT_Stream       stream,
+                                        unsigned long   offset,
+                                        unsigned char*  buffer,
+                                        unsigned long   count )
+    {
+        SkFaceRec* rec = (SkFaceRec*)stream->descriptor.pointer;
+        SkStream* str = &rec->fSkStream;
+
+        if (count)
+        {
+            if (!str->rewind())
+            {
+                SkDEBUGF(("sk_stream_read(file:%s offset:%ld count:%ld): rewind failed\n",
+                               rec->fFileName.c_str(), offset, count));
+                return 0;
+            }
+            else
+            {
+                unsigned long ret;
+                if (offset)
+                {
+                    ret = str->read(nil, offset);
+                    if (ret != offset) {
+                        SkDEBUGF(("sk_stream_read(file:%s offset:%d) read returned %d\n",
+                                  rec->fFileName.c_str(), offset, ret));
+                        return 0;
+                    }
+                }
+                ret = str->read(buffer, count);
+                if (ret != count) {
+                    SkDEBUGF(("sk_stream_read(file:%s offset:%d count:%d) read returned %d\n",
+                             rec->fFileName.c_str(), offset, count, ret));
+                    return 0;
+                }
+                count = ret;
+            }
+        }
+        return count;
+    }
+
+    static void sk_stream_close( FT_Stream stream)
+    {
+    }
+}
+
+SkFaceRec::SkFaceRec(const char filename[]) : fSkStream(filename)
+{
+//    SkDEBUGF(("SkFaceRec: opening %s (%p)\n", filename, fSkStream.getSkFILE()));
+
+    fFileName.set(filename);
+
+    memset(&fFTStream, 0, sizeof(fFTStream));
+    fFTStream.size = fSkStream.read(nil, 0);   // find out how big the file is
+    fFTStream.descriptor.pointer = this;
+    fFTStream.read     = sk_stream_read;
+    fFTStream.close = sk_stream_close;
+}
+
+static SkFaceRec* ref_ft_face(const char filename[], size_t filenameLen)
+{
+       SkFaceRec* rec = gFaceRecHead;
+       while (rec)
+       {
+               if (rec->fFileName.equals(filename, filenameLen))
+               {
+                       SkASSERT(rec->fFace);
+                       rec->fRefCnt += 1;
+                       return rec;
+               }
+               rec = rec->fNext;
+       }
+
+       rec = SkNEW_ARGS(SkFaceRec, (filename));
+
+    FT_Open_Args       args;
+    memset(&args, 0, sizeof(args));
+    args.flags = FT_OPEN_STREAM;
+    args.stream = &rec->fFTStream;
+
+       FT_Error err = FT_Open_Face(gFTLibrary, &args, 0, &rec->fFace);
+
+       if (err)        // bad filename, try the default font
+       {
+               fprintf(stderr, "ERROR: unable to open font '%s'\n", filename);
+               SkDELETE(rec);
+               sk_throw();
+               return 0;
+       }
+       else
+       {
+               SkASSERT(rec->fFace);
+               //fprintf(stderr, "Opened font '%s'\n", filename.c_str());
+               rec->fNext = gFaceRecHead;
+               gFaceRecHead = rec;
+               rec->fRefCnt = 1;
+               return rec;
+       }
+}
+
+static void unref_ft_face(FT_Face face)
+{
+       SkFaceRec*      rec = gFaceRecHead;
+       SkFaceRec*      prev = nil;
+       while (rec)
+       {
+               SkFaceRec* next = rec->fNext;
+               if (rec->fFace == face)
+               {
+                       if (--rec->fRefCnt == 0)
+                       {
+                               if (prev)
+                                       prev->fNext = next;
+                               else
+                                       gFaceRecHead = next;
+
+                               FT_Done_Face(face);
+                               SkDELETE(rec);
+                       }
+                       return;
+               }
+               prev = rec;
+               rec = next;
+       }
+       SkASSERT("shouldn't get here, face not in list");
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+struct FontFaceRec;
+extern void FontFaceRec_getFileName(const FontFaceRec*, SkString*);
+
+SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc)
+       : SkScalerContext(desc), fFTSize(nil)
+{
+    SkAutoMutexAcquire ac(gFTMutex);
+
+       FT_Error        err;
+
+    if (gFTCount == 0)
+    {
+        err = FT_Init_FreeType(&gFTLibrary);
+//        SkDEBUGF(("FT_Init_FreeType returned %d\n", err));
+        SkASSERT(err == 0);
+    }
+    ++gFTCount;
+
+    // load the font file
+    {
+        SkString     fileName;
+        const FontFaceRec** face = (const FontFaceRec**)desc->findEntry(kTypeface_SkDescriptorTag, nil);
+        FontFaceRec_getFileName(*face, &fileName);
+        fFaceRec = ref_ft_face(fileName.c_str(), fileName.size());
+        fFace = fFaceRec ? fFaceRec->fFace : nil;
+    }
+
+       // compute our factors from the record
+
+       SkMatrix        m;
+
+       fRec.getSingleMatrix(&m);
+
+       //      now compute our scale factors
+       SkScalar        sx = m.getScaleX();
+       SkScalar        sy = m.getScaleY();
+
+       if (m.getSkewX() || m.getSkewY() || sx < 0 || sy < 0)   // sort of give up on hinting
+       {
+               sx = SkMaxScalar(SkScalarAbs(sx), SkScalarAbs(m.getSkewX()));
+               sy = SkMaxScalar(SkScalarAbs(m.getSkewY()), SkScalarAbs(sy));
+               sx = sy = SkScalarAve(sx, sy);
+
+               SkScalar inv = SkScalarInvert(sx);
+
+               // flip the skew elements to go from our Y-down system to FreeType's
+               fMatrix22[0][0] = SkScalarToFixed(SkScalarMul(m.getScaleX(), inv));
+               fMatrix22[0][1] = -SkScalarToFixed(SkScalarMul(m.getSkewX(), inv));
+               fMatrix22[1][0] = -SkScalarToFixed(SkScalarMul(m.getSkewY(), inv));
+               fMatrix22[1][1] = SkScalarToFixed(SkScalarMul(m.getScaleY(), inv));
+       }
+       else
+       {
+               fMatrix22[0][0] = fMatrix22[1][1] = SK_Fixed1;
+               fMatrix22[0][1] = fMatrix22[1][0] = 0;
+       }
+
+       fScaleX = SkScalarToFixed(sx);
+       fScaleY = SkScalarToFixed(sy);
+
+    // compute the flags we send to Load_Glyph
+    {
+        uint32_t flags = 0;
+
+        if (!fRec.fUseHints) {
+            flags |= FT_LOAD_NO_HINTING;
+        }
+        if (!fRec.fDoAA) {
+            flags |= FT_LOAD_TARGET_MONO;
+        }
+        fLoadGlyphFlags = flags;
+    }
+    
+    // now create the FT_Size
+
+    {    
+        FT_Error       err;
+
+        err = FT_New_Size(fFace, &fFTSize);
+        if (err != 0) {
+            SkDEBUGF(("SkScalerContext_FreeType::FT_New_Size(%s): FT_Set_Char_Size(0x%x, 0x%x) returned 0x%x\n",
+                        fFaceRec->fFileName.c_str(), fScaleX, fScaleY, err));
+            fFace = nil;
+            return;
+        }
+        
+        err = FT_Activate_Size(fFTSize);
+        if (err != 0) {
+            SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%s, 0x%x, 0x%x) returned 0x%x\n",
+                        fFaceRec->fFileName.c_str(), fScaleX, fScaleY, err));
+            fFTSize = nil;
+        }
+
+        err = FT_Set_Char_Size(        fFace,
+                                SkFixedToFDot6(fScaleX), SkFixedToFDot6(fScaleY),
+                                72, 72);
+        if (err != 0) {
+            SkDEBUGF(("SkScalerContext_FreeType::FT_Set_Char_Size(%s, 0x%x, 0x%x) returned 0x%x\n",
+                        fFaceRec->fFileName.c_str(), fScaleX, fScaleY, err));
+            fFace = nil;
+            return;
+        }
+
+//        SkDEBUGF(("FT_Set_Transform %p %p %p [%x %x %x %x]\n", this, fFace, fFTSize,
+//                    fMatrix22[0][0], fMatrix22[0][1], fMatrix22[1][0], fMatrix22[1][1]));
+        // not sure if I need this here, given that I redo it in setup()
+        FT_Set_Transform( fFace, (FT_Matrix*)&fMatrix22, nil);
+    }
+}
+
+SkScalerContext_FreeType::~SkScalerContext_FreeType()
+{
+    if (fFTSize != nil)
+        FT_Done_Size(fFTSize);
+
+       SkAutoMutexAcquire      ac(gFTMutex);
+
+    if (fFace != nil)
+        unref_ft_face(fFace);
+
+       if (--gFTCount == 0)
+       {
+//        SkDEBUGF(("FT_Done_FreeType\n"));
+               FT_Done_FreeType(gFTLibrary);
+               SkDEBUGCODE(gFTLibrary = nil;)
+       }
+}
+
+/*     We call this before each use of the fFace, since we may be sharing
+       this face with other context (at different sizes).
+*/
+FT_Error SkScalerContext_FreeType::setupSize()
+{
+       FT_Error        err = FT_Activate_Size(fFTSize);
+
+    if (err != 0) {
+        SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%s, 0x%x, 0x%x) returned 0x%x\n",
+                    fFaceRec->fFileName.c_str(), fScaleX, fScaleY, err));
+        fFTSize = nil;
+    }
+    else
+    {
+        // seems we need to reset this every time (not sure why, but without it
+        // I get random italics from some other fFTSize)
+        FT_Set_Transform( fFace, (FT_Matrix*)&fMatrix22, nil);
+    }
+    return err;
+}
+
+void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph)
+{
+#if 0
+    {
+        static bool gOnce = true;
+        if (gOnce) {
+            gOnce = false;
+            for (int i = 403; i < fFace->num_glyphs; i++) {
+                FT_Error err = FT_Load_Glyph( fFace, i, fLoadGlyphFlags );
+                if (err != 0) {
+                    printf("FT_Load_Glyph[%d] returned %d\n", i, err);
+                }
+            }
+        }
+    }
+#endif
+
+    SkAutoMutexAcquire ac(gFTMutex);
+
+       FT_Error        err;
+
+       if (this->setupSize())
+        goto ERROR;
+
+       glyph->fGlyphID = SkToU16(FT_Get_Char_Index( fFace, glyph->fCharCode ));
+
+       err = FT_Load_Glyph( fFace, glyph->fGlyphID, fLoadGlyphFlags );
+       if (err != 0)
+       {
+        SkDEBUGF(("SkScalerContext_FreeType::generateMetrics(%s): FT_Load_Glyph(char:%d glyph:%d flags:%d) returned 0x%x\n",
+                    fFaceRec->fFileName.c_str(), glyph->fCharCode, glyph->fGlyphID, fLoadGlyphFlags, err));
+    ERROR:
+               glyph->fWidth   = 0;
+               glyph->fHeight  = 0;
+               glyph->fTop             = 0;
+               glyph->fLeft    = 0;
+               glyph->fAdvanceX = 0;
+               glyph->fAdvanceY = 0;
+        return;
+       }
+    
+    switch ( fFace->glyph->format )
+    {
+      case FT_GLYPH_FORMAT_OUTLINE:
+        FT_BBox bbox;
+        
+        FT_Outline_Get_CBox(&fFace->glyph->outline, &bbox);
+        bbox.xMin &= ~63;
+        bbox.yMin &= ~63;
+        bbox.xMax  = (bbox.xMax + 63) & ~63;
+        bbox.yMax  = (bbox.yMax + 63) & ~63;
+
+        glyph->fWidth  = SkToU16((bbox.xMax - bbox.xMin) >> 6);
+        glyph->fHeight = SkToU16((bbox.yMax - bbox.yMin) >> 6);
+        glyph->fTop            = -SkToS16(bbox.yMax >> 6);
+        glyph->fLeft   = SkToS16(bbox.xMin >> 6);
+        break;
+        
+      case FT_GLYPH_FORMAT_BITMAP:
+        glyph->fWidth  = SkToU16(fFace->glyph->bitmap.width);
+        glyph->fHeight = SkToU16(fFace->glyph->bitmap.rows);
+        glyph->fTop            = -SkToS16(fFace->glyph->bitmap_top);
+        glyph->fLeft   = SkToS16(fFace->glyph->bitmap_left);
+        break;
+
+      default:
+        SkASSERT(!"unknown glyph format");
+        goto ERROR;      
+    }
+    
+       if (fRec.fUseHints)
+       {
+               glyph->fAdvanceX = SkFDot6ToFixed(fFace->glyph->advance.x);
+               glyph->fAdvanceY = -SkFDot6ToFixed(fFace->glyph->advance.y);
+       }
+       else
+       {
+               glyph->fAdvanceX = SkFixedMul(fMatrix22[0][0], fFace->glyph->linearHoriAdvance);
+               glyph->fAdvanceY = -SkFixedMul(fMatrix22[1][0], fFace->glyph->linearHoriAdvance);
+       }
+
+#ifdef ENABLE_GLYPH_SPEW
+    SkDEBUGF(("FT_Set_Char_Size(this:%p sx:%x sy:%x ", this, fScaleX, fScaleY));
+    SkDEBUGF(("Metrics(glyph:%d flags:0x%x) w:%d\n", glyph->fGlyphID, fLoadGlyphFlags, glyph->fWidth));
+#endif
+}
+
+void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph)
+{
+    SkAutoMutexAcquire ac(gFTMutex);
+
+       FT_Error        err;
+
+       if (this->setupSize())
+        goto ERROR;
+
+       err = FT_Load_Glyph( fFace, glyph.fGlyphID, fLoadGlyphFlags);
+    if (err != 0) {
+        SkDEBUGF(("SkScalerContext_FreeType::generateImage: FT_Load_Glyph(char:%d glyph:%d width:%d height:%d rb:%d flags:%d) returned 0x%x\n",
+                    glyph.fCharCode, glyph.fGlyphID, glyph.fWidth, glyph.fHeight, glyph.fRowBytes, fLoadGlyphFlags, err));
+    ERROR:
+        memset(glyph.fImage, 0, glyph.fRowBytes * glyph.fHeight);
+        return;
+    }
+
+    switch ( fFace->glyph->format ) {
+    case FT_GLYPH_FORMAT_OUTLINE:
+        {
+            FT_Outline* outline = &fFace->glyph->outline;
+            FT_BBox     bbox;
+            FT_Bitmap   target;
+            
+            FT_Outline_Get_CBox(outline, &bbox);
+            FT_Outline_Translate(outline, -(bbox.xMin & ~63), -(bbox.yMin & ~63));
+
+            target.width = glyph.fWidth;
+            target.rows = glyph.fHeight;
+            target.pitch = glyph.fRowBytes;
+            target.buffer = reinterpret_cast<uint8_t*>(glyph.fImage);
+            target.pixel_mode = fRec.fDoAA ? FT_PIXEL_MODE_GRAY : FT_PIXEL_MODE_MONO;
+            target.num_grays = 256;
+            
+            memset(glyph.fImage, 0, glyph.fRowBytes * glyph.fHeight);
+            FT_Outline_Get_Bitmap(gFTLibrary, outline, &target);
+        }
+        break;
+    
+    case FT_GLYPH_FORMAT_BITMAP:
+        SkASSERT_CONTINUE(glyph.fWidth == fFace->glyph->bitmap.width);
+        SkASSERT_CONTINUE(glyph.fHeight == fFace->glyph->bitmap.rows);
+        SkASSERT_CONTINUE(glyph.fTop == -fFace->glyph->bitmap_top);
+        SkASSERT_CONTINUE(glyph.fLeft == fFace->glyph->bitmap_left);
+
+        {
+            const U8*  src = (const U8*)fFace->glyph->bitmap.buffer;
+            U8*                        dst = (U8*)glyph.fImage;
+            unsigned   srcRowBytes = fFace->glyph->bitmap.pitch;
+            unsigned   dstRowBytes = glyph.fRowBytes;
+            unsigned    minRowBytes = SkMin32(srcRowBytes, dstRowBytes);
+            unsigned    extraRowBytes = dstRowBytes - minRowBytes;
+
+            for (int y = fFace->glyph->bitmap.rows - 1; y >= 0; --y)
+            {
+                memcpy(dst, src, minRowBytes);
+                memset(dst + minRowBytes, 0, extraRowBytes);
+                src += srcRowBytes;
+                dst += dstRowBytes;
+            }
+        }
+        break;
+    
+    default:
+        SkASSERT(!"unknown glyph format");
+        goto ERROR;
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#define ft2sk(x)       SkFixedToScalar((x) << 10)
+
+static int move_proc(FT_Vector* pt, void* ctx)
+{
+       SkPath* path = (SkPath*)ctx;
+       path->close();  // to close the previous contour (if any)
+       path->moveTo(ft2sk(pt->x), -ft2sk(pt->y));
+       return 0;
+}
+
+static int line_proc(FT_Vector* pt, void* ctx)
+{
+       SkPath* path = (SkPath*)ctx;
+       path->lineTo(ft2sk(pt->x), -ft2sk(pt->y));
+       return 0;
+}
+
+static int quad_proc(FT_Vector* pt0, FT_Vector* pt1, void* ctx)
+{
+       SkPath* path = (SkPath*)ctx;
+       path->quadTo(ft2sk(pt0->x), -ft2sk(pt0->y), ft2sk(pt1->x), -ft2sk(pt1->y));
+       return 0;
+}
+
+static int cubic_proc(FT_Vector* pt0, FT_Vector* pt1, FT_Vector* pt2, void* ctx)
+{
+       SkPath* path = (SkPath*)ctx;
+       path->cubicTo(ft2sk(pt0->x), -ft2sk(pt0->y), ft2sk(pt1->x), -ft2sk(pt1->y), ft2sk(pt2->x), -ft2sk(pt2->y));
+       return 0;
+}
+
+void SkScalerContext_FreeType::generatePath(const SkGlyph& glyph, SkPath* path)
+{
+    SkAutoMutexAcquire ac(gFTMutex);
+
+       SkASSERT(&glyph && path);
+
+       if (this->setupSize()) {
+        path->reset();
+        return;
+    }
+
+       U32 flags = fLoadGlyphFlags;
+    flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
+    flags &= ~FT_LOAD_RENDER;   // don't scan convert (we just want the outline)
+
+       FT_Error err = FT_Load_Glyph( fFace, glyph.fGlyphID, flags);
+
+    if (err != 0) {
+        SkDEBUGF(("SkScalerContext_FreeType::generatePath: FT_Load_Glyph(char:%d glyph:%d flags:%d) returned 0x%x\n",
+                    glyph.fCharCode, glyph.fGlyphID, flags, err));
+        path->reset();
+        return;
+    }
+
+       FT_Outline_Funcs        funcs;
+
+       funcs.move_to   = move_proc;
+       funcs.line_to   = line_proc;
+       funcs.conic_to  = quad_proc;
+       funcs.cubic_to  = cubic_proc;
+       funcs.shift             = 0;
+       funcs.delta             = 0;
+
+       err = FT_Outline_Decompose(&fFace->glyph->outline, &funcs, path);
+
+    if (err != 0) {
+        SkDEBUGF(("SkScalerContext_FreeType::generatePath: FT_Load_Glyph(char:%d glyph:%d flags:%d) returned 0x%x\n",
+                    glyph.fCharCode, glyph.fGlyphID, flags, err));
+        path->reset();
+        return;
+    }
+
+       path->close();
+}
+
+static void map_y_to_pt(const FT_Matrix& mat, SkFixed y, SkPoint* pt)
+{
+       SkFixed x = SkFixedMul(mat.xy, y);
+       y = SkFixedMul(mat.yy, y);
+
+       pt->set(SkFixedToScalar(x), SkFixedToScalar(y));
+}
+
+void SkScalerContext_FreeType::generateLineHeight(SkPoint* ascent, SkPoint* descent)
+{
+    SkAutoMutexAcquire ac(gFTMutex);
+
+       if (this->setupSize()) {
+        if (ascent)
+            ascent->set(0, 0);
+        if (descent)
+            descent->set(0, 0);
+        return;
+    }
+
+       if (ascent)
+       {
+               SkFixed a = SkMulDiv(fScaleY, -fFace->ascender, fFace->units_per_EM);
+               map_y_to_pt(*(FT_Matrix*)fMatrix22, a, ascent);
+       }
+       if (descent)
+       {
+               SkFixed d = SkMulDiv(fScaleY, -fFace->descender, fFace->units_per_EM);
+               map_y_to_pt(*(FT_Matrix*)fMatrix22, d, descent);
+       }
+}
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+
+SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc)
+{
+       return SkNEW_ARGS(SkScalerContext_FreeType, (desc));
+}
+
diff --git a/libs/graphics/ports/SkFontHost_none.cpp b/libs/graphics/ports/SkFontHost_none.cpp
new file mode 100644 (file)
index 0000000..c9231cf
--- /dev/null
@@ -0,0 +1,33 @@
+#include "SkFontHost.h"
+
+SkTypeface* SkFontHost::CreateTypeface( const SkTypeface* familyFace,
+                                        const char familyName[],
+                                        SkTypeface::Style style)
+{
+    SkASSERT(!"SkFontHost::CreateTypeface unimplemented");
+    return nil;
+}
+
+uint32_t SkFontHost::FlattenTypeface(const SkTypeface* tface, void* buffer)
+{
+    SkASSERT(!"SkFontHost::FlattenTypeface unimplemented");
+    return 0;
+}
+
+SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc)
+{
+    SkASSERT(!"SkFontHost::CreateScalarContext unimplemented");
+    return nil;
+}
+
+SkFontHost::ScalerContextID SkFontHost::FindScalerContextIDForUnichar(int32_t unichar)
+{
+    SkASSERT(!"SkFontHost::FindScalerContextIDForUnichar unimplemented");
+    return kMissing_ScalerContextID;
+}
+
+SkScalerContext* SkFontHost::CreateScalerContextFromID(SkFontHost::ScalerContextID id, const SkScalerContext::Rec& rec)
+{
+    SkASSERT(!"SkFontHost::CreateScalerContextFromID unimplemented");
+    return nil;
+}
diff --git a/libs/graphics/ports/SkGlobals_global.cpp b/libs/graphics/ports/SkGlobals_global.cpp
new file mode 100644 (file)
index 0000000..2143b59
--- /dev/null
@@ -0,0 +1,11 @@
+#include "SkGlobals.h"
+#include "SkThread.h"
+
+static SkGlobals::BootStrap    gBootStrap;
+
+SkGlobals::BootStrap& SkGlobals::GetBootStrap()
+{
+       return gBootStrap;
+}
+
+
diff --git a/libs/graphics/ports/SkImageDecoder_Factory.cpp b/libs/graphics/ports/SkImageDecoder_Factory.cpp
new file mode 100644 (file)
index 0000000..3cec85a
--- /dev/null
@@ -0,0 +1,28 @@
+#include "SkImageDecoder.h"
+#include "SkStream.h"
+
+/*  Each of these is in their respective SkImageDecoder_libXXX.cpp file
+*/
+extern SkImageDecoder* SkImageDecoder_GIF_Factory(SkStream*);
+extern SkImageDecoder* SkImageDecoder_JPEG_Factory(SkStream*);
+extern SkImageDecoder* SkImageDecoder_PNG_Factory(SkStream*);
+
+typedef SkImageDecoder* (*SkImageDecoderFactoryProc)(SkStream*);
+
+static const SkImageDecoderFactoryProc gProc[] = {
+    SkImageDecoder_GIF_Factory,
+    SkImageDecoder_PNG_Factory,
+    SkImageDecoder_JPEG_Factory // JPEG must be last, as it doesn't have a sniffer/detector yet
+};
+
+SkImageDecoder* SkImageDecoder::Factory(SkStream* stream)
+{
+    for (unsigned i = 0; i < SK_ARRAY_COUNT(gProc); i++) {
+        SkImageDecoder* codec = gProc[i](stream);
+        if (codec)
+            return codec;
+        stream->rewind();
+    }
+       return NULL;
+}
+
diff --git a/libs/graphics/ports/SkOSEvent_android.cpp b/libs/graphics/ports/SkOSEvent_android.cpp
new file mode 100644 (file)
index 0000000..9c7360f
--- /dev/null
@@ -0,0 +1,138 @@
+#include "SkEvent.h"
+#include "utils/threads.h"
+#include <stdio.h>
+
+using namespace android;
+
+Mutex gEventQMutex;
+Condition gEventQCondition;
+
+void SkEvent::SignalNonEmptyQueue()
+{
+       gEventQCondition.broadcast();
+}
+
+///////////////////////////////////////////////////////////////////
+
+#ifdef FMS_ARCH_ANDROID_ARM
+
+// don't have pthreads.h, and therefore no timedwait(), so we punt for the demo
+
+void SkEvent::SignalQueueTimer(SkMSec delay)
+{
+}
+
+void SkEvent_start_timer_thread()
+{
+}
+
+void SkEvent_stop_timer_thread()
+{
+}
+
+#else
+
+#include <pthread.h>
+#include <errno.h>
+
+static pthread_t               gTimerThread;
+static pthread_mutex_t gTimerMutex;
+static pthread_cond_t  gTimerCond;
+static timespec                        gTimeSpec;
+
+static void* timer_event_thread_proc(void*)
+{
+       for (;;)
+       {
+               int status;
+               
+               pthread_mutex_lock(&gTimerMutex);
+
+               timespec spec = gTimeSpec;
+               // mark our global to be zero
+               // so we don't call timedwait again on a stale value
+               gTimeSpec.tv_sec = 0;
+               gTimeSpec.tv_nsec = 0;
+
+               if (spec.tv_sec == 0 && spec.tv_nsec == 0)
+                       status = pthread_cond_wait(&gTimerCond, &gTimerMutex);
+               else
+                       status = pthread_cond_timedwait(&gTimerCond, &gTimerMutex, &spec);
+               
+               if (status == 0)        // someone signaled us with a new time
+               {
+                       pthread_mutex_unlock(&gTimerMutex);
+               }
+               else
+               {
+                       SkASSERT(status == ETIMEDOUT);  // no need to unlock the mutex (its unlocked)
+                       // this is the payoff. Signal the event queue to wake up
+                       // and also check the delay-queue
+                       gEventQCondition.broadcast();
+               }
+       }
+       return 0;
+}
+
+#define kThousand      (1000)
+#define kMillion       (kThousand * kThousand)
+#define kBillion       (kThousand * kThousand * kThousand)
+
+void SkEvent::SignalQueueTimer(SkMSec delay)
+{
+       pthread_mutex_lock(&gTimerMutex);
+
+       if (delay)
+       {
+               struct timeval tv;
+               gettimeofday(&tv, nil);
+
+               // normalize tv
+               if (tv.tv_usec >= kMillion)
+               {
+                       tv.tv_sec += tv.tv_usec / kMillion;
+                       tv.tv_usec %= kMillion;
+               }
+
+               // add tv + delay, scale each up to land on nanoseconds
+               gTimeSpec.tv_nsec       = (tv.tv_usec + (delay % kThousand) * kThousand) * kThousand;
+               gTimeSpec.tv_sec        = (tv.tv_sec + (delay / kThousand) * kThousand) * kThousand;
+               
+               // check for overflow in nsec
+               if ((unsigned long)gTimeSpec.tv_nsec >= kBillion)
+               {
+                       gTimeSpec.tv_nsec -= kBillion;
+                       gTimeSpec.tv_sec += 1;
+                       SkASSERT((unsigned long)gTimeSpec.tv_nsec < kBillion);
+               }
+
+       //      printf("SignalQueueTimer(%d) timespec(%d %d)\n", delay, gTimeSpec.tv_sec, gTimeSpec.tv_nsec);
+       }
+       else    // cancel the timer
+       {
+               gTimeSpec.tv_nsec = 0;
+               gTimeSpec.tv_sec = 0;
+       }
+
+       pthread_mutex_unlock(&gTimerMutex);
+       pthread_cond_signal(&gTimerCond);
+}
+
+void SkEvent_start_timer_thread()
+{
+       int                             status;
+       pthread_attr_t  attr;
+       
+       status = pthread_attr_init(&attr);
+       SkASSERT(status == 0);
+       status = pthread_create(&gTimerThread, &attr, timer_event_thread_proc, 0);
+       SkASSERT(status == 0);
+}
+
+void SkEvent_stop_timer_thread()
+{
+       int status = pthread_cancel(gTimerThread);
+       SkASSERT(status == 0);
+}
+
+#endif
diff --git a/libs/graphics/ports/SkOSEvent_dummy.cpp b/libs/graphics/ports/SkOSEvent_dummy.cpp
new file mode 100644 (file)
index 0000000..1c6e188
--- /dev/null
@@ -0,0 +1,11 @@
+#include "SkEvent.h"
+
+void SkEvent::SignalNonEmptyQueue()
+{
+
+}
+
+void SkEvent::SignalQueueTimer(SkMSec delay)
+{
+
+}
diff --git a/libs/graphics/ports/SkOSFile_stdio.cpp b/libs/graphics/ports/SkOSFile_stdio.cpp
new file mode 100644 (file)
index 0000000..686ae52
--- /dev/null
@@ -0,0 +1,83 @@
+#include "SkOSFile.h"
+
+#ifndef SK_BUILD_FOR_BREW
+
+#include <stdio.h>
+
+SkFILE* sk_fopen(const char path[], SkFILE_Flags flags)
+{
+       char    perm[4];
+       char*   p = perm;
+
+       if (flags & kRead_SkFILE_Flag)
+               *p++ = 'r';
+       if (flags & kWrite_SkFILE_Flag)
+               *p++ = 'w';
+       *p++ = 'b';
+       *p = 0;
+
+       return (SkFILE*)::fopen(path, perm);
+}
+
+size_t sk_fgetsize(SkFILE* f)
+{
+       SkASSERT(f);
+
+       size_t  curr = ::ftell((FILE*)f);               // remember where we are
+       ::fseek((FILE*)f, 0, SEEK_END);                 // go to the end
+       size_t size = ::ftell((FILE*)f);                // record the size
+       ::fseek((FILE*)f, (long)curr, SEEK_SET);                // go back to our prev loc
+       return size;
+}
+
+bool sk_frewind(SkFILE* f)
+{
+       SkASSERT(f);
+    ::rewind((FILE*)f);
+//     ::fseek((FILE*)f, 0, SEEK_SET);
+       return true;
+}
+
+size_t sk_fread(void* buffer, size_t byteCount, SkFILE* f)
+{
+       SkASSERT(f);
+       if (buffer == nil)
+       {
+               size_t curr = ::ftell((FILE*)f);
+        if ((long)curr == -1) {
+            SkDEBUGF(("sk_fread: ftell(%p) returned -1 feof:%d ferror:%d\n", f, ::feof((FILE*)f), ::ferror((FILE*)f)));
+            return 0;
+        }
+       //      ::fseek((FILE*)f, (long)(curr + byteCount), SEEK_SET);
+        int err = ::fseek((FILE*)f, (long)byteCount, SEEK_CUR);
+        if (err != 0) {
+            SkDEBUGF(("sk_fread: fseek(%d) tell:%d failed with feof:%d ferror:%d returned:%d\n",
+                        byteCount, curr, ::feof((FILE*)f), ::ferror((FILE*)f), err));
+            return 0;
+        }
+               return byteCount;
+       }
+       else
+               return ::fread(buffer, 1, byteCount, (FILE*)f);
+}
+
+size_t sk_fwrite(const void* buffer, size_t byteCount, SkFILE* f)
+{
+       SkASSERT(f);
+       return ::fwrite(buffer, 1, byteCount, (FILE*)f);
+}
+
+void sk_fflush(SkFILE* f)
+{
+       SkASSERT(f);
+       ::fflush((FILE*)f);
+}
+
+void sk_fclose(SkFILE* f)
+{
+       SkASSERT(f);
+       ::fclose((FILE*)f);
+}
+
+#endif
+
diff --git a/libs/graphics/ports/SkThread_none.cpp b/libs/graphics/ports/SkThread_none.cpp
new file mode 100644 (file)
index 0000000..39ce355
--- /dev/null
@@ -0,0 +1,32 @@
+#include "SkThread.h"
+
+int32_t sk_atomic_inc(int32_t* addr)
+{
+    int32_t value = *addr;
+    *addr = value + 1;
+    return value;
+}
+
+int32_t sk_atomic_dec(int32_t* addr)
+{
+    int32_t value = *addr;
+    *addr = value - 1;
+    return value;
+}
+
+SkMutex::SkMutex()
+{
+}
+
+SkMutex::~SkMutex()
+{
+}
+
+void SkMutex::acquire()
+{
+}
+
+void SkMutex::release()
+{
+}
+
diff --git a/libs/graphics/ports/SkTime_Unix.cpp b/libs/graphics/ports/SkTime_Unix.cpp
new file mode 100644 (file)
index 0000000..6a0dda1
--- /dev/null
@@ -0,0 +1,33 @@
+#include "SkTime.h"
+
+#if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_MAC)
+#include <sys/time.h>
+#include <time.h>
+
+void SkTime::GetDateTime(DateTime* dt)
+{
+       if (dt)
+       {
+    time_t m_time;
+    time(&m_time);
+    struct tm* tstruct;
+    tstruct = localtime(&m_time);
+
+               dt->fYear               = tstruct->tm_year;
+               dt->fMonth              = SkToU8(tstruct->tm_mon + 1);
+               dt->fDayOfWeek  = SkToU8(tstruct->tm_wday);
+               dt->fDay                = SkToU8(tstruct->tm_mday);
+               dt->fHour               = SkToU8(tstruct->tm_hour);
+               dt->fMinute             = SkToU8(tstruct->tm_min);
+               dt->fSecond             = SkToU8(tstruct->tm_sec);
+       }
+}
+
+SkMSec SkTime::GetMSecs()
+{
+  struct timeval tv;
+  gettimeofday(&tv, nil);
+  return (SkMSec) (tv.tv_sec * 1000 + tv.tv_usec / 1000 ); // microseconds to milliseconds
+}
+
+#endif
diff --git a/libs/graphics/ports/SkXMLParser_empty.cpp b/libs/graphics/ports/SkXMLParser_empty.cpp
new file mode 100644 (file)
index 0000000..b808b49
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright Skia Inc. 2004 - 2005
+// 
+#include "SkXMLParser.h"
+
+bool SkXMLParser::parse(SkStream& docStream)
+{
+       return false;
+}
+
+bool SkXMLParser::parse(const char doc[], size_t len)
+{
+       return false;
+}
+
+void SkXMLParser::GetNativeErrorString(int error, SkString* str)
+{
+
+}
+
diff --git a/libs/graphics/ports/SkXMLParser_expat.cpp b/libs/graphics/ports/SkXMLParser_expat.cpp
new file mode 100644 (file)
index 0000000..7e31947
--- /dev/null
@@ -0,0 +1,132 @@
+#include "SkXMLParser.h"
+#include "SkString.h"
+#include "SkStream.h"
+
+#include "expat.h"
+
+#ifdef SK_BUILD_FOR_PPI
+#define CHAR_16_TO_9
+#endif
+
+#if defined CHAR_16_TO_9
+inline size_t sk_wcslen(const short* char16) {
+       const short* start = char16;
+       while (*char16)
+               char16++;
+       return char16 - start;
+}
+
+inline const char* ConvertUnicodeToChar(const short* ch16, size_t len, SkAutoMalloc& ch8Malloc) {
+       char* ch8 = (char*) ch8Malloc.get();
+       int index;
+       for (index = 0; index < len; index++) 
+               ch8[index] = (char) ch16[index];
+       ch8[index] = '\0';
+       return ch8;
+}
+#endif
+
+static void XMLCALL start_proc(void *data, const char *el, const char **attr)
+{
+#if defined CHAR_16_TO_9
+       size_t len = sk_wcslen((const short*) el);
+       SkAutoMalloc    el8(len + 1);
+       el = ConvertUnicodeToChar((const short*) el, len, el8);
+#endif
+       if (((SkXMLParser*)data)->startElement(el)) {
+               XML_StopParser((XML_Parser) ((SkXMLParser*)data)->fParser, false);
+               return;
+       }
+       while (*attr)
+       {
+               const char* attr0 = attr[0];
+               const char* attr1 = attr[1];
+#if defined CHAR_16_TO_9
+               size_t len0 = sk_wcslen((const short*) attr0);
+               SkAutoMalloc    attr0_8(len0 + 1);
+               attr0 = ConvertUnicodeToChar((const short*) attr0, len0, attr0_8);
+               size_t len1 = sk_wcslen((const short*) attr1);
+               SkAutoMalloc    attr1_8(len1 + 1);
+               attr1 = ConvertUnicodeToChar((const short*) attr1, len1, attr1_8);
+#endif
+               if (((SkXMLParser*)data)->addAttribute(attr0, attr1)) {
+                       XML_StopParser((XML_Parser) ((SkXMLParser*)data)->fParser, false);
+                       return;
+               }
+               attr += 2;
+       }
+}
+
+static void XMLCALL end_proc(void *data, const char *el)
+{
+#if defined CHAR_16_TO_9
+       size_t len = sk_wcslen((const short*) el);
+       SkAutoMalloc    el8(len + 1);
+       el = ConvertUnicodeToChar((const short*) el, len, el8);
+#endif
+       if (((SkXMLParser*)data)->endElement(el))
+               XML_StopParser((XML_Parser) ((SkXMLParser*)data)->fParser, false);
+}
+
+static void XMLCALL text_proc(void* data, const char* text, int len)
+{
+#if defined CHAR_16_TO_9
+       SkAutoMalloc    text8(len + 1);
+       text = ConvertUnicodeToChar((const short*) text, len, text8);
+#endif
+       if (((SkXMLParser*)data)->text(text, len))
+               XML_StopParser((XML_Parser) ((SkXMLParser*)data)->fParser, false);
+}
+
+bool SkXMLParser::parse(const char doc[], size_t len)
+{
+       if (len == 0) {
+               fError->fCode = SkXMLParserError::kEmptyFile;
+               reportError(nil);
+               return false;
+       }
+       XML_Parser p = XML_ParserCreate(NULL);
+       SkASSERT(p);
+       fParser = p;
+       XML_SetElementHandler(p, start_proc, end_proc);
+       XML_SetCharacterDataHandler(p, text_proc);
+       XML_SetUserData(p, this);
+
+       bool success = true;
+       int error = XML_Parse(p, doc, len, true);
+       if (error == XML_STATUS_ERROR) {
+               reportError(p);
+               success = false;
+       }
+       XML_ParserFree(p);
+       return success;
+}
+
+bool SkXMLParser::parse(SkStream& input)
+{
+       size_t                  len = input.read(nil, 0);
+       SkAutoMalloc    am(len);
+       char*                   doc = (char*)am.get();
+
+       input.rewind();
+       size_t  len2 = input.read(doc, len);
+       SkASSERT(len2 == len);
+
+       return this->parse(doc, len2);
+}
+
+void SkXMLParser::reportError(void* p)
+{
+       XML_Parser parser = (XML_Parser) p;
+       if (fError && parser) {
+               fError->fNativeCode = XML_GetErrorCode(parser);
+               fError->fLineNumber = XML_GetCurrentLineNumber(parser);
+       }
+}
+
+void SkXMLParser::GetNativeErrorString(int error, SkString* str)
+{
+       if (str)
+               str->set(XML_ErrorString((XML_Error) error));
+}
+
diff --git a/libs/graphics/ports/SkXMLParser_tinyxml.cpp b/libs/graphics/ports/SkXMLParser_tinyxml.cpp
new file mode 100644 (file)
index 0000000..bbea8e2
--- /dev/null
@@ -0,0 +1,79 @@
+#include "SkXMLParser.h"
+#include "SkStream.h"
+#include "SkTemplates.h"
+#include "tinyxml.h"
+
+static void walk_elem(SkXMLParser* parser, const TiXmlElement* elem)
+{
+       //printf("walk_elem(%s) ", elem->Value());
+
+       parser->startElement(elem->Value());
+
+       const TiXmlAttribute* attr = elem->FirstAttribute();
+       while (attr)
+       {
+               //printf("walk_elem_attr(%s=\"%s\") ", attr->Name(), attr->Value());
+       
+               parser->addAttribute(attr->Name(), attr->Value());
+               attr = attr->Next();
+       }
+       //printf("\n");
+       
+       const TiXmlNode* node = elem->FirstChild();
+       while (node)
+       {
+               if (node->ToElement())
+                       walk_elem(parser, node->ToElement());
+               else if (node->ToText())
+                       parser->text(node->Value(), strlen(node->Value()));
+               node = node->NextSibling();
+       }
+       
+       parser->endElement(elem->Value());
+}
+
+static bool load_buf(SkXMLParser* parser, const char buf[])
+{
+       TiXmlDocument                                   doc;
+
+       (void)doc.Parse(buf);
+       if (doc.Error())
+       {
+               printf("tinyxml error: <%s> row[%d] col[%d]\n", doc.ErrorDesc(), doc.ErrorRow(), doc.ErrorCol());
+               return false;
+       }
+       
+       walk_elem(parser, doc.RootElement());
+       return true;
+}
+
+bool SkXMLParser::parse(SkStream& stream)
+{
+       size_t size = stream.read(nil, 0);
+       
+       SkAutoMalloc    buffer(size + 1);
+       char*                   buf = (char*)buffer.get();
+       
+       stream.read(buf, size);
+       buf[size] = 0;
+       
+       return load_buf(this, buf);
+}
+
+bool SkXMLParser::parse(const char doc[], size_t len)
+{
+       SkAutoMalloc    buffer(len + 1);
+       char*                   buf = (char*)buffer.get();
+       
+       memcpy(buf, doc, len);
+       buf[len] = 0;
+       
+       return load_buf(this, buf);
+}
+
+void SkXMLParser::GetNativeErrorString(int error, SkString* str)
+{
+       if (str)
+               str->set("GetNativeErrorString not implemented for TinyXml");
+}
+
diff --git a/libs/graphics/sgl/SkAlphaRuns.cpp b/libs/graphics/sgl/SkAlphaRuns.cpp
new file mode 100644 (file)
index 0000000..891774f
--- /dev/null
@@ -0,0 +1,168 @@
+#include "SkAntiRun.h"
+
+void SkAlphaRuns::reset(int width)
+{
+       SkASSERT(width > 0);
+
+       fRuns[0] = SkToS16(width);
+       fRuns[width] = 0;
+       fAlpha[0] = 0;
+
+       SkDEBUGCODE(fWidth = width;)
+       SkDEBUGCODE(this->validate();)
+}
+
+void SkAlphaRuns::Break(S16 runs[], U8 alpha[], int x, int count)
+{
+       SkASSERT(count > 0 && x >= 0);
+
+//     SkAlphaRuns::BreakAt(runs, alpha, x);
+//     SkAlphaRuns::BreakAt(&runs[x], &alpha[x], count);
+
+       S16* next_runs = runs + x;
+       U8*      next_alpha = alpha + x;
+
+       while (x > 0)
+       {
+               int     n = runs[0];
+               SkASSERT(n > 0);
+
+               if (x < n)
+               {
+                       alpha[x] = alpha[0];
+                       runs[0] = SkToS16(x);
+                       runs[x] = SkToS16(n - x);
+                       break;
+               }
+               runs += n;
+               alpha += n;
+               x -= n;
+       }
+
+       runs = next_runs;
+       alpha = next_alpha;
+       x = count;
+
+       for (;;)
+       {
+               int     n = runs[0];
+               SkASSERT(n > 0);
+
+               if (x < n)
+               {
+                       alpha[x] = alpha[0];
+                       runs[0] = SkToS16(x);
+                       runs[x] = SkToS16(n - x);
+                       break;
+               }
+               x -= n;
+               if (x <= 0)
+                       break;
+
+               runs += n;
+               alpha += n;
+       }
+}
+
+void SkAlphaRuns::add(int x, U8CPU startAlpha, int middleCount, U8CPU stopAlpha, U8CPU maxValue)
+{
+       SkASSERT(middleCount >= 0);
+       SkASSERT(x >= 0 && x + (startAlpha != 0) + middleCount + (stopAlpha != 0) <= fWidth);
+
+       S16*    runs = fRuns;
+       U8*             alpha = fAlpha;
+
+       if (startAlpha)
+       {
+               SkAlphaRuns::Break(runs, alpha, x, 1);
+               /*      I should be able to just add alpha[x] + startAlpha.
+                       However, if the trailing edge of the previous span and the leading
+                       edge of the current span round to the same super-sampled x value,
+                       I might overflow to 256 with this add, hence the funny subtract (crud).
+               */
+               unsigned tmp = alpha[x] + startAlpha;
+               SkASSERT(tmp <= 256);
+               alpha[x] = SkToU8(tmp - (tmp >> 8));    // was (tmp >> 7), but that seems wrong if we're trying to catch 256
+
+               runs += x + 1;
+               alpha += x + 1;
+               x = 0;
+               SkDEBUGCODE(this->validate();)
+       }
+       if (middleCount)
+       {
+               SkAlphaRuns::Break(runs, alpha, x, middleCount);
+               alpha += x;
+               runs += x;
+               x = 0;
+               do {
+                       alpha[0] = SkToU8(alpha[0] + maxValue);
+                       int n = runs[0];
+                       SkASSERT(n <= middleCount);
+                       alpha += n;
+                       runs += n;
+                       middleCount -= n;
+               } while (middleCount > 0);
+               SkDEBUGCODE(this->validate();)
+       }
+       if (stopAlpha)
+       {
+               SkAlphaRuns::Break(runs, alpha, x, 1);
+               alpha[x] = SkToU8(alpha[x] + stopAlpha);
+               SkDEBUGCODE(this->validate();)
+       }
+}
+
+#ifdef SK_DEBUG
+       void SkAlphaRuns::assertValid(int y, int maxStep) const
+       {
+               int max = (y + 1) * maxStep - (y == maxStep - 1);
+
+               const S16* runs = fRuns;
+               const U8*       alpha = fAlpha;
+
+               while (*runs)
+               {
+                       SkASSERT(*alpha <= max);
+                       alpha += *runs;
+                       runs += *runs;
+               }
+       }
+
+       void SkAlphaRuns::dump() const
+       {
+               const S16* runs = fRuns;
+               const U8* alpha = fAlpha;
+
+               SkDebugf("Runs");
+               while (*runs)
+               {
+                       int n = *runs;
+
+                       SkDebugf(" %02x", *alpha);
+                       if (n > 1)
+                               SkDebugf(",%d", n);
+                       alpha += n;
+                       runs += n;
+               }
+               SkDebugf("\n");
+       }
+
+       void SkAlphaRuns::validate() const
+       {
+               SkASSERT(fWidth > 0);
+
+               int                     count = 0;
+               const S16*      runs = fRuns;
+
+               while (*runs)
+               {
+                       SkASSERT(*runs > 0);
+                       count += *runs;
+                       SkASSERT(count <= fWidth);
+                       runs += *runs;
+               }
+               SkASSERT(count == fWidth);
+       }
+#endif
+
diff --git a/libs/graphics/sgl/SkAntiRun.h b/libs/graphics/sgl/SkAntiRun.h
new file mode 100644 (file)
index 0000000..43d502f
--- /dev/null
@@ -0,0 +1,168 @@
+#ifndef SkAntiRun_DEFINED
+#define SkAntiRun_DEFINED
+
+#include "SkBlitter.h"
+
+inline int sk_make_nonzero_neg_one(int x)
+{
+       return (x | -x) >> 31;
+}
+
+#if 0
+template <int kShift> class SkAntiRun {
+       static U8 coverage_to_alpha(int aa)
+       {
+               aa <<= 8 - 2*kShift;
+               aa -= aa >> (8 - kShift - 1);
+               return SkToU8(aa);
+       }
+public:
+       void set(int start, int stop)
+       {
+               SkASSERT(start >= 0 && stop > start);
+
+#if 1
+               int     fb = start & kMask;
+               int fe = stop & kMask;
+               int     n = (stop >> kShift) - (start >> kShift) - 1;
+
+               if (n < 0)
+               {
+                       fb = fe - fb;
+                       n = 0;
+                       fe = 0;
+               }
+               else
+               {
+                       if (fb == 0)
+                               n += 1;
+                       else
+                               fb = (1 << kShift) - fb;
+               }
+
+               fStartAlpha = coverage_to_alpha(fb);
+               fMiddleCount = n;
+               fStopAlpha = coverage_to_alpha(fe);
+#else
+               int     x0 = start >> kShift;
+               int x1 = (stop - 1) >> kShift;
+               int middle = x1 - x0;
+               int aa;
+
+               if (middle == 0)
+               {
+                       aa = stop - start;
+                       aa <<= 8 - 2*kShift;
+                       aa -= aa >> (8 - kShift - 1);
+                       SkASSERT(aa > 0 && aa < kMax);
+                       fStartAlpha = SkToU8(aa);
+                       fMiddleCount = 0;
+                       fStopAlpha = 0;
+               }
+               else
+               {
+                       int aa = start & kMask;
+                       aa <<= 8 - 2*kShift;
+                       aa -= aa >> (8 - kShift - 1);
+                       SkASSERT(aa >= 0 && aa < kMax);
+                       if (aa)
+                               fStartAlpha = SkToU8(kMax - aa);
+                       else
+                       {
+                               fStartAlpha = 0;
+                               middle += 1;
+                       }
+                       aa = stop & kMask;
+                       aa <<= 8 - 2*kShift;
+                       aa -= aa >> (8 - kShift - 1);
+                       SkASSERT(aa >= 0 && aa < kMax);
+                       middle += sk_make_nonzero_neg_one(aa);
+
+                       fStopAlpha = SkToU8(aa);
+                       fMiddleCount = middle;
+               }
+               SkASSERT(fStartAlpha < kMax);
+               SkASSERT(fStopAlpha < kMax);
+#endif
+       }
+
+       void blit(int x, int y, SkBlitter* blitter)
+       {
+               S16     runs[2];
+               runs[0] = 1;
+               runs[1] = 0;
+
+               if (fStartAlpha)
+               {
+                       blitter->blitAntiH(x, y, &fStartAlpha, runs);
+                       x += 1;
+               }
+               if (fMiddleCount)
+               {
+                       blitter->blitH(x, y, fMiddleCount);
+                       x += fMiddleCount;
+               }
+               if (fStopAlpha)
+                       blitter->blitAntiH(x, y, &fStopAlpha, runs);
+       }
+
+       U8      getStartAlpha() const { return fStartAlpha; }
+       int     getMiddleCount() const { return fMiddleCount; }
+       U8      getStopAlpha() const { return fStopAlpha; }
+
+private:
+       U8      fStartAlpha, fStopAlpha;
+       int     fMiddleCount;
+
+       enum {
+               kMask = (1 << kShift) - 1,
+               kMax = (1 << (8 - kShift)) - 1
+       };
+};
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////
+
+class SkAlphaRuns {
+public:
+       S16*    fRuns;
+       U8*             fAlpha;
+
+       bool    empty() const
+       {
+               SkASSERT(fRuns[0] > 0);
+               return fAlpha[0] == 0 && fRuns[fRuns[0]] == 0;
+       }
+       void    reset(int width);
+       void    add(int x, U8CPU startAlpha, int middleCount, U8CPU stopAlpha, U8CPU maxValue);
+       SkDEBUGCODE(void assertValid(int y, int maxStep) const;)
+       SkDEBUGCODE(void dump() const;)
+
+       static void Break(S16 runs[], U8 alpha[], int x, int count);
+       static void BreakAt(S16 runs[], U8 alpha[], int x)
+       {
+               while (x > 0)
+               {
+                       int     n = runs[0];
+                       SkASSERT(n > 0);
+
+                       if (x < n)
+                       {
+                               alpha[x] = alpha[0];
+                               runs[0] = SkToS16(x);
+                               runs[x] = SkToS16(n - x);
+                               break;
+                       }
+                       runs += n;
+                       alpha += n;
+                       x -= n;
+               }
+       }
+
+private:
+       SkDEBUGCODE(int fWidth;)
+       SkDEBUGCODE(void validate() const;)
+};
+
+#endif
+
diff --git a/libs/graphics/sgl/SkBitmap.cpp b/libs/graphics/sgl/SkBitmap.cpp
new file mode 100644 (file)
index 0000000..a2ea623
--- /dev/null
@@ -0,0 +1,412 @@
+#include "SkBitmap.h"
+#include "SkColorPriv.h"
+#include "SkUtils.h"
+
+SkBitmap::SkBitmap()
+{
+       memset(this, 0, sizeof(*this));
+}
+
+SkBitmap::SkBitmap(const SkBitmap& src)
+{
+       src.fColorTable->safeRef();
+
+       memcpy(this, &src, sizeof(src));
+       fFlags &= ~(kWeOwnThePixels_Flag | kWeOwnTheMipMap_Flag);
+}
+
+SkBitmap::~SkBitmap()
+{
+       fColorTable->safeUnref();
+       this->freePixels();
+}
+
+SkBitmap& SkBitmap::operator=(const SkBitmap& src)
+{
+       src.fColorTable->safeRef();
+       fColorTable->safeUnref();
+
+       this->freePixels();
+       memcpy(this, &src, sizeof(src));
+       fFlags &= ~(kWeOwnThePixels_Flag | kWeOwnTheMipMap_Flag);
+
+       return *this;
+}
+
+void SkBitmap::swap(SkBitmap& other)
+{
+       SkTSwap<SkColorTable*>(fColorTable, other.fColorTable);
+
+#ifdef SK_SUPPORT_MIPMAP
+       SkTSwap<MipMap*>(fMipMap, other.fMipMap);
+#endif
+
+       SkTSwap<void*>(fPixels, other.fPixels);
+       SkTSwap<U16>(fWidth, other.fWidth);
+       SkTSwap<U16>(fHeight, other.fHeight);
+       SkTSwap<U16>(fRowBytes, other.fRowBytes);
+       SkTSwap<U8>(fConfig, other.fConfig);
+       SkTSwap<U8>(fFlags, other.fFlags);
+}
+
+void SkBitmap::reset()
+{
+       fColorTable->safeUnref();
+       this->freePixels();
+       memset(this, 0, sizeof(*this));
+}
+
+void SkBitmap::setConfig(Config c, U16CPU width, U16CPU height, U16CPU rowBytes)
+{
+       this->freePixels();
+
+       if (rowBytes == 0)
+       {
+               switch (c) {
+               case kA1_Config:
+                       rowBytes = (width + 7) >> 3;
+                       break;
+               case kA8_Config:
+               case kIndex8_Config:
+                       rowBytes = width;
+                       break;
+               case kRGB_565_Config:
+                       rowBytes = SkAlign4(width << 1);
+                       break;
+               case kARGB_8888_Config:
+                       rowBytes = width << 2;
+                       break;
+               default:
+                       SkASSERT(!"unknown config");
+                       break;
+               }
+       }
+
+       fConfig         = SkToU8(c);
+       fWidth          = SkToU16(width);
+       fHeight         = SkToU16(height);
+       fRowBytes       = SkToU16(rowBytes);
+}
+
+void SkBitmap::setPixels(void* p)
+{
+       this->freePixels();
+
+       fPixels = p;
+       fFlags &= ~(kWeOwnThePixels_Flag | kWeOwnTheMipMap_Flag);
+}
+
+void SkBitmap::allocPixels()
+{
+       this->freePixels();
+
+       fPixels = (U32*)sk_malloc_throw(fHeight * fRowBytes);
+       fFlags |= kWeOwnThePixels_Flag;
+}
+
+void SkBitmap::freePixels()
+{
+       if (fFlags & kWeOwnThePixels_Flag)
+       {
+               SkASSERT(fPixels);
+               sk_free(fPixels);
+               fPixels = NULL;
+               fFlags &= ~kWeOwnThePixels_Flag;
+       }
+#ifdef SK_SUPPORT_MIPMAP
+       if (fFlags & kWeOwnTheMipMap_Flag)
+       {
+               sk_free(fMipMap);
+               fMipMap = NULL;
+       }
+#endif
+}
+
+bool SkBitmap::getOwnsPixels() const
+{
+       return SkToBool(fFlags & kWeOwnThePixels_Flag);
+}
+
+void SkBitmap::setOwnsPixels(bool ownsPixels)
+{
+       if (ownsPixels)
+               fFlags |= kWeOwnThePixels_Flag;
+       else
+               fFlags &= ~kWeOwnThePixels_Flag;
+}
+
+SkColorTable* SkBitmap::setColorTable(SkColorTable* ct)
+{
+       SkRefCnt_SafeAssign(fColorTable, ct);
+       return ct;
+}
+
+bool SkBitmap::isOpaque() const
+{
+    switch (fConfig) {
+    case kA1_Config:
+    case kA8_Config:
+    case kARGB_8888_Config:
+        return (fFlags & kImageIsOpaque_Flag) != 0;
+
+    case kIndex8_Config:
+        return (fColorTable->getFlags() & SkColorTable::kColorsAreOpaque_Flag) != 0;
+
+    case kRGB_565_Config:
+        return true;
+
+    default:
+        SkASSERT(!"unknown bitmap config");
+        return false;
+    }
+}
+
+void SkBitmap::setIsOpaque(bool isOpaque)
+{
+    /*  we record this regardless of fConfig, though it is ignored in isOpaque() for
+        configs that can't support per-pixel alpha.
+    */
+    if (isOpaque)
+        fFlags |= kImageIsOpaque_Flag;
+    else
+        fFlags &= ~kImageIsOpaque_Flag;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////
+
+void SkBitmap::eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
+{
+       if (fPixels == NULL || fConfig == kNo_Config)
+               return;
+
+       int height = fHeight;
+
+    this->setIsOpaque(a == 255);
+
+       // make rgb premultiplied
+       if (a != 255)
+       {
+               r = SkAlphaMul(r, a);
+               g = SkAlphaMul(g, a);
+               b = SkAlphaMul(b, a);
+       }
+
+       switch (fConfig) {
+       case kA1_Config:
+               {
+                       U8* p = (uint8_t*)fPixels;
+                       size_t count = (fWidth + 7) >> 3;
+                       a = (a >> 7) ? 0xFF : 0;
+                       SkASSERT(count <= fRowBytes);
+                       while (--height >= 0)
+                       {
+                               memset(p, a, count);
+                               p += fRowBytes;
+                       }
+               }
+               break;
+       case kA8_Config:
+               memset(fPixels, a, fRowBytes * fWidth);
+               break;
+       case kIndex8_Config:
+               SkASSERT(!"Don't support writing to Index8 bitmaps");
+               break;
+       case kRGB_565_Config:
+               // now erase the color-plane
+               {
+                       U16* p = (uint16_t*)fPixels;
+                       U16      v = SkPackRGB16(r >> (8 - SK_R16_BITS),
+                                                               g >> (8 - SK_G16_BITS),
+                                                               b >> (8 - SK_B16_BITS));
+
+                       while (--height >= 0)
+                       {
+                               sk_memset16(p, v, fWidth);
+                               p = (uint16_t*)((char*)p + fRowBytes);
+                       }
+               }
+               break;
+       case kARGB_8888_Config:
+               {
+                       uint32_t* p = (uint32_t*)fPixels;
+                       uint32_t  v = SkPackARGB32(a, r, g, b);
+
+                       while (--height >= 0)
+                       {
+                               sk_memset32(p, v, fWidth);
+                               p = (uint32_t*)((char*)p + fRowBytes);
+                       }
+               }
+               break;
+       }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_SUPPORT_MIPMAP
+static void downsampleby2_proc32(SkBitmap* dst, int x, int y, const SkBitmap& src)
+{
+       x <<= 1;
+       y <<= 1;
+       const U32* p = src.getAddr32(x, y);
+       U32     c, ag, rb;
+
+       c = *p; ag = (c >> 8) & 0xFF00FF; rb = c & 0xFF00FF;
+       if (x < (int)src.width() - 1)
+               p += 1;
+       c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF;
+
+       if (y < (int)src.height() - 1)
+               p = src.getAddr32(x, y + 1);
+       c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF;
+       if (x < (int)src.width() - 1)
+               p += 1;
+       c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF;
+
+       *dst->getAddr32(x >> 1, y >> 1) = ((rb >> 2) & 0xFF00FF) | ((ag << 6) & 0xFF00FF00);
+}
+
+static inline uint32_t expand16(U16CPU c)
+{
+       return (c & SK_R16B16_MASK_IN_PLACE) | ((c & SK_G16_MASK_IN_PLACE) << 16);
+}
+
+static inline U16CPU pack16(uint32_t c)
+{
+       return (c & SK_R16B16_MASK_IN_PLACE) | ((c >> 16) & SK_G16_MASK_IN_PLACE);
+}
+
+static void downsampleby2_proc16(SkBitmap* dst, int x, int y, const SkBitmap& src)
+{
+       x <<= 1;
+       y <<= 1;
+       const U16*      p = src.getAddr16(x, y);
+       U32                     c;
+
+       c = expand16(*p);
+       if (x < (int)src.width() - 1)
+               p += 1;
+       c += expand16(*p);
+
+       if (y < (int)src.height() - 1)
+               p = src.getAddr16(x, y + 1);
+       c += expand16(*p);
+       if (x < (int)src.width() - 1)
+               p += 1;
+       c += expand16(*p);
+
+       *dst->getAddr16(x >> 1, y >> 1) = SkToU16(pack16(c >> 2));
+}
+
+void SkBitmap::buildMipMap(bool forceRebuild)
+{
+#ifdef SK_SUPPORT_MIPMAP
+    if (!forceRebuild && fMipMap)
+        return;
+
+       if (fFlags & kWeOwnTheMipMap_Flag)
+       {
+               SkASSERT(fMipMap);
+               sk_free(fMipMap);
+               fMipMap = NULL;
+               fFlags &= ~kWeOwnTheMipMap_Flag;
+       }
+
+       int     shift;
+       void (*proc)(SkBitmap* dst, int x, int y, const SkBitmap& src);
+
+       switch (this->getConfig()) {
+       case kARGB_8888_Config:
+               shift = 2;
+               proc = downsampleby2_proc32;
+               break;
+       case kRGB_565_Config:
+               shift = 1;
+               proc = downsampleby2_proc16;
+               break;
+       case kIndex8_Config:
+       case kA8_Config:
+//             shift = 0; break;
+       default:
+               return; // don't build mipmaps for these configs
+       }
+
+       // whip through our loop to compute the exact size needed
+       size_t  size;
+       {
+               unsigned        width = this->width();
+               unsigned        height = this->height();
+               size = 0;
+               for (int i = 1; i < kMaxMipLevels; i++)
+               {
+                       width = (width + 1) >> 1;
+                       height = (height + 1) >> 1;
+                       size += width * height << shift;
+               }
+       }
+
+       MipMap* mm = (MipMap*)sk_malloc_throw(sizeof(MipMap) + size);
+       U8*             addr = (U8*)(mm + 1);
+
+       unsigned        width = this->width();
+       unsigned        height = this->height();
+       unsigned        rowBytes = this->rowBytes();
+       SkBitmap        srcBM(*this), dstBM;
+
+       mm->fLevel[0].fPixels   = this->getPixels();
+       mm->fLevel[0].fWidth    = SkToU16(width);
+       mm->fLevel[0].fHeight   = SkToU16(height);
+       mm->fLevel[0].fRowBytes = SkToU16(rowBytes);
+       mm->fLevel[0].fConfig   = SkToU8(this->getConfig());
+       mm->fLevel[0].fShift    = SkToU8(shift);
+
+       for (int i = 1; i < kMaxMipLevels; i++)
+       {
+               width = (width + 1) >> 1;
+               height = (height + 1) >> 1;
+               rowBytes = width << shift;
+
+               mm->fLevel[i].fPixels   = addr;
+               mm->fLevel[i].fWidth    = SkToU16(width);
+               mm->fLevel[i].fHeight   = SkToU16(height);
+               mm->fLevel[i].fRowBytes = SkToU16(rowBytes);
+               mm->fLevel[i].fConfig   = SkToU8(this->getConfig());
+               mm->fLevel[i].fShift    = SkToU8(shift);
+
+               dstBM.setConfig(this->getConfig(), width, height, rowBytes);
+               dstBM.setPixels(addr);
+       
+               for (unsigned y = 0; y < height; y++)
+                       for (unsigned x = 0; x < width; x++)
+                               proc(&dstBM, x, y, srcBM);
+
+               srcBM = dstBM;
+               addr += height * rowBytes;
+       }
+       SkASSERT(addr == (U8*)mm->fLevel[1].fPixels + size);
+
+       fMipMap = mm;
+       fFlags |= kWeOwnTheMipMap_Flag;
+#endif
+}
+
+unsigned SkBitmap::countMipLevels() const
+{
+#ifdef SK_SUPPORT_MIPMAP
+       return fMipMap ? kMaxMipLevels : 0;
+#else
+    return 0;
+#endif
+}
+
+const SkBitmap::MipLevel* SkBitmap::getMipLevel(unsigned level) const
+{
+       SkASSERT(level < this->countMipLevels());
+
+       return &fMipMap->fLevel[level];
+}
+#endif
+
+
diff --git a/libs/graphics/sgl/SkBitmapSampler.cpp b/libs/graphics/sgl/SkBitmapSampler.cpp
new file mode 100644 (file)
index 0000000..28b83f0
--- /dev/null
@@ -0,0 +1,281 @@
+#include "SkBitmapSampler.h"
+
+static SkTileModeProc get_tilemode_proc(SkShader::TileMode mode)
+{
+    switch (mode) {
+    case SkShader::kClamp_TileMode:
+        return do_clamp;
+    case SkShader::kRepeat_TileMode:
+        return do_repeat_mod;
+    case SkShader::kMirror_TileMode:
+        return do_mirror_mod;
+    default:
+        SkASSERT(!"unknown mode");
+        return NULL;
+    }
+}
+
+SkBitmapSampler::SkBitmapSampler(const SkBitmap& bm, SkPaint::FilterType ftype,
+                                 SkShader::TileMode tmx, SkShader::TileMode tmy)
+       : fBitmap(bm), fFilterType(ftype), fTileModeX(tmx), fTileModeY(tmy)
+{
+       SkASSERT(bm.width() > 0 && bm.height() > 0);
+
+       fMaxX = SkToU16(bm.width() - 1);
+       fMaxY = SkToU16(bm.height() - 1);
+    
+    fTileProcX = get_tilemode_proc(tmx);
+    fTileProcY = get_tilemode_proc(tmy);
+}
+
+class SkNullBitmapSampler : public SkBitmapSampler {
+public:
+       SkNullBitmapSampler(const SkBitmap& bm, SkPaint::FilterType ft,
+                        SkShader::TileMode tmx, SkShader::TileMode tmy)
+               : SkBitmapSampler(bm, ft, tmx, tmy) {}
+
+       virtual SkPMColor sample(SkFixed x, SkFixed y) const { return 0; }
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+#define BITMAP_CLASSNAME_PREFIX(name)                  ARGB32##name
+#define BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y)  *bitmap.getAddr32(x, y)
+#include "SkBitmapSamplerTemplate.h"
+
+#include "SkColorPriv.h"
+
+#define BITMAP_CLASSNAME_PREFIX(name)                  RGB16##name
+#define BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y)  SkPixel16ToPixel32(*bitmap.getAddr16(x, y))
+#include "SkBitmapSamplerTemplate.h"
+
+#define BITMAP_CLASSNAME_PREFIX(name)                  Index8##name
+#define BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y)  bitmap.getIndex8Color(x, y)
+#include "SkBitmapSamplerTemplate.h"
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+///////////////// The Bilinear versions
+
+static void assert_valid_pmcolor(uint32_t c)
+{
+       SkASSERT(SkGetPackedA32(c) >= SkGetPackedR32(c));
+       SkASSERT(SkGetPackedA32(c) >= SkGetPackedG32(c));
+       SkASSERT(SkGetPackedA32(c) >= SkGetPackedB32(c));
+}
+
+#include "SkFilterProc.h"
+
+class ARGB32_Bilinear_Sampler : public SkBitmapSampler {
+public:
+       ARGB32_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
+               : SkBitmapSampler(bm, SkPaint::kBilinear_FilterType, tmx, tmy)
+       {
+               fProcTable = SkGetBilinearFilterProcTable();
+       }
+
+       virtual SkPMColor sample(SkFixed x, SkFixed y) const
+       {
+               int     ix = x >> 16;
+               int iy = y >> 16;
+
+        ix = fTileProcX(ix, fMaxX);
+        iy = fTileProcY(iy, fMaxY);
+
+               const uint32_t *p00, *p01, *p10, *p11;
+
+               p00 = p01 = fBitmap.getAddr32(ix, iy);
+               if (ix < fMaxX)
+                       p01 += 1;
+               p10 = p00;
+               p11 = p01;
+               if (iy < fMaxY)
+               {
+                       p10 = (const uint32_t*)((const char*)p10 + fBitmap.rowBytes());
+                       p11 = (const uint32_t*)((const char*)p11 + fBitmap.rowBytes());
+               }
+
+               uint32_t c00 = *p00;
+               uint32_t c01 = *p01;
+               uint32_t c10 = *p10;
+               uint32_t c11 = *p11;
+
+               assert_valid_pmcolor(c00);
+               assert_valid_pmcolor(c01);
+               assert_valid_pmcolor(c01);
+               assert_valid_pmcolor(c11);
+
+               SkFilterProc proc = SkGetBilinearFilterProc(fProcTable, x, y);
+               uint32_t c = SkPackARGB32(      proc(SkGetPackedA32(c00), SkGetPackedA32(c01), SkGetPackedA32(c10), SkGetPackedA32(c11)),
+                                                               proc(SkGetPackedR32(c00), SkGetPackedR32(c01), SkGetPackedR32(c10), SkGetPackedR32(c11)),
+                                                               proc(SkGetPackedG32(c00), SkGetPackedG32(c01), SkGetPackedG32(c10), SkGetPackedG32(c11)),
+                                                               proc(SkGetPackedB32(c00), SkGetPackedB32(c01), SkGetPackedB32(c10), SkGetPackedB32(c11)));
+
+               assert_valid_pmcolor(c);
+               return c;
+       }
+       
+private:
+       const SkFilterProc*   fProcTable;
+};
+
+class Index8_Bilinear_Sampler : public SkBitmapSampler {
+public:
+       Index8_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
+               : SkBitmapSampler(bm, SkPaint::kBilinear_FilterType, tmx, tmy)
+       {
+               fProcTable = SkGetBilinearFilterProcTable();
+       }
+
+       virtual SkPMColor sample(SkFixed x, SkFixed y) const
+       {
+               int     ix = x >> 16;
+               int iy = y >> 16;
+
+        ix = fTileProcX(ix, fMaxX);
+        iy = fTileProcY(iy, fMaxY);
+
+               const U8 *p00, *p01, *p10, *p11;
+
+               p00 = p01 = fBitmap.getAddr8(ix, iy);
+               if (ix < fMaxX)
+                       p01 += 1;
+               p10 = p00;
+               p11 = p01;
+               if (iy < fMaxY)
+               {
+                       p10 = (const U8*)((const char*)p10 + fBitmap.rowBytes());
+                       p11 = (const U8*)((const char*)p11 + fBitmap.rowBytes());
+               }
+
+               const SkPMColor* colors = fBitmap.getColorTable()->lockColors();
+
+               uint32_t c00 = colors[*p00];
+               uint32_t c01 = colors[*p01];
+               uint32_t c10 = colors[*p10];
+               uint32_t c11 = colors[*p11];
+
+               assert_valid_pmcolor(c00);
+               assert_valid_pmcolor(c01);
+               assert_valid_pmcolor(c01);
+               assert_valid_pmcolor(c11);
+
+               SkFilterProc proc = SkGetBilinearFilterProc(fProcTable, x, y);
+               uint32_t c = SkPackARGB32(      proc(SkGetPackedA32(c00), SkGetPackedA32(c01), SkGetPackedA32(c10), SkGetPackedA32(c11)),
+                                                               proc(SkGetPackedR32(c00), SkGetPackedR32(c01), SkGetPackedR32(c10), SkGetPackedR32(c11)),
+                                                               proc(SkGetPackedG32(c00), SkGetPackedG32(c01), SkGetPackedG32(c10), SkGetPackedG32(c11)),
+                                                               proc(SkGetPackedB32(c00), SkGetPackedB32(c01), SkGetPackedB32(c10), SkGetPackedB32(c11)));
+
+               assert_valid_pmcolor(c);
+
+               fBitmap.getColorTable()->unlockColors(false);
+
+               return c;
+       }
+       
+private:
+       const SkFilterProc*   fProcTable;
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+SkBitmapSampler* SkBitmapSampler::Create(const SkBitmap& bm, SkPaint::FilterType ftype,
+                                         SkShader::TileMode tmx, SkShader::TileMode tmy)
+{
+       switch (bm.getConfig()) {
+       case SkBitmap::kARGB_8888_Config:
+               switch (ftype) {
+               case SkPaint::kNo_FilterType:
+            if (tmx == tmy) {
+                switch (tmx) {
+                case SkShader::kClamp_TileMode:
+                    return SkNEW_ARGS(ARGB32_Point_Clamp_Sampler, (bm));
+                case SkShader::kRepeat_TileMode:
+                    if (is_pow2(bm.width()) && is_pow2(bm.height()))
+                        return SkNEW_ARGS(ARGB32_Point_Repeat_Pow2_Sampler, (bm));
+                    else
+                        return SkNEW_ARGS(ARGB32_Point_Repeat_Mod_Sampler, (bm));
+                case SkShader::kMirror_TileMode:
+                    if (is_pow2(bm.width()) && is_pow2(bm.height()))
+                        return SkNEW_ARGS(ARGB32_Point_Mirror_Pow2_Sampler, (bm));
+                    else
+                        return SkNEW_ARGS(ARGB32_Point_Mirror_Mod_Sampler, (bm));
+                default:
+                    SkASSERT(!"unknown mode");
+                }
+            }
+            else {  // tmx != tmy
+                return SkNEW_ARGS(ARGB32_Point_Sampler, (bm, tmx, tmy));
+            }
+            break;
+
+               case SkPaint::kBilinear_FilterType:
+                       return SkNEW_ARGS(ARGB32_Bilinear_Sampler, (bm, tmx, tmy));
+
+               default:
+                       SkASSERT(!"unknown filter type");
+               }
+               break;
+       case SkBitmap::kRGB_565_Config:
+        // we ignore ftype, since we haven't implemented bilinear for 16bit bitmaps yet
+        if (tmx == tmy) {
+            switch (tmx) {
+            case SkShader::kClamp_TileMode:
+                return SkNEW_ARGS(RGB16_Point_Clamp_Sampler, (bm));
+            case SkShader::kRepeat_TileMode:
+                if (is_pow2(bm.width()) && is_pow2(bm.height()))
+                    return SkNEW_ARGS(RGB16_Point_Repeat_Pow2_Sampler, (bm));
+                else
+                    return SkNEW_ARGS(RGB16_Point_Repeat_Mod_Sampler, (bm));
+            case SkShader::kMirror_TileMode:
+                if (is_pow2(bm.width()) && is_pow2(bm.height()))
+                    return SkNEW_ARGS(RGB16_Point_Mirror_Pow2_Sampler, (bm));
+                else
+                    return SkNEW_ARGS(RGB16_Point_Mirror_Mod_Sampler, (bm));
+            default:
+                SkASSERT(!"unknown mode");
+            }
+        }
+        else {  // tmx != tmy
+            return SkNEW_ARGS(RGB16_Point_Sampler, (bm, tmx, tmy));
+        }
+               break;
+       case SkBitmap::kIndex8_Config:
+               switch (ftype) {
+               case SkPaint::kNo_FilterType:
+            if (tmx == tmy) {
+                switch (tmx) {
+                case SkShader::kClamp_TileMode:
+                    return SkNEW_ARGS(Index8_Point_Clamp_Sampler, (bm));
+                case SkShader::kRepeat_TileMode:
+                    if (is_pow2(bm.width()) && is_pow2(bm.height()))
+                        return SkNEW_ARGS(Index8_Point_Repeat_Pow2_Sampler, (bm));
+                    else
+                        return SkNEW_ARGS(Index8_Point_Repeat_Mod_Sampler, (bm));
+                case SkShader::kMirror_TileMode:
+                    if (is_pow2(bm.width()) && is_pow2(bm.height()))
+                        return SkNEW_ARGS(Index8_Point_Mirror_Pow2_Sampler, (bm));
+                    else
+                        return SkNEW_ARGS(Index8_Point_Mirror_Mod_Sampler, (bm));
+                default:
+                    SkASSERT(!"unknown mode");
+                }
+            }
+            else {  // tmx != tmy
+                return SkNEW_ARGS(Index8_Point_Sampler, (bm, tmx, tmy));
+            }
+                       break;
+               case SkPaint::kBilinear_FilterType:
+                       return SkNEW_ARGS(Index8_Bilinear_Sampler, (bm, tmx, tmy));
+               default:        // to avoid warnings
+                       break;
+               }
+               break;
+       default:
+               SkASSERT(!"unknown device");
+       }
+       return SkNEW_ARGS(SkNullBitmapSampler, (bm, ftype, tmx, tmy));
+}
+
diff --git a/libs/graphics/sgl/SkBitmapSampler.h b/libs/graphics/sgl/SkBitmapSampler.h
new file mode 100644 (file)
index 0000000..27a1855
--- /dev/null
@@ -0,0 +1,150 @@
+#ifndef SkBitmapSampler_DEFINED
+#define SkBitmapSampler_DEFINED
+
+#include "SkBitmap.h"
+#include "SkPaint.h"
+#include "SkShader.h"
+
+typedef int (*SkTileModeProc)(int value, unsigned max);
+
+class SkBitmapSampler {
+public:
+       SkBitmapSampler(const SkBitmap&, SkPaint::FilterType, SkShader::TileMode tmx, SkShader::TileMode tmy);
+       virtual ~SkBitmapSampler() {}
+
+       const SkBitmap&         getBitmap() const { return fBitmap; }
+       SkPaint::FilterType     getFilterType() const { return fFilterType; }
+       SkShader::TileMode      getTileModeX() const { return fTileModeX; }
+       SkShader::TileMode      getTileModeY() const { return fTileModeY; }
+
+       // override this in your subclass
+       virtual SkPMColor sample(SkFixed x, SkFixed y) const = 0;
+
+       // This is the factory for finding an optimal subclass
+       static SkBitmapSampler* Create(const SkBitmap&, SkPaint::FilterType,
+                                   SkShader::TileMode tmx, SkShader::TileMode tmy);
+
+protected:
+       const SkBitmap&         fBitmap;
+       uint16_t                        fMaxX, fMaxY;
+       SkPaint::FilterType     fFilterType;
+       SkShader::TileMode      fTileModeX;
+       SkShader::TileMode      fTileModeY;
+    SkTileModeProc      fTileProcX;
+    SkTileModeProc      fTileProcY;
+
+       // illegal
+       SkBitmapSampler& operator=(const SkBitmapSampler&);
+};
+
+static inline int fixed_clamp(SkFixed x)
+{
+#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
+       if (x >> 16)
+               x = 0xFFFF;
+       if (x < 0)
+               x = 0;
+#else
+       if (x >> 16)
+       {
+               if (x < 0)
+                       x = 0;
+               else
+                       x = 0xFFFF;
+       }
+#endif
+    return x;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+static inline int fixed_repeat(SkFixed x)
+{
+    return x & 0xFFFF;
+}
+
+static inline int fixed_mirror(SkFixed x)
+{
+       SkFixed s = x << 15 >> 31;
+       // s is FFFFFFFF if we're on an odd interval, or 0 if an even interval
+       return (x ^ s) & 0xFFFF;
+}
+
+static inline bool is_pow2(int count)
+{
+       SkASSERT(count > 0);
+       return (count & (count - 1)) == 0;
+}
+
+static inline int do_clamp(int index, unsigned max)
+{
+       SkASSERT((int)max >= 0);
+
+#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
+       if (index > (int)max)
+               index = max;
+       if (index < 0)
+               index = 0;
+#else
+       if ((unsigned)index > max)
+       {
+               if (index < 0)
+                       index = 0;
+               else
+                       index = max;
+       }
+#endif
+       return index;
+}
+
+static inline int do_repeat_mod(int index, unsigned max)
+{
+       SkASSERT((int)max >= 0);
+
+       if ((unsigned)index > max)
+       {
+               if (index < 0)
+                       index = max - (~index % (max + 1));
+               else
+                       index = index % (max + 1);
+       }
+       return index;
+}
+
+static inline int do_repeat_pow2(int index, unsigned max)
+{
+       SkASSERT((int)max >= 0 && is_pow2(max + 1));
+
+       return index & max;
+}
+
+static inline int do_mirror_mod(int index, unsigned max)
+{
+       SkASSERT((int)max >= 0);
+
+       // have to handle negatives so that
+       // -1 -> 0, -2 -> 1, -3 -> 2, etc.
+       // so we can't just cal abs
+       index ^= index >> 31;
+
+       if ((unsigned)index > max)
+       {
+               int mod = (max + 1) << 1;
+               index = index % mod;
+               if ((unsigned)index > max)
+                       index = mod - index - 1;
+       }
+       return index;
+}
+
+static inline int do_mirror_pow2(int index, unsigned max)
+{
+       SkASSERT((int)max >= 0 && is_pow2(max + 1));
+
+       int s = (index & (max + 1)) - 1;
+       s = ~(s >> 31);
+       // at this stage, s is FFFFFFFF if we're on an odd interval, or 0 if an even interval
+       return (index ^ s) & max;
+}
+
+#endif
diff --git a/libs/graphics/sgl/SkBitmapSamplerTemplate.h b/libs/graphics/sgl/SkBitmapSamplerTemplate.h
new file mode 100644 (file)
index 0000000..19530a0
--- /dev/null
@@ -0,0 +1,99 @@
+/*     this guy is pulled in multiple times, with the following symbols defined each time:
+
+       #define BITMAP_CLASSNAME_PREFIX(name)                   ARGB32##name
+       #defube BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y)   *bitmap.getAddr32(x, y)
+*/
+
+class BITMAP_CLASSNAME_PREFIX(_Point_Sampler) : public SkBitmapSampler {
+public:
+       BITMAP_CLASSNAME_PREFIX(_Point_Sampler)(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
+               : SkBitmapSampler(bm, SkPaint::kNo_FilterType, tmx, tmy)
+       {
+       }
+
+       virtual SkPMColor sample(SkFixed x, SkFixed y) const
+       {
+        x = fTileProcX(SkFixedRound(x), fMaxX);
+        y = fTileProcY(SkFixedRound(y), fMaxY);
+               return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
+       }
+};
+
+
+class BITMAP_CLASSNAME_PREFIX(_Point_Clamp_Sampler) : public SkBitmapSampler {
+public:
+       BITMAP_CLASSNAME_PREFIX(_Point_Clamp_Sampler)(const SkBitmap& bm)
+               : SkBitmapSampler(bm, SkPaint::kNo_FilterType, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)
+       {
+       }
+
+       virtual SkPMColor sample(SkFixed x, SkFixed y) const
+       {
+               x = do_clamp(SkFixedRound(x), fMaxX);
+               y = do_clamp(SkFixedRound(y), fMaxY);
+               return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
+       }
+};
+
+class BITMAP_CLASSNAME_PREFIX(_Point_Repeat_Pow2_Sampler) : public SkBitmapSampler {
+public:
+       BITMAP_CLASSNAME_PREFIX(_Point_Repeat_Pow2_Sampler)(const SkBitmap& bm)
+               : SkBitmapSampler(bm, SkPaint::kNo_FilterType, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)
+       {
+       }
+
+       virtual SkPMColor sample(SkFixed x, SkFixed y) const
+       {
+               x = do_repeat_pow2(SkFixedRound(x), fMaxX);
+               y = do_repeat_pow2(SkFixedRound(y), fMaxY);
+               return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
+       }
+};
+
+class BITMAP_CLASSNAME_PREFIX(_Point_Repeat_Mod_Sampler) : public SkBitmapSampler {
+public:
+       BITMAP_CLASSNAME_PREFIX(_Point_Repeat_Mod_Sampler)(const SkBitmap& bm)
+               : SkBitmapSampler(bm, SkPaint::kNo_FilterType, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)
+       {
+       }
+
+       virtual SkPMColor sample(SkFixed x, SkFixed y) const
+       {
+               x = do_repeat_mod(SkFixedRound(x), fMaxX);
+               y = do_repeat_mod(SkFixedRound(y), fMaxY);
+               return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
+       }
+};
+
+class BITMAP_CLASSNAME_PREFIX(_Point_Mirror_Pow2_Sampler) : public SkBitmapSampler {
+public:
+       BITMAP_CLASSNAME_PREFIX(_Point_Mirror_Pow2_Sampler)(const SkBitmap& bm)
+               : SkBitmapSampler(bm, SkPaint::kNo_FilterType, SkShader::kMirror_TileMode, SkShader::kMirror_TileMode)
+       {
+       }
+
+       virtual SkPMColor sample(SkFixed x, SkFixed y) const
+       {
+               x = do_mirror_pow2(SkFixedRound(x), fMaxX);
+               y = do_mirror_pow2(SkFixedRound(y), fMaxY);
+               return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
+       }
+};
+
+class BITMAP_CLASSNAME_PREFIX(_Point_Mirror_Mod_Sampler) : public SkBitmapSampler {
+public:
+       BITMAP_CLASSNAME_PREFIX(_Point_Mirror_Mod_Sampler)(const SkBitmap& bm)
+               : SkBitmapSampler(bm, SkPaint::kNo_FilterType, SkShader::kMirror_TileMode, SkShader::kMirror_TileMode)
+       {
+       }
+
+       virtual SkPMColor sample(SkFixed x, SkFixed y) const
+       {
+               x = do_mirror_mod(SkFixedRound(x), fMaxX);
+               y = do_mirror_mod(SkFixedRound(y), fMaxY);
+               return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
+       }
+};
+
+#undef BITMAP_CLASSNAME_PREFIX
+#undef BITMAP_PIXEL_TO_PMCOLOR
diff --git a/libs/graphics/sgl/SkBitmapShader.cpp b/libs/graphics/sgl/SkBitmapShader.cpp
new file mode 100644 (file)
index 0000000..b70f8bb
--- /dev/null
@@ -0,0 +1,476 @@
+#include "SkBitmapShader.h"
+#include "SkBitmapSampler.h"
+
+#ifdef SK_SUPPORT_MIPMAP
+static SkFixed find_mip_level(SkFixed dx, SkFixed dy)
+{
+       dx = SkAbs32(dx);
+       dy = SkAbs32(dy);
+       if (dx < dy)
+               dx = dy;
+       
+       if (dx < SK_Fixed1)
+               return 0;
+       
+       int clz = SkCLZ(dx);
+       SkASSERT(clz >= 1 && clz <= 15);
+       return SkIntToFixed(15 - clz) + ((unsigned)(dx << (clz + 1)) >> 16);
+}
+#endif
+
+SkBitmapShader::SkBitmapShader(const SkBitmap& src,
+                                                          bool transferOwnershipOfPixels,
+                                                          SkPaint::FilterType filterType,
+                                                          TileMode tmx, TileMode tmy)
+    :
+#ifdef SK_SUPPORT_MIPMAP
+    fMipLevel(0), fMipSrcBitmap(src),
+#endif
+    fOrigSrcBitmap(src)
+    
+{
+       if (transferOwnershipOfPixels)
+       {
+               fOrigSrcBitmap.setOwnsPixels(src.getOwnsPixels());
+               ((SkBitmap*)&src)->setOwnsPixels(false);
+               // do the same for mipmap ownership???
+       }
+       fFilterType = SkToU8(filterType);
+       fTileModeX = SkToU8(tmx);
+       fTileModeY = SkToU8(tmy);
+}
+
+bool SkBitmapShader::setContext(const SkBitmap& device, const SkPaint& paint, const SkMatrix& matrix)
+{
+       // do this first, so we have a correct inverse matrix
+       if (!this->INHERITED::setContext(device, paint, matrix))
+               return false;
+
+       uint32_t flags = fOrigSrcBitmap.isOpaque() ? kOpaqueAlpha_Flag : 0;
+
+       if (flags == kOpaqueAlpha_Flag && paint.getAlpha() != 0xFF)
+               flags = kConstAlpha_Flag;
+       
+       fFlags = SkToU8(flags);
+
+#ifdef SK_SUPPORT_MIPMAP
+       if (fOrigSrcBitmap.countMipLevels())
+       {
+               const SkMatrix& inv = this->getTotalInverse();
+
+               fMipLevel = SkMin32(find_mip_level(     SkScalarToFixed(inv.getScaleX()),
+                                                                                       SkScalarToFixed(inv.getSkewY())),
+                                                       SkIntToFixed(fOrigSrcBitmap.countMipLevels() - 1));
+
+//        SkDEBUGF(("BitmapShader miplevel=%x\n", fMipLevel));
+
+        const SkBitmap::MipLevel* mm = fOrigSrcBitmap.getMipLevel(fMipLevel >> 16);
+        
+        fMipSrcBitmap.setConfig(fOrigSrcBitmap.getConfig(),
+                                mm->fWidth,
+                                mm->fHeight,
+                                mm->fRowBytes);
+        fMipSrcBitmap.setPixels(mm->fPixels);
+    }
+    else
+    {
+        fMipLevel = 0;
+        fMipSrcBitmap = fOrigSrcBitmap;
+    }
+#endif
+       return true;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+#include "SkColorPriv.h"
+#include "SkBitmapSampler.h"
+
+class Sampler_BitmapShader : public SkBitmapShader {
+public:
+       Sampler_BitmapShader(const SkBitmap& src,
+                                                bool transferOwnershipOfPixels,
+                                                SkPaint::FilterType ftype,
+                                                TileMode tmx, TileMode tmy)
+               : SkBitmapShader(src, transferOwnershipOfPixels, ftype, tmx, tmy)
+       {
+               // make sure to pass our copy of the src bitmap to the sampler, and not the
+               // original parameter (which might go away).
+               fSampler = NULL;
+       }
+
+       virtual ~Sampler_BitmapShader()
+       {
+               SkDELETE(fSampler);
+       }
+    
+    virtual bool setContext(const SkBitmap& device, const SkPaint& paint, const SkMatrix& matrix)
+    {
+        if (this->INHERITED::setContext(device, paint, matrix))
+        {
+            SkDELETE(fSampler);
+            fSampler = SkBitmapSampler::Create(this->getSrcBitmap(), this->getFilterType(),
+                                               this->getTileModeX(), this->getTileModeY());
+            return true;
+        }
+        return false;
+    }
+
+       virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count)
+       {
+               unsigned                        scale = SkAlpha255To256(this->getPaintAlpha());
+               const SkMatrix&         inv = this->getTotalInverse();
+               SkMatrix::MapPtProc     proc = this->getInverseMapPtProc();
+               SkBitmapSampler*         sampler = fSampler;
+               MatrixClass                     mc = this->getInverseClass();
+
+               SkPoint srcPt;
+
+               if (mc != kPerspective_MatrixClass)
+               {
+                       proc(inv, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
+
+                       SkFixed fx = SkScalarToFixed(srcPt.fX);
+                       SkFixed fy = SkScalarToFixed(srcPt.fY);
+                       SkFixed dx, dy;
+
+                       if (mc == kLinear_MatrixClass)
+                       {
+                               dx = SkScalarToFixed(inv.getScaleX());
+                               dy = SkScalarToFixed(inv.getSkewY());
+                       }
+                       else
+                               (void)inv.fixedStepInX(SkIntToScalar(y), &dx, &dy);
+
+#if defined(SK_SUPPORT_MIPMAP)
+        {   int level = this->getMipLevel() >> 16;
+            fx >>= level;
+            fy >>= level;
+            dx >>= level;
+            dy >>= level;
+               }
+#endif
+                       if (scale == 256)
+                       {
+                               for (int i = 0; i < count; i++)
+                               {
+                                       dstC[i] = sampler->sample(fx, fy);
+                                       fx += dx;
+                                       fy += dy;
+                               }
+                       }
+                       else
+                       {
+                               for (int i = 0; i < count; i++)
+                               {
+                                       uint32_t        c = sampler->sample(fx, fy);
+                                       dstC[i] = SkAlphaMulQ(c, scale);
+                                       fx += dx;
+                                       fy += dy;
+                               }
+                       }
+               }
+               else
+               {
+                       SkScalar        dstX = SkIntToScalar(x);
+                       SkScalar        dstY = SkIntToScalar(y);
+
+                       for (int i = 0; i < count; i++)
+                       {
+                               proc(inv, dstX, dstY, &srcPt);
+                               uint32_t        c = sampler->sample(SkScalarToFixed(srcPt.fX), SkScalarToFixed(srcPt.fY));
+
+                               if (scale != 256)
+                                       c = SkAlphaMulQ(c, scale);
+                               dstC[i] = c;
+                               dstX += SK_Scalar1;
+                       }
+               }
+       }
+
+protected:
+
+    const SkMatrix& getUnitInverse() const { return fUnitInverse; }
+    SkMatrix::MapPtProc getUnitInverseProc() const { return fUnitInverseProc; }
+
+       /* takes computed inverse (from setContext) and computes fUnitInverse,
+               taking srcBitmap width/height into account, so that fUnitInverse
+               walks 0...1, allowing the tile modes to all operate in a fast 16bit
+               space (no need for mod). The resulting coords need to be scaled by
+               width/height to get back into src space (coord * width >> 16).
+       */
+       void computeUnitInverse()
+       {
+               const SkBitmap& src = getSrcBitmap();
+               fUnitInverse = this->getTotalInverse();
+               fUnitInverse.postScale(SK_Scalar1 / src.width(), SK_Scalar1 / src.height(), 0, 0);
+        fUnitInverseProc = fUnitInverse.getMapPtProc();
+       }
+
+private:
+       SkBitmapSampler*        fSampler;
+       SkMatrix            fUnitInverse;
+    SkMatrix::MapPtProc fUnitInverseProc;
+    
+    typedef SkBitmapShader INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+class HasSpan16_Sampler_BitmapShader : public Sampler_BitmapShader {
+public:
+       HasSpan16_Sampler_BitmapShader(const SkBitmap& src, bool transferOwnershipOfPixels,
+                                                                       SkPaint::FilterType ft, TileMode tmx, TileMode tmy)
+               : Sampler_BitmapShader(src, transferOwnershipOfPixels, ft, tmx, tmy)
+       {
+       }
+
+       virtual uint32_t getFlags()
+       {
+               uint32_t flags = this->INHERITED::getFlags();
+
+               if (this->getPaintAlpha() == 0xFF && this->getInverseClass() != kPerspective_MatrixClass)
+                       flags |= SkShader::kHasSpan16_Flag;
+               else
+                       flags &= ~SkShader::kHasSpan16_Flag;
+
+               return flags;
+       }
+private:
+       typedef Sampler_BitmapShader INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////
+
+#define NOFILTER_BITMAP_SHADER_CLASS                                   Index8_NoFilter_ClampTile_BitmapShader
+#define NOFILTER_BITMAP_SHADER_TILEMODE                                        SkShader::kClamp_TileMode
+#define NOFILTER_BITMAP_SHADER_TILEPROC(x, max)                        SkClampMax((x >> 16), max)
+#define NOFILTER_BITMAP_SHADER_TYPE                                            uint8_t
+#define NOFILTER_BITMAP_SHADER_SAMPLE_X(p, x)                  colors32[p[x]]
+#define NOFILTER_BITMAP_SHADER_SAMPLE_XY(p, x, y, rb)  colors32[p[x + y * rb]]
+#define NOFILTER_BITMAP_SHADER_PREAMBLE(bitmap, rb)            const SkPMColor* colors32 = bitmap.getColorTable()->lockColors()
+#define NOFILTER_BITMAP_SHADER_POSTAMBLE(bitmap)               bitmap.getColorTable()->unlockColors(false)
+#define NOFILTER_BITMAP_SHADER_SAMPLE_X16(p, x)                        colors16[p[x]]
+#define NOFILTER_BITMAP_SHADER_SAMPLE_XY16(p, x, y, rb)        colors16[p[x + y * rb]]
+#define NOFILTER_BITMAP_SHADER_PREAMBLE16(bitmap, rb)  const uint16_t* colors16 = bitmap.getColorTable()->lock16BitCache()
+#define NOFILTER_BITMAP_SHADER_POSTAMBLE16(bitmap)             bitmap.getColorTable()->unlock16BitCache()
+#include "SkBitmapShaderTemplate.h"
+
+#define NOFILTER_BITMAP_SHADER_CLASS                                   Index8_NoFilter_RepeatTile_BitmapShader
+#define NOFILTER_BITMAP_SHADER_TILEMODE                                        SkShader::kRepeat_TileMode
+#define NOFILTER_BITMAP_SHADER_TILEPROC(x, max)                        (fixed_repeat(x) * (max + 1) >> 16)
+#define NOFILTER_BITMAP_SHADER_TYPE                                            uint8_t
+#define NOFILTER_BITMAP_SHADER_SAMPLE_X(p, x)                  colors32[p[x]]
+#define NOFILTER_BITMAP_SHADER_SAMPLE_XY(p, x, y, rb)  colors32[p[x + y * rb]]
+#define NOFILTER_BITMAP_SHADER_PREAMBLE(bitmap, rb)            const SkPMColor* colors32 = bitmap.getColorTable()->lockColors()
+#define NOFILTER_BITMAP_SHADER_POSTAMBLE(bitmap)               bitmap.getColorTable()->unlockColors(false)
+#define NOFILTER_BITMAP_SHADER_SAMPLE_X16(p, x)                        colors16[p[x]]
+#define NOFILTER_BITMAP_SHADER_SAMPLE_XY16(p, x, y, rb)        colors16[p[x + y * rb]]
+#define NOFILTER_BITMAP_SHADER_PREAMBLE16(bitmap, rb)  const uint16_t* colors16 = bitmap.getColorTable()->lock16BitCache()
+#define NOFILTER_BITMAP_SHADER_POSTAMBLE16(bitmap)             bitmap.getColorTable()->unlock16BitCache()
+#define NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
+#include "SkBitmapShaderTemplate.h"
+
+#define NOFILTER_BITMAP_SHADER_CLASS                                   U16_NoFilter_ClampTile_BitmapShader
+#define NOFILTER_BITMAP_SHADER_TILEMODE                                        SkShader::kClamp_TileMode
+#define NOFILTER_BITMAP_SHADER_TILEPROC(x, max)                        SkClampMax((x >> 16), max)
+#define NOFILTER_BITMAP_SHADER_TYPE                                            uint16_t
+#define NOFILTER_BITMAP_SHADER_SAMPLE_X(p, x)                  SkPixel16ToPixel32(p[x])
+#define NOFILTER_BITMAP_SHADER_SAMPLE_XY(p, x, y, rb)  SkPixel16ToPixel32(*(const uint16_t*)((const char*)p + y * rb + (x << 1)))
+#define NOFILTER_BITMAP_SHADER_SAMPLE_X16(p, x)                        p[x]
+#define NOFILTER_BITMAP_SHADER_SAMPLE_XY16(p, x, y, rb)        *(const uint16_t*)((const char*)p + y * rb + (x << 1))
+#include "SkBitmapShaderTemplate.h"
+
+#define NOFILTER_BITMAP_SHADER_CLASS                                   U16_NoFilter_RepeatTile_BitmapShader
+#define NOFILTER_BITMAP_SHADER_TILEMODE                                        SkShader::kRepeat_TileMode
+#define NOFILTER_BITMAP_SHADER_TILEPROC(x, max)                        (fixed_repeat(x) * (max + 1) >> 16)
+#define NOFILTER_BITMAP_SHADER_TYPE                                            uint16_t
+#define NOFILTER_BITMAP_SHADER_SAMPLE_X(p, x)                  SkPixel16ToPixel32(p[x])
+#define NOFILTER_BITMAP_SHADER_SAMPLE_XY(p, x, y, rb)  SkPixel16ToPixel32(*(const uint16_t*)((const char*)p + y * rb + (x << 1)))
+#define NOFILTER_BITMAP_SHADER_SAMPLE_X16(p, x)                        p[x]
+#define NOFILTER_BITMAP_SHADER_SAMPLE_XY16(p, x, y, rb)        *(const uint16_t*)((const char*)p + y * rb + (x << 1))
+#define NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
+#include "SkBitmapShaderTemplate.h"
+
+#define NOFILTER_BITMAP_SHADER_CLASS                                   U32_NoFilter_ClampTile_BitmapShader
+#define NOFILTER_BITMAP_SHADER_TILEMODE                                        SkShader::kClamp_TileMode
+#define NOFILTER_BITMAP_SHADER_TILEPROC(x, max)                        SkClampMax((x >> 16), max)
+#define NOFILTER_BITMAP_SHADER_TYPE                                            uint32_t
+#define NOFILTER_BITMAP_SHADER_SAMPLE_X(p, x)                  p[x]
+#define NOFILTER_BITMAP_SHADER_SAMPLE_XY(p, x, y, rb)  *(const uint32_t*)((const char*)p + y * rb + (x << 2))
+#define NOFILTER_BITMAP_SHADER_SAMPLE_X16(p, x)                        SkPixel32ToPixel16_ToU16(p[x])
+#define NOFILTER_BITMAP_SHADER_SAMPLE_XY16(p, x, y, rb)        SkPixel32ToPixel16_ToU16(*(const uint32_t*)((const char*)p + y * rb + (x << 2)))
+#include "SkBitmapShaderTemplate.h"
+
+#define NOFILTER_BITMAP_SHADER_CLASS                                   U32_NoFilter_RepeatTile_BitmapShader
+#define NOFILTER_BITMAP_SHADER_TILEMODE                                        SkShader::kRepeat_TileMode
+#define NOFILTER_BITMAP_SHADER_TILEPROC(x, max)                        (fixed_repeat(x) * (max + 1) >> 16)
+#define NOFILTER_BITMAP_SHADER_TYPE                                            uint32_t
+#define NOFILTER_BITMAP_SHADER_SAMPLE_X(p, x)                  p[x]
+#define NOFILTER_BITMAP_SHADER_SAMPLE_XY(p, x, y, rb)  *(const uint32_t*)((const char*)p + y * rb + (x << 2))
+#define NOFILTER_BITMAP_SHADER_SAMPLE_X16(p, x)                        SkPixel32ToPixel16_ToU16(p[x])
+#define NOFILTER_BITMAP_SHADER_SAMPLE_XY16(p, x, y, rb)        SkPixel32ToPixel16_ToU16(*(const uint32_t*)((const char*)p + y * rb + (x << 2)))
+#define NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
+#include "SkBitmapShaderTemplate.h"
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#define Pack4Bytes(c00, c01, c10, c11) (((c00) << 24) | ((c01) << 16) | ((c10) << 8) | (c11))
+/*     Each long stores 4 coefficients, each in a byte.
+       coeff >> 24     -> [0][0]
+       coeff >> 16     -> [0][1]
+       coeff >>  8     -> [1][0]
+       coeff >>  0     -> [1][1]
+*/
+static const uint32_t gBilerpPackedCoeff[] = {
+       /* y == 0 */
+       Pack4Bytes(16,  0,  0,  0),     // x == 0
+       Pack4Bytes(12,  4,  0,  0),     // x == 1/4
+       Pack4Bytes( 8,  8,  0,  0),     // x == 1/2
+       Pack4Bytes( 4, 12,  0,  0),     // x == 3/4
+
+       /* y == 1/4 */
+       Pack4Bytes(12,  0,  4,  0),
+       Pack4Bytes( 9,  3,  3,  1),
+       Pack4Bytes( 6,  6,  2,  2),
+       Pack4Bytes( 3,  9,  1,  3),
+
+       /* y == 1/2 */
+       Pack4Bytes( 8,  0,  8,  0),
+       Pack4Bytes( 6,  2,  6,  2),
+       Pack4Bytes( 4,  4,  4,  4),
+       Pack4Bytes( 2,  6,  2,  6),
+
+       /* y == 3/4 */
+       Pack4Bytes( 4,  0, 12,  0),
+       Pack4Bytes( 3,  1,  9,  3),
+       Pack4Bytes( 2,  2,  6,  6),
+       Pack4Bytes( 1,  3,  3,  9)
+};
+
+// extract the high two bits in the fractional part of the fixed
+#define SK_BILERP_GET_BITS(x)  (((x) >> 14) & 3)
+
+static inline uint32_t sk_find_bilerp_coeff(const uint32_t coeff[], SkFixed fx, SkFixed fy)
+{
+#ifdef SK_DEBUG
+       uint32_t c = coeff[(SK_BILERP_GET_BITS(fy) << 2) | SK_BILERP_GET_BITS(fx)];
+       SkASSERT((c >> 24) + ((c >> 16) & 0xFF) + ((c >> 8) & 0xFF) + (c & 0xFF) == 16);
+#endif
+       return coeff[(SK_BILERP_GET_BITS(fy) << 2) | SK_BILERP_GET_BITS(fx)];
+}
+
+static inline uint32_t expand_rgb_16(U16CPU c, U16CPU rbMask)
+{
+       return ((c & SK_G16_MASK_IN_PLACE) << 16) | (c & rbMask);
+}
+
+static inline U16CPU compact_rgb_16(uint32_t c, U16CPU rbMask)
+{
+       return ((c >> 16) & SK_G16_MASK_IN_PLACE) | (c & rbMask);
+}
+
+static inline U16CPU sk_bilerp16(U16CPU c00, U16CPU c01, U16CPU c10, U16CPU c11, uint32_t coeff, U16CPU rbMask)
+{
+//     U16CPU rbMask = SK_R16B16_MASK_IN_PLACE;
+
+       c00 =   expand_rgb_16(c00, rbMask) * (coeff >> 24) +
+                       expand_rgb_16(c01, rbMask) * ((coeff >> 16) & 0xFF) +
+                       expand_rgb_16(c10, rbMask) * ((coeff >> 8) & 0xFF) +
+                       expand_rgb_16(c11, rbMask) * (coeff & 0xFF);
+
+       return compact_rgb_16(c00 >> 4, rbMask);
+}
+
+// this wacky line is to force the compiler to put this contant into a register
+// rather than try to construct it each time it is referenced in the inner-loop
+extern const uint16_t gRBMask_Bilerp_BitmapShader;
+
+#define BILERP_BITMAP16_SHADER_CLASS                   U16_Bilerp_BitmapShader
+#define BILERP_BITMAP16_SHADER_TYPE                            uint16_t
+#define BILERP_BITMAP16_SHADER_PREAMBLE(bm)
+#define BILERP_BITMAP16_SHADER_PIXEL(c)                        (c)
+#define BILERP_BITMAP16_SHADER_POSTAMBLE(bm)
+#include "SkBitmapShader16BilerpTemplate.h"
+
+#define BILERP_BITMAP16_SHADER_CLASS                   Index8_Bilerp_BitmapShader
+#define BILERP_BITMAP16_SHADER_TYPE                            uint8_t
+#define BILERP_BITMAP16_SHADER_PREAMBLE(bm)            SkColorTable* ctable = (bm).getColorTable(); const uint16_t* colors16 = ctable->lock16BitCache()
+#define BILERP_BITMAP16_SHADER_PIXEL(c)                        colors16[c]
+#define BILERP_BITMAP16_SHADER_POSTAMBLE(bm)   ctable->unlock16BitCache()
+#include "SkBitmapShader16BilerpTemplate.h"
+
+// we define it below all the includes, so they won't try to inline the value
+// (which doesn't fit in an immediate register load)
+const uint16_t gRBMask_Bilerp_BitmapShader = SK_R16B16_MASK_IN_PLACE;
+
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+
+#include "SkTemplatesPriv.h"
+
+SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
+                                                                          bool transferOwnershipOfPixels,
+                                                                          SkPaint::FilterType filterType,
+                                                                          TileMode tmx, TileMode tmy,
+                                                                          void* storage, size_t storageSize)
+{
+       SkShader* shader = NULL;
+
+       if (filterType == SkPaint::kNo_FilterType)
+       {
+               switch (src.getConfig()) {
+               case SkBitmap::kIndex8_Config:
+                       if (kClamp_TileMode == tmx && kClamp_TileMode == tmy)
+                               SK_PLACEMENT_NEW_ARGS(shader, Index8_NoFilter_ClampTile_BitmapShader, storage, storageSize, (src, transferOwnershipOfPixels));
+            else if (kRepeat_TileMode == tmx && kRepeat_TileMode == tmy)
+                               SK_PLACEMENT_NEW_ARGS(shader, Index8_NoFilter_RepeatTile_BitmapShader, storage, storageSize, (src, transferOwnershipOfPixels));
+                       break;
+               case SkBitmap::kRGB_565_Config:
+            if (kClamp_TileMode == tmx && kClamp_TileMode == tmy)
+                SK_PLACEMENT_NEW_ARGS(shader, U16_NoFilter_ClampTile_BitmapShader, storage, storageSize, (src, transferOwnershipOfPixels));
+            else if (kRepeat_TileMode == tmx && kRepeat_TileMode == tmy)
+                SK_PLACEMENT_NEW_ARGS(shader, U16_NoFilter_RepeatTile_BitmapShader, storage, storageSize, (src, transferOwnershipOfPixels));
+                       break;
+               case SkBitmap::kARGB_8888_Config:
+                       if (kClamp_TileMode == tmx && kClamp_TileMode == tmy)
+                               SK_PLACEMENT_NEW_ARGS(shader, U32_NoFilter_ClampTile_BitmapShader, storage, storageSize, (src, transferOwnershipOfPixels));
+            else if (kRepeat_TileMode == tmx && kRepeat_TileMode == tmy)
+                               SK_PLACEMENT_NEW_ARGS(shader, U32_NoFilter_RepeatTile_BitmapShader, storage, storageSize, (src, transferOwnershipOfPixels));
+                       break;
+               default:
+                       break;
+               }
+       }
+       else if (filterType == SkPaint::kBilinear_FilterType
+             && kClamp_TileMode == tmx
+             && kClamp_TileMode == tmy)
+       {
+               switch (src.getConfig()) {
+               case SkBitmap::kIndex8_Config:
+                       SK_PLACEMENT_NEW_ARGS(shader, Index8_Bilerp_BitmapShader, storage, storageSize, (src, transferOwnershipOfPixels));
+                       break;
+               case SkBitmap::kRGB_565_Config:
+                       SK_PLACEMENT_NEW_ARGS(shader, U16_Bilerp_BitmapShader, storage, storageSize, (src, transferOwnershipOfPixels));
+                       break;
+        default:
+            break;
+               }
+       }
+    
+    // if shader is null, then none of the special cases could handle the request
+    // so fall through to our slow-general case
+       if (shader == NULL)
+               SK_PLACEMENT_NEW_ARGS(shader, Sampler_BitmapShader, storage, storageSize,
+                              (src, transferOwnershipOfPixels, filterType, tmx, tmy));
+       return shader;
+}
+
+SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
+                                                                          bool transferOwnershipOfPixels,
+                                                                          SkPaint::FilterType filterType,
+                                                                          TileMode tmx, TileMode tmy)
+{
+       return SkShader::CreateBitmapShader(src, transferOwnershipOfPixels, filterType, tmx, tmy, NULL, 0);
+}
+
diff --git a/libs/graphics/sgl/SkBitmapShader.h b/libs/graphics/sgl/SkBitmapShader.h
new file mode 100644 (file)
index 0000000..6727ec4
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef SkBitmapShader_DEFINED
+#define SkBitmapShader_DEFINED
+
+#include "SkShader.h"
+#include "SkBitmap.h"
+#include "SkPaint.h"
+
+class SkBitmapShader : public SkShader {
+public:
+       SkBitmapShader( const SkBitmap& src, bool transferOwnershipOfPixels,
+                                       SkPaint::FilterType, TileMode tx, TileMode ty);
+
+       virtual bool        setContext(const SkBitmap&, const SkPaint& paint, const SkMatrix&);
+       virtual uint32_t        getFlags() { return fFlags; }
+
+protected:
+       const SkBitmap&         getSrcBitmap() const
+    {
+#ifdef SK_SUPPORT_MIPMAP
+        return fMipSrcBitmap;
+#else
+        return fOrigSrcBitmap;
+#endif
+    }
+       SkPaint::FilterType     getFilterType() const { return (SkPaint::FilterType)fFilterType; }
+       TileMode            getTileModeX() const { return (TileMode)fTileModeX; }
+       TileMode            getTileModeY() const { return (TileMode)fTileModeY; }
+       SkFixed                         getMipLevel() const 
+    {
+#ifdef SK_SUPPORT_MIPMAP
+        return fMipLevel;
+#else
+        return 0;
+#endif
+    }
+
+private:
+#ifdef SK_SUPPORT_MIPMAP
+       SkFixed         fMipLevel;
+    SkBitmap    fMipSrcBitmap; // the chosen level (in setContext)
+#endif
+       SkBitmap        fOrigSrcBitmap;
+       U8                      fFilterType;
+       U8                      fTileModeX;
+    U8          fTileModeY;
+       U8                      fFlags;
+
+       typedef SkShader INHERITED;
+};
+
+#endif
diff --git a/libs/graphics/sgl/SkBitmapShader16BilerpTemplate.h b/libs/graphics/sgl/SkBitmapShader16BilerpTemplate.h
new file mode 100644 (file)
index 0000000..fa64a61
--- /dev/null
@@ -0,0 +1,126 @@
+
+
+class BILERP_BITMAP16_SHADER_CLASS : public HasSpan16_Sampler_BitmapShader {
+public:
+       BILERP_BITMAP16_SHADER_CLASS(const SkBitmap& src, bool transferOwnershipOfPixels)
+               : HasSpan16_Sampler_BitmapShader(src, transferOwnershipOfPixels, SkPaint::kBilinear_FilterType,
+                                         SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)
+       {
+       }
+
+       virtual void shadeSpanOpaque16(int x, int y, U16 dstC[], int count)
+       {
+               SkASSERT(count > 0);
+               SkASSERT(this->getInverseClass() != kPerspective_MatrixClass);
+               SkASSERT(this->getPaintAlpha() == 0xFF);
+
+               const SkMatrix& inv = this->getTotalInverse();
+               const SkBitmap& srcBitmap = this->getSrcBitmap();
+               unsigned                srcMaxX = srcBitmap.width() - 1;
+               unsigned                srcMaxY = srcBitmap.height() - 1;
+               unsigned                srcRB = srcBitmap.rowBytes();
+               SkFixed                 fx, fy, dx, dy;
+
+               // now init fx, fy, dx, dy
+               {
+                       SkPoint srcPt;
+                       this->getInverseMapPtProc()(inv, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
+
+                       fx = SkScalarToFixed(srcPt.fX);
+                       fy = SkScalarToFixed(srcPt.fY);
+
+                       if (this->getInverseClass() == kFixedStepInX_MatrixClass)
+                               (void)inv.fixedStepInX(SkIntToScalar(y), &dx, &dy);
+                       else
+                       {
+                               dx = SkScalarToFixed(inv.getScaleX());
+                               dy = SkScalarToFixed(inv.getSkewY());
+                       }
+               }
+
+               BILERP_BITMAP16_SHADER_PREAMBLE(srcBitmap);
+
+               const U32* coeff_table = gBilerpPackedCoeff;
+               const BILERP_BITMAP16_SHADER_TYPE* srcPixels = (const BILERP_BITMAP16_SHADER_TYPE*)srcBitmap.getPixels();
+               U16CPU rbMask = gRBMask_Bilerp_BitmapShader;
+
+               if (dy == 0)
+               {
+                       fy = SkClampMax(fy, srcMaxY << 16);
+                       coeff_table += SK_BILERP_GET_BITS(fy) << 2;     // jump the table to the correct section (so we can just use fx to index it)
+
+                       unsigned y = fy >> 16;
+                       SkASSERT((int)y >= 0 && y <= srcMaxY);
+                       // pre-bias srcPixels since y won't change
+                       srcPixels = (const BILERP_BITMAP16_SHADER_TYPE*)((const char*)srcPixels + y * srcRB);
+                       // now make y the step from one row to the next
+                       y = srcRB;
+                       if (y == srcMaxY)
+                               y = 0;
+
+                       do {
+                               unsigned fx_clamped = SkClampMax(fx, srcMaxX << 16);
+                               unsigned x = fx_clamped >> 16;
+                               SkASSERT((int)x >= 0 && x <= srcMaxX);
+
+                               const BILERP_BITMAP16_SHADER_TYPE *p00, *p01, *p10, *p11;
+
+                               p00 = p01 = srcPixels + x;
+                               if (x < srcMaxX)
+                                       p01 += 1;
+                               p10 = (const BILERP_BITMAP16_SHADER_TYPE*)((const char*)p00 + y);
+                               p11 = (const BILERP_BITMAP16_SHADER_TYPE*)((const char*)p01 + y);
+
+                               *dstC++ = SkToU16(sk_bilerp16(  BILERP_BITMAP16_SHADER_PIXEL(*p00),
+                                                                                               BILERP_BITMAP16_SHADER_PIXEL(*p01),
+                                                                                               BILERP_BITMAP16_SHADER_PIXEL(*p10),
+                                                                                               BILERP_BITMAP16_SHADER_PIXEL(*p11),
+                                                                                               coeff_table[SK_BILERP_GET_BITS(fx_clamped)],
+                                                                                               rbMask));
+
+                               fx += dx;
+                       } while (--count != 0);
+               }
+               else
+               {
+                       do {
+                               unsigned x = SkClampMax(fx, srcMaxX << 16) >> 16;
+                               unsigned y = SkClampMax(fy, srcMaxY << 16) >> 16;
+
+                               SkASSERT((int)x >= 0 && x <= srcMaxX);
+                               SkASSERT((int)y >= 0 && y <= srcMaxY);
+
+                               const BILERP_BITMAP16_SHADER_TYPE *p00, *p01, *p10, *p11;
+
+                               p00 = p01 = ((const BILERP_BITMAP16_SHADER_TYPE*)((const char*)srcPixels + y * srcRB)) + x;
+                               if (x < srcMaxX)
+                                       p01 += 1;
+                               p10 = p00;
+                               p11 = p01;
+                               if (y < srcMaxY)
+                               {
+                                       p10 = (const BILERP_BITMAP16_SHADER_TYPE*)((const char*)p10 + srcRB);
+                                       p11 = (const BILERP_BITMAP16_SHADER_TYPE*)((const char*)p11 + srcRB);
+                               }
+
+                               *dstC++ = SkToU16(sk_bilerp16(  BILERP_BITMAP16_SHADER_PIXEL(*p00),
+                                                                                               BILERP_BITMAP16_SHADER_PIXEL(*p01),
+                                                                                               BILERP_BITMAP16_SHADER_PIXEL(*p10),
+                                                                                               BILERP_BITMAP16_SHADER_PIXEL(*p11),
+                                                                                               sk_find_bilerp_coeff(coeff_table, fx, fy),
+                                                                                               rbMask));
+
+                               fx += dx;
+                               fy += dy;
+                       } while (--count != 0);
+               }
+
+               BILERP_BITMAP16_SHADER_POSTAMBLE(srcBitmap);
+       }
+};
+
+#undef BILERP_BITMAP16_SHADER_CLASS
+#undef BILERP_BITMAP16_SHADER_TYPE
+#undef BILERP_BITMAP16_SHADER_PREAMBLE
+#undef BILERP_BITMAP16_SHADER_PIXEL
+#undef BILERP_BITMAP16_SHADER_POSTAMBLE
diff --git a/libs/graphics/sgl/SkBitmapShaderTemplate.h b/libs/graphics/sgl/SkBitmapShaderTemplate.h
new file mode 100644 (file)
index 0000000..2e90b84
--- /dev/null
@@ -0,0 +1,231 @@
+
+#ifndef NOFILTER_BITMAP_SHADER_PREAMBLE
+       #define NOFILTER_BITMAP_SHADER_PREAMBLE(bitmap, rb)
+#endif
+#ifndef NOFILTER_BITMAP_SHADER_POSTAMBLE
+       #define NOFILTER_BITMAP_SHADER_POSTAMBLE(bitmap)
+#endif
+#ifndef NOFILTER_BITMAP_SHADER_PREAMBLE16
+       #define NOFILTER_BITMAP_SHADER_PREAMBLE16(bitmap, rb)
+#endif
+#ifndef NOFILTER_BITMAP_SHADER_POSTAMBLE16
+       #define NOFILTER_BITMAP_SHADER_POSTAMBLE16(bitmap)
+#endif
+
+class NOFILTER_BITMAP_SHADER_CLASS : public HasSpan16_Sampler_BitmapShader {
+public:
+       NOFILTER_BITMAP_SHADER_CLASS(const SkBitmap& src, bool transferOwnershipOfPixels)
+               : HasSpan16_Sampler_BitmapShader(src, transferOwnershipOfPixels, SkPaint::kNo_FilterType,
+                                         NOFILTER_BITMAP_SHADER_TILEMODE, NOFILTER_BITMAP_SHADER_TILEMODE)
+       {
+       }
+    
+#ifdef NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
+    virtual bool setContext(const SkBitmap& device, const SkPaint& paint, const SkMatrix& matrix)
+    {
+        if (this->INHERITED::setContext(device, paint, matrix)) {
+            this->computeUnitInverse();
+            return true;
+        }
+        return false;
+    }
+#endif
+
+       virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count)
+       {
+               if (this->getInverseClass() == kPerspective_MatrixClass)
+               {
+                       this->INHERITED::shadeSpan(x, y, dstC, count);
+                       return;
+               }
+
+               unsigned                scale = SkAlpha255To256(this->getPaintAlpha());
+#ifdef NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
+        const SkMatrix& inv = this->getUnitInverse();
+        SkMatrix::MapPtProc invProc = this->getUnitInverseProc();
+#else
+               const SkMatrix& inv = this->getTotalInverse();
+        SkMatrix::MapPtProc invProc = this->getInverseMapPtProc();
+#endif
+               const SkBitmap& srcBitmap = this->getSrcBitmap();
+               unsigned                srcMaxX = srcBitmap.width() - 1;
+               unsigned                srcMaxY = srcBitmap.height() - 1;
+               unsigned                srcRB = srcBitmap.rowBytes();
+               SkFixed                 fx, fy, dx, dy;
+
+               // now init fx, fy, dx, dy
+               {
+                       SkPoint srcPt;
+                       invProc(inv, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
+
+                       fx = SkScalarToFixed(srcPt.fX);
+                       fy = SkScalarToFixed(srcPt.fY);
+#ifndef NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
+            fx += SK_Fixed1/2;
+            fy += SK_Fixed1/2;
+#endif
+
+                       if (this->getInverseClass() == kFixedStepInX_MatrixClass)
+                               (void)inv.fixedStepInX(SkIntToScalar(y), &dx, &dy);
+                       else
+                       {
+                               dx = SkScalarToFixed(inv.getScaleX());
+                               dy = SkScalarToFixed(inv.getSkewY());
+                       }
+               }
+
+               const NOFILTER_BITMAP_SHADER_TYPE* srcPixels = (const NOFILTER_BITMAP_SHADER_TYPE*)srcBitmap.getPixels();
+               NOFILTER_BITMAP_SHADER_PREAMBLE(srcBitmap, srcRB);
+
+#if defined(SK_SUPPORT_MIPMAP) && !defined(NOFILTER_BITMAP_SHADER_USE_UNITINVERSE)
+        {   int level = this->getMipLevel() >> 16;
+            fx >>= level;
+            fy >>= level;
+            dx >>= level;
+            dy >>= level;
+               }
+#endif
+
+               if (dy == 0)
+               {
+                       int y_index = NOFILTER_BITMAP_SHADER_TILEPROC(fy, srcMaxY);
+//                     SkDEBUGF(("fy = %g, srcMaxY = %d, y_index = %d\n", SkFixedToFloat(fy), srcMaxY, y_index));
+                       srcPixels = (const NOFILTER_BITMAP_SHADER_TYPE*)((const char*)srcPixels + y_index * srcRB);
+                       if (scale == 256)
+                               while (--count >= 0)
+                               {
+                                       unsigned x = NOFILTER_BITMAP_SHADER_TILEPROC(fx, srcMaxX);
+                                       fx += dx;
+                                       *dstC++ = NOFILTER_BITMAP_SHADER_SAMPLE_X(srcPixels, x);
+                               }
+                       else
+                               while (--count >= 0)
+                               {
+                                       unsigned x = NOFILTER_BITMAP_SHADER_TILEPROC(fx, srcMaxX);
+                                       U32 c = NOFILTER_BITMAP_SHADER_SAMPLE_X(srcPixels, x);
+                                       fx += dx;
+                                       *dstC++ = SkAlphaMulQ(c, scale);
+                               }
+               }
+               else    // dy != 0
+               {
+                       if (scale == 256)
+                               while (--count >= 0)
+                               {
+                                       unsigned x = NOFILTER_BITMAP_SHADER_TILEPROC(fx, srcMaxX);
+                                       unsigned y = NOFILTER_BITMAP_SHADER_TILEPROC(fy, srcMaxY);
+                                       fx += dx;
+                                       fy += dy;
+                                       *dstC++ = NOFILTER_BITMAP_SHADER_SAMPLE_XY(srcPixels, x, y, srcRB);
+                               }
+                       else
+                               while (--count >= 0)
+                               {
+                                       unsigned x = NOFILTER_BITMAP_SHADER_TILEPROC(fx, srcMaxX);
+                                       unsigned y = NOFILTER_BITMAP_SHADER_TILEPROC(fy, srcMaxY);
+                                       U32 c = NOFILTER_BITMAP_SHADER_SAMPLE_XY(srcPixels, x, y, srcRB);
+                                       fx += dx;
+                                       fy += dy;
+                                       *dstC++ = SkAlphaMulQ(c, scale);
+                               }
+               }
+
+               NOFILTER_BITMAP_SHADER_POSTAMBLE(srcBitmap);
+       }
+
+       virtual void shadeSpanOpaque16(int x, int y, U16 dstC[], int count)
+       {
+               SkASSERT(count > 0);
+               SkASSERT(this->getInverseClass() != kPerspective_MatrixClass);
+               SkASSERT(this->getFlags() & SkShader::kHasSpan16_Flag);
+               SkASSERT(this->getFlags() & (SkShader::kOpaqueAlpha_Flag | SkShader::kConstAlpha_Flag));
+
+#ifdef NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
+        const SkMatrix& inv = this->getUnitInverse();
+        SkMatrix::MapPtProc invProc = this->getUnitInverseProc();
+#else
+               const SkMatrix& inv = this->getTotalInverse();
+        SkMatrix::MapPtProc invProc = this->getInverseMapPtProc();
+#endif
+               const SkBitmap& srcBitmap = this->getSrcBitmap();
+               unsigned                srcMaxX = srcBitmap.width() - 1;
+               unsigned                srcMaxY = srcBitmap.height() - 1;
+               unsigned                srcRB = srcBitmap.rowBytes();
+               SkFixed                 fx, fy, dx, dy;
+
+               // now init fx, fy, dx, dy
+               {
+                       SkPoint srcPt;
+                       invProc(inv, SkIntToScalar(x), SkIntToScalar(y), &srcPt);
+
+                       fx = SkScalarToFixed(srcPt.fX);
+                       fy = SkScalarToFixed(srcPt.fY);
+#ifndef NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
+            fx += SK_Fixed1/2;
+            fy += SK_Fixed1/2;
+#endif
+
+                       if (this->getInverseClass() == kFixedStepInX_MatrixClass)
+                               (void)inv.fixedStepInX(SkIntToScalar(y), &dx, &dy);
+                       else
+                       {
+                               dx = SkScalarToFixed(inv.getScaleX());
+                               dy = SkScalarToFixed(inv.getSkewY());
+                       }
+               }
+
+               const NOFILTER_BITMAP_SHADER_TYPE* srcPixels = (const NOFILTER_BITMAP_SHADER_TYPE*)srcBitmap.getPixels();
+               NOFILTER_BITMAP_SHADER_PREAMBLE16(srcBitmap, srcRB);
+
+#if defined(SK_SUPPORT_MIPMAP) && !defined(NOFILTER_BITMAP_SHADER_USE_UNITINVERSE)
+        {   int level = this->getMipLevel() >> 16;
+            fx >>= level;
+            fy >>= level;
+            dx >>= level;
+            dy >>= level;
+               }
+#endif
+
+               if (dy == 0)
+               {
+                       srcPixels = (const NOFILTER_BITMAP_SHADER_TYPE*)((const char*)srcPixels + NOFILTER_BITMAP_SHADER_TILEPROC(fy, srcMaxY) * srcRB);
+                       do {
+                               unsigned x = NOFILTER_BITMAP_SHADER_TILEPROC(fx, srcMaxX);
+                               fx += dx;
+                               *dstC++ = NOFILTER_BITMAP_SHADER_SAMPLE_X16(srcPixels, x);
+                       } while (--count != 0);
+               }
+               else    // dy != 0
+               {
+                       do {
+                               int ix = fx >> 16;
+                               unsigned x = NOFILTER_BITMAP_SHADER_TILEPROC(ix, srcMaxX);
+                               ix = fy >> 16;
+                               unsigned y = NOFILTER_BITMAP_SHADER_TILEPROC(ix, srcMaxY);
+                               fx += dx;
+                               fy += dy;
+                               *dstC++ = NOFILTER_BITMAP_SHADER_SAMPLE_XY16(srcPixels, x, y, srcRB);
+                       } while (--count != 0);
+               }
+
+               NOFILTER_BITMAP_SHADER_POSTAMBLE16(srcBitmap);
+       }
+private:
+       typedef HasSpan16_Sampler_BitmapShader INHERITED;
+};
+
+#undef NOFILTER_BITMAP_SHADER_CLASS
+#undef NOFILTER_BITMAP_SHADER_TYPE
+#undef NOFILTER_BITMAP_SHADER_PREAMBLE
+#undef NOFILTER_BITMAP_SHADER_POSTAMBLE
+#undef NOFILTER_BITMAP_SHADER_SAMPLE_X         //(x)
+#undef NOFILTER_BITMAP_SHADER_SAMPLE_XY                //(x, y, rowBytes)
+#undef NOFILTER_BITMAP_SHADER_TILEMODE
+#undef NOFILTER_BITMAP_SHADER_TILEPROC
+
+#undef NOFILTER_BITMAP_SHADER_PREAMBLE16
+#undef NOFILTER_BITMAP_SHADER_POSTAMBLE16
+#undef NOFILTER_BITMAP_SHADER_SAMPLE_X16               //(x)
+#undef NOFILTER_BITMAP_SHADER_SAMPLE_XY16              //(x, y, rowBytes)
+
+#undef NOFILTER_BITMAP_SHADER_USE_UNITINVERSE
diff --git a/libs/graphics/sgl/SkBlitBWMaskTemplate.h b/libs/graphics/sgl/SkBlitBWMaskTemplate.h
new file mode 100644 (file)
index 0000000..70530f1
--- /dev/null
@@ -0,0 +1,120 @@
+#include "SkBitmap.h"
+#include "SkMask.h"
+
+#ifndef ClearLow3Bits_DEFINED
+#define ClearLow3Bits_DEFINED
+       #define ClearLow3Bits(x)        ((unsigned)(x) >> 3 << 3)
+#endif
+
+/*
+       SK_BLITBWMASK_NAME                      name of function(const SkBitmap& bitmap, const SkMask& mask, const SkRect16& clip, SK_BLITBWMASK_ARGS)
+       SK_BLITBWMASK_ARGS                      list of additional arguments to SK_BLITBWMASK_NAME, beginning with a comma
+       SK_BLITBWMASK_BLIT8                     name of function(U8CPU byteMask, SK_BLITBWMASK_DEVTYPE* dst, int x, int y)
+       SK_BLITBWMASK_GETADDR           either getAddr32 or getAddr16 or getAddr8
+       SK_BLITBWMASK_DEVTYPE           either U32 or U16 or U8
+*/
+
+static void SK_BLITBWMASK_NAME(const SkBitmap& bitmap, const SkMask& srcMask, const SkRect16& clip SK_BLITBWMASK_ARGS)
+{
+       SkASSERT(clip.fRight <= srcMask.fBounds.fRight);
+
+       int cx = clip.fLeft;
+       int cy = clip.fTop;
+       int maskLeft = srcMask.fBounds.fLeft;
+       unsigned mask_rowBytes = srcMask.fRowBytes;
+       unsigned bitmap_rowBytes = bitmap.rowBytes();
+       unsigned height = clip.height();
+
+       SkASSERT(mask_rowBytes != 0);
+       SkASSERT(bitmap_rowBytes != 0);
+       SkASSERT(height != 0);
+
+       const U8* bits = srcMask.getAddr1(cx, cy);
+       SK_BLITBWMASK_DEVTYPE* device = bitmap.SK_BLITBWMASK_GETADDR(cx, cy);
+
+       if (cx == maskLeft && clip.fRight == srcMask.fBounds.fRight)
+       {
+               do {
+                       SK_BLITBWMASK_DEVTYPE* dst = device;
+                       unsigned rb = mask_rowBytes;
+                       do {
+                               U8CPU mask = *bits++;
+                               SK_BLITBWMASK_BLIT8(mask, dst);
+                               dst += 8;
+                       } while (--rb != 0);
+                       device = (SK_BLITBWMASK_DEVTYPE*)((char*)device + bitmap_rowBytes);
+               } while (--height != 0);
+       }
+       else
+       {
+               int left_edge = cx - maskLeft;
+               SkASSERT(left_edge >= 0);
+               int rite_edge = clip.fRight - maskLeft;
+               SkASSERT(rite_edge > left_edge);
+
+               int left_mask = 0xFF >> (left_edge & 7);
+               int rite_mask = 0xFF << (8 - (rite_edge & 7));
+               int full_runs = (rite_edge >> 3) - ((left_edge + 7) >> 3);
+
+               // check for empty right mask, so we don't read off the end (or go slower than we need to)
+               if (rite_mask == 0)
+               {
+                       SkASSERT(full_runs >= 0);
+                       full_runs -= 1;
+                       rite_mask = 0xFF;
+               }
+               if (left_mask == 0xFF)
+                       full_runs -= 1;
+
+               // back up manually so we can keep in sync with our byte-aligned src
+               // and not trigger an assert from the getAddr## function
+               device -= left_edge & 7;
+               // have cx reflect our actual starting x-coord
+               cx -= left_edge & 7;
+
+               if (full_runs < 0)
+               {
+                       left_mask &= rite_mask;
+                       SkASSERT(left_mask != 0);
+                       do {
+                               U8CPU mask = *bits & left_mask;
+                               SK_BLITBWMASK_BLIT8(mask, device);
+                               bits += mask_rowBytes;
+                               device = (SK_BLITBWMASK_DEVTYPE*)((char*)device + bitmap_rowBytes);
+                       } while (--height != 0);
+               }
+               else
+               {
+                       do {
+                               int runs = full_runs;
+                               SK_BLITBWMASK_DEVTYPE* dst = device;
+                               const U8* b = bits;
+                               U8CPU   mask;
+
+                               mask = *b++ & left_mask;
+                               SK_BLITBWMASK_BLIT8(mask, dst);
+                               dst += 8;
+
+                               while (--runs >= 0)
+                               {
+                                       mask = *b++;
+                                       SK_BLITBWMASK_BLIT8(mask, dst);
+                                       dst += 8;
+                               }
+
+                               mask = *b & rite_mask;
+                               SK_BLITBWMASK_BLIT8(mask, dst);
+
+                               bits += mask_rowBytes;
+                               device = (SK_BLITBWMASK_DEVTYPE*)((char*)device + bitmap_rowBytes);
+                       } while (--height != 0);
+               }
+       }
+}      
+
+#undef SK_BLITBWMASK_NAME
+#undef SK_BLITBWMASK_ARGS
+#undef SK_BLITBWMASK_BLIT8
+#undef SK_BLITBWMASK_GETADDR
+#undef SK_BLITBWMASK_DEVTYPE
+#undef SK_BLITBWMASK_DOROWSETUP
diff --git a/libs/graphics/sgl/SkBlitter.cpp b/libs/graphics/sgl/SkBlitter.cpp
new file mode 100644 (file)
index 0000000..5dcac42
--- /dev/null
@@ -0,0 +1,795 @@
+#include "SkBlitter.h"
+#include "SkAntiRun.h"
+#include "SkColor.h"
+#include "SkColorFilter.h"
+#include "SkMask.h"
+#include "SkMaskFilter.h"
+#include "SkTemplatesPriv.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+
+SkBlitter::~SkBlitter()
+{
+}
+
+void SkBlitter::blitH(int x, int y, int width)
+{
+       SkASSERT(!"unimplemented");
+}
+
+void SkBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[])
+{
+       SkASSERT(!"unimplemented");
+}
+
+void SkBlitter::blitV(int x, int y, int height, SkAlpha alpha)
+{
+       if (alpha == 255)
+               this->blitRect(x, y, 1, height);
+       else
+       {
+               int16_t runs[2];
+               runs[0] = 1;
+               runs[1] = 0;
+
+               while (--height >= 0)
+                       this->blitAntiH(x, y++, &alpha, runs);
+       }
+}
+
+void SkBlitter::blitRect(int x, int y, int width, int height)
+{
+       while (--height >= 0)
+               this->blitH(x, y++, width);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+static inline void bits_to_runs(SkBlitter* blitter, int x, int y, const uint8_t bits[], U8CPU left_mask, int rowBytes, U8CPU right_mask)
+{
+       int     inFill = 0;
+       int pos = 0;
+
+       while (--rowBytes >= 0)
+       {
+               unsigned b = *bits++ & left_mask;
+               if (rowBytes == 0)
+                       b &= right_mask;
+
+               for (unsigned test = 0x80; test != 0; test >>= 1)
+               {
+                       if (b & test)
+                       {
+                               if (!inFill)
+                               {
+                                       pos = x;
+                                       inFill = true;
+                               }
+                       }
+                       else
+                       {
+                               if (inFill)
+                               {
+                                       blitter->blitH(pos, y, x - pos);
+                                       inFill = false;
+                               }
+                       }
+                       x += 1;
+               }
+               left_mask = 0xFF;
+       }
+
+       // final cleanup
+       if (inFill)
+               blitter->blitH(pos, y, x - pos);
+}
+
+void SkBlitter::blitMask(const SkMask& mask, const SkRect16& clip)
+{
+       SkASSERT(mask.fBounds.contains(clip));
+
+       if (mask.fFormat == SkMask::kBW_Format)
+       {
+               int cx = clip.fLeft;
+               int cy = clip.fTop;
+               int maskLeft = mask.fBounds.fLeft;
+               int mask_rowBytes = mask.fRowBytes;
+               int     height = clip.height();
+
+               const uint8_t* bits = mask.getAddr1(cx, cy);
+
+               if (cx == maskLeft && clip.fRight == mask.fBounds.fRight)
+               {
+                       while (--height >= 0)
+                       {
+                               bits_to_runs(this, cx, cy, bits, 0xFF, mask_rowBytes, 0xFF);
+                               bits += mask_rowBytes;
+                               cy += 1;
+                       }
+               }
+               else
+               {
+                       int left_edge = cx - maskLeft;
+                       SkASSERT(left_edge >= 0);
+                       int rite_edge = clip.fRight - maskLeft;
+                       SkASSERT(rite_edge > left_edge);
+
+                       int left_mask = 0xFF >> (left_edge & 7);
+                       int rite_mask = 0xFF << (8 - (rite_edge & 7));
+                       int full_runs = (rite_edge >> 3) - ((left_edge + 7) >> 3);
+
+                       // check for empty right mask, so we don't read off the end (or go slower than we need to)
+                       if (rite_mask == 0)
+                       {
+                               SkASSERT(full_runs >= 0);
+                               full_runs -= 1;
+                               rite_mask = 0xFF;
+                       }
+                       if (left_mask == 0xFF)
+                               full_runs -= 1;
+
+                       // back up manually so we can keep in sync with our byte-aligned src
+                       // have cx reflect our actual starting x-coord
+                       cx -= left_edge & 7;
+
+                       if (full_runs < 0)
+                       {
+                               SkASSERT((left_mask & rite_mask) != 0);
+                               while (--height >= 0)
+                               {
+                                       bits_to_runs(this, cx, cy, bits, left_mask, 1, rite_mask);
+                                       bits += mask_rowBytes;
+                                       cy += 1;
+                               }
+                       }
+                       else
+                       {
+                               while (--height >= 0)
+                               {
+                                       bits_to_runs(this, cx, cy, bits, left_mask, full_runs + 2, rite_mask);
+                                       bits += mask_rowBytes;
+                                       cy += 1;
+                               }
+                       }
+               }
+       }
+       else
+       {
+               int                         width =     clip.width();
+               SkAutoSTMalloc<64, int16_t>     runStorage(width + 1);
+               int16_t*                    runs = runStorage.get();
+               const uint8_t*              aa = mask.getAddr(clip.fLeft, clip.fTop);
+
+               sk_memset16((U16*)runs, 1, width);
+               runs[width] = 0;
+
+               int height = clip.height();
+               int y = clip.fTop;
+               while (--height >= 0)
+               {
+                       this->blitAntiH(clip.fLeft, y, aa, runs);
+                       aa += mask.fRowBytes;
+                       y += 1;
+               }
+       }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+// this guy is not virtual, just a helper
+void SkBlitter::blitMaskRegion(const SkMask& mask, const SkRegion& clip)
+{
+    if (clip.quickReject(mask.fBounds))
+        return;
+
+    SkRegion::Cliperator clipper(clip, mask.fBounds);
+
+    if (!clipper.done())
+    {
+        const SkRect16&        cr = clipper.rect();
+        do {
+            this->blitMask(mask, cr);
+            clipper.next();
+        } while (!clipper.done());
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+static int compute_anti_width(const int16_t runs[])
+{
+       int     width = 0;
+
+       for (;;)
+       {
+               int count = runs[0];
+
+               SkASSERT(count >= 0);
+               if (count == 0)
+                       break;
+               width += count;
+               runs += count;
+
+               SkASSERT(width < 20000);
+       }
+       return width;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////
+
+void SkNullBlitter::blitH(int x, int y, int width)
+{
+}
+
+void SkNullBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[])
+{
+}
+
+void SkNullBlitter::blitV(int x, int y, int height, SkAlpha alpha)
+{
+}
+
+void SkNullBlitter::blitRect(int x, int y, int width, int height)
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////
+
+static inline bool y_in_rect(int y, const SkRect16& rect)
+{
+       return (unsigned)(y - rect.fTop) < (unsigned)rect.height();
+}
+
+static inline bool x_in_rect(int x, const SkRect16& rect)
+{
+       return (unsigned)(x - rect.fLeft) < (unsigned)rect.width();
+}
+
+void SkRectClipBlitter::blitH(int left, int y, int width)
+{
+       SkASSERT(width > 0);
+
+       if (!y_in_rect(y, fClipRect))
+               return;
+
+       int     right = left + width;
+
+       if (left < fClipRect.fLeft)
+               left = fClipRect.fLeft;
+       if (right > fClipRect.fRight)
+               right = fClipRect.fRight;
+
+       width = right - left;
+       if (width > 0)
+               fBlitter->blitH(left, y, width);
+}
+
+void SkRectClipBlitter::blitAntiH(int left, int y, const SkAlpha aa[], const int16_t runs[])
+{
+       if (!y_in_rect(y, fClipRect) || left >= fClipRect.fRight)
+               return;
+
+       int x0 = left;
+       int     x1 = left + compute_anti_width(runs);
+
+       if (x1 <= fClipRect.fLeft)
+               return;
+
+       SkASSERT(x0 < x1);
+       if (x0 < fClipRect.fLeft)
+       {
+               int dx = fClipRect.fLeft - x0;
+               SkAlphaRuns::BreakAt((int16_t*)runs, (U8*)aa, dx);
+               runs += dx;
+               aa += dx;
+               x0 = fClipRect.fLeft;
+       }
+
+       SkASSERT(x0 < x1 && runs[x1 - x0] == 0);
+       if (x1 > fClipRect.fRight)
+       {
+               x1 = fClipRect.fRight;
+               SkAlphaRuns::BreakAt((int16_t*)runs, (U8*)aa, x1 - x0);
+               ((int16_t*)runs)[x1 - x0] = 0;
+       }
+
+       SkASSERT(x0 < x1 && runs[x1 - x0] == 0);
+       SkASSERT(compute_anti_width(runs) == x1 - x0);
+
+       fBlitter->blitAntiH(x0, y, aa, runs);
+}
+
+void SkRectClipBlitter::blitV(int x, int y, int height, SkAlpha alpha)
+{
+       SkASSERT(height > 0);
+
+       if (!x_in_rect(x, fClipRect))
+               return;
+
+       int     y0 = y;
+       int y1 = y + height;
+
+       if (y0 < fClipRect.fTop)
+               y0 = fClipRect.fTop;
+       if (y1 > fClipRect.fBottom)
+               y1 = fClipRect.fBottom;
+
+       if (y0 < y1)
+               fBlitter->blitV(x, y0, y1 - y0, alpha);
+}
+
+void SkRectClipBlitter::blitRect(int left, int y, int width, int height)
+{
+       SkRect16        r;
+
+       r.set(left, y, left + width, y + height);
+       if (r.intersect(fClipRect))
+               fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////
+
+void SkRgnClipBlitter::blitH(int x, int y, int width)
+{
+       SkRegion::Spanerator span(*fRgn, y, x, x + width);
+       int     left, right;
+
+       while (span.next(&left, &right))
+       {
+               SkASSERT(left < right);
+               fBlitter->blitH(left, y, right - left);
+       }
+}
+
+void SkRgnClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[])
+{
+       int width = compute_anti_width(runs);
+       SkRegion::Spanerator span(*fRgn, y, x, x + width);
+       int     left, right;
+       bool firstTime = true;
+       SkDEBUGCODE(const SkRect16& bounds = fRgn->getBounds();)
+
+//SkDebugf("rgnClip: x=%d y=%d: ", x, y);
+
+       while (span.next(&left, &right))
+       {
+               SkASSERT(left < right);
+               SkASSERT(left >= bounds.fLeft && right <= bounds.fRight);
+               
+               if (firstTime && x < left)
+               {
+//SkDebugf("zap[%d %d] ", x, left);
+                       SkAlphaRuns::Break((int16_t*)runs, (U8*)aa, 0, left - x);
+                       ((U8*)aa)[0] = 0;       // skip runs before the first left
+                       ((int16_t*)runs)[0] = SkToS16(left - x);
+               }
+               firstTime = false;
+
+               SkAlphaRuns::Break((int16_t*)runs, (U8*)aa, left - x, right - left);
+               ((U8*)aa)[right - x] = 0;       // skip runs after right
+               ((int16_t*)runs)[right - x] = SkToS16(right - left);
+               
+//SkDebugf("[%d %d] ", left, right);
+       }
+       ((int16_t*)runs)[right - x] = 0;
+
+//dump_runs(runs, aa);
+
+       fBlitter->blitAntiH(x, y, aa, runs);
+}
+
+void SkRgnClipBlitter::blitV(int x, int y, int height, SkAlpha alpha)
+{
+       SkRect16        bounds;
+       bounds.set(x, y, x + 1, y + height);
+
+       SkRegion::Cliperator    iter(*fRgn, bounds);
+
+       while (!iter.done())
+       {
+               const SkRect16& r = iter.rect();
+               SkASSERT(bounds.contains(r));
+
+               fBlitter->blitV(x, r.fTop, r.height(), alpha);
+               iter.next();
+       }
+}
+
+void SkRgnClipBlitter::blitRect(int x, int y, int width, int height)
+{
+       SkRect16        bounds;
+       bounds.set(x, y, x + width, y + height);
+
+       SkRegion::Cliperator    iter(*fRgn, bounds);
+
+       while (!iter.done())
+       {
+               const SkRect16& r = iter.rect();
+               SkASSERT(bounds.contains(r));
+
+               fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
+               iter.next();
+       }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////
+
+SkBlitter* SkBlitterClipper::apply(SkBlitter* blitter, const SkRegion* clip, const SkRect16* ir)
+{
+       if (clip)
+       {
+               const SkRect16& clipR = clip->getBounds();
+
+               if (clip->isEmpty() || ir && !SkRect16::Intersects(clipR, *ir))
+                       blitter = &fNullBlitter;
+               else if (clip->isRect())
+               {
+                       if (ir == nil || !clipR.contains(*ir))
+                       {
+                               fRectBlitter.init(blitter, clipR);
+                               blitter = &fRectBlitter;
+                       }
+               }
+               else
+               {
+                       fRgnBlitter.init(blitter, clip);
+                       blitter = &fRgnBlitter;
+               }
+       }
+       return blitter;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkShader.h"
+#include "SkColorPriv.h"
+
+class SkColorShader : public SkShader {
+public:
+       virtual U32 getFlags()
+       {
+        // should I claim hasspan16 if my color isn't opaque?
+               return (SkGetPackedA32(fPMColor) == 255 ? kOpaqueAlpha_Flag : kConstAlpha_Flag) | kHasSpan16_Flag;
+       }
+       virtual bool setContext(const SkBitmap& device, const SkPaint& paint, const SkMatrix& matrix)
+       {
+               if (!this->INHERITED::setContext(device, paint, matrix))
+                       return false;
+
+               SkColor c = paint.getColor();
+               unsigned a = SkColorGetA(c);
+               unsigned r = SkColorGetR(c);
+               unsigned g = SkColorGetG(c);
+               unsigned b = SkColorGetB(c);
+
+               if (a != 255)
+               {
+                       a = SkAlpha255To256(a);
+                       r = SkAlphaMul(r, a);
+                       g = SkAlphaMul(g, a);
+                       b = SkAlphaMul(b, a);
+               }
+               fPMColor = SkPackARGB32(a, r, g, b);
+               fColor16 = SkPixel32ToPixel16_ToU16(fPMColor);  // only meaning full if a == 255
+               return true;
+       }
+       virtual void shadeSpan(int x, int y, SkPMColor span[], int count)
+       {
+               sk_memset32(span, fPMColor, count);
+       }
+       virtual void shadeSpanOpaque16(int x, int y, U16 span[], int count)
+       {
+               SkASSERT(SkGetPackedA32(fPMColor) == 255);
+               sk_memset16(span, fColor16, count);
+       }
+private:
+       SkPMColor       fPMColor;
+       U16                     fColor16;
+
+       typedef SkShader INHERITED;
+};
+
+class Sk3DShader : public SkShader {
+public:
+       Sk3DShader(SkShader* proxy) : fProxy(proxy)
+       {
+               proxy->safeRef();
+               fMask = nil;
+       }
+       virtual ~Sk3DShader()
+       {
+               fProxy->safeUnref();
+       }
+       void setMask(const SkMask* mask) { fMask = mask; }
+
+       virtual bool setContext(const SkBitmap& device, const SkPaint& paint, const SkMatrix& matrix)
+       {
+               if (fProxy)
+                       return fProxy->setContext(device, paint, matrix);
+               else
+               {
+                       fPMColor = SkPreMultiplyColor(paint.getColor());
+                       return this->INHERITED::setContext(device, paint, matrix);
+               }
+       }
+       virtual void shadeSpan(int x, int y, SkPMColor span[], int count)
+       {
+               if (fProxy)
+                       fProxy->shadeSpan(x, y, span, count);
+
+               if (fMask == nil)
+               {
+                       if (fProxy == nil)
+                               sk_memset32(span, fPMColor, count);
+                       return;
+               }
+
+               SkASSERT(fMask->fBounds.contains(x, y));
+               SkASSERT(fMask->fBounds.contains(x + count - 1, y));
+
+               size_t          size = fMask->computeImageSize();
+               const U8*       alpha = fMask->getAddr(x, y);
+               const U8*       mulp = alpha + size;
+               const U8*       addp = mulp + size;
+
+               if (fProxy)
+               {
+                       for (int i = 0; i < count; i++)
+                       {
+                               if (alpha[i])
+                               {
+                                       U32     c = span[i];
+                                       if (c)
+                                       {
+                                               unsigned a = SkGetPackedA32(c);
+                                               unsigned r = SkGetPackedR32(c);
+                                               unsigned g = SkGetPackedG32(c);
+                                               unsigned b = SkGetPackedB32(c);
+
+                                               unsigned mul = SkAlpha255To256(mulp[i]);
+                                               unsigned add = addp[i];
+
+                                               r = SkFastMin32(SkAlphaMul(r, mul) + add, a);
+                                               g = SkFastMin32(SkAlphaMul(g, mul) + add, a);
+                                               b = SkFastMin32(SkAlphaMul(b, mul) + add, a);
+
+                                               span[i] = SkPackARGB32(a, r, g, b);
+                                       }
+                               }
+                               else
+                                       span[i] = 0;
+                       }
+               }
+               else    // color
+               {
+                       unsigned a = SkGetPackedA32(fPMColor);
+                       unsigned r = SkGetPackedR32(fPMColor);
+                       unsigned g = SkGetPackedG32(fPMColor);
+                       unsigned b = SkGetPackedB32(fPMColor);
+                       for (int i = 0; i < count; i++)
+                       {
+                               if (alpha[i])
+                               {
+                                       unsigned mul = SkAlpha255To256(mulp[i]);
+                                       unsigned add = addp[i];
+
+                                       span[i] = SkPackARGB32( a,
+                                                                                       SkFastMin32(SkAlphaMul(r, mul) + add, a),
+                                                                                       SkFastMin32(SkAlphaMul(g, mul) + add, a),
+                                                                                       SkFastMin32(SkAlphaMul(b, mul) + add, a));
+                               }
+                               else
+                                       span[i] = 0;
+                       }
+               }
+       }
+private:
+       SkShader*               fProxy;
+       SkPMColor               fPMColor;
+       const SkMask*   fMask;
+
+       typedef SkShader INHERITED;
+};
+
+class Sk3DBlitter : public SkBlitter {
+public:
+       Sk3DBlitter(SkBlitter* proxy, Sk3DShader* shader, void (*killProc)(void*))
+               : fProxy(proxy), f3DShader(shader), fKillProc(killProc)
+       {
+               shader->ref();
+       }
+       virtual ~Sk3DBlitter()
+       {
+               f3DShader->unref();
+               fKillProc(fProxy);
+       }
+
+       virtual void blitH(int x, int y, int width)
+       {
+               fProxy->blitH(x, y, width);
+       }
+       virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[])
+       {
+               fProxy->blitAntiH(x, y, antialias, runs);
+       }
+       virtual void blitV(int x, int y, int height, SkAlpha alpha)
+       {
+               fProxy->blitV(x, y, height, alpha);
+       }
+       virtual void blitRect(int x, int y, int width, int height)
+       {
+               fProxy->blitRect(x, y, width, height);
+       }
+       virtual void blitMask(const SkMask& mask, const SkRect16& clip)
+       {
+               if (mask.fFormat == SkMask::k3D_Format)
+               {
+                       f3DShader->setMask(&mask);
+
+                       ((SkMask*)&mask)->fFormat = SkMask::kA8_Format;
+                       fProxy->blitMask(mask, clip);
+                       ((SkMask*)&mask)->fFormat = SkMask::k3D_Format;
+
+                       f3DShader->setMask(nil);
+               }
+               else
+                       fProxy->blitMask(mask, clip);
+       }
+private:
+       SkBlitter*      fProxy;
+       Sk3DShader* f3DShader;
+       void            (*fKillProc)(void*);
+};
+
+///////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkCoreBlitters.h"
+
+class SkAutoRestoreShader {
+public:
+       SkAutoRestoreShader(const SkPaint& p) : fPaint((SkPaint*)&p)
+       {
+               fShader = fPaint->getShader();
+               fShader->safeRef();
+       }
+       ~SkAutoRestoreShader()
+       {
+               fPaint->setShader(fShader);
+               fShader->safeUnref();
+       }
+private:
+       SkPaint*        fPaint;
+       SkShader*       fShader;
+};
+
+class SkAutoCallProc {
+public:
+       typedef void (*Proc)(void*);
+       SkAutoCallProc(void* obj, Proc proc)
+               : fObj(obj), fProc(proc)
+       {
+       }
+       ~SkAutoCallProc()
+       {
+               if (fObj && fProc)
+                       fProc(fObj);
+       }
+       void* get() const { return fObj; }
+       void* detach()
+       {
+               void* obj = fObj;
+               fObj = nil;
+               return obj;
+       }
+private:
+       void*   fObj;
+       Proc    fProc;
+};
+
+static void destroy_blitter(void* blitter)
+{
+       ((SkBlitter*)blitter)->~SkBlitter();
+}
+
+static void delete_blitter(void* blitter)
+{
+       SkDELETE((SkBlitter*)blitter);
+}
+
+SkBlitter* SkBlitter::Choose(const SkBitmap& device,
+                                                        const SkMatrix& matrix,
+                                                        const SkPaint& paint,
+                                                        void* storage, size_t storageSize)
+{
+       SkASSERT(storageSize == 0 || storage != nil);
+
+       SkBlitter*      blitter = nil;
+       SkAutoRestoreShader     restore(paint);
+       SkShader* shader = paint.getShader();
+
+       Sk3DShader* shader3D = nil;
+       if (paint.getMaskFilter() != nil && paint.getMaskFilter()->getFormat() == SkMask::k3D_Format)
+       {
+               shader3D = SkNEW_ARGS(Sk3DShader, (shader));
+               ((SkPaint*)&paint)->setShader(shader3D)->unref();
+               shader = shader3D;
+       }
+
+       SkXfermode* mode = paint.getXfermode();
+       if (NULL == shader && (NULL != mode || paint.getColorFilter() != NULL))
+       {
+               // xfermodes require shaders for our current set of blitters
+               shader = SkNEW(SkColorShader);
+               ((SkPaint*)&paint)->setShader(shader)->unref();
+       }
+    
+    if (paint.getColorFilter() != NULL)
+    {
+        SkASSERT(shader);
+        shader = SkNEW_ARGS(SkFilterShader, (shader, paint.getColorFilter()));
+        ((SkPaint*)&paint)->setShader(shader)->unref();
+    }
+
+       if (shader)
+       {
+               if (!shader->setContext(device, paint, matrix))
+                       return SkNEW(SkNullBlitter);
+       }
+
+       switch (device.getConfig()) {
+       case SkBitmap::kA1_Config:
+               SK_PLACEMENT_NEW_ARGS(blitter, SkA1_Blitter, storage, storageSize, (device, paint));
+               break;
+
+       case SkBitmap::kA8_Config:
+               if (shader)
+                       SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Shader_Blitter, storage, storageSize, (device, paint));
+               else
+                       SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Blitter, storage, storageSize, (device, paint));
+               break;
+
+       case SkBitmap::kRGB_565_Config:
+               if (shader)
+               {
+                       if (mode)
+                               SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Shader_Xfermode_Blitter, storage, storageSize, (device, paint));
+                       else
+                               SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Shader_Blitter, storage, storageSize, (device, paint));
+               }
+               else if (paint.getColor() == SK_ColorBLACK)
+                       SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Black_Blitter, storage, storageSize, (device, paint));
+               else
+                       SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Blitter, storage, storageSize, (device, paint));
+               break;
+
+       case SkBitmap::kARGB_8888_Config:
+               if (shader)
+                       SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Shader_Blitter, storage, storageSize, (device, paint));
+               else if (paint.getColor() == SK_ColorBLACK)
+                       SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Black_Blitter, storage, storageSize, (device, paint));
+        else
+                       SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Blitter, storage, storageSize, (device, paint));
+               break;
+
+       default:
+               SkASSERT(!"unsupported device config");
+               SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
+       }
+
+       if (shader3D)
+       {
+               void (*proc)(void*) = ((void*)storage == (void*)blitter) ? destroy_blitter : delete_blitter;
+               SkAutoCallProc  tmp(blitter, proc);
+
+               blitter = SkNEW_ARGS(Sk3DBlitter, (blitter, shader3D, proc));
+               (void)tmp.detach();
+       }
+       return blitter;
+}
+
diff --git a/libs/graphics/sgl/SkBlitter.h b/libs/graphics/sgl/SkBlitter.h
new file mode 100644 (file)
index 0000000..2031efa
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef SkBlitter_DEFINED
+#define SkBlitter_DEFINED
+
+#include "SkBitmap.h"
+#include "SkMatrix.h"
+#include "SkPaint.h"
+#include "SkRefCnt.h"
+#include "SkRegion.h"
+#include "SkMask.h"
+
+class SkBlitter {
+public:
+       virtual ~SkBlitter();
+       virtual void    blitH(int x, int y, int width);
+       virtual void    blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[]);
+       virtual void    blitV(int x, int y, int height, SkAlpha alpha);
+       virtual void    blitRect(int x, int y, int width, int height);
+       virtual void    blitMask(const SkMask&, const SkRect16& clip);
+
+    // not virtual, just a helper
+    void blitMaskRegion(const SkMask& mask, const SkRegion& clip);
+
+       static SkBlitter* Choose(const SkBitmap& device,
+                                                        const SkMatrix& matrix,
+                                                        const SkPaint& paint)
+       {
+               return Choose(device, matrix, paint, nil, 0);
+       }
+
+       static SkBlitter* Choose(const SkBitmap& device,
+                                                        const SkMatrix& matrix,
+                                                        const SkPaint& paint,
+                                                        void* storage, size_t storageSize);
+
+       static SkBlitter* ChooseSprite(const SkBitmap& device,
+                                                        const SkPaint&,
+                                                        const SkBitmap& src,
+                                                        int left, int top,
+                                                        void* storage, size_t storageSize);
+
+private:
+};
+
+class SkNullBlitter : public SkBlitter {
+public:
+       virtual void    blitH(int x, int y, int width);
+       virtual void    blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[]);
+       virtual void    blitV(int x, int y, int height, SkAlpha alpha);
+       virtual void    blitRect(int x, int y, int width, int height);
+};
+
+class SkRectClipBlitter : public SkBlitter {
+public:
+       void init(SkBlitter* blitter, const SkRect16& clipRect)
+       {
+               SkASSERT(!clipRect.isEmpty());
+               fBlitter = blitter;
+               fClipRect = clipRect;
+       }
+
+       // overrides
+       virtual void    blitH(int x, int y, int width);
+       virtual void    blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[]);
+       virtual void    blitV(int x, int y, int height, SkAlpha alpha);
+       virtual void    blitRect(int x, int y, int width, int height);
+
+private:
+       SkBlitter*      fBlitter;
+       SkRect16        fClipRect;
+};
+
+class SkRgnClipBlitter : public SkBlitter {
+public:
+       void init(SkBlitter* blitter, const SkRegion* rgn)
+       {
+               SkASSERT(rgn && !rgn->isEmpty());
+               fBlitter = blitter;
+               fRgn = rgn;
+       }
+
+       // overrides
+       virtual void    blitH(int x, int y, int width);
+       virtual void    blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[]);
+       virtual void    blitV(int x, int y, int height, SkAlpha alpha);
+       virtual void    blitRect(int x, int y, int width, int height);
+
+private:
+       SkBlitter*              fBlitter;
+       const SkRegion* fRgn;
+};
+
+class SkBlitterClipper {
+public:
+       SkBlitter*      apply(SkBlitter* blitter, const SkRegion* clip, const SkRect16* bounds = nil);
+
+private:
+       SkNullBlitter           fNullBlitter;
+       SkRectClipBlitter       fRectBlitter;
+       SkRgnClipBlitter        fRgnBlitter;
+};
+
+#endif
diff --git a/libs/graphics/sgl/SkBlitter_A1.cpp b/libs/graphics/sgl/SkBlitter_A1.cpp
new file mode 100644 (file)
index 0000000..38e0e4f
--- /dev/null
@@ -0,0 +1,46 @@
+#include "SkCoreBlitters.h"
+
+SkA1_Blitter::SkA1_Blitter(const SkBitmap& device, const SkPaint& paint)
+       : fDevice(device)
+{
+       fSrcA = SkToU8(SkColorGetA(paint.getColor()));
+}
+
+void SkA1_Blitter::blitH(int x, int y, int width)
+{
+       SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= fDevice.width());
+
+       if (fSrcA <= 0x7F)
+               return;
+
+       U8* dst = fDevice.getAddr1(x, y);
+       int     right = x + width;
+
+       int left_mask = 0xFF >> (x & 7);
+       int rite_mask = 0xFF << (8 - (right & 7));
+       int full_runs = (right >> 3) - ((x + 7) >> 3);
+
+       // check for empty right mask, so we don't read off the end (or go slower than we need to)
+       if (rite_mask == 0)
+       {
+               SkASSERT(full_runs >= 0);
+               full_runs -= 1;
+               rite_mask = 0xFF;
+       }
+       if (left_mask == 0xFF)
+               full_runs -= 1;
+
+       if (full_runs < 0)
+       {
+               SkASSERT((left_mask & rite_mask) != 0);
+               *dst |= (left_mask & rite_mask);
+       }
+       else
+       {
+               *dst++ |= left_mask;
+               memset(dst, 0xFF, full_runs);
+               dst += full_runs;
+               *dst |= rite_mask;
+       }
+}
+
diff --git a/libs/graphics/sgl/SkBlitter_A8.cpp b/libs/graphics/sgl/SkBlitter_A8.cpp
new file mode 100644 (file)
index 0000000..bb94050
--- /dev/null
@@ -0,0 +1,365 @@
+#include "SkCoreBlitters.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+#include "SkXfermode.h"
+
+SkA8_Blitter::SkA8_Blitter(const SkBitmap& device, const SkPaint& paint) : fDevice(device)
+{
+       fSrcA = SkColorGetA(paint.getColor());
+}
+
+void SkA8_Blitter::blitH(int x, int y, int width)
+{
+       SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= fDevice.width());
+
+       if (fSrcA == 0)
+               return;
+
+       uint8_t* device = fDevice.getAddr8(x, y);
+
+       if (fSrcA == 255)
+       {
+               memset(device, 0xFF, width);
+       }
+       else
+       {
+               unsigned scale = 256 - SkAlpha255To256(fSrcA);
+               unsigned srcA = fSrcA;
+
+               for (int i = 0; i < width; i++)
+               {
+                       device[i] = SkToU8(srcA + SkAlphaMul(device[i], scale));
+               }
+       }
+}
+
+void SkA8_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[])
+{
+       if (fSrcA == 0)
+               return;
+
+       uint8_t*        device = fDevice.getAddr8(x, y);
+       unsigned        srcA = fSrcA;
+
+       for (;;)
+       {
+               int count = runs[0];
+               SkASSERT(count >= 0);
+               if (count == 0)
+                       return;
+               unsigned aa = antialias[0];
+
+               if (aa == 255 && srcA == 255)
+                       memset(device, 0xFF, count);
+               else
+               {
+                       unsigned sa = SkAlphaMul(srcA, SkAlpha255To256(aa));
+                       unsigned scale = 256 - sa;
+
+                       for (int i = 0; i < count; i++)
+                       {
+                               device[i] = SkToU8(sa + SkAlphaMul(device[i], scale));
+                       }
+               }
+               runs += count;
+               antialias += count;
+               device += count;
+       }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+#define solid_8_pixels(mask, dst)                      \
+       do {                                                                    \
+               if (mask & 0x80) dst[0] = 0xFF;         \
+               if (mask & 0x40) dst[1] = 0xFF;         \
+               if (mask & 0x20) dst[2] = 0xFF;         \
+               if (mask & 0x10) dst[3] = 0xFF;         \
+               if (mask & 0x08) dst[4] = 0xFF;         \
+               if (mask & 0x04) dst[5] = 0xFF;         \
+               if (mask & 0x02) dst[6] = 0xFF;         \
+               if (mask & 0x01) dst[7] = 0xFF;         \
+       } while (0)
+
+#define        SK_BLITBWMASK_NAME                                      SkA8_BlitBW
+#define SK_BLITBWMASK_ARGS                                     
+#define SK_BLITBWMASK_BLIT8(mask, dst)         solid_8_pixels(mask, dst)
+#define SK_BLITBWMASK_GETADDR                          getAddr8
+#define SK_BLITBWMASK_DEVTYPE                          uint8_t
+#include "SkBlitBWMaskTemplate.h"
+
+static inline void blend_8_pixels(U8CPU bw, uint8_t dst[], U8CPU sa, unsigned dst_scale)
+{
+       if (bw & 0x80) dst[0] = SkToU8(sa + SkAlphaMul(dst[0], dst_scale));
+       if (bw & 0x40) dst[1] = SkToU8(sa + SkAlphaMul(dst[1], dst_scale));
+       if (bw & 0x20) dst[2] = SkToU8(sa + SkAlphaMul(dst[2], dst_scale));
+       if (bw & 0x10) dst[3] = SkToU8(sa + SkAlphaMul(dst[3], dst_scale));
+       if (bw & 0x08) dst[4] = SkToU8(sa + SkAlphaMul(dst[4], dst_scale));
+       if (bw & 0x04) dst[5] = SkToU8(sa + SkAlphaMul(dst[5], dst_scale));
+       if (bw & 0x02) dst[6] = SkToU8(sa + SkAlphaMul(dst[6], dst_scale));
+       if (bw & 0x01) dst[7] = SkToU8(sa + SkAlphaMul(dst[7], dst_scale));
+}
+
+#define        SK_BLITBWMASK_NAME                                      SkA8_BlendBW
+#define SK_BLITBWMASK_ARGS                                     , U8CPU sa, unsigned dst_scale
+#define SK_BLITBWMASK_BLIT8(mask, dst)         blend_8_pixels(mask, dst, sa, dst_scale)
+#define SK_BLITBWMASK_GETADDR                          getAddr8
+#define SK_BLITBWMASK_DEVTYPE                          uint8_t
+#include "SkBlitBWMaskTemplate.h"
+
+void SkA8_Blitter::blitMask(const SkMask& mask, const SkRect16& clip)
+{
+       if (fSrcA == 0)
+               return;
+
+       if (mask.fFormat == SkMask::kBW_Format)
+       {
+               if (fSrcA == 0xFF)
+                       SkA8_BlitBW(fDevice, mask, clip);
+               else
+                       SkA8_BlendBW(fDevice, mask, clip, fSrcA, SkAlpha255To256(255 - fSrcA));
+               return;
+       }
+
+       int     x = clip.fLeft;
+       int y = clip.fTop;
+       int width = clip.width();
+       int height = clip.height();
+       uint8_t* device = fDevice.getAddr8(x, y);
+       const uint8_t* alpha = mask.getAddr(x, y);
+       unsigned        srcA = fSrcA;
+
+       while (--height >= 0)
+       {
+               for (int i = width - 1; i >= 0; --i)
+               {
+                       unsigned sa;
+                       // scale our src by the alpha value
+                       {
+                               int aa = alpha[i];
+                               if (aa == 0)
+                                       continue;
+
+                               if (aa == 255)
+                               {
+                                       if (srcA == 255)
+                                       {
+                                               device[i] = 0xFF;
+                                               continue;
+                                       }
+                                       sa = srcA;
+                               }
+                               else
+                                       sa = SkAlphaMul(srcA, SkAlpha255To256(aa));
+                       }
+
+                       int scale = 256 - SkAlpha255To256(sa);
+                       device[i] = SkToU8(sa + SkAlphaMul(device[i], scale));
+               }
+               device += fDevice.rowBytes();
+               alpha += mask.fRowBytes;
+       }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+void SkA8_Blitter::blitV(int x, int y, int height, SkAlpha alpha)
+{
+       if (fSrcA == 0)
+               return;
+
+       unsigned sa = SkAlphaMul(fSrcA, SkAlpha255To256(alpha));
+       uint8_t* device = fDevice.getAddr8(x, y);
+       int              rowBytes = fDevice.rowBytes();
+
+       if (sa == 0xFF)
+       {
+               for (int i = 0; i < height; i++)
+               {
+                       *device = SkToU8(sa);
+                       device += rowBytes;
+               }
+       }
+       else
+       {
+               unsigned scale = 256 - SkAlpha255To256(sa);
+
+               for (int i = 0; i < height; i++)
+               {
+                       *device = SkToU8(sa + SkAlphaMul(*device, scale));
+                       device += rowBytes;
+               }
+       }
+}
+
+void SkA8_Blitter::blitRect(int x, int y, int width, int height)
+{
+       SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= fDevice.width() && (unsigned)(y + height) <= fDevice.height());
+
+       if (fSrcA == 0)
+               return;
+
+       uint8_t*        device = fDevice.getAddr8(x, y);
+       unsigned        srcA = fSrcA;
+
+       if (srcA == 255)
+       {
+               while (--height >= 0)
+               {
+                       memset(device, 0xFF, width);
+                       device += fDevice.rowBytes();
+               }
+       }
+       else
+       {
+               unsigned scale = 256 - SkAlpha255To256(srcA);
+
+               while (--height >= 0)
+               {
+                       for (int i = 0; i < width; i++)
+                       {
+                               device[i] = SkToU8(srcA + SkAlphaMul(device[i], scale));
+                       }
+                       device += fDevice.rowBytes();
+               }
+       }
+}
+
+///////////////////////////////////////////////////////////////////////
+
+SkA8_Shader_Blitter::SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint& paint) : fDevice(device)
+{
+       fShader = paint.getShader();
+       SkASSERT(fShader);
+       fShader->ref();
+
+       if ((fXfermode = paint.getXfermode()) != NULL)
+       {
+               fXfermode->ref();
+               SkASSERT(fShader);
+       }
+
+       int width = device.width();
+       fBuffer = (SkPMColor*)sk_malloc_throw(sizeof(SkPMColor) * (width + (SkAlign4(width) >> 2)));
+       fAAExpand = (uint8_t*)(fBuffer + width);
+}
+
+SkA8_Shader_Blitter::~SkA8_Shader_Blitter()
+{
+       fXfermode->safeUnref();
+       fShader->unref();
+       sk_free(fBuffer);
+}
+
+void SkA8_Shader_Blitter::blitH(int x, int y, int width)
+{
+       SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= fDevice.width());
+
+       uint8_t* device = fDevice.getAddr8(x, y);
+
+       if ((fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) && fXfermode == NULL)
+       {
+               memset(device, 0xFF, width);
+       }
+       else
+       {
+               SkPMColor*      span = fBuffer;
+
+               fShader->shadeSpan(x, y, span, width);
+               if (fXfermode)
+                       fXfermode->xferA8(device, span, width, NULL);
+               else
+               {
+                       for (int i = width - 1; i >= 0; --i)
+                       {
+                               unsigned        srcA = SkGetPackedA32(span[i]);
+                               unsigned        scale = 256 - SkAlpha255To256(srcA);
+
+                               device[i] = SkToU8(srcA + SkAlphaMul(device[i], scale));
+                       }
+               }
+       }
+}
+
+static inline uint8_t aa_blend8(U32 src, U8CPU da, int aa)
+{
+       SkASSERT((unsigned)aa <= 255);
+
+       int src_scale = SkAlpha255To256(aa);
+       int     sa = SkGetPackedA32(src);
+       int dst_scale = 256 - SkAlphaMul(sa, src_scale);
+
+       return SkToU8((sa * src_scale + da * dst_scale) >> 8);
+}
+
+void SkA8_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[])
+{
+       SkASSERT(x >= 0 && y >= 0 && x < (int)fDevice.width() && y < (int)fDevice.height());
+
+       SkShader*       shader = fShader;
+       SkXfermode*     mode = fXfermode;
+       uint8_t*        aaExpand = fAAExpand;
+       SkPMColor*      span = fBuffer;
+       uint8_t*        device = fDevice.getAddr8(x, y);
+       int                     opaque = fShader->getFlags() & SkShader::kOpaqueAlpha_Flag;
+
+       for (;;)
+       {
+               int     count = *runs;
+               if (count == 0)
+                       break;
+               int     aa = *antialias;
+               if (aa)
+               {
+                       if (opaque && aa == 255 && mode == NULL)
+                               memset(device, 0xFF, count);
+                       else
+                       {
+                               shader->shadeSpan(x, y, span, count);
+                               if (mode)
+                               {
+                                       memset(aaExpand, aa, count);
+                                       mode->xferA8(device, span, count, aaExpand);
+                               }
+                               else
+                               {
+                                       for (int i = count - 1; i >= 0; --i)
+                                               device[i] = aa_blend8(span[i], device[i], aa);
+                               }
+                       }
+               }
+               device += count;
+               runs += count;
+               antialias += count;
+               x += count;
+       } 
+}
+
+void SkA8_Shader_Blitter::blitMask(const SkMask& mask, const SkRect16& clip)
+{
+    if (mask.fFormat == SkMask::kBW_Format)
+    {
+        this->INHERITED::blitMask(mask, clip);
+        return;
+    }
+    
+       int     x = clip.fLeft;
+       int y = clip.fTop;
+       int width = clip.width();
+       int height = clip.height();
+       uint8_t* device = fDevice.getAddr8(x, y);
+       const uint8_t* alpha = mask.getAddr(x, y);
+
+       SkPMColor*      span = fBuffer;
+
+       while (--height >= 0)
+       {
+        fShader->shadeSpan(x, y, span, width);
+        fXfermode->xferA8(device, span, width, alpha);
+        
+        y += 1;
+               device += fDevice.rowBytes();
+               alpha += mask.fRowBytes;
+       }
+}
+
diff --git a/libs/graphics/sgl/SkBlitter_ARGB32.cpp b/libs/graphics/sgl/SkBlitter_ARGB32.cpp
new file mode 100644 (file)
index 0000000..66ff505
--- /dev/null
@@ -0,0 +1,465 @@
+#include "SkCoreBlitters.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+
+SkARGB32_Blitter::SkARGB32_Blitter(const SkBitmap& device, const SkPaint& paint) : fDevice(device)
+{
+       uint32_t color = paint.getColor();
+
+       fSrcA = SkColorGetA(color);
+       unsigned scale = SkAlpha255To256(fSrcA);
+       fSrcR = SkAlphaMul(SkColorGetR(color), scale);
+       fSrcG = SkAlphaMul(SkColorGetG(color), scale);
+       fSrcB = SkAlphaMul(SkColorGetB(color), scale);
+
+       fPMColor = SkPackARGB32(fSrcA, fSrcR, fSrcG, fSrcB);
+}
+
+#if defined _WIN32 && _MSC_VER >= 1300 // disable warning : local variable used without having been initialized
+#pragma warning ( push )
+#pragma warning ( disable : 4701 )
+#endif
+
+void SkARGB32_Blitter::blitH(int x, int y, int width)
+{
+       SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= fDevice.width());
+
+       if (fSrcA == 0)
+               return;
+
+       uint32_t* device = fDevice.getAddr32(x, y);
+
+       if (fSrcA == 255)
+       {
+               sk_memset32(device, fPMColor, width);
+       }
+       else
+       {
+               uint32_t color = fPMColor;
+               unsigned dst_scale = SkAlpha255To256(255 - fSrcA);
+               uint32_t prevDst = ~device[0];  // so we always fail the test the first time
+               uint32_t result SK_INIT_TO_AVOID_WARNING;
+
+               for (int i = 0; i < width; i++)
+               {
+                       uint32_t currDst = device[i];
+                       if (currDst != prevDst)
+                       {
+                               result = color + SkAlphaMulQ(currDst, dst_scale);
+                               prevDst = currDst;
+                       }
+                       device[i] = result;
+               }
+       }
+}
+
+void SkARGB32_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[])
+{
+       if (fSrcA == 0)
+               return;
+
+       uint32_t        color = fPMColor;
+       uint32_t*       device = fDevice.getAddr32(x, y);
+    unsigned    opaqueMask = fSrcA; // if fSrcA is 0xFF, then we will catch the fast opaque case
+
+    for (;;)
+    {
+        int count = runs[0];
+        SkASSERT(count >= 0);
+        if (count == 0)
+            return;
+
+        unsigned aa = antialias[0];
+        if (aa)
+        {
+            if ((opaqueMask & aa) == 255)
+                sk_memset32(device, color, count);
+            else
+            {
+                uint32_t sc = SkAlphaMulQ(color, aa);
+                unsigned dst_scale = 255 - SkGetPackedA32(sc);
+
+                for (int i = 0; i < count; i++)
+                    device[i] = sc + SkAlphaMulQ(device[i], dst_scale);
+            }
+        }
+        runs += count;
+        antialias += count;
+        device += count;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+#define solid_8_pixels(mask, dst, color)       \
+       do {                                                                    \
+               if (mask & 0x80) dst[0] = color;        \
+               if (mask & 0x40) dst[1] = color;        \
+               if (mask & 0x20) dst[2] = color;        \
+               if (mask & 0x10) dst[3] = color;        \
+               if (mask & 0x08) dst[4] = color;        \
+               if (mask & 0x04) dst[5] = color;        \
+               if (mask & 0x02) dst[6] = color;        \
+               if (mask & 0x01) dst[7] = color;        \
+       } while (0)
+
+#define        SK_BLITBWMASK_NAME                                      SkARGB32_BlitBW
+#define SK_BLITBWMASK_ARGS                                     , SkPMColor color
+#define SK_BLITBWMASK_BLIT8(mask, dst)         solid_8_pixels(mask, dst, color)
+#define SK_BLITBWMASK_GETADDR                          getAddr32
+#define SK_BLITBWMASK_DEVTYPE                          uint32_t
+#include "SkBlitBWMaskTemplate.h"
+
+#define blend_8_pixels(mask, dst, sc, dst_scale)                                                       \
+       do {                                                                                                                                    \
+               if (mask & 0x80) { dst[0] = sc + SkAlphaMulQ(dst[0], dst_scale); }      \
+               if (mask & 0x40) { dst[1] = sc + SkAlphaMulQ(dst[1], dst_scale); }      \
+               if (mask & 0x20) { dst[2] = sc + SkAlphaMulQ(dst[2], dst_scale); }      \
+               if (mask & 0x10) { dst[3] = sc + SkAlphaMulQ(dst[3], dst_scale); }      \
+               if (mask & 0x08) { dst[4] = sc + SkAlphaMulQ(dst[4], dst_scale); }      \
+               if (mask & 0x04) { dst[5] = sc + SkAlphaMulQ(dst[5], dst_scale); }      \
+               if (mask & 0x02) { dst[6] = sc + SkAlphaMulQ(dst[6], dst_scale); }      \
+               if (mask & 0x01) { dst[7] = sc + SkAlphaMulQ(dst[7], dst_scale); }      \
+       } while (0)
+
+#define        SK_BLITBWMASK_NAME                                      SkARGB32_BlendBW
+#define SK_BLITBWMASK_ARGS                                     , uint32_t sc, unsigned dst_scale
+#define SK_BLITBWMASK_BLIT8(mask, dst)         blend_8_pixels(mask, dst, sc, dst_scale)
+#define SK_BLITBWMASK_GETADDR                          getAddr32
+#define SK_BLITBWMASK_DEVTYPE                          uint32_t
+#include "SkBlitBWMaskTemplate.h"
+
+void SkARGB32_Blitter::blitMask(const SkMask& mask, const SkRect16& clip)
+{
+       SkASSERT(mask.fBounds.contains(clip));
+
+       if (fSrcA == 0)
+               return;
+
+       if (mask.fFormat == SkMask::kBW_Format)
+       {
+               if (fSrcA == 0xFF)
+                       SkARGB32_BlitBW(fDevice, mask, clip, fPMColor);
+               else
+                       SkARGB32_BlendBW(fDevice, mask, clip, fPMColor, SkAlpha255To256(255 - fSrcA));
+               return;
+       }
+
+       int     x = clip.fLeft;
+       int y = clip.fTop;
+       int width = clip.width();
+       int height = clip.height();
+
+       uint32_t*       device = fDevice.getAddr32(x, y);
+       const uint8_t*  alpha = mask.getAddr(x, y);
+       uint32_t        srcColor = fPMColor;
+
+       while (--height >= 0)
+       {
+               for (int i = width - 1; i >= 0; --i)
+               {
+                       uint32_t color = srcColor;
+
+                       // scale our src by the alpha value
+                       {
+                               int aa = alpha[i];
+                               if (aa == 0)
+                                       continue;
+
+                               if (aa == 255)
+                               {
+                                       if (fSrcA == 255)
+                                       {
+                                               device[i] = color;
+                                               continue;
+                                       }
+                               }
+                               else
+                                       color = SkAlphaMulQ(color, SkAlpha255To256(aa));
+                       }
+                       device[i] = SkPMSrcOver(color, device[i]);
+               }
+               device = (uint32_t*)((char*)device + fDevice.rowBytes());
+               alpha += mask.fRowBytes;
+       }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+void SkARGB32_Blitter::blitV(int x, int y, int height, SkAlpha alpha)
+{
+       if (alpha == 0 || fSrcA == 0)
+               return;
+
+       uint32_t* device = fDevice.getAddr32(x, y);
+       uint32_t  color = fPMColor;
+
+       if (alpha != 255)
+               color = SkAlphaMulQ(color, SkAlpha255To256(alpha));
+
+       unsigned dst_scale = 255 - SkGetPackedA32(color);
+       uint32_t prevDst = ~device[0];
+       uint32_t result  SK_INIT_TO_AVOID_WARNING;
+       uint32_t rowBytes = fDevice.rowBytes();
+
+       while (--height >= 0)
+       {
+               uint32_t dst = device[0];
+               if (dst != prevDst)
+               {
+                       result = color + SkAlphaMulQ(dst, dst_scale);
+                       prevDst = dst;
+               }
+               device[0] = result;
+               device = (uint32_t*)((char*)device + rowBytes);
+       }
+}
+
+void SkARGB32_Blitter::blitRect(int x, int y, int width, int height)
+{
+       SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= fDevice.width() && (unsigned)(y + height) <= fDevice.height());
+
+       if (fSrcA == 0)
+               return;
+
+       uint32_t*       device = fDevice.getAddr32(x, y);
+       uint32_t        color = fPMColor;
+
+       if (fSrcA == 255)
+       {
+               while (--height >= 0)
+               {
+                       sk_memset32(device, color, width);
+                       device = (uint32_t*)((char*)device + fDevice.rowBytes());
+               }
+       }
+       else
+       {
+               unsigned dst_scale = SkAlpha255To256(255 - fSrcA);
+
+               while (--height >= 0)
+               {
+                       uint32_t prevDst = ~device[0];
+                       uint32_t result SK_INIT_TO_AVOID_WARNING;
+
+                       for (int i = 0; i < width; i++)
+                       {
+                               uint32_t dst = device[i];
+                               if (dst != prevDst)
+                               {
+                                       result = color + SkAlphaMulQ(dst, dst_scale);
+                                       prevDst = dst;
+                               }
+                               device[i] = result;
+                       }
+                       device = (uint32_t*)((char*)device + fDevice.rowBytes());
+               }
+       }
+}
+
+#if defined _WIN32 && _MSC_VER >= 1300
+#pragma warning ( pop )
+#endif
+
+///////////////////////////////////////////////////////////////////////
+
+void SkARGB32_Black_Blitter::blitMask(const SkMask& mask, const SkRect16& clip)
+{
+       SkASSERT(mask.fBounds.contains(clip));
+
+    SkPMColor   black = (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT);
+
+       if (mask.fFormat == SkMask::kBW_Format)
+       {
+               SkARGB32_BlitBW(fDevice, mask, clip, black);
+       }
+       else
+       {
+               uint32_t*   device = fDevice.getAddr32(clip.fLeft, clip.fTop);
+               const U8*   alpha = mask.getAddr(clip.fLeft, clip.fTop);
+               unsigned    width = clip.width();
+               unsigned    height = clip.height();
+               unsigned    deviceRB = fDevice.rowBytes() - (width << 2);
+               unsigned    maskRB = mask.fRowBytes - width;
+
+               SkASSERT((int)height > 0);
+               SkASSERT((int)width > 0);
+               SkASSERT((int)deviceRB >= 0);
+               SkASSERT((int)maskRB >= 0);
+
+               do {
+                       unsigned w = width;
+                       do {
+                               unsigned aa = *alpha++;
+                               if (aa)
+                               {
+                                       if (aa == 255)
+                                               *device = black;
+                                       else
+                                               *device = (aa << SK_A32_SHIFT) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
+                               }
+                               device += 1;
+                       } while (--w != 0);
+                       device = (uint32_t*)((char*)device + deviceRB);
+                       alpha += maskRB;
+               } while (--height != 0);
+       }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device, const SkPaint& paint) : fDevice(device)
+{
+       fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor)));
+
+       fShader = paint.getShader();
+       SkASSERT(fShader);
+       fShader->ref();
+
+       (fXfermode = paint.getXfermode())->safeRef();
+}
+
+SkARGB32_Shader_Blitter::~SkARGB32_Shader_Blitter()
+{
+       fXfermode->safeUnref();
+       fShader->unref();
+       sk_free(fBuffer);
+}
+
+void SkARGB32_Shader_Blitter::blitH(int x, int y, int width)
+{
+       SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= fDevice.width());
+
+       uint32_t*       device = fDevice.getAddr32(x, y);
+
+       if (fXfermode == NULL && (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag))
+       {
+               fShader->shadeSpan(x, y, device, width);
+       }
+       else
+       {
+        SkPMColor*     span = fBuffer;
+               fShader->shadeSpan(x, y, span, width);
+               if (fXfermode)
+                       fXfermode->xfer32(device, span, width, NULL);
+               else
+               {
+                       for (int i = 0; i < width; i++)
+                       {
+                               uint32_t src = span[i];
+                               if (src)
+                               {
+                                       unsigned srcA = SkGetPackedA32(src);
+                                       if (srcA != 0xFF)
+                                               src += SkAlphaMulQ(device[i], SkAlpha255To256(255 - srcA));
+                                       device[i] = src;
+                               }
+                       }
+               }
+       }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[])
+{
+       SkASSERT(x >= 0 && y >= 0 && x < (int)fDevice.width() && y < (int)fDevice.height());
+
+       SkPMColor*      span = fBuffer;
+       uint32_t*       device = fDevice.getAddr32(x, y);
+    SkShader*   shader = fShader;
+
+    if (fXfermode)
+    {
+        for (;;)
+        {
+            SkXfermode* xfer = fXfermode;
+
+            int        count = *runs;
+            if (count == 0)
+                break;
+            int        aa = *antialias;
+            if (aa)
+            {
+                shader->shadeSpan(x, y, span, count);
+                if (aa == 255)
+                    xfer->xfer32(device, span, count, NULL);
+                else
+                {
+                    // count is almost always 1
+                    for (int i = count - 1; i >= 0; --i)
+                        xfer->xfer32(&device[i], &span[i], count, antialias);
+                }
+            }
+            device += count;
+            runs += count;
+            antialias += count;
+            x += count;
+        } 
+    }
+    else if (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)
+    {
+        for (;;)
+        {
+            int        count = *runs;
+            if (count == 0)
+                break;
+            int        aa = *antialias;
+            if (aa)
+            {
+                if (aa == 255)  // cool, have the shader draw right into the device
+                    shader->shadeSpan(x, y, device, count);
+                else
+                {
+                    shader->shadeSpan(x, y, span, count);
+                    for (int i = count - 1; i >= 0; --i)
+                    {
+                        if (span[i])
+                            device[i] = SkBlendARGB32(span[i], device[i], aa);
+                    }
+                }
+            }
+            device += count;
+            runs += count;
+            antialias += count;
+            x += count;
+        } 
+    }
+    else    // no xfermode but we are not opaque
+    {
+        for (;;)
+        {
+            int        count = *runs;
+            if (count == 0)
+                break;
+            int        aa = *antialias;
+            if (aa)
+            {
+                fShader->shadeSpan(x, y, span, count);
+                if (aa == 255)
+                {
+                    for (int i = count - 1; i >= 0; --i)
+                    {
+                        if (span[i])
+                            device[i] = SkPMSrcOver(span[i], device[i]);
+                    }
+                }
+                else
+                {
+                    for (int i = count - 1; i >= 0; --i)
+                    {
+                        if (span[i])
+                            device[i] = SkBlendARGB32(span[i], device[i], aa);
+                    }
+                }
+            }
+            device += count;
+            runs += count;
+            antialias += count;
+            x += count;
+        } 
+    }
+}
+
diff --git a/libs/graphics/sgl/SkBlitter_RGB16.cpp b/libs/graphics/sgl/SkBlitter_RGB16.cpp
new file mode 100644 (file)
index 0000000..56b2b41
--- /dev/null
@@ -0,0 +1,674 @@
+#include "SkCoreBlitters.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+
+#ifdef SK_DEBUG
+       static unsigned RGB16Add(U16CPU a, U16CPU b)
+       {
+               SkASSERT(SkGetPackedR16(a) + SkGetPackedR16(b) <= SK_R16_MASK);
+               SkASSERT(SkGetPackedG16(a) + SkGetPackedG16(b) <= SK_G16_MASK);
+               SkASSERT(SkGetPackedB16(a) + SkGetPackedB16(b) <= SK_B16_MASK);
+
+               return a + b;
+       }
+#else
+       #define RGB16Add(a, b)  (a + b)
+#endif
+
+#if 1
+#define black_8_pixels(mask, dst)              \
+       do {                                                            \
+               if (mask & 0x80) dst[0] = 0;    \
+               if (mask & 0x40) dst[1] = 0;    \
+               if (mask & 0x20) dst[2] = 0;    \
+               if (mask & 0x10) dst[3] = 0;    \
+               if (mask & 0x08) dst[4] = 0;    \
+               if (mask & 0x04) dst[5] = 0;    \
+               if (mask & 0x02) dst[6] = 0;    \
+               if (mask & 0x01) dst[7] = 0;    \
+       } while (0)
+#else
+static inline black_8_pixels(U8CPU mask, U16 dst[])
+{
+       if (mask & 0x80) dst[0] = 0;
+       if (mask & 0x40) dst[1] = 0;
+       if (mask & 0x20) dst[2] = 0;
+       if (mask & 0x10) dst[3] = 0;
+       if (mask & 0x08) dst[4] = 0;
+       if (mask & 0x04) dst[5] = 0;
+       if (mask & 0x02) dst[6] = 0;
+       if (mask & 0x01) dst[7] = 0;
+}
+#endif
+
+#define        SK_BLITBWMASK_NAME                                      SkRGB16_Black_BlitBW
+#define SK_BLITBWMASK_ARGS
+#define SK_BLITBWMASK_BLIT8(mask, dst)         black_8_pixels(mask, dst)
+#define SK_BLITBWMASK_GETADDR                          getAddr16
+#define SK_BLITBWMASK_DEVTYPE                          U16
+#include "SkBlitBWMaskTemplate.h"
+
+void SkRGB16_Black_Blitter::blitMask(const SkMask& mask, const SkRect16& clip)
+{
+       if (mask.fFormat == SkMask::kBW_Format)
+       {
+               SkRGB16_Black_BlitBW(fDevice, mask, clip);
+       }
+       else
+       {
+               U16* device = fDevice.getAddr16(clip.fLeft, clip.fTop);
+               const U8* alpha = mask.getAddr(clip.fLeft, clip.fTop);
+               unsigned width = clip.width();
+               unsigned height = clip.height();
+               unsigned deviceRB = fDevice.rowBytes() - (width << 1);
+               unsigned maskRB = mask.fRowBytes - width;
+
+               SkASSERT((int)height > 0);
+               SkASSERT((int)width > 0);
+               SkASSERT((int)deviceRB >= 0);
+               SkASSERT((int)maskRB >= 0);
+
+               do {
+                       unsigned w = width;
+                       do {
+                               unsigned aa = *alpha++;
+                               if (aa)
+                               {
+                                       if (aa == 255)
+                                               *device = 0;
+                                       else
+                                               *device = SkToU16(SkAlphaMulRGB16(*device, SkAlpha255To256(255 - aa)));
+                               }
+                               device += 1;
+                       } while (--w != 0);
+                       device = (U16*)((char*)device + deviceRB);
+                       alpha += maskRB;
+               } while (--height != 0);
+       }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+SkRGB16_Blitter::SkRGB16_Blitter(const SkBitmap& device, const SkPaint& paint) : fDevice(device)
+{
+       U32 color = paint.getColor();
+
+       fScale = SkAlpha255To256(SkColorGetA(color));
+
+       fRawColor16 = SkPackRGB16(      SkColorGetR(color) >> (8 - SK_R16_BITS),
+                                                               SkColorGetG(color) >> (8 - SK_G16_BITS),
+                                                               SkColorGetB(color) >> (8 - SK_B16_BITS));
+
+       fColor16 = SkPackRGB16( SkAlphaMul(SkColorGetR(color), fScale) >> (8 - SK_R16_BITS),
+                                                       SkAlphaMul(SkColorGetG(color), fScale) >> (8 - SK_G16_BITS),
+                                                       SkAlphaMul(SkColorGetB(color), fScale) >> (8 - SK_B16_BITS));
+}
+
+void SkRGB16_Blitter::blitH(int x, int y, int width)
+{
+       SkASSERT(width > 0);
+       SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= fDevice.width());
+
+       if (fScale == 0)
+               return;
+
+       U16*            device = fDevice.getAddr16(x, y);
+       unsigned        srcColor = fColor16;
+
+       if (fScale == 256)
+       {
+               sk_memset16(device, srcColor, width);
+       }
+       else
+       {
+               unsigned scale = 256 - fScale;
+               do {
+                       *device = (U16)RGB16Add(srcColor, SkAlphaMulRGB16(*device, scale));
+                       device += 1;
+               } while (--width != 0);
+       }
+}
+
+void SkRGB16_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[])
+{
+       if (fScale == 0)
+               return;
+
+       U16*            device = fDevice.getAddr16(x, y);
+       U16                     srcColor = fColor16;
+       unsigned        scale = fScale;
+
+       if (scale == 256)
+       {
+               for (;;)
+               {
+                       int count = runs[0];
+                       SkASSERT(count >= 0);
+                       if (count == 0)
+                               return;
+                       runs += count;
+
+                       unsigned aa = antialias[0];
+                       antialias += count;
+                       if (aa)
+                       {
+                               if (aa == 255)
+                               {
+                                       sk_memset16(device, srcColor, count);
+                               }
+                               else
+                               {
+                                       unsigned src = SkAlphaMulRGB16(srcColor, SkAlpha255To256(aa));
+                                       unsigned dst_scale = SkAlpha255To256(255 - aa);
+                                       do {
+                                               *device = (U16)RGB16Add(src, SkAlphaMulRGB16(*device, dst_scale));
+                                               device += 1;
+                                       } while (--count != 0);
+                                       continue;
+                               }
+                       }
+                       device += count;
+               }
+       }
+       else
+       {
+               for (;;)
+               {
+                       int count = runs[0];
+                       SkASSERT(count >= 0);
+                       if (count == 0)
+                               return;
+                       runs += count;
+
+                       unsigned aa = antialias[0];
+                       antialias += count;
+                       if (aa)
+                       {
+                               unsigned src = SkAlphaMulRGB16(srcColor, SkAlpha255To256(aa));
+                               unsigned dst_scale = SkAlpha255To256(255 - SkAlphaMul(aa, scale));
+                               do {
+                                       *device = (U16)RGB16Add(src, SkAlphaMulRGB16(*device, dst_scale));
+                                       device += 1;
+                               } while (--count != 0);
+                               continue;
+                       }
+                       device += count;
+               }
+       }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+#define solid_8_pixels(mask, dst, color)       \
+       do {                                                                    \
+               if (mask & 0x80) dst[0] = color;        \
+               if (mask & 0x40) dst[1] = color;        \
+               if (mask & 0x20) dst[2] = color;        \
+               if (mask & 0x10) dst[3] = color;        \
+               if (mask & 0x08) dst[4] = color;        \
+               if (mask & 0x04) dst[5] = color;        \
+               if (mask & 0x02) dst[6] = color;        \
+               if (mask & 0x01) dst[7] = color;        \
+       } while (0)
+
+#define        SK_BLITBWMASK_NAME                                      SkRGB16_BlitBW
+#define SK_BLITBWMASK_ARGS                                     , U16 color
+#define SK_BLITBWMASK_BLIT8(mask, dst)         solid_8_pixels(mask, dst, color)
+#define SK_BLITBWMASK_GETADDR                          getAddr16
+#define SK_BLITBWMASK_DEVTYPE                          U16
+#include "SkBlitBWMaskTemplate.h"
+
+static inline void blend_8_pixels(U8CPU bw, U16 dst[], unsigned dst_scale, U16CPU srcColor)
+{
+       if (bw & 0x80) dst[0] = SkToU16(srcColor + SkAlphaMulRGB16(dst[0], dst_scale));
+       if (bw & 0x40) dst[1] = SkToU16(srcColor + SkAlphaMulRGB16(dst[1], dst_scale));
+       if (bw & 0x20) dst[2] = SkToU16(srcColor + SkAlphaMulRGB16(dst[2], dst_scale));
+       if (bw & 0x10) dst[3] = SkToU16(srcColor + SkAlphaMulRGB16(dst[3], dst_scale));
+       if (bw & 0x08) dst[4] = SkToU16(srcColor + SkAlphaMulRGB16(dst[4], dst_scale));
+       if (bw & 0x04) dst[5] = SkToU16(srcColor + SkAlphaMulRGB16(dst[5], dst_scale));
+       if (bw & 0x02) dst[6] = SkToU16(srcColor + SkAlphaMulRGB16(dst[6], dst_scale));
+       if (bw & 0x01) dst[7] = SkToU16(srcColor + SkAlphaMulRGB16(dst[7], dst_scale));
+}
+
+#define        SK_BLITBWMASK_NAME                                      SkRGB16_BlendBW
+#define SK_BLITBWMASK_ARGS                                     , unsigned dst_scale, U16CPU src_color
+#define SK_BLITBWMASK_BLIT8(mask, dst)         blend_8_pixels(mask, dst, dst_scale, src_color)
+#define SK_BLITBWMASK_GETADDR                          getAddr16
+#define SK_BLITBWMASK_DEVTYPE                          U16
+#include "SkBlitBWMaskTemplate.h"
+
+void SkRGB16_Blitter::blitMask(const SkMask& mask, const SkRect16& clip)
+{
+       if (fScale == 0)
+               return;
+
+       if (mask.fFormat == SkMask::kBW_Format)
+       {
+               if (fScale == 256)
+                       SkRGB16_BlitBW(fDevice, mask, clip, fColor16);
+               else
+                       SkRGB16_BlendBW(fDevice, mask, clip, 256 - fScale, fColor16);
+               return;
+       }
+
+       U16* device = fDevice.getAddr16(clip.fLeft, clip.fTop);
+       const U8* alpha = mask.getAddr(clip.fLeft, clip.fTop);
+       int width = clip.width();
+       int height = clip.height();
+       unsigned        maskRB = mask.fRowBytes;
+       U16                     color16 = fRawColor16;
+       unsigned        scale = fScale;
+       unsigned        deviceRB = fDevice.rowBytes();
+
+       if (scale == 256)
+       {
+               while (--height >= 0)
+               {
+                       for (int i = width - 1; i >= 0; --i)
+                       {
+                               unsigned aa = alpha[i];
+                               if (aa)
+                               {
+                                       if (aa == 255)
+                                               device[i] = color16;
+                                       else
+                                       {
+                                               unsigned src_scale = SkAlpha255To256(aa);
+                                               unsigned dst_scale = SkAlpha255To256(255 - aa);
+                                               device[i] = (U16)RGB16Add(SkAlphaMulRGB16(color16, src_scale), SkAlphaMulRGB16(device[i], dst_scale));
+                                       }
+                               }
+                       }
+                       device = (U16*)((char*)device + deviceRB);
+                       alpha += maskRB;
+               }
+       }
+       else    // scale < 256
+       {
+               while (--height >= 0)
+               {
+                       for (int i = width - 1; i >= 0; --i)
+                       {
+                               unsigned aa = alpha[i];
+                               if (aa)
+                               {
+                                       aa = SkAlphaMul(aa, scale);
+                                       unsigned src_scale = SkAlpha255To256(aa);
+                                       unsigned dst_scale = SkAlpha255To256(255 - aa);
+                                       device[i] = (U16)RGB16Add(SkAlphaMulRGB16(color16, src_scale), SkAlphaMulRGB16(device[i], dst_scale));
+                               }
+                       }
+                       device = (U16*)((char*)device + deviceRB);
+                       alpha += maskRB;
+               }
+       }
+}
+
+void SkRGB16_Blitter::blitV(int x, int y, int height, SkAlpha alpha)
+{
+       if (fScale == 0)
+               return;
+
+       U16*    device = fDevice.getAddr16(x, y);
+       U16             color16 = fColor16;
+       unsigned deviceRB = fDevice.rowBytes();
+
+       if (alpha + fScale == (255 + 256))
+       {
+               do {
+                       device[0] = color16;
+                       device = (U16*)((char*)device + deviceRB);
+               } while (--height != 0);
+       }
+       else
+       {
+               unsigned scale = fScale;
+
+               if (alpha < 255)
+               {
+                       scale = SkAlphaMul(alpha, scale);
+                       color16 = SkToU16(SkAlphaMulRGB16(fRawColor16, scale));
+               }
+               scale = 256 - scale;
+               do {
+                       *device = (U16)RGB16Add(color16, SkAlphaMulRGB16(device[0], scale));
+                       device = (U16*)((char*)device + deviceRB);
+               } while (--height != 0);
+       }
+}
+
+void SkRGB16_Blitter::blitRect(int x, int y, int width, int height)
+{
+       SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= fDevice.width() && (unsigned)(y + height) <= fDevice.height());
+
+       if (fScale == 0)
+               return;
+
+       U16*            device = fDevice.getAddr16(x, y);
+       unsigned        deviceRB = fDevice.rowBytes();
+       U16                     color16 = fColor16;
+
+       if (fScale == 256)
+       {
+               while (--height >= 0)
+               {
+                       sk_memset16(device, color16, width);
+                       device = (U16*)((char*)device + deviceRB);
+               }
+       }
+       else
+       {
+               unsigned dst_scale = 256 - fScale;      // apply it to the dst
+
+               while (--height >= 0)
+               {
+                       for (int i = width - 1; i >= 0; --i)
+                               device[i] = SkToU16(color16 + SkAlphaMulRGB16(device[i], dst_scale));
+                       device = (U16*)((char*)device + deviceRB);
+               }
+       }
+}
+
+///////////////////////////////////////////////////////////////////////
+
+#define BLEND_32_TO_16(srcA, src, dst)  \
+    SkToU16(SkPixel32ToPixel16(src) + SkAlphaMulRGB16(dst, 256 - SkAlpha255To256(srcA)))
+
+SkRGB16_Shader_Blitter::SkRGB16_Shader_Blitter(const SkBitmap& device, const SkPaint& paint) : fDevice(device)
+{
+       SkASSERT(paint.getXfermode() == NULL);
+
+       fShader = paint.getShader();
+       SkASSERT(fShader);
+       fShader->ref();
+
+       SkAutoUnref autoUnref(fShader);
+       fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * sizeof(SkPMColor));
+       (void)autoUnref.detach();
+}
+
+SkRGB16_Shader_Blitter::~SkRGB16_Shader_Blitter()
+{
+       fShader->unref();
+       sk_free(fBuffer);
+}
+
+void SkRGB16_Shader_Blitter::blitH(int x, int y, int width)
+{
+       SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= fDevice.width());
+
+       U16*    device = fDevice.getAddr16(x, y);
+       U32             flags = fShader->getFlags();
+
+       if (SkShader::CanCallShadeSpanOpaque16(flags))
+       {
+               fShader->shadeSpanOpaque16(x, y, device, width);
+               return;
+       }
+
+       //      If we get here, we know we need the 32bit answer from the shader
+
+       SkPMColor*      span = fBuffer;
+
+       fShader->shadeSpan(x, y, span, width);
+       if (flags & SkShader::kOpaqueAlpha_Flag)
+       {
+               for (int i = width - 1; i >= 0; --i)
+                       device[i] = SkPixel32ToPixel16_ToU16(span[i]);
+       }
+       else
+       {
+               for (int i = 0; i < width; i++)
+               {
+                       U32     src = span[i];
+                       if (src)
+                       {
+                               unsigned srcA = SkGetPackedA32(src);
+                               if (srcA == 0xFF)
+                                       device[i] = SkPixel32ToPixel16_ToU16(src);
+                               else
+                    device[i] = BLEND_32_TO_16(srcA, src, device[i]);
+                       }
+               }
+       }
+}
+
+static inline U16 aa_blendS32D16(U32 src, U16CPU dst, int aa)
+{
+       SkASSERT((unsigned)aa <= 255);
+
+       int src_scale = SkAlpha255To256(aa);
+       int     sa = SkGetPackedA32(src);
+       int dst_scale = SkAlpha255To256(255 - SkAlphaMul(sa, src_scale));
+
+       int dr = (SkPacked32ToR16(src) * src_scale + SkGetPackedR16(dst) * dst_scale) >> 8;
+       int dg = (SkPacked32ToG16(src) * src_scale + SkGetPackedG16(dst) * dst_scale) >> 8;
+       int db = (SkPacked32ToB16(src) * src_scale + SkGetPackedB16(dst) * dst_scale) >> 8;
+
+       return SkPackRGB16(dr, dg, db);
+}
+
+static inline int count_nonzero_span(const S16 runs[], const SkAlpha aa[])
+{
+       int     count = 0;
+       for (;;)
+       {
+               int n = *runs;
+               if (n == 0 || *aa == 0)
+                       break;
+               runs += n;
+               aa += n;
+               count += n;
+       }
+       return count;
+}
+
+void SkRGB16_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[])
+{
+//    aa_blendS32D16(0xd4d4d49c, 65526, 238);
+
+       SkASSERT(x >= 0 && y >= 0 && x < (int)fDevice.width() && y < (int)fDevice.height());
+
+       SkShader*       shader = fShader;
+       SkPMColor*      span = fBuffer;
+       U16*            device = fDevice.getAddr16(x, y);
+       U32                     flags = fShader->getFlags();
+
+       if (SkShader::CanCallShadeSpanOpaque16(flags))
+       {
+               U16* span16 = (U16*)span;
+               for (;;)
+               {
+                       int     count = *runs;
+                       if (count == 0)
+                               break;
+
+                       int     aa = *antialias;
+                       if (aa == 255)
+                               shader->shadeSpanOpaque16(x, y, device, count);
+                       else if (aa)
+                       {
+                               unsigned scale = SkAlpha255To256(aa);
+                               shader->shadeSpanOpaque16(x, y, span16, count);
+                               for (int i = 0; i < count; i++)
+                                       device[i] = SkToU16(SkBlendRGB16(span16[i], device[i], scale));
+                       }
+                       device += count;
+                       runs += count;
+                       antialias += count;
+                       x += count;
+               }
+               return;
+       }
+
+       // If we get here, take the 32bit shadeSpan case
+
+       int     opaque = flags & SkShader::kOpaqueAlpha_Flag;
+
+       for (;;)
+       {
+               int     count = *runs;
+               if (count == 0)
+                       break;
+
+               int     aa = *antialias;
+               if (aa == 0)
+               {
+                       device += count;
+                       runs += count;
+                       antialias += count;
+                       x += count;
+                       continue;
+               }
+
+               int nonZeroCount = count + count_nonzero_span(runs + count, antialias + count);
+
+               shader->shadeSpan(x, y, span, nonZeroCount);
+               x += nonZeroCount;
+               SkPMColor* localSpan = span;
+               for (;;)
+               {
+                       if (aa == 255)  // no antialiasing
+                       {
+                               if (opaque)
+                               {
+                                       for (int i = 0; i < count; i++)
+                                               device[i] = SkPixel32ToPixel16_ToU16(localSpan[i]);
+                               }
+                               else
+                               {
+                                       for (int i = 0; i < count; i++)
+                                       {
+                                               U32     src = localSpan[i];
+                                               if (src)
+                                               {
+                                                       unsigned srcA = SkGetPackedA32(src);
+                                                       if (srcA == 0xFF)
+                                                               device[i] = SkPixel32ToPixel16_ToU16(src);
+                                                       else
+                                device[i] = BLEND_32_TO_16(srcA, src, device[i]);
+                                               }
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               for (int i = 0; i < count; i++)
+                               {
+                                       if (localSpan[i])
+                                               device[i] = aa_blendS32D16(localSpan[i], device[i], aa);
+                               }
+                       }
+
+                       device += count;
+                       runs += count;
+                       antialias += count;
+                       nonZeroCount -= count;
+                       if (nonZeroCount == 0)
+                               break;
+
+                       localSpan += count;
+                       SkASSERT(nonZeroCount > 0);
+                       count = *runs;
+                       SkASSERT(count > 0);
+                       aa = *antialias;
+               }
+       }
+}
+
+///////////////////////////////////////////////////////////////////////
+
+SkRGB16_Shader_Xfermode_Blitter::SkRGB16_Shader_Xfermode_Blitter(const SkBitmap& device, const SkPaint& paint) : fDevice(device)
+{
+       fShader = paint.getShader();
+       SkASSERT(fShader);
+       fShader->ref();
+
+       fXfermode = paint.getXfermode();
+       SkASSERT(fXfermode);
+       fXfermode->ref();
+
+       int width = device.width();
+       fBuffer = (SkPMColor*)sk_malloc_throw((width + (SkAlign4(width) >> 2)) * sizeof(SkPMColor));
+       fAAExpand = (U8*)(fBuffer + width);
+}
+
+SkRGB16_Shader_Xfermode_Blitter::~SkRGB16_Shader_Xfermode_Blitter()
+{
+       fXfermode->unref();
+       fShader->unref();
+       sk_free(fBuffer);
+}
+
+void SkRGB16_Shader_Xfermode_Blitter::blitH(int x, int y, int width)
+{
+       SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= fDevice.width());
+
+       U16*            device = fDevice.getAddr16(x, y);
+       SkPMColor*      span = fBuffer;
+
+       fShader->shadeSpan(x, y, span, width);
+       fXfermode->xfer16(device, span, width, NULL);
+}
+
+void SkRGB16_Shader_Xfermode_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[])
+{
+       SkASSERT(x >= 0 && y >= 0 && x < (int)fDevice.width() && y < (int)fDevice.height());
+
+       SkShader*       shader = fShader;
+       SkXfermode*     mode = fXfermode;
+       SkPMColor*      span = fBuffer;
+       U8*                     aaExpand = fAAExpand;
+       U16*            device = fDevice.getAddr16(x, y);
+
+       for (;;)
+       {
+               int     count = *runs;
+               if (count == 0)
+                       break;
+
+               int     aa = *antialias;
+               if (aa == 0)
+               {
+                       device += count;
+                       runs += count;
+                       antialias += count;
+                       x += count;
+                       continue;
+               }
+
+               int nonZeroCount = count + count_nonzero_span(runs + count, antialias + count);
+
+               shader->shadeSpan(x, y, span, nonZeroCount);
+               x += nonZeroCount;
+               SkPMColor* localSpan = span;
+               for (;;)
+               {
+                       if (aa == 0xFF)
+                               mode->xfer16(device, localSpan, count, NULL);
+                       else
+                       {
+                               SkASSERT(aa);
+                               memset(aaExpand, aa, count);
+                               mode->xfer16(device, localSpan, count, aaExpand);
+                       }
+                       device += count;
+                       runs += count;
+                       antialias += count;
+                       nonZeroCount -= count;
+                       if (nonZeroCount == 0)
+                               break;
+
+                       localSpan += count;
+                       SkASSERT(nonZeroCount > 0);
+                       count = *runs;
+                       SkASSERT(count > 0);
+                       aa = *antialias;
+               }
+       } 
+}
+
+
diff --git a/libs/graphics/sgl/SkBlitter_Sprite.cpp b/libs/graphics/sgl/SkBlitter_Sprite.cpp
new file mode 100644 (file)
index 0000000..a740e35
--- /dev/null
@@ -0,0 +1,73 @@
+#include "SkSpriteBlitter.h"
+
+SkSpriteBlitter::SkSpriteBlitter(const SkBitmap& source)
+       : fSource(&source)
+{
+}
+
+SkSpriteBlitter::~SkSpriteBlitter()
+{
+}
+
+#ifdef SK_DEBUG
+void SkSpriteBlitter::blitH(int x, int y, int width)
+{
+       SkASSERT(!"how did we get here?");
+}
+
+void SkSpriteBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[])
+{
+       SkASSERT(!"how did we get here?");
+}
+
+void SkSpriteBlitter::blitV(int x, int y, int height, SkAlpha alpha)
+{
+       SkASSERT(!"how did we get here?");
+}
+
+void SkSpriteBlitter::blitMask(const SkMask&, const SkRect16& clip)
+{
+       SkASSERT(!"how did we get here?");
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+// returning nil means the caller will call SkBlitter::Choose() and
+// have wrapped the source bitmap inside a shader
+SkBlitter* SkBlitter::ChooseSprite(    const SkBitmap& device,
+                                                                       const SkPaint& paint,
+                                                                       const SkBitmap& source,
+                                                                       int left, int top,
+                                                                       void* storage, size_t storageSize)
+{
+       /*      We currently ignore antialiasing and filtertype, meaning we will take our
+               special blitters regardless of these settings. Ignoring filtertype seems fine
+               since by definition there is no scale in the matrix. Ignoring antialiasing is
+               a bit of a hack, since we "could" pass in the fractional left/top for the bitmap,
+               and respect that by blending the edges of the bitmap against the device. To support
+               this we could either add more special blitters here, or detect antialiasing in the
+               paint and return nil if it is set, forcing the client to take the slow shader case
+               (which does respect soft edges).
+       */
+
+       SkSpriteBlitter* blitter = nil;
+       SkXfermode*              mode = paint.getXfermode();
+       U8                               alpha = paint.getAlpha();
+
+       switch (device.getConfig()) {
+       case SkBitmap::kRGB_565_Config:
+               blitter = SkSpriteBlitter::ChooseD16(source, mode, alpha, storage, storageSize);
+        break;
+       case SkBitmap::kARGB_8888_Config:
+               blitter = SkSpriteBlitter::ChooseD32(source, mode, alpha, storage, storageSize);
+       default:
+               break;
+       }
+
+       if (blitter)
+               blitter->setup(device, left, top);
+       return blitter;
+}
+
diff --git a/libs/graphics/sgl/SkCanvas.cpp b/libs/graphics/sgl/SkCanvas.cpp
new file mode 100644 (file)
index 0000000..75cb7bd
--- /dev/null
@@ -0,0 +1,623 @@
+#include "SkCanvas.h"
+#include "SkDraw.h"
+#include "SkBounder.h"
+#include "SkUtils.h"
+
+struct MCRecLayer {
+    SkBitmap    fBitmap;
+    int         fX, fY;
+    SkPaint     fPaint;
+
+    MCRecLayer(const SkPaint& paint) : fPaint(paint) {}
+};
+
+struct SkCanvas::MCRec {
+    MCRec*              fNext;
+
+    SkMatrix            fMatrix;
+    SkMatrix::MapPtProc        fMapPtProc;
+    SkRegion            fRegion;
+
+    MCRecLayer*     fLayer;         // may be NULL
+    const SkBitmap* fCurrBitmap;    // points to layer or prevLayer or pixels
+
+    uint8_t    fSetPaintBits;
+    uint8_t fClearPaintBits;
+    
+    MCRec() : fLayer(NULL)
+    {
+    }
+    MCRec(const MCRec& other)
+        : fMatrix(other.fMatrix), fRegion(other.fRegion), fLayer(NULL)
+    {
+        // don't bother initializing fNext
+        fMapPtProc      = other.fMapPtProc;
+        fCurrBitmap     = other.fCurrBitmap;
+        fSetPaintBits   = other.fSetPaintBits;
+        fClearPaintBits = other.fClearPaintBits;
+    }
+    ~MCRec()
+    {
+        SkDELETE(fLayer);
+    }
+};
+
+class AutoPaintSetClear {
+public:
+       AutoPaintSetClear(const SkPaint& paint, U32 setBits, U32 clearBits) : fPaint(paint)
+       {
+               fFlags = paint.getFlags();
+               ((SkPaint*)&paint)->setFlags((fFlags | setBits) & ~clearBits);
+       }
+       ~AutoPaintSetClear()
+       {
+               ((SkPaint*)&fPaint)->setFlags(fFlags);
+       }
+private:
+       const SkPaint&  fPaint;
+       U32                             fFlags;
+
+       // illegal
+       AutoPaintSetClear(const AutoPaintSetClear&);
+       AutoPaintSetClear& operator=(const AutoPaintSetClear&);
+};
+
+class SkAutoBounderCommit {
+public:
+       SkAutoBounderCommit(SkBounder* bounder) : fBounder(bounder) {}
+       ~SkAutoBounderCommit() { if (fBounder) fBounder->commit(); }
+private:
+       SkBounder*      fBounder;
+};
+
+////////////////////////////////////////////////////////////////////////////
+
+SkCanvas::SkCanvas()
+    : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)), fBounder(NULL)
+{
+    fMCRec = (MCRec*)fMCStack.push_back();
+    new (fMCRec) MCRec;
+
+       fMCRec->fNext = NULL;
+       fMCRec->fMatrix.reset();
+       fMCRec->fSetPaintBits = 0;
+       fMCRec->fClearPaintBits = 0;
+       fMCRec->fMapPtProc = NULL;      // mark as dirty/unknown
+
+    fMCRec->fLayer      = NULL;
+    fMCRec->fCurrBitmap = &fBitmap;
+}
+
+SkCanvas::SkCanvas(const SkBitmap& bitmap)
+    : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)), fBitmap(bitmap), fBounder(NULL)
+{
+    fMCRec = (MCRec*)fMCStack.push_back();
+    new (fMCRec) MCRec;
+    
+       fMCRec->fNext = NULL;
+       fMCRec->fMatrix.reset();
+       fMCRec->fSetPaintBits = 0;
+       fMCRec->fClearPaintBits = 0;
+       fMCRec->fMapPtProc = NULL;      // mark as dirty/unknown
+    
+    fMCRec->fRegion.setRect(0, 0, bitmap.width(), bitmap.height());
+
+    fMCRec->fLayer      = NULL;
+    fMCRec->fCurrBitmap = &fBitmap;
+}
+
+SkCanvas::~SkCanvas()
+{
+}
+
+SkBounder* SkCanvas::setBounder(SkBounder* bounder)
+{
+       SkRefCnt_SafeAssign(fBounder, bounder);
+       return bounder;
+}
+
+void SkCanvas::getPixels(SkBitmap* bitmap) const
+{
+       if (bitmap)
+               *bitmap = fBitmap;
+}
+
+void SkCanvas::setPixels(const SkBitmap& bitmap)
+{
+       unsigned        prevWidth = fBitmap.width();
+       unsigned        prevHeight = fBitmap.height();
+
+       fBitmap = bitmap;
+
+       /*      Now we update our initial region to have the bounds of the new bitmap,
+               and then intersect all of the clips in our stack with these bounds,
+               to ensure that we can't draw outside of the bitmap's bounds (and trash
+               memory).
+
+               NOTE: this is only a partial-fix, since if the new bitmap is larger than
+               the previous one, we don't know how to "enlarge" the clips in our stack,
+               so drawing may be artificially restricted. Without keeping a history of 
+               all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly
+               reconstruct the correct clips, so this approximation will have to do.
+               The caller really needs to restore() back to the base if they want to
+               accurately take advantage of the new bitmap bounds.
+       */
+
+       if (prevWidth != bitmap.width() || prevHeight != bitmap.height())
+       {
+               SkRect16        r;
+               r.set(0, 0, bitmap.width(), bitmap.height());
+
+        SkDeque::Iter   iter(fMCStack);
+        MCRec*          rec = (MCRec*)iter.next();
+        
+        SkASSERT(rec);
+               rec->fRegion.setRect(r);
+
+        while ((rec = (MCRec*)iter.next()) != NULL)
+                       (void)rec->fRegion.op(r, SkRegion::kIntersect_Op);
+       }
+}
+
+bool SkCanvas::isBitmapOpaque() const
+{
+    SkBitmap::Config c = fBitmap.getConfig();
+    
+    return c != SkBitmap::kA8_Config && c != SkBitmap::kARGB_8888_Config;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+U32 SkCanvas::getPaintSetBits() const
+{
+       return fMCRec->fSetPaintBits;
+}
+
+U32 SkCanvas::getPaintClearBits() const
+{
+       return fMCRec->fClearPaintBits;
+}
+
+void SkCanvas::setPaintSetClearBits(U32 setBits, U32 clearBits)
+{
+       fMCRec->fSetPaintBits = SkToU8(setBits & SkPaint::kAllFlagMasks);
+       fMCRec->fClearPaintBits = SkToU8(clearBits & SkPaint::kAllFlagMasks);
+}
+
+void SkCanvas::orPaintSetClearBits(U32 setBits, U32 clearBits)
+{
+       fMCRec->fSetPaintBits |= setBits;
+       fMCRec->fClearPaintBits |= clearBits;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int SkCanvas::save()
+{
+    int saveCount = this->getSaveCount(); // record this before the actual save
+
+    MCRec* newTop = (MCRec*)fMCStack.push_back();
+    new (newTop) MCRec(*fMCRec);
+
+    newTop->fNext = fMCRec;
+    fMCRec = newTop;
+
+    return saveCount;
+}
+
+int SkCanvas::saveLayer(const SkRect& bounds, const SkPaint& paint)
+{
+    // do this before we create the layer
+    int count = this->save();
+
+    SkRect      r;
+    SkRect16    ir;
+    
+    fMCRec->fMatrix.mapRect(&r, bounds);
+    r.roundOut(&ir);
+    
+    if (ir.intersect(fMCRec->fRegion.getBounds()))
+    {
+        MCRecLayer* layer = SkNEW_ARGS(MCRecLayer, (paint));
+
+        layer->fBitmap.setConfig(SkBitmap::kARGB_8888_Config, ir.width(), ir.height());
+        layer->fBitmap.allocPixels();
+        layer->fBitmap.eraseARGB(0, 0, 0, 0);
+        layer->fX = ir.fLeft;
+        layer->fY = ir.fTop;
+        
+        fMCRec->fLayer = layer;
+        fMCRec->fCurrBitmap = &layer->fBitmap;
+
+        fMCRec->fMatrix.postTranslate(-SkIntToScalar(ir.fLeft), -SkIntToScalar(ir.fTop));
+        fMCRec->fMapPtProc = NULL;
+
+        fMCRec->fRegion.op(ir, SkRegion::kIntersect_Op);
+        fMCRec->fRegion.translate(-ir.fLeft, -ir.fTop);
+    }
+    return count;
+}
+
+#include "SkTemplates.h"
+
+void SkCanvas::restore()
+{
+       SkASSERT(!fMCStack.empty());
+
+    MCRecLayer*                 layer = fMCRec->fLayer;
+    SkAutoTDelete<MCRecLayer>   ad(layer);
+    // now detach it from fMCRec
+    fMCRec->fLayer = NULL;
+
+    // now do the normal restore()
+    fMCStack.pop_back();
+    fMCRec = (MCRec*)fMCStack.back();
+
+    // now handle the layer if needed
+    if (layer)
+        this->drawSprite(layer->fBitmap, layer->fX, layer->fY, layer->fPaint);
+}
+
+int SkCanvas::getSaveCount() const
+{
+       return fMCStack.count();
+}
+
+void SkCanvas::restoreToCount(int count)
+{
+       SkASSERT(fMCStack.count() >= count);
+
+       while (fMCStack.count() > count)
+               this->restore();
+}
+
+void SkCanvas::clipDeviceRgn(const SkRegion& rgn)
+{
+       fMCRec->fRegion.op(rgn, SkRegion::kIntersect_Op);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool SkCanvas::translate(SkScalar dx, SkScalar dy)
+{
+       fMCRec->fMapPtProc = NULL;      // mark as dirty/unknown
+       return fMCRec->fMatrix.preTranslate(dx, dy);
+}
+
+bool SkCanvas::scale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
+{
+       fMCRec->fMapPtProc = NULL;      // mark as dirty/unknown
+       return fMCRec->fMatrix.preScale(sx, sy, px, py);
+}
+
+bool SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py)
+{
+       fMCRec->fMapPtProc = NULL;      // mark as dirty/unknown
+       return fMCRec->fMatrix.preRotate(degrees, px, py);
+}
+
+bool SkCanvas::skew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
+{
+       fMCRec->fMapPtProc = NULL;      // mark as dirty/unknown
+       return fMCRec->fMatrix.preSkew(sx, sy, px, py);
+}
+
+bool SkCanvas::concat(const SkMatrix& matrix)
+{
+       fMCRec->fMapPtProc = NULL;      // mark as dirty/unknown
+       return fMCRec->fMatrix.preConcat(matrix);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void SkCanvas::clipRect(const SkRect& rect)
+{
+       if (fMCRec->fMatrix.rectStaysRect())
+       {
+               SkRect          r;
+               SkRect16        ir;
+
+               fMCRec->fMatrix.mapRect(&r, rect);
+               r.round(&ir);
+               fMCRec->fRegion.op(ir, SkRegion::kIntersect_Op);
+       }
+       else
+       {
+               SkPath  path;
+
+               path.addRect(rect);
+               this->clipPath(path);
+       }
+}
+
+void SkCanvas::clipRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom)
+{
+    SkRect  r;
+    
+    r.set(left, top, right, bottom);
+    this->clipRect(r);
+}
+
+void SkCanvas::clipPath(const SkPath& path)
+{
+       SkPath  devPath;
+
+       path.transform(fMCRec->fMatrix, &devPath);
+       fMCRec->fRegion.setPath(devPath, &fMCRec->fRegion);
+}
+
+bool SkCanvas::quickReject(const SkRect& rect, bool antialiased) const
+{
+       if (fMCRec->fRegion.isEmpty() || rect.isEmpty())
+               return true;
+
+       SkRect          r;
+       SkRect16        ir;
+
+       fMCRec->fMatrix.mapRect(&r, rect);
+    if (antialiased)
+        r.roundOut(&ir);
+    else
+        r.round(&ir);
+
+       return fMCRec->fRegion.quickReject(ir);
+}
+
+bool SkCanvas::quickReject(const SkPath& path, bool antialiased) const
+{
+       if (fMCRec->fRegion.isEmpty() || path.isEmpty())
+               return true;        
+
+    if (fMCRec->fMatrix.rectStaysRect())
+    {
+        SkRect  r;
+        path.computeBounds(&r, SkPath::kExact_BoundsType);
+        return this->quickReject(r, antialiased);
+    }
+
+    SkPath      dstPath;
+       SkRect          r;
+       SkRect16        ir;
+
+    path.transform(fMCRec->fMatrix, &dstPath);
+    dstPath.computeBounds(&r, SkPath::kExact_BoundsType);
+    if (antialiased)
+        r.roundOut(&ir);
+    else
+        r.round(&ir);
+
+       return fMCRec->fRegion.quickReject(ir);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void SkCanvas::drawRGB(U8CPU r, U8CPU g, U8CPU b)
+{
+       SkPaint paint;
+
+       paint.setARGB(0xFF, r, g, b);
+       this->drawPaint(paint);
+}
+
+void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
+{
+       SkPaint paint;
+
+       paint.setARGB(a, r, g, b);
+       this->drawPaint(paint);
+}
+
+void SkCanvas::drawColor(SkColor c, SkPorterDuff::Mode mode)
+{
+       SkPaint paint;
+
+       paint.setColor(c);
+    paint.setPorterDuffXfermode(mode);
+       this->drawPaint(paint);
+}
+
+void SkCanvas::drawPaint(const SkPaint& paint)
+{
+       SkAutoBounderCommit     ac(fBounder);
+       SkDraw                          draw(*this);
+
+       draw.drawPaint(paint);
+}
+
+void SkCanvas::drawLine(const SkPoint& start, const SkPoint& stop, const SkPaint& paint)
+{
+       AutoPaintSetClear       force(paint, fMCRec->fSetPaintBits, fMCRec->fClearPaintBits);
+       SkAutoBounderCommit     ac(fBounder);
+       SkDraw                          draw(*this);
+
+       draw.drawLine(start, stop, paint);
+}
+
+void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint)
+{
+       AutoPaintSetClear       force(paint, fMCRec->fSetPaintBits, fMCRec->fClearPaintBits);
+       SkAutoBounderCommit     ac(fBounder);
+       SkDraw                          draw(*this);
+
+       SkPoint pts[2];
+       pts[0].set(x0, y0);
+       pts[1].set(x1, y1);
+       draw.drawLine(pts[0], pts[1], paint);
+}
+
+//#include <stdio.h>
+
+void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint)
+{
+       AutoPaintSetClear       force(paint, fMCRec->fSetPaintBits, fMCRec->fClearPaintBits);
+       SkAutoBounderCommit     ac(fBounder);
+       SkDraw                          draw(*this);
+
+#if 0
+    const SkScalar* m = (const SkScalar*)draw.fMatrix;
+printf("drawRect(%g %g %g %g) matrix(%g %g %g %g %g %g)\n",
+        SkScalarToFloat(r.fLeft), SkScalarToFloat(r.fTop), SkScalarToFloat(r.fRight), SkScalarToFloat(r.fBottom),
+        SkScalarToFloat(m[0]), SkScalarToFloat(m[1]), SkScalarToFloat(m[2]), 
+        SkScalarToFloat(m[3]), SkScalarToFloat(m[4]), SkScalarToFloat(m[5]),
+        SkScalarToFloat(m[6]), SkScalarToFloat(m[7]), SkScalarToFloat(m[8]));
+#endif
+
+       draw.drawRect(r, paint);
+}
+
+void SkCanvas::drawRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, const SkPaint& paint)
+{
+    SkRect  r;
+    
+    r.set(left, top, right, bottom);
+    this->drawRect(r, paint);
+}
+
+void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint)
+{
+       AutoPaintSetClear       force(paint, fMCRec->fSetPaintBits, fMCRec->fClearPaintBits);
+       SkAutoBounderCommit     ac(fBounder);
+       SkDraw                          draw(*this);
+
+       SkPath  path;
+
+       path.addOval(oval);
+       draw.drawPath(path, paint, NULL, true);
+}
+
+void SkCanvas::drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint)
+{
+       AutoPaintSetClear       force(paint, fMCRec->fSetPaintBits, fMCRec->fClearPaintBits);
+       SkAutoBounderCommit     ac(fBounder);
+       SkDraw                          draw(*this);
+
+       SkPath  path;
+
+       path.addCircle(cx, cy, radius);
+       draw.drawPath(path, paint, NULL, true);
+}
+
+void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, const SkPaint& paint)
+{
+       AutoPaintSetClear       force(paint, fMCRec->fSetPaintBits, fMCRec->fClearPaintBits);
+       SkAutoBounderCommit     ac(fBounder);
+       SkDraw                          draw(*this);
+
+       SkPath  path;
+
+       path.addRoundRect(r, rx, ry, SkPath::kCW_Direction);
+       draw.drawPath(path, paint, NULL, true);
+}
+
+void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint)
+{
+       AutoPaintSetClear       force(paint, fMCRec->fSetPaintBits, fMCRec->fClearPaintBits);
+       SkAutoBounderCommit     ac(fBounder);
+       SkDraw                          draw(*this);
+
+       draw.drawPath(path, paint, NULL, false);
+}
+
+void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint& paint)
+{
+       AutoPaintSetClear       force(paint, fMCRec->fSetPaintBits, fMCRec->fClearPaintBits);
+       SkAutoBounderCommit     ac(fBounder);
+       SkDraw                          draw(*this);
+
+       draw.drawBitmap(bitmap, x, y, paint);
+}
+
+void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y)
+{
+    SkPaint paint;
+    this->drawBitmap(bitmap, x, y, paint);
+}
+
+void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint)
+{
+       AutoPaintSetClear       force(paint, fMCRec->fSetPaintBits, fMCRec->fClearPaintBits);
+       SkAutoBounderCommit     ac(fBounder);
+       SkDraw                          draw(*this);
+
+       draw.drawSprite(bitmap, x, y, paint);
+}
+
+void SkCanvas::drawText(const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint)
+{
+       AutoPaintSetClear       force(paint, fMCRec->fSetPaintBits, fMCRec->fClearPaintBits);
+       SkAutoBounderCommit     ac(fBounder);
+       SkDraw                          draw(*this);
+
+       draw.drawText((SkUnicodeWalkerProc)SkUTF8_NextUnichar, text, byteLength, x, y, paint);
+}
+
+void SkCanvas::drawText16(const U16 text[], size_t numberOf16BitValues, SkScalar x, SkScalar y, const SkPaint& paint)
+{
+       AutoPaintSetClear       force(paint, fMCRec->fSetPaintBits, fMCRec->fClearPaintBits);
+       SkAutoBounderCommit     ac(fBounder);
+       SkDraw                          draw(*this);
+
+       draw.drawText((SkUnicodeWalkerProc)SkUTF16_NextUnichar, (const char*)text, numberOf16BitValues << 1, x, y, paint);
+}
+
+void SkCanvas::drawPosText(const char text[], size_t byteLength, const SkPoint pos[], const SkPaint& paint)
+{
+       AutoPaintSetClear       force(paint, fMCRec->fSetPaintBits, fMCRec->fClearPaintBits);
+       SkAutoBounderCommit     ac(fBounder);
+       SkDraw                          draw(*this);
+
+       draw.drawPosText((SkUnicodeWalkerProc)SkUTF8_NextUnichar, text, byteLength, pos, paint);
+}
+
+void SkCanvas::drawPosText16(const U16 text[], size_t numberOf16BitValues, const SkPoint pos[], const SkPaint& paint)
+{
+       AutoPaintSetClear       force(paint, fMCRec->fSetPaintBits, fMCRec->fClearPaintBits);
+       SkAutoBounderCommit     ac(fBounder);
+       SkDraw                          draw(*this);
+
+       draw.drawPosText((SkUnicodeWalkerProc)SkUTF16_NextUnichar, (const char*)text, numberOf16BitValues << 1, pos, paint);
+}
+
+void SkCanvas::drawTextOnPath(const char text[], size_t byteLength, const SkPath& path, SkScalar offset, const SkPaint& paint)
+{
+       AutoPaintSetClear       force(paint, fMCRec->fSetPaintBits, fMCRec->fClearPaintBits);
+       SkAutoBounderCommit     ac(fBounder);
+       SkDraw                          draw(*this);
+
+       draw.drawTextOnPath((SkUnicodeWalkerProc)SkUTF8_NextUnichar, text, byteLength, path, offset, paint);
+}
+
+void SkCanvas::drawText16OnPath(const U16 text[], size_t numberOf16BitValues, const SkPath& path, SkScalar offset, const SkPaint& paint)
+{
+       AutoPaintSetClear       force(paint, fMCRec->fSetPaintBits, fMCRec->fClearPaintBits);
+       SkAutoBounderCommit     ac(fBounder);
+       SkDraw                          draw(*this);
+
+       draw.drawTextOnPath((SkUnicodeWalkerProc)SkUTF16_NextUnichar, (const char*)text, numberOf16BitValues << 1, path, offset, paint);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+const SkBitmap& SkCanvas::getCurrBitmap() const
+{
+    return *fMCRec->fCurrBitmap;
+}
+
+SkMatrix::MapPtProc SkCanvas::getCurrMapPtProc() const
+{
+    if (fMCRec->fMapPtProc == NULL)
+        fMCRec->fMapPtProc = fMCRec->fMatrix.getMapPtProc();
+
+    return fMCRec->fMapPtProc;
+}
+
+const SkMatrix& SkCanvas::getTotalMatrix() const
+{
+    return fMCRec->fMatrix;
+}
+
+const SkRegion& SkCanvas::getTotalClip() const
+{
+    return fMCRec->fRegion;
+}
+
diff --git a/libs/graphics/sgl/SkColor.cpp b/libs/graphics/sgl/SkColor.cpp
new file mode 100644 (file)
index 0000000..3831c57
--- /dev/null
@@ -0,0 +1,118 @@
+#include "SkColor.h"
+#include "SkColorPriv.h"
+
+SkPMColor SkPreMultiplyARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
+{
+       if (a != 255)
+       {
+               unsigned scale = SkAlpha255To256(a);
+               r = SkAlphaMul(r, scale);
+               g = SkAlphaMul(g, scale);
+               b = SkAlphaMul(b, scale);
+       }
+       return SkPackARGB32(a, r, g, b);
+}
+
+SkPMColor SkPreMultiplyColor(SkColor c)
+{
+       unsigned a = SkColorGetA(c);
+       unsigned r = SkColorGetR(c);
+       unsigned g = SkColorGetG(c);
+       unsigned b = SkColorGetB(c);
+
+       return SkPreMultiplyARGB(a, r, g, b);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+static inline SkScalar ByteToScalar(U8CPU x)
+{
+    SkASSERT(x <= 255);
+    return SkIntToScalar(x) / 255;
+}
+
+static inline SkScalar ByteDivToScalar(int numer, U8CPU denom)
+{
+    // cast to keep the answer signed
+    return SkIntToScalar(numer) / (int)denom;
+}
+
+void SkRGBToHSV(U8CPU r, U8CPU g, U8CPU b, SkScalar hsv[3])
+{
+    SkASSERT(hsv);
+
+    unsigned min = SkMin32(r, SkMin32(g, b));
+    unsigned max = SkMax32(r, SkMax32(g, b));
+    unsigned delta = max - min;
+
+    SkScalar v = ByteToScalar(max);
+    SkASSERT(v >= 0 && v <= SK_Scalar1);
+
+    if (0 == delta) // we're a shade of gray
+    {
+        hsv[0] = hsv[1] = hsv[2] = v;
+        return;
+    }
+
+    SkScalar s = ByteDivToScalar(delta, max);
+    SkASSERT(s >= 0 && s <= SK_Scalar1);
+
+    SkScalar h;    
+    if (r == max)
+        h = ByteDivToScalar(g - b, delta);
+    else if (g == max)
+        h = SkIntToScalar(2) + ByteDivToScalar(b - r, delta);
+    else // b == max
+        h = SkIntToScalar(4) + ByteDivToScalar(r - g, delta);
+
+    h *= 60;
+    if (h < 0)
+        h += SkIntToScalar(360);
+    SkASSERT(h >= 0 && h < SkIntToScalar(360));
+
+    hsv[0] = h;
+    hsv[1] = s;
+    hsv[2] = v;
+}
+
+static inline U8CPU UnitScalarToByte(SkScalar x)
+{
+    if (x < 0)
+        return 0;
+    if (x >= SK_Scalar1)
+        return 255;
+    return SkScalarToFixed(x) >> 8;
+}
+
+SkColor SkHSVToColor(U8CPU a, const SkScalar hsv[3])
+{
+    SkASSERT(hsv);
+
+    U8CPU   s = UnitScalarToByte(hsv[1]);
+    U8CPU   v = UnitScalarToByte(hsv[2]);
+
+    if (0 == s) // shade of gray
+        return SkColorSetARGB(a, v, v, v);
+
+    SkFixed hx = (hsv[0] < 0 || hsv[0] >= SkIntToScalar(360)) ? 0 : SkScalarToFixed(hsv[0]/60);
+    SkFixed f = hx & 0xFFFF;
+    
+    unsigned v_scale = SkAlpha255To256(v);
+    unsigned p = SkAlphaMul(255 - s, v_scale);
+    unsigned q = SkAlphaMul(255 - (s * f >> 16), v_scale);
+    unsigned t = SkAlphaMul(255 - (s * (SK_Fixed1 - f) >> 16), v_scale);
+    
+    unsigned r, g, b;
+
+    SkASSERT((unsigned)(hx >> 16) < 6);
+    switch (hx >> 16) {
+        case 0: r = v; g = t; b = p; break;
+        case 1: r = q; g = v; b = p; break;
+        case 2: r = p; g = v; b = t; break;
+        case 3: r = p; g = q; b = v; break;
+        case 4: r = t;  g = p; b = v; break;
+        default: r = v; g = p; b = q; break;
+    }
+    return SkColorSetARGB(a, r, g, b);
+}
+
diff --git a/libs/graphics/sgl/SkColorFilter.cpp b/libs/graphics/sgl/SkColorFilter.cpp
new file mode 100644 (file)
index 0000000..dc89eb4
--- /dev/null
@@ -0,0 +1,36 @@
+#include "SkColorFilter.h"
+#include "SkShader.h"
+
+void SkColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor result[])
+{
+    memcpy(result, src, count * sizeof(SkPMColor));
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+SkFilterShader::SkFilterShader(SkShader* shader, SkColorFilter* filter)
+{
+    fShader = shader;   shader->ref();
+    fFilter = filter;   filter->ref();
+}
+
+SkFilterShader::~SkFilterShader()
+{
+    fFilter->unref();
+    fShader->unref();
+}
+
+bool SkFilterShader::setContext(const SkBitmap& device,
+                                const SkPaint& paint,
+                                const SkMatrix& matrix)
+{
+    return  this->INHERITED::setContext(device, paint, matrix) &&
+            fShader->setContext(device, paint, matrix);
+}
+
+void SkFilterShader::shadeSpan(int x, int y, SkPMColor result[], int count)
+{
+    fShader->shadeSpan(x, y, result, count);
+    fFilter->filterSpan(result, count, result);
+}
+
diff --git a/libs/graphics/sgl/SkColorTable.cpp b/libs/graphics/sgl/SkColorTable.cpp
new file mode 100644 (file)
index 0000000..2904a8f
--- /dev/null
@@ -0,0 +1,99 @@
+#include "SkBitmap.h"
+#include "SkTemplates.h"
+
+SkColorTable::SkColorTable() : fColors(nil), f16BitCache(nil), fCount(0), fFlags(0)
+{
+       SkDEBUGCODE(fColorLockCount = 0;)
+       SkDEBUGCODE(f16BitCacheLockCount = 0;)
+}
+
+SkColorTable::~SkColorTable()
+{
+       SkASSERT(fColorLockCount == 0);
+       SkASSERT(f16BitCacheLockCount == 0);
+
+       sk_free(fColors);
+       sk_free(f16BitCache);
+}
+
+void SkColorTable::setFlags(unsigned flags)
+{
+       fFlags = SkToU8(flags);
+}
+
+void SkColorTable::setColors(const SkPMColor src[], int count)
+{
+       SkASSERT(fColorLockCount == 0);
+       SkASSERT((unsigned)count <= 256);
+
+       if (fCount != count)
+       {
+               if (count == 0)
+               {
+                       sk_free(fColors);
+                       fColors = nil;
+               }
+               else
+               {
+                       // allocate new array before freeing old, in case the alloc fails (throws)
+                       SkPMColor* table = (SkPMColor*)sk_malloc_throw(count * sizeof(SkPMColor));
+                       sk_free(fColors);
+                       fColors = table;
+
+                       if (src)
+                               memcpy(fColors, src, count * sizeof(SkPMColor));
+               }
+               fCount = SkToU16(count);
+       }
+       else
+       {
+               if (src)
+                       memcpy(fColors, src, count * sizeof(SkPMColor));
+       }
+
+       this->inval16BitCache();
+}
+
+void SkColorTable::inval16BitCache()
+{
+       SkASSERT(f16BitCacheLockCount == 0);
+       if (f16BitCache)
+       {
+               sk_free(f16BitCache);
+               f16BitCache = nil;
+       }
+}
+
+#include "SkColorPriv.h"
+
+static inline void build_16bitcache(U16 dst[], const SkPMColor src[], int count)
+{
+       while (--count >= 0)
+               *dst++ = SkPixel32ToPixel16_ToU16(*src++);
+}
+
+const U16* SkColorTable::lock16BitCache()
+{
+       if (fFlags & kColorsAreOpaque_Flag)
+       {
+               if (f16BitCache == nil) // build the cache
+               {
+                       f16BitCache = (U16*)sk_malloc_throw(fCount * sizeof(U16));
+                       build_16bitcache(f16BitCache, fColors, fCount);
+               }
+       }
+       else    // our colors have alpha, so no cache
+       {
+               this->inval16BitCache();
+               if (f16BitCache)
+               {
+                       sk_free(f16BitCache);
+                       f16BitCache = nil;
+               }
+       }
+
+       SkDEBUGCODE(f16BitCacheLockCount += 1);
+       return f16BitCache;
+}
+
+
diff --git a/libs/graphics/sgl/SkCoreBlitters.h b/libs/graphics/sgl/SkCoreBlitters.h
new file mode 100644 (file)
index 0000000..ebf339a
--- /dev/null
@@ -0,0 +1,177 @@
+#ifndef SkCoreBlitters_DEFINED
+#define SkCoreBlitters_DEFINED
+
+#include "SkBlitter.h"
+
+class SkA8_Blitter : public SkBlitter {
+public:
+       SkA8_Blitter(const SkBitmap& device, const SkPaint& paint);
+       virtual void blitH(int x, int y, int width);
+       virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[]);
+       virtual void blitV(int x, int y, int height, SkAlpha alpha);
+       virtual void blitRect(int x, int y, int width, int height);
+       virtual void blitMask(const SkMask&, const SkRect16&);
+
+private:
+       const SkBitmap& fDevice;
+       unsigned                fSrcA;
+
+       // illegal
+       SkA8_Blitter& operator=(const SkA8_Blitter&);
+};
+
+class SkA8_Shader_Blitter : public SkBlitter {
+public:
+       SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint& paint);
+       virtual ~SkA8_Shader_Blitter();
+       virtual void blitH(int x, int y, int width);
+       virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[]);
+       virtual void blitMask(const SkMask&, const SkRect16&);
+
+private:
+       const SkBitmap& fDevice;
+       SkShader*       fShader;
+       SkXfermode*     fXfermode;
+       SkPMColor*      fBuffer;
+       U8*                     fAAExpand;
+
+    typedef SkBlitter INHERITED;
+
+       // illegal
+       SkA8_Shader_Blitter& operator=(const SkA8_Shader_Blitter&);
+};
+
+////////////////////////////////////////////////////////////////
+
+class SkARGB32_Blitter : public SkBlitter {
+public:
+       SkARGB32_Blitter(const SkBitmap& device, const SkPaint& paint);
+       virtual void blitH(int x, int y, int width);
+       virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[]);
+       virtual void blitV(int x, int y, int height, SkAlpha alpha);
+       virtual void blitRect(int x, int y, int width, int height);
+       virtual void blitMask(const SkMask&, const SkRect16&);
+
+protected:
+       const SkBitmap& fDevice;
+
+private:
+       SkColor         fPMColor;
+       unsigned        fSrcA, fSrcR, fSrcG, fSrcB;
+
+       // illegal
+       SkARGB32_Blitter& operator=(const SkARGB32_Blitter&);
+};
+
+class SkARGB32_Black_Blitter : public SkARGB32_Blitter {
+public:
+       SkARGB32_Black_Blitter(const SkBitmap& device, const SkPaint& paint)
+               : SkARGB32_Blitter(device, paint) {}
+       virtual void blitMask(const SkMask&, const SkRect16&);
+};
+
+class SkARGB32_Shader_Blitter : public SkBlitter {
+public:
+       SkARGB32_Shader_Blitter(const SkBitmap& device, const SkPaint& paint);
+       virtual ~SkARGB32_Shader_Blitter();
+       virtual void blitH(int x, int y, int width);
+       virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[]);
+
+private:
+       const SkBitmap& fDevice;
+       SkShader*       fShader;
+       SkXfermode*     fXfermode;
+       SkPMColor*      fBuffer;
+
+       typedef SkBlitter INHERITED;
+
+       // illegal
+       SkARGB32_Shader_Blitter& operator=(const SkARGB32_Shader_Blitter&);
+};
+
+////////////////////////////////////////////////////////////////
+
+class SkRGB16_Blitter : public SkBlitter {
+public:
+       SkRGB16_Blitter(const SkBitmap& device, const SkPaint& paint);
+       virtual void blitH(int x, int y, int width);
+       virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[]);
+       virtual void blitV(int x, int y, int height, SkAlpha alpha);
+       virtual void blitRect(int x, int y, int width, int height);
+       virtual void blitMask(const SkMask&, const SkRect16&);
+
+protected:
+       const SkBitmap& fDevice;
+
+private:
+       unsigned        fScale;
+       U16                     fColor16;
+       U16                     fRawColor16;
+
+       // illegal
+       SkRGB16_Blitter& operator=(const SkRGB16_Blitter&);
+};
+
+class SkRGB16_Black_Blitter : public SkRGB16_Blitter {
+public:
+       SkRGB16_Black_Blitter(const SkBitmap& device, const SkPaint& paint)
+               : SkRGB16_Blitter(device, paint) {}
+       virtual void blitMask(const SkMask&, const SkRect16&);
+};
+
+class SkRGB16_Shader_Blitter : public SkBlitter {
+public:
+       SkRGB16_Shader_Blitter(const SkBitmap& device, const SkPaint& paint);
+       virtual ~SkRGB16_Shader_Blitter();
+       virtual void blitH(int x, int y, int width);
+       virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[]);
+
+private:
+       const SkBitmap& fDevice;
+       SkShader*       fShader;
+       SkPMColor*      fBuffer;
+
+       typedef SkBlitter INHERITED;
+
+       // illegal
+       SkRGB16_Shader_Blitter& operator=(const SkRGB16_Shader_Blitter&);
+};
+
+class SkRGB16_Shader_Xfermode_Blitter : public SkBlitter {
+public:
+       SkRGB16_Shader_Xfermode_Blitter(const SkBitmap& device, const SkPaint& paint);
+       virtual ~SkRGB16_Shader_Xfermode_Blitter();
+       virtual void blitH(int x, int y, int width);
+       virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[]);
+
+private:
+       const SkBitmap& fDevice;
+       SkShader*       fShader;
+       SkXfermode*     fXfermode;
+       SkPMColor*      fBuffer;
+       U8*                     fAAExpand;
+
+       typedef SkBlitter INHERITED;
+
+       // illegal
+       SkRGB16_Shader_Xfermode_Blitter& operator=(const SkRGB16_Shader_Xfermode_Blitter&);
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+class SkA1_Blitter : public SkBlitter {
+public:
+       SkA1_Blitter(const SkBitmap& device, const SkPaint& paint);
+       virtual void blitH(int x, int y, int width);
+
+private:
+       const SkBitmap& fDevice;
+       U8                              fSrcA;
+
+       // illegal
+       SkA1_Blitter& operator=(const SkA1_Blitter&);
+};
+
+
+#endif
+
diff --git a/libs/graphics/sgl/SkDeque.cpp b/libs/graphics/sgl/SkDeque.cpp
new file mode 100644 (file)
index 0000000..d2ccfeb
--- /dev/null
@@ -0,0 +1,389 @@
+#include "SkDeque.h"
+
+#define INIT_ELEM_COUNT 1  // should we let the caller set this in the constructor?
+
+struct SkDeque::Head {
+    Head*   fNext;
+    Head*   fPrev;
+    char*   fBegin; // start of used section in this chunk
+    char*   fEnd;   // end of used section in this chunk
+    char*   fStop;  // end of the allocated chunk
+    
+    char*       start() { return (char*)(this + 1); }
+    const char* start() const { return (const char*)(this + 1); }
+    
+    void init(size_t size)
+    {
+        fNext   = fPrev = nil;
+        fBegin  = fEnd = nil;
+        fStop   = (char*)this + size;
+    }
+};
+
+SkDeque::SkDeque(size_t elemSize) : fElemSize(elemSize), fInitialStorage(nil), fCount(0)
+{
+    fFront = fBack = nil;
+}
+
+SkDeque::SkDeque(size_t elemSize, void* storage, size_t storageSize)
+    : fElemSize(elemSize), fInitialStorage(storage), fCount(0)
+{
+    SkASSERT(storageSize == 0 || storage != nil);
+    
+    if (storageSize >= sizeof(Head) + elemSize)
+    {
+        fFront = (Head*)storage;
+        fFront->init(storageSize);
+    }
+    else
+    {
+        fFront = nil;
+    }
+    fBack = fFront;
+}
+
+SkDeque::~SkDeque()
+{
+    Head* head = fFront;
+    Head* initialHead = (Head*)fInitialStorage;
+
+    while (head)
+    {
+        Head* next = head->fNext;
+        if (head != initialHead)
+            sk_free(head);
+        head = next;
+    }
+}
+
+const void* SkDeque::front() const
+{
+    Head* front = fFront;
+    
+    if (front == nil)
+        return nil;
+    
+    if (front->fBegin == nil)
+    {
+        front = front->fNext;
+        if (front == nil)
+            return nil;
+    }
+    SkASSERT(front->fBegin);
+    return front->fBegin;
+}
+
+const void* SkDeque::back() const
+{
+    Head* back = fBack;
+
+    if (back == nil)
+        return nil;
+
+    if (back->fEnd == nil)  // marked as deleted
+    {
+        back = back->fPrev;
+        if (back == nil)
+            return nil;
+    }
+    SkASSERT(back->fEnd);
+    return back->fEnd - fElemSize;
+}
+
+void* SkDeque::push_front()
+{
+    fCount += 1;
+
+    if (fFront == nil)
+    {
+        fFront = (Head*)sk_malloc_throw(sizeof(Head) + INIT_ELEM_COUNT * fElemSize);
+        fFront->init(sizeof(Head) + INIT_ELEM_COUNT * fElemSize);
+        fBack = fFront;     // update our linklist
+    }
+    
+    Head*   first = fFront;
+    char*   begin;
+
+    if (first->fBegin == nil)
+    {
+    INIT_CHUNK:
+        first->fEnd = first->fStop;
+        begin = first->fStop - fElemSize;
+    }
+    else
+    {
+        begin = first->fBegin - fElemSize;
+        if (begin < first->start())     // no more room in this chunk
+        {
+            // should we alloc more as we accumulate more elements?
+            size_t  size = sizeof(Head) + INIT_ELEM_COUNT * fElemSize;
+
+            first = (Head*)sk_malloc_throw(size);
+            first->init(size);
+            first->fNext = fFront;
+            fFront->fPrev = first;
+            fFront = first;
+            goto INIT_CHUNK;
+        }
+    }
+
+    first->fBegin = begin;
+    return begin;
+}
+
+void* SkDeque::push_back()
+{
+    fCount += 1;
+
+    if (fBack == nil)
+    {
+        fBack = (Head*)sk_malloc_throw(sizeof(Head) + INIT_ELEM_COUNT * fElemSize);
+        fBack->init(sizeof(Head) + INIT_ELEM_COUNT * fElemSize);
+        fFront = fBack; // update our linklist
+    }
+    
+    Head*   last = fBack;
+    char*   end;
+
+    if (last->fBegin == nil)
+    {
+    INIT_CHUNK:
+        last->fBegin = last->start();
+        end = last->fBegin + fElemSize;
+    }
+    else
+    {
+        end = last->fEnd + fElemSize;
+        if (end > last->fStop)  // no more room in this chunk
+        {
+            // should we alloc more as we accumulate more elements?
+            size_t  size = sizeof(Head) + INIT_ELEM_COUNT * fElemSize;
+
+            last = (Head*)sk_malloc_throw(size);
+            last->init(size);
+            last->fPrev = fBack;
+            fBack->fNext = last;
+            fBack = last;
+            goto INIT_CHUNK;
+        }
+    }
+
+    last->fEnd = end;
+    return end - fElemSize;
+}
+
+void SkDeque::pop_front()
+{
+    SkASSERT(fCount > 0);
+    fCount -= 1;
+
+    Head*   first = fFront;
+
+    SkASSERT(first != nil);
+    
+    if (first->fBegin == nil)   // we were marked empty from before
+    {
+        first = first->fNext;
+        first->fPrev = nil;
+        sk_free(fFront);
+        fFront = first;
+        SkASSERT(first != nil);    // else we popped too far
+    }
+
+    char* begin = first->fBegin + fElemSize;
+    SkASSERT(begin <= first->fEnd);
+
+    if (begin < fFront->fEnd)
+        first->fBegin = begin;
+    else
+        first->fBegin = first->fEnd = nil;  // mark as empty
+}
+
+void SkDeque::pop_back()
+{
+    SkASSERT(fCount > 0);
+    fCount -= 1;
+
+    Head* last = fBack;
+    
+    SkASSERT(last != nil);
+    
+    if (last->fEnd == nil)  // we were marked empty from before
+    {
+        last = last->fPrev;
+        last->fNext = nil;
+        sk_free(fBack);
+        fBack = last;
+        SkASSERT(last != nil);  // else we popped too far
+    }
+    
+    char* end = last->fEnd - fElemSize;
+    SkASSERT(end >= last->fBegin);
+
+    if (end > last->fBegin)
+        last->fEnd = end;
+    else
+        last->fBegin = last->fEnd = nil;    // mark as empty
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkDeque::Iter::Iter(const SkDeque& d) : fElemSize(d.fElemSize)
+{
+    fHead = d.fFront;
+    while (fHead != nil && fHead->fBegin == nil)
+        fHead = fHead->fNext;
+    fPos = fHead ? fHead->fBegin : nil;
+}
+
+void* SkDeque::Iter::next()
+{
+    char* pos = fPos;
+    
+    if (pos)   // if we were valid, try to move to the next setting
+    {
+        char* next = pos + fElemSize;
+        SkASSERT(next <= fHead->fEnd);
+        if (next == fHead->fEnd) // exhausted this chunk, move to next
+        {
+            do {
+                fHead = fHead->fNext;
+            } while (fHead != nil && fHead->fBegin == nil);
+            next = fHead ? fHead->fBegin : nil;
+        }
+        fPos = next;
+    }
+    return pos;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+SK_SET_BASIC_TRAITS(void);
+SK_SET_BASIC_TRAITS(bool);
+SK_SET_BASIC_TRAITS(char);
+SK_SET_BASIC_TRAITS(unsigned char);
+SK_SET_BASIC_TRAITS(short);
+SK_SET_BASIC_TRAITS(unsigned short);
+SK_SET_BASIC_TRAITS(int);
+SK_SET_BASIC_TRAITS(unsigned int);
+SK_SET_BASIC_TRAITS(long);
+SK_SET_BASIC_TRAITS(unsigned long);
+SK_SET_BASIC_TRAITS(float);
+SK_SET_BASIC_TRAITS(double);
+
+#include <new>
+
+static size_t gTestClassCount;
+
+//#define SPEW_LIFETIME
+
+class TestClass {
+public:
+    TestClass()
+    {
+        ++gTestClassCount;
+#ifdef SPEW_LIFETIME
+        SkDebugf("gTestClassCount=%d\n", gTestClassCount);
+#endif
+    }
+    TestClass(int value) : fValue(value)
+    {
+        ++gTestClassCount;
+#ifdef SPEW_LIFETIME
+        SkDebugf("gTestClassCount=%d\n", gTestClassCount);
+#endif
+    }
+    TestClass(const TestClass& src) : fValue(src.fValue)
+    {
+        ++gTestClassCount;
+#ifdef SPEW_LIFETIME
+        SkDebugf("gTestClassCount=%d\n", gTestClassCount);
+#endif
+    }
+    ~TestClass()
+    {
+        --gTestClassCount;
+#ifdef SPEW_LIFETIME
+        SkDebugf("~gTestClassCount=%d\n", gTestClassCount);
+#endif
+    }
+    int fValue;
+};
+
+SK_SET_TYPE_TRAITS(TestClass, false, false, false, true);
+
+void SkDeque::UnitTest()
+{
+    {
+        SkTDeque<int>           d1;
+        SkTDeque<int>           d2;
+        SkTDeque<TestClass>     d3;
+        SkSTDeque<5, TestClass> d4;
+
+        int i;
+        
+        SkASSERT(d1.empty());
+        SkASSERT(d2.empty());
+        SkASSERT(d3.empty());
+        SkASSERT(d4.empty());
+
+        for (i = 0; i < 100; i++)
+        {
+            d1.push_front(i);
+            SkASSERT(*d1.front() == i);
+            SkASSERT(*d1.back() == 0);
+
+            d2.push_back(i);
+            SkASSERT(*d2.back() == i);
+            SkASSERT(*d2.front() == 0);
+
+            d3.push_front(TestClass(i));
+            d3.push_back(TestClass(-i));
+            SkASSERT(d3.front()->fValue == i);
+            SkASSERT(d3.back()->fValue == -i);
+
+            d4.push_front()->fValue = i;
+            d4.push_back()->fValue = -i;
+            SkASSERT(d4.front()->fValue == i);
+            SkASSERT(d4.back()->fValue == -i);
+        }
+        
+        SkASSERT(d1.count() == 100);
+        SkASSERT(d2.count() == 100);
+        SkASSERT(d3.count() == 200);
+        SkASSERT(d4.count() == 200);
+        
+        {
+            SkTDeque<int>::Iter iter(d2);
+            int*                curr;
+            
+            i = 0;
+            while ((curr = iter.next()) != nil) {
+                SkASSERT(*curr == i);
+                i += 1;
+            }
+            SkASSERT(i == 100);
+        }
+        
+        for (i = 0; i < 50; i++)
+        {
+            d1.pop_front(); d1.pop_back();
+            d2.pop_front(); d2.pop_back();
+            d3.pop_front(); d3.pop_back();
+            d4.pop_front(); d4.pop_back();
+        }
+
+        SkASSERT(d1.count() == 0);
+        SkASSERT(d2.count() == 0);
+        SkASSERT(d3.count() == 100);
+        SkASSERT(d4.count() == 100);
+    }
+    int counter = gTestClassCount;
+    SkASSERT(counter == 0);
+}
+
+#endif
+
diff --git a/libs/graphics/sgl/SkDraw.cpp b/libs/graphics/sgl/SkDraw.cpp
new file mode 100644 (file)
index 0000000..9b1ed98
--- /dev/null
@@ -0,0 +1,1139 @@
+#include "SkDraw.h"
+#include "SkBlitter.h"
+#include "SkBounder.h"
+#include "SkCanvas.h"
+#include "SkMaskFilter.h"
+#include "SkPaint.h"
+#include "SkPathEffect.h"
+#include "SkRasterizer.h"
+#include "SkScan.h"
+#include "SkShader.h"
+#include "SkStroke.h"
+#include "SkTemplatesPriv.h"
+#include "SkTextLayout.h"
+
+/**    Helper for allocating small blitters on the stack.
+*/
+
+#define kBlitterStorageLongCount       40
+
+class SkAutoBlitterChoose {
+public:
+       SkAutoBlitterChoose(const SkBitmap& device, const SkMatrix& matrix, const SkPaint& paint)
+       {
+               fBlitter = SkBlitter::Choose(device, matrix, paint, fStorage, sizeof(fStorage));
+       }
+       ~SkAutoBlitterChoose();
+
+       SkBlitter*      operator->() { return fBlitter; }
+       SkBlitter*      get() const { return fBlitter; }
+
+private:
+       SkBlitter*      fBlitter;
+       uint32_t        fStorage[kBlitterStorageLongCount];
+};
+
+SkAutoBlitterChoose::~SkAutoBlitterChoose()
+{
+    if ((void*)fBlitter == (void*)fStorage)
+        fBlitter->~SkBlitter();
+    else
+        SkDELETE(fBlitter);
+}
+
+class SkAutoBitmapShaderInstall {
+public:
+       SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint* paint) : fPaint((SkPaint*)paint)
+       {
+               fPrevShader = paint->getShader();
+               fPrevShader->safeRef();
+               fPaint->setShader(SkShader::CreateBitmapShader( src, false, paint->getFilterType(),
+                                                        SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
+                                                                                                               fStorage, sizeof(fStorage)));
+       }
+       ~SkAutoBitmapShaderInstall()
+       {
+               SkShader* shader = fPaint->getShader();
+
+               fPaint->setShader(fPrevShader);
+               fPrevShader->safeUnref();
+
+               if ((void*)shader == (void*)fStorage)
+                       shader->~SkShader();
+               else
+                       SkDELETE(shader);
+       }
+private:
+       SkPaint*        fPaint;
+       SkShader*       fPrevShader;
+       uint32_t        fStorage[kBlitterStorageLongCount];
+};
+
+class SkAutoPaintStyleRestore {
+public:
+       SkAutoPaintStyleRestore(const SkPaint& paint, SkPaint::Style style)
+               : fPaint((SkPaint&)paint)
+       {
+               fStyle = paint.getStyle();      // record the old
+               fPaint.setStyle(style);         // change it to the specified style
+       }
+       ~SkAutoPaintStyleRestore()
+       {
+               fPaint.setStyle(fStyle);        // restore the old
+       }
+private:
+       SkPaint&                fPaint;
+       SkPaint::Style  fStyle;
+
+       // illegal
+       SkAutoPaintStyleRestore(const SkAutoPaintStyleRestore&);
+       SkAutoPaintStyleRestore& operator=(const SkAutoPaintStyleRestore&);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkDraw::SkDraw(const SkCanvas& canvas)
+{
+       fDevice         = &canvas.getCurrBitmap();
+       fMatrix         = &canvas.getTotalMatrix();
+       fClip           = &canvas.getTotalClip();
+       fBounder        = canvas.getBounder();
+       fMapPtProc      = canvas.getCurrMapPtProc();
+
+       SkDEBUGCODE(this->validate();)
+}
+
+void SkDraw::drawPaint(const SkPaint& paint)
+{
+       SkDEBUGCODE(this->validate();)
+
+       if (fClip->isEmpty())
+        return;
+
+    SkRect16   devRect;
+    devRect.set(0, 0, fDevice->width(), fDevice->height());
+
+    if (fBounder && !fBounder->doIRect(devRect, *fClip))
+        return;
+
+    SkAutoBlitterChoose        blitter(*fDevice, *fMatrix, paint);
+    SkScan::FillDevRect(devRect, fClip, blitter.get());
+}
+
+void SkDraw::drawLine(const SkPoint& start, const SkPoint& stop, const SkPaint& paint)
+{
+       SkDEBUGCODE(this->validate();)
+
+       if (fClip->isEmpty() ||
+        (paint.getAlpha() == 0 && paint.getXfermode() == NULL))        // nothing to draw
+        return;
+
+       if (!paint.getPathEffect() && !paint.getMaskFilter() &&
+        !paint.getRasterizer() && paint.getStrokeWidth() == 0) // hairline
+       {
+               SkPoint pts[2];
+               fMapPtProc(*fMatrix, start.fX, start.fY, &pts[0]);
+               fMapPtProc(*fMatrix, stop.fX, stop.fY, &pts[1]);
+
+               if (fBounder && !fBounder->doHairline(pts[0], pts[1], paint, *fClip))
+                       return;
+
+               SkAutoBlitterChoose     blitter(*fDevice, *fMatrix, paint);
+
+               if (paint.isAntiAliasOn())
+                       SkScan::AntiHairLine(pts[0], pts[1], fClip, blitter.get());
+               else
+                       SkScan::HairLine(pts[0], pts[1], fClip, blitter.get());
+       }
+       else
+       {
+               SkPath  path;
+               // temporarily mark the paint as framing
+               SkAutoPaintStyleRestore restore(paint, SkPaint::kStroke_Style);
+
+               path.moveTo(start.fX, start.fY);
+               path.lineTo(stop.fX, stop.fY);
+               this->drawPath(path, paint);
+       }
+}
+
+void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint)
+{
+       SkDEBUGCODE(this->validate();)
+
+       if (fClip->isEmpty() ||
+        (paint.getAlpha() == 0 && paint.getXfermode() == NULL))        // nothing to draw
+        return;
+
+       if (paint.getPathEffect() || paint.getMaskFilter() || paint.getRasterizer() ||
+               !fMatrix->rectStaysRect() || (paint.getStyle() != SkPaint::kFill_Style && (paint.getStrokeWidth() / 2) > 0))
+       {
+               SkPath  tmp;
+               tmp.addRect(rect);
+               tmp.setFillType(SkPath::kWinding_FillType);
+               this->drawPath(tmp, paint);
+               return;
+       }
+
+       SkRect  devRect;
+       fMapPtProc(*fMatrix, rect.fLeft, rect.fTop, (SkPoint*)&devRect.fLeft);
+       fMapPtProc(*fMatrix, rect.fRight, rect.fBottom, (SkPoint*)&devRect.fRight);
+       devRect.sort();
+
+       if (fBounder && !fBounder->doRect(devRect, paint, *fClip))
+               return;
+
+       SkAutoBlitterChoose     blitter(*fDevice, *fMatrix, paint);
+
+       if (paint.getStyle() == SkPaint::kFill_Style)
+               SkScan::FillRect(devRect, fClip, blitter.get());
+       else
+       {
+               if (paint.isAntiAliasOn())
+                       SkScan::AntiHairRect(devRect, fClip, blitter.get());
+               else
+                       SkScan::HairRect(devRect, fClip, blitter.get());
+       }
+}
+
+void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint)
+{
+    if (srcM.fBounds.isEmpty())
+        return;
+
+    SkMask          dstM;
+    const SkMask*   mask = &srcM;
+
+    dstM.fImage = NULL;
+    SkAutoMaskImage ami(&dstM, false);
+
+       if (paint.getMaskFilter() &&
+               paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, NULL))
+       {
+        mask = &dstM;
+       }
+
+       if (fBounder && !fBounder->doIRect(mask->fBounds, *fClip))
+               return;
+
+       SkAutoBlitterChoose     blitter(*fDevice, *fMatrix, paint);
+
+    blitter->blitMaskRegion(*mask, *fClip);
+}
+
+void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& paint, const SkMatrix* prePathMatrix, bool srcPathIsMutable)
+{
+       SkDEBUGCODE(this->validate();)
+
+       if (fClip->isEmpty() ||
+        (paint.getAlpha() == 0 && paint.getXfermode() == NULL))        // nothing to draw
+        return;
+
+    SkPath*         pathPtr = (SkPath*)&origSrcPath;
+    bool            doFill = true;
+    SkPath          tmpPath;
+    SkMatrix        tmpMatrix;
+    const SkMatrix* matrix = fMatrix;
+
+    if (prePathMatrix)
+    {
+        if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style || paint.getRasterizer())
+        {
+            SkPath* result = pathPtr;
+    
+            if (!srcPathIsMutable)
+            {
+                result = &tmpPath;
+                srcPathIsMutable = true;
+            }
+            pathPtr->transform(*prePathMatrix, result);
+            pathPtr = result;
+        }
+        else
+        {
+            tmpMatrix.setConcat(*matrix, *prePathMatrix);
+            matrix = &tmpMatrix;
+        }
+    }
+    // at this point we're done with prePathMatrix
+    SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
+
+    if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style)
+    {
+        doFill = paint.getFillPath(*pathPtr, &tmpPath);
+        pathPtr = &tmpPath;
+    }
+
+    if (paint.getRasterizer())
+    {
+        SkMask  mask;
+        if (paint.getRasterizer()->rasterize(*pathPtr, *matrix, &fClip->getBounds(),
+                                             paint.getMaskFilter(), &mask,
+                                             SkMask::kComputeBoundsAndRenderImage_CreateMode))
+        {
+            this->drawDevMask(mask, paint);
+            SkMask::FreeImage(mask.fImage);
+        }
+        return;
+    }
+
+    // avoid possibly allocating a new path in transform if we can
+       SkPath* devPathPtr = srcPathIsMutable ? pathPtr : &tmpPath;
+
+       // transform the path into device space
+    if (!pathPtr->transform(*matrix, devPathPtr))
+        return;
+
+       SkAutoBlitterChoose     blitter(*fDevice, *fMatrix, paint);
+
+    // how does filterPath() know to fill or hairline the path??? <mrr>
+       if (paint.getMaskFilter() &&
+               paint.getMaskFilter()->filterPath(*devPathPtr, *fMatrix, *fClip, fBounder, blitter.get()))
+       {
+               return; // filterPath() called the blitter, so we're done
+       }
+
+       if (fBounder && !fBounder->doPath(*devPathPtr, paint, *fClip, doFill))
+               return;
+
+       if (doFill)
+       {
+               if (paint.isAntiAliasOn())
+                       SkScan::AntiFillPath(*devPathPtr, fClip, blitter.get());
+               else
+                       SkScan::FillPath(*devPathPtr, fClip, blitter.get());
+       }
+       else    // hairline
+       {
+               if (paint.isAntiAliasOn())
+                       SkScan::AntiHairPath(*devPathPtr, fClip, blitter.get());
+               else
+                       SkScan::HairPath(*devPathPtr, fClip, blitter.get());
+       }
+}
+
+static inline bool just_translate(const SkMatrix& m)
+{
+       return (m.getType() & ~SkMatrix::kTranslate_Mask) == 0;
+}
+
+void SkDraw::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, const SkPaint& paint)
+{
+       SkDEBUGCODE(this->validate();)
+
+       if (fClip->isEmpty() ||
+        bitmap.width() == 0 || bitmap.height() == 0 || bitmap.getConfig() == SkBitmap::kNo_Config ||
+               (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) // nothing to draw
+               return;
+
+       SkAutoPaintStyleRestore restore(paint, SkPaint::kFill_Style);
+
+       SkMatrix matrix = *fMatrix;
+       matrix.preTranslate(x, y);
+
+       if (NULL == paint.getColorFilter() && just_translate(matrix))
+       {
+               int                     ix = SkScalarRound(matrix.getTranslateX());
+               int                     iy = SkScalarRound(matrix.getTranslateY());
+               U32                     storage[kBlitterStorageLongCount];
+               SkBlitter*      blitter = SkBlitter::ChooseSprite(*fDevice, paint, bitmap, ix, iy, storage, sizeof(storage));
+               if (blitter)
+               {
+                       SkAutoTPlacementDelete<SkBlitter>       ad(blitter, storage);
+
+                       SkRect16        ir;
+                       ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
+
+                       if (fBounder && !fBounder->doIRect(ir, *fClip))
+                               return;
+
+                       SkRegion::Cliperator iter(*fClip, ir);
+                       const SkRect16&          cr = iter.rect();
+
+                       for (; !iter.done(); iter.next())
+            {
+                SkASSERT(!cr.isEmpty());
+            #if 0
+                LOGI("blitRect(%d %d %d %d) [%d %d %p]\n", cr.fLeft, cr.fTop, cr.width(), cr.height(),
+                        bitmap.width(), bitmap.height(), bitmap.getPixels());
+            #endif
+                               blitter->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
+            }
+                       return;
+               }
+       }
+
+       SkAutoBitmapShaderInstall       install(bitmap, &paint);
+
+    // save our state
+       const SkMatrix*         saveMatrix = fMatrix;
+       SkMatrix::MapPtProc     saveProc = fMapPtProc;
+
+    // jam in the new temp state
+       fMatrix = &matrix;
+       fMapPtProc = matrix.getMapPtProc();
+
+    // call ourself with a rect
+    {
+        SkRect r;
+        r.set(0, 0, SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
+        // is this ok if paint has a rasterizer? <reed>
+        this->drawRect(r, paint);
+    }
+    
+    // restore our state
+       fMapPtProc = saveProc;
+       fMatrix = saveMatrix;
+}
+
+void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint)
+{
+       SkDEBUGCODE(this->validate();)
+
+    SkRect16    bounds;
+    bounds.set(x, y, x + bitmap.width(), y + bitmap.height());
+
+       if (fClip->quickReject(bounds) ||
+        bitmap.getConfig() == SkBitmap::kNo_Config ||
+               (paint.getAlpha() == 0 && paint.getXfermode() == NULL))
+    {
+               return; // nothing to draw
+    }
+
+       SkAutoPaintStyleRestore restore(paint, SkPaint::kFill_Style);
+
+       if (NULL == paint.getColorFilter())
+       {
+               uint32_t        storage[kBlitterStorageLongCount];
+               SkBlitter*      blitter = SkBlitter::ChooseSprite(*fDevice, paint, bitmap, x, y, storage, sizeof(storage));
+
+               if (blitter)
+               {
+                       SkAutoTPlacementDelete<SkBlitter>       ad(blitter, storage);
+
+                       if (fBounder && !fBounder->doIRect(bounds, *fClip))
+                               return;
+
+                       SkRegion::Cliperator iter(*fClip, bounds);
+                       const SkRect16&          cr = iter.rect();
+
+                       for (; !iter.done(); iter.next())
+            {
+                SkASSERT(!cr.isEmpty());
+                               blitter->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
+            }
+                       return;
+               }
+       }
+
+       SkAutoBitmapShaderInstall       install(bitmap, &paint);
+
+    // save our state
+       const SkMatrix*         saveMatrix = fMatrix;
+       SkMatrix::MapPtProc     saveProc = fMapPtProc;
+    SkMatrix            matrix;
+    SkRect              r;
+
+    // get a scalar version of our rect
+    r.set(bounds);
+
+    // tell the shader our offset
+    matrix.setTranslate(r.fLeft, r.fTop);
+    paint.getShader()->setLocalMatrix(matrix);
+
+    // jam in the new temp state
+    matrix.reset();
+       fMatrix = &matrix;
+       fMapPtProc = matrix.getMapPtProc();
+
+    // call ourself with a rect
+    {
+        // is this OK if paint has a rasterizer? <reed>
+        this->drawRect(r, paint);
+    }
+    
+    // restore our state
+       fMapPtProc = saveProc;
+       fMatrix = saveMatrix;
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+
+#include "SkScalerContext.h"
+#include "SkGlyphCache.h"
+#include "SkUtils.h"
+
+static void measure_text(SkGlyphCache* cache, SkUnicodeWalkerProc textProc, const char text[],
+                         size_t byteLength, SkVector* stopVector)
+{
+       SkFixed         x = 0, y = 0;
+       const char*     stop = text + byteLength;
+
+    while (text < stop)
+    {
+        const SkGlyph& glyph = cache->getMetrics(textProc(&text));
+        x += glyph.fAdvanceX;
+        y += glyph.fAdvanceY;
+    }
+       stopVector->set(SkFixedToScalar(x), SkFixedToScalar(y));
+
+       SkASSERT(text == stop);
+}
+
+static void measure_layout(SkGlyphCache* cache, const SkTextLayout::Rec rec[], int count,
+                           const SkMatrix& matrix, SkVector* stopVector)
+{
+       SkFixed         x = 0, y = 0;
+
+    for (int i = 0; i < count; i++)
+    {
+        // should pass glyphID to the cache, when we have that
+        const SkGlyph& glyph = cache->getMetrics(rec[i].charCode());
+        SkVector    adv;
+        adv.set(rec[i].fDeltaAdvance, 0);
+        matrix.mapVectors(&adv, 1);
+        x += glyph.fAdvanceX + SkScalarToFixed(adv.fX);
+        y += glyph.fAdvanceY + SkScalarToFixed(adv.fY);
+    }
+       stopVector->set(SkFixedToScalar(x), SkFixedToScalar(y));
+}
+
+void SkDraw::drawText_asPaths(SkUnicodeWalkerProc textProc, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint)
+{
+       SkDEBUGCODE(this->validate();)
+
+       SkTextToPathIter        iter(textProc, text, byteLength, paint, true, true);
+
+       SkMatrix        matrix;
+       matrix.setScale(iter.getPathScale(), iter.getPathScale(), 0, 0);
+       matrix.postTranslate(x, y);
+
+       const SkPath* iterPath;
+       SkScalar xpos, prevXPos = 0;
+
+       while ((iterPath = iter.next(&xpos)) != NULL)
+       {
+               matrix.postTranslate(xpos - prevXPos, 0);
+               this->drawPath(*iterPath, iter.getPaint(), &matrix, false);
+               prevXPos = xpos;
+       }
+}
+
+#define kStdStrikeThru_Offset          (-SK_Scalar1 * 6 / 21)
+#define kStdUnderline_Offset           (SK_Scalar1 / 9)
+#define kStdUnderline_Thickness                (SK_Scalar1 / 18)
+
+static void draw_paint_rect(SkDraw* draw, const SkPaint& paint, const SkRect& r, SkScalar textSize)
+{
+       if (paint.getStyle() == SkPaint::kFill_Style)
+               draw->drawRect(r, paint);
+       else
+       {
+               SkPaint p(paint);
+               p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
+               draw->drawRect(r, p);
+       }
+}
+
+static void handle_aftertext(SkDraw* draw, const SkPaint& paint, SkScalar width, const SkPoint& start)
+{
+       U32 flags = paint.getFlags();
+
+       if (flags & (SkPaint::kUnderlineText_Mask | SkPaint::kStrikeThruText_Mask))
+       {
+               SkScalar textSize = paint.getTextSize();
+               SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
+               SkRect   r;
+
+               r.fLeft = start.fX;
+               r.fRight = start.fX + width;
+
+               if (flags & SkPaint::kUnderlineText_Mask)
+               {
+                       SkScalar offset = start.fY + SkScalarMul(textSize, kStdUnderline_Offset);
+                       r.fTop = offset;
+                       r.fBottom = offset + height;
+                       draw_paint_rect(draw, paint, r, textSize);
+               }
+               if (flags & SkPaint::kStrikeThruText_Mask)
+               {
+                       SkScalar offset = start.fY + SkScalarMul(textSize, kStdStrikeThru_Offset);
+                       r.fTop = offset;
+                       r.fBottom = offset + height;
+                       draw_paint_rect(draw, paint, r, textSize);
+               }
+       }
+}
+
+#if defined _WIN32 && _MSC_VER >= 1300 // disable warning : local variable used without having been initialized
+#pragma warning ( push )
+#pragma warning ( disable : 4701 )
+#endif
+
+static inline void draw_one_glyph(const SkGlyph& glyph, int left, int top, SkBounder* bounder,
+                                  const SkRegion& clip, SkBlitter* blitter, SkGlyphCache* cache)
+{
+    SkMask     mask;
+
+    int right  = left + glyph.fWidth;
+    int bottom = top + glyph.fHeight;
+
+    mask.fBounds.set(left, top, right, bottom);
+
+    if (bounder == NULL && clip.quickContains(left, top, right, bottom))
+    {
+        uint8_t* aa = (uint8_t*)glyph.fImage;                          
+        if (aa == NULL)
+            aa = (uint8_t*)cache->findImage(glyph.fCharCode);
+
+        if (aa)
+        {
+            mask.fRowBytes = glyph.fRowBytes;
+            mask.fFormat = glyph.fMaskFormat;
+            mask.fImage = aa;
+            blitter->blitMask(mask, mask.fBounds);
+        }
+    }
+    else
+    {
+        SkRegion::Cliperator clipper(clip, mask.fBounds);
+        if (!clipper.done())
+        {
+            const SkRect16&    cr = clipper.rect();
+            const uint8_t*     aa = (const uint8_t*)glyph.fImage;
+            if (NULL == aa)
+                aa = (const uint8_t*)cache->findImage(glyph.fCharCode);
+
+            if (aa && (bounder == NULL || bounder->doIRect(cr, clip)))
+            {
+                mask.fRowBytes = glyph.fRowBytes;
+                mask.fFormat = glyph.fMaskFormat;
+                mask.fImage = (uint8_t*)aa;
+                do {
+                    blitter->blitMask(mask, cr);
+                    clipper.next();
+                } while (!clipper.done());
+            }
+        }
+    }
+}
+
+void SkDraw::drawText(SkUnicodeWalkerProc textProc, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint)
+{
+       SkASSERT(byteLength == 0 || text != NULL);
+
+       SkDEBUGCODE(this->validate();)
+
+       if (text == NULL || byteLength == 0 ||
+        fClip->isEmpty() ||
+        (paint.getAlpha() == 0 && paint.getXfermode() == NULL))        // nothing to draw
+               return;
+
+    SkASSERT(textProc);
+
+       SkScalar        underlineWidth = 0;
+       SkPoint         underlineStart;
+
+       if (paint.getFlags() & (SkPaint::kUnderlineText_Mask | SkPaint::kStrikeThruText_Mask))
+       {
+               underlineWidth = paint.privateMeasureText(textProc, text, byteLength, NULL, NULL);
+
+               SkScalar offsetX = 0;
+               if (paint.getTextAlign() == SkPaint::kCenter_Align)
+                       offsetX = SkScalarHalf(underlineWidth);
+               else if (paint.getTextAlign() == SkPaint::kRight_Align)
+                       offsetX = underlineWidth;
+
+               underlineStart.set(x - offsetX, y);
+       }
+
+       if (paint.isLinearTextOn() ||
+               (fMatrix->getType() & SkMatrix::kPerspective_Mask))
+       {
+               this->drawText_asPaths(textProc, text, byteLength, x, y, paint);
+               handle_aftertext(this, paint, underlineWidth, underlineStart);
+               return;
+       }
+
+       SkAutoGlyphCache        autoCache(paint, fMatrix);
+       SkGlyphCache*           cache = autoCache.getCache();
+       SkAutoBlitterChoose     blitter(*fDevice, *fMatrix, paint);
+    SkTextLayout*       layout = paint.getTextLayout();
+    
+       // transform our starting point
+       {
+               SkPoint loc;
+               fMapPtProc(*fMatrix, x, y, &loc);
+               x = loc.fX;
+               y = loc.fY;
+       }
+
+       if (paint.getTextAlign() != SkPaint::kLeft_Align)       // need to measure first
+       {
+               SkVector        stop;
+
+        if (layout)
+        {
+            SkAutoSTMalloc<32, SkTextLayout::Rec>   storage(byteLength);
+            SkTextLayout::Rec*                      rec = storage.get();
+
+            int count = layout->layout(paint, text, byteLength, textProc, rec);
+            measure_layout(cache, rec, count, *fMatrix, &stop);
+        }
+        else
+            measure_text(cache, textProc, text, byteLength, &stop);
+
+               SkScalar        stopX = stop.fX;
+               SkScalar        stopY = stop.fY;
+
+               if (paint.getTextAlign() == SkPaint::kCenter_Align)
+               {
+                       stopX = SkScalarHalf(stopX);
+                       stopY = SkScalarHalf(stopY);
+               }
+               x -= stopX;
+               y -= stopY;
+       }
+    
+       // add a half now so we can trunc rather than round in the loop
+       SkFixed fx = SkScalarToFixed(x) + SK_FixedHalf;
+       SkFixed fy = SkScalarToFixed(y) + SK_FixedHalf;
+       const char*     stop = text + byteLength;
+       const SkRegion& clip = *fClip;
+    SkBounder* bounder = fBounder;
+    SkBlitter* blit = blitter.get();
+
+    if (layout)
+    {
+        SkAutoSTMalloc<32, SkTextLayout::Rec>   storage(byteLength);
+        SkTextLayout::Rec*                      rec = storage.get();
+
+        int count = layout->layout(paint, text, byteLength, textProc, rec);
+        for (int i = 0; i < count; i++)
+        {
+            // should pass rec[i].glyphID when we have it
+            const SkGlyph&  glyph = cache->getMetrics(rec[i].charCode());
+            SkVector        advance;
+            
+            advance.set(rec[i].fDeltaAdvance, 0);
+            fMatrix->mapVectors(&advance, 1);
+            SkFixed dx = SkScalarToFixed(advance.fX);
+            SkFixed dy = SkScalarToFixed(advance.fY);
+            
+            if (glyph.fWidth) {
+                draw_one_glyph( glyph,
+                                SkFixedFloor(fx + (dx >> 1)) + glyph.fLeft,
+                                SkFixedFloor(fy + (dy >> 1)) + glyph.fTop,
+                                fBounder, *fClip, blit, cache);
+            }
+            fx += glyph.fAdvanceX + dx;
+            fy += glyph.fAdvanceY + dy;
+        }
+    }
+    else    // no layout object
+    {        
+        while (text < stop)
+        {
+            const SkGlyph& glyph = cache->getMetrics(textProc(&text));
+
+            if (glyph.fWidth) {
+                draw_one_glyph( glyph,
+                                SkFixedFloor(fx) + glyph.fLeft, SkFixedFloor(fy) + glyph.fTop,
+                                bounder, clip, blit, cache);
+            }
+            fx += glyph.fAdvanceX;
+            fy += glyph.fAdvanceY;
+        }
+       }
+
+       if (underlineWidth)
+       {
+               autoCache.release();    // release this now to free up the RAM
+               handle_aftertext(this, paint, underlineWidth, underlineStart);
+       }
+}
+
+typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkPoint16*);
+
+static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkPoint16* dst)
+{
+    dst->set(SkScalarRound(loc.fX) + glyph.fLeft,
+             SkScalarRound(loc.fY) + glyph.fTop);
+}
+
+static void centerAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkPoint16* dst)
+{
+    dst->set(SkFixedRound(SkScalarToFixed(loc.fX) - (glyph.fAdvanceX >> 1)) + glyph.fLeft,
+             SkFixedRound(SkScalarToFixed(loc.fY) - (glyph.fAdvanceY >> 1)) + glyph.fTop);
+}
+
+static void rightAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkPoint16* dst)
+{
+    dst->set(SkFixedRound(SkScalarToFixed(loc.fX) - glyph.fAdvanceX) + glyph.fLeft,
+             SkFixedRound(SkScalarToFixed(loc.fY) - glyph.fAdvanceY) + glyph.fTop);
+}
+
+static AlignProc pick_align_proc(SkPaint::Align align)
+{
+    static const AlignProc gProcs[] = { leftAlignProc, centerAlignProc, rightAlignProc };
+    
+    SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs));
+
+    return gProcs[align];
+}
+
+void SkDraw::drawPosText(SkUnicodeWalkerProc textProc, const char text[], size_t byteLength,
+                         const SkPoint pos[], const SkPaint& paint)
+{
+       SkASSERT(byteLength == 0 || text != NULL);
+
+       SkDEBUGCODE(this->validate();)
+
+       if (text == NULL || byteLength == 0 ||
+        fClip->isEmpty() ||
+        (paint.getAlpha() == 0 && paint.getXfermode() == NULL))        // nothing to draw
+               return;
+
+    SkASSERT(textProc);
+
+       if (paint.isLinearTextOn() ||
+               (fMatrix->getType() & SkMatrix::kPerspective_Mask))
+       {
+//             this->drawText_asPaths(textProc, text, byteLength, x, y, paint);
+               return;
+       }
+
+       SkAutoGlyphCache        autoCache(paint, fMatrix);
+       SkGlyphCache*           cache = autoCache.getCache();
+       SkAutoBlitterChoose     blitter(*fDevice, *fMatrix, paint);
+    
+       const char*         stop = text + byteLength;
+       const SkRegion&     clip = *fClip;
+    SkBounder*          bounder = fBounder;
+    SkBlitter*          blit = blitter.get();
+    SkMatrix::MapPtProc mapPtProc = fMapPtProc;
+    const SkMatrix&     matrix = *fMatrix;
+    AlignProc           alignProc = pick_align_proc(paint.getTextAlign());
+
+    while (text < stop)
+    {
+        const SkGlyph& glyph = cache->getMetrics(textProc(&text));
+
+        if (glyph.fWidth)
+        {
+            SkPoint loc;
+            mapPtProc(matrix, pos->fX, pos->fY, &loc);
+
+            SkPoint16   devLoc;
+            alignProc(loc, glyph, &devLoc);
+
+            draw_one_glyph( glyph, devLoc.fX, devLoc.fY,
+                            bounder, clip, blit, cache);
+        }
+        pos += 1;
+    }
+}
+
+#if defined _WIN32 && _MSC_VER >= 1300
+#pragma warning ( pop )
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkPathMeasure.h"
+
+static void morphpoints(SkPoint dst[], const SkPoint src[], int count,
+                                               SkPathMeasure& meas, SkScalar offset, SkScalar scale)
+{
+       for (int i = 0; i < count; i++)
+       {
+               SkPoint pos;
+               SkVector tangent;
+
+               SkScalar sx = SkScalarMul(src[i].fX, scale) + offset;
+               SkScalar sy = SkScalarMul(src[i].fY, scale);
+
+               meas.getPosTan(sx, &pos, &tangent);
+
+               SkMatrix        matrix;
+               SkPoint         pt;
+
+               pt.set(sx, sy);
+               matrix.setSinCos(tangent.fY, tangent.fX, 0, 0);
+               matrix.preTranslate(-sx, 0);
+               matrix.postTranslate(pos.fX, pos.fY);
+               matrix.mapPoints(&dst[i], &pt, 1);
+       }
+}
+
+/*     TODO
+
+       Need differentially more subdivisions when the follow-path is curvy. Not sure how to
+       determine that, but we need it. I guess a cheap answer is let the caller tell us,
+       but that seems like a cop-out. Another answer is to get Rob Johnson to figure it out.
+*/
+static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas,
+                                         SkScalar offset, SkScalar scale)
+{
+       SkPath::Iter    iter(src, false);
+       SkPoint                 srcP[4], dstP[3];
+       SkPath::Verb    verb;
+
+       while ((verb = iter.next(srcP)) != SkPath::kDone_Verb)
+       {
+               switch (verb) {
+               case SkPath::kMove_Verb:
+                       morphpoints(dstP, srcP, 1, meas, offset, scale);
+                       dst->moveTo(dstP[0]);
+                       break;
+               case SkPath::kLine_Verb:
+                       srcP[2] = srcP[1];
+                       srcP[1].set(SkScalarAve(srcP[0].fX, srcP[2].fX),
+                                               SkScalarAve(srcP[0].fY, srcP[2].fY));
+                       // fall through to quad
+               case SkPath::kQuad_Verb:
+                       morphpoints(dstP, &srcP[1], 2, meas, offset, scale);
+                       dst->quadTo(dstP[0], dstP[1]);
+                       break;
+               case SkPath::kCubic_Verb:
+                       morphpoints(dstP, &srcP[1], 3, meas, offset, scale);
+                       dst->cubicTo(dstP[0], dstP[1], dstP[2]);
+                       break;
+               case SkPath::kClose_Verb:
+                       dst->close();
+                       break;
+               default:
+                       SkASSERT(!"unknown verb");
+                       break;
+               }
+       }
+}
+
+void SkDraw::drawTextOnPath(SkUnicodeWalkerProc textProc, const char text[], size_t byteLength,
+                            const SkPath& follow, SkScalar offset, const SkPaint& paint)
+{
+       SkASSERT(byteLength == 0 || text != NULL);
+
+       if (text == NULL || byteLength == 0 ||
+        fClip->getBounds().isEmpty() ||
+        (paint.getAlpha() == 0 && paint.getXfermode() == NULL))        // nothing to draw
+               return;
+
+       SkTextToPathIter        iter(textProc, text, byteLength, paint, true, true);
+       SkPathMeasure           meas(follow, false);
+
+       if (paint.getTextAlign() != SkPaint::kLeft_Align)       // need to measure first
+       {
+               SkScalar pathLen = meas.getLength();
+               if (paint.getTextAlign() == SkPaint::kCenter_Align)
+                       pathLen = SkScalarHalf(pathLen);
+               offset += pathLen;
+       }
+
+       const SkPath*   iterPath;
+       SkScalar                xpos;
+       while ((iterPath = iter.next(&xpos)) != NULL)
+       {
+               SkPath  tmp;
+               morphpath(&tmp, *iterPath, meas, offset + xpos, iter.getPathScale());
+               this->drawPath(tmp, iter.getPaint());
+       }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+void SkDraw::validate() const
+{
+       SkASSERT(fDevice != NULL);
+       SkASSERT(fMatrix != NULL);
+       SkASSERT(fClip != NULL);
+
+       const SkRect16& cr = fClip->getBounds();
+       SkRect16                br;
+
+       br.set(0, 0, fDevice->width(), fDevice->height());
+       SkASSERT(br.contains(cr));
+}
+
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+bool SkBounder::doIRect(const SkRect16& r, const SkRegion& clip)
+{
+       SkRect16        rr;
+       return rr.intersect(clip.getBounds(), r) && this->onIRect(rr);
+}
+
+bool SkBounder::doHairline(const SkPoint& pt0, const SkPoint& pt1, const SkPaint& paint, const SkRegion& clip)
+{
+       SkRect16        r;
+       SkScalar        v0, v1;
+
+       v0 = pt0.fX;
+       v1 = pt1.fX;
+       if (v0 > v1)
+               SkTSwap<SkScalar>(v0, v1);
+       r.fLeft         = SkToS16(SkScalarFloor(v0));
+       r.fRight        = SkToS16(SkScalarCeil(v1));
+
+       v0 = pt0.fY;
+       v1 = pt1.fY;
+       if (v0 > v1)
+               SkTSwap<SkScalar>(v0, v1);
+       r.fTop          = SkToS16(SkScalarFloor(v0));
+       r.fBottom       = SkToS16(SkScalarCeil(v1));
+
+       if (paint.isAntiAliasOn())
+               r.inset(-1, -1);
+
+       return this->doIRect(r, clip);
+}
+
+bool SkBounder::doRect(const SkRect& rect, const SkPaint& paint, const SkRegion& clip)
+{
+       SkRect16        r;
+
+       if (paint.getStyle() == SkPaint::kFill_Style)
+               rect.round(&r);
+       else
+       {
+               int     rad = -1;
+               rect.roundOut(&r);
+               if (paint.isAntiAliasOn())
+                       rad = -2;
+               r.inset(rad, rad);
+       }
+       return this->doIRect(r, clip);
+}
+
+bool SkBounder::doPath(const SkPath& path, const SkPaint& paint, const SkRegion& clip, bool doFill)
+{
+       SkRect          bounds;
+       SkRect16        r;
+
+       path.computeBounds(&bounds, SkPath::kFast_BoundsType);
+
+       if (doFill)
+               bounds.round(&r);
+       else    // hairline
+               bounds.roundOut(&r);
+
+       if (paint.isAntiAliasOn())
+               r.inset(-1, -1);
+
+       return this->doIRect(r, clip);
+}
+
+void SkBounder::commit()
+{
+       // override in subclass
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkPath.h"
+#include "SkDraw.h"
+#include "SkRegion.h"
+#include "SkBlitter.h"
+
+static bool compute_bounds(const SkPath& devPath, const SkRect16* clipBounds,
+                           SkMaskFilter* filter, const SkMatrix* filterMatrix,
+                           SkRect16* bounds)
+{
+    if (devPath.isEmpty())
+        return false;
+
+    SkPoint16   margin;
+    margin.set(0, 0);
+
+    //  init our bounds from the path
+    {
+        SkRect      pathBounds;
+        devPath.computeBounds(&pathBounds, SkPath::kExact_BoundsType);
+        pathBounds.inset(-SK_ScalarHalf, -SK_ScalarHalf);
+        pathBounds.roundOut(bounds);
+    }
+    
+       if (filter)
+    {
+        SkASSERT(filterMatrix);
+        
+        SkMask  srcM, dstM;
+        
+        srcM.fBounds = *bounds;
+        srcM.fFormat = SkMask::kA8_Format;
+        srcM.fImage = NULL;
+        if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin))
+            return false;
+        
+        *bounds = dstM.fBounds;
+    }
+
+    if (clipBounds && !SkRect16::Intersects(*clipBounds, *bounds))
+        return false;
+    
+       // (possibly) trim the srcM bounds to reflect the clip
+       // (plus whatever slop the filter needs)
+       if (clipBounds && !clipBounds->contains(*bounds))
+       {
+        SkRect16 tmp = *bounds;
+               (void)tmp.intersect(*clipBounds);
+               tmp.inset(-margin.fX, -margin.fY);
+               (void)bounds->intersect(tmp);
+       }
+
+    return true;
+}
+
+static void draw_into_mask(const SkMask& mask, const SkPath& devPath)
+{
+    SkBitmap   bm;
+    SkDraw             draw;
+    SkRegion   clipRgn;
+    SkMatrix   matrix;
+    SkPaint            paint;
+
+    bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), mask.fBounds.height(), mask.fRowBytes);
+    bm.setPixels(mask.fImage);
+
+    clipRgn.setRect(0, 0, mask.fBounds.width(), mask.fBounds.height());
+    matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
+                        -SkIntToScalar(mask.fBounds.fTop));
+
+    draw.fDevice    = &bm;
+    draw.fClip      = &clipRgn;
+    draw.fMatrix    = &matrix;
+    draw.fMapPtProc = matrix.getMapPtProc();
+    draw.fBounder   = NULL;
+    paint.setAntiAliasOn(true);
+    draw.drawPath(devPath, paint);
+}
+
+bool SkDraw::DrawToMask(const SkPath& devPath, const SkRect16* clipBounds,
+                        SkMaskFilter* filter, const SkMatrix* filterMatrix,
+                        SkMask* mask, SkMask::CreateMode mode)
+{
+    if (SkMask::kJustRenderImage_CreateMode != mode)
+    {
+        if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds))
+            return false;
+    }
+    
+    if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode)
+    {
+        mask->fFormat = SkMask::kA8_Format;
+        mask->fRowBytes = mask->fBounds.width();
+        mask->fImage = SkMask::AllocImage(mask->computeImageSize());
+        memset(mask->fImage, 0, mask->computeImageSize());
+    }
+
+    if (SkMask::kJustComputeBounds_CreateMode != mode)
+        draw_into_mask(*mask, devPath);
+
+    return true;
+}
+
diff --git a/libs/graphics/sgl/SkDraw.h b/libs/graphics/sgl/SkDraw.h
new file mode 100644 (file)
index 0000000..488fa79
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef SkDraw_DEFINED
+#define SkDraw_DEFINED
+
+#include "SkBitmap.h"
+#include "SkMask.h"
+#include "SkMatrix.h"
+#include "SkPaint.h"
+#include "SkRect.h"
+
+class SkBounder;
+class SkCanvas;
+class SkPath;
+class SkRegion;
+
+class SkDraw {
+public:
+       SkDraw() {}
+       SkDraw(const SkCanvas&);
+
+       void    drawPaint(const SkPaint&);
+       void    drawLine(const SkPoint& start, const SkPoint& stop, const SkPaint&);
+       void    drawRect(const SkRect&, const SkPaint&);
+       /*      To save on mallocs, we allow a flag that tells us that srcPath is mutable, so that we don't have to
+               make copies of it as we transform it.
+       */
+       void    drawPath(const SkPath& srcPath, const SkPaint&, const SkMatrix* prePathMatrix, bool srcPathIsMutable);
+       void    drawBitmap(const SkBitmap&, SkScalar x, SkScalar y, const SkPaint&);
+    void    drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint);
+       void    drawText(SkUnicodeWalkerProc, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint);
+       void    drawPosText(SkUnicodeWalkerProc, const char text[], size_t byteLength, const SkPoint pos[], const SkPaint& paint);
+       void    drawTextOnPath(SkUnicodeWalkerProc, const char text[], size_t byteLength, const SkPath& follow,
+                                                       SkScalar offset, const SkPaint& paint);
+
+       void    drawPath(const SkPath& src, const SkPaint& paint)
+    {
+        this->drawPath(src, paint, NULL, false);
+    }
+
+    /** Helper function that creates a mask from a path and an optional maskfilter.
+        Note however, that the resulting mask will not have been actually filtered,
+        that must be done afterwards (by calling filterMask). The maskfilter is provided
+        solely to assist in computing the mask's bounds (if the mode requests that).
+    */
+    static bool DrawToMask(const SkPath& devPath, const SkRect16* clipBounds,
+                           SkMaskFilter* filter, const SkMatrix* filterMatrix,
+                           SkMask* mask, SkMask::CreateMode mode);
+
+private:
+       void    drawText_asPaths(SkUnicodeWalkerProc, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkPaint&);
+       void    drawDevMask(const SkMask& mask, const SkPaint&);
+
+#ifdef SK_DEBUG
+       void    validate() const;
+#endif
+
+public:
+       const SkBitmap* fDevice;                // required
+       const SkMatrix* fMatrix;                // required
+       const SkRegion* fClip;                  // required
+       SkMatrix::MapPtProc     fMapPtProc;     // required
+       SkBounder*              fBounder;               // optional
+};
+
+class SkTextToPathIter {
+public:
+       SkTextToPathIter(SkUnicodeWalkerProc, const char text[], size_t length, const SkPaint&,
+                                        bool applyStrokeAndPathEffects, bool forceLinearTextOn);
+       ~SkTextToPathIter();
+
+       const SkPaint&  getPaint() const { return fPaint; }
+       SkScalar                getPathScale() const { return fScale; }
+
+       const SkPath*   next(SkScalar* xpos);   //!< returns nil when there are no more paths
+
+private:
+       SkGlyphCache*   fCache;
+       SkPaint                 fPaint;
+       SkScalar                fScale, fPrevAdvance;
+       const char*             fText;
+       const char*             fStop;
+    SkUnicodeWalkerProc fTextProc;
+
+       const SkPath*   fPath;          // returned in next
+       SkScalar                fXPos;          // accumulated xpos, returned in next
+};
+
+#endif
+
+
diff --git a/libs/graphics/sgl/SkEdge.cpp b/libs/graphics/sgl/SkEdge.cpp
new file mode 100644 (file)
index 0000000..d5e5590
--- /dev/null
@@ -0,0 +1,429 @@
+#include "SkEdge.h"
+#include "SkFDot6.h"
+
+/*
+       In setLine, setQuadratic, setCubic, the first thing we do is to convert
+       the points into FDot6. This is modulated by the shift parameter, which
+       will either be 0, or something like 2 for antialiasing.
+
+       In the float case, we want to turn the float into .6 by saying pt * 64,
+       or pt * 256 for antialiasing. This is implemented as 1 << (shift + 6).
+
+       In the fixed case, we want to turn the fixed into .6 by saying pt >> 10,
+       or pt >> 8 for antialiasing. This is implemented as pt >> (10 - shift).
+*/
+
+/////////////////////////////////////////////////////////////////////////
+
+int SkEdge::setLine(const SkPoint pts[2], const SkRect16* clip, int shift)
+{
+       SkFDot6 x0, y0, x1, y1;
+
+       {
+#ifdef SK_SCALAR_IS_FLOAT
+               float scale = float(1 << (shift + 6));
+               x0 = int(pts[0].fX * scale);
+               y0 = int(pts[0].fY * scale);
+               x1 = int(pts[1].fX * scale);
+               y1 = int(pts[1].fY * scale);
+#else
+               shift = 10 - shift;
+               x0 = pts[0].fX >> shift;
+               y0 = pts[0].fY >> shift;
+               x1 = pts[1].fX >> shift;
+               y1 = pts[1].fY >> shift;
+#endif
+       }
+
+       int             winding = 1;
+
+       if (y0 > y1)
+       {
+               SkTSwap(x0, x1);
+               SkTSwap(y0, y1);
+               winding = -1;
+       }
+
+       int     top = SkFDot6Round(y0);
+       int     bot = SkFDot6Round(y1);
+
+       // are we a zero-height line?
+       if (top == bot)
+               return 0;
+
+       // are we completely above or below the clip?
+       if (clip && (top >= clip->fBottom || bot <= clip->fTop))
+               return 0;
+
+       SkFixed slope = SkFDot6Div(x1 - x0, y1 - y0);
+
+       fX                      = SkFDot6ToFixed(x0 + SkFixedMul(slope, (32 - y0) & 63));       // + SK_Fixed1/2
+       fDX                     = slope;
+       fFirstY         = SkToS16(top);
+       fLastY          = SkToS16(bot - 1);
+       fCurveCount     = 0;
+       fWinding        = SkToS8(winding);
+       fCurveShift     = 0;
+
+       if (clip)
+               this->chopLineWithClip(*clip);
+       return 1;
+}
+
+// called from a curve subclass
+int SkEdge::updateLine(SkFixed x0, SkFixed y0, SkFixed x1, SkFixed y1)
+{
+       SkASSERT(fWinding == 1 || fWinding == -1);
+       SkASSERT(fCurveCount != 0);
+       SkASSERT(fCurveShift != 0);
+
+       y0 >>= 10;
+       y1 >>= 10;
+
+       SkASSERT(y0 <= y1);
+
+       int     top = SkFDot6Round(y0);
+       int     bot = SkFDot6Round(y1);
+
+//     SkASSERT(top >= fFirstY);
+
+       // are we a zero-height line?
+       if (top == bot)
+               return 0;
+
+       x0 >>= 10;
+       x1 >>= 10;
+
+       SkFixed slope = SkFDot6Div(x1 - x0, y1 - y0);
+
+       fX                      = SkFDot6ToFixed(x0 + SkFixedMul(slope, (32 - y0) & 63));       // + SK_Fixed1/2
+       fDX                     = slope;
+       fFirstY         = SkToS16(top);
+       fLastY          = SkToS16(bot - 1);
+
+       return 1;
+}
+
+void SkEdge::chopLineWithClip(const SkRect16& clip)
+{
+       int     top = fFirstY;
+
+       SkASSERT(top < clip.fBottom);
+
+       // clip the line to the top
+       if (top < clip.fTop)
+       {
+               SkASSERT(fLastY >= clip.fTop);
+               fX += fDX * (clip.fTop - top);
+               fFirstY = clip.fTop;
+       }
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+static inline SkFDot6 cheap_distance(SkFDot6 dx, SkFDot6 dy)
+{
+       dx = SkAbs32(dx);
+       dy = SkAbs32(dy);
+       // return max + min/2
+       if (dx > dy)
+               dx += dy >> 1;
+       else
+               dx = dy + (dx >> 1);
+       return dx;
+}
+
+static inline int diff_to_shift(SkFDot6 dx, SkFDot6 dy)
+{
+       // cheap calc of distance from center of p0-p2 to the center of the curve
+       SkFDot6 dist = cheap_distance(dx, dy);
+
+       // shift down dist (it is currently in dot6)
+       // down by 5 should give us 1/2 pixel accuracy (assuming our dist is accurate...)
+       // this is chosen by heuristic: make it as big as possible (to minimize segments)
+       // ... but small enough so that our curves still look smooth
+       dist >>= 5;
+
+       // each subdivision (shift value) cuts this dist (error) by 1/4
+       return (32 - SkCLZ(dist)) >> 1;
+}
+
+int SkQuadraticEdge::setQuadratic(const SkPoint pts[3], const SkRect16* clip, int shift)
+{
+       SkFDot6 x0, y0, x1, y1, x2, y2;
+
+       {
+#ifdef SK_SCALAR_IS_FLOAT
+               float scale = float(1 << (shift + 6));
+               x0 = int(pts[0].fX * scale);
+               y0 = int(pts[0].fY * scale);
+               x1 = int(pts[1].fX * scale);
+               y1 = int(pts[1].fY * scale);
+               x2 = int(pts[2].fX * scale);
+               y2 = int(pts[2].fY * scale);
+#else
+               shift = 10 - shift;
+               x0 = pts[0].fX >> shift;
+               y0 = pts[0].fY >> shift;
+               x1 = pts[1].fX >> shift;
+               y1 = pts[1].fY >> shift;
+               x2 = pts[2].fX >> shift;
+               y2 = pts[2].fY >> shift;
+#endif
+       }
+
+       int     winding = 1;
+       if (y0 > y2)
+       {
+               SkTSwap(x0, x2);
+               SkTSwap(y0, y2);
+               winding = -1;
+       }
+       SkASSERT(y0 <= y1 && y1 <= y2);
+
+       int     top = SkFDot6Round(y0);
+       int     bot = SkFDot6Round(y2);
+
+       // are we a zero-height quad (line)?
+       if (top == bot)
+               return 0;
+       // are we completely above or below the clip?
+       if (clip && (top >= clip->fBottom || bot <= clip->fTop))
+               return 0;
+
+       // compute number of steps needed (1 << shift)
+       {
+               SkFDot6 dx = ((x1 << 1) - x0 - x2) >> 2;
+               SkFDot6 dy = ((y1 << 1) - y0 - y2) >> 2;
+               shift = diff_to_shift(dx, dy);
+       }
+       // need at least 1 subdivision for our bias trick
+       if (shift == 0)
+               shift = 1;
+
+       fWinding        = SkToS8(winding);
+       fCurveShift     = SkToU8(shift);
+       fCurveCount     = SkToS16(1 << shift);
+
+       SkFixed A = SkFDot6ToFixed(x0 - x1 - x1 + x2);
+       SkFixed B = SkFDot6ToFixed(x1 - x0 + x1 - x0);
+
+       fQx             = SkFDot6ToFixed(x0);
+       fQDx    = B + (A >> shift);             // biased by shift
+       fQDDx   = A >> (shift - 1);             // biased by shift
+
+       A = SkFDot6ToFixed(y0 - y1 - y1 + y2);
+       B = SkFDot6ToFixed(y1 - y0 + y1 - y0);
+
+       fQy             = SkFDot6ToFixed(y0);
+       fQDy    = B + (A >> shift);             // biased by shift
+       fQDDy   = A >> (shift - 1);             // biased by shift
+
+       fQLastX = SkFDot6ToFixed(x2);
+       fQLastY = SkFDot6ToFixed(y2);
+
+       if (clip)
+       {
+               do {
+                       for (;!this->updateQuadratic();)
+                               ;
+               } while (!this->intersectsClip(*clip));
+               this->chopLineWithClip(*clip);
+               return 1;
+       }
+       return this->updateQuadratic();
+}
+
+int SkQuadraticEdge::updateQuadratic()
+{
+       int             success;
+       int             count = fCurveCount;
+       SkFixed oldx = fQx;
+       SkFixed oldy = fQy;
+       SkFixed newx, newy;
+       int             shift = fCurveShift;
+
+       SkASSERT(count > 0);
+
+       do {
+               if (--count > 0)
+               {
+                       newx    = oldx + (fQDx >> shift);
+                       fQDx    += fQDDx;
+                       newy    = oldy + (fQDy >> shift);
+                       fQDy    += fQDDy;
+               }
+               else    // last segment
+               {
+                       newx    = fQLastX;
+                       newy    = fQLastY;
+               }
+               success = this->updateLine(oldx, oldy, newx, newy);
+               oldx = newx;
+               oldy = newy;
+       } while (count > 0 && !success);
+
+       fQx                     = newx;
+       fQy                     = newy;
+       fCurveCount = SkToS16(count);
+       return success;
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+/*     f(1/3) = (8a + 12b + 6c + d) / 27
+       f(2/3) = (a + 6b + 12c + 8d) / 27
+
+       f(1/3)-b = (8a - 15b + 6c + d) / 27
+       f(2/3)-c = (a + 6b - 15c + 8d) / 27
+
+       use 16/512 to approximate 1/27
+*/
+static SkFDot6 cubic_delta_from_line(SkFDot6 a, SkFDot6 b, SkFDot6 c, SkFDot6 d)
+{
+       SkFDot6 oneThird = ((a << 3) - ((b << 4) - b) + 6*c + d) * 19 >> 9;
+       SkFDot6 twoThird = (a + 6*b - ((c << 4) - c) + (d << 3)) * 19 >> 9;
+
+       return SkMax32(SkAbs32(oneThird), SkAbs32(twoThird));
+}
+
+int SkCubicEdge::setCubic(const SkPoint pts[4], const SkRect16* clip, int shift)
+{
+       SkFDot6 x0, y0, x1, y1, x2, y2, x3, y3;
+
+       {
+#ifdef SK_SCALAR_IS_FLOAT
+               float scale = float(1 << (shift + 6));
+               x0 = int(pts[0].fX * scale);
+               y0 = int(pts[0].fY * scale);
+               x1 = int(pts[1].fX * scale);
+               y1 = int(pts[1].fY * scale);
+               x2 = int(pts[2].fX * scale);
+               y2 = int(pts[2].fY * scale);
+               x3 = int(pts[3].fX * scale);
+               y3 = int(pts[3].fY * scale);
+#else
+               shift = 10 - shift;
+               x0 = pts[0].fX >> shift;
+               y0 = pts[0].fY >> shift;
+               x1 = pts[1].fX >> shift;
+               y1 = pts[1].fY >> shift;
+               x2 = pts[2].fX >> shift;
+               y2 = pts[2].fY >> shift;
+               x3 = pts[3].fX >> shift;
+               y3 = pts[3].fY >> shift;
+#endif
+       }
+
+       int     winding = 1;
+       if (y0 > y3)
+       {
+               SkTSwap(x0, x3);
+               SkTSwap(x1, x2);
+               SkTSwap(y0, y3);
+               SkTSwap(y1, y2);
+               winding = -1;
+       }
+
+       int     top = SkFDot6Round(y0);
+       int     bot = SkFDot6Round(y3);
+
+       // are we a zero-height cubic (line)?
+       if (top == bot)
+               return 0;
+
+       // are we completely above or below the clip?
+       if (clip && (top >= clip->fBottom || bot <= clip->fTop))
+               return 0;
+
+       // compute number of steps needed (1 << shift)
+       {
+               // Can't use (center of curve - center of baseline), since center-of-curve
+               // need not be the max delta from the baseline (it could even be coincident)
+               // so we try just looking at the two off-curve points
+               SkFDot6 dx = cubic_delta_from_line(x0, x1, x2, x3);
+               SkFDot6 dy = cubic_delta_from_line(y0, y1, y2, y3);
+               // add 1 (by observation)
+               shift = diff_to_shift(dx, dy) + 1;
+       }
+       // need at least 1 subdivision for our bias trick
+       SkASSERT(shift > 0);
+
+       fWinding        = SkToS8(winding);
+       fCurveShift     = SkToU8(shift);
+       fCurveCount     = SkToS16(-1 << shift);
+
+       SkFixed B = SkFDot6ToFixed(3 * (x1 - x0));
+       SkFixed C = SkFDot6ToFixed(3 * (x0 - x1 - x1 + x2));
+       SkFixed D = SkFDot6ToFixed(x3 + 3 * (x1 - x2) - x0);
+
+       fCx             = SkFDot6ToFixed(x0);
+       fCDx    = B + (C >> shift) + (D >> 2*shift);    // biased by shift
+       fCDDx   = 2*C + (3*D >> (shift - 1));                   // biased by 2*shift
+       fCDDDx  = 3*D >> (shift - 1);                                   // biased by 2*shift
+
+       B = SkFDot6ToFixed(3 * (y1 - y0));
+       C = SkFDot6ToFixed(3 * (y0 - y1 - y1 + y2));
+       D = SkFDot6ToFixed(y3 + 3 * (y1 - y2) - y0);
+
+       fCy             = SkFDot6ToFixed(y0);
+       fCDy    = B + (C >> shift) + (D >> 2*shift);    // biased by shift
+       fCDDy   = 2*C + (3*D >> (shift - 1));                   // biased by 2*shift
+       fCDDDy  = 3*D >> (shift - 1);                                   // biased by 2*shift
+
+       fCLastX = SkFDot6ToFixed(x3);
+       fCLastY = SkFDot6ToFixed(y3);
+
+       if (clip)
+       {
+               do {
+                       for (;!this->updateCubic();)
+                               ;
+               } while (!this->intersectsClip(*clip));
+               this->chopLineWithClip(*clip);
+               return 1;
+       }
+       return this->updateCubic();
+}
+
+int SkCubicEdge::updateCubic()
+{
+       int             success;
+       int             count = fCurveCount;
+       SkFixed oldx = fCx;
+       SkFixed oldy = fCy;
+       SkFixed newx, newy;
+       int             shift = fCurveShift;
+
+       SkASSERT(count < 0);
+
+       do {
+               if (++count < 0)
+               {
+                       newx    = oldx + (fCDx >> shift);
+                       fCDx    += fCDDx >> shift;
+                       fCDDx   += fCDDDx;
+
+                       newy    = oldy + (fCDy >> shift);
+                       fCDy    += fCDDy >> shift;
+                       fCDDy   += fCDDDy;
+               }
+               else    // last segment
+               {
+               //      SkDebugf("LastX err=%d, LastY err=%d\n", (oldx + (fCDx >> shift) - fLastX), (oldy + (fCDy >> shift) - fLastY));
+                       newx    = fCLastX;
+                       newy    = fCLastY;
+               }
+               success = this->updateLine(oldx, oldy, newx, newy);
+               oldx = newx;
+               oldy = newy;
+       } while (count < 0 && !success);
+
+       fCx                     = newx;
+       fCy                     = newy;
+       fCurveCount = SkToS16(count);
+       return success;
+}
+
+
+
diff --git a/libs/graphics/sgl/SkEdge.h b/libs/graphics/sgl/SkEdge.h
new file mode 100644 (file)
index 0000000..73add2a
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef SkEdge_DEFINED
+#define SkEdge_DEFINED
+
+#include "SkRect.h"
+
+struct SkEdge {
+       enum Type {
+               kLine_Type,
+               kQuad_Type,
+               kCubic_Type
+       };
+
+       SkEdge* fNext;
+       SkEdge* fPrev;
+
+       SkFixed fX;
+       SkFixed fDX;
+       S16             fFirstY;
+       S16             fLastY;
+       S16             fCurveCount;    // only used by kQuad(+) and kCubic(-)
+       U8              fCurveShift;
+       S8              fWinding;               // 1 or -1
+
+       int             setLine(const SkPoint pts[2], const SkRect16* clip, int shiftUp);
+       inline int      updateLine(SkFixed ax, SkFixed ay, SkFixed bx, SkFixed by);
+       void    chopLineWithClip(const SkRect16& clip);
+
+       inline bool intersectsClip(const SkRect16& clip) const
+       {
+               SkASSERT(fFirstY < clip.fBottom);
+               return fLastY >= clip.fTop;
+       }
+
+#ifdef SK_DEBUG
+       void dump() const
+       {
+    #ifdef SK_CAN_USE_FLOAT
+               SkDebugf("edge: firstY:%d lastY:%d x:%g dx:%g w:%d\n", fFirstY, fLastY, SkFixedToFloat(fX), SkFixedToFloat(fDX), fWinding);
+    #else
+               SkDebugf("edge: firstY:%d lastY:%d x:%x dx:%x w:%d\n", fFirstY, fLastY, fX, fDX, fWinding);
+    #endif
+       }
+
+       void validate() const
+       {
+               SkASSERT(fPrev && fNext);
+               SkASSERT(fPrev->fNext == this);
+               SkASSERT(fNext->fPrev == this);
+
+               SkASSERT(fFirstY <= fLastY);
+               SkASSERT(SkAbs32(fWinding) == 1);
+       }
+#endif
+};
+
+struct SkQuadraticEdge : public SkEdge {
+       SkFixed fQx, fQy;
+       SkFixed fQDx, fQDy;
+       SkFixed fQDDx, fQDDy;
+       SkFixed fQLastX, fQLastY;
+
+       int setQuadratic(const SkPoint pts[3], const SkRect16* clip, int shiftUp);
+       int updateQuadratic();
+};
+
+struct SkCubicEdge : public SkEdge {
+       SkFixed fCx, fCy;
+       SkFixed fCDx, fCDy;
+       SkFixed fCDDx, fCDDy;
+       SkFixed fCDDDx, fCDDDy;
+       SkFixed fCLastX, fCLastY;
+
+       int setCubic(const SkPoint pts[4], const SkRect16* clip, int shiftUp);
+       int     updateCubic();
+};
+
+#endif
diff --git a/libs/graphics/sgl/SkFP.h b/libs/graphics/sgl/SkFP.h
new file mode 100644 (file)
index 0000000..eb311b8
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef SkFP_DEFINED
+#define SkFP_DEFINED
+
+#include "SkMath.h"
+
+#ifdef SK_SCALAR_IS_FLOAT
+
+       typedef float SkFP;
+
+       #define SkScalarToFP(n)             (n)
+       #define SkFPToScalar(n)             (n)
+       #define SkIntToFP(n)                    SkIntToScalar(n)
+       #define SkFPRound(x)                    SkScalarRound(n)
+       #define SkFPCeil(x)             SkScalarCeil(n)
+       #define SkFPFloor(x)                    SkScalarFloor(n)
+
+       #define SkFPNeg(x)              (-(x))
+       #define SkFPAbs(x)              SkScalarAbs(x)
+       #define SkFPAdd(a, b)           ((a) + (b))
+       #define SkFPSub(a, b)           ((a) - (b))
+       #define SkFPMul(a, b)           ((a) * (b))
+       #define SkFPMulInt(a, n)                ((a) * (n))
+       #define SkFPDiv(a, b)           ((a) / (b))
+       #define SkFPDivInt(a, n)                ((a) / (n))
+       #define SkFPInvert(x)           SkScalarInvert(x)
+       #define SkFPSqrt(x)             SkScalarSqrt(x)
+       #define SkFPCubeRoot(x)         pow(x, 1.0f/3)
+
+       #define SkFPLT(a, b)                    ((a) < (b))
+       #define SkFPLE(a, b)                    ((a) <= (b))
+       #define SkFPGT(a, b)                    ((a) > (b))
+       #define SkFPGE(a, b)                    ((a) >= (b))
+
+#else  // scalar is fixed
+
+       #include "SkFloat.h"
+
+       typedef S32     SkFP;
+
+       #define SkScalarToFP(n)             SkFloat::SetShift(n, -16)
+       #define SkFPToScalar(n)             SkFloat::GetShift(n, -16)
+       #define SkIntToFP(n)                    SkFloat::SetShift(n, 0)
+       #define SkFPRound(x)                    SkFloat::Round(x);
+       #define SkFPCeil(x)             SkFloat::Ceil();
+       #define SkFPFloor(x)                    SkFloat::Floor();
+
+       #define SkFPNeg(x)              SkFloat::Neg(x)
+       #define SkFPAbs(x)              SkFloat::Abs(x)
+       #define SkFPAdd(a, b)           SkFloat::Add(a, b)
+       #define SkFPSub(a, b)           SkFloat::Add(a, SkFloat::Neg(b))
+       #define SkFPMul(a, b)           SkFloat::Mul(a, b)
+       #define SkFPMulInt(a, n)                SkFloat::MulInt(a, n)
+       #define SkFPDiv(a, b)           SkFloat::Div(a, b)
+       #define SkFPDivInt(a, n)                SkFloat::DivInt(a, n)
+       #define SkFPInvert(x)           SkFloat::Invert(x)
+       #define SkFPSqrt(x)             SkFloat::Sqrt(x)
+       #define SkFPCubeRoot(x)         SkFloat::CubeRoot(x)
+
+       #define SkFPLT(a, b)                    (SkFloat::Cmp(a, b) < 0)
+       #define SkFPLE(a, b)                    (SkFloat::Cmp(a, b) <= 0)
+       #define SkFPGT(a, b)                    (SkFloat::Cmp(a, b) > 0)
+       #define SkFPGE(a, b)                    (SkFloat::Cmp(a, b) >= 0)
+
+#endif
+
+#ifdef SK_DEBUG
+       void SkFP_UnitTest();
+#endif
+
+#endif
diff --git a/libs/graphics/sgl/SkFilterProc.cpp b/libs/graphics/sgl/SkFilterProc.cpp
new file mode 100644 (file)
index 0000000..b51fa93
--- /dev/null
@@ -0,0 +1,38 @@
+#include "SkFilterProc.h"
+
+/*     [1-x 1-y] [x 1-y]
+       [1-x   y] [x   y]
+*/
+
+static unsigned bilerp00(unsigned a00, unsigned a01, unsigned a10, unsigned a11) { return a00; }
+static unsigned bilerp01(unsigned a00, unsigned a01, unsigned a10, unsigned a11) { return (3 * a00 + a01) >> 2; }
+static unsigned bilerp02(unsigned a00, unsigned a01, unsigned a10, unsigned a11) { return (a00 + a01) >> 1; }
+static unsigned bilerp03(unsigned a00, unsigned a01, unsigned a10, unsigned a11) { return (a00 + 3 * a01) >> 2; }
+
+static unsigned bilerp10(unsigned a00, unsigned a01, unsigned a10, unsigned a11) { return (3 * a00 + a10) >> 2; }
+static unsigned bilerp11(unsigned a00, unsigned a01, unsigned a10, unsigned a11) { return (9 * a00 + 3 * (a01 + a10) + a11) >> 4; }
+static unsigned bilerp12(unsigned a00, unsigned a01, unsigned a10, unsigned a11) { return (3 * (a00 + a01) + a10 + a11) >> 3; }
+static unsigned bilerp13(unsigned a00, unsigned a01, unsigned a10, unsigned a11) { return (9 * a01 + 3 * (a00 + a11) + a10) >> 4; }
+
+static unsigned bilerp20(unsigned a00, unsigned a01, unsigned a10, unsigned a11) { return (a00 + a10) >> 1; }
+static unsigned bilerp21(unsigned a00, unsigned a01, unsigned a10, unsigned a11) { return (3 * (a00 + a10) + a01 + a11) >> 3; }
+static unsigned bilerp22(unsigned a00, unsigned a01, unsigned a10, unsigned a11) { return (a00 + a01 + a10 + a11) >> 2; }
+static unsigned bilerp23(unsigned a00, unsigned a01, unsigned a10, unsigned a11) { return (3 * (a01 + a11) + a00 + a10) >> 3; }
+
+static unsigned bilerp30(unsigned a00, unsigned a01, unsigned a10, unsigned a11) { return (a00 + 3 * a10) >> 2; }
+static unsigned bilerp31(unsigned a00, unsigned a01, unsigned a10, unsigned a11) { return (9 * a10 + 3 * (a00 + a11) + a01) >> 4; }
+static unsigned bilerp32(unsigned a00, unsigned a01, unsigned a10, unsigned a11) { return (3 * (a10 + a11) + a00 + a01) >> 3; }
+static unsigned bilerp33(unsigned a00, unsigned a01, unsigned a10, unsigned a11) { return (9 * a11 + 3 * (a01 + a10) + a00) >> 4; }
+
+static const SkFilterProc gBilerpProcs[4 * 4] = {
+       bilerp00, bilerp01, bilerp02, bilerp03,
+       bilerp10, bilerp11, bilerp12, bilerp13,
+       bilerp20, bilerp21, bilerp22, bilerp23,
+       bilerp30, bilerp31, bilerp32, bilerp33
+};
+
+const SkFilterProc* SkGetBilinearFilterProcTable()
+{
+       return gBilerpProcs;
+}
+
diff --git a/libs/graphics/sgl/SkFilterProc.h b/libs/graphics/sgl/SkFilterProc.h
new file mode 100644 (file)
index 0000000..a9c7223
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef SkFilter_DEFINED
+#define SkFilter_DEFINED
+
+#include "SkMath.h"
+
+typedef unsigned (*SkFilterProc)(unsigned x00, unsigned x01, unsigned x10, unsigned x11);
+
+const SkFilterProc* SkGetBilinearFilterProcTable();
+
+inline SkFilterProc SkGetBilinearFilterProc(const SkFilterProc* table, SkFixed x, SkFixed y)
+{
+       SkASSERT(table);
+
+       // convert to dot 2
+       x = (unsigned)(x << 16) >> 30;
+       y = (unsigned)(y << 16) >> 30;
+       return table[(y << 2) | x];
+}
+
+#endif
+
+
diff --git a/libs/graphics/sgl/SkGeometry.cpp b/libs/graphics/sgl/SkGeometry.cpp
new file mode 100644 (file)
index 0000000..fe47cff
--- /dev/null
@@ -0,0 +1,1013 @@
+#include "SkGeometry.h"
+#include "Sk64.h"
+#include "SkMatrix.h"
+
+/**    If defined, this makes eval_quad and eval_cubic do more setup (sometimes
+       involving integer multiplies by 2 or 3, but fewer calls to SkScalarMul.
+       May also introduce overflow of fixed when we compute our setup.
+*/
+#ifdef SK_SCALAR_IS_FIXED
+       #define DIRECT_EVAL_OF_POLYNOMIALS
+#endif
+
+////////////////////////////////////////////////////////////////////////
+
+#if defined(SK_SCALAR_IS_FIXED) && !defined(SK_CPU_HAS_CONDITIONAL_INSTR)
+       static int is_not_monotonic(int a, int b, int c, int d)
+       {
+               return (((a - b) | (b - c) | (c - d)) & ((b - a) | (c - b) | (d - c))) >> 31;
+       }
+       static int is_not_monotonic(int a, int b, int c)
+       {
+               return (((a - b) | (b - c)) & ((b - a) | (c - b))) >> 31;
+       }
+#else   // scalar-is-float or we have fast if/then instructions
+       static int is_not_monotonic(SkScalar a, SkScalar b, SkScalar c, SkScalar d)
+       {
+               int neg = 0, pos = 0;
+
+               if (a < b) neg = 1;
+               if (a > b) pos = 1;
+               if (b < c) neg = 1;
+               if (b > c) pos = 1;
+               if (c < d) neg = 1;
+               if (c > d) pos = 1;
+
+               return neg & pos;
+       }
+       static int is_not_monotonic(SkScalar a, SkScalar b, SkScalar c)
+       {
+               int neg = 0, pos = 0;
+
+               if (a < b) neg = 1;
+               if (a > b) pos = 1;
+               if (b < c) neg = 1;
+               if (b > c) pos = 1;
+
+               return neg & pos;
+       }
+#endif
+
+////////////////////////////////////////////////////////////////////////
+
+static bool is_unit_interval(SkScalar x)
+{
+       return x > 0 && x < SK_Scalar1;
+}
+
+static int valid_unit_divide(SkScalar numer, SkScalar denom, SkScalar* ratio)
+{
+       if (numer < 0)
+       {
+               numer = -numer;
+               denom = -denom;
+       }
+
+       if (denom == 0 || numer == 0 || numer >= denom)
+               return 0;
+
+       if (ratio)
+       {
+               SkScalar r = SkScalarDiv(numer, denom);
+               SkASSERT(r >= 0 && r < SK_Scalar1);
+               if (r == 0)     // catch underflow if numer <<<< denom
+                       return 0;
+               *ratio = r;
+       }
+       return 1;
+}
+
+/**    From Numerical Recipes in C.
+
+       Q = -1/2 (B + sign(B) sqrt[B*B - 4*A*C])
+       x1 = Q / A
+       x2 = C / Q
+*/
+int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2])
+{
+       SkScalar* r = roots;
+
+       if (A == 0)
+               return valid_unit_divide(-C, B, roots);
+
+#ifdef SK_SCALAR_IS_FLOAT
+       float R = B*B - 4*A*C;
+       if (R < 0)      // complex roots
+               return 0;
+       R = sk_float_sqrt(R);
+#else
+       Sk64    RR, tmp;
+
+       RR.setMul(B,B);
+       tmp.setMul(A,C);
+       tmp.shiftLeft(2);
+       RR.sub(tmp);
+       if (RR.isNeg())
+               return 0;
+       SkFixed R = RR.getSqrt();
+#endif
+
+       SkScalar Q = (B < 0) ? -(B-R)/2 : -(B+R)/2;
+       r += valid_unit_divide(Q, A, r);
+       r += valid_unit_divide(C, Q, r);
+       if (r - roots == 2)
+       {
+               if (roots[0] > roots[1])
+                       SkTSwap<SkScalar>(roots[0], roots[1]);
+               else if (roots[0] == roots[1])  // nearly-equal?
+                       r -= 1; // skip the double root
+       }
+       return (int)(r - roots);
+}
+
+#ifdef SK_SCALAR_IS_FIXED
+/**    Trim A/B/C down so that they are all <= 32bits
+       and then call SkFindUnitQuadRoots()
+*/
+static int Sk64FindFixedQuadRoots(const Sk64& A, const Sk64& B, const Sk64& C, SkFixed roots[2])
+{
+       int     na = A.shiftToMake32();
+       int     nb = B.shiftToMake32();
+       int     nc = C.shiftToMake32();
+
+       int shift = SkMax32(na, SkMax32(nb, nc));
+       SkASSERT(shift >= 0);
+
+       return SkFindUnitQuadRoots(A.getShiftRight(shift), B.getShiftRight(shift), C.getShiftRight(shift), roots);
+}
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////
+
+static SkScalar eval_quad(const SkScalar src[], SkScalar t)
+{
+       SkASSERT(src);
+       SkASSERT(t >= 0 && t <= SK_Scalar1);
+
+#ifdef DIRECT_EVAL_OF_POLYNOMIALS
+       SkScalar        C = src[0];
+       SkScalar        A = src[4] - 2 * src[2] + C;
+       SkScalar        B = 2 * (src[2] - C);
+       return SkScalarMul(SkScalarMul(A, t) + B, t) + C;
+#else
+       SkScalar        ab = SkScalarInterp(src[0], src[2], t);
+       SkScalar        bc = SkScalarInterp(src[2], src[4], t); 
+       return SkScalarInterp(ab, bc, t);
+#endif
+}
+
+static SkScalar eval_quad_derivative(const SkScalar src[], SkScalar t)
+{
+       SkScalar A = src[4] - 2 * src[2] + src[0];
+       SkScalar B = src[2] - src[0];
+
+       return 2 * (SkScalarMul(A, t) + B);
+}
+
+static SkScalar eval_quad_derivative_at_half(const SkScalar src[])
+{
+       SkScalar A = src[4] - 2 * src[2] + src[0];
+       SkScalar B = src[2] - src[0];
+       return A + 2 * B;
+}
+
+void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint* pt, SkVector* tangent)
+{
+       SkASSERT(src);
+       SkASSERT(t >= 0 && t <= SK_Scalar1);
+
+       if (pt)
+               pt->set(eval_quad(&src[0].fX, t), eval_quad(&src[0].fY, t));
+       if (tangent)
+               tangent->set(eval_quad_derivative(&src[0].fX, t),
+                                        eval_quad_derivative(&src[0].fY, t));
+}
+
+void SkEvalQuadAtHalf(const SkPoint src[3], SkPoint* pt, SkVector* tangent)
+{
+       SkASSERT(src);
+
+       if (pt)
+       {
+               SkScalar x01 = SkScalarAve(src[0].fX, src[1].fX);
+               SkScalar y01 = SkScalarAve(src[0].fY, src[1].fY);
+               SkScalar x12 = SkScalarAve(src[1].fX, src[2].fX);
+               SkScalar y12 = SkScalarAve(src[1].fY, src[2].fY);
+               pt->set(SkScalarAve(x01, x12), SkScalarAve(y01, y12));
+       }
+       if (tangent)
+               tangent->set(eval_quad_derivative_at_half(&src[0].fX),
+                                        eval_quad_derivative_at_half(&src[0].fY));
+}
+
+static void interp_quad_coords(const SkScalar* src, SkScalar* dst, SkScalar t)
+{
+       SkScalar        ab = SkScalarInterp(src[0], src[2], t);
+       SkScalar        bc = SkScalarInterp(src[2], src[4], t);
+
+       dst[0] = src[0];
+       dst[2] = ab;
+       dst[4] = SkScalarInterp(ab, bc, t);
+       dst[6] = bc;
+       dst[8] = src[4];
+}
+
+void SkChopQuadAt(const SkPoint src[3], SkPoint dst[5], SkScalar t)
+{
+       SkASSERT(t > 0 && t < SK_Scalar1);
+
+       interp_quad_coords(&src[0].fX, &dst[0].fX, t);
+       interp_quad_coords(&src[0].fY, &dst[0].fY, t);
+}
+
+void SkChopQuadAtHalf(const SkPoint src[3], SkPoint dst[5])
+{
+       SkScalar x01 = SkScalarAve(src[0].fX, src[1].fX);
+       SkScalar y01 = SkScalarAve(src[0].fY, src[1].fY);
+       SkScalar x12 = SkScalarAve(src[1].fX, src[2].fX);
+       SkScalar y12 = SkScalarAve(src[1].fY, src[2].fY);
+
+       dst[0] = src[0];
+       dst[1].set(x01, y01);
+       dst[2].set(SkScalarAve(x01, x12), SkScalarAve(y01, y12));
+       dst[3].set(x12, y12);
+       dst[4] = src[2];
+}
+
+/**    Quad'(t) = At + B, where
+       A = 2(a - 2b + c)
+       B = 2(b - a)
+       Solve for t, only if it fits between 0 < t < 1
+*/
+int SkFindQuadExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar tValue[1])
+{
+       /*      At + B == 0
+               t = -B / A
+       */
+#ifdef SK_SCALAR_IS_FIXED
+    return is_not_monotonic(a, b, c) && valid_unit_divide(a - b, a - b - b + c, tValue);
+#else
+       return valid_unit_divide(a - b, a - b - b + c, tValue);
+#endif
+}
+
+static void flatten_double_quad_extrema(SkScalar coords[14])
+{
+       coords[2] = coords[6] = coords[4];
+}
+
+static void force_quad_monotonic_in_y(SkPoint pts[3])
+{
+    // zap pts[1].fY to the nearest value
+    SkScalar ab = SkScalarAbs(pts[0].fY - pts[1].fY);
+    SkScalar bc = SkScalarAbs(pts[1].fY - pts[2].fY);
+    pts[1].fY = ab < bc ? pts[0].fY : pts[2].fY;
+}
+
+/*  Returns 0 for 1 quad, and 1 for two quads, either way the answer is
+    stored in dst[]. Guarantees that the 1/2 quads will be monotonic.
+*/
+int SkChopQuadAtYExtrema(const SkPoint src[3], SkPoint dst[5])
+{
+#if 0
+    static bool once = true;
+    if (once)
+    {
+        once = false;
+        SkPoint s[3] = { 0, 26398, 0, 26331, 0, 20621428 };
+        SkPoint d[6];
+        
+        int n = SkChopQuadAtYExtrema(s, d);
+        SkDebugf("chop=%d, Y=[%x %x %x %x %x %x]\n", n, d[0].fY, d[1].fY, d[2].fY, d[3].fY, d[4].fY, d[5].fY);
+    }
+#endif
+
+       SkScalar        tValue;
+       int                     roots = SkFindQuadExtrema(src[0].fY, src[1].fY, src[2].fY, &tValue);
+
+       if (dst)
+       {
+               if (roots == 0) // nothing to chop
+        {
+                       memcpy(dst, src, 3*sizeof(SkPoint));
+            // check if valid_unit_divide gave up but we're still not monotonic
+            // can happen if valid_unit_divide can't see the t-value (underflow)
+            // e.g. SkPoint s[3] = { 0, 26398, 0, 26331, 0, 20621428 };
+            if (is_not_monotonic(src[0].fY, src[1].fY, src[2].fY))
+                force_quad_monotonic_in_y(dst);
+        }
+               else
+               {
+                       SkChopQuadAt(src, dst, tValue);
+                       flatten_double_quad_extrema(&dst[0].fY);
+               }
+       }
+       return roots;
+}
+
+//     F(t)    = a (1 - t) ^ 2 + 2 b t (1 - t) + c t ^ 2
+//     F'(t)   = 2 (b - a) + 2 (a - 2b + c) t
+//     F''(t)  = 2 (a - 2b + c)
+//
+//     A = 2 (b - a)
+//     B = 2 (a - 2b + c)
+//
+//     Maximum curvature for a quadratic means solving
+//     Fx' Fx'' + Fy' Fy'' = 0
+//
+//     t = - (Ax Bx + Ay By) / (Bx ^ 2 + By ^ 2)
+//
+int SkChopQuadAtMaxCurvature(const SkPoint src[3], SkPoint dst[5])
+{
+       SkScalar        Ax = src[1].fX - src[0].fX;
+       SkScalar        Ay = src[1].fY - src[0].fY;
+       SkScalar        Bx = src[0].fX - src[1].fX - src[1].fX + src[2].fX;
+       SkScalar        By = src[0].fY - src[1].fY - src[1].fY + src[2].fY;
+       SkScalar        t = 0;  // 0 means don't chop
+
+#ifdef SK_SCALAR_IS_FLOAT
+       (void)valid_unit_divide(-(Ax * Bx + Ay * By), Bx * Bx + By * By, &t);
+#else
+       // !!! should I use SkFloat here? seems like it
+       Sk64    numer, denom, tmp;
+
+       numer.setMul(Ax, -Bx);
+       tmp.setMul(Ay, -By);
+       numer.add(tmp);
+
+       if (numer.isPos())      // do nothing if numer <= 0
+       {
+               denom.setMul(Bx, Bx);
+               tmp.setMul(By, By);
+               denom.add(tmp);
+               SkASSERT(!denom.isNeg());
+               if (numer < denom)
+               {
+                       t = numer.getFixedDiv(denom);
+                       SkASSERT(t >= 0 && t <= SK_Fixed1);             // assert that we're numerically stable (ha!)
+                       if ((unsigned)t >= SK_Fixed1)                   // runtime check for numerical stability
+                               t = 0;  // ignore the chop
+               }
+       }
+#endif
+
+       if (t == 0)
+       {
+               memcpy(dst, src, 3 * sizeof(SkPoint));
+               return 1;
+       }
+       else
+       {
+               SkChopQuadAt(src, dst, t);
+               return 2;
+       }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+///// CUBICS // CUBICS // CUBICS // CUBICS // CUBICS // CUBICS // CUBICS // CUBICS /////
+////////////////////////////////////////////////////////////////////////////////////////
+
+static void get_cubic_coeff(const SkScalar pt[], SkScalar coeff[4])
+{
+       coeff[0] = pt[6] + 3*(pt[2] - pt[4]) - pt[0];
+       coeff[1] = 3*(pt[4] - pt[2] - pt[2] + pt[0]);
+       coeff[2] = 3*(pt[2] - pt[0]);
+       coeff[3] = pt[0];
+}
+
+void SkGetCubicCoeff(const SkPoint pts[4], SkScalar cx[4], SkScalar cy[4])
+{
+       SkASSERT(pts);
+
+       if (cx)
+               get_cubic_coeff(&pts[0].fX, cx);
+       if (cy)
+               get_cubic_coeff(&pts[0].fY, cy);
+}
+
+static SkScalar eval_cubic(const SkScalar src[], SkScalar t)
+{
+       SkASSERT(src);
+       SkASSERT(t >= 0 && t <= SK_Scalar1);
+
+       if (t == 0)
+               return src[0];
+
+#ifdef DIRECT_EVAL_OF_POLYNOMIALS
+       SkScalar D = src[0];
+       SkScalar A = src[6] + 3*(src[2] - src[4]) - D;
+       SkScalar B = 3*(src[4] - src[2] - src[2] + D);
+       SkScalar C = 3*(src[2] - D);
+
+       return SkScalarMul(SkScalarMul(SkScalarMul(A, t) + B, t) + C, t) + D;
+#else
+       SkScalar        ab = SkScalarInterp(src[0], src[2], t);
+       SkScalar        bc = SkScalarInterp(src[2], src[4], t);
+       SkScalar        cd = SkScalarInterp(src[4], src[6], t);
+       SkScalar        abc = SkScalarInterp(ab, bc, t);
+       SkScalar        bcd = SkScalarInterp(bc, cd, t);
+       return SkScalarInterp(abc, bcd, t);
+#endif
+}
+
+/**    return At^2 + Bt + C
+*/
+static SkScalar eval_quadratic(SkScalar A, SkScalar B, SkScalar C, SkScalar t)
+{
+       SkASSERT(t >= 0 && t <= SK_Scalar1);
+
+       return SkScalarMul(SkScalarMul(A, t) + B, t) + C;
+}
+
+static SkScalar eval_cubic_derivative(const SkScalar src[], SkScalar t)
+{
+       SkScalar A = src[6] + 3*(src[2] - src[4]) - src[0];
+       SkScalar B = 2*(src[4] - 2 * src[2] + src[0]);
+       SkScalar C = src[2] - src[0];
+
+       return eval_quadratic(A, B, C, t);
+}
+
+static SkScalar eval_cubic_2ndDerivative(const SkScalar src[], SkScalar t)
+{
+       SkScalar A = src[6] + 3*(src[2] - src[4]) - src[0];
+       SkScalar B = src[4] - 2 * src[2] + src[0];
+
+       return SkScalarMul(A, t) + B;
+}
+
+void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint* loc, SkVector* tangent, SkVector* curvature)
+{
+       SkASSERT(src);
+       SkASSERT(t >= 0 && t <= SK_Scalar1);
+
+       if (loc)
+               loc->set(eval_cubic(&src[0].fX, t), eval_cubic(&src[0].fY, t));
+       if (tangent)
+               tangent->set(eval_cubic_derivative(&src[0].fX, t),
+                                        eval_cubic_derivative(&src[0].fY, t));
+       if (curvature)
+               curvature->set(eval_cubic_2ndDerivative(&src[0].fX, t),
+                                          eval_cubic_2ndDerivative(&src[0].fY, t));
+}
+
+/**    Cubic'(t) = At^2 + Bt + C, where
+       A = 3(-a + 3(b - c) + d)
+       B = 6(a - 2b + c)
+       C = 3(b - a)
+       Solve for t, keeping only those that fit betwee 0 < t < 1
+*/
+int SkFindCubicExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar d, SkScalar tValues[2])
+{
+#ifdef SK_SCALAR_IS_FIXED
+       if (!is_not_monotonic(a, b, c, d))
+               return 0;
+#endif
+
+       // we divide A,B,C by 3 to simplify
+       SkScalar A = d - a + 3*(b - c);
+       SkScalar B = 2*(a - b - b + c);
+       SkScalar C = b - a;
+
+       return SkFindUnitQuadRoots(A, B, C, tValues);
+}
+
+static void interp_cubic_coords(const SkScalar* src, SkScalar* dst, SkScalar t)
+{
+       SkScalar        ab = SkScalarInterp(src[0], src[2], t);
+       SkScalar        bc = SkScalarInterp(src[2], src[4], t);
+       SkScalar        cd = SkScalarInterp(src[4], src[6], t);
+       SkScalar        abc = SkScalarInterp(ab, bc, t);
+       SkScalar        bcd = SkScalarInterp(bc, cd, t);
+       SkScalar        abcd = SkScalarInterp(abc, bcd, t);
+
+       dst[0] = src[0];
+       dst[2] = ab;
+       dst[4] = abc;
+       dst[6] = abcd;
+       dst[8] = bcd;
+       dst[10] = cd;
+       dst[12] = src[6];
+}
+
+void SkChopCubicAt(const SkPoint src[4], SkPoint dst[7], SkScalar t)
+{
+       SkASSERT(t > 0 && t < SK_Scalar1);
+
+       interp_cubic_coords(&src[0].fX, &dst[0].fX, t);
+       interp_cubic_coords(&src[0].fY, &dst[0].fY, t);
+}
+
+void SkChopCubicAt(const SkPoint src[4], SkPoint dst[], const SkScalar tValues[], int roots)
+{
+#ifdef SK_DEBUG
+       {
+               for (int i = 0; i < roots - 1; i++)
+               {
+                       SkASSERT(is_unit_interval(tValues[i]));
+                       SkASSERT(is_unit_interval(tValues[i+1]));
+                       SkASSERT(tValues[i] < tValues[i+1]);
+               }
+       }
+#endif
+
+       if (dst)
+       {
+               if (roots == 0) // nothing to chop
+                       memcpy(dst, src, 4*sizeof(SkPoint));
+               else
+               {
+                       SkScalar        t = tValues[0];
+                       SkPoint         tmp[4];
+
+                       for (int i = 0; i < roots; i++)
+                       {
+                               SkChopCubicAt(src, dst, t);
+                               if (i == roots - 1)
+                                       break;
+
+                               SkDEBUGCODE(int valid =) valid_unit_divide(tValues[i+1] - tValues[i], SK_Scalar1 - tValues[i], &t);
+                               SkASSERT(valid);
+
+                               dst += 3;
+                               memcpy(tmp, dst, 4 * sizeof(SkPoint));
+                               src = tmp;
+                       }
+               }
+       }
+}
+
+void SkChopCubicAtHalf(const SkPoint src[4], SkPoint dst[7])
+{
+       SkScalar x01 = SkScalarAve(src[0].fX, src[1].fX);
+       SkScalar y01 = SkScalarAve(src[0].fY, src[1].fY);
+       SkScalar x12 = SkScalarAve(src[1].fX, src[2].fX);
+       SkScalar y12 = SkScalarAve(src[1].fY, src[2].fY);
+       SkScalar x23 = SkScalarAve(src[2].fX, src[3].fX);
+       SkScalar y23 = SkScalarAve(src[2].fY, src[3].fY);
+
+       SkScalar x012 = SkScalarAve(x01, x12);
+       SkScalar y012 = SkScalarAve(y01, y12);
+       SkScalar x123 = SkScalarAve(x12, x23);
+       SkScalar y123 = SkScalarAve(y12, y23);
+
+       dst[0] = src[0];
+       dst[1].set(x01, y01);
+       dst[2].set(x012, y012);
+       dst[3].set(SkScalarAve(x012, x123), SkScalarAve(y012, y123));
+       dst[4].set(x123, y123);
+       dst[5].set(x23, y23);
+       dst[6] = src[3];
+}
+
+static void flatten_double_cubic_extrema(SkScalar coords[14])
+{
+       coords[4] = coords[8] = coords[6];
+}
+
+/**    Given 4 points on a cubic bezier, chop it into 1, 2, 3 beziers such that
+       the resulting beziers are monotonic in Y. This is called by the scan converter.
+       Depending on what is returned, dst[] is treated as follows
+       0       dst[0..3] is the original cubic
+       1       dst[0..3] and dst[3..6] are the two new cubics
+       2       dst[0..3], dst[3..6], dst[6..9] are the three new cubics
+       If dst == nil, it is ignored and only the count is returned.
+*/
+int SkChopCubicAtYExtrema(const SkPoint src[4], SkPoint dst[10])
+{
+       SkScalar        tValues[2];
+       int                     roots = SkFindCubicExtrema(src[0].fY, src[1].fY, src[2].fY, src[3].fY, tValues);
+
+       SkChopCubicAt(src, dst, tValues, roots);
+       if (dst && roots > 0)
+       {
+               // we do some cleanup to ensure our Y extrema are flat
+               flatten_double_cubic_extrema(&dst[0].fY);
+               if (roots == 2)
+                       flatten_double_cubic_extrema(&dst[3].fY);
+       }
+       return roots;
+}
+
+/**    http://www.faculty.idc.ac.il/arik/quality/appendixA.html
+
+       Inflection means that curvature is zero.
+       Curvature is [F' x F''] / [F'^3]
+       So we solve F'x X F''y - F'y X F''y == 0
+       After some canceling of the cubic term, we get
+       A = b - a
+       B = c - 2b + a
+       C = d - 3c + 3b - a
+       (BxCy - ByCx)t^2 + (AxCy - AyCx)t + AxBy - AyBx == 0
+*/
+int SkFindCubicInflections(const SkPoint src[4], SkScalar tValues[])
+{
+       SkScalar        Ax = src[1].fX - src[0].fX;
+       SkScalar        Ay = src[1].fY - src[0].fY;
+       SkScalar        Bx = src[2].fX - 2 * src[1].fX + src[0].fX;
+       SkScalar        By = src[2].fY - 2 * src[1].fY + src[0].fY;
+       SkScalar        Cx = src[3].fX + 3 * (src[1].fX - src[2].fX) - src[0].fX;
+       SkScalar        Cy = src[3].fY + 3 * (src[1].fY - src[2].fY) - src[0].fY;
+       int                     count;
+
+#ifdef SK_SCALAR_IS_FLOAT
+       count = SkFindUnitQuadRoots(Bx*Cy - By*Cx, Ax*Cy - Ay*Cx, Ax*By - Ay*Bx, tValues);
+#else
+       Sk64    A, B, C, tmp;
+
+       A.setMul(Bx, Cy);
+       tmp.setMul(By, Cx);
+       A.sub(tmp);
+
+       B.setMul(Ax, Cy);
+       tmp.setMul(Ay, Cx);
+       B.sub(tmp);
+
+       C.setMul(Ax, By);
+       tmp.setMul(Ay, Bx);
+       C.sub(tmp);
+
+       count = Sk64FindFixedQuadRoots(A, B, C, tValues);
+#endif
+
+       return count;
+}
+
+int SkChopCubicAtInflections(const SkPoint src[], SkPoint dst[10])
+{
+       SkScalar        tValues[2];
+       int                     count = SkFindCubicInflections(src, tValues);
+
+       if (dst)
+       {
+               if (count == 0)
+                       memcpy(dst, src, 4 * sizeof(SkPoint));
+               else
+                       SkChopCubicAt(src, dst, tValues, count);
+       }
+       return count + 1;
+}
+
+template <typename T> void bubble_sort(T array[], int count)
+{
+       for (int i = count - 1; i > 0; --i)
+               for (int j = i; j > 0; --j)
+                       if (array[j] < array[j-1])
+                       {
+                               T       tmp(array[j]);
+                               array[j] = array[j-1];
+                               array[j-1] = tmp;
+                       }
+}
+
+#include "SkFP.h"
+
+// newton refinement
+#if 0
+static SkScalar refine_cubic_root(const SkFP coeff[4], SkScalar root)
+{
+       //      x1 = x0 - f(t) / f'(t)
+
+       SkFP    T = SkScalarToFloat(root);
+       SkFP    N, D;
+
+       // f' = 3*coeff[0]*T^2 + 2*coeff[1]*T + coeff[2]
+       D = SkFPMul(SkFPMul(coeff[0], SkFPMul(T,T)), 3);
+       D = SkFPAdd(D, SkFPMulInt(SkFPMul(coeff[1], T), 2));
+       D = SkFPAdd(D, coeff[2]);
+
+       if (D == 0)
+               return root;
+
+       // f = coeff[0]*T^3 + coeff[1]*T^2 + coeff[2]*T + coeff[3]
+       N = SkFPMul(SkFPMul(SkFPMul(T, T), T), coeff[0]);
+       N = SkFPAdd(N, SkFPMul(SkFPMul(T, T), coeff[1]));
+       N = SkFPAdd(N, SkFPMul(T, coeff[2]));
+       N = SkFPAdd(N, coeff[3]);
+
+       if (N)
+       {
+               SkScalar delta = SkFPToScalar(SkFPDiv(N, D));
+
+               if (delta)
+                       root -= delta;
+       }
+       return root;
+}
+#endif
+
+#if defined _WIN32 && _MSC_VER >= 1300 && defined SK_SCALAR_IS_FIXED // disable warning : unreachable code if building fixed point for windows desktop
+#pragma warning ( disable : 4702 )
+#endif
+
+/*     Solve coeff(t) == 0, returning the number of roots that
+       lie withing 0 < t < 1.
+       coeff[0]t^3 + coeff[1]t^2 + coeff[2]t + coeff[3]
+*/
+static int solve_cubic_polynomial(const SkFP coeff[4], SkScalar tValues[3])
+{
+#ifndef SK_SCALAR_IS_FLOAT
+       return 0;       // this is not yet implemented for software float
+#endif
+
+       if (SkScalarNearlyZero(coeff[0]))       // we're just a quadratic
+       {
+               return SkFindUnitQuadRoots(coeff[1], coeff[2], coeff[3], tValues);
+       }
+
+       SkFP    a, b, c, Q, R;
+
+       {
+               SkASSERT(coeff[0] != 0);
+
+               SkFP inva = SkFPInvert(coeff[0]);
+               a = SkFPMul(coeff[1], inva);
+               b = SkFPMul(coeff[2], inva);
+               c = SkFPMul(coeff[3], inva);
+       }
+       Q = SkFPDivInt(SkFPSub(SkFPMul(a,a), SkFPMulInt(b, 3)), 9);
+//     R = (2*a*a*a - 9*a*b + 27*c) / 54;
+       R = SkFPMulInt(SkFPMul(SkFPMul(a, a), a), 2);
+       R = SkFPSub(R, SkFPMulInt(SkFPMul(a, b), 9));
+       R = SkFPAdd(R, SkFPMulInt(c, 27));
+       R = SkFPDivInt(R, 54);
+
+       SkFP Q3 = SkFPMul(SkFPMul(Q, Q), Q);
+       SkFP R2MinusQ3 = SkFPSub(SkFPMul(R,R), Q3);
+       SkFP adiv3 = SkFPDivInt(a, 3);
+
+       SkScalar*       roots = tValues;
+       SkScalar        r;
+
+       if (SkFPLT(R2MinusQ3, 0))       // we have 3 real roots
+       {
+#ifdef SK_SCALAR_IS_FLOAT
+               float theta = sk_float_acos(R / sk_float_sqrt(Q3));
+               float neg2RootQ = -2 * sk_float_sqrt(Q);
+
+               r = neg2RootQ * sk_float_cos(theta/3) - adiv3;
+               if (is_unit_interval(r))
+                       *roots++ = r;
+
+               r = neg2RootQ * sk_float_cos((theta + 2*SK_ScalarPI)/3) - adiv3;
+               if (is_unit_interval(r))
+                       *roots++ = r;
+
+               r = neg2RootQ * sk_float_cos((theta - 2*SK_ScalarPI)/3) - adiv3;
+               if (is_unit_interval(r))
+                       *roots++ = r;
+
+               // now sort the roots
+               bubble_sort(tValues, (int)(roots - tValues));
+#endif
+       }
+       else                            // we have 1 real root
+       {
+               SkFP A = SkFPAdd(SkFPAbs(R), SkFPSqrt(R2MinusQ3));
+               A = SkFPCubeRoot(A);
+               if (SkFPGT(R, 0))
+                       A = SkFPNeg(A);
+
+               if (A != 0)
+                       A = SkFPAdd(A, SkFPDiv(Q, A));
+               r = SkFPToScalar(SkFPSub(A, adiv3));
+               if (is_unit_interval(r))
+                       *roots++ = r;
+       }
+
+       return (int)(roots - tValues);
+}
+
+/*     Looking for F' dot F'' == 0
+       
+       A = b - a
+       B = c - 2b + a
+       C = d - 3c + 3b - a
+
+       F' = 3Ct^2 + 6Bt + 3A
+       F'' = 6Ct + 6B
+
+       F' dot F'' -> CCt^3 + 3BCt^2 + (2BB + CA)t + AB
+*/
+static void formulate_F1DotF2(const SkScalar src[], SkFP coeff[4])
+{
+       SkScalar        a = src[2] - src[0];
+       SkScalar        b = src[4] - 2 * src[2] + src[0];
+       SkScalar        c = src[6] + 3 * (src[2] - src[4]) - src[0];
+
+       SkFP    A = SkScalarToFP(a);
+       SkFP    B = SkScalarToFP(b);
+       SkFP    C = SkScalarToFP(c);
+
+       coeff[0] = SkFPMul(C, C);
+       coeff[1] = SkFPMulInt(SkFPMul(B, C), 3);
+       coeff[2] = SkFPMulInt(SkFPMul(B, B), 2);
+       coeff[2] = SkFPAdd(coeff[2], SkFPMul(C, A));
+       coeff[3] = SkFPMul(A, B);
+}
+
+// EXPERIMENTAL: can set this to zero to accept all t-values 0 < t < 1
+//#define kMinTValueForChopping        (SK_Scalar1 / 256)
+#define kMinTValueForChopping  0
+
+/*     Looking for F' dot F'' == 0
+       
+       A = b - a
+       B = c - 2b + a
+       C = d - 3c + 3b - a
+
+       F' = 3Ct^2 + 6Bt + 3A
+       F'' = 6Ct + 6B
+
+       F' dot F'' -> CCt^3 + 3BCt^2 + (2BB + CA)t + AB
+*/
+int SkFindCubicMaxCurvature(const SkPoint src[4], SkScalar tValues[3])
+{
+       SkFP    coeffX[4], coeffY[4];
+       int             i;
+
+       formulate_F1DotF2(&src[0].fX, coeffX);
+       formulate_F1DotF2(&src[0].fY, coeffY);
+
+       for (i = 0; i < 4; i++)
+               coeffX[i] = SkFPAdd(coeffX[i],coeffY[i]);
+
+       SkScalar        t[3];
+       int                     count = solve_cubic_polynomial(coeffX, t);
+       int                     maxCount = 0;
+
+       // now remove extrema where the curvature is zero (mins)
+       // !!!! need a test for this !!!!
+       for (i = 0; i < count; i++)
+       {
+               // if (not_min_curvature())
+               if (t[i] > kMinTValueForChopping && t[i] < SK_Scalar1 - kMinTValueForChopping)
+                       tValues[maxCount++] = t[i];
+       }
+       return maxCount;
+}
+
+int SkChopCubicAtMaxCurvature(const SkPoint src[4], SkPoint dst[13], SkScalar tValues[3])
+{
+       SkScalar        t_storage[3];
+
+       if (tValues == nil)
+               tValues = t_storage;
+
+       int     count = SkFindCubicMaxCurvature(src, tValues);
+
+       if (dst)
+       {
+               if (count == 0)
+                       memcpy(dst, src, 4 * sizeof(SkPoint));
+               else
+                       SkChopCubicAt(src, dst, tValues, count);
+       }
+       return count + 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+/*     Find t value for quadratic [a, b, c] = d.
+       Return 0 if there is no solution
+*/
+static SkScalar quad_solve(SkScalar a, SkScalar b, SkScalar c, SkScalar d)
+{
+       // At^2 + Bt + C = d
+       SkScalar A = a - 2 * b + c;
+       SkScalar B = 2 * (b - a);
+       SkScalar C = a - d;
+
+       SkScalar        roots[2];
+       int                     count = SkFindUnitQuadRoots(A, B, C, roots);
+
+       SkASSERT(count <= 1);
+       return count == 1 ? roots[0] : 0;
+}
+
+/* given a quad-curve and a point (x,y), chop the quad at that point and return
+       the new quad's offCurve point.
+*/
+static bool quad_pt2OffCurve(const SkPoint quad[3], SkScalar x, SkScalar y, SkPoint* offCurve)
+{
+       SkScalar t;
+       SkPoint tmp[5];
+
+       if (SkScalarAbs(x) < SkScalarAbs(y))
+               t = quad_solve(quad[0].fX, quad[1].fX, quad[2].fX, x);
+       else
+               t = quad_solve(quad[0].fY, quad[1].fY, quad[2].fY, y);
+
+       if (t > 0)
+       {
+               SkChopQuadAt(quad, tmp, t);
+               *offCurve = tmp[1];
+               return true;
+       }
+       return false;
+}
+
+static const SkPoint gQuadCirclePts[kSkBuildQuadArcStorage] = {
+       { SK_Scalar1,                   0                               },
+       { SK_Scalar1,                   SK_ScalarTanPIOver8     },
+       { SK_ScalarRoot2Over2,  SK_ScalarRoot2Over2     },
+       { SK_ScalarTanPIOver8,  SK_Scalar1                      },
+
+       { 0,                                    SK_Scalar1              },
+       { -SK_ScalarTanPIOver8, SK_Scalar1      },
+       { -SK_ScalarRoot2Over2, SK_ScalarRoot2Over2     },
+       { -SK_Scalar1,                  SK_ScalarTanPIOver8     },
+
+       { -SK_Scalar1,                  0                               },
+       { -SK_Scalar1,                  -SK_ScalarTanPIOver8    },
+       { -SK_ScalarRoot2Over2, -SK_ScalarRoot2Over2    },
+       { -SK_ScalarTanPIOver8, -SK_Scalar1             },
+
+       { 0,                                    -SK_Scalar1             },
+       { SK_ScalarTanPIOver8,  -SK_Scalar1             },
+       { SK_ScalarRoot2Over2,  -SK_ScalarRoot2Over2    },
+       { SK_Scalar1,                   -SK_ScalarTanPIOver8    },
+
+       { SK_Scalar1,                   0       }
+};
+
+int SkBuildQuadArc(const SkVector& uStart, const SkVector& uStop,
+                                  SkRotationDirection dir, const SkMatrix* userMatrix,
+                                  SkPoint quadPoints[])
+{
+       // check for (effectively) coincident vectors
+       {
+               SkScalar dot = SkScalarMul(uStart.fX, uStop.fX) + SkScalarMul(uStart.fY, uStop.fY);
+               if (SkScalarAbs(dot - SK_Scalar1) <= SK_ScalarNearlyZero)
+                       return 0;
+       }
+       // rotate unitStop so that unitStart is at (1,0)
+       SkScalar x = SkScalarMul(uStop.fX, uStart.fX) + SkScalarMul(uStop.fY, uStart.fY);
+       SkScalar y = SkScalarMul(uStop.fY, uStart.fX) - SkScalarMul(uStop.fX, uStart.fY);
+
+       if (dir == kCCW_SkRotationDirection)
+               y = -y;
+
+       // what octant (quadratic curve) is [xy] in?
+       int     oct = 0;
+       bool sameSign = true;
+
+       if (y < 0)
+               oct += 4;
+       if ((x < 0) != (y < 0))
+       {
+               oct += 2;
+               sameSign = false;
+       }
+       if ((SkScalarAbs(x) < SkScalarAbs(y)) == sameSign)
+               oct += 1;
+
+       if (SkScalarAbs(y) >= SK_Scalar1 || x <= -SK_Scalar1)
+               oct += 1;
+
+       int     wholeCount = oct << 1;
+       memcpy(quadPoints, gQuadCirclePts, (wholeCount + 1) * sizeof(SkPoint));
+
+       const SkPoint* arc = &gQuadCirclePts[wholeCount];
+       if (quad_pt2OffCurve(arc, x, y, &quadPoints[wholeCount + 1]))
+       {
+               quadPoints[wholeCount + 2].set(x, y);
+               wholeCount += 2;
+       }
+       wholeCount += 1;
+
+       // now handle counter-clockwise and the initial unitStart rotation
+       SkMatrix        matrix;
+       matrix.setSinCos(uStart.fY, uStart.fX, 0, 0);
+       if (dir == kCCW_SkRotationDirection)
+               matrix.preScale(SK_Scalar1, -SK_Scalar1, 0, 0);
+       if (userMatrix)
+               matrix.postConcat(*userMatrix);
+       matrix.mapPoints(quadPoints, wholeCount);
+       return wholeCount;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+void SkGeometry::UnitTest()
+{
+#ifdef SK_SUPPORT_UNITTEST
+       SkPoint pts[3], dst[5];
+
+       pts[0].set(0, 0);
+       pts[1].set(100, 50);
+       pts[2].set(0, 100);
+
+       int count = SkChopQuadAtMaxCurvature(pts, dst);
+       SkASSERT(count == 1 || count == 2);
+#endif
+}
+
+#endif
+
+
diff --git a/libs/graphics/sgl/SkGeometry.h b/libs/graphics/sgl/SkGeometry.h
new file mode 100644 (file)
index 0000000..a76dfc2
--- /dev/null
@@ -0,0 +1,146 @@
+#ifndef SkGeometry_DEFINED
+#define SkGeometry_DEFINED
+
+#include "SkMatrix.h"
+
+/**    Given a quadratic equation Ax^2 + Bx + C = 0, return 0, 1, 2 roots for the
+       equation.
+*/
+int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2]);
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**    Set pt to the point on the src quadratic specified by t. t must be
+       0 <= t <= 1.0
+*/
+void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint* pt, SkVector* tangent = nil);
+void SkEvalQuadAtHalf(const SkPoint src[3], SkPoint* pt, SkVector* tangent = nil);
+
+/**    Given a src quadratic bezier, chop it at the specified t value,
+       where 0 < t < 1, and return the two new quadratics in dst:
+       dst[0..2] and dst[2..4]
+*/
+void SkChopQuadAt(const SkPoint src[3], SkPoint dst[5], SkScalar t);
+
+/**    Given a src quadratic bezier, chop it at the specified t == 1/2,
+       The new quads are returned in dst[0..2] and dst[2..4]
+*/
+void SkChopQuadAtHalf(const SkPoint src[3], SkPoint dst[5]);
+
+/**    Given the 3 coefficients for a quadratic bezier (either X or Y values), look
+       for extrema, and return the number of t-values that are found that represent
+       these extrema. If the quadratic has no extrema betwee (0..1) exclusive, the
+       function returns 0.
+       Returned count          tValues[]
+       0                                       ignored
+       1                                       0 < tValues[0] < 1
+*/
+int SkFindQuadExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar tValues[1]);
+
+/**    Given 3 points on a quadratic bezier, chop it into 1, 2 beziers such that
+       the resulting beziers are monotonic in Y. This is called by the scan converter.
+       Depending on what is returned, dst[] is treated as follows
+       1       dst[0..2] is the original quad
+       2       dst[0..2] and dst[2..4] are the two new quads
+       If dst == nil, it is ignored and only the count is returned.
+*/
+int SkChopQuadAtYExtrema(const SkPoint src[3], SkPoint dst[5]);
+
+/**    Given 3 points on a quadratic bezier, divide it into 2 quadratics
+       if the point of maximum curvature exists on the quad segment.
+       Depending on what is returned, dst[] is treated as follows
+       1       dst[0..2] is the original quad
+       2       dst[0..2] and dst[2..4] are the two new quads
+       If dst == nil, it is ignored and only the count is returned.
+*/
+int SkChopQuadAtMaxCurvature(const SkPoint src[3], SkPoint dst[5]);
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+/**    Convert from parametric from (pts) to polynomial coefficients
+       coeff[0]*T^3 + coeff[1]*T^2 + coeff[2]*T + coeff[3]
+*/
+void SkGetCubicCoeff(const SkPoint pts[4], SkScalar cx[4], SkScalar cy[4]);
+
+/**    Set pt to the point on the src cubic specified by t. t must be
+       0 <= t <= 1.0
+*/
+void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint* locOrNil, SkVector* tangentOrNil, SkVector* curvatureOrNil);
+
+/**    Given a src cubic bezier, chop it at the specified t value,
+       where 0 < t < 1, and return the two new cubics in dst:
+       dst[0..3] and dst[3..6]
+*/
+void SkChopCubicAt(const SkPoint src[4], SkPoint dst[7], SkScalar t);
+void SkChopCubicAt(const SkPoint src[4], SkPoint dst[7], const SkScalar t[], int t_count);
+
+/**    Given a src cubic bezier, chop it at the specified t == 1/2,
+       The new cubics are returned in dst[0..3] and dst[3..6]
+*/
+void SkChopCubicAtHalf(const SkPoint src[4], SkPoint dst[7]);
+
+/**    Given the 4 coefficients for a cubic bezier (either X or Y values), look
+       for extrema, and return the number of t-values that are found that represent
+       these extrema. If the cubic has no extrema betwee (0..1) exclusive, the
+       function returns 0.
+       Returned count          tValues[]
+       0                                       ignored
+       1                                       0 < tValues[0] < 1
+       2                                       0 < tValues[0] < tValues[1] < 1
+*/
+int SkFindCubicExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar d, SkScalar tValues[2]);
+
+/**    Given 4 points on a cubic bezier, chop it into 1, 2, 3 beziers such that
+       the resulting beziers are monotonic in Y. This is called by the scan converter.
+       Depending on what is returned, dst[] is treated as follows
+       1       dst[0..3] is the original cubic
+       2       dst[0..3] and dst[3..6] are the two new cubics
+       3       dst[0..3], dst[3..6], dst[6..9] are the three new cubics
+       If dst == nil, it is ignored and only the count is returned.
+*/
+int SkChopCubicAtYExtrema(const SkPoint src[4], SkPoint dst[10]);
+
+/**    Given a cubic bezier, return 0, 1, or 2 t-values that represent the
+       inflection points.
+*/
+int SkFindCubicInflections(const SkPoint src[4], SkScalar tValues[2]);
+
+/**    Return 1 for no chop, or 2 for having chopped the cubic at its
+       inflection point.
+*/
+int SkChopCubicAtInflections(const SkPoint src[4], SkPoint dst[10]);
+
+int SkFindCubicMaxCurvature(const SkPoint src[4], SkScalar tValues[3]);
+int SkChopCubicAtMaxCurvature(const SkPoint src[4], SkPoint dst[13], SkScalar tValues[3] = nil);
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+enum SkRotationDirection {
+       kCW_SkRotationDirection,
+       kCCW_SkRotationDirection
+};
+
+/**    Maximum number of points needed in the quadPoints[] parameter for
+       SkBuildQuadArc()
+*/
+#define kSkBuildQuadArcStorage 17
+
+/**    Given 2 unit vectors and a rotation direction, fill out the specified
+       array of points with quadratic segments. Return is the number of points
+       written to, which will be { 0, 3, 5, 7, ... kSkBuildQuadArcStorage }
+
+       matrix, if not nil, is appled to the points before they are returned.
+*/
+int SkBuildQuadArc(const SkVector& unitStart, const SkVector& unitStop, SkRotationDirection,
+                                  const SkMatrix* matrix, SkPoint quadPoints[]);
+
+//////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+       class SkGeometry {
+       public:
+               static void UnitTest();
+       };
+#endif
+
+#endif
diff --git a/libs/graphics/sgl/SkGlobals.cpp b/libs/graphics/sgl/SkGlobals.cpp
new file mode 100644 (file)
index 0000000..a53cc1d
--- /dev/null
@@ -0,0 +1,75 @@
+#include "SkGlobals.h"
+#include "SkThread.h"
+
+SkGlobals::Rec::~Rec()
+{
+}
+
+SkGlobals::Rec* SkGlobals::Find(U32 tag, Rec* (*create_proc)())
+{
+       SkGlobals::BootStrap&   bootstrap = SkGlobals::GetBootStrap();
+
+       Rec* rec = bootstrap.fHead;
+       while (rec)
+       {
+               if (rec->fTag == tag)
+                       return rec;
+               rec = rec->fNext;
+       }
+
+       if (create_proc == nil) // no create proc, just return not found
+               return nil;
+
+       // if we get here, we may need to create one. First grab the mutex, and
+       // search again, creating one if its not found the 2nd time.
+
+       bootstrap.fMutex.acquire();
+
+       // search again, now that we have the mutex. Odds are it won't be there, but we check again
+       // just in case it was added by another thread before we grabbed the mutex
+
+       Rec*& head = bootstrap.fHead;
+       rec = head;
+       while (rec)
+       {
+               if (rec->fTag == tag)
+                       break;
+               rec = rec->fNext;
+       }
+
+       if (rec == nil && (rec = create_proc()) != nil)
+       {
+               rec->fTag = tag;
+               rec->fNext = head;
+               bootstrap.fHead = rec;
+       }
+
+       bootstrap.fMutex.release();
+       return rec;
+}
+
+void SkGlobals::Init()
+{
+}
+
+void SkGlobals::Term()
+{
+       SkGlobals::BootStrap&   bootstrap = SkGlobals::GetBootStrap();
+
+       bootstrap.fMutex.acquire();
+
+       Rec*&   head = bootstrap.fHead;
+       Rec*    rec = head;
+
+       while (rec)
+       {
+               Rec* next = rec->fNext;
+               SkDELETE(rec);
+               rec = next;
+       }
+
+       bootstrap.fHead = nil;
+       bootstrap.fMutex.release();
+}
+
+
diff --git a/libs/graphics/sgl/SkGlyphCache.cpp b/libs/graphics/sgl/SkGlyphCache.cpp
new file mode 100644 (file)
index 0000000..60d0ba3
--- /dev/null
@@ -0,0 +1,234 @@
+#include "SkGlyphCache.h"
+#include "SkPaint.h"
+#include "SkTemplates.h"
+
+//////////////////////////////////////////////////////////////////////
+
+#define kMinGlphAlloc          (sizeof(SkGlyph) * 64)
+#define kMinImageAlloc         (24 * 64)       // this guy should be pointsize-dependent IMHO
+
+/*  We use this local function instead of the static class method to work around
+    a bug in gcc98
+*/
+void SkDescriptor_Free(SkDescriptor* desc);
+void SkDescriptor_Free(SkDescriptor* desc)
+{
+    SkDescriptor::Free(desc);
+}
+
+SkGlyphCache::SkGlyphCache(const SkDescriptor* desc)
+       : fGlyphAlloc(kMinGlphAlloc), fImageAlloc(kMinImageAlloc)
+{
+       fNext = NULL;
+       fDesc = desc->copy();
+       SkAutoTCallProc<SkDescriptor, SkDescriptor_Free> autoFree(fDesc);
+       fScalerContext = SkScalerContext::Create(desc);
+       memset(fHash, 0, sizeof(fHash));
+
+       fScalerContext->getLineHeight(&fAbove, &fBelow);
+       (void)autoFree.detach();
+}
+
+SkGlyphCache::~SkGlyphCache()
+{
+       SkGlyph**       gptr = fGlyphArray.begin();
+       SkGlyph**       stop = fGlyphArray.end();
+       while (gptr < stop)
+       {
+               SkPath* path = (*gptr)->fPath;
+               if (path)
+                       SkDELETE(path);
+               gptr += 1;
+       }
+       SkDescriptor::Free(fDesc);
+       SkDELETE(fScalerContext);
+}
+
+const SkGlyph& SkGlyphCache::lookupMetrics(SkUnichar charCode)
+{
+       SkGlyph* glyph;
+
+       int             hi = 0;
+       int             count = fGlyphArray.count();
+
+       if (count)
+       {
+               SkGlyph**       gptr = fGlyphArray.begin();
+               int             lo = 0;
+
+               hi = count - 1;
+               while (lo < hi)
+               {
+                       int mid = (hi + lo) >> 1;
+                       if (gptr[mid]->fCharCode < charCode)
+                               lo = mid + 1;
+                       else
+                               hi = mid;
+               }
+               glyph = gptr[hi];
+               if (glyph->fCharCode == charCode)
+                       goto DONE;
+
+               // check if we need to bump hi before falling though to the allocator
+               if (glyph->fCharCode < charCode)
+                       hi += 1;
+       }
+
+       // not found, but hi tells us where to inser the new glyph
+
+       glyph = (SkGlyph*)fGlyphAlloc.alloc(sizeof(SkGlyph), SkChunkAlloc::kThrow_AllocFailType);
+       glyph->fCharCode = SkToU16(charCode);
+       glyph->fImage = NULL;
+       glyph->fPath = NULL;
+       fScalerContext->getMetrics(glyph);
+       *fGlyphArray.insert(hi) = glyph;
+
+DONE:
+       fHash[charCode & kHashMask] = glyph;
+       return *glyph;
+}
+
+const void* SkGlyphCache::findImage(SkUnichar uni)
+{
+       // cast away the constness, so we can update fImage if needed
+       SkGlyph* glyph = (SkGlyph*)&this->getMetrics(uni);
+
+       if (glyph->fWidth)
+       {
+               if (glyph->fImage == NULL)
+               {
+                       size_t  size = glyph->computeImageSize();
+                       glyph->fImage = fImageAlloc.alloc(size, SkChunkAlloc::kReturnNil_AllocFailType);
+                       fScalerContext->getImage(*glyph);
+               }
+       }
+       return glyph->fImage;
+}
+
+const SkPath* SkGlyphCache::findPath(SkUnichar uni)
+{
+       // cast away the constness, so we can update fImage if needed
+       SkGlyph* glyph = (SkGlyph*)&this->getMetrics(uni);
+
+       if (glyph->fWidth)
+       {
+               if (glyph->fPath == NULL)
+               {
+                       glyph->fPath = SkNEW(SkPath);
+                       fScalerContext->getPath(*glyph, glyph->fPath);
+               }
+       }
+       return glyph->fPath;
+}
+
+void SkGlyphCache::getLineHeight(SkPoint* above, SkPoint* below)
+{
+       if (above)
+               *above = fAbove;
+       if (below)
+               *below = fBelow;
+}
+
+/////////////////////////////////////////////////////////////////
+
+SkGlyphCache* SkGlyphCache::DetachCache(const SkPaint& paint, const SkMatrix* matrix)
+{
+       return paint.detachCache(matrix);
+}
+
+#include "SkGlobals.h"
+#include "SkThread.h"
+
+#define SkGlyphCache_GlobalsTag                SkSetFourByteTag('g', 'l', 'f', 'c')
+
+class SkGlyphCache_Globals : public SkGlobals::Rec {
+public:
+       SkMutex                 fMutex;
+       SkGlyphCache*   fHead;
+};
+
+#ifdef SK_USE_RUNTIME_GLOBALS
+       static SkGlobals::Rec* create_globals()
+       {
+               SkGlyphCache_Globals* rec = SkNEW(SkGlyphCache_Globals);
+               rec->fHead = NULL;
+               return rec;
+       }
+
+       #define FIND_GC_GLOBALS()       *(SkGlyphCache_Globals*)SkGlobals::Find(SkGlyphCache_GlobalsTag, create_globals)
+       #define GET_GC_GLOBALS()        *(SkGlyphCache_Globals*)SkGlobals::Get(SkGlyphCache_GlobalsTag)
+#else
+       static SkGlyphCache_Globals     gGCGlobals;
+       #define FIND_GC_GLOBALS()       gGCGlobals
+       #define GET_GC_GLOBALS()        gGCGlobals
+#endif
+
+SkGlyphCache* SkGlyphCache::DetachCache(const SkDescriptor* desc)
+{
+       SkASSERT(desc);
+
+       SkGlyphCache_Globals& globals = FIND_GC_GLOBALS();
+
+       globals.fMutex.acquire();
+       SkGlyphCache*   cache = globals.fHead;
+       SkGlyphCache*   prev = NULL;
+
+       while (cache)
+       {
+               SkGlyphCache* next = cache->fNext;
+
+               if (*cache->fDesc == *desc)
+               {
+                       if (prev)
+                               prev->fNext = next;
+                       else
+                               globals.fHead = next;
+                       cache->fNext = NULL;
+                       break;
+               }
+               prev = cache;
+               cache = next;
+       }
+       globals.fMutex.release();
+
+       if (cache == NULL)
+               cache = SkNEW_ARGS(SkGlyphCache, (desc));
+       return cache;
+}
+
+void SkGlyphCache::AttachCache(SkGlyphCache* cache)
+{
+       SkASSERT(cache);
+       SkASSERT(cache->fNext == NULL);
+
+       SkGlyphCache_Globals& globals = GET_GC_GLOBALS();
+
+       globals.fMutex.acquire();
+
+       cache->fNext = globals.fHead;
+       globals.fHead = cache;
+
+       globals.fMutex.release();
+}
+
+bool SkGlyphCache::FreeCache(size_t bytesNeeded)
+{
+       SkGlyphCache_Globals& globals = FIND_GC_GLOBALS();
+
+       globals.fMutex.acquire();
+       SkGlyphCache*   cache = globals.fHead;
+       bool                    didSomething = (cache != NULL);
+
+       while (cache)
+       {
+               SkGlyphCache* next = cache->fNext;
+               SkDELETE(cache);
+               cache = next;
+       }
+
+       globals.fHead = NULL;
+       globals.fMutex.release();
+
+       return didSomething;
+}
+
diff --git a/libs/graphics/sgl/SkGlyphCache.h b/libs/graphics/sgl/SkGlyphCache.h
new file mode 100644 (file)
index 0000000..20a7ace
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef SkGlyphCache_DEFINED
+#define SkGlyphCache_DEFINED
+
+#include "SkBitmap.h"
+#include "SkChunkAlloc.h"
+#include "SkDescriptor.h"
+#include "SkScalerContext.h"
+#include "SkTemplates.h"
+
+class SkPaint;
+
+class SkGlyphCache {
+public:
+       const SkGlyph& getMetrics(SkUnichar charCode)
+       {
+               int              hash = charCode & kHashMask;
+               SkGlyph* glyph = fHash[hash];
+
+               if (glyph != nil && glyph->fCharCode == charCode)
+                       return *glyph;
+               return this->lookupMetrics(charCode);
+       }
+
+
+       const void*             findImage(SkUnichar);
+       const SkPath*   findPath(SkUnichar);
+       void                    getLineHeight(SkPoint* above, SkPoint* below);
+
+       static SkGlyphCache* DetachCache(const SkPaint&, const SkMatrix* matrix);
+       static SkGlyphCache* DetachCache(const SkDescriptor*);
+       static void                      AttachCache(SkGlyphCache*);
+       static bool                      FreeCache(size_t bytesNeeded);
+
+private:
+       SkGlyphCache(const SkDescriptor*);
+       ~SkGlyphCache();
+
+       const SkGlyph& lookupMetrics(SkUnichar charCode);
+
+       SkGlyphCache*           fNext;
+       SkDescriptor*           fDesc;
+       SkScalerContext*        fScalerContext;
+
+       enum {
+               kHashBits       = 6,
+               kHashCount      = 1 << kHashBits,
+               kHashMask       = kHashCount - 1
+       };
+       SkGlyph*                        fHash[kHashCount];
+       SkTDArray<SkGlyph*>     fGlyphArray;
+       SkChunkAlloc            fGlyphAlloc;
+       SkChunkAlloc            fImageAlloc;
+
+       SkPoint fAbove, fBelow;
+};
+
+class SkAutoGlyphCache {
+public:
+       SkAutoGlyphCache(SkGlyphCache* cache) : fCache(cache) {}
+       SkAutoGlyphCache(const SkDescriptor* desc)
+       {
+               fCache = SkGlyphCache::DetachCache(desc);
+       }
+       SkAutoGlyphCache(const SkPaint& paint, const SkMatrix* matrix)
+       {
+               fCache = SkGlyphCache::DetachCache(paint, matrix);
+       }
+       ~SkAutoGlyphCache()
+       {
+               if (fCache)
+                       SkGlyphCache::AttachCache(fCache);
+       }
+
+       SkGlyphCache*   getCache() const { return fCache; }
+
+       void release()
+       {
+               if (fCache)
+               {
+                       SkGlyphCache::AttachCache(fCache);
+                       fCache = nil;
+               }
+       }
+private:
+       SkGlyphCache*   fCache;
+};
+
+#endif
+
diff --git a/libs/graphics/sgl/SkGraphics.cpp b/libs/graphics/sgl/SkGraphics.cpp
new file mode 100644 (file)
index 0000000..82c9a68
--- /dev/null
@@ -0,0 +1,143 @@
+#include "SkGraphics.h"
+
+#include "Sk64.h"
+#include "SkBlitter.h"
+#include "SkCanvas.h"
+#include "SkDeque.h"
+#include "SkDOM.h"
+#include "SkFloat.h"
+#include "SkGeometry.h"
+#include "SkGlobals.h"
+#include "SkMath.h"
+#include "SkMatrix.h"
+#include "SkPath.h"
+#include "SkPathEffect.h"
+#include "SkPathMeasure.h"
+#include "SkRefCnt.h"
+#include "SkShader.h"
+#include "SkStream.h"
+#include "SkTSearch.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+
+#define typesizeline(type)     { #type , sizeof(type) }
+#define unittestline(type)     { #type , type::UnitTest }
+
+
+#ifdef BUILD_EMBOSS_TABLE
+       extern void SkEmbossMask_BuildTable();
+#endif
+
+#ifdef BUILD_RADIALGRADIENT_TABLE
+       extern void SkRadialGradient_BuildTable();
+#endif
+
+void SkGraphics::Init(bool runUnitTests)
+{
+       SkGlobals::Init();
+
+#ifdef BUILD_EMBOSS_TABLE
+       SkEmbossMask_BuildTable();
+#endif
+#ifdef BUILD_RADIALGRADIENT_TABLE
+       SkRadialGradient_BuildTable();
+#endif
+
+#ifdef SK_SUPPORT_UNITTEST
+       if (runUnitTests == false)
+               return;
+       int i;
+
+       static const struct {
+               const char*     fTypeName;
+               size_t          fSizeOf;
+       } gTypeSize[] = {
+               typesizeline(char),
+               typesizeline(short),
+               typesizeline(int),
+               typesizeline(long),
+               typesizeline(size_t),
+               typesizeline(void*),
+
+               typesizeline(S8),
+               typesizeline(U8),
+               typesizeline(S16),
+               typesizeline(U16),
+               typesizeline(S32),
+               typesizeline(U32),
+               typesizeline(S8CPU),
+               typesizeline(U8CPU),
+               typesizeline(S16CPU),
+               typesizeline(U16CPU),
+
+               typesizeline(SkPoint),
+               typesizeline(SkRect),
+               typesizeline(SkMatrix),
+               typesizeline(SkPath),
+               typesizeline(SkRefCnt),
+
+               typesizeline(SkPaint),
+               typesizeline(SkCanvas),
+               typesizeline(SkBlitter),
+               typesizeline(SkShader),
+               typesizeline(SkXfermode),
+               typesizeline(SkPathEffect)
+       };
+
+       {
+               char    test = (char)(0-1);     // use this subtract to avoid truncation warnings (in VC7 at least)
+               if (test < 0)
+                       SkDebugf("SkGraphics: char is signed\n");
+               else
+                       SkDebugf("SkGraphics: char is unsigned\n");
+       }
+       for (i = 0; i < (int)SK_ARRAY_COUNT(gTypeSize); i++)
+               SkDebugf("SkGraphics: sizeof(%s) = %d\n", gTypeSize[i].fTypeName, gTypeSize[i].fSizeOf);
+
+       static const struct {
+               const char*     fTypeName;
+               void (*fUnitTest)();
+       } gUnitTests[] = {
+               unittestline(Sk64),
+               unittestline(SkMath),
+               unittestline(SkUtils),
+               unittestline(SkString),
+               unittestline(SkFloat),
+               unittestline(SkMatrix),
+               unittestline(SkGeometry),
+        unittestline(SkDeque),
+               unittestline(SkPath),
+               unittestline(SkPathMeasure)
+       };
+
+       for (i = 0; i < (int)SK_ARRAY_COUNT(gUnitTests); i++)
+       {
+               SkDebugf("SkGraphics: Running UnitTest for %s\n", gUnitTests[i].fTypeName);
+               gUnitTests[i].fUnitTest();
+               SkDebugf("SkGraphics: End UnitTest for %s\n", gUnitTests[i].fTypeName);
+       }
+       SkQSort_UnitTest();
+
+#endif
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+#include "SkGlyphCache.h"
+#include "SkImageDecoder.h"
+
+void SkGraphics::Term()
+{
+       SkBitmapRef::PurgeCacheAll();
+       SkGraphics::FreeCaches(SK_MaxS32);
+       SkGlobals::Term();
+}
+
+bool SkGraphics::FreeCaches(size_t bytesNeeded)
+{
+       bool didSomething = SkBitmapRef::PurgeCacheOne();
+
+       return SkGlyphCache::FreeCache(bytesNeeded) || didSomething;
+}
+
+
diff --git a/libs/graphics/sgl/SkMaskFilter.cpp b/libs/graphics/sgl/SkMaskFilter.cpp
new file mode 100644 (file)
index 0000000..a23b44e
--- /dev/null
@@ -0,0 +1,69 @@
+#include "SkMaskFilter.h"
+#include "SkBlitter.h"
+#include "SkBounder.h"
+#include "SkBuffer.h"
+#include "SkDraw.h"
+#include "SkRegion.h"
+
+size_t SkMask::computeImageSize() const
+{
+       return fBounds.height() * fRowBytes;
+}
+
+size_t SkMask::computeTotalImageSize() const
+{
+       size_t size = this->computeImageSize();
+
+       if (fFormat == SkMask::k3D_Format)
+               size *= 3;
+       return size;
+}
+
+uint8_t* SkMask::AllocImage(size_t size)
+{
+       return (uint8_t*)sk_malloc_throw(SkAlign4(size));
+}
+
+void SkMask::FreeImage(uint8_t* image)
+{
+       sk_free(image);
+}
+
+bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&, SkPoint16*)
+{
+       return false;
+}
+
+bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix,
+                                                         const SkRegion& clip, SkBounder* bounder,
+                                                         SkBlitter* blitter)
+{
+       SkMask  srcM, dstM;
+
+    if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), this, &matrix, &srcM,
+                            SkMask::kComputeBoundsAndRenderImage_CreateMode))
+    {
+        return false;
+    }
+
+       SkAutoMaskImage autoSrc(&srcM, false);
+
+       if (!this->filterMask(&dstM, srcM, matrix, NULL))
+               return false;
+
+       SkAutoMaskImage                 autoDst(&dstM, false);
+       SkRegion::Cliperator    clipper(clip, dstM.fBounds);
+
+       if (!clipper.done() && (bounder == NULL || bounder->doIRect(dstM.fBounds, clip)))
+       {
+               const SkRect16& cr = clipper.rect();
+               do {
+                       blitter->blitMask(dstM, cr);
+                       clipper.next();
+               } while (!clipper.done());
+       }
+
+       return true;
+}
+
+
diff --git a/libs/graphics/sgl/SkPaint.cpp b/libs/graphics/sgl/SkPaint.cpp
new file mode 100644 (file)
index 0000000..2321684
--- /dev/null
@@ -0,0 +1,868 @@
+#include "SkPaint.h"
+#include "SkColorFilter.h"
+#include "SkFontHost.h"
+#include "SkMaskFilter.h"
+#include "SkPathEffect.h"
+#include "SkRasterizer.h"
+#include "SkShader.h"
+#include "SkScalerContext.h"
+#include "SkStroke.h"
+#include "SkTextLayout.h"
+#include "SkTypeface.h"
+#include "SkXfermode.h"
+
+#define SK_DefaultTextSize             SkIntToScalar(12)
+
+SkPaint::SkPaint()
+{
+       fTypeface       = NULL;
+       fTextSize       = SK_DefaultTextSize;
+       fTextScaleX     = SK_Scalar1;
+       fTextSkewX      = 0;
+
+       fPathEffect     = NULL;
+       fShader         = NULL;
+       fXfermode       = NULL;
+       fMaskFilter     = NULL;
+    fColorFilter = NULL;
+    fTextLayout = NULL;
+    fRasterizer = NULL;
+
+       fColor          = SK_ColorBLACK;
+       fWidth          = 0;
+       fMiterLimit     = SK_DefaultMiterLimit;
+       fFlags          = 0;
+       fCapType        = kDefault_Cap;
+       fJoinType       = kDefault_Join;
+       fFilterType     = kNo_FilterType;
+       fTextAlign      = kLeft_Align;
+       fStyle          = kFill_Style;
+}
+
+SkPaint::SkPaint(const SkPaint& src)
+{
+       memcpy(this, &src, sizeof(src));
+
+       fTypeface->safeRef();
+       fPathEffect->safeRef();
+       fShader->safeRef();
+       fXfermode->safeRef();
+       fMaskFilter->safeRef();
+       fColorFilter->safeRef();
+    fTextLayout->safeRef();
+    fRasterizer->safeRef();
+}
+
+SkPaint::~SkPaint()
+{
+       fTypeface->safeUnref();
+       fPathEffect->safeUnref();
+       fShader->safeUnref();
+       fXfermode->safeUnref();
+       fMaskFilter->safeUnref();
+       fColorFilter->safeUnref();
+    fTextLayout->safeUnref();
+    fRasterizer->safeUnref();
+}
+
+SkPaint& SkPaint::operator=(const SkPaint& src)
+{
+       SkASSERT(&src);
+
+       src.fTypeface->safeRef();
+       src.fPathEffect->safeRef();
+       src.fShader->safeRef();
+       src.fXfermode->safeRef();
+       src.fMaskFilter->safeRef();
+       src.fColorFilter->safeRef();
+       src.fTextLayout->safeRef();
+       src.fRasterizer->safeRef();
+
+       fTypeface->safeUnref();
+       fPathEffect->safeUnref();
+       fShader->safeUnref();
+       fXfermode->safeUnref();
+       fMaskFilter->safeUnref();
+       fColorFilter->safeUnref();
+       fTextLayout->safeUnref();
+       fRasterizer->safeUnref();
+
+       memcpy(this, &src, sizeof(src));
+
+       return *this;
+}
+
+int operator==(const SkPaint& a, const SkPaint& b)
+{
+       return memcmp(&a, &b, sizeof(a)) == 0;
+}
+
+void SkPaint::reset()
+{
+       SkPaint init;
+
+       *this = init;
+}
+
+void SkPaint::setFlags(U32 flags)
+{
+       fFlags = SkToU8(flags);
+}
+
+void SkPaint::setAntiAliasOn(bool doAA)
+{
+       this->setFlags(SkSetClear32(fFlags, doAA, kAntiAlias_Shift));
+}
+
+void SkPaint::setLinearTextOn(bool doLinearText)
+{
+       this->setFlags(SkSetClear32(fFlags, doLinearText, kLinearText_Shift));
+}
+
+void SkPaint::setUnderlineTextOn(bool doUnderline)
+{
+       this->setFlags(SkSetClear32(fFlags, doUnderline, kUnderlineText_Shift));
+}
+
+void SkPaint::setStrikeThruTextOn(bool doStrikeThru)
+{
+       this->setFlags(SkSetClear32(fFlags, doStrikeThru, kStrikeThruText_Shift));
+}
+
+void SkPaint::setFakeBoldTextOn(bool doFakeBold)
+{
+       this->setFlags(SkSetClear32(fFlags, doFakeBold, kFakeBoldText_Shift));
+}
+
+void SkPaint::setStyle(Style style)
+{
+       SkASSERT((unsigned)style < kStyleCount);
+       fStyle = style;
+}
+
+void SkPaint::setColor(SkColor color)
+{
+       fColor = color;
+}
+
+void SkPaint::setAlpha(U8CPU a)
+{
+       fColor = SkColorSetARGB(a, SkColorGetR(fColor), SkColorGetG(fColor), SkColorGetB(fColor));
+}
+
+void SkPaint::setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
+{
+       fColor = SkColorSetARGB(a, r, g, b);
+}
+
+void SkPaint::setStrokeWidth(SkScalar width)
+{
+       SkASSERT(width >= 0);
+       fWidth = width;
+}
+
+void SkPaint::setStrokeMiter(SkScalar limit)
+{
+       SkASSERT(limit >= 0);
+       fMiterLimit = limit;
+}
+
+void SkPaint::setStrokeCap(Cap ct)
+{
+       SkASSERT((unsigned)ct < kCapCount);
+       fCapType = SkToU8(ct);
+}
+
+void SkPaint::setStrokeJoin(Join jt)
+{
+       SkASSERT((unsigned)jt < kJoinCount);
+       fJoinType = SkToU8(jt);
+}
+
+void SkPaint::setFilterType(FilterType ft)
+{
+       SkASSERT((unsigned)ft < kFilterTypeCount);
+       fFilterType = SkToU8(ft);
+}
+
+//////////////////////////////////////////////////////////////////
+
+void SkPaint::setTextAlign(Align align)
+{
+       SkASSERT((unsigned)align < kAlignCount);
+       fTextAlign = SkToU8(align);
+}
+
+void SkPaint::setTextSize(SkScalar ts)
+{
+       SkASSERT(ts > 0);
+       fTextSize = ts;
+}
+
+void SkPaint::setTextScaleX(SkScalar scaleX)
+{
+       fTextScaleX = scaleX;
+}
+
+void SkPaint::setTextSkewX(SkScalar skewX)
+{
+       fTextSkewX = skewX;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+SkTextLayout* SkPaint::setTextLayout(SkTextLayout* layout)
+{
+    SkRefCnt_SafeAssign(fTextLayout, layout);
+    return layout;
+}
+
+SkTypeface* SkPaint::setTypeface(SkTypeface* font)
+{
+       SkRefCnt_SafeAssign(fTypeface, font);
+       return font;
+}
+
+SkRasterizer* SkPaint::setRasterizer(SkRasterizer* r)
+{
+    SkRefCnt_SafeAssign(fRasterizer, r);
+    return r;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkGlyphCache.h"
+#include "SkUtils.h"
+
+class SkAutoRestorePaintTextSizeAndFrame {
+public:
+       SkAutoRestorePaintTextSizeAndFrame(const SkPaint* paint) : fPaint((SkPaint*)paint)
+       {
+               fTextSize = paint->getTextSize();
+               fStyle = paint->getStyle();
+               fPaint->setStyle(SkPaint::kFill_Style);
+       }
+       ~SkAutoRestorePaintTextSizeAndFrame()
+       {
+               fPaint->setStyle(fStyle);
+               fPaint->setTextSize(fTextSize);
+       }
+    
+private:
+       SkPaint*                fPaint;
+       SkScalar                fTextSize;
+       SkPaint::Style  fStyle;
+};
+
+static SkScalar measure_text(const SkPaint& paint, SkGlyphCache* cache,
+                             SkUnicodeWalkerProc proc, const char* text, size_t byteLength,
+                             int* count)
+{
+       SkASSERT(count);
+
+       SkFixed         x = 0;
+       int             n;
+    SkTextLayout*   layout = paint.getTextLayout();
+    
+    if (layout)
+    {
+        SkAutoSTMalloc<32, SkTextLayout::Rec>   storage(byteLength);
+        SkTextLayout::Rec*                      rec = storage.get();
+
+        n = layout->layout(paint, text, byteLength, proc, rec);
+        for (int i = 0; i < n; i++)
+        {
+            // should pass rec[i].glyphID when we have it
+            x += cache->getMetrics(rec[i].charCode()).fAdvanceX + SkScalarToFixed(rec[i].fDeltaAdvance);
+        }
+    }
+    else
+    {
+        const char*    stop = (const char*)text + byteLength;
+        for (n = 0; text < stop; n++)
+        {
+            x += cache->getMetrics(proc(&text)).fAdvanceX;
+        }
+        SkASSERT(text == stop);
+    }
+       *count = n;
+       return SkFixedToScalar(x);
+}
+
+SkScalar SkPaint::privateMeasureText(SkUnicodeWalkerProc textProc,
+                                     const char* text, size_t byteLength,
+                                     SkScalar* above, SkScalar* below) const
+{
+       SkASSERT(text != NULL || byteLength == 0);
+
+       SkScalar                            scale = 0;
+    SkAutoRestorePaintTextSizeAndFrame restore(this);
+
+       if (this->isLinearTextOn())
+       {
+               scale = fTextSize / kCanonicalTextSizeForPaths;
+               // this gets restored by restore
+               ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths));
+       }
+
+       SkAutoGlyphCache        autoCache(*this, NULL);
+       SkGlyphCache*           cache = autoCache.getCache();
+
+       if (above || below)
+       {
+               SkPoint abovePt, belowPt;
+               cache->getLineHeight(&abovePt, &belowPt);
+               if (scale)
+               {
+                       abovePt.fY = SkScalarMul(abovePt.fY, scale);
+                       belowPt.fY = SkScalarMul(belowPt.fY, scale);
+               }
+               if (above)
+                       *above = abovePt.fY;
+               if (below)
+                       *below = belowPt.fY;
+       }
+    
+    SkScalar width = 0;
+    
+    if (byteLength)
+    {
+        int count;
+        width = measure_text(*this, cache, textProc, text, byteLength, &count);
+
+        if (scale)
+            width = SkScalarMul(width, scale);
+    }
+    return width;
+}
+
+SkScalar SkPaint::measureText(const char utf8[], size_t length,
+                                                         SkScalar* above, SkScalar* below) const
+{
+    return this->privateMeasureText((SkUnicodeWalkerProc)SkUTF8_NextUnichar, utf8, length, above, below);
+}
+
+SkScalar SkPaint::measureText16(const U16 utf16[], size_t numberOf16BitValues,
+                                                         SkScalar* above, SkScalar* below) const
+{
+    return this->privateMeasureText((SkUnicodeWalkerProc)SkUTF16_NextUnichar, (const char*)utf16, numberOf16BitValues << 1, above, below);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+int SkPaint::privateGetTextWidths(const char text[], size_t byteLength,
+                                  SkScalar widths[], SkUnicodeWalkerProc proc) const
+{
+       SkASSERT(text != NULL && byteLength > 0);
+
+       SkAutoRestorePaintTextSizeAndFrame      restore(this);
+       SkScalar                                                        scale = 0;
+
+       if (this->isLinearTextOn())
+       {
+               scale = fTextSize / kCanonicalTextSizeForPaths;
+               // this gets restored by restore
+               ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths));
+       }
+
+       SkAutoGlyphCache        autoCache(*this, NULL);
+       SkGlyphCache*           cache = autoCache.getCache();
+
+    SkScalar*   w = widths;
+       const char*     stop = (const char*)text + byteLength;
+    if (scale) {
+        while (text < stop)
+            *w++ = SkScalarMul(SkFixedToScalar(cache->getMetrics(proc(&text)).fAdvanceX), scale);
+    }
+    else {
+        while (text < stop)
+            *w++ = SkFixedToScalar(cache->getMetrics(proc(&text)).fAdvanceX);
+    }
+    return w - widths;  // count
+}
+
+int SkPaint::getTextWidths(const char text[], size_t byteLength, SkScalar widths[]) const
+{
+    if (0 == byteLength)
+        return 0;
+    
+    if (NULL == widths)
+        return SkUTF8_CountUnichars(text, byteLength);
+    
+    int count = this->privateGetTextWidths(text, byteLength, widths, (SkUnicodeWalkerProc)SkUTF8_NextUnichar);
+    SkASSERT(SkUTF8_CountUnichars(text, byteLength) == count);
+    return count;
+}
+
+int SkPaint::getTextWidths16(const uint16_t text[], size_t numberOf16BitValues, SkScalar widths[]) const
+{
+    if (0 == numberOf16BitValues)
+        return 0;
+    
+    if (NULL == widths)
+        return SkUTF16_CountUnichars(text, numberOf16BitValues);
+    
+    int count = this->privateGetTextWidths((const char*)text, numberOf16BitValues << 1, widths, (SkUnicodeWalkerProc)SkUTF16_NextUnichar);
+    SkASSERT(SkUTF16_CountUnichars(text, numberOf16BitValues) == count);
+    return count;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+SkScalar SkPaint::ascent() const
+{
+    SkScalar above;
+    (void)this->measureText(NULL, 0, &above, NULL);
+    return above;
+}
+
+SkScalar SkPaint::descent() const
+{
+    SkScalar below;
+    (void)this->measureText(NULL, 0, NULL, &below);
+    return below;
+}
+
+#include "SkDraw.h"
+
+void SkPaint::privateGetTextPath(SkUnicodeWalkerProc textProc, const char text[], size_t length, SkScalar x, SkScalar y, SkPath* path) const
+{
+       SkASSERT(length == 0 || text != NULL);
+       if (text == NULL || length == 0 || path == NULL)
+               return;
+    SkASSERT(textProc);
+
+       SkTextToPathIter        iter(textProc, text, length, *this, false, true);
+       SkMatrix                        matrix;
+       SkScalar                        prevXPos = 0;
+
+       matrix.setScale(iter.getPathScale(), iter.getPathScale(), 0, 0);
+       matrix.postTranslate(x, y);
+       path->reset();
+
+       SkScalar                xpos;
+       const SkPath*   iterPath;
+       while ((iterPath = iter.next(&xpos)) != NULL)
+       {
+               matrix.postTranslate(xpos - prevXPos, 0);
+               path->addPath(*iterPath, matrix);
+               prevXPos = xpos;
+       }
+}
+
+void SkPaint::getTextPath(const char text[], size_t length, SkScalar x, SkScalar y, SkPath* path) const
+{
+    this->privateGetTextPath((SkUnicodeWalkerProc)SkUTF8_NextUnichar, text, length, x, y, path);
+}
+
+void SkPaint::getText16Path(const U16 text[], size_t numberOf16BitValues, SkScalar x, SkScalar y, SkPath* path) const
+{
+    this->privateGetTextPath((SkUnicodeWalkerProc)SkUTF16_NextUnichar, (const char*)text, numberOf16BitValues << 1, x, y, path);
+}
+
+static void add_flattenable(SkDescriptor* desc, U32 tag, U32 len, SkFlattenable* obj)
+{
+       SkFlattenable::Factory fact = obj->getFactory();
+       SkASSERT(fact);
+
+       SkWBuffer   buffer(desc->addEntry(tag, sizeof(void*) + len, NULL), sizeof(void*) + len);
+    buffer.writePtr((const void*)fact);
+    obj->flatten(buffer);
+    SkASSERT(buffer.pos() == buffer.size());
+}
+
+/*
+ *  interpolates to find the right value for key, in the function represented by the 'length' number of pairs: (keys[i], values[i])
+    inspired by a desire to change the multiplier for thickness in fakebold
+    therefore, i assumed number of pairs (length) will be small, so a linear search is sufficient
+    repeated keys are allowed for discontinuous functions (so long as keys is monotonically increasing), and if 
+       key is the value of a repeated scalar in keys, the first one will be used 
+       - this may change if a binary search is used
+       - also, this ensures that there is no divide by zero (an assert also checks for that)
+*/
+static SkScalar interpolate(SkScalar key, const SkScalar keys[], const SkScalar values[], int length)
+{
+
+    SkASSERT(length > 0);
+    SkASSERT(keys != NULL);    
+    SkASSERT(values != NULL);
+#ifdef SK_DEBUG
+    for (int i = 1; i < length; i++)
+        SkASSERT(keys[i] >= keys[i-1]);
+#endif
+    int right = 0;
+    while (right < length && key > keys[right])
+        right++;
+    //could use sentinal values to eliminate conditionals
+    //i assume i am not in control of input values, so i want to make it simple
+    if (length == right)
+        return values[length-1];
+    if (0 == right)
+        return values[0];
+    //otherwise, we interpolate between right-1 and right
+    SkScalar rVal = values[right];
+    SkScalar lVal = values[right-1];
+    SkScalar rightKey = keys[right];
+    SkScalar leftKey = keys[right-1];
+    SkASSERT(rightKey != leftKey);
+    //fractional amount which we will multiply by the difference in the left value and right value
+    SkScalar fract = SkScalarDiv(key-leftKey,rightKey-leftKey);
+    return lVal + SkScalarMul(fract, rVal-lVal);
+}
+
+//used for interpolating in fakeBold
+static const SkScalar pointSizes[] = { SkIntToScalar(9), SkIntToScalar(36) };
+static const SkScalar multipliers[] = { SK_Scalar1/24, SK_Scalar1/32 };
+
+void SkScalerContext::MakeRec(const SkPaint& paint, const SkMatrix* deviceMatrix, Rec* rec)
+{
+       SkASSERT(deviceMatrix == NULL || (deviceMatrix->getType() & SkMatrix::kPerspective_Mask) == 0);
+
+       rec->fTextSize = paint.getTextSize();
+       rec->fPreScaleX = paint.getTextScaleX();
+       rec->fPreSkewX  = paint.getTextSkewX();
+
+       if (deviceMatrix)
+       {
+               rec->fPost2x2[0][0] = deviceMatrix->getScaleX();
+               rec->fPost2x2[0][1] = deviceMatrix->getSkewX();
+               rec->fPost2x2[1][0] = deviceMatrix->getSkewY();
+               rec->fPost2x2[1][1] = deviceMatrix->getScaleY();
+       }
+       else
+       {
+               rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1;
+               rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0;
+       }
+    
+    SkPaint::Style  style = paint.getStyle();
+    SkScalar        strokeWidth = paint.getStrokeWidth();
+    
+    if (paint.isFakeBoldTextOn())
+    {
+        SkScalar fakeBoldScale = interpolate(paint.getTextSize(), pointSizes, multipliers, 2);
+        SkScalar extra = SkScalarMul(paint.getTextSize(), fakeBoldScale);
+        
+        if (style == SkPaint::kFill_Style)
+        {
+            style = SkPaint::kStrokeAndFill_Style;
+            strokeWidth = extra;    // ignore paint's strokeWidth if it was "fill"
+        }
+        else
+            strokeWidth += extra;
+    }
+
+       if (style != SkPaint::kFill_Style && strokeWidth > 0)
+       {
+               rec->fFrameWidth = strokeWidth;
+               rec->fMiterLimit = paint.getStrokeMiter();
+               rec->fFrameAndFill = SkToU8(style == SkPaint::kStrokeAndFill_Style);
+               rec->fStrokeJoin = SkToU8(paint.getStrokeJoin());
+       }
+       else
+       {
+               rec->fFrameWidth = 0;
+               rec->fMiterLimit = 0;
+               rec->fFrameAndFill = false;
+               rec->fStrokeJoin = 0;
+       }
+
+       rec->fUseHints = SkToU8(!paint.isLinearTextOn());
+       rec->fDoAA = SkToU8(paint.isAntiAliasOn());
+}
+
+SkGlyphCache* SkPaint::detachCache(const SkMatrix* deviceMatrix) const
+{
+       SkScalerContext::Rec    rec;
+
+       SkScalerContext::MakeRec(*this, deviceMatrix, &rec);
+
+       size_t                  descSize = sizeof(rec);
+       int                             entryCount = 2; // scalerrec + typeface
+       SkTypeface*             tf = this->getTypeface();
+       size_t                  tfSize = 0;
+       SkPathEffect*   pe = this->getPathEffect();
+       size_t                  peLen = 0;
+       SkMaskFilter*   mf = this->getMaskFilter();
+       size_t                  mfLen = 0;
+       SkRasterizer*   ra = this->getRasterizer();
+       size_t                  raLen = 0;
+
+    // we always do this, even if tf is NULL
+    tfSize = SkFontHost::FlattenTypeface(tf, NULL);
+    descSize += tfSize;
+
+       if (pe)
+       {
+               if (pe->getFactory())
+               {
+            SkWBuffer   buffer;
+                       pe->flatten(buffer);
+            peLen = buffer.pos();
+                       descSize += sizeof(SkFlattenable::Factory) + peLen;
+                       entryCount += 1;
+                       rec.fDoAA = true;       // force antialiasing when we do the scan conversion
+               }
+               else
+                       pe = NULL;
+       }
+       if (mf)
+       {
+               if (mf->getFactory())
+               {
+            SkWBuffer   buffer;
+            mf->flatten(buffer);
+                       mfLen = buffer.pos();
+                       descSize += sizeof(SkFlattenable::Factory) + mfLen;
+                       entryCount += 1;
+                       rec.fDoAA = true;       // force antialiasing with maskfilters
+               }
+               else
+                       mf = NULL;
+       }
+       if (ra)
+       {
+               if (ra->getFactory())
+               {
+            SkWBuffer   buffer;
+            ra->flatten(buffer);
+                       raLen = buffer.pos();
+                       descSize += sizeof(SkFlattenable::Factory) + raLen;
+                       entryCount += 1;
+                       rec.fDoAA = true;       // force antialiasing when we do the scan conversion
+               }
+               else
+                       ra = NULL;
+       }
+       descSize += SkDescriptor::ComputeOverhead(entryCount);
+
+       SkAutoDescriptor        ad(descSize);
+       SkDescriptor*           desc = ad.getDesc();
+
+       desc->init();
+       desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
+
+    // we always do this, even if tf is NULL
+    {
+        SkDEBUGCODE(size_t tfSize2 = ) SkFontHost::FlattenTypeface(tf, desc->addEntry(kTypeface_SkDescriptorTag, tfSize, NULL));
+               SkASSERT(tfSize2 == tfSize);
+       }
+
+       if (pe)
+               add_flattenable(desc, kPathEffect_SkDescriptorTag, peLen, pe);
+       if (mf)
+               add_flattenable(desc, kMaskFilter_SkDescriptorTag, mfLen, mf);
+       if (ra)
+               add_flattenable(desc, kRasterizer_SkDescriptorTag, raLen, ra);
+
+       SkASSERT(descSize == desc->getLength());
+       desc->computeChecksum();
+
+       return SkGlyphCache::DetachCache(desc);
+}
+
+//////////////////////////////////////////////////////////////////
+
+SkShader* SkPaint::setShader(SkShader* shader)
+{
+       SkRefCnt_SafeAssign(fShader, shader);
+       return shader;
+}
+
+SkColorFilter* SkPaint::setColorFilter(SkColorFilter* filter)
+{
+       SkRefCnt_SafeAssign(fColorFilter, filter);
+       return filter;
+}
+
+SkXfermode* SkPaint::setXfermode(SkXfermode* mode)
+{
+       SkRefCnt_SafeAssign(fXfermode, mode);
+       return mode;
+}
+
+SkXfermode* SkPaint::setPorterDuffXfermode(SkPorterDuff::Mode mode)
+{
+    fXfermode->safeUnref();
+    fXfermode = SkPorterDuff::CreateXfermode(mode);
+       return fXfermode;
+}
+
+SkPathEffect* SkPaint::setPathEffect(SkPathEffect* effect)
+{
+       SkRefCnt_SafeAssign(fPathEffect, effect);
+       return effect;
+}
+
+SkMaskFilter* SkPaint::setMaskFilter(SkMaskFilter* filter)
+{
+       SkRefCnt_SafeAssign(fMaskFilter, filter);
+       return filter;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+bool SkPaint::getFillPath(const SkPath& src, SkPath* dst) const
+{
+    SkPath          effectPath, strokePath;
+    const SkPath*   path = &src;
+
+       SkScalar width = this->getStrokeWidth();
+    
+    switch (this->getStyle()) {
+    case SkPaint::kFill_Style:
+        width = -1; // mark it as no-stroke
+        break;
+    case SkPaint::kStrokeAndFill_Style:
+        if (width == 0)
+            width = -1; // mark it as no-stroke
+        break;
+    case SkPaint::kStroke_Style:
+        break;
+    default:
+        SkASSERT(!"unknown paint style");
+    }
+
+       if (this->getPathEffect())
+       {
+        // lie to the pathEffect if our style is strokeandfill, so that it treats us as just fill
+        if (this->getStyle() == SkPaint::kStrokeAndFill_Style)
+            width = -1; // mark it as no-stroke
+
+               if (this->getPathEffect()->filterPath(&effectPath, src, &width))
+                       path = &effectPath;
+        
+        // restore the width if we earlier had to lie, and if we're still set to no-stroke
+        // note: if we're now stroke (width >= 0), then the pathEffect asked for that change
+        // and we want to respect that (i.e. don't overwrite their setting for width)
+        if (this->getStyle() == SkPaint::kStrokeAndFill_Style && width < 0)
+        {
+            width = this->getStrokeWidth();
+            if (width == 0)
+                width = -1;
+        }
+       }
+    
+    if (width > 0 && !path->isEmpty())
+    {
+               SkStroke stroker(*this, width);
+               stroker.strokePath(*path, &strokePath);
+        path = &strokePath;
+       }
+
+    if (path == &src)
+        *dst = src;
+    else
+    {
+        SkASSERT(path == &effectPath || path == &strokePath);
+        dst->swap(*(SkPath*)path);
+    }
+
+    return width != 0;  // return true if we're filled, or false if we're hairline (width == 0)
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+static bool has_thick_frame(const SkPaint& paint)
+{
+       return paint.getStrokeWidth() > 0 && paint.getStyle() != SkPaint::kFill_Style;
+}
+
+SkTextToPathIter::SkTextToPathIter( SkUnicodeWalkerProc textProc,
+                                    const char text[], size_t length,
+                                    const SkPaint& paint,
+                                    bool applyStrokeAndPathEffects,
+                                    bool forceLinearTextOn)
+                                    : fPaint(paint), fTextProc(textProc)
+{
+       if (forceLinearTextOn)
+               fPaint.setLinearTextOn(true);
+       fPaint.setMaskFilter(NULL);   // don't want this affecting our path-cache lookup
+
+       if (fPaint.getPathEffect() == NULL && !has_thick_frame(fPaint))
+               applyStrokeAndPathEffects = false;
+
+       // can't use our canonical size if we need to apply patheffects/strokes
+       if (fPaint.isLinearTextOn() && !applyStrokeAndPathEffects)
+       {
+               fPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
+               fScale = paint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
+       }
+       else
+               fScale = SK_Scalar1;
+       
+       if (!applyStrokeAndPathEffects)
+       {
+               fPaint.setStyle(SkPaint::kFill_Style);
+               fPaint.setPathEffect(NULL);
+       }
+
+       fCache = SkGlyphCache::DetachCache(fPaint, NULL);
+
+       SkPaint::Style  style = SkPaint::kFill_Style;
+       SkPathEffect*   pe = NULL;
+
+       if (!applyStrokeAndPathEffects)
+       {
+               style = paint.getStyle();       // restore
+               pe = paint.getPathEffect();             // restore
+       }
+       fPaint.setStyle(style);
+       fPaint.setPathEffect(pe);
+       fPaint.setMaskFilter(paint.getMaskFilter());    // restore
+
+       // now compute fXOffset if needed
+
+       SkScalar xOffset = 0;
+       if (paint.getTextAlign() != SkPaint::kLeft_Align)       // need to measure first
+       {
+               int              count;
+               SkScalar width = SkScalarMul(measure_text(paint, fCache, textProc, text, length, &count), fScale);
+               if (paint.getTextAlign() == SkPaint::kCenter_Align)
+                       width = SkScalarHalf(width);
+               xOffset = -width;
+       }
+       fXPos = xOffset; // + SkScalarHalf(paint.getTextTracking()); do we need to return the textlayout's first deltaAdvance?
+       fPrevAdvance = 0;
+
+       fText = text;
+       fStop = text + length;
+}
+
+SkTextToPathIter::~SkTextToPathIter()
+{
+       SkGlyphCache::AttachCache(fCache);
+}
+
+const SkPath* SkTextToPathIter::next(SkScalar* xpos)
+{
+       while (fText < fStop)
+       {
+               const SkGlyph& glyph = fCache->getMetrics(fTextProc(&fText));
+
+               fXPos += fPrevAdvance;
+               fPrevAdvance = SkScalarMul(SkFixedToScalar(glyph.fAdvanceX), fScale);   // + fPaint.getTextTracking();
+
+               if (glyph.fWidth)
+               {
+                       if (xpos)
+                               *xpos = fXPos;
+                       return fCache->findPath(glyph.fCharCode);
+               }
+       }
+       return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+
+SkTypeface* SkTypeface::Create(const char name[], Style style)
+{
+       return SkFontHost::CreateTypeface(NULL, name, style);
+}
+
+SkTypeface* SkTypeface::CreateFromTypeface(const SkTypeface* family, Style style)
+{
+       return SkFontHost::CreateTypeface(family, NULL, style);
+}
+
diff --git a/libs/graphics/sgl/SkPath.cpp b/libs/graphics/sgl/SkPath.cpp
new file mode 100644 (file)
index 0000000..18e4fb8
--- /dev/null
@@ -0,0 +1,1139 @@
+#include "SkPath.h"
+#include "SkMath.h"
+
+/*
+       Stores the verbs and points as they are given to us, with exceptions:
+       - we only record "Close" if it was immediately preceeded by Line | Quad | Cubic
+       - we insert a Move(0,0) if Line | Quad | Cubic is our first command
+
+       The iterator does more cleanup, especially if forceClose == true
+       1. if we encounter Close, return a cons'd up Line() first (if the curr-pt != start-pt)
+       2. if we encounter Move without a preceeding Close, and forceClose is true, goto #1
+       3. if we encounter Line | Quad | Cubic after Close, cons up a Move
+*/
+
+////////////////////////////////////////////////////////////////////////////
+
+SkPath::SkPath() : fFillType(kWinding_FillType)
+{
+}
+
+SkPath::SkPath(const SkPath& src)
+{
+       *this = src;
+}
+
+SkPath::~SkPath()
+{
+}
+
+SkPath& SkPath::operator=(const SkPath& src)
+{
+    if (this != &src)
+    {
+        fPts           = src.fPts;
+        fVerbs         = src.fVerbs;
+        fFillType      = src.fFillType;
+    }
+       return *this;
+}
+
+void SkPath::swap(SkPath& other)
+{
+       SkASSERT(&other != nil);
+
+       if (this != &other)
+       {
+               fPts.swap(other.fPts);
+               fVerbs.swap(other.fVerbs);
+               SkTSwap<U8>(fFillType, other.fFillType);
+       }
+}
+
+void SkPath::reset()
+{
+       fPts.reset();
+       fVerbs.reset();
+}
+
+bool SkPath::isEmpty() const
+{
+       int count = fVerbs.count();
+       return count == 0 || (count == 1 && fVerbs[0] == kMove_Verb);
+}
+
+bool SkPath::isRect(SkRect*) const
+{
+       SkASSERT(!"unimplemented");
+       return false;
+}
+
+int SkPath::getPoints(SkPoint copy[], int max) const
+{
+       SkASSERT(max >= 0);
+       int count = fPts.count();
+       if (copy && max > 0 && count > 0)
+               memcpy(copy, fPts.begin(), sizeof(SkPoint) * SkMin32(max, count));
+       return count;
+}
+
+void SkPath::getLastPt(SkPoint* lastPt) const
+{
+       if (lastPt)
+       {
+               int count = fPts.count();
+               if (count == 0)
+                       lastPt->set(0, 0);
+               else
+                       *lastPt = fPts[count - 1];
+       }
+}
+
+void SkPath::setLastPt(SkScalar x, SkScalar y)
+{
+       int count = fPts.count();
+       if (count == 0)
+               this->moveTo(x, y);
+       else
+               fPts[count - 1].set(x, y);
+}
+
+void SkPath::computeBounds(SkRect* bounds, BoundsType bt) const
+{
+       SkASSERT(bounds);
+
+       if (fPts.count() <= 1)
+               bounds->set(0, 0, 0, 0);
+       else if (true || bt == kFast_BoundsType)
+               bounds->set(fPts.begin(), fPts.count());
+       else
+       {
+               SkASSERT(!"unimplemented");
+               Iter    iter(*this, false);
+               SkPoint pts[4];
+               Verb    verb;
+
+               while ((verb = iter.next(pts)) != kDone_Verb)
+               {
+                       switch (verb) {
+                       case kLine_Verb:
+                       case kQuad_Verb:
+                       case kCubic_Verb:
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//     Construction methods
+
+void SkPath::incReserve(U16CPU inc)
+{
+       fVerbs.setReserve(fVerbs.count() + inc);
+       fPts.setReserve(fPts.count() + inc);
+}
+
+void SkPath::moveTo(SkScalar x, SkScalar y)
+{
+       int              vc = fVerbs.count();
+       SkPoint* pt;
+
+       if (vc > 0 && fVerbs[vc - 1] == kMove_Verb)
+       {
+               pt = &fPts[fPts.count() - 1];
+       }
+       else
+       {
+               pt = fPts.append();
+               *fVerbs.append() = kMove_Verb;
+       }
+       pt->set(x, y);
+}
+
+void SkPath::rMoveTo(SkScalar x, SkScalar y)
+{
+       SkPoint pt;
+       this->getLastPt(&pt);
+       this->moveTo(pt.fX + x, pt.fY + y);
+}
+
+void SkPath::lineTo(SkScalar x, SkScalar y)
+{
+       if (fVerbs.count() == 0)
+       {
+               fPts.append()->set(0, 0);
+               *fVerbs.append() = kMove_Verb;
+       }
+       fPts.append()->set(x, y);
+       *fVerbs.append() = kLine_Verb;
+}
+
+void SkPath::rLineTo(SkScalar x, SkScalar y)
+{
+       SkPoint pt;
+       this->getLastPt(&pt);
+       this->lineTo(pt.fX + x, pt.fY + y);
+}
+
+void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
+{
+       if (fVerbs.count() == 0)
+       {
+               fPts.append()->set(0, 0);
+               *fVerbs.append() = kMove_Verb;
+       }
+
+       SkPoint* pts = fPts.append(2);
+       pts[0].set(x1, y1);
+       pts[1].set(x2, y2);
+       *fVerbs.append() = kQuad_Verb;
+}
+
+void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
+{
+       SkPoint pt;
+       this->getLastPt(&pt);
+       this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2);
+}
+
+void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3)
+{
+       if (fVerbs.count() == 0)
+       {
+               fPts.append()->set(0, 0);
+               *fVerbs.append() = kMove_Verb;
+       }
+       SkPoint* pts = fPts.append(3);
+       pts[0].set(x1, y1);
+       pts[1].set(x2, y2);
+       pts[2].set(x3, y3);
+       *fVerbs.append() = kCubic_Verb;
+}
+
+void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3)
+{
+       SkPoint pt;
+       this->getLastPt(&pt);
+       this->cubicTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2, pt.fX + x3, pt.fY + y3);
+}
+
+void SkPath::close()
+{
+       int count = fVerbs.count();
+       if (count > 0)
+       {
+               switch (fVerbs[count - 1]) {
+               case kLine_Verb:
+               case kQuad_Verb:
+               case kCubic_Verb:
+                       *fVerbs.append() = kClose_Verb;
+                       break;
+               default:
+                       // don't add a close if the prev wasn't a primitive
+                       break;
+               }
+       }
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+void SkPath::addRect(const SkRect& rect, Direction dir)
+{
+    this->addRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, dir);
+}
+
+void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, Direction dir)
+{
+       this->moveTo(left, top);
+       if (dir == kCCW_Direction)
+       {
+               this->lineTo(left, bottom);
+               this->lineTo(right, bottom);
+               this->lineTo(right, top);
+       }
+       else
+       {
+               this->lineTo(right, top);
+               this->lineTo(right, bottom);
+               this->lineTo(left, bottom);
+       }
+       this->close();
+}
+
+#define CUBIC_ARC_FACTOR       ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3)
+
+void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, Direction dir)
+{
+       SkScalar        w = rect.width();
+       SkScalar        halfW = SkScalarHalf(w);
+       SkScalar        h = rect.height();
+       SkScalar        halfH = SkScalarHalf(h);
+
+       if (halfW <= 0 || halfH <= 0)
+               return;
+
+       bool    skip_hori = rx >= halfW;
+       bool    skip_vert = ry >= halfH;
+
+       if (skip_hori && skip_vert)
+       {
+               this->addOval(rect, dir);
+               return;
+       }
+       if (skip_hori)
+               rx = halfW;
+       else if (skip_vert)
+               ry = halfH;
+
+       SkScalar        sx = SkScalarMul(rx, CUBIC_ARC_FACTOR);
+       SkScalar        sy = SkScalarMul(ry, CUBIC_ARC_FACTOR);
+
+       this->incReserve(17);
+       this->moveTo(rect.fRight - rx, rect.fTop);
+       if (dir == kCCW_Direction)
+       {
+               if (!skip_hori)
+                       this->lineTo(rect.fLeft + rx, rect.fTop);               // top
+               this->cubicTo(rect.fLeft + rx - sx, rect.fTop,
+                                         rect.fLeft, rect.fTop + ry - sy,
+                                         rect.fLeft, rect.fTop + ry);                  // top-left
+               if (!skip_vert)
+                       this->lineTo(rect.fLeft, rect.fBottom - ry);            // left
+               this->cubicTo(rect.fLeft, rect.fBottom - ry + sy,
+                                         rect.fLeft + rx - sx, rect.fBottom,
+                                         rect.fLeft + rx, rect.fBottom);               // bot-left
+               if (!skip_hori)
+                       this->lineTo(rect.fRight - rx, rect.fBottom);   // bottom
+               this->cubicTo(rect.fRight - rx + sx, rect.fBottom,
+                                         rect.fRight, rect.fBottom - ry + sy,
+                                         rect.fRight, rect.fBottom - ry);              // bot-right
+               if (!skip_vert)
+                       this->lineTo(rect.fRight, rect.fTop + ry);
+               this->cubicTo(rect.fRight, rect.fTop + ry - sy,
+                                         rect.fRight - rx + sx, rect.fTop,
+                                         rect.fRight - rx, rect.fTop);                 // top-right
+       }
+       else
+       {
+               this->cubicTo(rect.fRight - rx + sx, rect.fTop,
+                                         rect.fRight, rect.fTop + ry - sy,
+                                         rect.fRight, rect.fTop + ry);                 // top-right
+               if (!skip_vert)
+                       this->lineTo(rect.fRight, rect.fBottom - ry);
+               this->cubicTo(rect.fRight, rect.fBottom - ry + sy,
+                                         rect.fRight - rx + sx, rect.fBottom,
+                                         rect.fRight - rx, rect.fBottom);              // bot-right
+               if (!skip_hori)
+                       this->lineTo(rect.fLeft + rx, rect.fBottom);    // bottom
+               this->cubicTo(rect.fLeft + rx - sx, rect.fBottom,
+                                         rect.fLeft, rect.fBottom - ry + sy,
+                                         rect.fLeft, rect.fBottom - ry);               // bot-left
+               if (!skip_vert)
+                       this->lineTo(rect.fLeft, rect.fTop + ry);               // left
+               this->cubicTo(rect.fLeft, rect.fTop + ry - sy,
+                                         rect.fLeft + rx - sx, rect.fTop,
+                                         rect.fLeft + rx, rect.fTop);                  // top-left
+               if (!skip_hori)
+                       this->lineTo(rect.fRight - rx, rect.fTop);              // top
+       }
+       this->close();
+}
+
+void SkPath::addOval(const SkRect& oval, Direction dir)
+{
+       SkScalar        cx = oval.centerX();
+       SkScalar        cy = oval.centerY();
+       SkScalar        rx = SkScalarHalf(oval.width());
+       SkScalar        ry = SkScalarHalf(oval.height());
+#if 1  // these seem faster than using quads (1/2 the number of edges to process)
+       SkScalar        sx = SkScalarMul(rx, CUBIC_ARC_FACTOR);
+       SkScalar        sy = SkScalarMul(ry, CUBIC_ARC_FACTOR);
+
+       this->incReserve(13);
+       this->moveTo(cx + rx, cy);
+       if (dir == kCCW_Direction)
+       {
+               this->cubicTo(cx + rx, cy - sy, cx + sx, cy - ry, cx, cy - ry);
+               this->cubicTo(cx - sx, cy - ry, cx - rx, cy - sy, cx - rx, cy);
+               this->cubicTo(cx - rx, cy + sy, cx - sx, cy + ry, cx, cy + ry);
+               this->cubicTo(cx + sx, cy + ry, cx + rx, cy + sy, cx + rx, cy);
+       }
+       else
+       {
+               this->cubicTo(cx + rx, cy + sy, cx + sx, cy + ry, cx, cy + ry);
+               this->cubicTo(cx - sx, cy + ry, cx - rx, cy + sy, cx - rx, cy);
+               this->cubicTo(cx - rx, cy - sy, cx - sx, cy - ry, cx, cy - ry);
+               this->cubicTo(cx + sx, cy - ry, cx + rx, cy - sy, cx + rx, cy);
+       }
+#else
+       SkScalar        sx = SkScalarMul(rx, SK_ScalarTanPIOver8);
+       SkScalar        sy = SkScalarMul(ry, SK_ScalarTanPIOver8);
+       SkScalar        mx = SkScalarMul(rx, SK_ScalarRoot2Over2);
+       SkScalar        my = SkScalarMul(ry, SK_ScalarRoot2Over2);
+
+       this->incReserve(16);
+       this->moveTo(cx + rx, cy);
+       if (dir == kCCW_Direction)
+       {
+               this->quadTo(cx + rx, cy - sy, cx + mx, cy - my);
+               this->quadTo(cx + sx, cy - ry, cx +  0, cy - ry);
+               this->quadTo(cx - sx, cy - ry, cx - mx, cy - my);
+               this->quadTo(cx - rx, cy - sy, cx - rx, cy -  0);
+               this->quadTo(cx - rx, cy + sy, cx - mx, cy + my);
+               this->quadTo(cx - sx, cy + ry, cx -  0, cy + ry);
+               this->quadTo(cx + sx, cy + ry, cx + mx, cy + my);
+               this->quadTo(cx + rx, cy + sy, cx + rx, cy +  0);
+       }
+       else
+       {
+               this->quadTo(cx + rx, cy + sy, cx + mx, cy + my);
+               this->quadTo(cx + sx, cy + ry, cx -  0, cy + ry);
+               this->quadTo(cx - sx, cy + ry, cx - mx, cy + my);
+               this->quadTo(cx - rx, cy + sy, cx - rx, cy -  0);
+               this->quadTo(cx - rx, cy - sy, cx - mx, cy - my);
+               this->quadTo(cx - sx, cy - ry, cx +  0, cy - ry);
+               this->quadTo(cx + sx, cy - ry, cx + mx, cy - my);
+               this->quadTo(cx + rx, cy - sy, cx + rx, cy +  0);
+       }
+#endif
+       this->close();
+}
+
+void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir)
+{
+       if (r > 0)
+       {
+               SkRect  rect;
+               rect.set(x - r, y - r, x + r, y + r);
+               this->addOval(rect, dir);
+       }
+}
+
+void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy)
+{
+       SkMatrix matrix;
+
+       matrix.setTranslate(dx, dy);
+       this->addPath(path, matrix);
+}
+
+void SkPath::addPath(const SkPath& path, const SkMatrix& matrix)
+{
+       this->incReserve(path.fPts.count());
+
+       Iter    iter(path, false);
+       SkPoint pts[4];
+       Verb    verb;
+
+       SkMatrix::TypeMask mask = matrix.getType();
+
+       while ((verb = iter.next(pts)) != kDone_Verb)
+       {
+               switch (verb) {
+               case kMove_Verb:
+                       matrix.mapPoints(&pts[0], &pts[0], 1, mask);
+                       this->moveTo(pts[0]);
+                       break;
+               case kLine_Verb:
+                       matrix.mapPoints(&pts[1], &pts[1], 1, mask);
+                       this->lineTo(pts[1]);
+                       break;
+               case kQuad_Verb:
+                       matrix.mapPoints(&pts[1], &pts[1], 2, mask);
+                       this->quadTo(pts[1], pts[2]);
+                       break;
+               case kCubic_Verb:
+                       matrix.mapPoints(&pts[1], &pts[1], 3, mask);
+                       this->cubicTo(pts[1], pts[2], pts[3]);
+                       break;
+               case kClose_Verb:
+                       this->close();
+                       break;
+               default:
+                       SkASSERT(!"unknown verb");
+               }
+       }
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+static const U8 gPtsInVerb[] = {
+       1,      // kMove
+       1,      // kLine
+       2,      // kQuad
+       3,      // kCubic
+       0,      // kClose
+       0       // kDone
+};
+
+// ignore the initial moveto, and stop when the 1st contour ends
+void SkPath::pathTo(const SkPath& path)
+{
+       int     i, vcount = path.fVerbs.count();
+       if (vcount == 0)
+               return;
+
+       const U8*               verbs = path.fVerbs.begin();
+       const SkPoint*  pts = path.fPts.begin() + 1;    // 1 for the initial moveTo
+
+       SkASSERT(verbs[0] == kMove_Verb);
+       for (i = 1; i < vcount; i++)
+       {
+               switch (verbs[i]) {
+               case kLine_Verb:
+                       this->lineTo(pts[0].fX, pts[0].fY);
+                       break;
+               case kQuad_Verb:
+                       this->quadTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY);
+                       break;
+               case kCubic_Verb:
+                       this->cubicTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
+                       break;
+               case kClose_Verb:
+                       return;
+               }
+               pts += gPtsInVerb[verbs[i]];
+       }
+}
+
+// ignore the last point of the 1st contour
+void SkPath::reversePathTo(const SkPath& path)
+{
+       int     i, vcount = path.fVerbs.count();
+       if (vcount == 0)
+               return;
+
+       const U8*               verbs = path.fVerbs.begin();
+       const SkPoint*  pts = path.fPts.begin();
+
+       SkASSERT(verbs[0] == kMove_Verb);
+       for (i = 1; i < vcount; i++)
+       {
+               int n = gPtsInVerb[verbs[i]];
+               if (n == 0)
+                       break;
+               pts += n;
+       }
+
+       while (--i > 0)
+       {
+               switch (verbs[i]) {
+               case kLine_Verb:
+                       this->lineTo(pts[-1].fX, pts[-1].fY);
+                       break;
+               case kQuad_Verb:
+                       this->quadTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY);
+                       break;
+               case kCubic_Verb:
+                       this->cubicTo(pts[-1].fX, pts[-1].fY, pts[-2].fX, pts[-2].fY, pts[-3].fX, pts[-3].fY);
+                       break;
+               default:
+                       SkASSERT(!"bad verb");
+                       break;
+               }
+               pts -= gPtsInVerb[verbs[i]];
+       }
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+bool SkPath::offset(SkScalar dx, SkScalar dy, SkPath* dst) const
+{
+       SkMatrix        matrix;
+
+       matrix.setTranslate(dx, dy);
+    return this->transform(matrix, dst);
+}
+
+#include "SkGeometry.h"
+
+static void subdivide_quad_to(SkPath* path, const SkPoint pts[3], int level = 2)
+{
+       if (--level >= 0)
+       {
+               SkPoint tmp[5];
+
+               SkChopQuadAtHalf(pts, tmp);
+               subdivide_quad_to(path, &tmp[0], level);
+               subdivide_quad_to(path, &tmp[2], level);
+       }
+       else
+               path->quadTo(pts[1], pts[2]);
+}
+
+static void subdivide_cubic_to(SkPath* path, const SkPoint pts[4], int level = 2)
+{
+       if (--level >= 0)
+       {
+               SkPoint tmp[7];
+
+               SkChopCubicAtHalf(pts, tmp);
+               subdivide_cubic_to(path, &tmp[0], level);
+               subdivide_cubic_to(path, &tmp[3], level);
+       }
+       else
+               path->cubicTo(pts[1], pts[2], pts[3]);
+}
+
+bool SkPath::transform(const SkMatrix& matrix, SkPath* dst) const
+{
+       if (dst == nil)
+               dst = (SkPath*)this;
+
+       if (matrix.getType() & SkMatrix::kPerspective_Mask)
+       {
+               SkPath  tmp;
+               tmp.fFillType = fFillType;
+
+               SkPath::Iter    iter(*this, false);
+               SkPoint                 pts[4];
+               SkPath::Verb    verb;
+
+               while ((verb = iter.next(pts)) != kDone_Verb)
+               {
+                       switch (verb) {
+                       case kMove_Verb:
+                               tmp.moveTo(pts[0]);
+                               break;
+                       case kLine_Verb:
+                               tmp.lineTo(pts[1]);
+                               break;
+                       case kQuad_Verb:
+                               subdivide_quad_to(&tmp, pts);
+                               break;
+                       case kCubic_Verb:
+                               subdivide_cubic_to(&tmp, pts);
+                               break;
+                       case kClose_Verb:
+                               tmp.close();
+                               break;
+                       default:
+                               SkASSERT(!"unknown verb");
+                               break;
+                       }
+               }
+
+               dst->swap(tmp);
+               return matrix.mapPoints(dst->fPts.begin(), dst->fPts.count());
+       }
+
+       else
+       {
+               if (this != dst)
+               {
+                       dst->fVerbs = fVerbs;
+                       dst->fPts.setCount(fPts.count());
+                       dst->fFillType = fFillType;
+               }
+               return matrix.mapPoints(dst->fPts.begin(), fPts.begin(), fPts.count());
+       }
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+
+enum NeedMoveToState {
+       kAfterClose_NeedMoveToState,
+       kAfterCons_NeedMoveToState,
+       kAfterPrefix_NeedMoveToState
+};
+
+SkPath::Iter::Iter()
+{
+#ifdef SK_DEBUG
+       fPts = nil;
+       fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0;
+       fForceClose = fNeedMoveTo = fCloseLine = false;
+#endif
+       // need to init enough to make next() harmlessly return kDone_Verb
+       fVerbs = nil;
+       fVerbStop = nil;
+       fNeedClose = false;
+}
+
+SkPath::Iter::Iter(const SkPath& path, bool forceClose)
+{
+       this->setPath(path, forceClose);
+}
+
+void SkPath::Iter::setPath(const SkPath& path, bool forceClose)
+{
+       fPts = path.fPts.begin();
+       fVerbs = path.fVerbs.begin();
+       fVerbStop = path.fVerbs.end();
+       fForceClose = SkToU8(forceClose);
+       fNeedClose = false;
+       fNeedMoveTo = kAfterPrefix_NeedMoveToState;
+}
+
+bool SkPath::Iter::isClosedContour() const
+{
+    if (fVerbs == nil || fVerbs == fVerbStop)
+        return false;
+    if (fForceClose)
+        return true;
+
+    const uint8_t* verbs = fVerbs;
+    const uint8_t* stop = fVerbStop;
+    
+    if (kMove_Verb == *verbs)
+        verbs += 1; // skip the initial moveto
+
+    while (verbs < stop)
+    {
+        unsigned v = *verbs++;        
+        if (kMove_Verb == v)
+            break;
+        if (kClose_Verb == v)
+            return true;
+    }
+    return false;
+}
+
+SkPath::Verb SkPath::Iter::autoClose(SkPoint pts[2])
+{
+       if (fLastPt != fMoveTo)
+       {
+               if (pts)
+               {
+                       pts[0] = fLastPt;
+                       pts[1] = fMoveTo;
+               }
+               fLastPt = fMoveTo;
+               fCloseLine = true;
+               return kLine_Verb;
+       }
+       return kClose_Verb;
+}
+
+bool SkPath::Iter::cons_moveTo(SkPoint pts[1])
+{
+       if (fNeedMoveTo == kAfterClose_NeedMoveToState)
+       {
+               if (pts)
+                       *pts = fMoveTo;
+               fNeedClose = fForceClose;
+               fNeedMoveTo = kAfterCons_NeedMoveToState;
+               fVerbs -= 1;
+               return true;
+       }
+
+       if (fNeedMoveTo == kAfterCons_NeedMoveToState)
+       {
+               if (pts)
+                       *pts = fMoveTo;
+               fNeedMoveTo = kAfterPrefix_NeedMoveToState;
+       }
+       else
+       {
+               SkASSERT(fNeedMoveTo == kAfterPrefix_NeedMoveToState);
+               if (pts)
+                       *pts = fPts[-1];
+       }
+       return false;
+}
+
+SkPath::Verb SkPath::Iter::next(SkPoint pts[4])
+{
+       if (fVerbs == fVerbStop)
+       {
+               if (fNeedClose)
+               {
+                       if (kLine_Verb == this->autoClose(pts))
+                               return kLine_Verb;
+                       fNeedClose = false;
+                       return kClose_Verb;
+               }
+               return kDone_Verb;
+       }
+
+       unsigned                verb = *fVerbs++;
+       const SkPoint*  srcPts = fPts;
+
+       switch (verb) {
+       case kMove_Verb:
+               if (fNeedClose)
+               {
+                       fVerbs -= 1;
+                       verb = this->autoClose(pts);
+                       if (verb == kClose_Verb)
+                               fNeedClose = false;
+                       return (Verb)verb;
+               }
+               if (fVerbs == fVerbStop)        // might be a trailing moveto
+                       return kDone_Verb;
+               fMoveTo = *srcPts;
+               if (pts)
+                       pts[0] = *srcPts;
+               srcPts += 1;
+               fNeedMoveTo = kAfterCons_NeedMoveToState;
+               fNeedClose = fForceClose;
+               break;
+       case kLine_Verb:
+               if (this->cons_moveTo(pts))
+                       return kMove_Verb;
+               if (pts)
+                       pts[1] = srcPts[0];
+               fLastPt = srcPts[0];
+               fCloseLine = false;
+               srcPts += 1;
+               break;
+       case kQuad_Verb:
+               if (this->cons_moveTo(pts))
+                       return kMove_Verb;
+               if (pts)
+                       memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint));
+               fLastPt = srcPts[1];
+               srcPts += 2;
+               break;
+       case kCubic_Verb:
+               if (this->cons_moveTo(pts))
+                       return kMove_Verb;
+               if (pts)
+                       memcpy(&pts[1], srcPts, 3 * sizeof(SkPoint));
+               fLastPt = srcPts[2];
+               srcPts += 3;
+               break;
+       case kClose_Verb:
+               verb = this->autoClose(pts);
+               if (verb == kLine_Verb)
+                       fVerbs -= 1;
+               else
+                       fNeedClose = false;
+               fNeedMoveTo = kAfterClose_NeedMoveToState;
+               break;
+       }
+       fPts = srcPts;
+       return (Verb)verb;
+}
+
+///////////////////////////////////////////////////////////////////////
+
+static bool exceeds_dist(const SkScalar p[], const SkScalar q[], SkScalar dist, int count)
+{
+       SkASSERT(dist > 0);
+
+       count *= 2;
+       for (int i = 0; i < count; i++)
+               if (SkScalarAbs(p[i] - q[i]) > dist)
+                       return true;
+       return false;
+}
+
+static void subdivide_quad(SkPath* dst, const SkPoint pts[3], SkScalar dist, int subLevel = 4)
+{
+       if (--subLevel >= 0 && exceeds_dist(&pts[0].fX, &pts[1].fX, dist, 4))
+       {
+               SkPoint tmp[5];
+               SkChopQuadAtHalf(pts, tmp);
+
+               subdivide_quad(dst, &tmp[0], dist, subLevel);
+               subdivide_quad(dst, &tmp[2], dist, subLevel);
+       }
+       else
+               dst->quadTo(pts[1], pts[2]);
+}
+
+static void subdivide_cubic(SkPath* dst, const SkPoint pts[4], SkScalar dist, int subLevel = 4)
+{
+       if (--subLevel >= 0 && exceeds_dist(&pts[0].fX, &pts[1].fX, dist, 6))
+       {
+               SkPoint tmp[7];
+               SkChopCubicAtHalf(pts, tmp);
+
+               subdivide_cubic(dst, &tmp[0], dist, subLevel);
+               subdivide_cubic(dst, &tmp[3], dist, subLevel);
+       }
+       else
+               dst->cubicTo(pts[1], pts[2], pts[3]);
+}
+
+void SkPath::subdivide(SkScalar dist, bool bendLines, SkPath* dst) const
+{
+       SkPath  tmpPath;
+       if (nil == dst || this == dst)
+               dst = &tmpPath;
+
+       SkPath::Iter    iter(*this, false);
+       SkPoint                 pts[4];
+
+       for (;;)
+       {
+               switch (iter.next(pts)) {
+               case SkPath::kMove_Verb:
+                       dst->moveTo(pts[0]);
+                       break;
+               case SkPath::kLine_Verb:
+                       if (!bendLines)
+                       {
+                               dst->lineTo(pts[1]);
+                               break;
+                       }
+                       // construct a quad from the line
+                       pts[2] = pts[1];
+                       pts[1].set(SkScalarAve(pts[0].fX, pts[2].fX), SkScalarAve(pts[0].fY, pts[2].fY));
+                       // fall through to the quad case
+               case SkPath::kQuad_Verb:
+                       subdivide_quad(dst, pts, dist);
+                       break;
+               case SkPath::kCubic_Verb:
+                       subdivide_cubic(dst, pts, dist);
+                       break;
+               case SkPath::kClose_Verb:
+                       dst->close();
+                       break;
+               case SkPath::kDone_Verb:
+                       goto DONE;
+               }
+       }
+DONE:
+       if (&tmpPath == dst)    // i.e. the dst should be us
+               dst->swap(*(SkPath*)this);
+}
+
+///////////////////////////////////////////////////////////////////////
+/*
+       Format in flattened buffer: [ptCount, verbCount, pts[], verbs[]]
+*/
+
+#include "SkBuffer.h"
+
+U32 SkPath::flatten(void* storage) const
+{
+       if (storage)
+       {
+        SkWBuffer   buffer(storage);
+        
+        buffer.write32(fPts.count());
+               buffer.write32(fVerbs.count());
+               buffer.write32(fFillType);
+               buffer.write(fPts.begin(), sizeof(SkPoint) * fPts.count());
+        buffer.write(fVerbs.begin(), fVerbs.count());
+        buffer.padToAlign4();
+       }
+       return 3 * sizeof(int32_t) + sizeof(SkPoint) * fPts.count() + SkAlign4(fVerbs.count());
+}
+
+void SkPath::unflatten(const void* storage)
+{
+    SkRBuffer   buffer(storage);
+
+    fPts.setCount(buffer.readS32());
+    fVerbs.setCount(buffer.readS32());
+    fFillType = buffer.readS32();
+    buffer.read(fPts.begin(), sizeof(SkPoint) * fPts.count());
+    buffer.read(fVerbs.begin(), fVerbs.count());
+    buffer.skipToAlign4();
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkString.h"
+#include "SkStream.h"
+
+static void write_scalar(SkWStream* stream, SkScalar value)
+{
+    char    buffer[SkStrAppendScalar_MaxSize];
+    char*   stop = SkStrAppendScalar(buffer, value);
+    stream->write(buffer, stop - buffer);
+}
+
+static void append_scalars(SkWStream* stream, char verb, const SkScalar data[], int count)
+{
+    stream->write(&verb, 1);
+    write_scalar(stream, data[0]);
+    for (int i = 1; i < count; i++) {
+        if (data[i] >= 0)
+            stream->write(" ", 1);   // can skip the separater if data[i] is negative
+        write_scalar(stream, data[i]);
+    }
+}
+
+void SkPath::toString(SkString* str) const
+{
+    SkDynamicMemoryWStream  stream;
+
+    SkPath::Iter    iter(*this, false);
+    SkPoint         pts[4];
+    
+    for (;;) {
+        switch (iter.next(pts)) {
+        case SkPath::kMove_Verb:
+            append_scalars(&stream, 'M', &pts[0].fX, 2);
+            break;
+        case SkPath::kLine_Verb:
+            append_scalars(&stream, 'L', &pts[1].fX, 2);
+            break;
+        case SkPath::kQuad_Verb:
+            append_scalars(&stream, 'Q', &pts[1].fX, 4);
+            break;
+        case SkPath::kCubic_Verb:
+            append_scalars(&stream, 'C', &pts[1].fX, 6);
+            break;
+        case SkPath::kClose_Verb:
+            stream.write("Z", 1);
+            break;
+        case SkPath::kDone_Verb:
+            str->resize(stream.getOffset());
+            stream.copyTo(str->writable_str());
+            return;
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+#if 0  // test to ensure that the iterator returns the same data as the path
+void SkPath::test() const
+{
+       Iter    iter(*this, false);
+       SkPoint pts[4];
+       Verb    verb;
+
+       const U8*               verbs = fVerbs.begin();
+       const SkPoint*  points = fPts.begin();
+
+       while ((verb = iter.next(pts)) != kDone_Verb)
+       {
+               SkASSERT(*verbs == verb);
+               verbs += 1;
+
+               int count;
+               switch (verb) {
+               case kMove_Verb:
+                       count = 1;
+                       break;
+               case kLine_Verb:
+                       count = 2;
+                       break;
+               case kQuad_Verb:
+                       count = 3;
+                       break;
+               case kCubic_Verb:
+                       count = 4;
+                       break;
+               case kClose_Verb:
+               default:
+                       count = 0;
+                       break;
+               }
+               if (count > 1)
+                       points -= 1;
+               SkASSERT(memcmp(pts, points, count * sizeof(SkPoint)) == 0);
+               points += count;
+       }
+
+       int vc = fVerbs.count(), pc = fPts.count();
+       if (vc && fVerbs.begin()[vc-1] == kMove_Verb)
+       {
+               vc -= 1;
+               pc -= 1;
+       }
+       SkASSERT(verbs - fVerbs.begin() == vc);
+       SkASSERT(points - fPts.begin() == pc);
+}
+#endif
+
+void SkPath::dump(bool forceClose, const char title[]) const
+{
+       Iter    iter(*this, forceClose);
+       SkPoint pts[4];
+       Verb    verb;
+
+       SkDebugf("path: forceClose=%s %s\n", forceClose ? "true" : "false", title ? title : "");
+
+       while ((verb = iter.next(pts)) != kDone_Verb)
+       {
+               switch (verb) {
+               case kMove_Verb:
+#ifdef SK_CAN_USE_FLOAT
+                       SkDebugf("  path: moveTo [%g %g]\n",
+                    SkScalarToFloat(pts[0].fX), SkScalarToFloat(pts[0].fY));
+#else
+                       SkDebugf("  path: moveTo [%x %x]\n", pts[0].fX, pts[0].fY);
+#endif
+                       break;
+               case kLine_Verb:
+#ifdef SK_CAN_USE_FLOAT
+                       SkDebugf("  path: lineTo [%g %g]\n",
+                    SkScalarToFloat(pts[1].fX), SkScalarToFloat(pts[1].fY));
+#else
+                       SkDebugf("  path: lineTo [%x %x]\n", pts[1].fX, pts[1].fY);
+#endif
+                       break;
+               case kQuad_Verb:
+#ifdef SK_CAN_USE_FLOAT
+                       SkDebugf("  path: quadTo [%g %g] [%g %g]\n",
+                    SkScalarToFloat(pts[1].fX), SkScalarToFloat(pts[1].fY),
+                    SkScalarToFloat(pts[2].fX), SkScalarToFloat(pts[2].fY));
+#else
+                       SkDebugf("  path: quadTo [%x %x] [%x %x]\n", pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
+#endif
+                       break;
+               case kCubic_Verb:
+#ifdef SK_CAN_USE_FLOAT
+                       SkDebugf("  path: cubeTo [%g %g] [%g %g] [%g %g]\n",
+                    SkScalarToFloat(pts[1].fX), SkScalarToFloat(pts[1].fY),
+                    SkScalarToFloat(pts[2].fX), SkScalarToFloat(pts[2].fY),
+                    SkScalarToFloat(pts[3].fX), SkScalarToFloat(pts[3].fY));
+#else
+                       SkDebugf("  path: cubeTo [%x %x] [%x %x] [%x %x]\n",
+                    pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY, pts[3].fX, pts[3].fY);
+#endif
+                       break;
+               case kClose_Verb:
+                       SkDebugf("  path: close\n");
+                       break;
+               default:
+                       SkDebugf("  path: UNKNOWN VERB %d, aborting dump...\n", verb);
+                       verb = kDone_Verb;      // stop the loop
+                       break;
+               }
+       }
+       SkDebugf("path: done %s\n", title ? title : "");
+}
+
+#include "SkTSort.h"
+
+void SkPath::UnitTest()
+{
+#ifdef SK_SUPPORT_UNITTEST
+       SkPath  p;
+       SkRect  r;
+
+       r.set(0, 0, 10, 20);
+       p.addRect(r);
+       p.dump(false);
+       p.dump(true);
+
+       {
+               int array[] = { 5, 3, 7, 2, 6, 1, 2, 9, 5, 0 };
+               int i;
+
+               for (i = 0; i < (int)SK_ARRAY_COUNT(array); i++)
+                       SkDebugf(" %d", array[i]);
+               SkDebugf("\n");
+               SkTHeapSort<int>(array, SK_ARRAY_COUNT(array));
+               for (i = 0; i < (int)SK_ARRAY_COUNT(array); i++)
+                       SkDebugf(" %d", array[i]);
+               SkDebugf("\n");
+       }
+
+       {
+               SkPath  p;
+               SkPoint pt;
+
+               p.moveTo(SK_Scalar1, 0);
+               p.getLastPt(&pt);
+               SkASSERT(pt.fX == SK_Scalar1);
+       }
+#endif
+}
+
+#endif
diff --git a/libs/graphics/sgl/SkPathEffect.cpp b/libs/graphics/sgl/SkPathEffect.cpp
new file mode 100644 (file)
index 0000000..cb09db1
--- /dev/null
@@ -0,0 +1,181 @@
+#include "SkPathEffect.h"
+#include "SkPath.h"
+#include "SkBuffer.h"
+
+SkFlattenable::Factory SkFlattenable::getFactory()
+{
+       return NULL;
+}
+
+void SkFlattenable::flatten(SkWBuffer&)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+bool SkPathEffect::filterPath(SkPath*, const SkPath&, SkScalar*)
+{
+       return false;
+}
+
+static SkFlattenable* create_null_patheffect(SkRBuffer&)
+{
+       return SkNEW(SkPathEffect);
+}
+
+SkFlattenable::Factory SkPathEffect::getFactory()
+{
+       return create_null_patheffect;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+SkPairPathEffect::SkPairPathEffect(SkPathEffect* pe0, SkPathEffect* pe1)
+       : fPE0(pe0), fPE1(pe1)
+{
+       SkASSERT(pe0);
+       SkASSERT(pe1);
+       fPE0->ref();
+       fPE1->ref();
+}
+
+SkPairPathEffect::~SkPairPathEffect()
+{
+       fPE0->unref();
+       fPE1->unref();
+}
+
+/*
+       Format: [oe0-factory][pe1-factory][pe0-size][pe0-data][pe1-data]
+*/
+void SkPairPathEffect::flatten(SkWBuffer& buffer)
+{
+    buffer.writePtr((void*)fPE0->getFactory());
+    buffer.writePtr((void*)fPE1->getFactory());
+    fPE0->flatten(buffer);
+    fPE1->flatten(buffer);
+}
+
+SkPairPathEffect::SkPairPathEffect(SkRBuffer& buffer)
+{
+    Factory factory0 = (Factory)buffer.readPtr();
+    Factory factory1 = (Factory)buffer.readPtr();
+       
+       fPE0 = (SkPathEffect*)factory0(buffer);
+       fPE1 = (SkPathEffect*)factory1(buffer);
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+bool SkComposePathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
+{
+       SkPath                  tmp;
+       const SkPath*   ptr = &src;
+
+       if (fPE1->filterPath(&tmp, src, width))
+               ptr = &tmp;
+       return fPE0->filterPath(dst, *ptr, width);
+}
+
+SkFlattenable* SkComposePathEffect::CreateProc(SkRBuffer& buffer)
+{
+       return SkNEW_ARGS(SkComposePathEffect, (buffer));
+}
+
+SkFlattenable::Factory SkComposePathEffect::getFactory()
+{
+       return SkComposePathEffect::CreateProc;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+bool SkSumPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
+{
+       // use bit-or so that we always call both, even if the first one succeeds
+       return  fPE0->filterPath(dst, src, width) | fPE1->filterPath(dst, src, width);
+}
+
+SkFlattenable* SkSumPathEffect::CreateProc(SkRBuffer& buffer)
+{
+       return SkNEW_ARGS(SkSumPathEffect, (buffer));
+}
+
+SkFlattenable::Factory SkSumPathEffect::getFactory()
+{
+       return SkSumPathEffect::CreateProc;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+#include "SkStroke.h"
+
+SkStrokePathEffect::SkStrokePathEffect(const SkPaint& paint)
+       : fWidth(paint.getStrokeWidth()), fMiter(paint.getStrokeMiter()),
+         fStyle(SkToU8(paint.getStyle())), fJoin(SkToU8(paint.getStrokeJoin())), fCap(SkToU8(paint.getStrokeCap()))
+{
+}
+
+SkStrokePathEffect::SkStrokePathEffect(SkScalar width, SkPaint::Style style, SkPaint::Join join, SkPaint::Cap cap, SkScalar miter)
+       : fWidth(width), fMiter(miter), fStyle(SkToU8(style)), fJoin(SkToU8(join)), fCap(SkToU8(cap))
+{
+       if (miter < 0)  // signal they want the default
+               fMiter = SK_DefaultMiterLimit;
+}
+
+bool SkStrokePathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
+{
+       if (fWidth < 0 || fStyle == SkPaint::kFill_Style)
+               return false;
+
+       if (fStyle == SkPaint::kStroke_Style && fWidth == 0)    // hairline
+       {
+               *width = 0;
+               return true;
+       }
+
+       SkStroke        stroke;
+
+       stroke.setWidth(fWidth);
+       stroke.setMiterLimit(fMiter);
+       stroke.setJoin((SkPaint::Join)fJoin);
+       stroke.setCap((SkPaint::Cap)fCap);
+       stroke.setDoFill(fStyle == SkPaint::kStrokeAndFill_Style);
+
+       stroke.strokePath(src, dst);
+       return true;
+}
+
+SkFlattenable::Factory SkStrokePathEffect::getFactory()
+{
+       return CreateProc;
+}
+
+SkFlattenable* SkStrokePathEffect::CreateProc(SkRBuffer& buffer)
+{
+       return SkNEW_ARGS(SkStrokePathEffect, (buffer));
+}
+
+void SkStrokePathEffect::flatten(SkWBuffer& buffer)
+{
+    this->INHERITED::flatten(buffer);
+
+       buffer.writeScalar(fWidth);
+       buffer.writeScalar(fMiter);
+    buffer.write8(fStyle);
+    buffer.write8(fJoin);
+    buffer.write8(fCap);
+    buffer.padToAlign4();
+}
+
+SkStrokePathEffect::SkStrokePathEffect(SkRBuffer& buffer)
+       : SkPathEffect(buffer)
+{
+    fWidth = buffer.readScalar();
+    fMiter = buffer.readScalar();
+    fStyle = buffer.readU8();
+    fJoin = buffer.readU8();
+    fCap = buffer.readU8();
+    buffer.skipToAlign4();
+}
+
+
diff --git a/libs/graphics/sgl/SkPathMeasure.cpp b/libs/graphics/sgl/SkPathMeasure.cpp
new file mode 100644 (file)
index 0000000..6191724
--- /dev/null
@@ -0,0 +1,623 @@
+#include "SkPathMeasure.h"
+#include "SkGeometry.h"
+#include "SkPath.h"
+#include "SkTSearch.h"
+
+// these must be 0,1,2 since they are in our 2-bit field
+enum {
+       kLine_SegType,
+       kCloseLine_SegType,
+       kQuad_SegType,
+       kCubic_SegType
+};
+
+#define kMaxTValue     32767
+
+static inline SkScalar tValue2Scalar(int t)
+{
+       SkASSERT((unsigned)t <= kMaxTValue);
+
+#ifdef SK_SCALAR_IS_FLOAT
+       return t * 3.05185e-5f; // t / 32767
+#else
+       return (t + (t >> 14)) << 1;
+#endif
+}
+
+SkScalar SkPathMeasure::Segment::getScalarT() const
+{
+       return tValue2Scalar(fTValue);
+}
+
+const SkPathMeasure::Segment* SkPathMeasure::NextSegment(const Segment* seg)
+{
+       unsigned ptIndex = seg->fPtIndex;
+
+       do {
+               ++seg;
+       } while (seg->fPtIndex == ptIndex);
+       return seg;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+static inline int tspan_big_enough(int tspan)
+{
+       SkASSERT((unsigned)tspan <= kMaxTValue);
+       return tspan >> 10;
+}
+
+#if 0
+static inline bool tangents_too_curvy(const SkVector& tan0, SkVector& tan1)
+{
+       static const SkScalar kFlatEnoughTangentDotProd = SK_Scalar1 * 99 / 100;
+
+       SkASSERT(kFlatEnoughTangentDotProd > 0 && kFlatEnoughTangentDotProd < SK_Scalar1);
+
+       return SkPoint::DotProduct(tan0, tan1) < kFlatEnoughTangentDotProd;
+}
+#endif
+
+// can't use tangents, since we need [0..1..................2] to be seen
+// as definitely not a line (it is when drawn, but not parametrically)
+// so we compare midpoints
+#define CHEAP_DIST_LIMIT       (SK_Scalar1/2)  // just made this value up
+
+static bool cheap_dist_exceeds_limit(const SkPoint& pt, SkScalar x, SkScalar y)
+{
+       SkScalar dist = SkMaxScalar(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY));
+       // just made up the 1/2
+       return dist > CHEAP_DIST_LIMIT;
+}
+
+static bool quad_too_curvy(const SkPoint pts[3])
+{
+#if 0
+       SkPoint         mid;
+       SkEvalQuadAtHalf(pts, &mid);
+       return cheap_dist_exceeds_limit(mid,
+                                                                       SkScalarAve(pts[0].fX, pts[2].fX),
+                                                                       SkScalarAve(pts[0].fY, pts[2].fY));
+#else
+       // diff = (a/4 + b/2 + c/4) - (a/2 + c/2)
+       // diff = -a/4 + b/2 - c/4
+       SkScalar dx = SkScalarHalf(pts[1].fX) - SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX));
+       SkScalar dy = SkScalarHalf(pts[1].fY) - SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY));
+
+       SkScalar dist = SkMaxScalar(SkScalarAbs(dx), SkScalarAbs(dy));
+       return dist > CHEAP_DIST_LIMIT;
+#endif
+}
+
+static bool cubic_too_curvy(const SkPoint pts[4])
+{
+       SkPoint third;
+
+       // test 1/3
+       SkEvalCubicAt(pts, SK_Scalar1/3, &third, nil, nil);
+       if (cheap_dist_exceeds_limit(third,
+                                                                SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3),
+                                                                SkScalarInterp(pts[0].fY, pts[2].fY, SK_Scalar1/3)))
+               return true;
+
+       // test 2/3
+       SkEvalCubicAt(pts, SK_Scalar1*2/3, &third, nil, nil);
+       return cheap_dist_exceeds_limit(third,
+                                                                       SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3),
+                                                                       SkScalarInterp(pts[0].fY, pts[2].fY, SK_Scalar1*2/3));
+}
+
+SkScalar SkPathMeasure::compute_quad_segs(const SkPoint pts[3], SkScalar distance,
+                                                                                 int mint, int maxt, int ptIndex)
+{
+       if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts))
+       {
+               SkPoint tmp[5];
+               int             halft = (mint + maxt) >> 1;
+
+               SkChopQuadAtHalf(pts, tmp);
+               distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex);
+               distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptIndex);
+       }
+       else
+       {
+               SkScalar d = SkPoint::Distance(pts[0], pts[2]);
+               SkASSERT(d >= 0);
+               if (!SkScalarNearlyZero(d))
+               {
+                       distance += d;
+                       Segment* seg = fSegments.append();
+                       seg->fDistance = distance;
+                       seg->fPtIndex = ptIndex;
+                       seg->fType = kQuad_SegType;
+                       seg->fTValue = maxt;
+               }
+       }
+       return distance;
+}
+
+SkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4], SkScalar distance,
+                                                                                  int mint, int maxt, int ptIndex)
+{
+       if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts))
+       {
+               SkPoint tmp[7];
+               int             halft = (mint + maxt) >> 1;
+
+               SkChopCubicAtHalf(pts, tmp);
+               distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex);
+               distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIndex);
+       }
+       else
+       {
+               SkScalar d = SkPoint::Distance(pts[0], pts[3]);
+               SkASSERT(d >= 0);
+               if (!SkScalarNearlyZero(d))
+               {
+                       distance += d;
+                       Segment* seg = fSegments.append();
+                       seg->fDistance = distance;
+                       seg->fPtIndex = ptIndex;
+                       seg->fType = kCubic_SegType;
+                       seg->fTValue = maxt;
+               }
+       }
+       return distance;
+}
+
+void SkPathMeasure::buildSegments()
+{
+       SkPoint                 pts[4];
+       int                             ptIndex = fFirstPtIndex;
+       SkScalar                d, distance = 0;
+       bool                    isClosed = fForceClosed;
+       bool                    firstMoveTo = ptIndex < 0;
+       Segment*                seg;
+
+       fSegments.reset();
+       for (;;)
+       {
+               switch (fIter.next(pts)) {
+               case SkPath::kMove_Verb:
+                       if (!firstMoveTo)
+                               goto DONE;
+                       ptIndex += 1;
+                       firstMoveTo = false;
+                       break;
+
+               case SkPath::kLine_Verb:
+                       d = SkPoint::Distance(pts[0], pts[1]);
+                       SkASSERT(d >= 0);
+                       if (!SkScalarNearlyZero(d))
+                       {
+                               distance += d;
+                               seg = fSegments.append();
+                               seg->fDistance = distance;
+                               seg->fPtIndex = ptIndex;
+                               seg->fType = fIter.isCloseLine() ? kCloseLine_SegType : kLine_SegType;
+                               seg->fTValue = kMaxTValue;
+                       }
+                       ptIndex += !fIter.isCloseLine();
+                       break;
+
+               case SkPath::kQuad_Verb:
+                       distance = this->compute_quad_segs(pts, distance, 0, kMaxTValue, ptIndex);
+                       ptIndex += 2;
+                       break;
+
+               case SkPath::kCubic_Verb:
+                       distance = this->compute_cubic_segs(pts, distance, 0, kMaxTValue, ptIndex);
+                       ptIndex += 3;
+                       break;
+
+               case SkPath::kClose_Verb:
+                       isClosed = true;
+                       break;
+                       
+               case SkPath::kDone_Verb:
+                       goto DONE;
+               }
+       }
+DONE:
+       fLength = distance;
+       fIsClosed = isClosed;
+       fFirstPtIndex = ptIndex + 1;
+
+#ifdef SK_DEBUG
+       {
+               const Segment* seg = fSegments.begin();
+               const Segment* stop = fSegments.end();
+               unsigned                ptIndex = 0;
+               SkScalar                distance = 0;
+
+               while (seg < stop)
+               {
+               //      SkDebugf("seg dist=%g t=%d p=%d\n", seg->fDistance, seg->fTValue, seg->fPtIndex);
+
+                       SkASSERT(seg->fDistance > distance);
+                       SkASSERT(seg->fPtIndex >= ptIndex);
+                       SkASSERT(seg->fTValue > 0);
+
+                       const Segment* s = seg;
+                       while (s < stop - 1 && s[0].fPtIndex == s[1].fPtIndex)
+                       {
+                               SkASSERT(s[0].fType == s[1].fType);
+                               SkASSERT(s[0].fTValue < s[1].fTValue);
+                               s += 1;
+                       }
+
+                       distance = seg->fDistance;
+                       ptIndex = seg->fPtIndex;
+                       seg += 1;
+               }
+       //      SkDebugf("\n");
+       }
+#endif
+}
+
+// marked as a friend in SkPath.h
+const SkPoint* sk_get_path_points(const SkPath& path, int index)
+{
+       return &path.fPts[index];
+}
+
+static void compute_pos_tan(const SkPath& path, int firstPtIndex, int ptIndex, int segType,
+                                                       SkScalar t, SkPoint* pos, SkVector* tangent)
+{
+       const SkPoint*  pts = sk_get_path_points(path, ptIndex);
+
+       switch (segType) {
+       case kLine_SegType:
+       case kCloseLine_SegType:
+               {
+                       const SkPoint* endp = (segType == kLine_SegType) ?
+                                                                       &pts[1] :
+                                                                       sk_get_path_points(path, firstPtIndex);
+
+                       if (pos)
+                               pos->set(SkScalarInterp(pts[0].fX, endp->fX, t),
+                                               SkScalarInterp(pts[0].fY, endp->fY, t));
+                       if (tangent)
+                               tangent->setUnit(endp->fX - pts[0].fX, endp->fY - pts[0].fY);
+               }
+               break;
+       case kQuad_SegType:
+               SkEvalQuadAt(pts, t, pos, tangent);
+               if (tangent)
+                       tangent->normalize();
+               break;
+       case kCubic_SegType:
+               SkEvalCubicAt(pts, t, pos, tangent, nil);
+               if (tangent)
+                       tangent->normalize();
+               break;
+       default:
+               SkASSERT(!"unknown segType");
+       }
+}
+
+static void seg_to(const SkPath& src, int firstPtIndex, int ptIndex, int segType, SkScalar startT, SkScalar stopT, SkPath* dst)
+{
+       SkASSERT(startT >= 0 && startT <= SK_Scalar1);
+       SkASSERT(stopT >= 0 && stopT <= SK_Scalar1);
+       SkASSERT(startT <= stopT);
+
+       if (SkScalarNearlyZero(stopT - startT))
+               return;
+
+       const SkPoint*  pts = sk_get_path_points(src, ptIndex);
+       SkPoint                 tmp0[7], tmp1[7];
+
+       switch (segType) {
+       case kLine_SegType:
+       case kCloseLine_SegType:
+               {
+                       const SkPoint* endp = (segType == kLine_SegType) ?
+                                                                       &pts[1] :
+                                                                       sk_get_path_points(src, firstPtIndex);
+
+                       if (stopT == kMaxTValue)
+                               dst->lineTo(*endp);
+                       else
+                               dst->lineTo(SkScalarInterp(pts[0].fX, endp->fX, stopT),
+                                                       SkScalarInterp(pts[0].fY, endp->fY, stopT));
+               }
+               break;
+       case kQuad_SegType:
+               if (startT == 0)
+               {
+                       if (stopT == SK_Scalar1)
+                               dst->quadTo(pts[1], pts[2]);
+                       else
+                       {
+                               SkChopQuadAt(pts, tmp0, stopT);
+                               dst->quadTo(tmp0[1], tmp0[2]);
+                       }
+               }
+               else
+               {
+                       SkChopQuadAt(pts, tmp0, startT);
+                       if (stopT == SK_Scalar1)
+                               dst->quadTo(tmp0[3], tmp0[4]);
+                       else
+                       {
+                               SkChopQuadAt(&tmp0[2], tmp1, SkScalarDiv(stopT - startT, SK_Scalar1 - startT));
+                               dst->quadTo(tmp1[1], tmp1[2]);
+                       }
+               }
+               break;
+       case kCubic_SegType:
+               if (startT == 0)
+               {
+                       if (stopT == SK_Scalar1)
+                               dst->cubicTo(pts[1], pts[2], pts[3]);
+                       else
+                       {
+                               SkChopCubicAt(pts, tmp0, stopT);
+                               dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]);
+                       }
+               }
+               else
+               {
+                       SkChopCubicAt(pts, tmp0, startT);
+                       if (stopT == SK_Scalar1)
+                               dst->cubicTo(tmp0[4], tmp0[5], tmp0[6]);
+                       else
+                       {
+                               SkChopCubicAt(&tmp0[3], tmp1, SkScalarDiv(stopT - startT, SK_Scalar1 - startT));
+                               dst->cubicTo(tmp1[1], tmp1[2], tmp1[3]);
+                       }
+               }
+               break;
+       default:
+               SkASSERT(!"unknown segType");
+               sk_throw();
+       }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+SkPathMeasure::SkPathMeasure()
+{
+       fPath = nil;
+       fLength = -1;   // signal we need to compute it
+       fForceClosed = false;
+       fFirstPtIndex = -1;
+}
+
+SkPathMeasure::SkPathMeasure(const SkPath& path, bool forceClosed)
+{
+       fPath = &path;
+       fLength = -1;   // signal we need to compute it
+       fForceClosed = forceClosed;
+       fFirstPtIndex = -1;
+
+       fIter.setPath(path, forceClosed);
+}
+
+SkPathMeasure::~SkPathMeasure()
+{
+}
+
+/** Assign a new path, or nil to have none.
+*/
+void SkPathMeasure::setPath(const SkPath* path, bool forceClosed)
+{
+       fPath = path;
+       fLength = -1;   // signal we need to compute it
+       fForceClosed = forceClosed;
+       fFirstPtIndex = -1;
+
+       if (path)
+               fIter.setPath(*path, forceClosed);
+       fSegments.reset();
+}
+
+SkScalar SkPathMeasure::getLength()
+{
+       if (fPath == nil)
+               return 0;
+
+       if (fLength < 0)
+               this->buildSegments();
+
+       SkASSERT(fLength >= 0);
+       return fLength;
+}
+
+const SkPathMeasure::Segment* SkPathMeasure::distanceToSegment(SkScalar distance, SkScalar* t)
+{
+       SkDEBUGCODE(SkScalar length = ) this->getLength();
+       SkASSERT(distance >= 0 && distance <= length);
+
+       const Segment*  seg = fSegments.begin();
+       int                             count = fSegments.count();
+
+       int index = SkTSearch<SkScalar>(&seg->fDistance, count, distance, sizeof(Segment));
+       // don't care if we hit an exact match or not, so we xor index if it is negative
+       index ^= (index >> 31);
+       seg = &seg[index];
+
+       // now interpolate t-values with the prev segment (if possible)
+       SkScalar        startT = 0, startD = 0;
+       // check if the prev segment is legal, and references the same set of points
+       if (index > 0)
+       {
+               startD = seg[-1].fDistance;
+               if (seg[-1].fPtIndex == seg->fPtIndex)
+               {
+                       SkASSERT(seg[-1].fType == seg->fType);
+                       startT = seg[-1].getScalarT();
+               }
+       }
+
+       SkASSERT(seg->getScalarT() > startT);
+       SkASSERT(distance >= startD);
+       SkASSERT(seg->fDistance > startD);
+
+       *t = startT + SkScalarMulDiv(seg->getScalarT() - startT,
+                                                                distance - startD,
+                                                                seg->fDistance - startD);
+       return seg;
+}
+
+bool SkPathMeasure::getPosTan(SkScalar distance, SkPoint* pos, SkVector* tangent)
+{
+       SkASSERT(fPath);
+       if (fPath == nil)
+       {
+       EMPTY:
+               return false;
+       }
+
+       SkScalar        length = this->getLength();     // call this to force computing it
+       int                     count = fSegments.count();
+
+       if (count == 0 || length == 0)
+               goto EMPTY;
+
+       // pin the distance to a legal range
+       if (distance < 0)
+               distance = 0;
+       else if (distance > length)
+               distance = length;
+
+       SkScalar                t;
+       const Segment*  seg = this->distanceToSegment(distance, &t);
+
+       compute_pos_tan(*fPath, fSegments[0].fPtIndex, seg->fPtIndex, seg->fType, t, pos, tangent);
+       return true;
+}
+
+bool SkPathMeasure::getMatrix(SkScalar distance, SkMatrix* matrix, MatrixFlags flags)
+{
+       SkPoint         position;
+       SkVector        tangent;
+
+       if (this->getPosTan(distance, &position, &tangent))
+       {
+               if (matrix)
+               {
+                       if (flags & kGetTangent_MatrixFlag)
+                               matrix->setSinCos(tangent.fY, tangent.fX, 0, 0);
+                       else
+                               matrix->reset();
+                       if (flags & kGetPosition_MatrixFlag)
+                               matrix->postTranslate(position.fX, position.fY);
+               }
+               return true;
+       }
+       return false;
+}
+
+bool SkPathMeasure::getSegment(SkScalar startD, SkScalar stopD, SkPath* dst, bool startWithMoveTo)
+{
+       SkASSERT(dst);
+
+       SkScalar length = this->getLength();    // ensure we have built our segments
+
+       if (startD < 0)
+               startD = 0;
+       if (stopD > length)
+               stopD = length;
+       if (startD >= stopD)
+               return false;
+
+       SkPoint  p;
+       SkScalar startT, stopT;
+       const Segment* seg = this->distanceToSegment(startD, &startT);
+       const Segment* stopSeg = this->distanceToSegment(stopD, &stopT);
+       SkASSERT(seg <= stopSeg);
+
+       if (startWithMoveTo)
+       {
+               compute_pos_tan(*fPath, fSegments[0].fPtIndex, seg->fPtIndex, seg->fType, startT, &p, nil);
+               dst->moveTo(p);
+       }
+
+       if (seg->fPtIndex == stopSeg->fPtIndex)
+               seg_to(*fPath, fSegments[0].fPtIndex, seg->fPtIndex, seg->fType, startT, stopT, dst);
+       else
+       {
+               do {
+                       seg_to(*fPath, fSegments[0].fPtIndex, seg->fPtIndex, seg->fType, startT, SK_Scalar1, dst);
+                       seg = SkPathMeasure::NextSegment(seg);
+                       startT = 0;
+               } while (seg->fPtIndex < stopSeg->fPtIndex);
+               seg_to(*fPath, fSegments[0].fPtIndex, seg->fPtIndex, seg->fType, 0, stopT, dst);
+       }
+       return true;
+}
+
+bool SkPathMeasure::isClosed()
+{
+       (void)this->getLength();
+       return fIsClosed;
+}
+
+/**    Move to the next contour in the path. Return true if one exists, or false if
+       we're done with the path.
+*/
+bool SkPathMeasure::nextContour()
+{
+       fLength = -1;
+       return this->getLength() > 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+void SkPathMeasure::dump()
+{
+       SkDebugf("pathmeas: length=%g, segs=%d\n", fLength, fSegments.count());
+
+       for (int i = 0; i < fSegments.count(); i++)
+       {
+               const Segment* seg = &fSegments[i];
+               SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n",
+                               i, seg->fDistance, seg->fPtIndex, seg->getScalarT(), seg->fType);
+       }
+}
+
+void SkPathMeasure::UnitTest()
+{
+#ifdef SK_SUPPORT_UNITTEST
+       SkPath  path;
+
+       path.moveTo(0, 0);
+       path.lineTo(SK_Scalar1, 0);
+       path.lineTo(SK_Scalar1, SK_Scalar1);
+       path.lineTo(0, SK_Scalar1);
+
+       SkPathMeasure   meas(path, true);
+       SkScalar                length = meas.getLength();
+       SkASSERT(length == SK_Scalar1*4);
+
+       path.reset();
+       path.moveTo(0, 0);
+       path.lineTo(SK_Scalar1*3, SK_Scalar1*4);
+       meas.setPath(&path, false);
+       length = meas.getLength();
+       SkASSERT(length == SK_Scalar1*5);
+
+       path.reset();
+       path.addCircle(0, 0, SK_Scalar1);
+       meas.setPath(&path, true);
+       length = meas.getLength();
+       SkDebugf("circle arc-length = %g\n", length);
+
+       for (int i = 0; i < 8; i++)
+       {
+               SkScalar        d = length * i / 8;
+               SkPoint         p;
+               SkVector        v;
+               meas.getPosTan(d, &p, &v);
+               SkDebugf("circle arc-length=%g, pos[%g %g] tan[%g %g]\n", d, p.fX, p.fY, v.fX, v.fY);
+       }
+#endif
+}
+
+#endif
diff --git a/libs/graphics/sgl/SkProcSpriteBlitter.cpp b/libs/graphics/sgl/SkProcSpriteBlitter.cpp
new file mode 100644 (file)
index 0000000..9f0592f
--- /dev/null
@@ -0,0 +1,38 @@
+#if 0  // experimental
+
+class SkProcSpriteBlitter : public SkSpriteBlitter {
+public:
+       typedef void (*Proc)(void* dst, const void* src, int count, const U32 ctable[]);
+
+       SkProcSpriteBlitter(const SkBitmap& source, Proc proc, unsigned srcShift, unsigned dstShift)
+               : SkSpriteBlitter(source), fProc(proc), fSrcShift(SkToU8(srcShift)), fDstShift(SkToU8(dstShift)) {}
+
+       virtual void blitRect(int x, int y, int width, int height)
+       {
+               size_t          dstRB = fDevice.rowBytes();
+               size_t          srcRB = fSource.rowBytes();
+               char*           dst = (char*)fDevice.getPixels() + y * dstRB + (x << fDstShift);
+               const char*     src = (const char*)fSource.getPixels() + (y - fTop) * srcRB + ((x - fLeft) << fSrcShift);
+               Proc            proc = fProc;
+               const U32*      ctable = nil;
+
+               if fSource.getColorTable())
+                       ctable = fSource.getColorTable()->lockColors();
+
+               while (--height >= 0)
+               {
+                       proc(dst, src, width, ctable);
+                       dst += dstRB;
+                       src += srcRB;
+               }
+
+               if fSource.getColorTable())
+                       fSource.getColorTable()->unlockColors(false);
+       }
+
+private:
+       Proc    fProc;
+       U8              fSrcShift, fDstShift;
+};
+
+#endif
diff --git a/libs/graphics/sgl/SkRasterizer.cpp b/libs/graphics/sgl/SkRasterizer.cpp
new file mode 100644 (file)
index 0000000..5e3dc99
--- /dev/null
@@ -0,0 +1,45 @@
+#include "SkRasterizer.h"
+#include "SkDraw.h"
+#include "SkMaskFilter.h"
+#include "SkPath.h"
+
+// do nothing for now, since we don't store anything at flatten time
+SkRasterizer::SkRasterizer(SkRBuffer&) {}
+
+bool SkRasterizer::rasterize(const SkPath& fillPath, const SkMatrix& matrix,
+                             const SkRect16* clipBounds, SkMaskFilter* filter,
+                             SkMask* mask, SkMask::CreateMode mode)
+{
+    SkRect16 storage;
+    
+    if (clipBounds && filter && SkMask::kJustRenderImage_CreateMode != mode)
+    {        
+        SkPoint16   margin;
+        SkMask      srcM, dstM;
+        
+        srcM.fFormat = SkMask::kA8_Format;
+        srcM.fBounds.set(0, 0, 1, 1);
+        srcM.fImage = NULL;
+        if (!filter->filterMask(&dstM, srcM, matrix, &margin))
+            return false;
+        
+        storage = *clipBounds;
+        storage.inset(-margin.fX, -margin.fY);
+        clipBounds = &storage;
+    }
+    
+    return this->onRasterize(fillPath, matrix, clipBounds, mask, mode);
+}
+
+/*  Our default implementation of the virtual method just scan converts
+*/
+bool SkRasterizer::onRasterize(const SkPath& fillPath, const SkMatrix& matrix,
+                             const SkRect16* clipBounds,
+                             SkMask* mask, SkMask::CreateMode mode)
+{
+    SkPath  devPath;
+    
+    fillPath.transform(matrix, &devPath);
+    return SkDraw::DrawToMask(devPath, clipBounds, NULL, NULL, mask, mode);
+}
+
diff --git a/libs/graphics/sgl/SkRefCnt.cpp b/libs/graphics/sgl/SkRefCnt.cpp
new file mode 100644 (file)
index 0000000..7c3d59c
--- /dev/null
@@ -0,0 +1,36 @@
+#include "SkRefCnt.h"
+
+SkAutoUnref::~SkAutoUnref()
+{
+       if (fObj)
+               fObj->unref();
+}
+
+bool SkAutoUnref::ref()
+{
+       if (fObj)
+       {
+               fObj->ref();
+               return true;
+       }
+       return false;
+}
+
+bool SkAutoUnref::unref()
+{
+       if (fObj)
+       {
+               fObj->unref();
+               fObj = nil;
+               return true;
+       }
+       return false;
+}
+
+SkRefCnt* SkAutoUnref::detach()
+{
+       SkRefCnt* obj = fObj;
+
+       fObj = nil;
+       return obj;
+}
diff --git a/libs/graphics/sgl/SkRegion_path.cpp b/libs/graphics/sgl/SkRegion_path.cpp
new file mode 100644 (file)
index 0000000..ab45c8f
--- /dev/null
@@ -0,0 +1,478 @@
+#include "SkRegionPriv.h"
+#include "SkBlitter.h"
+#include "SkScan.h"
+#include "SkTDArray.h"
+#include "SkPath.h"
+
+class SkRgnBuilder : public SkBlitter {
+public:
+       virtual ~SkRgnBuilder();
+       
+       void    init(int maxHeight, int maxTransitions);
+       void    done() { (void)this->collapsWithPrev(); }
+
+       int             computeRunCount() const;
+       void    copyToRect(SkRect16*) const;
+       void    copyToRgn(S16 runs[]) const;
+
+       virtual void blitH(int x, int y, int width);
+
+#ifdef SK_DEBUG
+       void dump() const
+       {
+               SkDebugf("SkRgnBuilder: Top = %d\n", fTop);
+               const Scanline* line = (Scanline*)fStorage;
+               while (line < fCurrScanline)
+               {
+                       SkDebugf("SkRgnBuilder::Scanline: LastY=%d, fXCount=%d", line->fLastY, line->fXCount);
+                       for (int i = 0; i < line->fXCount; i++)
+                               SkDebugf(" %d", line->firstX()[i]);
+                       SkDebugf("\n");
+
+                       line = line->nextScanline();
+               }
+       }
+#endif
+private:
+       struct Scanline {
+               S16     fLastY;
+               S16     fXCount;
+
+               S16*            firstX() const { return (S16*)(this + 1); }
+               Scanline*       nextScanline() const { return (Scanline*)((S16*)(this + 1) + fXCount); }
+       };
+       S16*            fStorage;
+       Scanline*       fCurrScanline;
+       Scanline*       fPrevScanline;
+       S16*            fCurrXPtr;              //      points at next avialable x[] in fCurrScanline
+       S16                     fTop;                   // first Y value
+
+       bool collapsWithPrev()
+       {
+               if (fPrevScanline != nil &&
+                       fPrevScanline->fLastY + 1 == fCurrScanline->fLastY &&
+                       fPrevScanline->fXCount == fCurrScanline->fXCount &&
+                       !memcmp(fPrevScanline->firstX(),
+                                       fCurrScanline->firstX(),
+                                       fCurrScanline->fXCount * sizeof(S16)))
+               {
+                       // update the height of fPrevScanline
+                       fPrevScanline->fLastY = fCurrScanline->fLastY;
+                       return true;
+               }
+               return false;
+       }
+};
+
+SkRgnBuilder::~SkRgnBuilder()
+{
+       sk_free(fStorage);
+}
+
+void SkRgnBuilder::init(int maxHeight, int maxTransitions)
+{
+       int     count = maxHeight * (3 + maxTransitions);
+
+       // add maxTransitions to have slop for working buffer
+       fStorage = (S16*)sk_malloc_throw((count + 3 + maxTransitions) * sizeof(S16));
+
+       fCurrScanline = nil;    // signal empty collection
+       fPrevScanline = nil;    // signal first scanline
+}
+
+void SkRgnBuilder::blitH(int x, int y, int width)
+{
+       if (fCurrScanline == nil)       // first time
+       {
+               fTop = SkToS16(y);
+               fCurrScanline = (Scanline*)fStorage;
+               fCurrScanline->fLastY = SkToS16(y);
+               fCurrXPtr = fCurrScanline->firstX();
+       }
+       else
+       {
+               SkASSERT(y >= fCurrScanline->fLastY);
+
+               if (y > fCurrScanline->fLastY)
+               {
+                       // if we get here, we're done with fCurrScanline
+                       fCurrScanline->fXCount = SkToS16((int)(fCurrXPtr - fCurrScanline->firstX()));
+
+                       int     prevLastY = fCurrScanline->fLastY;
+                       if (!this->collapsWithPrev())
+                       {
+                               fPrevScanline = fCurrScanline;
+                               fCurrScanline = fCurrScanline->nextScanline();
+
+                       }
+                       if (y - 1 > prevLastY)  // insert empty run
+                       {
+                               fCurrScanline->fLastY = SkToS16(y - 1);
+                               fCurrScanline->fXCount = 0;
+                               fCurrScanline = fCurrScanline->nextScanline();
+                       }
+                       // setup for the new curr line
+                       fCurrScanline->fLastY = SkToS16(y);
+                       fCurrXPtr = fCurrScanline->firstX();
+               }
+       }
+       //      check if we should extend the current run, or add a new one
+       if (fCurrXPtr > fCurrScanline->firstX() && fCurrXPtr[-1] == x)
+               fCurrXPtr[-1] = SkToS16(x + width);
+       else
+       {
+               fCurrXPtr[0] = SkToS16(x);
+               fCurrXPtr[1] = SkToS16(x + width);
+               fCurrXPtr += 2;
+       }
+}
+
+int SkRgnBuilder::computeRunCount() const
+{
+       if (fCurrScanline == nil)
+               return 0;
+
+       const S16*      line = fStorage;
+       const S16*      stop = (const S16*)fCurrScanline;
+
+       return 2 + (int)(stop - line);
+}
+
+void SkRgnBuilder::copyToRect(SkRect16* r) const
+{
+       SkASSERT(fCurrScanline != nil);
+       SkASSERT((const S16*)fCurrScanline - fStorage == 4);
+
+       const Scanline* line = (const Scanline*)fStorage;
+       SkASSERT(line->fXCount == 2);
+
+       r->set(line->firstX()[0], fTop, line->firstX()[1], line->fLastY + 1);
+}
+
+void SkRgnBuilder::copyToRgn(S16 runs[]) const
+{
+       SkASSERT(fCurrScanline != nil);
+       SkASSERT((const S16*)fCurrScanline - fStorage > 4);
+
+       const Scanline* line = (const Scanline*)fStorage;
+       const Scanline* stop = fCurrScanline;
+
+       *runs++ = fTop;
+       do {
+               *runs++ = SkToS16(line->fLastY + 1);
+               int     count = line->fXCount;
+               if (count)
+               {
+                       memcpy(runs, line->firstX(), count * sizeof(S16));
+                       runs += count;
+               }
+               *runs++ = kRunTypeSentinel;
+               line = line->nextScanline();
+       } while (line < stop);
+       SkASSERT(line == stop);
+       *runs = kRunTypeSentinel;
+}
+
+static int count_path_runtype_values(const SkPath& path, int* itop, int* ibot)
+{
+       static const U8 gPathVerbToInitialPointCount[] = {
+               0,      //      kMove_Verb
+               1,      //      kLine_Verb
+               2,      //      kQuad_Verb
+               3,      //      kCubic_Verb
+               0,      //      kClose_Verb
+               0       //      kDone_Verb
+       };
+
+       static const U8 gPathVerbToMaxEdges[] = {
+               0,      //      kMove_Verb
+               1,      //      kLine_Verb
+               2,      //      kQuad_VerbB
+               3,      //      kCubic_Verb
+               0,      //      kClose_Verb
+               0       //      kDone_Verb
+       };
+
+       SkPath::Iter    iter(path, true);
+       SkPoint                 pts[4];
+       SkPath::Verb    verb;
+
+       int     maxEdges = 0;
+       SkScalar        top = SkIntToScalar(SK_MaxS16);
+       SkScalar        bot = SkIntToScalar(SK_MinS16);
+
+       while ((verb = iter.next(pts)) != SkPath::kDone_Verb)
+       {
+               int     ptCount = gPathVerbToInitialPointCount[verb];
+               if (ptCount)
+               {
+                       maxEdges += gPathVerbToMaxEdges[verb];
+                       for (int i = ptCount - 1; i >= 0; --i)
+                       {
+                               if (top > pts[i].fY)
+                                       top = pts[i].fY;
+                               else if (bot < pts[i].fY)
+                                       bot = pts[i].fY;
+                       }
+               }
+       }
+       SkASSERT(top <= bot);
+
+       *itop = SkScalarRound(top);
+       *ibot = SkScalarRound(bot);
+       return maxEdges;
+}
+
+bool SkRegion::setPath(const SkPath& path, const SkRegion* clip)
+{
+       SkDEBUGCODE(this->validate();)
+
+       if (path.isEmpty() || clip && clip->isEmpty())
+               return this->setEmpty();
+
+       //      compute worst-case rgn-size for the path
+       int     pathTop, pathBot;
+       int     pathTransitions = count_path_runtype_values(path, &pathTop, &pathBot);
+       int     clipTop, clipBot;
+       int clipTransitions = clip->count_runtype_values(&clipTop, &clipBot);
+
+       int     top = SkMax32(pathTop, clipTop);
+       int bot = SkMin32(pathBot, clipBot);
+
+       if (top >= bot)
+               return this->setEmpty();
+
+       SkRgnBuilder builder;
+       
+       builder.init(bot - top, SkMax32(pathTransitions, clipTransitions));
+       SkScan::FillPath(path, clip, &builder);
+       builder.done();
+
+       int     count = builder.computeRunCount();
+       if (count == 0)
+    {
+               return this->setEmpty();
+    }
+       else if (count == kRectRegionRuns)
+       {
+               builder.copyToRect(&fBounds);
+        this->setRect(fBounds);
+       }
+       else
+       {
+               SkRegion        tmp;
+
+               tmp.fRunHead = RunHead::Alloc(count);
+               builder.copyToRgn(tmp.fRunHead->runs());
+               compute_run_bounds(tmp.fRunHead->runs(), count, &tmp.fBounds);
+               this->swap(tmp);
+       }
+       SkDEBUGCODE(this->validate();)
+       return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+struct SkPrivPoint {
+    int fX, fY;
+    
+    friend int operator==(const SkPrivPoint& a, const SkPrivPoint& b)
+    {
+        return a.fX == b.fX && a.fY == b.fY;
+    }
+    friend int operator!=(const SkPrivPoint& a, const SkPrivPoint& b)
+    {
+        return a.fX != b.fX || a.fY != b.fY;
+    }
+};
+
+struct SkPrivLine {
+    SkPrivPoint   fP0, fP1;
+    int     fWinding;
+    SkPrivLine*   fNext, *fPrev;
+    
+    void set(int x, int y0, int y1)
+    {
+        fP0.fX = x;
+        fP0.fY = y0;
+        fP1.fX = x;
+        fP1.fY = y1;
+        fWinding = y1 > y0;     // 1: up, 0: down
+        fNext = fPrev = nil;
+    }
+    
+    void detach()
+    {
+        fNext->fPrev = fPrev;
+        fPrev->fNext = fNext;
+    }
+    
+    void attachNext(SkPrivLine* next)
+    {
+        next->fNext = fNext;
+        next->fPrev = this;
+        fNext->fPrev = next;
+        fNext = next;
+    }
+};
+
+static SkPrivLine* find_match(SkPrivLine* ctr, SkPrivLine* skip)
+{
+    const SkPrivPoint pt = skip->fP1;
+    int         winding = skip->fWinding;
+
+    SkPrivLine* start = ctr;
+    
+    SkPrivLine*   closest_pos = nil;
+    int     dist_pos = 0x7FFFFFFF;
+    SkPrivLine*   closest_neg = nil;
+    int     dist_neg = -0x7FFFFFFF;
+
+    do {
+        // find a Line one the same scan as pt
+        if (ctr != skip && (ctr->fP0.fY == pt.fY || ctr->fP1.fY == pt.fY))
+        {
+            int dist = ctr->fP0.fX - pt.fX; // keep the sign
+
+            if (dist == 0)
+            {
+                if (winding == ctr->fWinding)   // quick accept
+                    goto FOUND;
+                else
+                    goto NEXT;                  // quick reject
+            }
+            
+            if (dist < 0)
+            {
+                if (dist > dist_neg)
+                {
+                    dist_neg = dist;
+                    closest_neg = ctr;
+                }
+            }
+            else
+            {
+                if (dist < dist_pos)
+                {
+                    dist_pos = dist;
+                    closest_pos = ctr;
+                }
+            }
+        }
+    NEXT:
+        ctr = ctr->fNext;
+    } while (ctr != start);
+
+    SkASSERT(closest_pos != nil || closest_neg != nil);
+
+    if (closest_pos == nil)
+        ctr = closest_neg;
+    else if (closest_neg == nil)
+        ctr = closest_pos;
+    else
+    {
+        if (closest_neg->fP0.fY != pt.fY)
+            ctr = closest_pos;
+        else if (closest_pos->fP0.fY != pt.fY)
+            ctr = closest_neg;
+        else
+        {
+            if (closest_pos->fWinding != closest_neg->fWinding)
+            {
+                if (closest_pos->fWinding == winding)
+                    ctr = closest_pos;
+                else
+                    ctr = closest_neg;
+            }
+            else
+            {
+                if (winding == 0)
+                    ctr = closest_pos;
+                else
+                    ctr = closest_neg;
+            }
+        }
+    }
+
+FOUND:
+    SkASSERT(ctr && ctr->fP0.fY == pt.fY);
+    return ctr;
+}
+
+static void LinesToPath(SkPrivLine lines[], int count, SkPath* path)
+{
+    SkASSERT(count > 1);
+
+    // turn the array into a linked list
+    lines[0].fNext = &lines[1];
+    lines[0].fPrev = &lines[count - 1];
+    for (int i = 1; i < count - 1; i++)
+    {
+        lines[i].fNext = &lines[i+1];
+        lines[i].fPrev = &lines[i-1];
+    }
+    lines[count - 1].fNext = &lines[0];
+    lines[count - 1].fPrev = &lines[count - 2];
+    
+    SkPrivLine* head = lines;
+
+    // loop through looking for contours
+    while (count > 0)
+    {
+        SkPrivLine* ctr = head;
+        SkPrivLine* first = ctr;
+        head = head->fNext;
+        
+        path->moveTo(SkIntToScalar(ctr->fP0.fX), SkIntToScalar(ctr->fP0.fY));
+        do {
+            SkPrivLine* next = find_match(head, ctr);
+
+            if (ctr->fP1 != next->fP0)
+            {
+                path->lineTo(SkIntToScalar(ctr->fP1.fX), SkIntToScalar(ctr->fP1.fY));      // Vertical
+                path->lineTo(SkIntToScalar(next->fP0.fX), SkIntToScalar(next->fP0.fY));    // Horzontal
+            }
+            if (head == next)
+                head = head->fNext;
+            next->detach();
+            count -= 1;
+            ctr = next;
+        } while (ctr != first);
+        path->close();
+        ctr->detach();
+        count -= 1;
+    }
+//    SkASSERT(count == 0);
+}
+
+bool SkRegion::getBoundaryPath(SkPath* path) const
+{
+    if (this->isEmpty())
+        return false;
+
+    const SkRect16& bounds = this->getBounds();
+
+    if (this->isRect())
+    {
+        SkRect  r;        
+        r.set(bounds);      // this converts the ints to scalars
+        path->addRect(r);
+        return true;
+    }
+
+    SkRegion::Iterator      iter(*this);
+    SkTDArray<SkPrivLine>     lines;
+    
+    for (const SkRect16& r = iter.rect(); !iter.done(); iter.next())
+    {
+        SkPrivLine* line = lines.append(2);
+        line[0].set(r.fLeft, r.fBottom, r.fTop);
+        line[1].set(r.fRight, r.fTop, r.fBottom);
+    }
+    
+    LinesToPath(lines.begin(), lines.count(), path);
+    return true;
+}
+
+
diff --git a/libs/graphics/sgl/SkScalerContext.cpp b/libs/graphics/sgl/SkScalerContext.cpp
new file mode 100644 (file)
index 0000000..9e44bdc
--- /dev/null
@@ -0,0 +1,498 @@
+#include "SkScalerContext.h"
+#include "SkDescriptor.h"
+#include "SkDraw.h"
+#include "SkFontHost.h"
+#include "SkMaskFilter.h"
+#include "SkPathEffect.h"
+#include "SkRasterizer.h"
+#include "SkRegion.h"
+#include "SkStroke.h"
+#include "SkThread.h"
+
+#define ComputeBWRowBytes(width)               (((unsigned)(width) + 7) >> 3)
+
+static uint16_t compute_rowbytes(unsigned format, unsigned width)
+{
+       if (format == SkMask::kBW_Format)
+               width = ComputeBWRowBytes(width);
+       return SkToU16(width);
+}
+
+size_t SkGlyph::computeImageSize() const
+{
+       size_t size = fRowBytes * fHeight;
+       if (fMaskFormat == SkMask::k3D_Format)
+               size *= 3;
+       return size;
+}
+
+#ifdef SK_DEBUG
+       #define DUMP_RECx
+#endif
+
+static SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag)
+{
+    SkFlattenable*  obj = NULL;
+    uint32_t        len;
+       const void*     data = desc->findEntry(tag, &len);
+
+       if (data)
+       {
+        SkRBuffer   buffer(data, len);
+               SkFlattenable::Factory fact = (SkFlattenable::Factory)buffer.readPtr();
+               SkASSERT(fact);
+               obj = fact(buffer);
+        SkASSERT(buffer.pos() == buffer.size());
+       }
+    return obj;
+}
+
+SkScalerContext::SkScalerContext(const SkDescriptor* desc)
+       : fPathEffect(NULL), fMaskFilter(NULL)
+{
+    memset(fAuxContext, 0, sizeof(fAuxContext));
+
+       const Rec* rec = (const Rec*)desc->findEntry(kRec_SkDescriptorTag, NULL);
+       SkASSERT(rec);
+
+       fRec = *rec;
+
+#ifdef DUMP_REC
+       desc->assertChecksum();
+       SkDebugf("SkScalarContext checksum %x count %d length %d\n", desc->getChecksum(), desc->getCount(), desc->getLength());
+       SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n",
+               rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0],
+               rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]);
+       SkDebugf("  frame %g miter %g hints %d framefill %d aa %d join %d\n",
+               rec->fFrameWidth, rec->fMiterLimit, rec->fUseHints, rec->fFrameAndFill,
+               rec->fDoAA, rec->fStrokeJoin);
+       SkDebugf("  pathEffect %x maskFilter %x\n", desc->findEntry(kPathEffect_SkDescriptorTag, NULL),
+               desc->findEntry(kMaskFilter_SkDescriptorTag, NULL));
+#endif
+
+    fPathEffect = (SkPathEffect*)load_flattenable(desc, kPathEffect_SkDescriptorTag);
+    fMaskFilter = (SkMaskFilter*)load_flattenable(desc, kMaskFilter_SkDescriptorTag);
+    fRasterizer = (SkRasterizer*)load_flattenable(desc, kRasterizer_SkDescriptorTag);
+}
+
+SkScalerContext::~SkScalerContext()
+{
+       fPathEffect->safeUnref();
+       fMaskFilter->safeUnref();
+    fRasterizer->safeUnref();
+    
+    for (unsigned i = 0; i < SK_ARRAY_COUNT(fAuxContext); i++)
+        delete fAuxContext[i];
+}
+
+static void glyph2mask(const SkGlyph& glyph, SkMask* mask)
+{
+       SkASSERT(&glyph && mask);
+
+       mask->fImage = (uint8_t*)glyph.fImage;
+       mask->fBounds.set(glyph.fLeft, glyph.fTop,
+                                       glyph.fLeft + glyph.fWidth,
+                                       glyph.fTop + glyph.fHeight);
+       mask->fRowBytes = glyph.fRowBytes;
+       mask->fFormat = glyph.fMaskFormat;
+}
+
+void SkScalerContext::getMetrics(SkGlyph* glyph)
+{
+    this->generateMetrics(glyph);
+    // assume that we're handling this glyph
+    glyph->fUseAuxContext = false;
+    
+    if (0 == glyph->fGlyphID)
+    {
+        SkFontHost::ScalerContextID id = SkFontHost::FindScalerContextIDForUnichar(glyph->fCharCode);
+        if (SK_UnknownAuxScalerContextID != id)
+        {
+            SkASSERT(id > 0 && (unsigned)id <= SK_ARRAY_COUNT(fAuxContext));
+            SkScalerContext* ctx = fAuxContext[id - 1];
+            if (NULL == ctx)
+            {
+                ctx = SkFontHost::CreateScalerContextFromID(id, fRec);
+                SkASSERT(ctx);
+                fAuxContext[id - 1] = ctx;
+            }
+            ctx->generateMetrics(glyph);
+            glyph->fUseAuxContext = true;
+        }
+    }
+
+       if (0 == glyph->fWidth)
+               return;
+    
+       if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL)
+    {
+        SkPath      devPath, fillPath;
+        SkMatrix    fillToDevMatrix;
+
+        this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
+
+        if (fRasterizer)
+        {
+            SkMask  mask;
+
+            if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
+                                       fMaskFilter, &mask,
+                                       SkMask::kJustComputeBounds_CreateMode))
+            {
+                glyph->fLeft   = mask.fBounds.fLeft;
+                glyph->fTop            = mask.fBounds.fTop;
+                glyph->fWidth  = SkToU16(mask.fBounds.width());
+                glyph->fHeight = SkToU16(mask.fBounds.height());
+            }
+            else    // draw nothing 'cause we failed
+            {
+                glyph->fLeft   = 0;
+                glyph->fTop            = 0;
+                glyph->fWidth  = 0;
+                glyph->fHeight = 0;
+                return;
+            }
+        }
+        else    // just use devPath
+        {
+            SkRect             r;
+            SkRect16   ir;
+
+            devPath.computeBounds(&r, SkPath::kExact_BoundsType);
+            r.roundOut(&ir);
+            
+            glyph->fLeft       = ir.fLeft;
+            glyph->fTop                = ir.fTop;
+            glyph->fWidth      = SkToU16(ir.width());
+            glyph->fHeight     = SkToU16(ir.height());
+        }
+    }
+
+       glyph->fMaskFormat = SkToU8(fRec.fDoAA ? SkMask::kA8_Format : SkMask::kBW_Format);
+
+       if (fMaskFilter)
+       {
+               SkMask          src, dst;
+               SkMatrix        matrix;
+
+               glyph2mask(*glyph, &src);
+               fRec.getMatrixFrom2x2(&matrix);
+
+               src.fImage = NULL;      // only want the bounds from the filter
+               if (fMaskFilter->filterMask(&dst, src, matrix, NULL))
+               {
+                       SkASSERT(dst.fImage == NULL);
+                       glyph->fLeft    = dst.fBounds.fLeft;
+                       glyph->fTop             = dst.fBounds.fTop;
+                       glyph->fWidth   = SkToU16(dst.fBounds.width());
+                       glyph->fHeight  = SkToU16(dst.fBounds.height());
+                       glyph->fMaskFormat = dst.fFormat;
+               }
+       }
+
+       glyph->fRowBytes = compute_rowbytes(glyph->fMaskFormat, glyph->fWidth);
+}
+
+//#define PLAY_WITH_GAMMA
+
+#ifdef PLAY_WITH_GAMMA
+static SkFixed interp(SkFixed a, SkFixed b, int scale)  // scale is [0..255]
+{
+    return a + ((b - a) * scale >> 8);
+}
+
+static void filter_image(uint8_t image[], size_t size)
+{
+       static uint8_t gGammaTable[256];
+    static bool gInit;
+
+       if (!gInit)
+       {
+        for (int i = 0; i < 256; i++)
+        {
+            SkFixed n = i * 257;
+            n += n >> 15;
+            SkASSERT(n >= 0 && n <= SK_Fixed1);
+        
+        //    n = SkFixedSqrt(n);
+            n = interp(SkFixedMul(n, n), n, 0xDD);
+
+            n = n * 255 >> 16;
+        //     SkDebugf("morph %d -> %d\n", i, n);
+            gGammaTable[i] = SkToU8(n);
+        }
+        gInit = true;
+       }
+    
+    const uint8_t*   table = gGammaTable;
+    uint8_t*         stop = image + size;
+    while (image < stop)
+    {
+        *image = table[*image];
+        image += 1;
+    }
+}
+#endif
+
+void SkScalerContext::getImage(const SkGlyph& origGlyph)
+{
+       const SkGlyph*  glyph = &origGlyph;
+
+       SkGlyph tmpGlyph;
+       if (fMaskFilter)        // restore the prefilter bounds
+       {
+               tmpGlyph.fCharCode = origGlyph.fCharCode;
+
+               // need the original bounds, sans our maskfilter
+               SkMaskFilter* mf = fMaskFilter;
+               fMaskFilter = NULL;                             // temp disable
+               this->getMetrics(&tmpGlyph);
+               fMaskFilter = mf;                               // restore
+
+               tmpGlyph.fImage = origGlyph.fImage;
+
+               // we need the prefilter bounds to be <= filter bounds
+               SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
+               SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
+               glyph = &tmpGlyph;
+       }
+
+       if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL)
+    {
+        SkPath      devPath, fillPath;
+        SkMatrix    fillToDevMatrix;
+
+        this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
+
+        if (fRasterizer)
+        {
+            SkMask  mask;
+            
+            mask.fFormat = SkMask::kA8_Format;
+            mask.fRowBytes = glyph->fRowBytes;
+            mask.fBounds.set(glyph->fLeft,
+                             glyph->fTop,
+                             glyph->fLeft + glyph->fWidth,
+                             glyph->fTop + glyph->fHeight);
+            mask.fImage = (uint8_t*)glyph->fImage;
+            memset(glyph->fImage, 0, glyph->fRowBytes * glyph->fHeight);
+            
+            if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
+                                        fMaskFilter, &mask, SkMask::kJustRenderImage_CreateMode))
+            {
+                return;
+            }
+        }
+        else
+        {
+            SkBitmap   bm;
+            SkBitmap::Config config;
+            SkMatrix   matrix;
+            SkRegion   clip;
+            SkPaint            paint;
+            SkDraw             draw;
+
+            if (fRec.fDoAA)
+            {
+                config = SkBitmap::kA8_Config;
+                paint.setAntiAliasOn(true);
+            }
+            else
+            {
+                config = SkBitmap::kA1_Config;
+                paint.setAntiAliasOn(false);
+            }
+
+            clip.setRect(0, 0, glyph->fWidth, glyph->fHeight);
+            matrix.setTranslate(-SkIntToScalar(glyph->fLeft), -SkIntToScalar(glyph->fTop));
+            bm.setConfig(config, glyph->fWidth, glyph->fHeight);
+            bm.setPixels(glyph->fImage);
+            memset(glyph->fImage, 0, bm.height() * bm.rowBytes());
+
+            draw.fClip = &clip;
+            draw.fMatrix = &matrix;
+            draw.fDevice = &bm;
+            draw.fBounder = NULL;
+            draw.drawPath(devPath, paint);
+        }
+    }
+       else
+    {
+        SkScalerContext* ctx = this;
+        if (glyph->fUseAuxContext)
+        {
+            SkFontHost::ScalerContextID id = SkFontHost::FindScalerContextIDForUnichar(glyph->fCharCode);
+            SkASSERT(id > 0 && (unsigned)id <= SK_ARRAY_COUNT(fAuxContext));
+            ctx = fAuxContext[id - 1];
+            SkASSERT(ctx);
+        }
+        ctx->generateImage(*glyph);
+    }
+
+       if (fMaskFilter)
+       {
+               SkMask          srcM, dstM;
+               SkMatrix        matrix;
+
+               SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);     // the src glyph image shouldn't be 3D
+               glyph2mask(*glyph, &srcM);
+               fRec.getMatrixFrom2x2(&matrix);
+
+               if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL))
+               {
+            if (true)   // hack until I can figure out why the assert below sometimes fails
+            {
+                int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width());
+                int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height());
+                int srcRB = origGlyph.fRowBytes;
+                int dstRB = dstM.fRowBytes;
+                
+                const uint8_t* src = (const uint8_t*)dstM.fImage;
+                uint8_t* dst = (uint8_t*)origGlyph.fImage;
+                
+                if (SkMask::k3D_Format == dstM.fFormat)   // we have to copy 3 times as much
+                    height *= 3;
+
+                while (--height >= 0)
+                {
+                    memcpy(dst, src, width);
+                    src += srcRB;
+                    dst += dstRB;
+                }
+            }
+            else
+            {
+                SkASSERT(origGlyph.fWidth == dstM.fBounds.width());
+                SkASSERT(origGlyph.fTop == dstM.fBounds.fTop);
+                SkASSERT(origGlyph.fLeft == dstM.fBounds.fLeft);
+                SkASSERT(origGlyph.fHeight == dstM.fBounds.height());
+                SkASSERT(origGlyph.computeImageSize() == dstM.computeTotalImageSize());
+
+                memcpy(glyph->fImage, dstM.fImage, dstM.computeTotalImageSize());
+            }
+                       SkMask::FreeImage(dstM.fImage);
+               }
+       }
+}
+
+void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path)
+{
+    this->internalGetPath(glyph, NULL, path, NULL);
+}
+
+void SkScalerContext::getLineHeight(SkPoint* above, SkPoint* below)
+{
+       this->generateLineHeight(above, below);
+
+       // apply any mods due to effects (e.g. stroking, etc.)...
+}
+
+///////////////////////////////////////////////////////////////////////
+
+void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath, SkPath* devPath, SkMatrix* fillToDevMatrix)
+{
+    SkPath  path;
+
+       this->generatePath(glyph, &path);
+
+       if (fRec.fFrameWidth > 0 || fPathEffect != NULL)
+       {
+               // need the path in user-space, with only the point-size applied
+               // so that our stroking and effects will operate the same way they
+               // would if the user had extracted the path themself, and then
+               // called drawPath
+               SkPath          localPath;
+               SkMatrix        matrix, inverse;
+
+               fRec.getMatrixFrom2x2(&matrix);
+               matrix.invert(&inverse);
+               path.transform(inverse, &localPath);
+               // now localPath is only affected by the paint settings, and not the canvas matrix
+
+               SkScalar width = fRec.fFrameWidth;
+
+               if (fPathEffect)
+               {
+                       SkPath effectPath;
+
+                       if (fPathEffect->filterPath(&effectPath, localPath, &width))
+                               localPath.swap(effectPath);
+               }
+
+               if (width > 0)
+               {
+                       SkStroke        stroker;
+                       SkPath          outline;
+
+                       stroker.setWidth(width);
+                       stroker.setMiterLimit(fRec.fMiterLimit);
+                       stroker.setJoin((SkPaint::Join)fRec.fStrokeJoin);
+                       stroker.setDoFill(fRec.fFrameAndFill != 0);
+                       stroker.strokePath(localPath, &outline);
+                       localPath.swap(outline);
+               }
+        
+        // now return stuff to the caller
+        if (fillToDevMatrix)
+            *fillToDevMatrix = matrix;
+        
+        if (devPath)
+            localPath.transform(matrix, devPath);
+        
+        if (fillPath)
+            fillPath->swap(localPath);
+       }
+    else    // nothing tricky to do
+    {
+        if (fillToDevMatrix)
+            fillToDevMatrix->reset();
+        
+        if (devPath)
+        {
+            if (fillPath == NULL)
+                devPath->swap(path);
+            else
+                *devPath = path;
+        }
+        
+        if (fillPath)
+            fillPath->swap(path);
+    }
+}
+
+
+void SkScalerContext::Rec::getMatrixFrom2x2(SkMatrix* dst) const
+{
+       dst->reset();
+       dst->setScaleX(fPost2x2[0][0]);
+       dst->setSkewX( fPost2x2[0][1]);
+       dst->setSkewY( fPost2x2[1][0]);
+       dst->setScaleY(fPost2x2[1][1]);
+}
+
+void SkScalerContext::Rec::getLocalMatrix(SkMatrix* m) const
+{
+       m->setScale(SkScalarMul(fTextSize, fPreScaleX), fTextSize, 0, 0);
+       if (fPreSkewX)
+               m->postSkew(fPreSkewX, 0, 0, 0);
+}
+
+void SkScalerContext::Rec::getSingleMatrix(SkMatrix* m) const
+{
+       this->getLocalMatrix(m);
+
+       //      now concat the device matrix
+       {
+               SkMatrix        deviceMatrix;
+               this->getMatrixFrom2x2(&deviceMatrix);
+               m->postConcat(deviceMatrix);
+       }
+}
+
+#include "SkFontHost.h"
+
+SkScalerContext* SkScalerContext::Create(const SkDescriptor* desc)
+{
+       return SkFontHost::CreateScalerContext(desc);
+}
+
diff --git a/libs/graphics/sgl/SkScan.cpp b/libs/graphics/sgl/SkScan.cpp
new file mode 100644 (file)
index 0000000..b8534e6
--- /dev/null
@@ -0,0 +1,32 @@
+#include "SkScan.h"
+#include "SkBlitter.h"
+#include "SkRegion.h"
+
+void SkScan::FillRect(const SkRect& rect, const SkRegion* clip, SkBlitter* blitter)
+{
+       SkRect16 r;
+
+       rect.round(&r);
+       SkScan::FillDevRect(r, clip, blitter);
+}
+
+void SkScan::FillDevRect(const SkRect16& r, const SkRegion* clip, SkBlitter* blitter)
+{
+       if (!r.isEmpty())
+       {
+               if (clip)
+               {
+                       SkRegion::Cliperator    cliper(*clip, r);
+                       const SkRect16&                 rr = cliper.rect();
+
+                       while (!cliper.done())
+                       {
+                               blitter->blitRect(rr.fLeft, rr.fTop, rr.width(), rr.height());
+                               cliper.next();
+                       }
+               }
+               else
+                       blitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
+       }
+}
+
diff --git a/libs/graphics/sgl/SkScan.h b/libs/graphics/sgl/SkScan.h
new file mode 100644 (file)
index 0000000..c8b62c8
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef SkScan_DEFINED
+#define SkScan_DEFINED
+
+#include "SkRect.h"
+
+class SkRegion;
+class SkBlitter;
+class SkPath;
+
+class SkScan {
+public:
+       static void     FillDevRect(const SkRect16&, const SkRegion* clip, SkBlitter*);
+       static void     FillRect(const SkRect&, const SkRegion* clip, SkBlitter*);
+       static void FillPath(const SkPath&, const SkRegion* clip, SkBlitter*);
+
+       static void HairLine(const SkPoint&, const SkPoint&, const SkRegion* clip, SkBlitter*);
+       static void HairRect(const SkRect&, const SkRegion* clip, SkBlitter*);
+       static void HairPath(const SkPath&, const SkRegion* clip, SkBlitter*);
+
+       static void FrameRect(const SkRect&, SkScalar width, const SkRegion* clip, SkBlitter*);
+
+       static void     AntiFillRect(const SkRect&, const SkRegion* clip, SkBlitter*);
+       static void AntiFillPath(const SkPath&, const SkRegion* clip, SkBlitter*);
+
+       static void AntiHairLine(const SkPoint&, const SkPoint&, const SkRegion* clip, SkBlitter*);
+       static void AntiHairRect(const SkRect&, const SkRegion* clip, SkBlitter*);
+       static void AntiHairPath(const SkPath&, const SkRegion* clip, SkBlitter*);
+};
+
+#endif
diff --git a/libs/graphics/sgl/SkScanPriv.h b/libs/graphics/sgl/SkScanPriv.h
new file mode 100644 (file)
index 0000000..2fce606
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef SkScanPriv_DEFINED
+#define SkScanPriv_DEFINED
+
+#include "SkScan.h"
+#include "SkBlitter.h"
+
+class SkScanClipper {
+public:
+       SkScanClipper(SkBlitter* blitter, const SkRegion* clip, const SkRect16& bounds);
+
+       SkBlitter*              getBlitter() const { return fBlitter; }
+       const SkRect16* getClipRect() const { return fClipRect; }
+
+private:
+       SkRectClipBlitter       fRectBlitter;
+       SkRgnClipBlitter        fRgnBlitter;
+       SkBlitter*                      fBlitter;
+       const SkRect16*         fClipRect;
+};
+
+void sk_fill_path(const SkPath& path, const SkRect16* clipRect, SkBlitter* blitter,
+                                 const SkRect16& ir, int shiftEdgesUp);
+
+#endif
+
diff --git a/libs/graphics/sgl/SkScan_AntiPath.cpp b/libs/graphics/sgl/SkScan_AntiPath.cpp
new file mode 100644 (file)
index 0000000..592edff
--- /dev/null
@@ -0,0 +1,209 @@
+#include "SkScanPriv.h"
+#include "SkPath.h"
+#include "SkMatrix.h"
+#include "SkBlitter.h"
+#include "SkRegion.h"
+#include "SkAntiRun.h"
+
+#define SHIFT  2
+#define SCALE  (1 << SHIFT)
+#define MASK   (SCALE - 1)
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+class SuperBlitter : public SkBlitter {
+public:
+       SuperBlitter(SkBlitter* realBlitter, const SkRegion* clip, const SkRect16& ir);
+       virtual ~SuperBlitter()
+       {
+               sk_free(fRuns.fRuns);
+       }
+       void flush();
+
+       virtual void    blitH(int x, int y, int width);
+       virtual void    blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[])
+       {
+               SkASSERT(!"How did I get here?");
+       }
+       virtual void    blitV(int x, int y, int height, SkAlpha alpha)
+       {
+               SkASSERT(!"How did I get here?");
+       }
+       virtual void    blitRect(int x, int y, int width, int height)
+       {
+               SkASSERT(!"How did I get here?");
+       }
+
+private:
+       SkBlitter*                      fRealBlitter;
+       int                                     fCurrIY;
+       int                                     fWidth, fLeft, fSuperLeft;
+       SkAlphaRuns                     fRuns;
+
+       SkDEBUGCODE(int fCurrX;)
+       SkDEBUGCODE(int fCurrY;)
+};
+
+SuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkRegion* clip, const SkRect16& ir)
+{
+       fRealBlitter = realBlitter;
+
+       int     width = ir.width();
+
+       // extra one to store the zero at the end
+       fRuns.fRuns = (S16*)sk_malloc_throw((width + 1 + (width + 2)/2) * sizeof(S16));
+       fRuns.fAlpha = (U8*)(fRuns.fRuns + width + 1);
+       fRuns.reset(width);
+
+       fLeft = ir.fLeft;
+       fSuperLeft = ir.fLeft << SHIFT;
+       fWidth = ir.width();
+       fCurrIY = -1;
+       SkDEBUGCODE(fCurrX = -1; fCurrY = -1;)
+}
+
+void SuperBlitter::flush()
+{
+       if (fCurrIY >= 0)
+       {
+               if (!fRuns.empty())
+               {
+               //      SkDEBUGCODE(fRuns.dump();)
+                       fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns);
+                       fRuns.reset(fWidth);
+               }
+               fCurrIY = -1;
+               SkDEBUGCODE(fCurrX = -1;)
+       }
+}
+
+static inline int coverage_to_alpha(int aa)
+{
+       aa <<= 8 - 2*SHIFT;
+       aa -= aa >> (8 - SHIFT - 1);
+       return aa;
+}
+
+#define SUPER_Mask             ((1 << SHIFT) - 1)
+
+void SuperBlitter::blitH(int x, int y, int width)
+{
+       int     iy = y >> SHIFT;
+       SkASSERT(iy >= fCurrIY);
+
+       x -= fSuperLeft;
+#if 0  // I should just need to assert
+       SkASSERT(x >= 0);
+#else
+       // hack, until I figure out why my cubics (I think) go beyond the bounds
+       if (x < 0)
+       {
+               width += x;
+               x = 0;
+       }
+#endif
+
+#ifdef SK_DEBUG
+       SkASSERT(y >= fCurrY);
+       SkASSERT(y != fCurrY || x >= fCurrX);
+       fCurrY = y;
+#endif
+
+       if (iy != fCurrIY)      // new scanline
+       {
+               this->flush();
+               fCurrIY = iy;
+       }
+
+       // we sub 1 from maxValue 1 time for each block, so that we don't
+       // hit 256 as a summed max, but 255.
+//     int maxValue = (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT);
+
+#if 0
+       SkAntiRun<SHIFT>        arun;   
+       arun.set(x, x + width);
+       fRuns.add(x >> SHIFT, arun.getStartAlpha(), arun.getMiddleCount(), arun.getStopAlpha(), maxValue);
+#else
+       {
+               int start = x;
+               int stop = x + width;
+
+               SkASSERT(start >= 0 && stop > start);
+               int     fb = start & SUPER_Mask;
+               int fe = stop & SUPER_Mask;
+               int     n = (stop >> SHIFT) - (start >> SHIFT) - 1;
+
+               if (n < 0)
+               {
+                       fb = fe - fb;
+                       n = 0;
+                       fe = 0;
+               }
+               else
+               {
+                       if (fb == 0)
+                               n += 1;
+                       else
+                               fb = (1 << SHIFT) - fb;
+               }
+               fRuns.add(x >> SHIFT, coverage_to_alpha(fb), n, coverage_to_alpha(fe), (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT));
+       }
+#endif
+
+#ifdef SK_DEBUG
+       fRuns.assertValid(y & MASK, (1 << (8 - SHIFT)));
+       fCurrX = x + width;
+#endif
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+static int overflows_short(int value)
+{
+       return value - (short)value;
+}
+
+void SkScan::AntiFillPath(const SkPath& path, const SkRegion* clip, SkBlitter* blitter)
+{
+       if (clip && clip->isEmpty())
+               return;
+
+       SkRect          r;
+       SkRect16        ir;
+
+       path.computeBounds(&r, SkPath::kFast_BoundsType);
+       r.roundOut(&ir);
+       if (ir.isEmpty())
+               return;
+
+       if (overflows_short(ir.fLeft << SHIFT) ||
+               overflows_short(ir.fRight << SHIFT) ||
+               overflows_short(ir.width() << SHIFT) ||
+               overflows_short(ir.fTop << SHIFT) ||
+               overflows_short(ir.fBottom << SHIFT) ||
+               overflows_short(ir.height() << SHIFT))
+               return;
+
+       SkScanClipper   clipper(blitter, clip, ir);
+       const SkRect16* clipRect = clipper.getClipRect();
+
+       blitter = clipper.getBlitter();
+       if (blitter == nil)     // clipped out
+               return;
+
+       SuperBlitter    superBlit(blitter, clip, ir);
+       SkRect16                superIR, superRect, *superClipRect = nil;
+
+       superIR.set(ir.fLeft << SHIFT, ir.fTop << SHIFT,
+                               ir.fRight << SHIFT, ir.fBottom << SHIFT);
+
+       if (clipRect)
+       {
+               superRect.set(  clipRect->fLeft << SHIFT, clipRect->fTop << SHIFT,
+                                               clipRect->fRight << SHIFT, clipRect->fBottom << SHIFT);
+               superClipRect = &superRect;
+       }
+
+       sk_fill_path(path, superClipRect, &superBlit, superIR, SHIFT);
+       superBlit.flush();
+}
diff --git a/libs/graphics/sgl/SkScan_Antihair.cpp b/libs/graphics/sgl/SkScan_Antihair.cpp
new file mode 100644 (file)
index 0000000..81f503b
--- /dev/null
@@ -0,0 +1,397 @@
+#include "SkScan.h"
+#include "SkBlitter.h"
+#include "SkRegion.h"
+#include "SkFDot6.h"
+
+#define HLINE_STACK_BUFFER             100
+
+//#define TEST_GAMMA
+
+#ifdef TEST_GAMMA
+       static U8 gGammaTable[256];
+       #define ApplyGamma(table, alpha)        (table)[alpha]
+
+       static void build_gamma_table()
+       {
+               static bool gInit = false;
+
+               if (gInit == false)
+               {
+                       for (int i = 0; i < 256; i++)
+                       {
+                               SkFixed n = i * 257;
+                               n += n >> 15;
+                               SkASSERT(n >= 0 && n <= SK_Fixed1);
+                               n = SkFixedSqrt(n);
+                               n = n * 255 >> 16;
+                       //      SkDebugf("morph %d -> %d\n", i, n);
+                               gGammaTable[i] = SkToU8(n);
+                       }
+                       gInit = true;
+               }
+       }
+#else
+       #define ApplyGamma(table, alpha)        SkToU8(alpha)
+#endif
+
+
+static void call_hline_blitter(SkBlitter* blitter, int x, int y, int count, U8 alpha)
+{
+       SkASSERT(count > 0);
+
+       S16     runs[HLINE_STACK_BUFFER + 1];
+       U8      aa[HLINE_STACK_BUFFER];
+
+       aa[0] = ApplyGamma(gGammaTable, alpha);
+       do {
+               int n = count;
+               if (n > HLINE_STACK_BUFFER)
+                       n = HLINE_STACK_BUFFER;
+
+               runs[0] = SkToS16(n);
+               runs[n] = 0;
+               blitter->blitAntiH(x, y, aa, runs);
+               x += n;
+               count -= n;
+       } while (count > 0);
+}
+
+static void hline(int x, int stopx, SkFixed fy, SkFixed /*slope*/, SkBlitter* blitter)
+{
+       SkASSERT(x < stopx);
+       int     count = stopx - x;
+       fy += SK_Fixed1/2;
+
+       int     y = fy >> 16;
+       U8      a = (U8)(fy >> 8);
+
+       // lower line
+       if (a)
+               call_hline_blitter(blitter, x, y, count, a);
+
+       // upper line
+       a = (U8)(255 - a);
+       if (a)
+               call_hline_blitter(blitter, x, y - 1, count, a);
+}
+
+static void horish(int x, int stopx, SkFixed fy, SkFixed dy, SkBlitter* blitter)
+{
+       SkASSERT(x < stopx);
+
+#ifdef TEST_GAMMA
+       const U8* gamma = gGammaTable;
+#endif
+       S16     runs[2];
+       U8      aa[1];
+
+       runs[0] = 1;
+       runs[1] = 0;
+
+       fy += SK_Fixed1/2;
+       do {
+               int     lower_y = fy >> 16;
+               U8      a = (U8)(fy >> 8);
+
+               if (a)
+               {
+                       aa[0] = ApplyGamma(gamma, a);
+                       blitter->blitAntiH(x, lower_y, aa, runs);
+                       // the clipping blitters might edit runs, but should not affect us
+                       SkASSERT(runs[0] == 1);
+                       SkASSERT(runs[1] == 0);
+               }
+               a = (U8)(255 - a);
+               if (a)
+               {
+                       aa[0] = ApplyGamma(gamma, a);
+                       blitter->blitAntiH(x, lower_y - 1, aa, runs);
+                       // the clipping blitters might edit runs, but should not affect us
+                       SkASSERT(runs[0] == 1);
+                       SkASSERT(runs[1] == 0);
+               }
+               fy += dy;
+       } while (++x < stopx);
+}
+
+static void vline(int y, int stopy, SkFixed fx, SkFixed /*slope*/, SkBlitter* blitter)
+{
+       SkASSERT(y < stopy);
+       fx += SK_Fixed1/2;
+
+       int x = fx >> 16;
+       int     a = (U8)(fx >> 8);
+
+       if (a)
+               blitter->blitV(x, y, stopy - y, ApplyGamma(gGammaTable, a));
+       a = 255 - a;
+       if (a)
+               blitter->blitV(x - 1, y, stopy - y, ApplyGamma(gGammaTable, a));
+}
+
+static void vertish(int y, int stopy, SkFixed fx, SkFixed dx, SkBlitter* blitter)
+{
+       SkASSERT(y < stopy);
+#ifdef TEST_GAMMA
+       const U8* gamma = gGammaTable;
+#endif
+       S16     runs[3];
+       U8      aa[2];
+
+       runs[0] = 1;
+       runs[2] = 0;
+
+       fx += SK_Fixed1/2;
+       do {
+               int x = fx >> 16;
+               U8      a = (U8)(fx >> 8);
+
+               aa[0] = ApplyGamma(gamma, 255 - a);
+               aa[1] = ApplyGamma(gamma, a);
+               // the clippng blitters might overwrite this guy, so we have to reset it each time
+               runs[1] = 1;
+               blitter->blitAntiH(x - 1, y, aa, runs);
+               // the clipping blitters might edit runs, but should not affect us
+               SkASSERT(runs[0] == 1);
+               SkASSERT(runs[2] == 0);
+               fx += dx;
+       } while (++y < stopy);
+}
+
+typedef void (*LineProc)(int istart, int istop, SkFixed fstart, SkFixed slope, SkBlitter*);
+
+static inline SkFixed fastfixdiv(SkFDot6 a, SkFDot6 b)
+{
+       SkASSERT((a << 16 >> 16) == a);
+       SkASSERT(b != 0);
+       return (a << 16) / b;
+}
+static inline SkFDot6 fastfixmul(SkFixed fixed, SkFDot6 b)
+{
+       SkASSERT(SkAbs32(fixed) <= SK_Fixed1 && SkAbs32(b) <= SkIntToFDot6(511));
+       return (fixed * b + 0x8000) >> 16;
+}
+
+static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1,
+                                                        const SkRect16* clip, SkBlitter* blitter)
+{
+       // check that we're no larger than 511 pixels (so we can do a faster div).
+       // if we are, subdivide and call again
+
+       if (SkAbs32(x1 - x0) > SkIntToFDot6(511) || SkAbs32(y1 - y0) > SkIntToFDot6(511))
+       {
+               int     hx = (x0 + x1) >> 1;
+               int     hy = (y0 + y1) >> 1;
+               do_anti_hairline(x0, y0, hx, hy, clip, blitter);
+               do_anti_hairline(hx, hy, x1, y1, clip, blitter);
+               return;
+       }
+
+       int                     istart, istop;
+       SkFixed         fstart, slope; 
+       LineProc        proc;
+
+       if (SkAbs32(x1 - x0) > SkAbs32(y1 - y0))        // mostly horizontal
+       {
+               if (x0 > x1)    // we want to go left-to-right
+               {
+                       SkTSwap<SkFDot6>(x0, x1);
+                       SkTSwap<SkFDot6>(y0, y1);
+               }
+               istart = SkFDot6Round(x0);
+               istop = SkFDot6Round(x1);
+               if (istart == istop)    // too short to draw
+                       return;
+
+               if (y0 == y1)   // completely horizontal, take fast case
+               {
+                       slope = 0;
+                       fstart = SkFDot6ToFixed(y0);
+                       proc = hline;
+               }
+               else
+               {
+                       slope = fastfixdiv(y1 - y0, x1 - x0);
+                       SkASSERT(slope >= -SK_Fixed1 && slope <= SK_Fixed1);
+                       fstart = SkFDot6ToFixed(y0 + fastfixmul(slope, (32 - x0) & 63));
+                       proc = horish;
+               }
+
+               if (clip)
+               {
+                       if (istart >= clip->fRight || istop <= clip->fLeft)
+                               return;
+                       if (istart < clip->fLeft)
+                       {
+                               fstart += slope * (clip->fLeft - istart);
+                               istart = clip->fLeft;
+                       }
+                       if (istop > clip->fRight)
+                               istop = clip->fRight;
+                       SkASSERT(istart <= istop);
+                       if (istart == istop)
+                               return;
+                       // now test if our Y values are completely inside the clip
+                       int     top, bottom;
+                       if (slope >= 0) // T2B
+                       {
+                               top = SkFixedFloor(fstart - SK_FixedHalf);
+                               bottom = SkFixedCeil(fstart + (istop - istart - 1) * slope + SK_FixedHalf);
+                       }
+                       else                    // B2T
+                       {
+                               bottom = SkFixedCeil(fstart + SK_FixedHalf);
+                               top = SkFixedFloor(fstart + (istop - istart - 1) * slope - SK_FixedHalf);
+                       }
+                       if (top >= clip->fBottom || bottom <= clip->fTop)
+                               return;
+                       if (clip->fTop <= top && clip->fBottom >= bottom)
+                               clip = nil;
+               }
+       }
+       else    // mostly vertical
+       {
+               if (y0 > y1)    // we want to go top-to-bottom
+               {
+                       SkTSwap<SkFDot6>(x0, x1);
+                       SkTSwap<SkFDot6>(y0, y1);
+               }
+               istart = SkFDot6Round(y0);
+               istop = SkFDot6Round(y1);
+               if (istart == istop)    // too short to draw
+                       return;
+
+               if (x0 == x1)
+               {
+                       slope = 0;
+                       fstart = SkFDot6ToFixed(x0);
+                       proc = vline;
+               }
+               else
+               {
+                       slope = fastfixdiv(x1 - x0, y1 - y0);
+                       SkASSERT(slope <= SK_Fixed1 && slope >= -SK_Fixed1);
+                       fstart = SkFDot6ToFixed(x0 + fastfixmul(slope, (32 - y0) & 63));
+                       proc = vertish;
+               }
+
+               if (clip)
+               {
+                       if (istart >= clip->fBottom || istop <= clip->fTop)
+                               return;
+                       if (istart < clip->fTop)
+                       {
+                               fstart += slope * (clip->fTop - istart);
+                               istart = clip->fTop;
+                       }
+                       if (istop > clip->fBottom)
+                               istop = clip->fBottom;
+                       SkASSERT(istart <= istop);
+                       if (istart == istop)
+                               return;
+                       // now test if our X values are completely inside the clip
+                       int     left, right;
+                       if (slope >= 0) // L2R
+                       {
+                               left = SkFixedFloor(fstart - SK_FixedHalf);
+                               right = SkFixedCeil(fstart + (istop - istart - 1) * slope + SK_FixedHalf);
+                       }
+                       else                    // R2L
+                       {
+                               right = SkFixedCeil(fstart + SK_FixedHalf);
+                               left = SkFixedFloor(fstart + (istop - istart - 1) * slope - SK_FixedHalf);
+                       }
+                       if (left >= clip->fRight || right <= clip->fLeft)
+                               return;
+                       if (clip->fLeft <= left && clip->fRight >= right)
+                               clip = nil;
+               }
+       }
+
+       SkRectClipBlitter       rectClipper;
+       if (clip)
+       {
+               rectClipper.init(blitter, *clip);
+               blitter = &rectClipper;
+       }
+       proc(istart, istop, fstart, slope, blitter);
+}
+
+void SkScan::AntiHairLine(const SkPoint& pt0, const SkPoint& pt1,
+                                                 const SkRegion* clip, SkBlitter* blitter)
+{
+       if (clip && clip->isEmpty())
+               return;
+
+       SkASSERT(clip == nil || !clip->getBounds().isEmpty());
+
+#ifdef TEST_GAMMA
+       build_gamma_table();
+#endif
+
+       SkFDot6 x0 = SkScalarToFDot6(pt0.fX);
+       SkFDot6 y0 = SkScalarToFDot6(pt0.fY);
+       SkFDot6 x1 = SkScalarToFDot6(pt1.fX);
+       SkFDot6 y1 = SkScalarToFDot6(pt1.fY);
+
+       if (clip)
+       {
+               SkFDot6         left = SkMin32(x0, x1);
+               SkFDot6         top = SkMin32(y0, y1);
+               SkFDot6         right = SkMax32(x0, x1);
+               SkFDot6         bottom = SkMax32(y0, y1);
+               SkRect16        ir;
+
+               ir.set( SkFDot6Round(left) - 1,
+                               SkFDot6Round(top) - 1,
+                               SkFDot6Round(right) + 1,
+                               SkFDot6Round(bottom) + 1);
+
+               if (clip->quickReject(ir))
+                       return;
+               if (!clip->quickContains(ir))
+               {
+                       SkRegion::Cliperator iter(*clip, ir);
+                       const SkRect16*          r = &iter.rect();
+
+                       while (!iter.done())
+                       {
+                               do_anti_hairline(x0, y0, x1, y1, r, blitter);
+                               iter.next();
+                       }
+                       return;
+               }
+               // fall through to no-clip case
+       }
+       do_anti_hairline(x0, y0, x1, y1, nil, blitter);
+}
+
+void SkScan::AntiHairRect(const SkRect& rect, const SkRegion* clip, SkBlitter* blitter)
+{
+       if (clip)
+       {
+               SkRect16        ir;
+               SkRect          r = rect;
+
+               r.inset(-SK_Scalar1/2, -SK_Scalar1/2);
+               r.roundOut(&ir);
+               if (clip->quickReject(ir))
+                       return;
+               if (clip->quickContains(ir))
+                       clip = nil;
+       }
+
+       SkPoint p0, p1;
+
+       p0.set(rect.fLeft, rect.fTop);
+       p1.set(rect.fRight, rect.fTop);
+       SkScan::AntiHairLine(p0, p1, clip, blitter);
+       p0.set(rect.fRight, rect.fBottom);
+       SkScan::AntiHairLine(p0, p1, clip, blitter);
+       p1.set(rect.fLeft, rect.fBottom);
+       SkScan::AntiHairLine(p0, p1, clip, blitter);
+       p0.set(rect.fLeft, rect.fTop);
+       SkScan::AntiHairLine(p0, p1, clip, blitter);
+}
+
+
diff --git a/libs/graphics/sgl/SkScan_Hairline.cpp b/libs/graphics/sgl/SkScan_Hairline.cpp
new file mode 100644 (file)
index 0000000..2af9e12
--- /dev/null
@@ -0,0 +1,254 @@
+#include "SkScan.h"
+#include "SkBlitter.h"
+#include "SkRegion.h"
+#include "SkFDot6.h"
+
+static void horiline(int x, int stopx, SkFixed fy, SkFixed dy, SkBlitter* blitter)
+{
+       SkASSERT(x < stopx);
+
+       do {
+               blitter->blitH(x, fy >> 16, 1);
+               fy += dy;
+       } while (++x < stopx);
+}
+
+static void vertline(int y, int stopy, SkFixed fx, SkFixed dx, SkBlitter* blitter)
+{
+       SkASSERT(y < stopy);
+
+       do {
+               blitter->blitH(fx >> 16, y, 1);
+               fx += dx;
+       } while (++y < stopy);
+}
+
+void SkScan::HairLine(const SkPoint& pt0, const SkPoint& pt1, const SkRegion* clip, SkBlitter* blitter)
+{
+       SkBlitterClipper        clipper;
+
+       SkFDot6 x0 = SkScalarToFDot6(pt0.fX);
+       SkFDot6 y0 = SkScalarToFDot6(pt0.fY);
+       SkFDot6 x1 = SkScalarToFDot6(pt1.fX);
+       SkFDot6 y1 = SkScalarToFDot6(pt1.fY);
+
+       if (clip)
+       {
+               SkRect          r;
+               SkRect16        ir;
+               SkPoint         pts[2];
+
+               pts[0] = pt0;
+               pts[1] = pt1;
+               r.set(pts, 2);
+               r.roundOut(&ir);
+
+               if (clip->quickReject(ir))
+                       return;
+               if (clip->quickContains(ir))
+                       clip = nil;
+               else
+               {
+                       blitter = clipper.apply(blitter, clip);
+               }
+       }
+
+       SkFDot6 dx = x1 - x0;
+       SkFDot6 dy = y1 - y0;
+
+       if (SkAbs32(dx) > SkAbs32(dy))  // mostly horizontal
+       {
+               if (x0 > x1)    // we want to go left-to-right
+               {
+                       SkTSwap<SkFDot6>(x0, x1);
+                       SkTSwap<SkFDot6>(y0, y1);
+               }
+               int ix0 = SkFDot6Round(x0);
+               int ix1 = SkFDot6Round(x1);
+               if (ix0 == ix1) // too short to draw
+                       return;
+
+               SkFixed slope = SkFixedDiv(dy, dx);
+               SkFixed startY = SkFDot6ToFixed(y0 + SkFixedMul(slope, (32 - x0) & 63));
+
+               horiline(ix0, ix1, startY, slope, blitter);
+       }
+       else                            // mostly vertical
+       {
+               if (y0 > y1)    // we want to go top-to-bottom
+               {
+                       SkTSwap<SkFDot6>(x0, x1);
+                       SkTSwap<SkFDot6>(y0, y1);
+               }
+               int iy0 = SkFDot6Round(y0);
+               int iy1 = SkFDot6Round(y1);
+               if (iy0 == iy1) // too short to draw
+                       return;
+
+               SkFixed slope = SkFixedDiv(dx, dy);
+               SkFixed startX = SkFDot6ToFixed(x0 + SkFixedMul(slope, (32 - y0) & 63));
+
+               vertline(iy0, iy1, startX, slope, blitter);
+       }
+}
+
+void SkScan::HairRect(const SkRect& rect, const SkRegion* clip, SkBlitter* blitter)
+{
+       SkPoint p0, p1;
+
+       p0.set(rect.fLeft, rect.fTop);
+       p1.set(rect.fRight, rect.fTop);
+       SkScan::HairLine(p0, p1, clip, blitter);
+       p0.set(rect.fRight, rect.fBottom);
+       SkScan::HairLine(p0, p1, clip, blitter);
+       p1.set(rect.fLeft, rect.fBottom);
+       SkScan::HairLine(p0, p1, clip, blitter);
+       p0.set(rect.fLeft, rect.fTop);
+       SkScan::HairLine(p0, p1, clip, blitter);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkPath.h"
+#include "SkGeometry.h"
+
+static bool quad_too_curvy(const SkPoint pts[3])
+{
+       return true;
+}
+
+static void hairquad(const SkPoint pts[3], const SkRegion* clip, SkBlitter* blitter, int level,
+                                        void (*lineproc)(const SkPoint&, const SkPoint&, const SkRegion* clip, SkBlitter*))
+{
+#if 1
+       if (level > 0 && quad_too_curvy(pts))
+       {
+               SkPoint tmp[5];
+
+               SkChopQuadAtHalf(pts, tmp);
+               hairquad(tmp, clip, blitter, level - 1, lineproc);
+               hairquad(&tmp[2], clip, blitter, level - 1, lineproc);
+       }
+       else
+               lineproc(pts[0], pts[2], clip, blitter);
+#else
+       lineproc(pts[0], pts[1], clip, blitter);
+       lineproc(pts[1], pts[2], clip, blitter);
+#endif
+}
+
+static bool cubic_too_curvy(const SkPoint pts[4])
+{
+       return true;
+}
+
+static void haircubic(const SkPoint pts[4], const SkRegion* clip, SkBlitter* blitter, int level,
+                                         void (*lineproc)(const SkPoint&, const SkPoint&, const SkRegion*, SkBlitter*))
+{
+       if (level > 0 && cubic_too_curvy(pts))
+       {
+               SkPoint tmp[7];
+
+               SkChopCubicAt(pts, tmp, SK_Scalar1/2);
+               haircubic(tmp, clip, blitter, level - 1, lineproc);
+               haircubic(&tmp[3], clip, blitter, level - 1, lineproc);
+       }
+       else
+               lineproc(pts[0], pts[3], clip, blitter);
+}
+
+#define kMaxCubicSubdivideLevel        6
+#define kMaxQuadSubdivideLevel 5
+
+static void hair_path(const SkPath& path, const SkRegion* clip, SkBlitter* blitter,
+                                         void (*lineproc)(const SkPoint&, const SkPoint&, const SkRegion*, SkBlitter*))
+{
+       if (path.isEmpty())
+               return;
+
+       const SkRect16* clipR = nil;
+
+       if (clip)
+       {
+               SkRect          bounds;
+               SkRect16        ibounds;
+
+               path.computeBounds(&bounds, SkPath::kFast_BoundsType);
+               bounds.roundOut(&ibounds);
+               ibounds.inset(-1, -1);
+
+               if (clip->quickReject(ibounds))
+                       return;
+
+               if (clip->quickContains(ibounds))
+                       clip = nil;
+               else
+                       clipR = &clip->getBounds();
+       }
+
+       SkPath::Iter    iter(path, false);
+       SkPoint                 pts[4];
+       SkPath::Verb    verb;
+
+       while ((verb = iter.next(pts)) != SkPath::kDone_Verb)
+       {
+               switch (verb) {
+               case SkPath::kLine_Verb:
+                       lineproc(pts[0], pts[1], clip, blitter);
+                       break;
+               case SkPath::kQuad_Verb:
+                       hairquad(pts, clip, blitter, kMaxQuadSubdivideLevel, lineproc);
+                       break;
+               case SkPath::kCubic_Verb:
+                       haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc);
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+void SkScan::HairPath(const SkPath& path, const SkRegion* clip, SkBlitter* blitter)
+{
+       hair_path(path, clip, blitter, SkScan::HairLine);
+}
+
+void SkScan::AntiHairPath(const SkPath& path, const SkRegion* clip, SkBlitter* blitter)
+{
+       hair_path(path, clip, blitter, SkScan::AntiHairLine);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void SkScan::FrameRect(const SkRect& r, SkScalar diameter, const SkRegion* clip, SkBlitter* blitter)
+{
+       SkASSERT(diameter > 0);
+
+       if (r.isEmpty())
+               return;
+
+       SkScalar radius = diameter / 2;
+       SkRect   outer, tmp;
+
+       outer.set(      r.fLeft - radius, r.fTop - radius,
+                               r.fRight + radius, r.fBottom + radius);
+
+       if (r.width() <= diameter || r.height() <= diameter)
+       {
+               SkScan::FillRect(outer, clip, blitter);
+               return;
+       }
+
+       tmp.set(outer.fLeft, outer.fTop, outer.fRight, outer.fTop + diameter);
+       SkScan::FillRect(tmp, clip, blitter);
+       tmp.fTop = outer.fBottom - diameter;
+       tmp.fBottom = outer.fBottom;
+       SkScan::FillRect(tmp, clip, blitter);
+
+       tmp.set(outer.fLeft, outer.fTop + diameter, outer.fLeft + diameter, outer.fBottom - diameter);
+       SkScan::FillRect(tmp, clip, blitter);
+       tmp.fLeft = outer.fRight - diameter;
+       tmp.fRight = outer.fRight;
+       SkScan::FillRect(tmp, clip, blitter);
+}
+
diff --git a/libs/graphics/sgl/SkScan_Path.cpp b/libs/graphics/sgl/SkScan_Path.cpp
new file mode 100644 (file)
index 0000000..2518bb5
--- /dev/null
@@ -0,0 +1,430 @@
+#include "SkScanPriv.h"
+#include "SkBlitter.h"
+#include "SkEdge.h"
+#include "SkGeometry.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkTemplates.h"
+
+#define kEDGE_HEAD_Y   SK_MinS16
+#define kEDGE_TAIL_Y   SK_MaxS16
+
+#ifdef SK_DEBUG
+       static void validate_sort(const SkEdge* edge)
+       {
+               int     y = kEDGE_HEAD_Y;
+
+               while (edge->fFirstY != SK_MaxS16)
+               {
+                       edge->validate();
+                       SkASSERT(y <= edge->fFirstY);
+
+                       y = edge->fFirstY;
+                       edge = edge->fNext;
+               }
+       }
+#else
+       #define validate_sort(edge)
+#endif
+
+static inline void remove_edge(SkEdge* edge)
+{
+       edge->fPrev->fNext = edge->fNext;
+       edge->fNext->fPrev = edge->fPrev;
+}
+
+static inline void swap_edges(SkEdge* prev, SkEdge* next)
+{
+       SkASSERT(prev->fNext == next && next->fPrev == prev);
+
+       // remove prev from the list
+       prev->fPrev->fNext = next;
+       next->fPrev = prev->fPrev;
+
+       // insert prev after next
+       prev->fNext = next->fNext;
+       next->fNext->fPrev = prev;
+       next->fNext = prev;
+       prev->fPrev = next;
+}
+
+static void backward_insert_edge_based_on_x(SkEdge* edge SkDECLAREPARAM(int, curr_y))
+{
+       SkFixed x = edge->fX;
+
+       for (;;)
+       {
+               SkEdge* prev = edge->fPrev;
+               
+               // add 1 to curr_y since we may have added new edges (built from curves)
+               // that start on the next scanline
+               SkASSERT(prev && prev->fFirstY <= curr_y + 1);
+
+               if (prev->fX <= x)
+                       break;
+
+               swap_edges(prev, edge);
+       }
+}
+
+static void insert_new_edges(SkEdge* newEdge, int curr_y)
+{
+       SkASSERT(newEdge->fFirstY >= curr_y);
+
+       while (newEdge->fFirstY == curr_y)
+       {
+               SkEdge* next = newEdge->fNext;
+               backward_insert_edge_based_on_x(newEdge  SkPARAM(curr_y));
+               newEdge = next;
+       }
+}
+
+#ifdef SK_DEBUG
+static void validate_edges_for_y(const SkEdge* edge, int curr_y)
+{
+       while (edge->fFirstY <= curr_y)
+       {
+               SkASSERT(edge->fPrev && edge->fNext);
+               SkASSERT(edge->fPrev->fNext == edge);
+               SkASSERT(edge->fNext->fPrev == edge);
+               SkASSERT(edge->fFirstY <= edge->fLastY);
+
+               SkASSERT(edge->fPrev->fX <= edge->fX);
+               edge = edge->fNext;
+       }
+}
+#else
+       #define validate_edges_for_y(edge, curr_y)
+#endif
+
+#if defined _WIN32 && _MSC_VER >= 1300 // disable warning : local variable used without having been initialized
+#pragma warning ( push )
+#pragma warning ( disable : 4701 )
+#endif
+
+static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType, SkBlitter* blitter,
+                                          int stop_y)
+{
+       validate_sort(prevHead->fNext);
+
+       int     curr_y = prevHead->fNext->fFirstY;
+       int windingMask = (fillType == SkPath::kWinding_FillType) ? -1 : 1;
+
+       for (;;)
+       {
+               int             w = 0;
+               int             left SK_INIT_TO_AVOID_WARNING;
+               bool    in_interval     = false;
+               SkEdge* currE = prevHead->fNext;
+               SkFixed prevX = prevHead->fX;
+
+               validate_edges_for_y(currE, curr_y);
+
+               while (currE->fFirstY <= curr_y)
+               {
+                       SkASSERT(currE->fLastY >= curr_y);
+
+                       int x = (currE->fX + SK_Fixed1/2) >> 16;
+                       w += currE->fWinding;
+                       if ((w & windingMask) == 0)     // we finished an interval
+                       {
+                               SkASSERT(in_interval);
+                               int width = x - left;
+                               SkASSERT(width >= 0);
+                               if (width)
+                                       blitter->blitH(left, curr_y, width);
+                               in_interval = false;
+                       }
+                       else if (!in_interval)
+                       {
+                               left = x;
+                               in_interval = true;
+                       }
+
+                       SkEdge* next = currE->fNext;
+                       SkFixed newX;
+
+                       if (currE->fLastY == curr_y)    // are we done with this edge?
+                       {
+                               if (currE->fCurveCount < 0)
+                               {
+                                       if (((SkCubicEdge*)currE)->updateCubic())
+                                       {
+                                               SkASSERT(currE->fFirstY == curr_y + 1);
+                                               
+                                               newX = currE->fX;
+                                               goto NEXT_X;
+                                       }
+                               }
+                               else if (currE->fCurveCount > 0)
+                               {
+                                       if (((SkQuadraticEdge*)currE)->updateQuadratic())
+                                       {
+                                               newX = currE->fX;
+                                               goto NEXT_X;
+                                       }
+                               }
+                               remove_edge(currE);
+                       }
+                       else
+                       {
+                               SkASSERT(currE->fLastY > curr_y);
+                               newX = currE->fX + currE->fDX;
+                               currE->fX = newX;
+                       NEXT_X:
+                               if (newX < prevX)       // ripple currE backwards until it is x-sorted
+                                       backward_insert_edge_based_on_x(currE  SkPARAM(curr_y));
+                               else
+                                       prevX = newX;
+                       }
+                       currE = next;
+                       SkASSERT(currE);
+               }
+
+               curr_y += 1;
+               if (curr_y >= stop_y)
+                       break;
+
+               // now currE points to the first edge with a Yint larger than curr_y
+               insert_new_edges(currE, curr_y);
+       }
+}
+
+#if defined _WIN32 && _MSC_VER >= 1300
+#pragma warning ( pop )
+#endif
+
+/*     Our line edge relies on the maximum span being <= 512, so that it can
+       use FDot6 and keep the dx,dy in 16bits (for much faster slope divide).
+       This function returns true if the specified line is too big.
+*/
+static inline bool line_too_big(const SkPoint pts[2])
+{
+       SkScalar dx = pts[1].fX - pts[0].fX;
+       SkScalar dy = pts[1].fY - pts[0].fY;
+
+       return  SkScalarAbs(dx) > SkIntToScalar(511) ||
+                       SkScalarAbs(dy) > SkIntToScalar(511);
+}
+
+static int build_edges(SkEdge edge[], const SkPath& path, const SkRect16* clipRect, SkEdge* list[], int shiftUp)
+{
+       SkEdge**                start = list;
+       SkPath::Iter    iter(path, true);
+       SkPoint                 pts[4];
+       SkPath::Verb    verb;
+
+       while ((verb = iter.next(pts)) != SkPath::kDone_Verb)
+       {
+               switch (verb) {
+               case SkPath::kLine_Verb:
+                       if (edge->setLine(pts, clipRect, shiftUp))
+                       {
+                               *list++ = edge;
+                               edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
+                       }
+                       break;
+               case SkPath::kQuad_Verb:
+                       {
+                               SkPoint tmp[5];
+                               SkPoint* p = tmp;
+                               int             count = SkChopQuadAtYExtrema(pts, tmp);
+
+                               do {
+                                       if (((SkQuadraticEdge*)edge)->setQuadratic(p, clipRect, shiftUp))
+                                       {
+                                               *list++ = edge;
+                                               edge = (SkEdge*)((char*)edge + sizeof(SkQuadraticEdge));
+                                       }
+                                       p += 2;
+                               } while (--count >= 0);
+                       }
+                       break;
+               case SkPath::kCubic_Verb:
+                       {
+                               SkPoint tmp[10];
+                               SkPoint* p = tmp;
+                               int             count = SkChopCubicAtYExtrema(pts, tmp);                                
+                               SkASSERT(count >= 0 && count <= 2);
+
+                               do {
+                                       if (((SkCubicEdge*)edge)->setCubic(p, clipRect, shiftUp))
+                                       {
+                                               *list++ = edge;
+                                               edge = (SkEdge*)((char*)edge + sizeof(SkCubicEdge));
+                                       }
+                                       p += 3;
+                               } while (--count >= 0);
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+       return (int)(list - start);
+}
+
+extern "C" {
+       static int edge_compare(const void* a, const void* b)
+       {
+               const SkEdge* edgea = *(const SkEdge**)a;
+               const SkEdge* edgeb = *(const SkEdge**)b;
+
+               int valuea = edgea->fFirstY;
+               int valueb = edgeb->fFirstY;
+
+               if (valuea == valueb)
+               {
+                       valuea = edgea->fX;
+                       valueb = edgeb->fX;
+               }
+               return valuea - valueb;
+       }
+}
+
+static SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last)
+{
+       qsort(list, count, sizeof(SkEdge*), edge_compare);
+
+       // now make the edges linked in sorted order
+       for (int i = 1; i < count; i++)
+       {
+               list[i - 1]->fNext = list[i];
+               list[i]->fPrev = list[i - 1];
+       }
+
+       *last = list[count - 1];
+       return list[0];
+}
+
+static int worst_case_edge_count(const SkPath& path, size_t* storage)
+{
+       size_t  size = 0;
+       int             edgeCount = 0;
+
+       SkPath::Iter    iter(path, true);
+       SkPath::Verb    verb;
+
+       while ((verb = iter.next(nil)) != SkPath::kDone_Verb)
+       {
+               switch (verb) {
+               case SkPath::kLine_Verb:
+                       edgeCount += 1;
+                       size += sizeof(SkQuadraticEdge);        // treat line like Quad (in case its > 512)
+                       break;
+               case SkPath::kQuad_Verb:
+                       edgeCount += 2;                                         // might need 2 edges when we chop on Y extrema
+                       size += 2 * sizeof(SkQuadraticEdge);
+                       break;
+               case SkPath::kCubic_Verb:
+                       edgeCount += 3;                                         // might need 3 edges when we chop on Y extrema
+                       size += 3 * sizeof(SkCubicEdge);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       SkASSERT(storage);
+       *storage = size;
+       return edgeCount;
+}
+
+void sk_fill_path(const SkPath& path, const SkRect16* clipRect, SkBlitter* blitter,
+                                 const SkRect16& ir, int shiftEdgesUp)
+{
+       SkASSERT(&path && blitter);
+
+       size_t  size;
+       int             maxCount = worst_case_edge_count(path, &size);
+
+       SkAutoMalloc    memory(maxCount * sizeof(SkEdge*) + size);
+       SkEdge**                list = (SkEdge**)memory.get();
+       SkEdge*                 edge = (SkEdge*)(list + maxCount);
+       int                             count = build_edges(edge, path, clipRect, list, shiftEdgesUp);
+       SkEdge                  headEdge, tailEdge, *last;
+
+       SkASSERT(count <= maxCount);
+       if (count == 0)
+               return;
+       SkASSERT(count > 1);
+
+       // this returns the first and last edge after they're sorted into a dlink list
+       edge = sort_edges(list, count, &last);
+
+       headEdge.fPrev = nil;
+       headEdge.fNext = edge;
+       headEdge.fFirstY = kEDGE_HEAD_Y;
+       headEdge.fX = SK_MinS32;
+       edge->fPrev = &headEdge;
+
+       tailEdge.fPrev = last;
+       tailEdge.fNext = nil;
+       tailEdge.fFirstY = kEDGE_TAIL_Y;
+       last->fNext = &tailEdge;
+
+       // now edge is the head of the sorted linklist
+       int     stop_y = ir.fBottom;
+       if (clipRect && stop_y > clipRect->fBottom)
+               stop_y = clipRect->fBottom;
+       walk_edges(&headEdge, path.getFillType(), blitter, stop_y);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+SkScanClipper::SkScanClipper(SkBlitter* blitter, const SkRegion* clip, const SkRect16& ir)
+{
+       fBlitter = nil;         // nil means blit nothing
+       fClipRect = nil;
+
+       if (clip)
+       {
+               fClipRect = &clip->getBounds();
+               if (!SkRect16::Intersects(*fClipRect, ir))      // completely clipped out
+                       return;
+
+               if (clip->isRect())
+               {
+                       if (fClipRect->contains(ir))
+                               fClipRect = nil;
+                       else
+                       {
+                               // only need a wrapper blitter if we're horizontally clipped
+                               if (fClipRect->fLeft > ir.fLeft || fClipRect->fRight < ir.fRight)
+                               {
+                                       fRectBlitter.init(blitter, *fClipRect);
+                                       blitter = &fRectBlitter;
+                               }
+                       }
+               }
+               else
+               {
+                       fRgnBlitter.init(blitter, clip);
+                       blitter = &fRgnBlitter;
+               }
+       }
+       fBlitter = blitter;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+void SkScan::FillPath(const SkPath& path, const SkRegion* clip, SkBlitter* blitter)
+{
+       if (clip && clip->isEmpty())
+               return;
+
+       SkRect          r;
+       SkRect16        ir;
+
+       path.computeBounds(&r, SkPath::kFast_BoundsType);
+       r.round(&ir);
+       if (ir.isEmpty())
+               return;
+
+       SkScanClipper   clipper(blitter, clip, ir);
+
+       blitter = clipper.getBlitter();
+       if (blitter)
+               sk_fill_path(path, clipper.getClipRect(), blitter, ir, 0);
+}
+
diff --git a/libs/graphics/sgl/SkShader.cpp b/libs/graphics/sgl/SkShader.cpp
new file mode 100644 (file)
index 0000000..6d1ac3e
--- /dev/null
@@ -0,0 +1,370 @@
+#include "SkShader.h"
+#include "SkPaint.h"
+
+SkShader::SkShader() : fLocalMatrix(nil)
+{
+}
+
+SkShader::~SkShader()
+{
+       sk_free(fLocalMatrix);
+}
+
+void SkShader::setLocalMatrix(const SkMatrix& matrix)
+{
+       if (matrix.isIdentity())
+       {
+               if (fLocalMatrix)
+               {
+                       sk_free(fLocalMatrix);
+                       fLocalMatrix = nil;
+               }
+       }
+       else
+       {
+               if (fLocalMatrix == nil)
+                       fLocalMatrix = (SkMatrix*)sk_malloc_throw(sizeof(SkMatrix));
+               *fLocalMatrix = matrix;
+       }
+}
+
+bool SkShader::setContext(const SkBitmap& device,
+                                                 const SkPaint& paint,
+                                                 const SkMatrix& matrix)
+{
+       const SkMatrix* m = &matrix;
+       SkMatrix                total;
+
+       fDeviceConfig = SkToU8(device.getConfig());
+       fPaintAlpha = paint.getAlpha();
+       if (fLocalMatrix)
+       {
+               total.setConcat(matrix, *fLocalMatrix);
+               m = &total;
+       }
+       if (m->invert(&fTotalInverse))
+       {
+               fInverseMapPtProc = fTotalInverse.getMapPtProc();
+               fTotalInverseClass = (U8)SkShader::ComputeMatrixClass(fTotalInverse);
+               return true;
+       }
+       return false;
+}
+
+U32 SkShader::getFlags()
+{
+       return 0;
+}
+
+#include "SkColorPriv.h"
+
+void SkShader::shadeSpanOpaque16(int x, int y, U16 span16[], int count)
+{
+       SkASSERT(span16);
+       SkASSERT(count > 0);
+       SkASSERT(this->canCallShadeSpanOpaque16());
+
+       // basically, if we get here, the subclass screwed up
+       SkASSERT(!"kHasSpan16 flag is set, but shadeSpanOpaque16() not implemented");
+}
+
+#define kTempColorQuadCount    6       // balance between speed (larger) and saving stack-space
+#define kTempColorCount                (kTempColorQuadCount << 2)      
+
+#ifdef SK_CPU_BENDIAN
+       #define SkU32BitShiftToByteOffset(shift)        (3 - ((shift) >> 3))
+#else
+       #define SkU32BitShiftToByteOffset(shift)        ((shift) >> 3)
+#endif
+
+void SkShader::shadeSpanAlpha(int x, int y, U8 alpha[], int count)
+{
+       SkASSERT(count > 0);
+
+       SkPMColor       colors[kTempColorCount];
+
+       while ((count -= kTempColorCount) >= 0)
+       {
+               this->shadeSpan(x, y, colors, kTempColorCount);
+               x += kTempColorCount;
+
+               const U8* srcA = (const U8*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
+               int quads = kTempColorQuadCount;
+               do {
+                       U8CPU a0 = srcA[0];
+                       U8CPU a1 = srcA[4];
+                       U8CPU a2 = srcA[8];
+                       U8CPU a3 = srcA[12];
+                       srcA += 4*4;
+                       *alpha++ = SkToU8(a0);
+                       *alpha++ = SkToU8(a1);
+                       *alpha++ = SkToU8(a2);
+                       *alpha++ = SkToU8(a3);
+               } while (--quads != 0);
+       }
+       SkASSERT(count < 0);
+       SkASSERT(count + kTempColorCount >= 0);
+       if (count += kTempColorCount)
+       {
+               this->shadeSpan(x, y, colors, count);
+
+               const U8* srcA = (const U8*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
+               do {
+                       *alpha++ = *srcA;
+                       srcA += 4;
+               } while (--count != 0);
+       }
+#if 0
+       do {
+               int n = count;
+               if (n > kTempColorCount)
+                       n = kTempColorCount;
+               SkASSERT(n > 0);
+
+               this->shadeSpan(x, y, colors, n);
+               x += n;
+               count -= n;
+
+               const U8* srcA = (const U8*)colors + SkU32BitShiftToByteOffset(SK_A32_SHIFT);
+               do {
+                       *alpha++ = *srcA;
+                       srcA += 4;
+               } while (--n != 0);
+       } while (count > 0);
+#endif
+}
+
+SkShader::MatrixClass SkShader::ComputeMatrixClass(const SkMatrix& mat)
+{
+       MatrixClass     mc = kLinear_MatrixClass;
+
+       if (mat.getType() & SkMatrix::kPerspective_Mask)
+       {
+               if (mat.fixedStepInX(0, nil, nil))
+                       mc = kFixedStepInX_MatrixClass;
+               else
+                       mc = kPerspective_MatrixClass;
+       }
+       return mc;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+#if 0
+SkPairShader::SkPairShader(SkShader* s0, SkShader* s1)
+       : fShader0(s0), fShader1(s1)
+{
+       s0->safeRef();
+       s1->safeRef();
+}
+
+SkPairShader::~SkPairShader()
+{
+       fShader1->safeUnref();
+       fShader0->safeUnref();
+}
+
+U32 SkPairShader::getFlags()
+{
+       SkASSERT(fShader0 || fShader1);
+
+       U32     flags = 0-1U;
+
+       if (fShader0)
+               flags &= fShader0->getFlags();
+       if (fShader1)
+               flags &= fShader1->getFlags();
+       return flags;
+}
+
+bool SkPairShader::setContext( const SkBitmap& device,
+                                                               const SkPaint& paint,
+                                                               const SkMatrix& matrix)
+{
+       if (fShader0 == nil && fShader1 == nil)
+               return false;
+
+       const SkMatrix* localM = this->getLocalMatrix();
+       SkMatrix                tmp;
+
+       if (localM)
+       {
+               tmp.setConcat(matrix, *localM);
+               localM = &tmp;
+       }
+       else
+               localM = &matrix;
+
+       //      wonder if some subclasses will want OR instead of AND?
+
+       if (fShader0 && !fShader0->setContext(device, paint, *localM))
+               return false;
+       if (fShader1 && !fShader1->setContext(device, paint, *localM))
+               return false;
+       return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+void SkComposeShader::shadeSpan(int x, int y, SkPMColor span[], int count)
+{
+       SkShader*       s0 = this->getShader0();
+       SkShader*       s1 = this->getShader1();
+
+       if (s1)
+               s1->shadeSpan(x, y, span, count);
+       if (s0)
+               s0->shadeSpan(x, y, span, count);
+}
+
+void SkComposeShader::shadeSpanOpaque16(int x, int y, U16 span[], int count)
+{
+       SkShader*       s0 = this->getShader0();
+       SkShader*       s1 = this->getShader1();
+
+       if (s1)
+               s1->shadeSpanOpaque16(x, y, span, count);
+       if (s0)
+               s0->shadeSpanOpaque16(x, y, span, count);
+}
+
+void SkComposeShader::shadeSpanAlpha(int x, int y, U8 span[], int count)
+{
+       SkShader*       s0 = this->getShader0();
+       SkShader*       s1 = this->getShader1();
+
+       if (s1)
+               s1->shadeSpanAlpha(x, y, span, count);
+       if (s0)
+               s0->shadeSpanAlpha(x, y, span, count);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkXfermode.h"
+#include "SkColorPriv.h"
+#include "SkBitmap.h"
+
+SkSumShader::SkSumShader(SkShader* s0, SkShader* s1, U8CPU weight)
+       : SkPairShader(s0, s1), fBuffer(nil), fMode(nil), fWeight(SkToU8(weight))
+{
+}
+
+SkSumShader::SkSumShader(SkShader* s0, SkShader* s1, SkXfermode* mode)
+       : SkPairShader(s0, s1), fBuffer(nil), fMode(mode), fWeight(0xFF)
+{
+       mode->safeRef();
+}
+
+SkSumShader::~SkSumShader()
+{
+       fMode->safeUnref();
+       sk_free(fBuffer);
+}
+
+bool SkSumShader::setContext(const SkBitmap& device,
+                                                        const SkPaint& paint,
+                                                        const SkMatrix& matrix)
+{
+       if (!this->INHERITED::setContext(device, paint, matrix))
+               return false;
+
+       if (fBuffer == nil)
+               fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * sizeof(SkPMColor));
+       else
+               fBuffer = (SkPMColor*)sk_realloc_throw(fBuffer, device.width() * sizeof(SkPMColor));
+       return true;
+}
+
+void SkSumShader::shadeSpan(int x, int y, SkPMColor dst[], int count)
+{
+       SkShader*       s0 = this->getShader0();
+       SkShader*       s1 = this->getShader1();
+       SkASSERT(s0 || s1);
+
+       if (s0 == nil)
+               s1->shadeSpan(x, y, dst, count);
+       else
+       {
+               s0->shadeSpan(x, y, dst, count);
+               if (s1)
+               {
+                       SkPMColor* src = fBuffer;
+                       s1->shadeSpan(x, y, src, count);
+
+                       if (fMode)
+                               fMode->xfer32(dst, src, count, nil);
+                       else
+                       {
+                               unsigned weight = fWeight;
+                               for (int i = 0; i < count; i++)
+                                       dst[i] = SkBlendARGB32(src[i], dst[i], weight);
+                       }
+               }
+       }
+}
+
+void SkSumShader::shadeSpanOpaque16(int x, int y, U16 dst[], int count)
+{
+       SkShader*       s0 = this->getShader0();
+       SkShader*       s1 = this->getShader1();
+       SkASSERT(s0 || s1);
+
+       if (s0 == nil)
+               s1->shadeSpanOpaque16(x, y, dst, count);
+       else
+       {
+               s0->shadeSpanOpaque16(x, y, dst, count);
+               if (s1)
+               {
+                       if (fMode)
+                       {
+                               SkPMColor* src = fBuffer;
+                               s1->shadeSpan(x, y, src, count);
+                               fMode->xfer16(dst, src, count, nil);
+                       }
+                       else
+                       {
+                               U16* src = (U16*)fBuffer;
+                               s1->shadeSpanOpaque16(x, y, src, count);
+
+                               unsigned scale = SkAlpha255To256(fWeight);
+                               for (int i = 0; i < count; i++)
+                                       dst[i] = (U16)SkBlendRGB16(src[i], dst[i], scale);
+                       }
+               }
+       }
+}
+
+void SkSumShader::shadeSpanAlpha(int x, int y, U8 dst[], int count)
+{
+       SkShader*       s0 = this->getShader0();
+       SkShader*       s1 = this->getShader1();
+       SkASSERT(s0 || s1);
+
+       if (s0 == nil)
+               s1->shadeSpanAlpha(x, y, dst, count);
+       else
+       {
+               s0->shadeSpanAlpha(x, y, dst, count);
+               if (s1)
+               {
+                       if (fMode)
+                       {
+                               SkPMColor* src = fBuffer;
+                               s1->shadeSpan(x, y, src, count);
+                               fMode->xferA8(dst, src, count, nil);
+                       }
+                       else
+                       {
+                               U8* src = (U8*)fBuffer;
+                               s1->shadeSpanAlpha(x, y, src, count);
+
+                               unsigned scale = SkAlpha255To256(fWeight);
+                               for (int i = 0; i < count; i++)
+                                       dst[i] = (U8)SkAlphaBlend(src[i], dst[i], scale);
+                       }
+               }
+       }
+}
+#endif
diff --git a/libs/graphics/sgl/SkSinTable.h b/libs/graphics/sgl/SkSinTable.h
new file mode 100644 (file)
index 0000000..2c4c11d
--- /dev/null
@@ -0,0 +1,268 @@
+#ifndef SkSinTable_DEFINED
+#define SkSinTable_DEFINED
+
+#include "SkTypes.h"
+
+/* Fixed point values (low 16 bits) of sin(radians) for
+       radians in [0...PI/2)
+*/
+static const U16 gSkSinTable[256] = {
+       0x0000,
+       0x0192,
+       0x0324,
+       0x04B6,
+       0x0648,
+       0x07DA,
+       0x096C,
+       0x0AFE,
+       0x0C8F,
+       0x0E21,
+       0x0FB2,
+       0x1144,
+       0x12D5,
+       0x1466,
+       0x15F6,
+       0x1787,
+       0x1917,
+       0x1AA7,
+       0x1C37,
+       0x1DC7,
+       0x1F56,
+       0x20E5,
+       0x2273,
+       0x2402,
+       0x2590,
+       0x271D,
+       0x28AA,
+       0x2A37,
+       0x2BC4,
+       0x2D50,
+       0x2EDB,
+       0x3066,
+       0x31F1,
+       0x337B,
+       0x3505,
+       0x368E,
+       0x3817,
+       0x399F,
+       0x3B26,
+       0x3CAD,
+       0x3E33,
+       0x3FB9,
+       0x413E,
+       0x42C3,
+       0x4447,
+       0x45CA,
+       0x474D,
+       0x48CE,
+       0x4A50,
+       0x4BD0,
+       0x4D50,
+       0x4ECF,
+       0x504D,
+       0x51CA,
+       0x5347,
+       0x54C3,
+       0x563E,
+       0x57B8,
+       0x5931,
+       0x5AAA,
+       0x5C22,
+       0x5D98,
+       0x5F0E,
+       0x6083,
+       0x61F7,
+       0x636A,
+       0x64DC,
+       0x664D,
+       0x67BD,
+       0x692D,
+       0x6A9B,
+       0x6C08,
+       0x6D74,
+       0x6EDF,
+       0x7049,
+       0x71B1,
+       0x7319,
+       0x7480,
+       0x75E5,
+       0x774A,
+       0x78AD,
+       0x7A0F,
+       0x7B70,
+       0x7CD0,
+       0x7E2E,
+       0x7F8B,
+       0x80E7,
+       0x8242,
+       0x839C,
+       0x84F4,
+       0x864B,
+       0x87A1,
+       0x88F5,
+       0x8A48,
+       0x8B9A,
+       0x8CEA,
+       0x8E39,
+       0x8F87,
+       0x90D3,
+       0x921E,
+       0x9368,
+       0x94B0,
+       0x95F6,
+       0x973C,
+       0x987F,
+       0x99C2,
+       0x9B02,
+       0x9C42,
+       0x9D7F,
+       0x9EBC,
+       0x9FF6,
+       0xA12F,
+       0xA267,
+       0xA39D,
+       0xA4D2,
+       0xA605,
+       0xA736,
+       0xA866,
+       0xA994,
+       0xAAC0,
+       0xABEB,
+       0xAD14,
+       0xAE3B,
+       0xAF61,
+       0xB085,
+       0xB1A8,
+       0xB2C8,
+       0xB3E7,
+       0xB504,
+       0xB620,
+       0xB73A,
+       0xB852,
+       0xB968,
+       0xBA7C,
+       0xBB8F,
+       0xBCA0,
+       0xBDAE,
+       0xBEBC,
+       0xBFC7,
+       0xC0D0,
+       0xC1D8,
+       0xC2DE,
+       0xC3E2,
+       0xC4E3,
+       0xC5E4,
+       0xC6E2,
+       0xC7DE,
+       0xC8D8,
+       0xC9D1,
+       0xCAC7,
+       0xCBBB,
+       0xCCAE,
+       0xCD9F,
+       0xCE8D,
+       0xCF7A,
+       0xD064,
+       0xD14D,
+       0xD233,
+       0xD318,
+       0xD3FA,
+       0xD4DB,
+       0xD5B9,
+       0xD695,
+       0xD770,
+       0xD848,
+       0xD91E,
+       0xD9F2,
+       0xDAC4,
+       0xDB94,
+       0xDC61,
+       0xDD2D,
+       0xDDF6,
+       0xDEBE,
+       0xDF83,
+       0xE046,
+       0xE106,
+       0xE1C5,
+       0xE282,
+       0xE33C,
+       0xE3F4,
+       0xE4AA,
+       0xE55E,
+       0xE60F,
+       0xE6BE,
+       0xE76B,
+       0xE816,
+       0xE8BF,
+       0xE965,
+       0xEA09,
+       0xEAAB,
+       0xEB4B,
+       0xEBE8,
+       0xEC83,
+       0xED1C,
+       0xEDB2,
+       0xEE46,
+       0xEED8,
+       0xEF68,
+       0xEFF5,
+       0xF080,
+       0xF109,
+       0xF18F,
+       0xF213,
+       0xF294,
+       0xF314,
+       0xF391,
+       0xF40B,
+       0xF484,
+       0xF4FA,
+       0xF56D,
+       0xF5DE,
+       0xF64D,
+       0xF6BA,
+       0xF724,
+       0xF78B,
+       0xF7F1,
+       0xF853,
+       0xF8B4,
+       0xF912,
+       0xF96E,
+       0xF9C7,
+       0xFA1E,
+       0xFA73,
+       0xFAC5,
+       0xFB14,
+       0xFB61,
+       0xFBAC,
+       0xFBF5,
+       0xFC3B,
+       0xFC7E,
+       0xFCBF,
+       0xFCFE,
+       0xFD3A,
+       0xFD74,
+       0xFDAB,
+       0xFDE0,
+       0xFE13,
+       0xFE43,
+       0xFE70,
+       0xFE9B,
+       0xFEC4,
+       0xFEEA,
+       0xFF0E,
+       0xFF2F,
+       0xFF4E,
+       0xFF6A,
+       0xFF84,
+       0xFF9C,
+       0xFFB1,
+       0xFFC3,
+       0xFFD3,
+       0xFFE1,
+       0xFFEC,
+       0xFFF4,
+       0xFFFB,
+       0xFFFE
+};
+
+#endif
diff --git a/libs/graphics/sgl/SkSpriteBlitter.h b/libs/graphics/sgl/SkSpriteBlitter.h
new file mode 100644 (file)
index 0000000..b85690e
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef SkSpriteBlitter_DEFINED
+#define SkSpriteBlitter_DEFINED
+
+#include "SkBlitter.h"
+#include "SkBitmap.h"
+
+class SkXfermode;
+
+class SkSpriteBlitter : public SkBlitter {
+public:
+                       SkSpriteBlitter(const SkBitmap& source);
+       virtual ~SkSpriteBlitter();
+
+       void setup(const SkBitmap& device, int left, int top)
+       {
+               fDevice = &device;
+               fLeft = left;
+               fTop = top;
+       }
+
+       // overrides
+#ifdef SK_DEBUG
+       virtual void    blitH(int x, int y, int width);
+       virtual void    blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[]);
+       virtual void    blitV(int x, int y, int height, SkAlpha alpha);
+       virtual void    blitMask(const SkMask&, const SkRect16& clip);
+#endif
+
+       static SkSpriteBlitter* ChooseD16(const SkBitmap& source, SkXfermode* mode, U8 alpha,
+                                                                         void* storage, size_t storageSize);
+       static SkSpriteBlitter* ChooseD32(const SkBitmap& source, SkXfermode* mode, U8 alpha,
+                                                                         void* storage, size_t storageSize);
+
+protected:
+       const SkBitmap* fDevice;
+       const SkBitmap* fSource;
+       int                             fLeft, fTop;
+};
+
+#endif
+
diff --git a/libs/graphics/sgl/SkSpriteBlitterTemplate.h b/libs/graphics/sgl/SkSpriteBlitterTemplate.h
new file mode 100644 (file)
index 0000000..23d2fbf
--- /dev/null
@@ -0,0 +1,60 @@
+
+class SkSPRITE_CLASSNAME : public SkSpriteBlitter {
+public:
+       SkSPRITE_CLASSNAME(const SkBitmap& source SkSPRITE_ARGS)
+               : SkSpriteBlitter(source)
+       {
+               SkSPRITE_INIT
+       }
+       virtual void blitRect(int x, int y, int width, int height)
+       {
+               SkASSERT(width > 0 && height > 0);
+               int srcX = x - fLeft;
+               int srcY = y - fTop;
+               SkSPRITE_DST_TYPE*                      dst = fDevice->SkSPRITE_DST_GETADDR(x, y);
+               const SkSPRITE_SRC_TYPE*        src = fSource->SkSPRITE_SRC_GETADDR(srcX, srcY);
+               unsigned                                        dstRB = fDevice->rowBytes();
+               unsigned                                        srcRB = fSource->rowBytes();
+
+               SkDEBUGCODE((void)fDevice->SkSPRITE_DST_GETADDR(x + width - 1, y + height - 1);)
+               SkDEBUGCODE((void)fSource->SkSPRITE_SRC_GETADDR(srcX + width  - 1, srcY + height - 1);)
+
+               SkSPRITE_PREAMBLE((*fSource), srcX, srcY);
+
+               do {
+                       SkSPRITE_DST_TYPE* d = dst;
+                       const SkSPRITE_SRC_TYPE* s = src;
+#ifdef SkSPRITE_BEGIN_ROW
+                       SkSPRITE_BEGIN_ROW
+#endif
+                       int w = width;
+                       do {
+                               SkSPRITE_SRC_TYPE sc = *s++;
+                               SkSPRITE_BLIT_PIXEL(d, sc);
+                               d += 1;
+                       } while (--w != 0);
+                       dst = (SkSPRITE_DST_TYPE*)((char*)dst + dstRB);
+                       src = (const SkSPRITE_SRC_TYPE*)((const char*)src + srcRB);
+                       SkSPRITE_NEXT_ROW
+               } while (--height != 0);
+
+               SkSPRITE_POSTAMBLE((*fSource));
+       }
+private:
+       SkSPRITE_FIELDS
+};
+
+#undef SkSPRITE_BLIT_PIXEL
+#undef SkSPRITE_CLASSNAME
+#undef SkSPRITE_DST_TYPE
+#undef SkSPRITE_SRC_TYPE
+#undef SkSPRITE_DST_GETADDR
+#undef SkSPRITE_SRC_GETADDR
+#undef SkSPRITE_PREAMBLE
+#undef SkSPRITE_POSTAMBLE
+#undef SkSPRITE_ARGS
+#undef SkSPRITE_FIELDS
+#undef SkSPRITE_INIT
+#undef SkSPRITE_NEXT_ROW
+#undef SkSPRITE_BEGIN_ROW
+
diff --git a/libs/graphics/sgl/SkSpriteBlitter_ARGB32.cpp b/libs/graphics/sgl/SkSpriteBlitter_ARGB32.cpp
new file mode 100644 (file)
index 0000000..80ab5a5
--- /dev/null
@@ -0,0 +1,81 @@
+#include "SkSpriteBlitter.h"
+#include "SkTemplates.h"
+#include "SkUtils.h"
+#include "SkColorPriv.h"
+
+#define D32_S32A_Opaque_Pixel(dst, sc)                                                                                                                         \
+do {                                                                                                                                                                                           \
+       if (sc)                                                                                                                                                                                 \
+       {                                                                                                                                                                                               \
+               unsigned srcA = SkGetPackedA32(sc);                                                                                                                     \
+               U32 result = sc;                                                                                                        \
+               if (srcA != 0xFF)                                                                                                                                                       \
+                       result += SkAlphaMulQ(*dst, SkAlpha255To256(255 - srcA));                                                       \
+               *dst = result;                                                                                                                                                          \
+       }                                                                                                                                                                                               \
+} while (0)
+
+#define SkSPRITE_CLASSNAME                                     Sprite_D32_S32A_Opaque
+#define SkSPRITE_ARGS
+#define SkSPRITE_FIELDS
+#define SkSPRITE_INIT
+#define SkSPRITE_DST_TYPE                                      uint32_t
+#define SkSPRITE_SRC_TYPE                                      uint32_t
+#define SkSPRITE_DST_GETADDR                           getAddr32
+#define SkSPRITE_SRC_GETADDR                           getAddr32
+#define SkSPRITE_PREAMBLE(srcBM, x, y)
+#define SkSPRITE_BLIT_PIXEL(dst, src)          D32_S32A_Opaque_Pixel(dst, src)
+#define SkSPRITE_NEXT_ROW
+#define SkSPRITE_POSTAMBLE(srcBM)
+#include "SkSpriteBlitterTemplate.h"
+
+class Sprite_D32_S32_Opaque : public SkSpriteBlitter {
+public:
+       Sprite_D32_S32_Opaque(const SkBitmap& source) : SkSpriteBlitter(source) {}
+
+       virtual void blitRect(int x, int y, int width, int height)
+       {
+               SkASSERT(width > 0 && height > 0);
+               uint32_t*               dst = fDevice->getAddr32(x, y);
+               const uint32_t* src = fSource->getAddr32(x - fLeft, y - fTop);
+               unsigned                dstRB = fDevice->rowBytes();
+               unsigned                srcRB = fSource->rowBytes();
+        size_t          size = width * sizeof(uint32_t);
+
+               do {
+            memcpy(dst, src, size);
+                       dst = (uint32_t*)((char*)dst + dstRB);
+                       src = (const uint32_t*)((const char*)src + srcRB);
+               } while (--height != 0);
+       }
+};
+
+//////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkTemplatesPriv.h"
+
+SkSpriteBlitter* SkSpriteBlitter::ChooseD32(const SkBitmap& source, SkXfermode* mode, U8 alpha,
+                                                                                       void* storage, size_t storageSize)
+{
+       SkSpriteBlitter* blitter = nil;
+
+       switch (source.getConfig()) {
+       case SkBitmap::kARGB_8888_Config:
+               if (mode == nil)
+               {
+                       if (alpha == 255)
+            {
+                if (source.isOpaque())
+                    SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D32_S32_Opaque, storage, storageSize, (source));
+                else
+                    SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D32_S32A_Opaque, storage, storageSize, (source));
+            }
+               }
+               break;
+       default:
+               break;
+       }
+       return blitter;
+}
+
diff --git a/libs/graphics/sgl/SkSpriteBlitter_RGB16.cpp b/libs/graphics/sgl/SkSpriteBlitter_RGB16.cpp
new file mode 100644 (file)
index 0000000..ab65bae
--- /dev/null
@@ -0,0 +1,300 @@
+#include "SkSpriteBlitter.h"
+#include "SkTemplates.h"
+#include "SkUtils.h"
+#include "SkColorPriv.h"
+
+#define D16_S32A_Opaque_Pixel(dst, sc)                                                                                                                         \
+do {                                                                                                                                                                                           \
+       if (sc)                                                                                                                                                                                 \
+       {                                                                                                                                                                                               \
+               unsigned srcA = SkGetPackedA32(sc);                                                                                                                     \
+               unsigned result = SkPixel32ToPixel16(sc);                                                                                                       \
+               if (srcA != 0xFF)                                                                                                                                                       \
+                       result += SkAlphaMulRGB16(*dst, SkAlpha255To256(255 - srcA));                                                   \
+               *dst = SkToU16(result);                                                                                                                                                         \
+       }                                                                                                                                                                                               \
+} while (0)
+
+#define SkSPRITE_CLASSNAME                                     Sprite_D16_S32A_Opaque
+#define SkSPRITE_ARGS
+#define SkSPRITE_FIELDS
+#define SkSPRITE_INIT
+#define SkSPRITE_DST_TYPE                                      uint16_t
+#define SkSPRITE_SRC_TYPE                                      uint32_t
+#define SkSPRITE_DST_GETADDR                           getAddr16
+#define SkSPRITE_SRC_GETADDR                           getAddr32
+#define SkSPRITE_PREAMBLE(srcBM, x, y)
+#define SkSPRITE_BLIT_PIXEL(dst, src)          D16_S32A_Opaque_Pixel(dst, src)
+#define SkSPRITE_NEXT_ROW
+#define SkSPRITE_POSTAMBLE(srcBM)
+#include "SkSpriteBlitterTemplate.h"
+
+static inline void D16_S32A_Blend_Pixel_helper(U16* dst, U32 sc, unsigned src_scale)
+{
+       uint16_t dc = *dst;
+       unsigned sa = SkGetPackedA32(sc);
+       unsigned dr, dg, db;
+
+       if (sa == 255)
+       {
+               dr = SkAlphaBlend(SkPacked32ToR16(sc), SkGetPackedR16(dc), src_scale);
+               dg = SkAlphaBlend(SkPacked32ToG16(sc), SkGetPackedG16(dc), src_scale);
+               db = SkAlphaBlend(SkPacked32ToB16(sc), SkGetPackedB16(dc), src_scale);
+       }
+       else
+       {
+               unsigned dst_scale = 255 - SkAlphaMul(sa, src_scale);
+               dr = (SkPacked32ToR16(sc) * src_scale + SkGetPackedR16(dc) * dst_scale) >> 8;
+               dg = (SkPacked32ToG16(sc) * src_scale + SkGetPackedG16(dc) * dst_scale) >> 8;
+               db = (SkPacked32ToB16(sc) * src_scale + SkGetPackedB16(dc) * dst_scale) >> 8;
+       }
+       *dst = SkPackRGB16(dr, dg, db);
+}
+
+#define D16_S32A_Blend_Pixel(dst, sc, src_scale)       do { if (sc) D16_S32A_Blend_Pixel_helper(dst, sc, src_scale); } while (0)
+
+
+#define SkSPRITE_CLASSNAME                                     Sprite_D16_S32A_Blend
+#define SkSPRITE_ARGS                                          , U8 alpha
+#define SkSPRITE_FIELDS                                                U8 fSrcAlpha;
+#define SkSPRITE_INIT                                          fSrcAlpha = alpha;
+#define SkSPRITE_DST_TYPE                                      uint16_t
+#define SkSPRITE_SRC_TYPE                                      uint32_t
+#define SkSPRITE_DST_GETADDR                           getAddr16
+#define SkSPRITE_SRC_GETADDR                           getAddr32
+#define SkSPRITE_PREAMBLE(srcBM, x, y)         unsigned src_scale = SkAlpha255To256(fSrcAlpha);
+#define SkSPRITE_BLIT_PIXEL(dst, src)          D16_S32A_Blend_Pixel(dst, src, src_scale)
+#define SkSPRITE_NEXT_ROW
+#define SkSPRITE_POSTAMBLE(srcBM)
+#include "SkSpriteBlitterTemplate.h"
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+#define SkSPRITE_CLASSNAME                                     Sprite_D16_S32_Opaque
+#define SkSPRITE_ARGS
+#define SkSPRITE_FIELDS
+#define SkSPRITE_INIT
+#define SkSPRITE_DST_TYPE                                      uint16_t
+#define SkSPRITE_SRC_TYPE                                      uint32_t
+#define SkSPRITE_DST_GETADDR                           getAddr16
+#define SkSPRITE_SRC_GETADDR                           getAddr32
+#define SkSPRITE_PREAMBLE(srcBM, x, y)
+#define SkSPRITE_BLIT_PIXEL(dst, src)          *dst = SkPixel32ToPixel16_ToU16(src)
+#define SkSPRITE_NEXT_ROW
+#define SkSPRITE_POSTAMBLE(srcBM)
+#include "SkSpriteBlitterTemplate.h"
+
+#if 1
+#define D16_S32_Blend_Pixel(dst, sc, scale)                                                                                            \
+do {                                                                                                                                                                   \
+       U16 dc = *dst;                                                                                                                                          \
+       *dst = SkPackRGB16(     SkAlphaBlend(SkPacked32ToR16(sc), SkGetPackedR16(dc), scale),   \
+                                               SkAlphaBlend(SkPacked32ToG16(sc), SkGetPackedG16(dc), scale),   \
+                                               SkAlphaBlend(SkPacked32ToB16(sc), SkGetPackedB16(dc), scale));  \
+} while (0)
+#else
+static inline void D16_S32_Blend_Pixel(uint16_t* dst, uint32_t sc, int scale)
+{
+       U16 dc = *dst;
+       *dst = SkPackRGB16(     SkAlphaBlend(SkPacked32ToR16(sc), SkGetPackedR16(dc), scale),
+                                               SkAlphaBlend(SkPacked32ToG16(sc), SkGetPackedG16(dc), scale),
+                                               SkAlphaBlend(SkPacked32ToB16(sc), SkGetPackedB16(dc), scale));
+}
+#endif
+
+#define SkSPRITE_CLASSNAME                                     Sprite_D16_S32_Blend
+#define SkSPRITE_ARGS                                          , uint8_t alpha
+#define SkSPRITE_FIELDS                                                uint8_t fSrcAlpha;
+#define SkSPRITE_INIT                                          fSrcAlpha = alpha;
+#define SkSPRITE_DST_TYPE                                      uint16_t
+#define SkSPRITE_SRC_TYPE                                      uint32_t
+#define SkSPRITE_DST_GETADDR                           getAddr16
+#define SkSPRITE_SRC_GETADDR                           getAddr32
+#define SkSPRITE_PREAMBLE(srcBM, x, y)         int src_scale = SkAlpha255To256(fSrcAlpha);
+#define SkSPRITE_BLIT_PIXEL(dst, src)          D16_S32_Blend_Pixel(dst, src, src_scale)
+#define SkSPRITE_NEXT_ROW
+#define SkSPRITE_POSTAMBLE(srcBM)
+#include "SkSpriteBlitterTemplate.h"
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+class Sprite_D16_S16_Opaque : public SkSpriteBlitter {
+public:
+       Sprite_D16_S16_Opaque(const SkBitmap& source)
+               : SkSpriteBlitter(source) {}
+
+       // overrides
+       virtual void blitRect(int x, int y, int width, int height)
+       {
+               uint16_t*               dst = fDevice->getAddr16(x, y);
+               const uint16_t* src = fSource->getAddr16(x - fLeft, y - fTop);
+               unsigned        dstRB = fDevice->rowBytes();
+               unsigned        srcRB = fSource->rowBytes();
+
+               while (--height >= 0)
+               {
+                       memcpy(dst, src, width << 1);
+                       dst = (uint16_t*)((char*)dst + dstRB);
+                       src = (const uint16_t*)((const char*)src + srcRB);
+               }
+       }
+};
+
+#define D16_S16_Blend_Pixel(dst, sc, scale)                            \
+       do {                                                                                            \
+               uint16_t dc = *dst;                                                             \
+               *dst = SkToU16(SkBlendRGB16(sc, dc, scale));    \
+       } while (0)
+
+#define SkSPRITE_CLASSNAME                                     Sprite_D16_S16_Blend
+#define SkSPRITE_ARGS                                          , U8 alpha
+#define SkSPRITE_FIELDS                                                U8      fSrcAlpha;
+#define SkSPRITE_INIT                                          fSrcAlpha = alpha;
+#define SkSPRITE_DST_TYPE                                      uint16_t
+#define SkSPRITE_SRC_TYPE                                      uint16_t
+#define SkSPRITE_DST_GETADDR                           getAddr16
+#define SkSPRITE_SRC_GETADDR                           getAddr16
+#define SkSPRITE_PREAMBLE(srcBM, x, y)         int scale = SkAlpha255To256(fSrcAlpha);
+#define SkSPRITE_BLIT_PIXEL(dst, src)          D16_S16_Blend_Pixel(dst, src, scale)
+#define SkSPRITE_NEXT_ROW
+#define SkSPRITE_POSTAMBLE(srcBM)
+#include "SkSpriteBlitterTemplate.h"
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+#define SkSPRITE_CLASSNAME                                     Sprite_D16_SIndex8A_Opaque
+#define SkSPRITE_ARGS
+#define SkSPRITE_FIELDS
+#define SkSPRITE_INIT
+#define SkSPRITE_DST_TYPE                                      uint16_t
+#define SkSPRITE_SRC_TYPE                                      uint8_t
+#define SkSPRITE_DST_GETADDR                           getAddr16
+#define SkSPRITE_SRC_GETADDR                           getAddr8
+#define SkSPRITE_PREAMBLE(srcBM, x, y)         const SkPMColor* ctable = srcBM.getColorTable()->lockColors()
+#define SkSPRITE_BLIT_PIXEL(dst, src)          D16_S32A_Opaque_Pixel(dst, ctable[src])
+#define SkSPRITE_NEXT_ROW
+#define SkSPRITE_POSTAMBLE(srcBM)                      srcBM.getColorTable()->unlockColors(false)
+#include "SkSpriteBlitterTemplate.h"
+
+#define SkSPRITE_CLASSNAME                                     Sprite_D16_SIndex8A_Blend
+#define SkSPRITE_ARGS                                          , uint8_t alpha
+#define SkSPRITE_FIELDS                                                uint8_t fSrcAlpha;
+#define SkSPRITE_INIT                                          fSrcAlpha = alpha;
+#define SkSPRITE_DST_TYPE                                      uint16_t
+#define SkSPRITE_SRC_TYPE                                      uint8_t
+#define SkSPRITE_DST_GETADDR                           getAddr16
+#define SkSPRITE_SRC_GETADDR                           getAddr8
+#define SkSPRITE_PREAMBLE(srcBM, x, y)         const SkPMColor* ctable = srcBM.getColorTable()->lockColors(); unsigned src_scale = SkAlpha255To256(fSrcAlpha);
+#define SkSPRITE_BLIT_PIXEL(dst, src)          D16_S32A_Blend_Pixel(dst, ctable[src], src_scale)
+#define SkSPRITE_NEXT_ROW
+#define SkSPRITE_POSTAMBLE(srcBM)                      srcBM.getColorTable()->unlockColors(false);
+#include "SkSpriteBlitterTemplate.h"
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+#define SkSPRITE_CLASSNAME                                     Sprite_D16_SIndex8_Opaque
+#define SkSPRITE_ARGS
+#define SkSPRITE_FIELDS
+#define SkSPRITE_INIT
+#define SkSPRITE_DST_TYPE                                      uint16_t
+#define SkSPRITE_SRC_TYPE                                      uint8_t
+#define SkSPRITE_DST_GETADDR                           getAddr16
+#define SkSPRITE_SRC_GETADDR                           getAddr8
+#define SkSPRITE_PREAMBLE(srcBM, x, y)         const uint16_t* ctable = srcBM.getColorTable()->lock16BitCache()
+#define SkSPRITE_BLIT_PIXEL(dst, src)          *dst = ctable[src]
+#define SkSPRITE_NEXT_ROW
+#define SkSPRITE_POSTAMBLE(srcBM)                      srcBM.getColorTable()->unlock16BitCache()
+#include "SkSpriteBlitterTemplate.h"
+
+#define SkSPRITE_CLASSNAME                                     Sprite_D16_SIndex8_Blend
+#define SkSPRITE_ARGS                                          , uint8_t alpha
+#define SkSPRITE_FIELDS                                                uint8_t fSrcAlpha;
+#define SkSPRITE_INIT                                          fSrcAlpha = alpha;
+#define SkSPRITE_DST_TYPE                                      uint16_t
+#define SkSPRITE_SRC_TYPE                                      uint8_t
+#define SkSPRITE_DST_GETADDR                           getAddr16
+#define SkSPRITE_SRC_GETADDR                           getAddr8
+#define SkSPRITE_PREAMBLE(srcBM, x, y)         const uint16_t* ctable = srcBM.getColorTable()->lock16BitCache(); unsigned src_scale = SkAlpha255To256(fSrcAlpha);
+#define SkSPRITE_BLIT_PIXEL(dst, src)          D16_S16_Blend_Pixel(dst, ctable[src], src_scale)
+#define SkSPRITE_NEXT_ROW
+#define SkSPRITE_POSTAMBLE(srcBM)                      srcBM.getColorTable()->unlock16BitCache();
+#include "SkSpriteBlitterTemplate.h"
+
+//////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkTemplatesPriv.h"
+
+SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkBitmap& source, SkXfermode* mode, U8 alpha,
+                                                                                       void* storage, size_t storageSize)
+{
+       SkSpriteBlitter* blitter = nil;
+
+       switch (source.getConfig()) {
+       case SkBitmap::kARGB_8888_Config:
+        if (mode == nil)
+        {
+            bool srcIsOpaque = source.isOpaque();
+            if (alpha == 255)
+            {
+                if (srcIsOpaque)
+                    SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S32_Opaque, storage, storageSize, (source));
+                else
+                    SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S32A_Opaque, storage, storageSize, (source));
+            }
+            else
+            {
+                if (srcIsOpaque)
+                    SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S32_Blend, storage, storageSize, (source, alpha));
+                else
+                    SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S32A_Blend, storage, storageSize, (source, alpha));
+            }
+        }
+               break;
+       case SkBitmap::kRGB_565_Config:
+#ifdef SK_SUPPORT_16_8_BITMAP
+               if (source.getA8Plane())
+               {
+                       if (mode == nil)
+                       {
+                               if (alpha == 255)
+                                       SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S816_Opaque, storage, storageSize, (source));
+                               else
+                                       SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S816_Blend, storage, storageSize, (source, alpha));
+                       }
+               }
+               else
+#endif
+               if (mode == nil)
+               {
+                       if (alpha == 255)
+                               SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S16_Opaque, storage, storageSize, (source));
+                       else
+                               SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_S16_Blend, storage, storageSize, (source, alpha));
+               }
+               break;
+       case SkBitmap::kIndex8_Config:
+               if (mode == nil)
+               {
+                       if (source.getColorTable()->getFlags() & SkColorTable::kColorsAreOpaque_Flag)
+                       {
+                               if (alpha == 255)
+                                       SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8_Opaque, storage, storageSize, (source));
+                               else
+                                       SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8_Blend, storage, storageSize, (source, alpha));
+                       }
+                       else
+                       {
+                               if (alpha == 255)
+                                       SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8A_Opaque, storage, storageSize, (source));
+                               else
+                                       SK_PLACEMENT_NEW_ARGS(blitter, Sprite_D16_SIndex8A_Blend, storage, storageSize, (source, alpha));
+                       }
+               }
+               break;
+       default:
+               break;
+       }
+       return blitter;
+}
+
diff --git a/libs/graphics/sgl/SkString.cpp b/libs/graphics/sgl/SkString.cpp
new file mode 100644 (file)
index 0000000..1859f98
--- /dev/null
@@ -0,0 +1,602 @@
+#include "SkString.h"
+#include "SkFixed.h"
+#include "SkUtils.h"
+#include <stdarg.h>
+
+bool SkStrStartsWith(const char string[], const char prefix[])
+{
+       SkASSERT(string);
+       SkASSERT(prefix);
+       return !strncmp(string, prefix, strlen(prefix));
+}
+
+bool SkStrEndsWith(const char string[], const char suffix[])
+{
+       SkASSERT(string);
+       SkASSERT(suffix);
+       size_t  strLen = strlen(string);
+       size_t  suffixLen = strlen(suffix);
+       return  strLen >= suffixLen &&
+                       !strncmp(string + strLen - suffixLen, suffix, suffixLen);
+}
+
+int SkStrStartsWithOneOf(const char string[], const char prefixes[])
+{
+       int index = 0;
+       do {
+               const char* limit = strchr(prefixes, '\0');
+        if (!strncmp(string, prefixes, limit - prefixes))
+                       return index;
+               prefixes = limit + 1;
+               index++;
+       } while (prefixes[0]);
+       return -1;
+}
+
+char* SkStrAppendS32(char string[], int32_t dec)
+{
+    SkDEBUGCODE(char* start = string;)
+
+       char    buffer[SkStrAppendS32_MaxSize];
+       char*   p = buffer + sizeof(buffer);
+       bool    neg = false;
+
+       if (dec < 0)
+       {
+               neg = true;
+               dec = -dec;
+       }
+       do {
+               *--p = SkToU8('0' + dec % 10);
+               dec /= 10;
+       } while (dec != 0);
+       if (neg)
+               *--p = '-';
+
+       SkASSERT(p >= buffer);
+    char* stop = buffer + sizeof(buffer);
+    while (p < stop)
+        *string++ = *p++;
+
+    SkASSERT(string - start <= SkStrAppendS32_MaxSize);
+    return string;
+}
+
+char* SkStrAppendScalar(char string[], SkScalar value)
+{
+    SkDEBUGCODE(char* start = string;)
+
+       SkFixed x = SkScalarToFixed(value);
+
+       if (x < 0)
+       {
+        *string++ = '-';
+               x = -x;
+       }
+
+       unsigned frac = x & 0xFFFF;
+       x >>= 16;
+       if (frac == 0xFFFF)     // need to do this to "round up", since 65535/65536 is closer to 1 than to .9999
+       {
+               x += 1;
+               frac = 0;
+       }
+    string = SkStrAppendS32(string, x);
+
+       // now handle the fractional part (if any)
+       if (frac)
+       {
+               static const uint16_t   gTens[] = { 1000, 100, 10, 1 };
+               const uint16_t*         tens = gTens;
+
+               x = SkFixedRound(frac * 10000);
+               SkASSERT(x < 10000);
+               *string++ = '.';
+               do {
+                       unsigned powerOfTen = *tens++;
+                       *string++ = SkToU8('0' + x / powerOfTen);
+                       x %= powerOfTen;
+               } while (x != 0);
+       }
+    
+    SkASSERT(string - start <= SkStrAppendScalar_MaxSize);
+    return string;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+#define kMaxRefCnt_SkString            SK_MaxU16
+
+// the 3 values are [length] [refcnt] [terminating zero data]
+static const U16 gEmptyRec[3] = { 0, 0, 0 };
+
+SkString::Rec* SkString::AllocRec(const char text[], U16CPU len)
+{
+       Rec* rec;
+
+       if (len == 0)
+               rec = (Rec*)gEmptyRec;
+       else
+       {
+               // add 1 for terminating 0, then align4 so we can have some slop when growing the string
+               rec = (Rec*)sk_malloc_throw(sizeof(Rec) + SkAlign4(len + 1));
+               rec->fLength = SkToU16(len);
+               rec->fRefCnt = 1;
+               if (text)
+                       memcpy(rec->data(), text, len);
+               rec->data()[len] = 0;
+       }
+       return rec;
+}
+
+SkString::Rec* SkString::RefRec(Rec* src)
+{
+       if (src != (Rec*)gEmptyRec)
+       {
+               if (src->fRefCnt == kMaxRefCnt_SkString) {
+                       src = AllocRec(src->data(), src->fLength);
+               } else
+                       src->fRefCnt += 1;
+       }
+       return src;
+}
+
+#ifdef SK_DEBUG
+void SkString::validate() const
+{
+       // make sure know one has written over our global
+       SkASSERT(((Rec*)gEmptyRec)->fLength == 0);
+       SkASSERT(((Rec*)gEmptyRec)->fRefCnt == 0);
+       SkASSERT(((Rec*)gEmptyRec)->data()[0] == 0);
+
+       if (fRec != (Rec*)gEmptyRec)
+       {
+               SkASSERT(fRec->fLength > 0);
+               SkASSERT(fRec->fRefCnt > 0);
+               SkASSERT(fRec->data()[fRec->fLength] == 0);
+       }
+       SkASSERT(fStr == c_str());
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////
+
+SkString::SkString() : fRec((Rec*)gEmptyRec) {
+#ifdef SK_DEBUG
+       fStr = fRec->data();
+#endif
+}
+
+SkString::SkString(size_t len)
+{
+       SkASSERT(SkToU16(len) == len);  // can't handle larger than 64K
+
+       fRec = AllocRec(nil, (U16CPU)len);
+#ifdef SK_DEBUG
+       fStr = fRec->data();
+#endif
+}
+
+SkString::SkString(const char text[])
+{
+       size_t  len = text ? strlen(text) : 0;
+
+       fRec = AllocRec(text, (U16CPU)len);
+#ifdef SK_DEBUG
+       fStr = fRec->data();
+#endif
+}
+
+SkString::SkString(const char text[], size_t len)
+{
+       fRec = AllocRec(text, (U16CPU)len);
+#ifdef SK_DEBUG
+       fStr = fRec->data();
+#endif
+}
+
+SkString::SkString(const SkString& src)
+{
+       src.validate();
+
+       fRec = RefRec(src.fRec);
+#ifdef SK_DEBUG
+       fStr = fRec->data();
+#endif
+}
+
+SkString::~SkString()
+{
+       this->validate();
+
+       if (fRec->fLength)
+       {
+               SkASSERT(fRec->fRefCnt > 0);
+               if (--fRec->fRefCnt == 0)
+                       sk_free(fRec);
+       }
+}
+
+bool SkString::equals(const SkString& src) const
+{
+       return fRec == src.fRec || this->equals(src.c_str(), src.size());
+}
+
+bool SkString::equals(const char text[]) const
+{
+       return this->equals(text, text ? strlen(text) : 0);
+}
+
+bool SkString::equals(const char text[], size_t len) const
+{
+       SkASSERT(len == 0 || text != nil);
+
+       return fRec->fLength == len && !memcmp(fRec->data(), text, len);
+}
+
+SkString& SkString::operator=(const SkString& src)
+{
+       this->validate();
+
+       if (fRec != src.fRec)
+       {
+               SkString        tmp(src);
+               this->swap(tmp);
+       }
+       return *this;
+}
+
+void SkString::reset()
+{
+       this->validate();
+
+       if (fRec->fLength)
+       {
+               SkASSERT(fRec->fRefCnt > 0);
+               if (--fRec->fRefCnt == 0)
+                       sk_free(fRec);
+       }
+
+       fRec = (Rec*)gEmptyRec;
+#ifdef SK_DEBUG
+       fStr = fRec->data();
+#endif
+}
+
+char* SkString::writable_str()
+{
+       this->validate();
+
+       if (fRec->fLength)
+       {
+               if (fRec->fRefCnt > 1)
+               {
+                       fRec->fRefCnt -= 1;
+                       fRec = AllocRec(fRec->data(), fRec->fLength);
+               #ifdef SK_DEBUG
+                       fStr = fRec->data();
+               #endif
+               }
+       }
+       return fRec->data();
+}
+
+void SkString::set(const char text[])
+{
+       this->set(text, text ? strlen(text) : 0);
+}
+
+void SkString::set(const char text[], size_t len)
+{
+       if (len == 0)
+               this->reset();
+       else if (fRec->fRefCnt == 1 && len <= fRec->fLength)    // should we resize if len <<<< fLength, to save RAM? (e.g. len < (fLength>>1))
+       {
+               // just use less of the buffer without allocating a smaller one
+               char* p = this->writable_str();
+               if (text)
+                       memcpy(p, text, len);
+               p[len] = 0;
+               fRec->fLength = SkToU16(len);
+       }
+       else if (fRec->fRefCnt == 1 && ((unsigned)fRec->fLength >> 2) == (len >> 2))
+       {
+               // we have spare room in the current allocation, so don't alloc a larger one
+               char* p = this->writable_str();
+               if (text)
+                       memcpy(p, text, len);
+               p[len] = 0;
+               fRec->fLength = SkToU16(len);
+       }
+       else
+       {
+               SkString tmp(text, len);
+               this->swap(tmp);
+       }
+}
+
+void SkString::setUTF16(const U16 src[])
+{
+       int     count = 0;
+
+       while (src[count])
+               count += 1;
+
+       if (count == 0)
+               this->reset();
+       else if (count <= fRec->fLength)        // should we resize if len <<<< fLength, to save RAM? (e.g. len < (fLength>>1))
+       {
+               if (count < fRec->fLength)
+                       this->resize(count);
+               char* p = this->writable_str();
+               for (int i = 0; i < count; i++)
+                       p[i] = SkToU8(src[i]);
+               p[count] = 0;
+       }
+       else
+       {
+               SkString        tmp(count);
+               char*           p = tmp.writable_str();
+
+               for (int i = 0; i < count; i++)
+                       p[i] = SkToU8(src[i]);
+
+               this->swap(tmp);
+       }
+}
+
+void SkString::insert(size_t offset, const char text[])
+{
+       this->insert(offset, text, text ? strlen(text) : 0);
+}
+
+void SkString::insert(size_t offset, const char text[], size_t len)
+{
+       if (len)
+       {
+               size_t length = fRec->fLength;
+               if (offset > length)
+                       offset = length;
+
+               /*      If we're the only owner, and we have room in our allocation for the insert,
+                       do it in place, rather than allocating a new buffer.
+
+                       To know we have room, compare the allocated sizes
+                       beforeAlloc = SkAlign4(length + 1)
+                       afterAlloc  = SkAligh4(length + 1 + len)
+                       but SkAlign4(x) is (x + 3) >> 2 << 2
+                       which is equivalent for testing to (length + 1 + 3) >> 2 == (length + 1 + 3 + len) >> 2
+                       and we can then eliminate the +1+3 since that doesn't affec the answer
+               */
+               if (fRec->fRefCnt == 1 && (length >> 2) == ((length + len) >> 2))
+               {
+                       char* dst = this->writable_str();
+
+                       if (offset < length)
+                               memmove(dst + offset + len, dst + offset, length - offset);
+                       memcpy(dst + offset, text, len);
+
+                       dst[length + len] = 0;
+                       fRec->fLength = SkToU16(length + len);
+               }
+               else
+               {
+                       /*      Seems we should use realloc here, since that is safe if it fails
+                               (we have the original data), and might be faster than alloc/copy/free.
+                       */
+                       SkString        tmp(fRec->fLength + len);
+                       char*           dst = tmp.writable_str();
+
+                       if (offset > 0)
+                               memcpy(dst, fRec->data(), offset);
+                       memcpy(dst + offset, text, len);
+                       if (offset < fRec->fLength)
+                               memcpy(dst + offset + len, fRec->data() + offset, fRec->fLength - offset);
+
+                       this->swap(tmp);
+               }
+       }
+}
+
+void SkString::insertUnichar(size_t offset, SkUnichar uni)
+{
+       char    buffer[kMaxBytesInUTF8Sequence];
+       size_t  len = SkUTF8_FromUnichar(uni, buffer);
+
+       if (len)
+               this->insert(offset, buffer, len);
+}
+
+void SkString::insertS32(size_t offset, S32 dec)
+{
+       char    buffer[SkStrAppendS32_MaxSize];
+    char*   stop = SkStrAppendS32(buffer, dec);
+    this->insert(offset, buffer, stop - buffer);
+}
+
+void SkString::insertHex(size_t offset, U32 hex, int minDigits)
+{
+       minDigits = SkPin32(minDigits, 0, 8);
+       
+       static const char gHex[] = "0123456789ABCDEF";
+
+       char    buffer[8];
+       char*   p = buffer + sizeof(buffer);
+
+       do {
+               *--p = gHex[hex & 0xF];
+               hex >>= 4;
+               minDigits -= 1;
+       } while (hex != 0);
+       while (--minDigits >= 0)
+               *--p = '0';
+
+       SkASSERT(p >= buffer);
+       this->insert(offset, p, buffer + sizeof(buffer) - p);
+}
+
+void SkString::insertScalar(size_t offset, SkScalar value)
+{
+       char    buffer[SkStrAppendScalar_MaxSize];
+    char*   stop = SkStrAppendScalar(buffer, value);
+    this->insert(offset, buffer, stop - buffer);
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+//#include <stdarg.h>
+#if defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
+       #include <stdio.h>
+#endif
+
+void SkString::printf(const char format[], ...)
+{
+       static const size_t kBufferSize = 100;
+
+       char    buffer[kBufferSize + 1];
+
+#ifdef SK_BUILD_FOR_WIN
+       va_list args;
+       va_start(args, format);
+       _vsnprintf(buffer, kBufferSize, format, args);
+       va_end(args);
+#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
+       va_list args;
+       va_start(args, format);
+       vsnprintf(buffer, kBufferSize, format, args);
+       va_end(args);
+#else
+       buffer[0] = 0;
+#endif
+
+       this->set(buffer, strlen(buffer));
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+void SkString::remove(size_t offset, size_t length)
+{
+       size_t size = this->size();
+
+       if (offset < size)
+       {
+               if (offset + length > size)
+                       length = size - offset;
+               if (length > 0)
+               {
+                       SkASSERT(size > length);
+                       SkString        tmp(size - length);
+                       char*           dst = tmp.writable_str();
+                       const char*     src = this->c_str();
+
+                       if (offset)
+                       {
+                               SkASSERT(offset <= tmp.size());
+                               memcpy(dst, src, offset);
+                       }
+                       size_t tail = size - offset - length;
+                       SkASSERT((S32)tail >= 0);
+                       if (tail)
+                       {
+               //              SkASSERT(offset + length <= tmp.size());
+                               memcpy(dst + offset, src + offset + length, tail);
+                       }
+                       SkASSERT(dst[tmp.size()] == 0);
+                       this->swap(tmp);
+               }
+       }
+}
+
+void SkString::swap(SkString& other)
+{
+       this->validate();
+       other.validate();
+
+       SkTSwap<Rec*>(fRec, other.fRec);
+#ifdef SK_DEBUG
+       SkTSwap<const char*>(fStr, other.fStr);
+#endif
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+SkAutoUCS2::SkAutoUCS2(const char utf8[])
+{
+       size_t len = strlen(utf8);
+       fUCS2 = (U16*)sk_malloc_throw((len + 1) * sizeof(U16));
+
+       U16* dst = fUCS2;
+       for (;;)
+       {
+               SkUnichar       uni = SkUTF8_NextUnichar(&utf8);
+               *dst++ = SkToU16(uni);
+               if (uni == 0)
+                       break;
+       }
+       fCount = (int)(dst - fUCS2);
+}
+
+SkAutoUCS2::~SkAutoUCS2()
+{
+       delete[] fUCS2;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+void SkString::UnitTest()
+{
+#ifdef SK_SUPPORT_UNITTEST
+       SkString        a;
+       SkString        b((size_t)0);
+       SkString        c("");
+       SkString        d(nil, 0);
+
+       SkASSERT(a.isEmpty());
+       SkASSERT(a == b && a == c && a == d);
+
+       a.set("hello");
+       b.set("hellox", 5);
+       c.set(a);
+       d.resize(5);
+       memcpy(d.writable_str(), "helloz", 5);
+
+       SkASSERT(!a.isEmpty());
+       SkASSERT(a.size() == 5);
+       SkASSERT(a == b && a == c && a == d);
+       SkASSERT(a.equals("hello", 5));
+       SkASSERT(a.equals("hello"));
+       SkASSERT(!a.equals("help"));
+
+       SkString        e(a);
+       SkString        f("hello");
+       SkString        g("helloz", 5);
+
+       SkASSERT(a == e && a == f && a == g);
+
+       b.set("world");
+       c = b;
+       SkASSERT(a != b && a != c && b == c);
+
+       a.append(" world");
+       e.append("worldz", 5);
+       e.insert(5, " ");
+       f.set("world");
+       f.prepend("hello ");
+       SkASSERT(a.equals("hello world") && a == e && a == f);
+
+       a.reset();
+       b.resize(0);
+       SkASSERT(a.isEmpty() && b.isEmpty() && a == b);
+
+       a.set("a");
+       a.set("ab");
+       a.set("abc");
+       a.set("abcd");
+#endif
+}
+
+#endif
+
diff --git a/libs/graphics/sgl/SkStroke.cpp b/libs/graphics/sgl/SkStroke.cpp
new file mode 100644 (file)
index 0000000..f0c6654
--- /dev/null
@@ -0,0 +1,586 @@
+#include "SkStrokerPriv.h"
+#include "SkGeometry.h"
+#include "SkPath.h"
+
+#define kMaxQuadSubdivide      5
+#define kMaxCubicSubdivide     4
+
+static inline bool degenerate_vector(const SkVector& v)
+{
+       return SkScalarNearlyZero(v.fX) && SkScalarNearlyZero(v.fY);
+}
+
+static inline bool degenerate_line(const SkPoint& a, const SkPoint& b, SkScalar tolerance = SK_ScalarNearlyZero)
+{
+       return SkScalarNearlyZero(a.fX - b.fX, tolerance) && SkScalarNearlyZero(a.fY - b.fY, tolerance);
+}
+
+static inline bool normals_too_curvy(const SkVector& norm0, SkVector& norm1)
+{
+       /*      root2/2 is a 45-degree angle
+               make this constant bigger for more subdivisions (but not >= 1)
+       */
+       static const SkScalar kFlatEnoughNormalDotProd = SK_ScalarSqrt2/2 + SK_Scalar1/10;
+
+       SkASSERT(kFlatEnoughNormalDotProd > 0 && kFlatEnoughNormalDotProd < SK_Scalar1);
+
+       return SkPoint::DotProduct(norm0, norm1) <= kFlatEnoughNormalDotProd;
+}
+
+static inline bool normals_too_pinchy(const SkVector& norm0, SkVector& norm1)
+{
+       static const SkScalar kTooPinchyNormalDotProd = -SK_Scalar1 * 999 / 1000;
+
+       return SkPoint::DotProduct(norm0, norm1) <= kTooPinchyNormalDotProd;
+}
+
+static bool set_normal_unitnormal(const SkPoint& before, const SkPoint& after,
+                                                                 SkScalar radius,
+                                                                 SkVector* normal, SkVector* unitNormal)
+{
+       if (!unitNormal->setUnit(after.fX - before.fX, after.fY - before.fY))
+               return false;
+
+       unitNormal->rotateCCW();
+       unitNormal->scale(radius, normal);
+       return true;
+}
+
+static bool set_normal_unitnormal(const SkVector& vec,
+                                                                 SkScalar radius,
+                                                                 SkVector* normal, SkVector* unitNormal)
+{
+       if (!unitNormal->setUnit(vec.fX, vec.fY))
+               return false;
+
+       unitNormal->rotateCCW();
+       unitNormal->scale(radius, normal);
+       return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+class SkPathStroker {
+public:
+       SkPathStroker(SkScalar radius, SkScalar miterLimit, SkPaint::Cap cap, SkPaint::Join join);
+
+       void    moveTo(const SkPoint&);
+       void    lineTo(const SkPoint&);
+       void    quadTo(const SkPoint&, const SkPoint&);
+       void    cubicTo(const SkPoint&, const SkPoint&, const SkPoint&);
+       void    close(bool isLine) { this->finishContour(true, isLine); }
+
+       void    done(SkPath* dst, bool isLine)
+       {
+               this->finishContour(false, isLine);
+               fOuter.addPath(fExtra);
+               dst->swap(fOuter);
+       }
+
+private:
+       SkScalar        fRadius;
+       SkScalar        fInvMiterLimit;
+
+       SkVector        fFirstNormal, fPrevNormal, fFirstUnitNormal, fPrevUnitNormal;
+       SkPoint         fFirstPt, fPrevPt;      // on original path
+       SkPoint         fFirstOuterPt;
+       int                     fSegmentCount;
+       bool            fPrevIsLine;
+
+       SkStrokerPriv::CapProc  fCapper;
+       SkStrokerPriv::JoinProc fJoiner;
+
+       SkPath  fInner, fOuter; // outer is our working answer, inner is temp
+       SkPath  fExtra;                 // added as extra complete contours
+
+       void    finishContour(bool close, bool isLine);
+       void    preJoinTo(const SkPoint&, SkVector* normal, SkVector* unitNormal, bool isLine);
+       void    postJoinTo(const SkPoint&, const SkVector& normal, const SkVector& unitNormal);
+
+       void    line_to(const SkPoint& currPt, const SkVector& normal);
+       void    quad_to(const SkPoint pts[3],
+                                       const SkVector& normalAB, const SkVector& unitNormalAB,
+                                       SkVector* normalBC, SkVector* unitNormalBC,
+                                       int subDivide);
+       void    cubic_to(const SkPoint pts[4],
+                                       const SkVector& normalAB, const SkVector& unitNormalAB,
+                                       SkVector* normalCD, SkVector* unitNormalCD,
+                                       int subDivide);
+};
+
+////////////////////////////////////////////////////////////////////////////
+
+void SkPathStroker::preJoinTo(const SkPoint& currPt, SkVector* normal, SkVector* unitNormal, bool currIsLine)
+{
+       SkASSERT(fSegmentCount >= 0);
+
+       SkScalar        prevX = fPrevPt.fX;
+       SkScalar        prevY = fPrevPt.fY;
+
+       SkAssertResult(set_normal_unitnormal(fPrevPt, currPt, fRadius, normal, unitNormal));
+
+       if (fSegmentCount == 0)
+       {
+               fFirstNormal = *normal;
+               fFirstUnitNormal = *unitNormal;
+               fFirstOuterPt.set(prevX + normal->fX, prevY + normal->fY);
+
+               fOuter.moveTo(fFirstOuterPt.fX, fFirstOuterPt.fY);
+               fInner.moveTo(prevX - normal->fX, prevY - normal->fY);
+       }
+       else    // we have a previous segment
+       {
+               fJoiner(&fOuter, &fInner, fPrevUnitNormal, fPrevPt, *unitNormal, fRadius, fInvMiterLimit,
+                               fPrevIsLine, currIsLine);
+       }
+       fPrevIsLine = currIsLine;
+}
+
+void SkPathStroker::postJoinTo(const SkPoint& currPt, const SkVector& normal, const SkVector& unitNormal)
+{
+       fPrevPt = currPt;
+       fPrevUnitNormal = unitNormal;
+       fPrevNormal = normal;
+       fSegmentCount += 1;
+}
+
+void SkPathStroker::finishContour(bool close, bool currIsLine)
+{
+       if (fSegmentCount > 0)
+       {
+               SkPoint pt;
+
+               if (close)
+               {
+                       fJoiner(&fOuter, &fInner, fPrevUnitNormal, fPrevPt, fFirstUnitNormal,
+                                       fRadius, fInvMiterLimit, fPrevIsLine, currIsLine);
+                       fOuter.close();
+                       // now add fInner as its own contour
+                       fInner.getLastPt(&pt);
+                       fOuter.moveTo(pt.fX, pt.fY);
+                       fOuter.reversePathTo(fInner);
+                       fOuter.close();
+               }
+               else    // add caps to start and end
+               {
+                       // cap the end
+                       fInner.getLastPt(&pt);
+                       fCapper(&fOuter, fPrevPt, fPrevNormal, pt, currIsLine ? &fInner : nil);
+                       fOuter.reversePathTo(fInner);
+                       // cap the start
+                       fCapper(&fOuter, fFirstPt, -fFirstNormal, fFirstOuterPt, fPrevIsLine ? &fInner : nil);
+                       fOuter.close();
+               }
+       }
+       fInner.reset();
+       fSegmentCount = -1;
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+SkPathStroker::SkPathStroker(SkScalar radius, SkScalar miterLimit, SkPaint::Cap cap, SkPaint::Join join)
+       : fRadius(radius)
+{
+       if (join == SkPaint::kMiter_Join)
+       {
+               if (miterLimit <= SK_Scalar1)
+                       join = SkPaint::kBevel_Join;
+               else
+                       fInvMiterLimit = SkScalarInvert(miterLimit);
+       }
+       fCapper = SkStrokerPriv::CapFactory(cap);
+       fJoiner = SkStrokerPriv::JoinFactory(join);
+       fSegmentCount = -1;
+       fPrevIsLine = false;
+}
+
+void SkPathStroker::moveTo(const SkPoint& pt)
+{
+       if (fSegmentCount > 0)
+               this->finishContour(false, false);
+
+       fSegmentCount = 0;
+       fFirstPt = fPrevPt = pt;
+}
+
+void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal)
+{
+       fOuter.lineTo(currPt.fX + normal.fX, currPt.fY + normal.fY);
+       fInner.lineTo(currPt.fX - normal.fX, currPt.fY - normal.fY);
+}
+
+void SkPathStroker::lineTo(const SkPoint& currPt)
+{
+       if (degenerate_line(fPrevPt, currPt))
+               return;
+
+       SkVector        normal, unitNormal;
+
+       this->preJoinTo(currPt, &normal, &unitNormal, true);
+       this->line_to(currPt, normal);
+       this->postJoinTo(currPt, normal, unitNormal);
+}
+
+void SkPathStroker::quad_to(const SkPoint pts[3],
+                                         const SkVector& normalAB, const SkVector& unitNormalAB,
+                                         SkVector* normalBC, SkVector* unitNormalBC,
+                                         int subDivide)
+{
+       if (!set_normal_unitnormal(pts[1], pts[2], fRadius, normalBC, unitNormalBC))
+       {
+               // pts[1] nearly equals pts[2], so just draw a line to pts[2]
+               this->line_to(pts[2], normalAB);
+               *normalBC = normalAB;
+               *unitNormalBC = unitNormalAB;
+               return;
+       }
+
+       if (--subDivide >= 0 && normals_too_curvy(unitNormalAB, *unitNormalBC))
+       {
+               SkPoint         tmp[5];
+               SkVector        norm, unit;
+
+               SkChopQuadAtHalf(pts, tmp);
+               this->quad_to(&tmp[0], normalAB, unitNormalAB, &norm, &unit, subDivide);
+               this->quad_to(&tmp[2], norm, unit, normalBC, unitNormalBC, subDivide);
+       }
+       else
+       {
+               SkVector        normalB, unitB;
+               SkAssertResult(set_normal_unitnormal(pts[0], pts[2], fRadius, &normalB, &unitB));
+
+               fOuter.quadTo(  pts[1].fX + normalB.fX, pts[1].fY + normalB.fY,
+                                               pts[2].fX + normalBC->fX, pts[2].fY + normalBC->fY);
+               fInner.quadTo(  pts[1].fX - normalB.fX, pts[1].fY - normalB.fY,
+                                               pts[2].fX - normalBC->fX, pts[2].fY - normalBC->fY);
+       }
+}
+
+void SkPathStroker::cubic_to(const SkPoint pts[4],
+                                         const SkVector& normalAB, const SkVector& unitNormalAB,
+                                         SkVector* normalCD, SkVector* unitNormalCD,
+                                         int subDivide)
+{
+       SkVector        ab = pts[1] - pts[0];
+       SkVector        cd = pts[3] - pts[2];
+       SkVector        normalBC, unitNormalBC;
+
+       bool    degenerateAB = degenerate_vector(ab);
+       bool    degenerateCD = degenerate_vector(cd);
+
+       if (degenerateAB && degenerateCD)
+       {
+DRAW_LINE:
+               this->line_to(pts[3], normalAB);
+               *normalCD = normalAB;
+               *unitNormalCD = unitNormalAB;
+               return;
+       }
+
+       if (degenerateAB)
+       {
+               ab = pts[2] - pts[0];
+               degenerateAB = degenerate_vector(ab);
+       }
+       if (degenerateCD)
+       {
+               cd = pts[3] - pts[1];
+               degenerateCD = degenerate_vector(cd);
+       }
+       if (degenerateAB || degenerateCD)
+               goto DRAW_LINE;
+
+       SkAssertResult(set_normal_unitnormal(cd, fRadius, normalCD, unitNormalCD));
+       bool degenerateBC = !set_normal_unitnormal(pts[1], pts[2], fRadius, &normalBC, &unitNormalBC);
+
+       if (--subDivide >= 0 &&
+               (degenerateBC || normals_too_curvy(unitNormalAB, unitNormalBC) || normals_too_curvy(unitNormalBC, *unitNormalCD)))
+       {
+               SkPoint         tmp[7];
+               SkVector        norm, unit, dummy, unitDummy;
+
+               SkChopCubicAtHalf(pts, tmp);
+               this->cubic_to(&tmp[0], normalAB, unitNormalAB, &norm, &unit, subDivide);
+               // we use dummys since we already have a valid (and more accurate) normals for CD
+               this->cubic_to(&tmp[3], norm, unit, &dummy, &unitDummy, subDivide);
+       }
+       else
+       {
+               SkVector        normalB, normalC;
+               
+               // need normals to inset/outset the off-curve pts B and C
+
+               if (0)// this is normal to the line between our adjacent pts
+               {
+                       normalB = pts[2] - pts[0];
+                       normalB.rotateCCW();
+                       SkAssertResult(normalB.setLength(fRadius));
+
+                       normalC = pts[3] - pts[1];
+                       normalC.rotateCCW();
+                       SkAssertResult(normalC.setLength(fRadius));
+               }
+               else    // miter-join
+               {
+                       SkVector        unitBC = pts[2] - pts[1];
+                       unitBC.normalize();
+                       unitBC.rotateCCW();
+
+                       normalB = unitNormalAB + unitBC;
+                       normalC = *unitNormalCD + unitBC;
+
+                       SkScalar dot = SkPoint::DotProduct(unitNormalAB, unitBC);
+                       SkAssertResult(normalB.setLength(SkScalarDiv(fRadius, SkScalarSqrt((SK_Scalar1 + dot)/2))));
+                       dot = SkPoint::DotProduct(*unitNormalCD, unitBC);
+                       SkAssertResult(normalC.setLength(SkScalarDiv(fRadius, SkScalarSqrt((SK_Scalar1 + dot)/2))));
+               }
+
+               fOuter.cubicTo( pts[1].fX + normalB.fX, pts[1].fY + normalB.fY,
+                                               pts[2].fX + normalC.fX, pts[2].fY + normalC.fY,
+                                               pts[3].fX + normalCD->fX, pts[3].fY + normalCD->fY);
+
+               fInner.cubicTo( pts[1].fX - normalB.fX, pts[1].fY - normalB.fY,
+                                               pts[2].fX - normalC.fX, pts[2].fY - normalC.fY,
+                                               pts[3].fX - normalCD->fX, pts[3].fY - normalCD->fY);
+       }
+}
+
+void SkPathStroker::quadTo(const SkPoint& pt1, const SkPoint& pt2)
+{
+       bool    degenerateAB = degenerate_line(fPrevPt, pt1);
+       bool    degenerateBC = degenerate_line(pt1, pt2);
+
+       if (degenerateAB | degenerateBC)
+       {
+               if (degenerateAB ^ degenerateBC)
+                       this->lineTo(pt2);
+               return;
+       }
+
+       SkVector        normalAB, unitAB, normalBC, unitBC;
+
+       this->preJoinTo(pt1, &normalAB, &unitAB, false);
+
+       {
+               SkPoint pts[3], tmp[5];
+               pts[0] = fPrevPt;
+               pts[1] = pt1;
+               pts[2] = pt2;
+
+               if (SkChopQuadAtMaxCurvature(pts, tmp) == 2)
+               {
+                       unitBC.setUnit(pts[2].fX - pts[1].fX, pts[2].fY - pts[1].fY);
+                       unitBC.rotateCCW();
+                       if (normals_too_pinchy(unitAB, unitBC))
+                       {
+                               normalBC = unitBC;
+                               normalBC.scale(fRadius);
+
+                               fOuter.lineTo(tmp[2].fX + normalAB.fX, tmp[2].fY + normalAB.fY);
+                               fOuter.lineTo(tmp[2].fX + normalBC.fX, tmp[2].fY + normalBC.fY);
+                               fOuter.lineTo(tmp[4].fX + normalBC.fX, tmp[4].fY + normalBC.fY);
+
+                               fInner.lineTo(tmp[2].fX - normalAB.fX, tmp[2].fY - normalAB.fY);
+                               fInner.lineTo(tmp[2].fX - normalBC.fX, tmp[2].fY - normalBC.fY);
+                               fInner.lineTo(tmp[4].fX - normalBC.fX, tmp[4].fY - normalBC.fY);
+
+                               fExtra.addCircle(tmp[2].fX, tmp[2].fY, fRadius, SkPath::kCW_Direction);
+                       }
+                       else
+                       {
+                               this->quad_to(&tmp[0], normalAB, unitAB, &normalBC, &unitBC, kMaxQuadSubdivide);
+                               SkVector n = normalBC;
+                               SkVector u = unitBC;
+                               this->quad_to(&tmp[2], n, u, &normalBC, &unitBC, kMaxQuadSubdivide);
+                       }
+               }
+               else
+                       this->quad_to(pts, normalAB, unitAB, &normalBC, &unitBC, kMaxQuadSubdivide);
+       }
+
+       this->postJoinTo(pt2, normalBC, unitBC);
+}
+
+void SkPathStroker::cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3)
+{
+       bool    degenerateAB = degenerate_line(fPrevPt, pt1);
+       bool    degenerateBC = degenerate_line(pt1, pt2);
+       bool    degenerateCD = degenerate_line(pt2, pt3);
+
+       if (degenerateAB + degenerateBC + degenerateCD >= 2)
+       {
+               this->lineTo(pt3);
+               return;
+       }
+
+       SkVector        normalAB, unitAB, normalCD, unitCD;
+
+       // find the first tangent (which might be pt1 or pt2
+       {
+               const SkPoint*  nextPt = &pt1;
+               if (degenerateAB)
+                       nextPt = &pt2;
+               this->preJoinTo(*nextPt, &normalAB, &unitAB, false);
+       }
+
+       {
+               SkPoint pts[4], tmp[13];
+               int                     i, count;
+               SkVector        n, u;
+               SkScalar        tValues[3];
+
+               pts[0] = fPrevPt;
+               pts[1] = pt1;
+               pts[2] = pt2;
+               pts[3] = pt3;
+
+#if 1
+               count = SkChopCubicAtMaxCurvature(pts, tmp, tValues);
+#else
+               count = 1;
+               memcpy(tmp, pts, 4 * sizeof(SkPoint));
+#endif
+               n = normalAB;
+               u = unitAB;
+               for (i = 0; i < count; i++)
+               {
+                       this->cubic_to(&tmp[i * 3], n, u, &normalCD, &unitCD, kMaxCubicSubdivide);
+                       if (i == count - 1)
+                               break;
+                       n = normalCD;
+                       u = unitCD;
+
+               }
+
+               // check for too pinchy
+               for (i = 1; i < count; i++)
+               {
+                       SkPoint p;
+                       SkVector        v, c;
+
+                       SkEvalCubicAt(pts, tValues[i - 1], &p, &v, &c);
+
+                       SkScalar        dot = SkPoint::DotProduct(c, c);
+                       v.scale(SkScalarInvert(dot));
+
+                       if (SkScalarNearlyZero(v.fX) && SkScalarNearlyZero(v.fY))
+                       {
+                               fExtra.addCircle(p.fX, p.fY, fRadius, SkPath::kCW_Direction);
+                       }
+               }
+
+       }
+
+       this->postJoinTo(pt3, normalCD, unitCD);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////
+
+#include "SkPaint.h"
+
+SkStroke::SkStroke()
+{
+       fWidth          = SK_DefaultStrokeWidth;
+       fMiterLimit     = SK_DefaultMiterLimit;
+       fCap            = SkPaint::kDefault_Cap;
+       fJoin           = SkPaint::kDefault_Join;
+       fDoFill         = false;
+}
+
+SkStroke::SkStroke(const SkPaint& p)
+{
+       fWidth          = p.getStrokeWidth();
+       fMiterLimit     = p.getStrokeMiter();
+       fCap            = (U8)p.getStrokeCap();
+       fJoin           = (U8)p.getStrokeJoin();
+       fDoFill         = SkToU8(p.getStyle() == SkPaint::kStrokeAndFill_Style);
+}
+
+SkStroke::SkStroke(const SkPaint& p, SkScalar width)
+{
+       fWidth          = width;
+       fMiterLimit     = p.getStrokeMiter();
+       fCap            = (U8)p.getStrokeCap();
+       fJoin           = (U8)p.getStrokeJoin();
+       fDoFill         = SkToU8(p.getStyle() == SkPaint::kStrokeAndFill_Style);
+}
+
+void SkStroke::setWidth(SkScalar width)
+{
+       SkASSERT(width >= 0);
+       fWidth = width;
+}
+
+void SkStroke::setMiterLimit(SkScalar miterLimit)
+{
+       SkASSERT(miterLimit >= 0);
+       fMiterLimit = miterLimit;
+}
+
+void SkStroke::setCap(SkPaint::Cap cap)
+{
+       SkASSERT((unsigned)cap < SkPaint::kCapCount);
+       fCap = SkToU8(cap);
+}
+
+void SkStroke::setJoin(SkPaint::Join join)
+{
+       SkASSERT((unsigned)join < SkPaint::kJoinCount);
+       fJoin = SkToU8(join);
+}
+
+void SkStroke::strokePath(const SkPath& src, SkPath* dst) const
+{
+       SkASSERT(&src != nil && dst != nil);
+
+       dst->reset();
+       if (SkScalarHalf(fWidth) <= 0)
+               return;
+
+       SkPathStroker   stroker(SkScalarHalf(fWidth), fMiterLimit, this->getCap(), this->getJoin());
+
+       SkPath::Iter    iter(src, false);
+       SkPoint                 pts[4];
+       SkPath::Verb    verb, lastSegment = SkPath::kMove_Verb;
+
+       while ((verb = iter.next(pts)) != SkPath::kDone_Verb)
+       {
+               switch (verb) {
+               case SkPath::kMove_Verb:
+                       stroker.moveTo(pts[0]);
+                       break;
+               case SkPath::kLine_Verb:
+                       stroker.lineTo(pts[1]);
+                       lastSegment = verb;
+                       break;
+               case SkPath::kQuad_Verb:
+                       stroker.quadTo(pts[1], pts[2]);
+                       lastSegment = verb;
+                       break;
+               case SkPath::kCubic_Verb:
+                       stroker.cubicTo(pts[1], pts[2], pts[3]);
+                       lastSegment = verb;
+                       break;
+               case SkPath::kClose_Verb:
+                       stroker.close(lastSegment == SkPath::kLine_Verb);
+                       break;
+               default:
+                       break;
+               }
+       }
+       stroker.done(dst, lastSegment == SkPath::kLine_Verb);
+
+       if (fDoFill)
+               dst->addPath(src);
+}
+
+void SkStroke::strokeLine(const SkPoint& p0, const SkPoint& p1, SkPath* dst) const
+{
+       SkPath  tmp;
+
+       tmp.moveTo(p0);
+       tmp.lineTo(p1);
+       this->strokePath(tmp, dst);
+}
+
diff --git a/libs/graphics/sgl/SkStrokerPriv.cpp b/libs/graphics/sgl/SkStrokerPriv.cpp
new file mode 100644 (file)
index 0000000..4daf932
--- /dev/null
@@ -0,0 +1,216 @@
+#include "SkStrokerPriv.h"
+#include "SkGeometry.h"
+#include "SkPath.h"
+
+static void ButtCapper(SkPath* path, const SkPoint& pivot,
+                                          const SkVector& normal, const SkPoint& stop,
+                                          SkPath*)
+{
+       path->lineTo(stop.fX, stop.fY);
+}
+
+static void RoundCapper(SkPath* path, const SkPoint& pivot,
+                                               const SkVector& normal, const SkPoint& stop,
+                                               SkPath*)
+{
+       SkScalar        px = pivot.fX;
+       SkScalar        py = pivot.fY;
+       SkScalar        nx = normal.fX;
+       SkScalar        ny = normal.fY;
+       SkScalar        sx = SkScalarMul(nx, CUBIC_ARC_FACTOR);
+       SkScalar        sy = SkScalarMul(ny, CUBIC_ARC_FACTOR);
+
+       path->cubicTo(px + nx + CWX(sx, sy), py + ny + CWY(sx, sy),
+                                 px + CWX(nx, ny) + sx, py + CWY(nx, ny) + sy,
+                                 px + CWX(nx, ny), py + CWY(nx, ny));
+       path->cubicTo(px + CWX(nx, ny) - sx, py + CWY(nx, ny) - sy,
+                                 px - nx + CWX(sx, sy), py - ny + CWY(sx, sy),
+                                 stop.fX, stop.fY);
+}
+
+static void SquareCapper(SkPath* path, const SkPoint& pivot,
+                                                const SkVector& normal, const SkPoint& stop,
+                                                SkPath* otherPath)
+{
+       SkVector parallel;
+       normal.rotateCW(&parallel);
+
+       if (otherPath)
+       {
+               path->setLastPt(pivot.fX + normal.fX + parallel.fX, pivot.fY + normal.fY + parallel.fY);
+               path->lineTo(pivot.fX - normal.fX + parallel.fX, pivot.fY - normal.fY + parallel.fY);
+       }
+       else
+       {
+               path->lineTo(pivot.fX + normal.fX + parallel.fX, pivot.fY + normal.fY + parallel.fY);
+               path->lineTo(pivot.fX - normal.fX + parallel.fX, pivot.fY - normal.fY + parallel.fY);
+               path->lineTo(stop.fX, stop.fY);
+       }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static bool is_clockwise(const SkVector& before, const SkVector& after)
+{
+       return SkScalarMul(before.fX, after.fY) - SkScalarMul(before.fY, after.fX) > 0;
+}
+
+enum AngleType {
+       kNearly180_AngleType,
+       kSharp_AngleType,
+       kShallow_AngleType,
+       kNearlyLine_AngleType
+};
+
+static AngleType Dot2AngleType(SkScalar dot)
+{
+// need more precise fixed normalization
+//     SkASSERT(SkScalarAbs(dot) <= SK_Scalar1 + SK_ScalarNearlyZero);
+
+       if (dot >= 0)   // shallow or line
+               return SkScalarNearlyZero(SK_Scalar1 - dot) ? kNearlyLine_AngleType : kShallow_AngleType;
+       else                    // sharp or 180
+               return SkScalarNearlyZero(SK_Scalar1 + dot) ? kNearly180_AngleType : kSharp_AngleType;
+}
+
+static void BluntJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal,
+                                               const SkPoint& pivot, const SkVector& afterUnitNormal,
+                                               SkScalar radius, SkScalar invMiterLimit, bool, bool)
+{
+       SkVector        after;
+       afterUnitNormal.scale(radius, &after);
+
+       outer->lineTo(pivot.fX + after.fX, pivot.fY + after.fY);
+       inner->lineTo(pivot.fX - after.fX, pivot.fY - after.fY);
+}
+
+static void RoundJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal,
+                                               const SkPoint& pivot, const SkVector& afterUnitNormal,
+                                               SkScalar radius, SkScalar invMiterLimit, bool, bool)
+{
+       SkScalar        dotProd = SkPoint::DotProduct(beforeUnitNormal, afterUnitNormal);
+       AngleType       angleType = Dot2AngleType(dotProd);
+
+       if (angleType == kNearlyLine_AngleType)
+               return;
+
+       SkVector                        before = beforeUnitNormal;
+       SkVector                        after = afterUnitNormal;
+       SkRotationDirection     dir = kCW_SkRotationDirection;
+
+       if (!is_clockwise(before, after))
+       {
+               SkTSwap<SkPath*>(outer, inner);
+               before.negate();
+               after.negate();
+               dir = kCCW_SkRotationDirection;
+       }
+
+       SkPoint         pts[kSkBuildQuadArcStorage];
+       SkMatrix        matrix;
+       matrix.setScale(radius, radius, 0, 0);
+       matrix.postTranslate(pivot.fX, pivot.fY);
+       int count = SkBuildQuadArc(before, after, dir, &matrix, pts);
+
+       if (count > 0)
+       {
+               for (int i = 1; i < count; i += 2)
+                       outer->quadTo(pts[i].fX, pts[i].fY, pts[i+1].fX, pts[i+1].fY);
+
+               after.scale(radius);
+               inner->lineTo(pivot.fX - after.fX, pivot.fY - after.fY);
+       }
+}
+
+static void MiterJoiner(SkPath* outer, SkPath* inner, const SkVector& beforeUnitNormal,
+                                               const SkPoint& pivot, const SkVector& afterUnitNormal,
+                                               SkScalar radius, SkScalar invMiterLimit,
+                                               bool prevIsLine, bool currIsLine)
+{
+       // negate the dot since we're using normals instead of tangents
+       SkScalar        dotProd = SkPoint::DotProduct(beforeUnitNormal, afterUnitNormal);
+       AngleType       angleType = Dot2AngleType(dotProd);
+       SkVector        before = beforeUnitNormal;
+       SkVector        after = afterUnitNormal;
+       SkVector        mid;
+       SkScalar        sinHalfAngle;
+       bool            ccw;
+
+       if (angleType == kNearlyLine_AngleType)
+               return;
+       if (angleType == kNearly180_AngleType)
+       {
+               currIsLine = false;
+               goto DO_BLUNT;
+       }
+
+       /*      midLength = radius / sinHalfAngle
+               if (midLength > miterLimit * radius) abort
+               if (radius / sinHalf > miterLimit * radius) abort
+               if (1 / sinHalf > miterLimit) abort
+               if (1 / miterLimit > sinHalf) abort
+               My dotProd is opposite sign, since it is built from normals and not tangents
+               hence 1 + dot instead of 1 - dot in the formula
+       */
+       sinHalfAngle = SkScalarSqrt(SkScalarHalf(SK_Scalar1 + dotProd));
+       if (sinHalfAngle < invMiterLimit)
+       {
+               currIsLine = false;
+               goto DO_BLUNT;
+       }
+
+       ccw = !is_clockwise(before, after);
+       if (ccw)
+       {
+               SkTSwap<SkPath*>(outer, inner);
+               before.negate();
+               after.negate();
+       }
+
+       // choose the most accurate way to form the initial mid-vector
+       if (angleType == kSharp_AngleType)
+       {
+               mid.set(after.fY - before.fY, before.fX - after.fX);
+               if (ccw)
+                       mid.negate();
+       }
+       else
+               mid.set(before.fX + after.fX, before.fY + after.fY);
+
+       mid.setLength(SkScalarDiv(radius, sinHalfAngle));
+       if (prevIsLine)
+               outer->setLastPt(pivot.fX + mid.fX, pivot.fY + mid.fY);
+       else
+               outer->lineTo(pivot.fX + mid.fX, pivot.fY + mid.fY);
+
+DO_BLUNT:
+       after.scale(radius);
+       if (!currIsLine)
+               outer->lineTo(pivot.fX + after.fX, pivot.fY + after.fY);
+       inner->lineTo(pivot.fX - after.fX, pivot.fY - after.fY);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+SkStrokerPriv::CapProc SkStrokerPriv::CapFactory(SkPaint::Cap cap)
+{
+       static const SkStrokerPriv::CapProc gCappers[] = {
+               ButtCapper, RoundCapper, SquareCapper
+       };
+
+       SkASSERT((unsigned)cap < SkPaint::kCapCount);
+       return gCappers[cap];
+}
+
+SkStrokerPriv::JoinProc SkStrokerPriv::JoinFactory(SkPaint::Join join)
+{
+       static const SkStrokerPriv::JoinProc gJoiners[] = {
+               MiterJoiner, RoundJoiner, BluntJoiner
+       };
+
+       SkASSERT((unsigned)join < SkPaint::kJoinCount);
+       return gJoiners[join];
+}
+
+
+
diff --git a/libs/graphics/sgl/SkStrokerPriv.h b/libs/graphics/sgl/SkStrokerPriv.h
new file mode 100644 (file)
index 0000000..60a2a1f
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef SkStrokerPriv_DEFINED
+#define SkStrokerPriv_DEFINED
+
+#include "SkStroke.h"
+
+#define CWX(x, y)      (-y)
+#define CWY(x, y)      (x)
+#define CCWX(x, y)     (y)
+#define CCWY(x, y)     (-x)
+
+#define CUBIC_ARC_FACTOR       ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3)
+
+class SkStrokerPriv {
+public:
+       typedef void (*CapProc)(SkPath* path,
+                                                       const SkPoint& pivot,
+                                                       const SkVector& normal,
+                                                       const SkPoint& stop,
+                                                       SkPath* otherPath);
+
+       typedef void (*JoinProc)(SkPath* outer, SkPath* inner,
+                                                        const SkVector& beforeUnitNormal,
+                                                        const SkPoint& pivot,
+                                                        const SkVector& afterUnitNormal,
+                                                        SkScalar radius, SkScalar invMiterLimit,
+                                                        bool prevIsLine, bool currIsLine);
+
+       static CapProc  CapFactory(SkPaint::Cap);
+       static JoinProc JoinFactory(SkPaint::Join);
+};
+
+#endif
+
diff --git a/libs/graphics/sgl/SkTSearch.cpp b/libs/graphics/sgl/SkTSearch.cpp
new file mode 100644 (file)
index 0000000..41118bb
--- /dev/null
@@ -0,0 +1,176 @@
+#include "SkTSearch.h"
+#include <ctype.h>
+
+static inline const char* index_into_base(const char*const* base, int index, size_t elemSize)
+{
+       return *(const char*const*)((const char*)base + index * elemSize);
+}
+
+int SkStrSearch(const char*const* base, int count, const char target[], size_t target_len, size_t elemSize)
+{
+       SkASSERT(base != nil);
+       SkASSERT(count >= 0);
+
+       if (count <= 0)
+               return ~0;
+
+       int     lo = 0;
+       int     hi = count - 1;
+
+       while (lo < hi)
+       {
+               int mid = (hi + lo) >> 1;
+               const char* elem = index_into_base(base, mid, elemSize);
+
+               int cmp = strncmp(elem, target, target_len);
+               if (cmp < 0)
+                       lo = mid + 1;
+               else if (cmp > 0 || strlen(elem) > target_len)
+                       hi = mid;
+               else
+                       return mid;
+       }
+
+       const char* elem = index_into_base(base, hi, elemSize);
+       int cmp = strncmp(elem, target, target_len);
+       if (cmp || strlen(elem) > target_len)
+       {
+               if (cmp < 0)
+                       hi += 1;
+               hi = ~hi;
+       }
+       return hi;
+}
+
+int SkStrSearch(const char*const* base, int count, const char target[], size_t elemSize) {
+       return SkStrSearch(base, count, target, strlen(target), elemSize);
+}
+
+#define kLCBufferSize  32
+
+int SkStrLCSearch(const char*const* base, int count, const char target[], size_t len, size_t elemSize)
+{
+       SkASSERT(target);
+
+       char            lcBuffer[kLCBufferSize + 1];
+       char*           lc;
+
+       if (len <= kLCBufferSize)
+               lc = lcBuffer;
+       else
+               lc = (char*)sk_malloc_throw(len + 1);
+
+       for (int i = (int)(len - 1); i >= 0; --i)
+       {
+               SkASSERT((target[i] & 0x80) == 0);      // only works for ascii
+               lc[i] = (char)tolower(target[i]);
+       }
+       lc[len] = 0;
+
+       int index = SkStrSearch(base, count, lc, len, elemSize);
+
+       if (lc != lcBuffer)
+               sk_free(lc);
+       return index;
+}
+
+int SkStrLCSearch(const char*const* base, int count, const char target[], size_t elemSize) {
+       return SkStrLCSearch(base, count, target, strlen(target), elemSize);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+#define SK_QSortTempSize       16
+
+static inline void sk_qsort_swap(char a[], char b[], size_t elemSize)
+{
+       char    tmp[SK_QSortTempSize];
+
+       while (elemSize > 0)
+       {
+               size_t size = elemSize;
+               if (size > SK_QSortTempSize)
+                       size = SK_QSortTempSize;
+               elemSize -= size;
+
+               memcpy(tmp, a, size);
+               memcpy(a, b, size);
+               memcpy(b, tmp, size);
+               a += size;
+               b += size;
+       }
+}
+
+static void SkQSort_Partition(char* first, char* last, size_t elemSize, SkQSortCompareProc compare)
+{
+       char*   left = first;
+       char*   rite = last;
+       char*   pivot = left;
+
+       while (left <= rite)
+       {
+               while (left < last && compare(left, pivot) < 0)
+                       left += elemSize;
+               while (first < rite && compare(rite, pivot) > 0)
+                       rite -= elemSize;
+               if (left <= rite)
+               {
+                       if (left < rite)
+                       {
+                               SkASSERT(compare(left, rite) >= 0);
+                               sk_qsort_swap(left, rite, elemSize);
+                       }
+                       left += elemSize;
+                       rite -= elemSize;
+               }
+       }
+       if (first < rite)
+               SkQSort_Partition(first, rite, elemSize, compare);
+       if (left < last)
+               SkQSort_Partition(left, last, elemSize, compare);
+}
+
+void SkQSort(void* base, size_t count, size_t elemSize, SkQSortCompareProc compare)
+{
+       SkASSERT(base);
+       SkASSERT(compare);
+       SkASSERT(elemSize > 0);
+
+       if (count <= 1)
+               return;
+
+       SkQSort_Partition((char*)base, (char*)base + (count - 1) * elemSize, elemSize, compare);
+}
+
+#ifdef SK_DEBUG
+
+#include "SkRandom.h"
+
+#ifdef SK_SUPPORT_UNITTEST
+extern "C" {
+       int compare_int(const void* a, const void* b)
+       {
+               return *(const int*)a - *(const int*)b;
+       }
+}
+#endif
+
+void SkQSort_UnitTest()
+{
+#ifdef SK_SUPPORT_UNITTEST
+       int                     array[100];
+       SkRandom        rand;
+
+       for (int i = 0; i < 1000; i++)
+       {
+               int     j, count = rand.nextRangeU(1, SK_ARRAY_COUNT(array));
+               for (j = 0; j < count; j++)
+                       array[j] = rand.nextS() & 0xFF;
+               SkQSort(array, count, sizeof(int), compare_int);
+               for (j = 1; j < count; j++)
+                       SkASSERT(array[j-1] <= array[j]);
+       }
+#endif
+}
+
+#endif
diff --git a/libs/graphics/sgl/SkTSort.h b/libs/graphics/sgl/SkTSort.h
new file mode 100644 (file)
index 0000000..bdfbf6d
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef SkTSort_DEFINED
+#define SkTSort_DEFINED
+
+#include "SkTypes.h"
+
+template <typename T>
+void SkTHeapSort_SiftDown(T array[], int root, int bottom)
+{
+       int     root2 = root << 1;
+
+       while (root2 <= bottom)
+       {
+               int     maxChild;
+
+               if (root2 == bottom)
+                       maxChild = root2;
+               else if (array[root2] > array[root2 + 1])
+                       maxChild = root2;
+               else
+                       maxChild = root2 + 1;
+
+               if (array[root] < array[maxChild])
+               {
+                       SkTSwap<T>(array[root], array[maxChild]);
+                       root = maxChild;
+                       root2 = root << 1;
+               }
+               else
+                       break;
+       }
+}
+
+template <typename T>
+void SkTHeapSort(T array[], int count)
+{
+       int i;
+
+       for (i = count/2 - 1; i >= 0; --i)
+               SkTHeapSort_SiftDown<T>(array, i, count);
+
+       for (i = count - 2; i >= 0; --i)
+       {
+               SkTSwap<T>(array[0], array[i + 1]);
+               SkTHeapSort_SiftDown<T>(array, 0, i);
+       }
+}
+
+#endif
diff --git a/libs/graphics/sgl/SkTemplatesPriv.h b/libs/graphics/sgl/SkTemplatesPriv.h
new file mode 100644 (file)
index 0000000..7c2e915
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef SkTemplatesPriv_DEFINED
+#define SkTemplatesPriv_DEFINED
+
+#include "SkTemplates.h"
+
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_BUILD_FOR_WIN32
+       #define SK_PLACEMENT_NEW(result, classname, storage, storageSize)       \
+               result = SkNEW(classname)
+
+       #define SK_PLACEMENT_NEW_ARGS(result, classname, storage, storageSize, args)    \
+               result = SkNEW_ARGS(classname, args)
+#else
+       #include <new>
+       #define SK_PLACEMENT_NEW(result, classname, storage, storagesize)               \
+       do {                                                                                                                                    \
+               if (storagesize)                                                                                                        \
+               {                                                                                                                                       \
+                       SkASSERT(storageSize >= sizeof(classname));                                             \
+                       result = new(storage) classname;                                                                \
+               }                                                                                                                                       \
+               else                                                                                                                            \
+                       result = SkNEW(classname);                                                                              \
+       } while (0)
+
+       #define SK_PLACEMENT_NEW_ARGS(result, classname, storage, storagesize, args)            \
+       do {                                                                                                                                                            \
+               if (storagesize)                                                                                                                                \
+               {                                                                                                                                                               \
+                       SkASSERT(storageSize >= sizeof(classname));                                                                     \
+                       result = new(storage) classname args;                                                                           \
+               }                                                                                                                                                               \
+               else                                                                                                                                                    \
+                       result = SkNEW_ARGS(classname, args);                                                                           \
+       } while (0)
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T> class SkAutoTPlacementDelete {
+public:
+       SkAutoTPlacementDelete(T* obj, void* storage) : fObj(obj), fStorage(storage)
+       {
+       }
+       ~SkAutoTPlacementDelete()
+       {
+               if (fObj)
+               {
+                       if (fObj == fStorage)
+                               fObj->~T();
+                       else
+                               delete fObj;
+               }
+       }
+       T* detach()
+       {
+               T*      obj = fObj;
+               fObj = nil;
+               return obj;
+       }
+private:
+       T*              fObj;
+       void*   fStorage;
+};
+
+#endif
diff --git a/libs/graphics/sgl/SkTextLayout.cpp b/libs/graphics/sgl/SkTextLayout.cpp
new file mode 100644 (file)
index 0000000..1ff4264
--- /dev/null
@@ -0,0 +1,66 @@
+#include "SkTextLayout.h"
+#include "SkPaint.h"
+
+int SkTextLayout::layout(const SkPaint& paint,
+                          const char* text, size_t byteLength, SkUnicodeWalkerProc proc,
+                          Rec rec[])
+{
+    const char* stop = text + byteLength;
+    Rec*        recStart = rec;
+    
+    while (text < stop)
+    {
+        rec->fCharCode = proc(&text);
+        rec += 1;
+        // set private fields of Rec (when we use them)
+    }
+    
+    int count = rec - recStart;
+    if (count > 0)
+        this->onLayout(paint, recStart, count);
+    return count;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+
+class SkTrackingTextLayout : public SkTextLayout {
+public:
+    SkTrackingTextLayout(SkScalar charExtra, SkScalar spaceExtra)
+        : fCharExtra(charExtra), fSpaceExtra(spaceExtra) {}
+
+protected:
+    // override
+    virtual void onLayout(const SkPaint& paint, Rec rec[], int count)
+    {
+        SkScalar ce = fCharExtra;
+        SkScalar se = fSpaceExtra;
+
+        if (0 == se)    // special case no space-extra (so we don't have to read charCode()
+        {
+            for (int i = 0; i < count; i++)
+                rec[i].fDeltaAdvance = ce;
+        }
+        else
+        {
+            for (int i = 0; i < count; i++)
+            {
+                SkScalar delta = ce;
+                if (32 == rec[i].charCode())    // do I need a fancier test?
+                    delta += se;
+                rec[i].fDeltaAdvance = delta;
+            }
+        }
+    }
+
+private:
+    SkScalar    fCharExtra, fSpaceExtra;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+
+SkTextLayout* SkTextLayout::CreateTrackingLayout(SkScalar charExtra, SkScalar spaceExtra)
+{
+    return SkNEW_ARGS(SkTrackingTextLayout, (charExtra, spaceExtra));
+}
+
+
diff --git a/libs/graphics/sgl/SkUtils.cpp b/libs/graphics/sgl/SkUtils.cpp
new file mode 100644 (file)
index 0000000..9cb7c65
--- /dev/null
@@ -0,0 +1,496 @@
+#include "SkUtils.h"
+
+#if 0
+#define assign_16_longs(dst, value)                            \
+       do {                                                                            \
+               (dst)[0] = value;       (dst)[1] = value;       \
+               (dst)[2] = value;       (dst)[3] = value;       \
+               (dst)[4] = value;       (dst)[5] = value;       \
+               (dst)[6] = value;       (dst)[7] = value;       \
+               (dst)[8] = value;       (dst)[9] = value;       \
+               (dst)[10] = value;      (dst)[11] = value;      \
+               (dst)[12] = value;      (dst)[13] = value;      \
+               (dst)[14] = value;      (dst)[15] = value;      \
+       } while (0)
+#else
+#define assign_16_longs(dst, value)                            \
+       do {                                                                            \
+               *(dst)++ = value;       *(dst)++ = value;       \
+               *(dst)++ = value;       *(dst)++ = value;       \
+               *(dst)++ = value;       *(dst)++ = value;       \
+               *(dst)++ = value;       *(dst)++ = value;       \
+               *(dst)++ = value;       *(dst)++ = value;       \
+               *(dst)++ = value;       *(dst)++ = value;       \
+               *(dst)++ = value;       *(dst)++ = value;       \
+               *(dst)++ = value;       *(dst)++ = value;       \
+       } while (0)
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef SK_MEMSET16_REDIRECT
+void sk_memset16(uint16_t dst[], U16CPU value, int count)
+{
+       SkASSERT(dst != NULL && count >= 0);
+
+       if (count <= 0)
+               return;
+
+       // not sure if this helps to short-circuit on small values of count
+       if (count < 8)
+       {
+               do {
+                       *dst++ = (uint16_t)value;
+               } while (--count != 0);
+               return;
+       }
+
+       // ensure we're on a long boundary
+       if ((size_t)dst & 2)
+       {
+               *dst++ = (uint16_t)value;
+               count -= 1;
+       }
+
+       uint32_t value32 = ((uint32_t)value << 16) | value;
+
+       // handle the bulk with our unrolled macro
+       {
+               int sixteenlongs = count >> 5;
+               if (sixteenlongs)
+               {
+                       U32* dst32 = (U32*)dst;
+                       do {
+                               assign_16_longs(dst32, value32);
+                       } while (--sixteenlongs != 0);
+                       dst = (uint16_t*)dst32;
+                       count &= 31;
+               }
+       }
+
+       // handle (most) of the rest
+       {
+               int longs = count >> 1;
+               if (longs)
+               {
+                       do {
+                               *(uint32_t*)dst = value32;
+                               dst += 2;
+                       } while (--longs != 0);
+               }
+       }
+
+       // cleanup a possible trailing short
+       if (count & 1)
+               *dst = (uint16_t)value;
+}
+#endif
+
+#ifndef SK_MEMSET32_REDIRECT
+void sk_memset32(uint32_t dst[], uint32_t value, int count)
+{
+       SkASSERT(dst != NULL && count >= 0);
+
+       {
+               int sixteenlongs = count >> 4;
+               if (sixteenlongs)
+               {
+                       do {
+                               assign_16_longs(dst, value);
+                       } while (--sixteenlongs != 0);
+                       count &= 15;
+               }
+       }
+
+       if (count)
+       {
+               do {
+                       *dst++ = value;
+               } while (--count != 0);
+       }
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+
+/*     0xxxxxxx        1 total
+       10xxxxxx        // never a leading byte
+       110xxxxx        2 total
+       1110xxxx        3 total
+       11110xxx        4 total
+
+       11 10 01 01 xx xx xx xx 0...
+       0xE5XX0000
+       0xE5 << 24
+*/
+
+#ifdef SK_DEBUG
+       static void assert_utf8_leadingbyte(unsigned c)
+       {
+               SkASSERT(c <= 0xF7);    // otherwise leading byte is too big (more than 4 bytes)
+               SkASSERT((c & 0xC0) != 0x80);   // can't begin with a middle char
+       }
+
+       int SkUTF8_LeadByteToCount(unsigned c)
+       {
+               assert_utf8_leadingbyte(c);
+               return (((0xE5 << 24) >> (c >> 4 << 1)) & 3) + 1;
+       }
+#else
+       #define assert_utf8_leadingbyte(c)
+#endif
+
+int SkUTF8_CountUnichars(const char utf8[])
+{
+       SkASSERT(utf8);
+
+       int count = 0;
+
+       for (;;)
+       {
+               int c = *(const U8*)utf8;
+               if (c == 0)
+                       break;
+
+               utf8 += SkUTF8_LeadByteToCount(c);
+               count += 1;
+       }
+       return count;
+}
+
+int SkUTF8_CountUnichars(const char utf8[], size_t byteLength)
+{
+       SkASSERT(NULL != utf8 || 0 == byteLength);
+
+       int         count = 0;
+    const char* stop = utf8 + byteLength;
+
+       while (utf8 < stop)
+       {
+               utf8 += SkUTF8_LeadByteToCount(*(const uint8_t*)utf8);
+               count += 1;
+       }
+       return count;
+}
+
+SkUnichar SkUTF8_ToUnichar(const char utf8[])
+{
+    SkASSERT(NULL != utf8);
+
+       const U8*       p = (const U8*)utf8;
+       int                     c = *p;
+       int                     hic = c << 24;
+
+       assert_utf8_leadingbyte(c);
+
+       if (hic < 0)
+       {
+               U32 mask = (U32)~0x3F;
+               hic <<= 1;
+               do {
+                       c = (c << 6) | (*++p & 0x3F);
+                       mask <<= 5;
+               } while ((hic <<= 1) < 0);
+               c &= ~mask;
+       }
+       return c;
+}
+
+SkUnichar SkUTF8_NextUnichar(const char** ptr)
+{
+    SkASSERT(NULL != ptr && NULL != *ptr);
+
+       const U8*       p = (const U8*)*ptr;
+       int                     c = *p;
+       int                     hic = c << 24;
+       
+       assert_utf8_leadingbyte(c);
+
+       if (hic < 0)
+       {
+               U32 mask = (U32)~0x3F;
+               hic <<= 1;
+               do {
+                       c = (c << 6) | (*++p & 0x3F);
+                       mask <<= 5;
+               } while ((hic <<= 1) < 0);
+               c &= ~mask;
+       }
+       *ptr = (char*)p + 1;
+       return c;
+}
+
+size_t SkUTF8_FromUnichar(SkUnichar uni, char utf8[])
+{
+       if ((uint32_t)uni > 0x10FFFF)
+       {
+               SkASSERT(!"bad unichar");
+               return 0;
+       }
+
+       if (uni <= 127)
+       {
+               if (utf8)
+                       *utf8 = (char)uni;
+               return 1;
+       }
+
+       char    tmp[4];
+       char*   p = tmp;
+       size_t  count = 1;
+
+       SkDEBUGCODE(SkUnichar orig = uni;)
+
+       while (uni > 0x3F)
+       {
+               *p++ = (char)(0x80 | (uni & 0x3F));
+               uni >>= 6;
+               count += 1;
+       }
+
+       if (utf8)
+       {
+               p = tmp;
+               utf8 += count;
+               while (p < tmp + count - 1)
+                       *--utf8 = *p++;
+               *--utf8 = (char)(~(0xFF >> count) | uni);
+       }
+
+       SkASSERT(utf8 == NULL || orig == SkUTF8_ToUnichar(utf8));
+       return count;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+int SkUTF16_CountUnichars(const uint16_t src[])
+{
+    SkASSERT(src);
+
+    int count = 0;
+    unsigned c;
+    while ((c = *src++) != 0)
+    {
+        SkASSERT(!SkUTF16_IsLowSurrogate(c));
+        if (SkUTF16_IsHighSurrogate(c))
+        {
+            c = *src++;
+            SkASSERT(SkUTF16_IsLowSurrogate(c));
+        }
+        count += 1;
+    }
+    return count;
+}
+
+int SkUTF16_CountUnichars(const uint16_t src[], int numberOf16BitValues)
+{
+    SkASSERT(src);
+
+    const uint16_t* stop = src + numberOf16BitValues;
+    int count = 0;
+    while (src < stop)
+    {
+        unsigned c = *src++;
+        SkASSERT(!SkUTF16_IsLowSurrogate(c));
+        if (SkUTF16_IsHighSurrogate(c))
+        {
+            SkASSERT(src < stop);
+            c = *src++;
+            SkASSERT(SkUTF16_IsLowSurrogate(c));
+        }
+        count += 1;
+    }
+    return count;
+}
+
+SkUnichar SkUTF16_NextUnichar(const uint16_t** srcPtr)
+{
+    SkASSERT(srcPtr && *srcPtr);
+    
+    const uint16_t* src = *srcPtr;
+    SkUnichar       c = *src++;
+    
+    SkASSERT(!SkUTF16_IsLowSurrogate(c));
+    if (SkUTF16_IsHighSurrogate(c))
+    {
+        unsigned c2 = *src++;
+        SkASSERT(SkUTF16_IsLowSurrogate(c2));
+        
+        // c = ((c & 0x3FF) << 10) + (c2 & 0x3FF) + 0x10000
+        // c = (((c & 0x3FF) + 64) << 10) + (c2 & 0x3FF)
+        c = (c << 10) + c2 + (0x10000 - (0xD800 << 10) - 0xDC00);
+    }
+    *srcPtr = src;
+    return c;
+}
+
+size_t SkUTF16_FromUnichar(SkUnichar uni, uint16_t dst[])
+{
+    SkASSERT((unsigned)uni <= 0x10FFFF);
+
+    int extra = (uni > 0xFFFF);
+
+    if (dst)
+    {
+        if (extra)
+        {
+            // dst[0] = SkToU16(0xD800 | ((uni - 0x10000) >> 10));
+            // dst[0] = SkToU16(0xD800 | ((uni >> 10) - 64));
+            dst[0] = SkToU16((0xD800 - 64) + (uni >> 10));
+            dst[1] = SkToU16(0xDC00 | (uni & 0x3FF));
+            
+            SkASSERT(SkUTF16_IsHighSurrogate(dst[0]));
+            SkASSERT(SkUTF16_IsLowSurrogate(dst[1]));
+        }
+        else
+        {
+            dst[0] = SkToU16(uni);
+            SkASSERT(!SkUTF16_IsHighSurrogate(dst[0]));
+            SkASSERT(!SkUTF16_IsLowSurrogate(dst[0]));
+        }
+    }
+    return 1 + extra;
+}
+
+size_t SkUTF16_ToUTF8(const uint16_t utf16[], int numberOf16BitValues, char utf8[])
+{
+    SkASSERT(numberOf16BitValues >= 0);
+    if (numberOf16BitValues <= 0)
+        return 0;
+
+    SkASSERT(utf16 != NULL);
+    
+    const uint16_t* stop = utf16 + numberOf16BitValues;
+    size_t          size = 0;
+    
+    if (utf8 == NULL)    // just count
+    {
+        while (utf16 < stop)
+            size += SkUTF8_FromUnichar(SkUTF16_NextUnichar(&utf16), NULL);
+    }
+    else
+    {
+        char* start = utf8;
+        while (utf16 < stop)
+            utf8 += SkUTF8_FromUnichar(SkUTF16_NextUnichar(&utf16), utf8);
+        size = utf8 - start;
+    }
+    return size;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+#include "SkRandom.h"
+#include "SkTSearch.h"
+#include "SkTSort.h"
+
+#define kSEARCH_COUNT  91
+
+#ifdef SK_SUPPORT_UNITTEST
+static void test_search()
+{
+       int                     i, array[kSEARCH_COUNT];
+       SkRandom        rand;
+
+       for (i = 0; i < kSEARCH_COUNT; i++)
+               array[i] = rand.nextS();
+
+       SkTHeapSort<int>(array, kSEARCH_COUNT);
+       // make sure we got sorted properly
+       for (i = 1; i < kSEARCH_COUNT; i++)
+               SkASSERT(array[i-1] <= array[i]);
+
+       // make sure we can find all of our values
+       for (i = 0; i < kSEARCH_COUNT; i++)
+       {
+               int index = SkTSearch<int>(array, kSEARCH_COUNT, array[i], sizeof(int));
+               SkASSERT(index == i);
+       }
+
+       // make sure that random values are either found, or the correct
+       // insertion index is returned
+       for (i = 0; i < 10000; i++)
+       {
+               int value = rand.nextS();
+               int index = SkTSearch<int>(array, kSEARCH_COUNT, value, sizeof(int));
+
+               if (index >= 0)
+                       SkASSERT(index < kSEARCH_COUNT && array[index] == value);
+               else
+               {
+                       index = ~index;
+                       SkASSERT(index <= kSEARCH_COUNT);
+                       if (index < kSEARCH_COUNT)
+                       {
+                               SkASSERT(value < array[index]);
+                               if (index > 0)
+                                       SkASSERT(value > array[index - 1]);
+                       }
+                       else    // we should append the new value
+                       {
+                               SkASSERT(value > array[kSEARCH_COUNT - 1]);
+                       }
+               }
+       }
+}
+
+static void test_utf16()
+{
+    static const SkUnichar gUni[] = {
+        0x10000, 0x18080, 0x20202, 0xFFFFF, 0x101234
+    };
+    
+    uint16_t buf[2];
+    
+    for (unsigned i = 0; i < SK_ARRAY_COUNT(gUni); i++)
+    {
+        size_t count = SkUTF16_FromUnichar(gUni[i], buf);
+        SkASSERT(count == 2);
+        size_t count2 = SkUTF16_CountUnichars(buf, 2);
+        SkASSERT(count2 == 1);
+        const uint16_t* ptr = buf;
+        SkUnichar c = SkUTF16_NextUnichar(&ptr);
+        SkASSERT(c == gUni[i]);
+        SkASSERT(ptr - buf == 2);
+    }
+}
+
+#endif
+
+void SkUtils::UnitTest()
+{
+#ifdef SK_SUPPORT_UNITTEST
+       static const struct {
+               const char*     fUtf8;
+               SkUnichar       fUni;
+       } gTest[] = {
+               { "a",                                  'a'     },
+               { "\xC3\x83",                   (3 << 6) | 3    },
+               { "\xE3\x83\x83",               (3 << 12) | (3 << 6) | 3        },
+               { "\xF3\x83\x83\x83",   (3 << 18) | (3 << 12) | (3 << 6) | 3    }
+       };
+
+       for (unsigned i = 0; i < SK_ARRAY_COUNT(gTest); i++)
+       {
+               const char*     p = gTest[i].fUtf8;
+               int                     n = SkUTF8_CountUnichars(p);
+               SkUnichar       u0 = SkUTF8_ToUnichar(gTest[i].fUtf8);
+               SkUnichar       u1 = SkUTF8_NextUnichar(&p);
+
+               SkASSERT(n == 1);
+               SkASSERT(u0 == u1);
+               SkASSERT(u0 == gTest[i].fUni);
+               SkASSERT(p - gTest[i].fUtf8 == (int)strlen(gTest[i].fUtf8));
+       }
+    
+    test_utf16();
+
+       test_search();
+#endif
+}
+
+#endif
+
+
diff --git a/libs/graphics/sgl/SkXfermode.cpp b/libs/graphics/sgl/SkXfermode.cpp
new file mode 100644 (file)
index 0000000..6f5a9a8
--- /dev/null
@@ -0,0 +1,535 @@
+#include "SkXfermode.h"
+#include "SkColorPriv.h"
+
+static inline U8CPU SkAlphaMulAlpha(U8CPU a, U8CPU b)
+{
+    unsigned ab = a * b;
+#if 0
+    return ab / 255;
+#else
+    return ((ab << 8) + ab + 257) >> 16;
+#endif
+}
+
+void SkXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count, const SkAlpha aa[])
+{
+       // override in subclass
+}
+
+void SkXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count, const SkAlpha aa[])
+{
+       // override in subclass
+}
+
+void SkXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count, const SkAlpha aa[])
+{
+       // override in subclass
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+static SkPMColor SkFourByteInterp(SkPMColor src, SkPMColor dst, U8CPU alpha)
+{
+       unsigned scale = SkAlpha255To256(alpha);
+
+       unsigned a = SkAlphaBlend(SkGetPackedA32(src), SkGetPackedA32(dst), scale);
+       unsigned r = SkAlphaBlend(SkGetPackedR32(src), SkGetPackedR32(dst), scale);
+       unsigned g = SkAlphaBlend(SkGetPackedG32(src), SkGetPackedG32(dst), scale);
+       unsigned b = SkAlphaBlend(SkGetPackedB32(src), SkGetPackedB32(dst), scale);
+
+       return SkPackARGB32(a, r, g, b);
+}
+
+void SkProcXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], int count, const SkAlpha aa[])
+{
+       SkASSERT(dst && src && count >= 0);
+
+       SkXfermodeProc proc = fProc;
+       if (proc)
+       {
+               if (NULL == aa)         
+               {
+                       for (int i = count - 1; i >= 0; --i)
+                               dst[i] = proc(src[i], dst[i]);
+               }
+               else
+               {
+                       for (int i = count - 1; i >= 0; --i)
+                       {
+                               unsigned a = aa[i];
+                               if (a != 0)
+                               {
+                                       SkPMColor dstC = dst[i];
+                                       SkPMColor C = proc(src[i], dstC);
+                                       if (a != 0xFF)
+                                               C = SkFourByteInterp(C, dstC, a);
+                                       dst[i] = C;
+                               }
+                       }
+               }
+       }
+}
+
+void SkProcXfermode::xfer16(uint16_t dst[], const SkPMColor src[], int count, const SkAlpha aa[])
+{
+       SkASSERT(dst && src && count >= 0);
+
+       SkXfermodeProc proc = fProc;
+       if (proc)
+       {
+               if (NULL == aa)         
+               {
+                       for (int i = count - 1; i >= 0; --i)
+                       {
+                               SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
+                               dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
+                       }
+               }
+               else
+               {
+                       for (int i = count - 1; i >= 0; --i)
+                       {
+                               unsigned a = aa[i];
+                               if (a != 0)
+                               {
+                                       SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
+                                       SkPMColor C = proc(src[i], dstC);
+                                       if (a != 0xFF)
+                                               C = SkFourByteInterp(C, dstC, a);
+                                       dst[i] = SkPixel32ToPixel16_ToU16(C);
+                               }
+                       }
+               }
+       }
+}
+
+void SkProcXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count, const SkAlpha aa[])
+{
+       SkASSERT(dst && src && count >= 0);
+
+       SkXfermodeProc proc = fProc;
+       if (proc)
+       {
+               if (NULL == aa)         
+               {
+                       for (int i = count - 1; i >= 0; --i)
+                               dst[i] = SkToU8(SkGetPackedA32(proc(src[i], (SkPMColor)(dst[i] << SK_A32_SHIFT))));
+               }
+               else
+               {
+                       for (int i = count - 1; i >= 0; --i)
+                       {
+                               unsigned a = aa[i];
+                               if (a != 0)
+                               {
+                                       SkAlpha dstA = dst[i];
+                                       unsigned A = SkGetPackedA32(proc(src[i], (SkPMColor)(dstA << SK_A32_SHIFT)));
+                                       if (a != 0xFF)
+                                               A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
+                                       dst[i] = SkToU8(A);
+                               }
+                       }
+               }
+       }
+}
+
+SkProcXfermode::SkProcXfermode(SkRBuffer& buffer) : SkXfermode(buffer)
+{
+    fProc = (SkXfermodeProc)buffer.readPtr();
+}
+
+void SkProcXfermode::flatten(SkWBuffer& buffer)
+{
+    this->INHERITED::flatten(buffer);
+    
+    buffer.writePtr((void*)fProc);
+}
+
+SkFlattenable::Factory SkProcXfermode::getFactory()
+{
+    return CreateProc;
+}
+
+SkFlattenable* SkProcXfermode::CreateProc(SkRBuffer& buffer)
+{
+    return SkNEW_ARGS(SkProcXfermode, (buffer));
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+
+//     kClear_Mode,    //!< [0, 0]
+static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst)
+{
+       return 0;
+}
+
+//     kSrc_Mode,              //!< [Sa, Sc]
+static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst)
+{
+       return src;
+}
+
+//     kDst_Mode,              //!< [Da, Dc]
+static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst)
+{
+       return dst;
+}
+
+//     kSrcOver_Mode,  //!< [Sa + (1 - Sa)*Da, Sc + (1 - Sa)*Dc] this is the default mode
+static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst)
+{
+       return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
+}
+
+//     kDstOver_Mode,  //!< [Sa + (1 - Sa)*Da, Dc + (1 - Da)*Sc]
+static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst)
+{
+       unsigned sa = SkGetPackedA32(src);
+       unsigned da = SkGetPackedA32(dst);
+
+       return SkPackARGB32(sa + da - SkAlphaMulAlpha(sa, da),
+                                               SkGetPackedR32(dst) + SkAlphaMulAlpha(255 - da, SkGetPackedR32(src)),
+                                               SkGetPackedG32(dst) + SkAlphaMulAlpha(255 - da, SkGetPackedG32(src)),
+                                               SkGetPackedB32(dst) + SkAlphaMulAlpha(255 - da, SkGetPackedB32(src)));
+}
+
+//     kSrcIn_Mode,    //!< [Sa * Da, Sc * Da]
+static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst)
+{
+       return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
+}
+
+//     kDstIn_Mode,    //!< [Sa * Da, Sa * Dc]
+static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst)
+{
+       return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
+}
+
+//     kSrcOut_Mode,   //!< [Sa * (1 - Da), Sc * (1 - Da)]
+static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst)
+{
+       return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
+}
+
+//     kDstOut_Mode,   //!< [Da * (1 - Sa), Dc * (1 - Sa)]
+static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst)
+{
+       return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
+}
+
+//     kSrcATop_Mode,  //!< [Da, Sc * Da + (1 - Sa) * Dc]
+static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst)
+{
+       unsigned sa = SkGetPackedA32(src);
+       unsigned da = SkGetPackedA32(dst);
+       unsigned src_scale = SkAlpha255To256(255 - sa);
+       unsigned dst_scale = SkAlpha255To256(da);
+
+       return SkPackARGB32(da,
+                                               (dst_scale * SkGetPackedR32(src) + src_scale * SkGetPackedR32(dst)) >> 8,
+                                               (dst_scale * SkGetPackedG32(src) + src_scale * SkGetPackedG32(dst)) >> 8,
+                                               (dst_scale * SkGetPackedB32(src) + src_scale * SkGetPackedB32(dst)) >> 8);
+}
+
+//     kDstATop_Mode,  //!< [Sa, Sa * Dc + Sc * (1 - Da)]
+static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst)
+{
+       unsigned sa = SkGetPackedA32(src);
+       unsigned da = SkGetPackedA32(dst);
+       unsigned src_scale = SkAlpha255To256(sa);
+       unsigned dst_scale = SkAlpha255To256(255 - da);
+
+       return SkPackARGB32(sa,
+                                               (dst_scale * SkGetPackedR32(src) + src_scale * SkGetPackedR32(dst)) >> 8,
+                                               (dst_scale * SkGetPackedG32(src) + src_scale * SkGetPackedG32(dst)) >> 8,
+                                               (dst_scale * SkGetPackedB32(src) + src_scale * SkGetPackedB32(dst)) >> 8);
+}
+
+//     kXor_Mode,              //!< [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
+static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst)
+{
+       unsigned sa = SkGetPackedA32(src);
+       unsigned da = SkGetPackedA32(dst);
+       unsigned src_scale = SkAlpha255To256(255 - sa);
+       unsigned dst_scale = SkAlpha255To256(255 - da);
+
+       return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
+                                               (dst_scale * SkGetPackedR32(src) + src_scale * SkGetPackedR32(dst)) >> 8,
+                                               (dst_scale * SkGetPackedG32(src) + src_scale * SkGetPackedG32(dst)) >> 8,
+                                               (dst_scale * SkGetPackedB32(src) + src_scale * SkGetPackedB32(dst)) >> 8);
+}
+
+
+//        kDarken_Mode,   [Sa + Da - SaáDa, Scá(1 - Da) + Dcá(1 - Sa) + min(Sc, Dc)]
+
+static inline unsigned darken_p(unsigned src, unsigned dst, unsigned src_mul, unsigned dst_mul)
+{
+    return (dst_mul * src + src_mul * dst >> 8) + SkMin32(src, dst);
+}
+
+static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst)
+{
+       unsigned sa = SkGetPackedA32(src);
+       unsigned da = SkGetPackedA32(dst);
+       unsigned src_scale = SkAlpha255To256(255 - sa);
+       unsigned dst_scale = SkAlpha255To256(255 - da);
+
+    unsigned ra = sa + da - SkAlphaMulAlpha(sa, da);
+    unsigned rr = darken_p(SkGetPackedR32(src), SkGetPackedR32(dst), src_scale, dst_scale);
+    unsigned rg = darken_p(SkGetPackedG32(src), SkGetPackedG32(dst), src_scale, dst_scale);
+    unsigned rb = darken_p(SkGetPackedB32(src), SkGetPackedB32(dst), src_scale, dst_scale);
+
+       return SkPackARGB32(ra, SkFastMin32(rr, ra), SkFastMin32(rg, ra), SkFastMin32(rb, ra));
+}
+
+//        kLighten_Mode,  [Sa + Da - SaáDa, Scá(1 - Da) + Dcá(1 - Sa) + max(Sc, Dc)]
+static inline unsigned lighten_p(unsigned src, unsigned dst, unsigned src_mul, unsigned dst_mul)
+{
+    return (dst_mul * src + src_mul * dst >> 8) + SkMax32(src, dst);
+}
+
+static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst)
+{
+       unsigned sa = SkGetPackedA32(src);
+       unsigned da = SkGetPackedA32(dst);
+       unsigned src_scale = SkAlpha255To256(255 - sa);
+       unsigned dst_scale = SkAlpha255To256(255 - da);
+    
+    unsigned ra = sa + da - SkAlphaMulAlpha(sa, da);
+    unsigned rr = lighten_p(SkGetPackedR32(src), SkGetPackedR32(dst), src_scale, dst_scale);
+    unsigned rg = lighten_p(SkGetPackedG32(src), SkGetPackedG32(dst), src_scale, dst_scale);
+    unsigned rb = lighten_p(SkGetPackedB32(src), SkGetPackedB32(dst), src_scale, dst_scale);
+
+       return SkPackARGB32(ra, SkFastMin32(rr, ra), SkFastMin32(rg, ra), SkFastMin32(rb, ra));
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+#if 0 // maybe do these later
+
+#define SkPinToU8(value)       SkFastMin32(value, 0xFF)
+
+//     kAdd_Mode,              //!< clamp [Sa + Da, Sc + Dc]
+static SkPMColor add_modeproc(SkPMColor src, SkPMColor dst)
+{
+       return SkPackARGB32(SkPinToU8(SkGetPackedA32(src) + SkGetPackedA32(dst)),
+                                               SkPinToU8(SkGetPackedR32(src) + SkGetPackedR32(dst)),
+                                               SkPinToU8(SkGetPackedG32(src) + SkGetPackedG32(dst)),
+                                               SkPinToU8(SkGetPackedB32(src) + SkGetPackedB32(dst)));
+}
+
+static U8CPU do_mul(U8CPU src, U8CPU dst, unsigned src_scale, unsigned dst_scale)
+{
+       return (src * dst_scale + dst * (SkAlpha255To256(src) + src_scale)) >> 8;
+}
+
+//     kMul_Mode,              //!< clamp [Sa + Da - Sa * Da, Sc * Dc + Sc * (1 - Da) + (1 - Sa) * Dc]
+static SkPMColor mul_modeproc(SkPMColor src, SkPMColor dst)
+{
+       unsigned sa = SkGetPackedA32(src);
+       unsigned src_scale = SkAlpha255To256(255 - sa);
+
+       unsigned da = SkGetPackedA32(dst);
+       unsigned dst_scale = SkAlpha255To256(255 - da);
+
+       return SkPackARGB32(sa + da - SkAlphaMul(SkAlpha255To256(sa), da),
+                                               do_mul(SkGetPackedR32(src), SkGetPackedR32(dst), src_scale, dst_scale),
+                                               do_mul(SkGetPackedG32(src), SkGetPackedG32(dst), src_scale, dst_scale),
+                                               do_mul(SkGetPackedB32(src), SkGetPackedB32(dst), src_scale, dst_scale));
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////
+
+class SkClearXfermode : public SkProcXfermode {
+public:
+       SkClearXfermode() : SkProcXfermode(clear_modeproc) {}
+
+       virtual void xfer32(SkPMColor dst[], const SkPMColor[], int count, const SkAlpha aa[])
+       {
+               SkASSERT(dst && count >= 0);
+
+               if (NULL == aa)
+                       memset(dst, 0, count << 2);
+               else
+               {
+                       for (int i = count - 1; i >= 0; --i)
+                       {
+                               unsigned a = aa[i];
+                               if (a == 0xFF)
+                                       dst[i] = 0;
+                               else if (a != 0)
+                                       dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
+                       }
+               }
+       }
+       virtual void xferA8(SkAlpha dst[], const SkPMColor[], int count, const SkAlpha aa[])
+       {
+               SkASSERT(dst && count >= 0);
+
+               if (NULL == aa)
+                       memset(dst, 0, count);
+               else
+               {
+                       for (int i = count - 1; i >= 0; --i)
+                       {
+                               unsigned a = aa[i];
+                               if (a == 0xFF)
+                                       dst[i] = 0;
+                               else if (a != 0)
+                                       dst[i] = SkToU8(SkAlphaMul(dst[i], SkAlpha255To256(255 - a)));
+                       }
+               }
+       }
+    
+    virtual Factory getFactory() { return CreateProc; }
+    // we have nothing to flatten(), so don't need to override it
+
+private:
+    SkClearXfermode(SkRBuffer& buffer) : SkProcXfermode(buffer) {}
+    
+    static SkFlattenable* CreateProc(SkRBuffer& buffer)
+    {
+        return SkNEW_ARGS(SkClearXfermode, (buffer));
+    }
+};
+
+//////////////////////////////////////////////////////////////////////////////////
+
+class SkSrcXfermode : public SkProcXfermode {
+public:
+       SkSrcXfermode() : SkProcXfermode(src_modeproc) {}
+
+       virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count, const SkAlpha aa[])
+       {
+               SkASSERT(dst && src && count >= 0);
+
+               if (NULL == aa)
+                       memcpy(dst, src, count << 2);
+               else
+               {
+                       for (int i = count - 1; i >= 0; --i)
+                       {
+                               unsigned a = aa[i];
+                               if (a == 0xFF)
+                                       dst[i] = src[i];
+                               else if (a != 0)
+                                       dst[i] = SkFourByteInterp(src[i], dst[i], a);
+                       }
+               }
+       }
+       virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count, const SkAlpha aa[])
+       {
+               SkASSERT(dst && src && count >= 0);
+
+               if (NULL == aa)
+               {
+                       for (int i = count - 1; i >= 0; --i)
+                               dst[i] = SkToU8(SkGetPackedA32(src[i]));
+               }
+               else
+               {
+                       for (int i = count - 1; i >= 0; --i)
+                       {
+                               unsigned a = aa[i];
+                               if (a != 0)
+                               {
+                                       unsigned srcA = SkGetPackedA32(src[i]);
+                                       if (a == 0xFF)
+                                               dst[i] = SkToU8(srcA);
+                                       else
+                                               dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
+                               }
+                       }
+               }
+       }
+    
+    virtual Factory getFactory() { return CreateProc; }
+    // we have nothing to flatten(), so don't need to override it
+
+private:
+    SkSrcXfermode(SkRBuffer& buffer) : SkProcXfermode(buffer) {}
+    
+    static SkFlattenable* CreateProc(SkRBuffer& buffer)
+    {
+        return SkNEW_ARGS(SkSrcXfermode, (buffer));
+    }
+};
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkPorterDuff.h"
+
+static const SkXfermodeProc gPorterDuffModeProcs[] = {
+       clear_modeproc,
+       src_modeproc,
+       dst_modeproc,
+       srcover_modeproc,
+       dstover_modeproc,
+       srcin_modeproc,
+       dstin_modeproc,
+       srcout_modeproc,
+       dstout_modeproc,
+       srcatop_modeproc,
+       dstatop_modeproc,
+       xor_modeproc,
+    darken_modeproc,
+    lighten_modeproc
+};
+
+SkXfermode* SkPorterDuff::CreateXfermode(SkPorterDuff::Mode mode)
+{
+       SkASSERT(SK_ARRAY_COUNT(gPorterDuffModeProcs) == SkPorterDuff::kModeCount);
+       SkASSERT((unsigned)mode < SkPorterDuff::kModeCount);
+
+       switch (mode) {
+       case kClear_Mode:
+               return SkNEW(SkClearXfermode);
+       case kSrc_Mode:
+               return SkNEW(SkSrcXfermode);
+       case kSrcOver_Mode:
+               return NULL;
+       default:
+               return SkNEW_ARGS(SkProcXfermode, (gPorterDuffModeProcs[mode]));
+       }
+}
+
+#ifdef SK_DEBUG
+static void unit_test()
+{
+    for (unsigned a = 0; a <= 255; a++) {
+        for (unsigned c = 0; c <= a; c++) {
+            SkPMColor pm = SkPackARGB32(a, c, c, c);
+            for (unsigned aa = 0; aa <= 255; aa++) {
+                for (unsigned cc = 0; cc <= aa; cc++) {
+                    SkPMColor pm2 = SkPackARGB32(aa, cc, cc, cc);
+                    
+                    for (unsigned i = 0; i < SK_ARRAY_COUNT(gPorterDuffModeProcs); i++) {
+                        gPorterDuffModeProcs[i](pm, pm2);
+                    }
+                }
+            }
+        }
+    }            
+}
+#endif
+
+SkXfermodeProc SkPorterDuff::GetXfermodeProc(Mode mode)
+{
+#ifdef SK_DEBUGx
+    static bool gUnitTest;
+    if (!gUnitTest) {
+        gUnitTest = true;
+        unit_test();
+    }
+#endif
+
+    SkXfermodeProc  proc = NULL;
+
+    if ((unsigned)mode < SkPorterDuff::kModeCount)
+        proc = gPorterDuffModeProcs[mode];
+
+    return proc;
+}
+
diff --git a/libs/graphics/svg/SkSVG.cpp b/libs/graphics/svg/SkSVG.cpp
new file mode 100644 (file)
index 0000000..190957a
--- /dev/null
@@ -0,0 +1,19 @@
+#include "SkSVG.h"
+#include 'SkSVGParser.h"
+
+SkSVG::SkSVG() {
+}
+
+SkSVG::~SkSVG() {
+}
+
+bool SkSVG::decodeStream(SkStream* stream);
+{
+       size_t size = stream->read(nil, 0);
+    SkAutoMalloc    storage(size);
+    char* data = (char*)storage.get();
+       size_t actual = stream->read(data, size);
+    SkASSERT(size == actual);
+       SkSVGParser parser(*fMaker);
+       return parser.parse(data, actual, &fErrorCode, &fErrorLineNumber);
+}
diff --git a/libs/graphics/svg/SkSVGCircle.cpp b/libs/graphics/svg/SkSVGCircle.cpp
new file mode 100644 (file)
index 0000000..e964229
--- /dev/null
@@ -0,0 +1,36 @@
+#include "SkSVGCircle.h"
+#include "SkSVGParser.h"
+#include "SkParse.h"
+#include <stdio.h>
+
+const SkSVGAttribute SkSVGCircle::gAttributes[] = {
+       SVG_ATTRIBUTE(cx),
+       SVG_ATTRIBUTE(cy),
+       SVG_ATTRIBUTE(r)
+};
+
+DEFINE_SVG_INFO(Circle)
+
+void SkSVGCircle::translate(SkSVGParser& parser, bool defState) {
+       parser._startElement("oval");
+       INHERITED::translate(parser, defState);
+       SkScalar cx, cy, r;
+       SkParse::FindScalar(f_cx.c_str(), &cx);
+       SkParse::FindScalar(f_cy.c_str(), &cy);
+       SkParse::FindScalar(f_r.c_str(), &r);
+       SkScalar left, top, right, bottom;
+       left = cx - r;
+       top = cy - r;
+       right = cx + r;
+       bottom = cy + r;
+       char scratch[16];
+       sprintf(scratch, "%g", left);
+       parser._addAttribute("left", scratch);
+       sprintf(scratch, "%g", top);
+       parser._addAttribute("top", scratch);
+       sprintf(scratch, "%g", right);
+       parser._addAttribute("right", scratch);
+       sprintf(scratch, "%g", bottom);
+       parser._addAttribute("bottom", scratch);
+       parser._endElement();
+}
diff --git a/libs/graphics/svg/SkSVGCircle.h b/libs/graphics/svg/SkSVGCircle.h
new file mode 100644 (file)
index 0000000..4535a66
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef SkSVGCircle_DEFINED
+#define SkSVGCircle_DEFINED
+
+#include "SkSVGElements.h"
+
+class SkSVGCircle : public SkSVGElement {
+       DECLARE_SVG_INFO(Circle);
+private:
+       SkString f_cx;
+       SkString f_cy;
+       SkString f_r;
+       typedef SkSVGElement INHERITED;
+};
+
+#endif // SkSVGCircle_DEFINED
diff --git a/libs/graphics/svg/SkSVGClipPath.cpp b/libs/graphics/svg/SkSVGClipPath.cpp
new file mode 100644 (file)
index 0000000..6671921
--- /dev/null
@@ -0,0 +1,31 @@
+#include "SkSVGClipPath.h"
+#include "SkSVGParser.h"
+#include "SkSVGUse.h"
+
+DEFINE_SVG_NO_INFO(ClipPath)
+
+bool SkSVGClipPath::isDef() {
+       return true;
+}
+
+bool SkSVGClipPath::isNotDef() {
+       return false;
+}
+
+void SkSVGClipPath::translate(SkSVGParser& parser, bool defState) {
+       parser._startElement("clip");
+       INHERITED::translate(parser, defState);
+       SkASSERT(fChildren.count() == 1);
+       SkSVGElement* child = *fChildren.begin();
+       SkASSERT(child->getType() == SkSVGType_Use);
+       SkSVGUse* use = (SkSVGUse*) child;
+       SkSVGElement* ref;
+       const char* refStr = &use->f_xlink_href.c_str()[1];
+       SkASSERT(parser.getIDs().find(refStr, &ref));
+       SkASSERT(ref);
+       if (ref->getType() == SkSVGType_Rect) 
+               parser._addAttribute("rectangle", refStr);
+       else
+               parser._addAttribute("path", refStr);
+       parser._endElement();
+}
diff --git a/libs/graphics/svg/SkSVGClipPath.h b/libs/graphics/svg/SkSVGClipPath.h
new file mode 100644 (file)
index 0000000..a06103a
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef SkSVGClipPath_DEFINED
+#define SkSVGClipPath_DEFINED
+
+#include "SkSVGElements.h"
+
+class SkSVGClipPath : public SkSVGElement {
+       DECLARE_SVG_INFO(ClipPath);
+       virtual bool isDef();
+       virtual bool isNotDef();
+private:
+       typedef SkSVGElement INHERITED;
+};
+
+#endif // SkSVGClipPath_DEFINED
diff --git a/libs/graphics/svg/SkSVGDefs.cpp b/libs/graphics/svg/SkSVGDefs.cpp
new file mode 100644 (file)
index 0000000..d0aaef5
--- /dev/null
@@ -0,0 +1,15 @@
+#include "SkSVGDefs.h"
+
+DEFINE_SVG_NO_INFO(Defs)
+
+bool SkSVGDefs::isDef() {
+       return true;
+}
+
+bool SkSVGDefs::isNotDef() {
+       return false;
+}
+
+void SkSVGDefs::translate(SkSVGParser& parser, bool defState) {
+       INHERITED::translate(parser, defState);
+}
diff --git a/libs/graphics/svg/SkSVGDefs.h b/libs/graphics/svg/SkSVGDefs.h
new file mode 100644 (file)
index 0000000..5a4f087
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef SkSVGDefs_DEFINED
+#define SkSVGDefs_DEFINED
+
+#include "SkSVGGroup.h"
+
+class SkSVGDefs : public SkSVGGroup {
+       DECLARE_SVG_INFO(Defs);
+       virtual bool isDef();
+       virtual bool isNotDef();
+private:
+       typedef SkSVGGroup INHERITED;
+};
+
+#endif // SkSVGDefs_DEFINED
diff --git a/libs/graphics/svg/SkSVGElements.cpp b/libs/graphics/svg/SkSVGElements.cpp
new file mode 100644 (file)
index 0000000..0848436
--- /dev/null
@@ -0,0 +1,79 @@
+#include "SkSVGElements.h"
+#include "SkSVGParser.h"
+
+SkSVGBase::~SkSVGBase() {
+}
+
+void SkSVGBase::addAttribute(SkSVGParser& parser, int attrIndex, 
+               const char* attrValue, size_t attrLength) {
+       SkString* first = (SkString*) ((char*) this + sizeof(SkSVGElement));
+       first += attrIndex;
+       first->set(attrValue, attrLength);
+}
+
+
+SkSVGElement::SkSVGElement() : fParent(nil), fIsDef(false), fIsNotDef(true) {
+}
+
+SkSVGElement::~SkSVGElement() {
+}
+
+SkSVGElement* SkSVGElement::getGradient() {
+       return nil;
+}
+
+bool SkSVGElement::isGroupParent() {
+       SkSVGElement* parent = fParent;
+       while (parent) {
+               if (parent->getType() != SkSVGType_G)
+                       return false;
+               parent = parent->fParent;
+       }
+       return true;
+}
+
+bool SkSVGElement::isDef() {
+       return isGroupParent() == false ? fParent->isDef() : fIsDef;
+}
+
+bool SkSVGElement::isFlushable() {
+       return true;
+}
+
+bool SkSVGElement::isGroup() {
+       return false;
+}
+
+bool SkSVGElement::isNotDef() {
+       return isGroupParent() == false ? fParent->isNotDef() : fIsNotDef;
+}
+
+bool SkSVGElement::onEndElement(SkSVGParser& parser) {
+       if (f_id.size() > 0)
+               parser.getIDs().set(f_id.c_str(), f_id.size(), this);
+       return false;
+}
+
+bool SkSVGElement::onStartElement(SkSVGElement* child) {
+       *fChildren.append() = child;
+       return false;
+}
+
+void SkSVGElement::translate(SkSVGParser& parser, bool) {
+       if (f_id.size() > 0)
+               SVG_ADD_ATTRIBUTE(id);
+}
+
+void SkSVGElement::setIsDef() {
+       fIsDef = isDef();
+}
+
+//void SkSVGElement::setIsNotDef() {
+//     fIsNotDef = isNotDef();
+//}
+
+void SkSVGElement::write(SkSVGParser& , SkString& ) {
+       SkASSERT(0); 
+}
+
+
diff --git a/libs/graphics/svg/SkSVGElements.h b/libs/graphics/svg/SkSVGElements.h
new file mode 100644 (file)
index 0000000..8fe7814
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef SkSVGElements_DEFINED
+#define SkSVGElements_DEFINED
+
+#include "SkSVGPaintState.h"
+#include "SkSVGTypes.h"
+#include "SkTDArray.h"
+
+class SkSVGParser;
+
+#define DECLARE_SVG_INFO(_type) \
+public: \
+       virtual ~SkSVG##_type(); \
+       static const SkSVGAttribute gAttributes[]; \
+       virtual int getAttributes(const SkSVGAttribute** attrPtr); \
+       virtual SkSVGTypes getType() const; \
+       virtual void translate(SkSVGParser& parser, bool defState); \
+       typedef SkSVG##_type BASE_CLASS
+
+#define DEFINE_SVG_INFO(_type) \
+       SkSVG##_type::~SkSVG##_type() {} \
+       int SkSVG##_type::getAttributes(const SkSVGAttribute** attrPtr) { \
+               *attrPtr = gAttributes; \
+               return SK_ARRAY_COUNT(gAttributes); \
+       } \
+       SkSVGTypes SkSVG##_type::getType() const { return SkSVGType_##_type; }
+
+#define DEFINE_SVG_NO_INFO(_type) \
+       SkSVG##_type::~SkSVG##_type() {} \
+       int SkSVG##_type::getAttributes(const SkSVGAttribute** ) { return 0; } \
+       SkSVGTypes SkSVG##_type::getType() const { return SkSVGType_##_type; }
+
+
+struct SkSVGTypeName {
+       const char* fName;
+       SkSVGTypes fType;
+};
+
+class SkSVGElement : public SkSVGBase {
+public:
+       SkSVGElement();
+       virtual ~SkSVGElement();
+       virtual SkSVGElement* getGradient();
+       virtual SkSVGTypes getType() const  = 0;
+       virtual bool isDef();
+       virtual bool isFlushable();
+       virtual bool isGroup();
+       virtual bool isNotDef();
+       virtual bool onEndElement(SkSVGParser& parser);
+       virtual bool onStartElement(SkSVGElement* child);
+       void setIsDef();
+//     void setIsNotDef();
+       virtual void translate(SkSVGParser& parser, bool defState);
+       virtual void write(SkSVGParser& , SkString& color);
+       SkString f_id;
+       SkSVGPaint fPaintState;
+       SkTDArray<SkSVGElement*> fChildren;
+       SkSVGElement* fParent;
+       bool fIsDef;
+       bool fIsNotDef;
+private:
+       bool isGroupParent();
+};
+
+#endif // SkSVGElements_DEFINED
diff --git a/libs/graphics/svg/SkSVGEllipse.cpp b/libs/graphics/svg/SkSVGEllipse.cpp
new file mode 100644 (file)
index 0000000..a4dfd02
--- /dev/null
@@ -0,0 +1,38 @@
+#include "SkSVGEllipse.h"
+#include "SkSVGParser.h"
+#include "SkParse.h"
+#include <stdio.h>
+
+const SkSVGAttribute SkSVGEllipse::gAttributes[] = {
+       SVG_ATTRIBUTE(cx),
+       SVG_ATTRIBUTE(cy),
+       SVG_ATTRIBUTE(rx),
+       SVG_ATTRIBUTE(ry)
+};
+
+DEFINE_SVG_INFO(Ellipse)
+
+void SkSVGEllipse::translate(SkSVGParser& parser, bool defState) {
+       parser._startElement("oval");
+       INHERITED::translate(parser, defState);
+       SkScalar cx, cy, rx, ry;
+       SkParse::FindScalar(f_cx.c_str(), &cx);
+       SkParse::FindScalar(f_cy.c_str(), &cy);
+       SkParse::FindScalar(f_rx.c_str(), &rx);
+       SkParse::FindScalar(f_ry.c_str(), &ry);
+       SkScalar left, top, right, bottom;
+       left = cx - rx;
+       top = cy - ry;
+       right = cx + rx;
+       bottom = cy + ry;
+       char scratch[16];
+       sprintf(scratch, "%g", left);
+       parser._addAttribute("left", scratch);
+       sprintf(scratch, "%g", top);
+       parser._addAttribute("top", scratch);
+       sprintf(scratch, "%g", right);
+       parser._addAttribute("right", scratch);
+       sprintf(scratch, "%g", bottom);
+       parser._addAttribute("bottom", scratch);
+       parser._endElement();
+}
diff --git a/libs/graphics/svg/SkSVGEllipse.h b/libs/graphics/svg/SkSVGEllipse.h
new file mode 100644 (file)
index 0000000..b822e4d
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef SkSVGEllipse_DEFINED
+#define SkSVGEllipse_DEFINED
+
+#include "SkSVGElements.h"
+
+class SkSVGEllipse : public SkSVGElement {
+       DECLARE_SVG_INFO(Ellipse);
+private:
+       SkString f_cx;
+       SkString f_cy;
+       SkString f_rx;
+       SkString f_ry;
+       typedef SkSVGElement INHERITED;
+};
+
+#endif // SkSVGEllipse_DEFINED
diff --git a/libs/graphics/svg/SkSVGFeColorMatrix.cpp b/libs/graphics/svg/SkSVGFeColorMatrix.cpp
new file mode 100644 (file)
index 0000000..46225f8
--- /dev/null
@@ -0,0 +1,15 @@
+#include "SkSVGFeColorMatrix.h"
+#include "SkSVGParser.h"
+
+const SkSVGAttribute SkSVGFeColorMatrix::gAttributes[] = {
+       SVG_LITERAL_ATTRIBUTE(color-interpolation-filters, f_color_interpolation_filters),
+       SVG_ATTRIBUTE(result),
+       SVG_ATTRIBUTE(type),
+       SVG_ATTRIBUTE(values)
+};
+
+DEFINE_SVG_INFO(FeColorMatrix)
+
+void SkSVGFeColorMatrix::translate(SkSVGParser& parser, bool defState) {
+       INHERITED::translate(parser, defState);
+}
diff --git a/libs/graphics/svg/SkSVGFeColorMatrix.h b/libs/graphics/svg/SkSVGFeColorMatrix.h
new file mode 100644 (file)
index 0000000..408c501
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef SkSVGFeColorMatrix_DEFINED
+#define SkSVGFeColorMatrix_DEFINED
+
+#include "SkSVGElements.h"
+
+class SkSVGFeColorMatrix : public SkSVGElement {
+       DECLARE_SVG_INFO(FeColorMatrix);
+protected:
+       SkString f_color_interpolation_filters;
+       SkString f_result;
+       SkString f_type;
+       SkString f_values;
+private:
+       typedef SkSVGElement INHERITED;
+};
+
+#endif // SkSVGFeColorMatrix_DEFINED
diff --git a/libs/graphics/svg/SkSVGFilter.cpp b/libs/graphics/svg/SkSVGFilter.cpp
new file mode 100644 (file)
index 0000000..0463ee1
--- /dev/null
@@ -0,0 +1,16 @@
+#include "SkSVGFilter.h"
+#include "SkSVGParser.h"
+
+const SkSVGAttribute SkSVGFilter::gAttributes[] = {
+       SVG_ATTRIBUTE(filterUnits),
+       SVG_ATTRIBUTE(height),
+       SVG_ATTRIBUTE(width),
+       SVG_ATTRIBUTE(x),
+       SVG_ATTRIBUTE(y)
+};
+
+DEFINE_SVG_INFO(Filter)
+
+void SkSVGFilter::translate(SkSVGParser& parser, bool defState) {
+//     INHERITED::translate(parser, defState);
+}
diff --git a/libs/graphics/svg/SkSVGFilter.h b/libs/graphics/svg/SkSVGFilter.h
new file mode 100644 (file)
index 0000000..71bb45f
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef SkSVGFilter_DEFINED
+#define SkSVGFilter_DEFINED
+
+#include "SkSVGElements.h"
+
+class SkSVGFilter : public SkSVGElement {
+       DECLARE_SVG_INFO(Filter);
+protected:
+       SkString f_filterUnits;
+       SkString f_height;
+       SkString f_width;
+       SkString f_x;
+       SkString f_y;
+private:
+       typedef SkSVGElement INHERITED;
+};
+
+#endif // SkSVGFilter_DEFINED
\ No newline at end of file
diff --git a/libs/graphics/svg/SkSVGG.cpp b/libs/graphics/svg/SkSVGG.cpp
new file mode 100644 (file)
index 0000000..cf45054
--- /dev/null
@@ -0,0 +1,7 @@
+#include "SkSVGG.h"
+
+DEFINE_SVG_NO_INFO(G)
+
+void SkSVGG::translate(SkSVGParser& parser, bool defState) {
+       INHERITED::translate(parser, defState);
+}
diff --git a/libs/graphics/svg/SkSVGG.h b/libs/graphics/svg/SkSVGG.h
new file mode 100644 (file)
index 0000000..3e9e5c9
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef SkSVGG_DEFINED
+#define SkSVGG_DEFINED
+
+#include "SkSVGGroup.h"
+
+class SkSVGG : public SkSVGGroup {
+       DECLARE_SVG_INFO(G);
+private:
+       typedef SkSVGGroup INHERITED;
+};
+
+#endif // SkSVGG_DEFINED
diff --git a/libs/graphics/svg/SkSVGGradient.cpp b/libs/graphics/svg/SkSVGGradient.cpp
new file mode 100644 (file)
index 0000000..ba64c16
--- /dev/null
@@ -0,0 +1,106 @@
+#include "SkSVGGradient.h"
+#include "SkSVGParser.h"
+#include "SkSVGStop.h"
+
+SkSVGGradient::SkSVGGradient() {
+}
+
+SkSVGElement* SkSVGGradient::getGradient() {
+       return this;
+}
+
+bool SkSVGGradient::isDef() {
+       return true;
+}
+
+bool SkSVGGradient::isNotDef() {
+       return false;
+}
+
+void SkSVGGradient::translate(SkSVGParser& parser, bool defState) {
+       INHERITED::translate(parser, defState);
+       // !!! no support for 'objectBoundingBox' yet
+       bool first = true;
+       bool addedFirst = false;
+       bool addedLast = false;
+       SkString offsets("[");
+       SkString* lastOffset = nil;
+       for (SkSVGElement** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               SkASSERT((*ptr)->getType() == SkSVGType_Stop);
+               SkSVGStop* stop = (SkSVGStop*) *ptr;
+               if (first && stop->f_offset.equals("0") == false) {
+                       addedFirst = true;
+                       offsets.append("0,");
+               }
+               SkString* thisOffset = &stop->f_offset;
+               if (lastOffset && thisOffset->equals(*lastOffset)) {
+                       if (thisOffset->equals("1")) {
+                               offsets.remove(offsets.size() - 2, 2);
+                               offsets.append(".999,");
+                       } else {
+                               SkASSERT(0); // !!! need to write this case
+                       }
+               }
+               offsets.append(*thisOffset);
+               if (ptr == fChildren.end() - 1) { // last
+                       if (stop->f_offset.equals("1") == false) {
+                               offsets.append(",1");
+                               addedLast = true;
+                       }
+               } else
+                       offsets.appendUnichar(',');
+               first = false;
+               lastOffset = thisOffset;
+       }
+       offsets.appendUnichar(']');
+       parser._addAttribute("offsets", offsets);
+       if (addedFirst)
+               parser.translate(*fChildren.begin(), defState);
+       for (SkSVGElement** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++)
+               parser.translate(*ptr, defState);
+       if (addedLast)
+               parser.translate(*(fChildren.end() - 1), defState);
+}
+
+void SkSVGGradient::translateGradientUnits(SkString& units) {
+       // !!! no support for 'objectBoundingBox' yet
+       SkASSERT(strcmp(units.c_str(), "userSpaceOnUse") == 0);
+}
+
+void SkSVGGradient::write(SkSVGParser& parser, SkString& baseColor) {
+       if (baseColor.c_str()[0] != '#')
+               return;
+       SkSVGPaint* saveHead = parser.fHead;
+       parser.fHead = &fPaintState;
+       parser.fSuppressPaint = true;
+       SkString originalID(f_id);
+       f_id.set("mask"); // write out gradient named given name + color (less initial #)
+       f_id.append(baseColor.c_str() + 1); 
+       SkString originalColors;
+       for (SkSVGElement** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               SkSVGStop* colorElement = (SkSVGStop*) *ptr;
+               SkString& color = colorElement->fPaintState.f_stopColor;
+               originalColors.append(color);
+               originalColors.appendUnichar(',');
+               SkASSERT(color.c_str()[0] == '#');
+               SkString replacement;
+               replacement.set("0x");
+               replacement.append(color.c_str() + 1, 2); // add stop colors using given color, turning existing stop color into alpha
+               SkASSERT(baseColor.c_str()[0] == '#');
+               SkASSERT(baseColor.size() == 7);
+               replacement.append(baseColor.c_str() + 1);
+               color.set(replacement);
+       }
+       translate(parser, true);
+       const char* originalPtr = originalColors.c_str(); // restore original gradient values
+       for (SkSVGElement** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               SkSVGStop* color = (SkSVGStop*) *ptr;
+               const char* originalEnd = strchr(originalPtr, ',');
+               color->fPaintState.f_stopColor.set(originalPtr, originalEnd - originalPtr);
+               originalPtr = originalEnd + 1;
+       }
+       f_id.set(originalID);
+       parser.fSuppressPaint = false;
+       parser.fHead = saveHead;
+}
+
diff --git a/libs/graphics/svg/SkSVGGradient.h b/libs/graphics/svg/SkSVGGradient.h
new file mode 100644 (file)
index 0000000..25421ce
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef SkSVGGradient_DEFINED
+#define SkSVGGradient_DEFINED
+
+#include "SkSVGElements.h"
+
+class SkSVGGradient : public SkSVGElement {
+public:
+       SkSVGGradient();
+       virtual SkSVGElement* getGradient();
+       virtual bool isDef();
+       virtual bool isNotDef();
+       virtual void write(SkSVGParser& , SkString& color);
+protected:
+       void translate(SkSVGParser& , bool defState);
+       void translateGradientUnits(SkString& units);
+private:
+       typedef SkSVGElement INHERITED;
+};
+
+#endif // SkSVGGradient_DEFINED
diff --git a/libs/graphics/svg/SkSVGGroup.cpp b/libs/graphics/svg/SkSVGGroup.cpp
new file mode 100644 (file)
index 0000000..a72dd8a
--- /dev/null
@@ -0,0 +1,36 @@
+#include "SkSVGGroup.h"
+#include "SkSVGParser.h"
+
+SkSVGGroup::SkSVGGroup() {
+       fIsNotDef = false;
+}
+
+SkSVGElement* SkSVGGroup::getGradient() {
+       for (SkSVGElement** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               SkSVGElement* result = (*ptr)->getGradient();
+               if (result != nil)
+                       return result;
+       }
+       return nil;
+}
+
+bool SkSVGGroup::isDef() {
+       return fParent ? fParent->isDef() : false;
+}
+
+bool SkSVGGroup::isFlushable() {
+       return false;
+}
+
+bool SkSVGGroup::isGroup() {
+       return true;
+}
+
+bool SkSVGGroup::isNotDef() {
+       return fParent ? fParent->isNotDef() : false;
+}
+
+void SkSVGGroup::translate(SkSVGParser& parser, bool defState) {
+       for (SkSVGElement** ptr = fChildren.begin(); ptr < fChildren.end(); ptr++)
+               parser.translate(*ptr, defState);
+}
diff --git a/libs/graphics/svg/SkSVGGroup.h b/libs/graphics/svg/SkSVGGroup.h
new file mode 100644 (file)
index 0000000..ff4c342
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef SkSVGGroup_DEFINED
+#define SkSVGGroup_DEFINED
+
+#include "SkSVGElements.h"
+
+class SkSVGGroup : public SkSVGElement {
+public:
+       SkSVGGroup();
+       virtual SkSVGElement* getGradient();
+       virtual bool isDef();
+       virtual bool isFlushable();
+       virtual bool isGroup();
+       virtual bool isNotDef();
+       void translate(SkSVGParser& , bool defState);
+private:
+       typedef SkSVGElement INHERITED;
+};
+
+#endif // SkSVGGroup_DEFINED
diff --git a/libs/graphics/svg/SkSVGImage.cpp b/libs/graphics/svg/SkSVGImage.cpp
new file mode 100644 (file)
index 0000000..bcf8a4f
--- /dev/null
@@ -0,0 +1,35 @@
+#include "SkSVGImage.h"
+#include "SkSVGParser.h"
+
+const SkSVGAttribute SkSVGImage::gAttributes[] = {
+       SVG_ATTRIBUTE(height),
+       SVG_ATTRIBUTE(width),
+       SVG_ATTRIBUTE(x),
+       SVG_LITERAL_ATTRIBUTE(xlink:href, f_xlink_href),
+       SVG_ATTRIBUTE(y)
+};
+
+DEFINE_SVG_INFO(Image)
+
+void SkSVGImage::translate(SkSVGParser& parser, bool defState) {
+       parser._startElement("image");
+       INHERITED::translate(parser, defState);
+       SVG_ADD_ATTRIBUTE(x);
+       SVG_ADD_ATTRIBUTE(y);
+//     SVG_ADD_ATTRIBUTE(width);
+//     SVG_ADD_ATTRIBUTE(height);
+       translateImage(parser);
+       parser._endElement();
+}
+
+void SkSVGImage::translateImage(SkSVGParser& parser) {
+       SkASSERT(f_xlink_href.size() > 0);
+       const char* data = f_xlink_href.c_str();
+       SkASSERT(strncmp(data, "data:image/", 11) == 0);
+       data += 11;
+       SkASSERT(strncmp(data, "png;", 4) == 0 || strncmp(data, "jpeg;", 5) == 0);
+       data = strchr(data, ';');
+       SkASSERT(strncmp(data, ";base64,", 8) == 0);
+       data += 8;
+       parser._addAttribute("base64", data);
+}
diff --git a/libs/graphics/svg/SkSVGImage.h b/libs/graphics/svg/SkSVGImage.h
new file mode 100644 (file)
index 0000000..3a0a2a5
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef SkSVGImage_DEFINED
+#define SkSVGImage_DEFINED
+
+#include "SkSVGElements.h"
+
+class SkSVGImage : public SkSVGElement {
+public:
+       DECLARE_SVG_INFO(Image);
+private:
+       void translateImage(SkSVGParser& parser);
+       SkString f_height;
+       SkString f_width;
+       SkString f_x;
+       SkString f_xlink_href;
+       SkString f_y;
+       typedef SkSVGElement INHERITED;
+};
+
+#endif // SkSVGImage_DEFINED
diff --git a/libs/graphics/svg/SkSVGLine.cpp b/libs/graphics/svg/SkSVGLine.cpp
new file mode 100644 (file)
index 0000000..5a5e978
--- /dev/null
@@ -0,0 +1,21 @@
+#include "SkSVGLine.h"
+#include "SkSVGParser.h"
+
+const SkSVGAttribute SkSVGLine::gAttributes[] = {
+       SVG_ATTRIBUTE(x1),
+       SVG_ATTRIBUTE(x2),
+       SVG_ATTRIBUTE(y1),
+       SVG_ATTRIBUTE(y2)
+};
+
+DEFINE_SVG_INFO(Line)
+
+void SkSVGLine::translate(SkSVGParser& parser, bool defState) {
+       parser._startElement("line");
+       INHERITED::translate(parser, defState);
+       SVG_ADD_ATTRIBUTE(x1);
+       SVG_ADD_ATTRIBUTE(y1);
+       SVG_ADD_ATTRIBUTE(x2);
+       SVG_ADD_ATTRIBUTE(y2);
+       parser._endElement();
+}
diff --git a/libs/graphics/svg/SkSVGLine.h b/libs/graphics/svg/SkSVGLine.h
new file mode 100644 (file)
index 0000000..f7a665b
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef SkSVGLine_DEFINED
+#define SkSVGLine_DEFINED
+
+#include "SkSVGElements.h"
+
+class SkSVGLine : public SkSVGElement {
+       DECLARE_SVG_INFO(Line);
+private:
+       SkString f_x1;
+       SkString f_x2;
+       SkString f_y1;
+       SkString f_y2;
+       typedef SkSVGElement INHERITED;
+};
+
+#endif // SkSVGLine_DEFINED
diff --git a/libs/graphics/svg/SkSVGLinearGradient.cpp b/libs/graphics/svg/SkSVGLinearGradient.cpp
new file mode 100644 (file)
index 0000000..69f4823
--- /dev/null
@@ -0,0 +1,35 @@
+#include "SkSVGLinearGradient.h"
+#include "SkSVGParser.h"
+
+const SkSVGAttribute SkSVGLinearGradient::gAttributes[] = {
+       SVG_ATTRIBUTE(gradientTransform),
+       SVG_ATTRIBUTE(gradientUnits),
+       SVG_ATTRIBUTE(x1),
+       SVG_ATTRIBUTE(x2),
+       SVG_ATTRIBUTE(y1),
+       SVG_ATTRIBUTE(y2)
+};
+
+DEFINE_SVG_INFO(LinearGradient)
+
+void SkSVGLinearGradient::translate(SkSVGParser& parser, bool defState) {
+       if (fMatrixID.size() == 0)
+               parser.translateMatrix(f_gradientTransform, &fMatrixID);
+       parser._startElement("linearGradient");
+       if (fMatrixID.size() > 0)
+               parser._addAttribute("matrix", fMatrixID);
+       INHERITED::translateGradientUnits(f_gradientUnits);
+       SkString points;
+       points.appendUnichar('[');
+       points.append(f_x1);
+       points.appendUnichar(',');
+       points.append(f_y1);
+       points.appendUnichar(',');
+       points.append(f_x2);
+       points.appendUnichar(',');
+       points.append(f_y2);
+       points.appendUnichar(']');
+       parser._addAttribute("points", points.c_str());
+       INHERITED::translate(parser, defState);
+       parser._endElement();
+}
diff --git a/libs/graphics/svg/SkSVGLinearGradient.h b/libs/graphics/svg/SkSVGLinearGradient.h
new file mode 100644 (file)
index 0000000..fac7aa3
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef SkSVGLinearGradient_DEFINED
+#define SkSVGLinearGradient_DEFINED
+
+#include "SkSVGGradient.h"
+
+class SkSVGLinearGradient : public SkSVGGradient {
+       DECLARE_SVG_INFO(LinearGradient);
+private:
+       SkString f_gradientTransform;
+       SkString f_gradientUnits;
+       SkString f_x1;
+       SkString f_x2;
+       SkString f_y1;
+       SkString f_y2;
+       SkString fMatrixID;
+       typedef SkSVGGradient INHERITED;
+};
+
+#endif // SkSVGLinearGradient_DEFINED
diff --git a/libs/graphics/svg/SkSVGMask.cpp b/libs/graphics/svg/SkSVGMask.cpp
new file mode 100644 (file)
index 0000000..cb029d4
--- /dev/null
@@ -0,0 +1,24 @@
+#include "SkSVGMask.h"
+#include "SkSVGParser.h"
+
+const SkSVGAttribute SkSVGMask::gAttributes[] = {
+       SVG_ATTRIBUTE(height),
+       SVG_ATTRIBUTE(maskUnits),
+       SVG_ATTRIBUTE(width),
+       SVG_ATTRIBUTE(x),
+       SVG_ATTRIBUTE(y)
+};
+
+DEFINE_SVG_INFO(Mask)
+
+bool SkSVGMask::isDef() {
+       return false;
+}
+
+bool SkSVGMask::isNotDef() {
+       return false;
+}
+
+void SkSVGMask::translate(SkSVGParser& parser, bool defState) {
+       INHERITED::translate(parser, defState);
+}
diff --git a/libs/graphics/svg/SkSVGMask.h b/libs/graphics/svg/SkSVGMask.h
new file mode 100644 (file)
index 0000000..632061e
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef SkSVGMask_DEFINED
+#define SkSVGMask_DEFINED
+
+#include "SkSVGGroup.h"
+
+class SkSVGMask : public SkSVGGroup {
+       DECLARE_SVG_INFO(Mask);
+       virtual bool isDef();
+       virtual bool isNotDef();
+protected:
+       SkString f_height;
+       SkString f_maskUnits;
+       SkString f_width;
+       SkString f_x;
+       SkString f_y;
+private:
+       typedef SkSVGGroup INHERITED;
+};
+
+#endif // SkSVGMask_DEFINED
diff --git a/libs/graphics/svg/SkSVGMetadata.cpp b/libs/graphics/svg/SkSVGMetadata.cpp
new file mode 100644 (file)
index 0000000..3dd8e35
--- /dev/null
@@ -0,0 +1,15 @@
+#include "SkSVGMetadata.h"
+#include "SkSVGParser.h"
+
+DEFINE_SVG_NO_INFO(Metadata)
+
+bool SkSVGMetadata::isDef() {
+       return false;
+}
+
+bool SkSVGMetadata::isNotDef() {
+       return false;
+}
+
+void SkSVGMetadata::translate(SkSVGParser& parser, bool defState) {
+}
diff --git a/libs/graphics/svg/SkSVGMetadata.h b/libs/graphics/svg/SkSVGMetadata.h
new file mode 100644 (file)
index 0000000..c8d0232
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef SkSVGMetadata_DEFINED
+#define SkSVGMetadata_DEFINED
+
+#include "SkSVGElements.h"
+
+class SkSVGMetadata : public SkSVGElement {
+       DECLARE_SVG_INFO(Metadata);
+       virtual bool isDef();
+       virtual bool isNotDef();
+private:
+       typedef SkSVGElement INHERITED;
+};
+
+#endif // SkSVGMetadata_DEFINED
diff --git a/libs/graphics/svg/SkSVGPaintState.cpp b/libs/graphics/svg/SkSVGPaintState.cpp
new file mode 100644 (file)
index 0000000..50ba21d
--- /dev/null
@@ -0,0 +1,446 @@
+#include "SkSVGPaintState.h"
+#include "SkSVGElements.h"
+#include "SkSVGParser.h"
+#include "SkParse.h"
+
+SkSVGAttribute SkSVGPaint::gAttributes[] = {
+       SVG_LITERAL_ATTRIBUTE(clip-path, f_clipPath),
+       SVG_LITERAL_ATTRIBUTE(clip-rule, f_clipRule),
+       SVG_LITERAL_ATTRIBUTE(enable-background, f_enableBackground),
+       SVG_ATTRIBUTE(fill),
+       SVG_LITERAL_ATTRIBUTE(fill-rule, f_fillRule),
+       SVG_ATTRIBUTE(filter),
+       SVG_LITERAL_ATTRIBUTE(font-family, f_fontFamily),
+       SVG_LITERAL_ATTRIBUTE(font-size, f_fontSize),
+       SVG_LITERAL_ATTRIBUTE(letter-spacing, f_letterSpacing),
+       SVG_ATTRIBUTE(mask),
+       SVG_ATTRIBUTE(opacity),
+       SVG_LITERAL_ATTRIBUTE(stop-color, f_stopColor),
+       SVG_LITERAL_ATTRIBUTE(stop-opacity, f_stopOpacity),
+       SVG_ATTRIBUTE(stroke),
+       SVG_LITERAL_ATTRIBUTE(stroke-dasharray, f_strokeDasharray),
+       SVG_LITERAL_ATTRIBUTE(stroke-linecap, f_strokeLinecap),
+       SVG_LITERAL_ATTRIBUTE(stroke-linejoin, f_strokeLinejoin),
+       SVG_LITERAL_ATTRIBUTE(stroke-miterlimit, f_strokeMiterlimit),
+       SVG_LITERAL_ATTRIBUTE(stroke-width, f_strokeWidth),
+       SVG_ATTRIBUTE(style),
+       SVG_ATTRIBUTE(transform)
+};
+
+const int SkSVGPaint::kAttributesSize = SK_ARRAY_COUNT(SkSVGPaint::gAttributes);
+
+SkSVGPaint::SkSVGPaint() : fNext(nil) {
+}
+
+SkString* SkSVGPaint::operator[](int index) {
+       SkASSERT(index >= 0);
+       SkASSERT(index < &fTerminal - &fInitial);
+       SkASSERT(&fTerminal - &fInitial == kTerminal - kInitial);
+       SkString* result = &fInitial + index + 1;
+       return result;
+}
+
+void SkSVGPaint::addAttribute(SkSVGParser& parser, int attrIndex, 
+               const char* attrValue, size_t attrLength) {
+       SkString* attr = (*this)[attrIndex];
+       switch(attrIndex) {
+               case kClipPath:
+               case kClipRule:
+               case kEnableBackground:
+               case kFill:
+               case kFillRule:
+               case kFilter:
+               case kFontFamily:
+               case kFontSize:
+               case kLetterSpacing:
+               case kMask:
+               case kOpacity:
+               case kStopColor:
+               case kStopOpacity:
+               case kStroke:
+               case kStroke_Dasharray:
+               case kStroke_Linecap:
+               case kStroke_Linejoin:
+               case kStroke_Miterlimit:
+               case kStroke_Width:
+               case kTransform:
+                       attr->set(attrValue, attrLength);
+                       return;
+               case kStyle: {
+                       // iterate through colon / semi-colon delimited pairs
+                       int pairs = SkParse::Count(attrValue, ';');
+                       const char* attrEnd = attrValue + attrLength;
+                       do {
+                               const char* end = strchr(attrValue, ';');
+                               if (end == nil)
+                                       end = attrEnd;
+                               const char* delimiter = strchr(attrValue, ':');
+                               SkASSERT(delimiter != 0 && delimiter < end);
+                               int index = parser.findAttribute(this, attrValue, (int) (delimiter - attrValue), true);
+                               SkASSERT(index >= 0);
+                               delimiter++;
+                               addAttribute(parser, index, delimiter, (int) (end - delimiter));
+                               attrValue = end + 1;
+                       } while (--pairs);
+                       return;
+                       }
+               default:
+                       SkASSERT(0);
+       }
+}
+
+bool SkSVGPaint::flush(SkSVGParser& parser, bool isFlushable, bool isDef) {
+       SkSVGPaint current;
+       SkSVGPaint* walking = parser.fHead;
+       int index;
+       while (walking != nil) {
+               for (index = kInitial + 1; index < kTerminal; index++) {
+                       SkString* lastAttr = (*walking)[index];
+                       if (lastAttr->size() == 0)
+                               continue;
+                       if (current[index]->size() > 0)
+                               continue;
+                       current[index]->set(*lastAttr);
+               }
+               walking = walking->fNext;
+       }
+       bool paintChanged = false;
+       SkSVGPaint& lastState = parser.fLastFlush;
+       if (isFlushable == false) {
+               if (isDef == true) {
+                       if (current.f_mask.size() > 0 && current.f_mask.equals(lastState.f_mask) == false) {
+                               SkSVGElement* found;
+                               const char* idStart = strchr(current.f_mask.c_str(), '#');
+                               SkASSERT(idStart);
+                               SkString id(idStart + 1, strlen(idStart) - 2);
+                               bool itsFound = parser.fIDs.find(id.c_str(), &found);
+                               SkASSERT(itsFound);
+                               SkSVGElement* gradient = found->getGradient();
+                               if (gradient) {
+                                       gradient->write(parser, current.f_fill);
+                                       gradient->write(parser, current.f_stroke);
+                               }
+                       }
+               }
+               goto setLast;
+       }
+       {
+               bool changed[kTerminal];
+               memset(changed, 0, sizeof(changed));
+               for (index = kInitial + 1; index < kTerminal; index++) {
+                       if (index == kTransform || index == kClipPath || index == kStopColor || index == kStopOpacity ||
+                                       index == kClipRule || index == kFillRule)
+                               continue;
+                       SkString* lastAttr = lastState[index];
+                       SkString* currentAttr = current[index];
+                       paintChanged |= changed[index] = lastAttr->equals(*currentAttr) == false;
+               }
+               if (paintChanged) {
+                       if (current.f_mask.size() > 0) {
+                               if (current.f_fill.equals("none") == false && strncmp(current.f_fill.c_str(), "url(#", 5) != 0) {
+                                       SkASSERT(current.f_fill.c_str()[0] == '#');
+                                       SkString replacement("url(#mask");
+                                       replacement.append(current.f_fill.c_str() + 1);
+                                       replacement.appendUnichar(')');
+                                       current.f_fill.set(replacement);
+                               }
+                               if (current.f_stroke.equals("none") == false && strncmp(current.f_stroke.c_str(), "url(#", 5) != 0) {
+                                       SkASSERT(current.f_stroke.c_str()[0] == '#');
+                                       SkString replacement("url(#mask");
+                                       replacement.append(current.f_stroke.c_str() + 1);
+                                       replacement.appendUnichar(')');
+                                       current.f_stroke.set(replacement);
+                               }
+                       }
+                       if (current.f_fill.equals("none") && current.f_stroke.equals("none"))
+                               current.f_opacity.set("0");
+                       if (parser.fSuppressPaint == false) {
+                               parser._startElement("paint");
+                               bool success = writeChangedAttributes(parser, current, changed);
+                               if (success == false)
+                                       return paintChanged;
+                               success = writeChangedElements(parser, current, changed);
+                               if (success == false)
+                                       return paintChanged;
+                               parser._endElement(); // paint
+                       }
+               }
+       }
+setLast:
+       for (index = kInitial + 1; index < kTerminal; index++) {
+               SkString* lastAttr = lastState[index];
+               SkString* currentAttr = current[index];
+               lastAttr->set(*currentAttr);
+       }
+       return paintChanged;
+}
+
+int SkSVGPaint::getAttributes(const SkSVGAttribute** attrPtr) {
+       *attrPtr = gAttributes;
+       return kAttributesSize;
+}
+
+void SkSVGPaint::setSave(SkSVGParser& parser) {
+       SkTDArray<SkString*> clips;
+       SkSVGPaint* walking = parser.fHead;
+       int index;
+       SkMatrix sum;
+       sum.reset();
+       while (walking != nil) {
+               for (index = kInitial + 1; index < kTerminal; index++) {
+                       SkString* lastAttr = (*walking)[index];
+                       if (lastAttr->size() == 0)
+                               continue;
+                       if (index == kTransform) {
+                               const char* str = lastAttr->c_str();
+                               SkASSERT(strncmp(str, "matrix(", 7) == 0);
+                               str += 6;
+                               const char* strEnd = strrchr(str, ')');
+                               SkASSERT(strEnd != nil);
+                               SkString mat(str, strEnd - str);
+                               SkSVGParser::ConvertToArray(mat);
+                               SkScalar values[6];
+                               SkParse::FindScalars(mat.c_str() + 1, values, 6);
+                               SkMatrix matrix;
+                               matrix.reset();
+                               matrix.setScaleX(values[0]);
+                               matrix.setSkewY(values[1]);
+                               matrix.setSkewX(values[2]);
+                               matrix.setScaleY(values[3]);
+                               matrix.setTranslateX(values[4]);
+                               matrix.setTranslateY(values[5]);
+                               sum.setConcat(matrix, sum);
+                               continue;
+                       }
+                       if ( index == kClipPath) 
+                               *clips.insert(0) = lastAttr;
+               }
+               walking = walking->fNext;
+       }
+       if ((sum == parser.fLastTransform) == false) {
+               SkMatrix inverse;
+               bool success = parser.fLastTransform.invert(&inverse);
+               SkASSERT(success == true);
+               SkMatrix output;
+               output.setConcat(inverse, sum);
+               parser.fLastTransform = sum;
+               SkString outputStr;
+               outputStr.appendUnichar('[');
+               outputStr.appendScalar(output.getScaleX());
+               outputStr.appendUnichar(',');
+               outputStr.appendScalar(output.getSkewX());
+               outputStr.appendUnichar(',');
+               outputStr.appendScalar(output.getTranslateX());
+               outputStr.appendUnichar(',');
+               outputStr.appendScalar(output.getSkewY());
+               outputStr.appendUnichar(',');
+               outputStr.appendScalar(output.getScaleY());
+               outputStr.appendUnichar(',');
+               outputStr.appendScalar(output.getTranslateY());
+               outputStr.appendUnichar(',');
+               outputStr.appendScalar(output.getPerspX());
+               outputStr.appendUnichar(',');
+               outputStr.appendScalar(output.getPerspY());
+               outputStr.append(",1]");
+               parser._startElement("matrix");
+               parser._addAttributeLen("matrix", outputStr.c_str(), outputStr.size());
+               parser._endElement();
+       }
+#if 0  // incomplete
+       if (parser.fTransformClips.size() > 0) {
+               // need to reset the clip when the 'g' scope is ended
+               parser._startElement("add");
+               const char* start = strchr(current->f_clipPath.c_str(), '#') + 1;
+               SkASSERT(start);
+               parser._addAttributeLen("use", start, strlen(start) - 1);
+               parser._endElement();   // clip
+       }
+#endif
+}
+
+bool SkSVGPaint::writeChangedAttributes(SkSVGParser& parser, 
+               SkSVGPaint& current, bool* changed) {
+       SkSVGPaint& lastState = parser.fLastFlush;
+       for (int index = kInitial + 1; index < kTerminal; index++) {
+               if (changed[index] == false)
+                               continue;
+               SkString* topAttr = current[index];
+               size_t attrLength = topAttr->size();
+               if (attrLength == 0)
+                       continue;
+               const char* attrValue = topAttr->c_str();
+               SkString* lastAttr = lastState[index];
+               switch(index) {
+                       case kClipPath:
+                       case kClipRule:
+                       case kEnableBackground:
+                               break;
+                       case kFill:
+                               if (topAttr->equals("none") == false && lastAttr->equals("none") == true) 
+                                       parser._addAttribute("stroke", "false");
+                               goto fillStrokeAttrCommon;
+                       case kFillRule:
+                       case kFilter:
+                       case kFontFamily:
+                               break;
+                       case kFontSize:
+                               parser._addAttributeLen("textSize", attrValue, attrLength);
+                               break;
+                       case kLetterSpacing:
+                               parser._addAttributeLen("textTracking", attrValue, attrLength);
+                               break;
+                       case kMask:
+                               break;
+                       case kOpacity:
+                               break;
+                       case kStopColor:
+                               break;
+                       case kStopOpacity:
+                               break;
+                       case kStroke:
+                               if (topAttr->equals("none") == false && lastAttr->equals("none") == true) 
+                                       parser._addAttribute("stroke", "true");
+fillStrokeAttrCommon:
+                               if (strncmp(attrValue, "url(", 4) == 0) {
+                                       SkASSERT(attrValue[4] == '#');
+                                       const char* idStart = attrValue + 5;
+                                       char* idEnd = strrchr(attrValue, ')');
+                                       SkASSERT(idStart < idEnd);
+                                       SkString id(idStart, idEnd - idStart);
+                                       SkSVGElement* found;
+                                       if (strncmp(id.c_str(), "mask", 4) != 0) {
+                                               bool itsFound = parser.fIDs.find(id.c_str(), &found);
+                                               SkASSERT(itsFound);
+                                               SkASSERT(found->getType() == SkSVGType_LinearGradient ||
+                                                       found->getType() == SkSVGType_RadialGradient);
+                                       }
+                                       parser._addAttribute("shader", id.c_str());
+                               }
+                               break;
+                       case kStroke_Dasharray:
+                               break;
+                       case kStroke_Linecap:
+                               parser._addAttributeLen("strokeCap", attrValue, attrLength);
+                               break;
+                       case kStroke_Linejoin:
+                               parser._addAttributeLen("strokeJoin", attrValue, attrLength);
+                               break;
+                       case kStroke_Miterlimit:
+                               parser._addAttributeLen("strokeMiter", attrValue, attrLength);
+                               break;
+                       case kStroke_Width:
+                               parser._addAttributeLen("strokeWidth", attrValue, attrLength);
+                       case kStyle:
+                       case kTransform:
+                               break;
+               default:
+                       SkASSERT(0);
+                       return false;
+               }
+       }
+       return true;
+}
+
+bool SkSVGPaint::writeChangedElements(SkSVGParser& parser,
+               SkSVGPaint& current, bool* changed) {
+       SkSVGPaint& lastState = parser.fLastFlush;
+       for (int index = kInitial + 1; index < kTerminal; index++) {
+               SkString* topAttr = current[index];
+               size_t attrLength = topAttr->size();
+               if (attrLength == 0)
+                       continue;
+               const char* attrValue = topAttr->c_str();
+               SkString* lastAttr = lastState[index];
+               switch(index) {
+                       case kClipPath:
+                       case kClipRule:
+                               // !!! need to add this outside of paint
+                               break;
+                       case kEnableBackground:
+                               // !!! don't know what to do with this
+                               break;
+                       case kFill:
+                               goto addColor;
+                       case kFillRule:
+                       case kFilter:
+                               break;
+                       case kFontFamily:
+                               parser._startElement("typeface");
+                               parser._addAttributeLen("fontName", attrValue, attrLength);
+                               parser._endElement();   // typeface
+                               break;
+                       case kFontSize:
+                       case kLetterSpacing:
+                               break;
+                       case kMask:
+                       case kOpacity:
+                               if (changed[kStroke] == false && changed[kFill] == false) {
+                                       parser._startElement("color");
+                                       SkString& opacity = current.f_opacity;
+                                       parser._addAttributeLen("color", parser.fLastColor.c_str(), parser.fLastColor.size());
+                                       parser._addAttributeLen("alpha", opacity.c_str(), opacity.size());
+                                       parser._endElement();   // color
+                               }
+                               break;
+                       case kStopColor:
+                               break;
+                       case kStopOpacity:
+                               break;
+                       case kStroke:
+addColor:
+                               if (strncmp(lastAttr->c_str(), "url(", 4) == 0 && strncmp(attrValue, "url(", 4) != 0) {
+                                       parser._startElement("shader");
+                                       parser._endElement();
+                               }
+                               if (topAttr->equals(*lastAttr))
+                                       continue;
+                               {
+                                       bool urlRef = strncmp(attrValue, "url(", 4) == 0;
+                                       bool colorNone = strcmp(attrValue, "none") == 0;
+                                       bool lastEqual = parser.fLastColor.equals(attrValue, attrLength);
+                                       bool newColor = urlRef == false && colorNone == false && lastEqual == false;
+                                       if (newColor || changed[kOpacity]) {
+                                               parser._startElement("color");
+                                               if (newColor || changed[kOpacity]) {
+                                                       parser._addAttributeLen("color", attrValue, attrLength);
+                                                       parser.fLastColor.set(attrValue, attrLength);
+                                               }
+                                               if (changed[kOpacity]) {
+                                                       SkString& opacity = current.f_opacity;
+                                                       parser._addAttributeLen("alpha", opacity.c_str(), opacity.size());
+                                               }
+                                               parser._endElement();   // color
+                                       }
+                               }
+                               break;
+                       case kStroke_Dasharray:
+                               parser._startElement("dash");
+                               SkSVGParser::ConvertToArray(*topAttr);
+                               parser._addAttribute("intervals", topAttr->c_str());
+                               parser._endElement();   // dash
+                       break;
+                       case kStroke_Linecap:
+                       case kStroke_Linejoin:
+                       case kStroke_Miterlimit:
+                       case kStroke_Width:
+                       case kStyle:
+                       case kTransform:
+                               break;
+               default:
+                       SkASSERT(0);
+                       return false;
+               }
+       }
+       return true;
+}
+                       
+void SkSVGPaint::Push(SkSVGPaint** head, SkSVGPaint* newRecord) {
+       newRecord->fNext = *head;
+       *head = newRecord;
+}
+
+void SkSVGPaint::Pop(SkSVGPaint** head) {
+       SkSVGPaint* next = (*head)->fNext;
+       *head = next;
+}
+
diff --git a/libs/graphics/svg/SkSVGParser.cpp b/libs/graphics/svg/SkSVGParser.cpp
new file mode 100644 (file)
index 0000000..a31f436
--- /dev/null
@@ -0,0 +1,428 @@
+#include "SkSVGParser.h"
+#include "SkSVGCircle.h"
+#include "SkSVGClipPath.h"
+#include "SkSVGDefs.h"
+#include "SkSVGEllipse.h"
+#include "SkSVGFeColorMatrix.h"
+#include "SkSVGFilter.h"
+#include "SkSVGG.h"
+#include "SkSVGImage.h"
+#include "SkSVGLine.h"
+#include "SkSVGLinearGradient.h"
+#include "SkSVGMask.h"
+#include "SkSVGMetadata.h"
+#include "SkSVGPath.h"
+#include "SkSVGPolygon.h"
+#include "SkSVGPolyline.h"
+#include "SkSVGRadialGradient.h"
+#include "SkSVGRect.h"
+#include "SkSVGSVG.h"
+#include "SkSVGStop.h"
+#include "SkSVGSymbol.h"
+#include "SkSVGText.h"
+#include "SkSVGUse.h"
+#include "SkTSearch.h"
+#include <stdio.h>
+
+static int gGeneratedMatrixID = 0;
+
+SkSVGParser::SkSVGParser() : fHead(&fEmptyPaint), fIDs(256),
+               fXMLWriter(&fStream), fCurrElement(nil), fInSVG(false), fSuppressPaint(false) {
+       fLastTransform.reset();
+       fEmptyPaint.f_fill.set("black");
+       fEmptyPaint.f_stroke.set("none");
+       fEmptyPaint.f_strokeMiterlimit.set("4");
+       fEmptyPaint.f_fillRule.set("winding");
+       fEmptyPaint.f_opacity.set("1");
+       fEmptyPaint.fNext = nil;
+       for (int index = SkSVGPaint::kInitial + 1; index < SkSVGPaint::kTerminal; index++) {
+               SkString* initial = fEmptyPaint[index];
+               if (initial->size() == 0)
+                       continue;
+               fLastFlush[index]->set(*initial);
+       }
+}
+
+SkSVGParser::~SkSVGParser() {
+}
+
+void SkSVGParser::Delete(SkTDArray<SkSVGElement*>& fChildren) {
+       SkSVGElement** ptr;
+       for (ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               Delete((*ptr)->fChildren);
+               delete *ptr;
+       }
+}
+
+int SkSVGParser::findAttribute(SkSVGBase* element, const char* attrValue,
+               size_t len, bool isPaint) {
+       const SkSVGAttribute* attributes;
+       int count = element->getAttributes(&attributes);
+       int result = 0;
+       while (result < count) {
+               if (strncmp(attributes->fName, attrValue, len) == 0 && strlen(attributes->fName) == len) {
+                       SkASSERT(result == (attributes->fOffset - 
+                               (isPaint ? sizeof(SkString) : sizeof(SkSVGElement))) / sizeof(SkString));
+                       return result;
+               }
+               attributes++;
+               result++;
+       }
+       return -1;
+}
+
+const char* SkSVGParser::getFinal() {
+       _startElement("screenplay");
+       // generate defs
+       SkSVGElement** ptr;
+       for (ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               SkSVGElement* element = *ptr;
+               translate(element, true);
+       }
+       // generate onLoad
+       _startElement("event");
+       _addAttribute("kind", "onLoad");
+       _startElement("paint");
+       _addAttribute("antiAlias", "true");
+       _endElement();
+       for (ptr = fChildren.begin(); ptr < fChildren.end(); ptr++) {
+               SkSVGElement* element = *ptr;
+               translate(element, false);
+       }
+       _endElement(); // event
+       _endElement(); // screenplay
+       Delete(fChildren);
+       fStream.write("", 1);
+       return fStream.getStream();
+}
+
+SkString& SkSVGParser::getPaintLast(SkSVGPaint::Field field) {
+       SkSVGPaint* state = fHead;
+       do {
+               SkString* attr = (*state)[field];
+               SkASSERT(attr);
+               if (attr->size() > 0)
+                       return *attr;
+               state = state->fNext;
+       } while (state);
+       SkASSERT(0);
+       SkASSERT(fEmptyPaint[field]);
+       return *fEmptyPaint[field];
+}
+
+bool SkSVGParser::isStrokeAndFill(     SkSVGPaint** strokeState, SkSVGPaint** fillState) {
+       SkSVGPaint* walking = fHead;
+       bool stroke = false;
+       bool fill = false;
+       bool strokeSet = false;
+       bool fillSet = false;
+       while (walking != nil) {
+               if (strokeSet == false && walking->f_stroke.size() > 0) {
+                       stroke = walking->f_stroke.equals("none") == false;
+                       *strokeState = walking;
+                       strokeSet = true;
+               }
+               if (fillSet == false && walking->f_fill.size() > 0) {
+                       fill = walking->f_fill.equals("none") == false;
+                       *fillState = walking;
+                       fillSet = true;
+               }
+               walking = walking->fNext;
+       }
+       return stroke && fill;
+}
+
+bool SkSVGParser::onAddAttribute(const char name[], const char value[]) {
+       return onAddAttributeLen(name, value, strlen(value));
+}
+
+bool SkSVGParser::onAddAttributeLen(const char name[], const char value[], size_t len) {
+       if (fCurrElement == nil)        // this signals we should ignore attributes for this element
+               return true;
+       if (fCurrElement->fIsDef == false && fCurrElement->fIsNotDef == false)
+               return true; // also an ignored element
+       size_t nameLen = strlen(name);
+       int attrIndex = findAttribute(fCurrElement, name, nameLen, false);
+       if (attrIndex == -1) {
+               attrIndex = findAttribute(&fCurrElement->fPaintState, name, nameLen, true);
+               if (attrIndex >= 0) {
+                       fCurrElement->fPaintState.addAttribute(*this, attrIndex, value, len);
+                       return false;
+               }
+               if (nameLen == 2 && strncmp("id", name, nameLen) == 0) {
+                       fCurrElement->f_id.set(value, len);
+                       return false;
+               }
+               if (strchr(name, ':') != 0)     // part of a different namespace
+                       return false;
+       }
+       SkASSERT(attrIndex >= 0);
+       fCurrElement->addAttribute(*this, attrIndex, value, len);
+       return false;
+}
+
+bool SkSVGParser::onEndElement(const char elem[]) {
+       int parentIndex = fParents.count() - 1;
+       if (parentIndex >= 0) {
+               SkSVGElement* element = fParents[parentIndex];
+               element->onEndElement(*this);
+               fParents.remove(parentIndex);
+       }
+       return false;
+}
+
+bool SkSVGParser::onStartElement(const char name[]) {
+       return onStartElementLen(name, strlen(name));
+}
+
+bool SkSVGParser::onStartElementLen(const char name[], size_t len) {
+       if (strncmp(name, "svg", len) == 0) {
+               fInSVG = true;
+       } else if (fInSVG == false)
+               return false;
+       const char* nextColon = strchr(name, ':');
+       if (nextColon && nextColon - name < len)
+               return false;
+       SkSVGTypes type = GetType(name, len);
+       SkASSERT(type >= 0);
+       if (type < 0)
+               return true;
+       SkSVGElement* parent = fParents.count() > 0 ? fParents.top() : nil;
+       SkSVGElement* element = CreateElement(type, parent);
+       bool result = false;
+       if (parent) {
+               element->fParent = parent;
+               result = fParents.top()->onStartElement(element);
+       } else
+               *fChildren.append() = element;
+       if (strncmp(name, "svg", len) != 0)
+               *fParents.append() = element;
+       fCurrElement = element;
+       return result;
+}
+
+bool SkSVGParser::onText(const char text[], int len) {
+       if (fInSVG == false)
+               return false;
+       SkSVGTypes type = fCurrElement->getType(); 
+       if (type != SkSVGType_Text && type != SkSVGType_Tspan)
+               return false;
+       SkSVGText* textElement = (SkSVGText*) fCurrElement;
+       textElement->f_text.set(text, len);
+       return false;
+}
+
+static S32 strokeFillID = 0;
+
+void SkSVGParser::translate(SkSVGElement* element, bool isDef) {
+       SkSVGPaint::Push(&fHead, &element->fPaintState);
+       bool isFlushable = element->isFlushable();
+       if ((element->fIsDef == false && element->fIsNotDef == false) ||
+               (element->fIsDef && isDef == false && element->fIsNotDef == false) ||
+               (element->fIsDef == false && isDef && element->fIsNotDef)) {
+               isFlushable = false;
+       }
+       SkSVGPaint* strokeState = nil, * fillState = nil;
+       if (isFlushable)
+               element->fPaintState.setSave(*this);
+       if (isFlushable && isStrokeAndFill(&strokeState, &fillState)) {
+               SkString& elementID = element->f_id;
+               if (elementID.size() == 0) {
+                       elementID.set("sf");
+                       elementID.appendS32(++strokeFillID);
+               }
+               SkString saveStroke(strokeState->f_stroke);
+               SkString saveFill(fillState->f_fill);
+               strokeState->f_stroke.set("none");
+               element->fPaintState.flush(*this, isFlushable, isDef);
+               element->translate(*this, isDef);
+               strokeState->f_stroke.set(saveStroke);
+               fillState->f_fill.set("none");
+               if (element->fPaintState.flush(*this, isFlushable, isDef)) {
+                       _startElement("add");
+                       _addAttributeLen("use", elementID.c_str(), elementID.size());
+                       _endElement();  // add
+               }
+               fillState->f_fill.set(saveFill);
+       } else {
+               element->fPaintState.flush(*this, isFlushable, isDef);
+               if (isFlushable || element->isGroup())
+                       element->translate(*this, isDef);
+       }
+       SkSVGPaint::Pop(&fHead);
+}
+
+void SkSVGParser::translateMatrix(SkString& string, SkString* stringID) {
+       if (string.size() == 0)
+               return;
+       if (stringID->size() > 0) {
+               _startElement("add");
+               _addAttribute("use", stringID->c_str());
+               _endElement(); // add
+               return;
+       }
+       SkASSERT(strncmp(string.c_str(), "matrix", 6) == 0);
+       ++gGeneratedMatrixID;
+       _startElement("matrix");
+       char idStr[16];
+       strcpy(idStr, "sk_matrix");
+       char num[8];
+       sprintf(num, "%d", gGeneratedMatrixID);
+       strcat(idStr, num);
+       _addAttribute("id", idStr);
+       stringID->set(idStr);
+       const char* str = string.c_str();
+       SkASSERT(strncmp(str, "matrix(", 7) == 0);
+       str += 6;
+       const char* strEnd = strrchr(str, ')');
+       SkASSERT(strEnd != nil);
+       SkString mat(str, strEnd - str);
+       ConvertToArray(mat);
+       const char* elems[6];
+       static const int order[] = {0, 3, 1, 4, 2, 5};
+       const int* orderPtr = order;
+       str = mat.c_str();
+       strEnd = str + mat.size();
+       while (str < strEnd) {
+               elems[*orderPtr++] = str;
+               while (str < strEnd && *str != ',' )
+                       str++;
+               str++;
+       }
+       string.reset();
+       for (int index = 0; index < 6; index++) {
+               const char* end = strchr(elems[index], ',');
+               if (end == nil)
+                       end= strchr(elems[index], ']');
+               string.append(elems[index], end - elems[index] + 1);
+       }
+       string.remove(string.size() - 1, 1);
+       string.append(",0,0,1]");    
+       _addAttribute("matrix", string);
+       _endElement();  // matrix
+}
+
+static bool is_whitespace(char ch) {
+       return ch > 0 && ch <= ' ';
+}
+
+void SkSVGParser::ConvertToArray(SkString& vals) {
+       vals.appendUnichar(']');
+       char* valCh = (char*) vals.c_str();
+       valCh[0] = '[';
+       int index = 1;
+       while (valCh[index] != ']') {
+               while (is_whitespace(valCh[index]))
+                       index++;
+               bool foundComma = false;
+               char next;
+               do {
+                       next = valCh[index++];
+                       if (next == ',') {
+                               foundComma = true;
+                               continue;
+                       }
+                       if (next == ']') {
+                               index--;
+                               goto undoLastComma;
+                       }
+                       if (next == ' ')
+                               break;
+                       foundComma = false;
+               } while (is_whitespace(next) == false);
+               if (foundComma == false)
+                       valCh[index - 1] = ',';
+       }
+undoLastComma:
+       while (is_whitespace(valCh[--index]))
+               ;
+       if (valCh[index] == ',')
+               valCh[index] = ' ';
+}
+
+#define CASE_NEW(type) case SkSVGType_##type : created = new SkSVG##type(); break
+
+SkSVGElement* SkSVGParser::CreateElement(SkSVGTypes type, SkSVGElement* parent) {
+       SkSVGElement* created = nil;
+       switch (type) {
+               CASE_NEW(Circle);
+               CASE_NEW(ClipPath);
+               CASE_NEW(Defs);
+               CASE_NEW(Ellipse);
+               CASE_NEW(FeColorMatrix);
+               CASE_NEW(Filter);
+               CASE_NEW(G);
+               CASE_NEW(Image);
+               CASE_NEW(Line);
+               CASE_NEW(LinearGradient);
+               CASE_NEW(Mask);
+               CASE_NEW(Metadata);
+               CASE_NEW(Path);
+               CASE_NEW(Polygon);
+               CASE_NEW(Polyline);
+               CASE_NEW(RadialGradient);
+               CASE_NEW(Rect);
+               CASE_NEW(Stop);
+               CASE_NEW(SVG);
+               CASE_NEW(Symbol);
+               CASE_NEW(Text);
+               CASE_NEW(Tspan);
+               CASE_NEW(Use);
+               default:
+                       SkASSERT(0);
+                       return nil;
+       }
+       created->fParent = parent;
+       bool isDef = created->fIsDef = created->isDef();
+       bool isNotDef = created->fIsNotDef = created->isNotDef();
+       if (isDef) {
+               SkSVGElement* up = parent;
+               while (up && up->fIsDef == false) {
+                       up->fIsDef = true;
+                       up = up->fParent;
+               }
+       }
+       if (isNotDef) {
+               SkSVGElement* up = parent;
+               while (up && up->fIsNotDef == false) {
+                       up->fIsNotDef = true;
+                       up = up->fParent;
+               }
+       }
+       return created;
+}
+
+const SkSVGTypeName gSVGTypeNames[] = {
+       {"circle", SkSVGType_Circle},
+       {"clipPath", SkSVGType_ClipPath},
+       {"defs", SkSVGType_Defs},
+       {"ellipse", SkSVGType_Ellipse},
+       {"feColorMatrix", SkSVGType_FeColorMatrix},
+       {"filter", SkSVGType_Filter},
+       {"g", SkSVGType_G},
+       {"image", SkSVGType_Image},
+       {"line", SkSVGType_Line},
+       {"linearGradient", SkSVGType_LinearGradient},
+       {"mask", SkSVGType_Mask},
+       {"metadata", SkSVGType_Metadata},
+       {"path", SkSVGType_Path},
+       {"polygon", SkSVGType_Polygon},
+       {"polyline", SkSVGType_Polyline},
+       {"radialGradient", SkSVGType_RadialGradient},
+       {"rect", SkSVGType_Rect},
+       {"stop", SkSVGType_Stop},
+       {"svg", SkSVGType_SVG},
+       {"symbol", SkSVGType_Symbol},
+       {"text", SkSVGType_Text},
+       {"tspan", SkSVGType_Tspan},
+       {"use", SkSVGType_Use}
+};
+
+const int kSVGTypeNamesSize = SK_ARRAY_COUNT(gSVGTypeNames);
+
+SkSVGTypes SkSVGParser::GetType(const char match[], size_t len ) {
+       int index = SkStrSearch(&gSVGTypeNames[0].fName, kSVGTypeNamesSize, match, 
+               len, sizeof(gSVGTypeNames[0]));
+       return index >= 0 && index < kSVGTypeNamesSize ? gSVGTypeNames[index].fType : 
+               (SkSVGTypes) -1;
+}
diff --git a/libs/graphics/svg/SkSVGPath.cpp b/libs/graphics/svg/SkSVGPath.cpp
new file mode 100644 (file)
index 0000000..be7a45f
--- /dev/null
@@ -0,0 +1,28 @@
+#include "SkSVGPath.h"
+#include "SkSVGParser.h"
+
+const SkSVGAttribute SkSVGPath::gAttributes[] = {
+       SVG_ATTRIBUTE(d)
+};
+
+DEFINE_SVG_INFO(Path)
+
+void SkSVGPath::translate(SkSVGParser& parser, bool defState) {
+       parser._startElement("path");
+       INHERITED::translate(parser, defState);
+       bool hasMultiplePaths = false;
+       const char* firstZ = strchr(f_d.c_str(), 'z');
+       if (firstZ != nil) {
+               firstZ++; // skip over 'z'
+               while (*firstZ == ' ')
+                       firstZ++;
+               hasMultiplePaths = *firstZ != '\0';
+       }
+       if (hasMultiplePaths) {
+               SkString& fillRule = parser.getPaintLast(SkSVGPaint::kFillRule);
+               if (fillRule.size() > 0) 
+                       parser._addAttribute("fillType", fillRule.equals("evenodd") ? "evenOdd" : "winding");
+       }
+       SVG_ADD_ATTRIBUTE(d);
+       parser._endElement();
+}
diff --git a/libs/graphics/svg/SkSVGPath.h b/libs/graphics/svg/SkSVGPath.h
new file mode 100644 (file)
index 0000000..1cbff6d
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef SkSVGPath_DEFINED
+#define SkSVGPath_DEFINED
+
+#include "SkSVGElements.h"
+
+class SkSVGPath : public SkSVGElement {
+       DECLARE_SVG_INFO(Path);
+private:
+       SkString f_d;
+       typedef SkSVGElement INHERITED;
+};
+
+#endif // SkSVGPath_DEFINED
diff --git a/libs/graphics/svg/SkSVGPolygon.cpp b/libs/graphics/svg/SkSVGPolygon.cpp
new file mode 100644 (file)
index 0000000..f7e4165
--- /dev/null
@@ -0,0 +1,24 @@
+#include "SkSVGPolygon.h"
+#include "SkSVGParser.h"
+
+const SkSVGAttribute SkSVGPolygon::gAttributes[] = {
+       SVG_LITERAL_ATTRIBUTE(clip-rule, f_clipRule),
+       SVG_LITERAL_ATTRIBUTE(fill-rule, f_fillRule),
+       SVG_ATTRIBUTE(points)
+};
+
+DEFINE_SVG_INFO(Polygon)
+
+void SkSVGPolygon::addAttribute(SkSVGParser& parser, int attrIndex, 
+               const char* attrValue, size_t attrLength) {
+       INHERITED::addAttribute(parser, attrIndex, attrValue, attrLength);
+}
+
+void SkSVGPolygon::translate(SkSVGParser& parser, bool defState) {
+       parser._startElement("polygon");
+       SkSVGElement::translate(parser, defState);
+       SVG_ADD_ATTRIBUTE(points);
+       if (f_fillRule.size() > 0) 
+               parser._addAttribute("fillType", f_fillRule.equals("evenodd") ? "evenOdd" : "winding");
+       parser._endElement();
+}
diff --git a/libs/graphics/svg/SkSVGPolygon.h b/libs/graphics/svg/SkSVGPolygon.h
new file mode 100644 (file)
index 0000000..9cf8619
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef SkSVGPolygon_DEFINED
+#define SkSVGPolygon_DEFINED
+
+#include "SkSVGPolyline.h"
+
+class SkSVGPolygon : public SkSVGPolyline {
+       DECLARE_SVG_INFO(Polygon);
+       virtual void addAttribute(SkSVGParser& , int attrIndex, 
+               const char* attrValue, size_t attrLength);
+private:
+       typedef SkSVGPolyline INHERITED;
+};
+
+#endif // SkSVGPolygon_DEFINED
diff --git a/libs/graphics/svg/SkSVGPolyline.cpp b/libs/graphics/svg/SkSVGPolyline.cpp
new file mode 100644 (file)
index 0000000..cc4c197
--- /dev/null
@@ -0,0 +1,34 @@
+#include "SkSVGPolyline.h"
+#include "SkSVGParser.h"
+
+enum {
+       kCliipRule,
+       kFillRule,
+       kPoints
+};
+
+const SkSVGAttribute SkSVGPolyline::gAttributes[] = {
+       SVG_LITERAL_ATTRIBUTE(clip-rule, f_clipRule),
+       SVG_LITERAL_ATTRIBUTE(fill-rule, f_fillRule),
+       SVG_ATTRIBUTE(points)
+};
+
+DEFINE_SVG_INFO(Polyline)
+
+void SkSVGPolyline::addAttribute(SkSVGParser& , int attrIndex, 
+               const char* attrValue, size_t attrLength) {
+       if (attrIndex != kPoints)
+               return;
+       f_points.set("[");
+       f_points.append(attrValue, attrLength);
+       SkSVGParser::ConvertToArray(f_points);
+}
+
+void SkSVGPolyline::translate(SkSVGParser& parser, bool defState) {
+       parser._startElement("polyline");
+       INHERITED::translate(parser, defState);
+       SVG_ADD_ATTRIBUTE(points);
+       if (f_fillRule.size() > 0) 
+               parser._addAttribute("fillType", f_fillRule.equals("evenodd") ? "evenOdd" : "winding");
+       parser._endElement();
+}
diff --git a/libs/graphics/svg/SkSVGPolyline.h b/libs/graphics/svg/SkSVGPolyline.h
new file mode 100644 (file)
index 0000000..50840b2
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef SkSVGPolyline_DEFINED
+#define SkSVGPolyline_DEFINED
+
+#include "SkSVGElements.h"
+#include "SkString.h"
+
+class SkSVGPolyline : public SkSVGElement {
+       DECLARE_SVG_INFO(Polyline);
+       virtual void addAttribute(SkSVGParser& , int attrIndex, 
+               const char* attrValue, size_t attrLength);
+protected:
+       SkString f_clipRule;
+       SkString f_fillRule;
+       SkString f_points;
+       typedef SkSVGElement INHERITED;
+};
+
+#endif // SkSVGPolyline_DEFINED
diff --git a/libs/graphics/svg/SkSVGRadialGradient.cpp b/libs/graphics/svg/SkSVGRadialGradient.cpp
new file mode 100644 (file)
index 0000000..8883f36
--- /dev/null
@@ -0,0 +1,33 @@
+#include "SkSVGRadialGradient.h"
+#include "SkSVGParser.h"
+
+const SkSVGAttribute SkSVGRadialGradient::gAttributes[] = {
+       SVG_ATTRIBUTE(cx),
+       SVG_ATTRIBUTE(cy),
+       SVG_ATTRIBUTE(fx),
+       SVG_ATTRIBUTE(fy),
+       SVG_ATTRIBUTE(gradientTransform),
+       SVG_ATTRIBUTE(gradientUnits),
+       SVG_ATTRIBUTE(r)
+};
+
+DEFINE_SVG_INFO(RadialGradient)
+
+void SkSVGRadialGradient::translate(SkSVGParser& parser, bool defState) {
+       if (fMatrixID.size() == 0)
+               parser.translateMatrix(f_gradientTransform, &fMatrixID);
+       parser._startElement("radialGradient");
+       if (fMatrixID.size() > 0)
+               parser._addAttribute("matrix", fMatrixID);
+       INHERITED::translateGradientUnits(f_gradientUnits);
+       SkString center;
+       center.appendUnichar('[');
+       center.append(f_cx);
+       center.appendUnichar(',');
+       center.append(f_cy);
+       center.appendUnichar(']');
+       parser._addAttribute("center", center);
+       parser._addAttribute("radius", f_r);
+       INHERITED::translate(parser, defState);
+       parser._endElement();
+}
diff --git a/libs/graphics/svg/SkSVGRadialGradient.h b/libs/graphics/svg/SkSVGRadialGradient.h
new file mode 100644 (file)
index 0000000..514523e
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef SkSVGRadialGradient_DEFINED
+#define SkSVGRadialGradient_DEFINED
+
+#include "SkSVGGradient.h"
+
+class SkSVGRadialGradient : public SkSVGGradient {
+       DECLARE_SVG_INFO(RadialGradient);
+protected:
+       SkString f_cx;
+       SkString f_cy;
+       SkString f_fx;
+       SkString f_fy;
+       SkString f_gradientTransform;
+       SkString f_gradientUnits;
+       SkString f_r;
+       SkString fMatrixID;
+private:
+       typedef SkSVGGradient INHERITED;
+};
+
+#endif // SkSVGRadialGradient_DEFINED
diff --git a/libs/graphics/svg/SkSVGRect.cpp b/libs/graphics/svg/SkSVGRect.cpp
new file mode 100644 (file)
index 0000000..aff3a63
--- /dev/null
@@ -0,0 +1,26 @@
+#include "SkSVGRect.h"
+#include "SkSVGParser.h"
+
+const SkSVGAttribute SkSVGRect::gAttributes[] = {
+       SVG_ATTRIBUTE(height),
+       SVG_ATTRIBUTE(width),
+       SVG_ATTRIBUTE(x),
+       SVG_ATTRIBUTE(y)
+};
+
+DEFINE_SVG_INFO(Rect)
+
+SkSVGRect::SkSVGRect() {
+       f_x.set("0");
+       f_y.set("0");
+}
+
+void SkSVGRect::translate(SkSVGParser& parser, bool defState) {
+       parser._startElement("rectangle");
+       INHERITED::translate(parser, defState);
+       SVG_ADD_ATTRIBUTE_ALIAS(left, x);
+       SVG_ADD_ATTRIBUTE_ALIAS(top, y);
+       SVG_ADD_ATTRIBUTE(width);
+       SVG_ADD_ATTRIBUTE(height);
+       parser._endElement();
+}
diff --git a/libs/graphics/svg/SkSVGRect.h b/libs/graphics/svg/SkSVGRect.h
new file mode 100644 (file)
index 0000000..e6202ec
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef SkSVGRect_DEFINED
+#define SkSVGRect_DEFINED
+
+#include "SkSVGElements.h"
+
+class SkSVGRect : public SkSVGElement {
+       DECLARE_SVG_INFO(Rect);
+       SkSVGRect();
+private:
+       SkString f_height;
+       SkString f_width;
+       SkString f_x;
+       SkString f_y;
+       typedef SkSVGElement INHERITED;
+};
+
+#endif // SkSVGRect_DEFINED
diff --git a/libs/graphics/svg/SkSVGSVG.cpp b/libs/graphics/svg/SkSVGSVG.cpp
new file mode 100644 (file)
index 0000000..b56d2c8
--- /dev/null
@@ -0,0 +1,65 @@
+#include "SkSVGSVG.h"
+#include "SkParse.h"
+#include "SkRect.h"
+#include "SkSVGParser.h"
+
+const SkSVGAttribute SkSVGSVG::gAttributes[] = {
+       SVG_LITERAL_ATTRIBUTE(enable-background, f_enable_background),
+       SVG_ATTRIBUTE(height),
+       SVG_ATTRIBUTE(overflow),
+       SVG_ATTRIBUTE(width),
+       SVG_ATTRIBUTE(version),
+       SVG_ATTRIBUTE(viewBox),
+       SVG_LITERAL_ATTRIBUTE(xml:space, f_xml_space),
+       SVG_ATTRIBUTE(xmlns),
+       SVG_LITERAL_ATTRIBUTE(xmlns:xlink, f_xml_xlink)
+};
+
+DEFINE_SVG_INFO(SVG)
+
+
+bool SkSVGSVG::isFlushable() {
+       return false;
+}
+
+void SkSVGSVG::translate(SkSVGParser& parser, bool defState) {
+       SkScalar height, width;
+       SkScalar viewBox[4];
+       const char* hSuffix = SkParse::FindScalar(f_height.c_str(), &height);
+       if (strcmp(hSuffix, "pt") == 0)
+               height = SkScalarMulDiv(height, SK_Scalar1 * 72, SK_Scalar1 * 96);
+       const char* wSuffix = SkParse::FindScalar(f_width.c_str(), &width);
+       if (strcmp(wSuffix, "pt") == 0)
+               width = SkScalarMulDiv(width, SK_Scalar1 * 72, SK_Scalar1 * 96);
+       SkParse::FindScalars(f_viewBox.c_str(), viewBox, 4);
+       SkRect box;
+       box.fLeft = SkScalarDiv(viewBox[0], width);
+       box.fTop = SkScalarDiv(viewBox[1], height);
+       box.fRight = SkScalarDiv(viewBox[2], width);
+       box.fBottom = SkScalarDiv(viewBox[3], height);
+       if (box.fLeft == 0 && box.fTop == 0 && 
+               box.fRight == SK_Scalar1 && box.fBottom == SK_Scalar1) 
+                       return;
+       parser._startElement("matrix");
+       if (box.fLeft != 0) {
+               SkString x;
+               x.appendScalar(box.fLeft);
+               parser._addAttributeLen("translateX", x.c_str(), x.size());
+       }
+       if (box.fTop != 0) {
+               SkString y;
+               y.appendScalar(box.fTop);
+               parser._addAttributeLen("translateY", y.c_str(), y.size());
+       }
+       if (box.fRight != SK_Scalar1) {
+               SkString x;
+               x.appendScalar(box.fRight);
+               parser._addAttributeLen("scaleX", x.c_str(), x.size());
+       }
+       if (box.fBottom != SK_Scalar1) {
+               SkString y;
+               y.appendScalar(box.fBottom);
+               parser._addAttributeLen("scaleY", y.c_str(), y.size());
+       }
+       parser._endElement();   
+}
diff --git a/libs/graphics/svg/SkSVGSVG.h b/libs/graphics/svg/SkSVGSVG.h
new file mode 100644 (file)
index 0000000..0326b46
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef SkSVGSVG_DEFINED
+#define SkSVGSVG_DEFINED
+
+#include "SkSVGElements.h"
+
+class SkSVGSVG : public SkSVGElement {
+       DECLARE_SVG_INFO(SVG);
+       virtual bool isFlushable();
+private:
+       SkString f_enable_background;
+       SkString f_height;
+       SkString f_overflow;
+       SkString f_width;
+       SkString f_version;
+       SkString f_viewBox;
+       SkString f_xml_space;
+       SkString f_xmlns;
+       SkString f_xml_xlink;
+       typedef SkSVGElement INHERITED;
+};
+
+#endif // SkSVGSVG_DEFINED
diff --git a/libs/graphics/svg/SkSVGStop.cpp b/libs/graphics/svg/SkSVGStop.cpp
new file mode 100644 (file)
index 0000000..f4d7308
--- /dev/null
@@ -0,0 +1,15 @@
+#include "SkSVGStop.h"
+#include "SkSVGParser.h"
+
+const SkSVGAttribute SkSVGStop::gAttributes[] = {
+       SVG_ATTRIBUTE(offset)
+};
+
+DEFINE_SVG_INFO(Stop)
+
+void SkSVGStop::translate(SkSVGParser& parser, bool defState) {
+       parser._startElement("color");
+       INHERITED::translate(parser, defState);
+       parser._addAttribute("color", parser.getPaintLast(SkSVGPaint::kStopColor));
+       parser._endElement();
+}
diff --git a/libs/graphics/svg/SkSVGStop.h b/libs/graphics/svg/SkSVGStop.h
new file mode 100644 (file)
index 0000000..e2fe273
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef SkSVGStop_DEFINED
+#define SkSVGStop_DEFINED
+
+#include "SkSVGElements.h"
+
+class SkSVGStop : public SkSVGElement {
+       DECLARE_SVG_INFO(Stop);
+private:
+       SkString f_offset;
+       friend class SkSVGGradient;
+       typedef SkSVGElement INHERITED;
+};
+
+#endif // SkSVGStop_DEFINED
diff --git a/libs/graphics/svg/SkSVGSymbol.cpp b/libs/graphics/svg/SkSVGSymbol.cpp
new file mode 100644 (file)
index 0000000..5458115
--- /dev/null
@@ -0,0 +1,13 @@
+#include "SkSVGSymbol.h"
+#include "SkSVGParser.h"
+
+const SkSVGAttribute SkSVGSymbol::gAttributes[] = {
+       SVG_ATTRIBUTE(viewBox)
+};
+
+DEFINE_SVG_INFO(Symbol)
+
+void SkSVGSymbol::translate(SkSVGParser& parser, bool defState) {
+       INHERITED::translate(parser, defState);
+       // !!! children need to be written into document 
+}
diff --git a/libs/graphics/svg/SkSVGSymbol.h b/libs/graphics/svg/SkSVGSymbol.h
new file mode 100644 (file)
index 0000000..f63d683
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef SkSVGSymbol_DEFINED
+#define SkSVGSymbol_DEFINED
+
+#include "SkSVGElements.h"
+
+class SkSVGSymbol : public SkSVGElement {
+       DECLARE_SVG_INFO(Symbol);
+private:
+       SkString f_viewBox;
+       typedef SkSVGElement INHERITED;
+};
+
+#endif // SkSVGSymbol_DEFINED
diff --git a/libs/graphics/svg/SkSVGText.cpp b/libs/graphics/svg/SkSVGText.cpp
new file mode 100644 (file)
index 0000000..e8d4cd1
--- /dev/null
@@ -0,0 +1,30 @@
+#include "SkSVGText.h"
+#include "SkSVGParser.h"
+
+const SkSVGAttribute SkSVGText::gAttributes[] = {
+       SVG_ATTRIBUTE(x),
+       SVG_ATTRIBUTE(y)
+};
+
+DEFINE_SVG_INFO(Text)
+
+void SkSVGText::translate(SkSVGParser& parser, bool defState) {
+       parser._startElement("text");
+       INHERITED::translate(parser, defState);
+       SVG_ADD_ATTRIBUTE(x);
+       SVG_ADD_ATTRIBUTE(y);
+       SVG_ADD_ATTRIBUTE(text);
+       parser._endElement();
+}
+
+
+const SkSVGAttribute SkSVGTspan::gAttributes[] = {
+       SVG_ATTRIBUTE(x),
+       SVG_ATTRIBUTE(y)
+};
+
+DEFINE_SVG_INFO(Tspan)
+
+void SkSVGTspan::translate(SkSVGParser& parser, bool defState) {
+       INHERITED::translate(parser, defState);
+}
diff --git a/libs/graphics/svg/SkSVGText.h b/libs/graphics/svg/SkSVGText.h
new file mode 100644 (file)
index 0000000..76703d5
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef SkSVGText_DEFINED
+#define SkSVGText_DEFINED
+
+#include "SkSVGElements.h"
+
+class SkSVGText : public SkSVGElement {
+       DECLARE_SVG_INFO(Text);
+protected:
+       SkString f_x;
+       SkString f_y;
+       SkString f_text;        // not an attribute
+private:
+       typedef SkSVGElement INHERITED;
+       friend class SkSVGParser;
+};
+
+class SkSVGTspan : public SkSVGText {
+       DECLARE_SVG_INFO(Tspan);
+private:
+       typedef SkSVGText INHERITED;
+};
+
+#endif // SkSVGText_DEFINED
diff --git a/libs/graphics/svg/SkSVGUse.cpp b/libs/graphics/svg/SkSVGUse.cpp
new file mode 100644 (file)
index 0000000..4d2a6e4
--- /dev/null
@@ -0,0 +1,21 @@
+#include "SkSVGUse.h"
+#include "SkSVGParser.h"
+
+const SkSVGAttribute SkSVGUse::gAttributes[] = {
+       SVG_ATTRIBUTE(height),
+       SVG_ATTRIBUTE(width),
+       SVG_ATTRIBUTE(x),
+       SVG_LITERAL_ATTRIBUTE(xlink:href, f_xlink_href),
+       SVG_ATTRIBUTE(y)
+};
+
+DEFINE_SVG_INFO(Use)
+
+void SkSVGUse::translate(SkSVGParser& parser, bool defState) {
+       INHERITED::translate(parser, defState);
+       parser._startElement("add");
+       const char* start = strchr(f_xlink_href.c_str(), '#') + 1;
+       SkASSERT(start);
+       parser._addAttributeLen("use", start, strlen(start) - 1);
+       parser._endElement();   // clip
+}
diff --git a/libs/graphics/svg/SkSVGUse.h b/libs/graphics/svg/SkSVGUse.h
new file mode 100644 (file)
index 0000000..5ea9ac5
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef SkSVGUse_DEFINED
+#define SkSVGUse_DEFINED
+
+#include "SkSVGElements.h"
+
+class SkSVGUse : public SkSVGElement {
+       DECLARE_SVG_INFO(Use);
+protected:
+       SkString f_height;
+       SkString f_width;
+       SkString f_x;
+       SkString f_xlink_href;
+       SkString f_y;
+private:
+       typedef SkSVGElement INHERITED;
+       friend class SkSVGClipPath;
+};
+
+#endif // SkSVGUse_DEFINED
diff --git a/libs/graphics/text/ATextEntry.h b/libs/graphics/text/ATextEntry.h
new file mode 100644 (file)
index 0000000..0a584b7
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef ATextEntry_DEFINED
+#define ATextEntry_DEFINED
+
+#include "SkTypes.h"
+
+class SkCanavs;
+
+class ATextEntry {
+public:
+    ATextEntry();
+    ~ATextEntry();
+    
+    void    setUtf16(const U16 text[], size_t count);
+    void    setSize(SkScalar width, SkScalar height);
+    void    setSelection(int start, int stop);
+    void    draw(SkCanvas*);
+    void    handleKey(int key);
+};
+
+#endif
diff --git a/libs/graphics/views/SkEvent.cpp b/libs/graphics/views/SkEvent.cpp
new file mode 100644 (file)
index 0000000..f7a9648
--- /dev/null
@@ -0,0 +1,548 @@
+#include "SkEvent.h"
+
+void SkEvent::initialize(const char* type, size_t typeLen) {
+       fType = NULL;
+       setType(type, typeLen);
+       f32 = 0;
+#ifdef SK_DEBUG
+       fTargetID = 0;
+       fTime = 0;
+       fNextEvent = NULL;
+#endif
+       SkDEBUGCODE(fDebugTrace = false;)
+}
+
+SkEvent::SkEvent()
+{
+       initialize("", 0);
+}
+
+SkEvent::SkEvent(const SkEvent& src)
+{
+       *this = src;
+       if (((size_t) fType & 1) == 0)
+               setType(src.fType);
+}
+
+SkEvent::SkEvent(const SkString& type)
+{
+       initialize(type.c_str(), type.size());
+}
+
+SkEvent::SkEvent(const char type[])
+{
+       SkASSERT(type);
+       initialize(type, strlen(type));
+}
+
+SkEvent::~SkEvent()
+{
+       if (((size_t) fType & 1) == 0)
+               sk_free((void*) fType);
+}
+
+static size_t makeCharArray(char* buffer, size_t compact)
+{
+       size_t bits = (size_t) compact >> 1;
+       memcpy(buffer, &bits, sizeof(compact));
+       buffer[sizeof(compact)] = 0;
+       return strlen(buffer);
+}
+
+#if 0
+const char* SkEvent::getType() const 
+{ 
+       if ((size_t) fType & 1) {       // not a pointer
+               char chars[sizeof(size_t) + 1];
+               size_t len = makeCharArray(chars, (size_t) fType);
+               fType = (char*) sk_malloc_throw(len);
+               SkASSERT(((size_t) fType & 1) == 0);
+               memcpy(fType, chars, len);
+       }
+       return fType; 
+}
+#endif
+
+void SkEvent::getType(SkString* str) const 
+{ 
+       if (str) 
+       {
+               if ((size_t) fType & 1) // not a pointer
+               {
+                       char chars[sizeof(size_t) + 1];
+                       size_t len = makeCharArray(chars, (size_t) fType);
+                       str->set(chars, len);
+               }
+               else
+                       str->set(fType);
+       }
+}
+
+bool SkEvent::isType(const SkString& str) const 
+{
+       return this->isType(str.c_str(), str.size()); 
+}
+
+bool SkEvent::isType(const char type[], size_t typeLen) const 
+{ 
+       if (typeLen == 0)
+               typeLen = strlen(type);
+       if ((size_t) fType & 1) {       // not a pointer
+               char chars[sizeof(size_t) + 1];
+               size_t len = makeCharArray(chars, (size_t) fType);
+               return len == typeLen && strncmp(chars, type, typeLen) == 0;
+       }
+       return strncmp(fType, type, typeLen) == 0 && fType[typeLen] == 0; 
+}
+
+void SkEvent::setType(const char type[], size_t typeLen)
+{
+       if (typeLen == 0)
+               typeLen = strlen(type);
+       if (typeLen <= sizeof(fType)) {
+               size_t slot = 0;
+               memcpy(&slot, type, typeLen);
+               if (slot << 1 >> 1 != slot)
+                       goto useCharStar;
+               slot <<= 1;
+               slot |= 1;
+               fType = (char*) slot;
+       } else {
+useCharStar:
+               fType = (char*) sk_malloc_throw(typeLen + 1);
+               SkASSERT(((size_t) fType & 1) == 0);
+               memcpy(fType, type, typeLen);
+               fType[typeLen] = 0;
+       }
+}
+
+void SkEvent::setType(const SkString& type)
+{
+       setType(type.c_str());
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+#include "SkParse.h"
+
+void SkEvent::inflate(const SkDOM& dom, const SkDOM::Node* node)
+{
+       const char* name = dom.findAttr(node, "type");
+       if (name)
+               this->setType(name);
+
+       const char* value;
+       if ((value = dom.findAttr(node, "fast32")) != NULL)
+       {
+               int32_t n;
+               if (SkParse::FindS32(value, &n))
+                       this->setFast32(n);
+       }
+
+       for (node = dom.getFirstChild(node); node; node = dom.getNextSibling(node))
+       {
+               if (strcmp(dom.getName(node), "data"))
+               {
+                       SkDEBUGCODE(SkDebugf("SkEvent::inflate unrecognized subelement <%s>\n", dom.getName(node));)
+                       continue;
+               }
+
+               name = dom.findAttr(node, "name");
+               if (name == NULL)
+               {
+                       SkDEBUGCODE(SkDebugf("SkEvent::inflate missing required \"name\" attribute in <data> subelement\n");)
+                       continue;
+               }
+
+               if ((value = dom.findAttr(node, "s32")) != NULL)
+               {
+                       int32_t n;
+                       if (SkParse::FindS32(value, &n))
+                               this->setS32(name, n);
+               }
+               else if ((value = dom.findAttr(node, "scalar")) != NULL)
+               {
+                       SkScalar x;
+                       if (SkParse::FindScalar(value, &x))
+                               this->setScalar(name, x);
+               }
+               else if ((value = dom.findAttr(node, "string")) != NULL)
+                       this->setString(name, value);
+#ifdef SK_DEBUG
+               else
+               {
+                       SkDebugf("SkEvent::inflate <data name=\"%s\"> subelement missing required type attribute [S32 | scalar | string]\n", name);
+               }
+#endif
+       }
+}
+
+#ifdef SK_DEBUG
+
+       #ifndef SkScalarToFloat
+               #define SkScalarToFloat(x)      ((x) / 65536.f)
+       #endif
+
+       void SkEvent::dump(const char title[])
+       {
+               if (title)
+                       SkDebugf("%s ", title);
+                       
+               SkString        etype;
+               this->getType(&etype);
+               SkDebugf("event<%s> fast32=%d", etype.c_str(), this->getFast32());
+
+               const SkMetaData&       md = this->getMetaData();
+               SkMetaData::Iter        iter(md);
+               SkMetaData::Type        mtype;
+               int                                     count;
+               const char*                     name;
+               
+               while ((name = iter.next(&mtype, &count)) != NULL)
+               {
+                       SkASSERT(count > 0);
+
+                       SkDebugf(" <%s>=", name);
+                       switch (mtype) {
+                       case SkMetaData::kS32_Type:             // vector version???
+                               {
+                                       int32_t value;
+                                       md.findS32(name, &value);
+                                       SkDebugf("%d ", value);
+                               }
+                               break;
+                       case SkMetaData::kScalar_Type:
+                               {
+                                       const SkScalar* values = md.findScalars(name, &count, NULL);
+                                       SkDebugf("%f", SkScalarToFloat(values[0]));
+                                       for (int i = 1; i < count; i++)
+                                               SkDebugf(", %f", SkScalarToFloat(values[i]));
+                                       SkDebugf(" ");
+                               }
+                               break;
+                       case SkMetaData::kString_Type:
+                               {
+                                       const char* value = md.findString(name);
+                                       SkASSERT(value);
+                                       SkDebugf("<%s> ", value);
+                               }
+                               break;
+                       case SkMetaData::kPtr_Type:             // vector version???
+                               {
+                                       void*   value;
+                                       md.findPtr(name, &value);
+                                       SkDebugf("%p ", value);
+                               }
+                               break;
+                       case SkMetaData::kBool_Type:    // vector version???
+                               {
+                                       bool    value;
+                                       md.findBool(name, &value);
+                                       SkDebugf("%s ", value ? "true" : "false");
+                               }
+                               break;
+                       default:
+                               SkASSERT(!"unknown metadata type returned from iterator");
+                               break;
+                       }
+               }
+               SkDebugf("\n");
+       }
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+// #define SK_TRACE_EVENTSx
+#endif
+
+#ifdef SK_TRACE_EVENTS
+       static void event_log(const char s[])
+       {
+               SkDEBUGF(("%s\n", s));
+       }
+
+       #define EVENT_LOG(s)            event_log(s)
+       #define EVENT_LOGN(s, n)        do { SkString str(s); str.append(" "); str.appendS32(n); event_log(str.c_str()); } while (0)
+#else
+       #define EVENT_LOG(s)
+       #define EVENT_LOGN(s, n)
+#endif
+
+#include "SkGlobals.h"
+#include "SkThread.h"
+#include "SkTime.h"
+
+#define SK_Event_GlobalsTag            SkSetFourByteTag('e', 'v', 'n', 't')
+
+class SkEvent_Globals : public SkGlobals::Rec {
+public:
+       SkMutex         fEventMutex;
+       SkEvent*        fEventQHead, *fEventQTail;
+       SkEvent*        fDelayQHead;
+       SkDEBUGCODE(int fEventCounter;)
+};
+
+static SkGlobals::Rec* create_globals()
+{
+       SkEvent_Globals* rec = new SkEvent_Globals;
+       rec->fEventQHead = NULL;
+       rec->fEventQTail = NULL;
+       rec->fDelayQHead = NULL;
+       SkDEBUGCODE(rec->fEventCounter = 0;)
+       return rec;
+}
+
+bool SkEvent::Post(SkEvent* evt, SkEventSinkID sinkID, SkMSec delay)
+{
+       if (delay)
+               return SkEvent::PostTime(evt, sinkID, SkTime::GetMSecs() + delay);
+
+       SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+
+       evt->fTargetID = sinkID;
+
+#ifdef SK_TRACE_EVENTS
+       {
+               SkString        str("SkEvent::Post(");
+               str.append(evt->getType());
+               str.append(", 0x");
+               str.appendHex(sinkID);
+               str.append(", ");
+               str.appendS32(delay);
+               str.append(")");
+               event_log(str.c_str());
+       }
+#endif
+
+       globals.fEventMutex.acquire();
+       bool wasEmpty = SkEvent::Enqueue(evt);
+       globals.fEventMutex.release();
+
+       // call outside of us holding the mutex
+       if (wasEmpty)
+               SkEvent::SignalNonEmptyQueue();
+       return true;
+}
+
+#if defined(SK_SIMULATE_FAILED_MALLOC) && defined(SK_FIND_MEMORY_LEAKS)
+SkMSec gMaxDrawTime;
+#endif
+
+bool SkEvent::PostTime(SkEvent* evt, SkEventSinkID sinkID, SkMSec time)
+{
+#if defined(SK_SIMULATE_FAILED_MALLOC) && defined(SK_FIND_MEMORY_LEAKS)
+       gMaxDrawTime = time;
+#endif
+       SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+
+       evt->fTargetID = sinkID;
+
+#ifdef SK_TRACE_EVENTS
+       {
+               SkString        str("SkEvent::Post(");
+               str.append(evt->getType());
+               str.append(", 0x");
+               str.appendHex(sinkID);
+               str.append(", ");
+               str.appendS32(time);
+               str.append(")");
+               event_log(str.c_str());
+       }
+#endif
+
+       globals.fEventMutex.acquire();
+       SkMSec queueDelay = SkEvent::EnqueueTime(evt, time);
+       globals.fEventMutex.release();
+
+       // call outside of us holding the mutex
+       if ((int32_t)queueDelay != ~0)
+               SkEvent::SignalQueueTimer(queueDelay);
+       return true;
+}
+
+bool SkEvent::Enqueue(SkEvent* evt)
+{
+       SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+       //      gEventMutex acquired by caller
+
+       SkASSERT(evt);
+
+       bool wasEmpty = globals.fEventQHead == NULL;
+
+       if (globals.fEventQTail)
+               globals.fEventQTail->fNextEvent = evt;
+       globals.fEventQTail = evt;
+       if (globals.fEventQHead == NULL)
+               globals.fEventQHead = evt;
+       evt->fNextEvent = NULL;
+
+       SkDEBUGCODE(++globals.fEventCounter);
+//     SkDebugf("Enqueue: count=%d\n", gEventCounter);
+
+       return wasEmpty;
+}
+
+SkEvent* SkEvent::Dequeue(SkEventSinkID* sinkID)
+{
+       SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+       globals.fEventMutex.acquire();
+
+       SkEvent* evt = globals.fEventQHead;
+       if (evt)
+       {
+               SkDEBUGCODE(--globals.fEventCounter);
+
+               if (sinkID)
+                       *sinkID = evt->fTargetID;
+
+               globals.fEventQHead = evt->fNextEvent;
+               if (globals.fEventQHead == NULL)
+                       globals.fEventQTail = NULL;
+       }
+       globals.fEventMutex.release();
+
+//     SkDebugf("Dequeue: count=%d\n", gEventCounter);
+
+       return evt;
+}
+
+bool SkEvent::QHasEvents()
+{
+       SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+
+       // this is not thread accurate, need a semaphore for that
+       return globals.fEventQHead != NULL;
+}
+
+#ifdef SK_TRACE_EVENTS
+       static int gDelayDepth;
+#endif
+
+SkMSec SkEvent::EnqueueTime(SkEvent* evt, SkMSec time)
+{
+#ifdef SK_TRACE_EVENTS
+       SkDebugf("enqueue-delay %s %d (%d)", evt->getType(), time, gDelayDepth);
+       const char* idStr = evt->findString("id");
+       if (idStr)
+               SkDebugf(" (%s)", idStr);
+       SkDebugf("\n");
+       ++gDelayDepth;
+#endif
+
+       SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+       //      gEventMutex acquired by caller
+
+       SkEvent* curr = globals.fDelayQHead;
+       SkEvent* prev = NULL;
+
+       while (curr)
+       {
+               if (SkMSec_LT(time, curr->fTime))
+                       break;
+               prev = curr;
+               curr = curr->fNextEvent;
+       }
+
+       evt->fTime = time;
+       evt->fNextEvent = curr;
+       if (prev == NULL)
+               globals.fDelayQHead = evt;
+       else
+               prev->fNextEvent = evt;
+
+       SkMSec delay = globals.fDelayQHead->fTime - SkTime::GetMSecs();
+       if ((int32_t)delay <= 0)
+               delay = 1;
+       return delay;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+#include "SkEventSink.h"
+
+bool SkEvent::ProcessEvent()
+{
+       SkEventSinkID   sinkID;
+       SkEvent*                evt = SkEvent::Dequeue(&sinkID);
+       SkAutoTDelete<SkEvent>  autoDelete(evt);
+       bool                    again = false;
+
+       EVENT_LOGN("ProcessEvent", (int32_t)evt);
+
+       if (evt)
+       {
+               (void)SkEventSink::DoEvent(*evt, sinkID);
+               again = SkEvent::QHasEvents();
+       }
+       return again;
+}
+
+void SkEvent::ServiceQueueTimer()
+{
+       SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+
+       globals.fEventMutex.acquire();
+
+       bool            wasEmpty = false;
+       SkMSec          now = SkTime::GetMSecs();
+       SkEvent*        evt = globals.fDelayQHead;
+
+       while (evt)
+       {
+               if (SkMSec_LT(now, evt->fTime))
+                       break;
+
+#ifdef SK_TRACE_EVENTS
+               --gDelayDepth;
+               SkDebugf("dequeue-delay %s (%d)", evt->getType(), gDelayDepth);
+               const char* idStr = evt->findString("id");
+               if (idStr)
+                       SkDebugf(" (%s)", idStr);
+               SkDebugf("\n");
+#endif
+
+               SkEvent* next = evt->fNextEvent;
+               if (SkEvent::Enqueue(evt))
+                       wasEmpty = true;
+               evt = next;
+       }
+       globals.fDelayQHead = evt;
+
+       SkMSec time = evt ? evt->fTime - now : 0;
+
+       globals.fEventMutex.release();
+
+       if (wasEmpty)
+               SkEvent::SignalNonEmptyQueue();
+
+       SkEvent::SignalQueueTimer(time);
+}
+
+////////////////////////////////////////////////////////////////
+
+void SkEvent::Init()
+{
+}
+
+void SkEvent::Term()
+{
+       SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+
+       SkEvent* evt = globals.fEventQHead;
+       while (evt)
+       {
+               SkEvent* next = evt->fNextEvent;
+               delete evt;
+               evt = next;
+       }
+
+       evt = globals.fDelayQHead;
+       while (evt)
+       {
+               SkEvent* next = evt->fNextEvent;
+               delete evt;
+               evt = next;
+       }
+}
+
diff --git a/libs/graphics/views/SkEventSink.cpp b/libs/graphics/views/SkEventSink.cpp
new file mode 100644 (file)
index 0000000..e2a45f0
--- /dev/null
@@ -0,0 +1,328 @@
+#include "SkEventSink.h"
+#include "SkTagList.h"
+#include "SkThread.h"
+
+#include "SkGlobals.h"
+#include "SkThread.h"
+#include "SkTime.h"
+
+#define SK_EventSink_GlobalsTag                SkSetFourByteTag('e', 'v', 's', 'k')
+
+class SkEventSink_Globals : public SkGlobals::Rec {
+public:
+       SkMutex                 fSinkMutex;
+       SkEventSinkID   fNextSinkID;
+       SkEventSink*    fSinkHead;
+};
+
+static SkGlobals::Rec* create_globals()
+{
+       SkEventSink_Globals* rec = new SkEventSink_Globals;
+       rec->fNextSinkID = 0;
+       rec->fSinkHead = nil;
+       return rec;
+}
+
+SkEventSink::SkEventSink() : fTagHead(nil)
+{
+       SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
+
+       globals.fSinkMutex.acquire();
+
+       fID = ++globals.fNextSinkID;
+       fNextSink = globals.fSinkHead;
+       globals.fSinkHead = this;
+
+       globals.fSinkMutex.release();
+}
+
+SkEventSink::~SkEventSink()
+{
+       SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
+
+       if (fTagHead)
+               SkTagList::DeleteAll(fTagHead);
+
+       globals.fSinkMutex.acquire();
+
+       SkEventSink* sink = globals.fSinkHead;
+       SkEventSink* prev = nil;
+
+       for (;;)
+       {
+               SkEventSink* next = sink->fNextSink;
+               if (sink == this)
+               {
+                       if (prev)
+                               prev->fNextSink = next;
+                       else
+                               globals.fSinkHead = next;
+                       break;
+               }
+               prev = sink;
+               sink = next;
+       }
+       globals.fSinkMutex.release();
+}
+
+bool SkEventSink::doEvent(const SkEvent& evt)
+{
+       return this->onEvent(evt);
+}
+
+bool SkEventSink::doQuery(SkEvent* evt)
+{
+       SkASSERT(evt);
+       return this->onQuery(evt);
+}
+
+bool SkEventSink::onEvent(const SkEvent&)
+{
+       return false;
+}
+
+bool SkEventSink::onQuery(SkEvent*)
+{
+       return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkTagList* SkEventSink::findTagList(U8CPU tag) const
+{
+       return fTagHead ? SkTagList::Find(fTagHead, tag) : nil;
+}
+
+void SkEventSink::addTagList(SkTagList* rec)
+{
+       SkASSERT(rec);
+       SkASSERT(fTagHead == nil || SkTagList::Find(fTagHead, rec->fTag) == nil);
+
+       rec->fNext = fTagHead;
+       fTagHead = rec;
+}
+
+void SkEventSink::removeTagList(U8CPU tag)
+{
+       if (fTagHead)
+               SkTagList::DeleteTag(&fTagHead, tag);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct SkListenersTagList : SkTagList {
+       SkListenersTagList(U16CPU count) : SkTagList(kListeners_SkTagList)
+       {
+               fExtra16 = SkToU16(count);
+               fIDs = (SkEventSinkID*)sk_malloc_throw(count * sizeof(SkEventSinkID));
+       }
+       virtual ~SkListenersTagList()
+       {
+               sk_free(fIDs);
+       }
+
+       int     countListners() const { return fExtra16; }
+
+       int find(SkEventSinkID id) const
+       {
+               const SkEventSinkID* idptr = fIDs;
+               for (int i = fExtra16 - 1; i >= 0; --i)
+                       if (idptr[i] == id)
+                               return i;
+               return -1;
+       }
+
+       SkEventSinkID*  fIDs;
+};
+
+void SkEventSink::addListenerID(SkEventSinkID id)
+{
+       if (id == 0)
+               return;
+
+       SkListenersTagList* prev = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
+       int                                     count = 0;
+
+       if (prev)
+       {
+               if (prev->find(id) >= 0)
+                       return;
+               count = prev->countListners();
+       }
+
+       SkListenersTagList* next = SkNEW_ARGS(SkListenersTagList, (count + 1));
+
+       if (prev)
+       {
+               memcpy(next->fIDs, prev->fIDs, count * sizeof(SkEventSinkID));
+               this->removeTagList(kListeners_SkTagList);
+       }
+       next->fIDs[count] = id;
+       this->addTagList(next);
+}
+
+void SkEventSink::copyListeners(const SkEventSink& sink) 
+{
+       SkListenersTagList* sinkList = (SkListenersTagList*)sink.findTagList(kListeners_SkTagList);
+       if (sinkList == nil)
+               return;
+       SkASSERT(sinkList->countListners() > 0);
+       const SkEventSinkID* iter = sinkList->fIDs;
+       const SkEventSinkID* stop = iter + sinkList->countListners();
+       while (iter < stop)
+               addListenerID(*iter++);
+}
+
+void SkEventSink::removeListenerID(SkEventSinkID id)
+{
+       if (id == 0)
+               return;
+
+       SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
+
+       if (list == nil)
+               return;
+
+       int index = list->find(id);
+       if (index >= 0)
+       {
+               int count = list->countListners();
+               SkASSERT(count > 0);
+               if (count == 1)
+                       this->removeTagList(kListeners_SkTagList);
+               else
+               {
+                       // overwrite without resize/reallocating our struct (for speed)
+                       list->fIDs[index] = list->fIDs[count - 1];
+                       list->fExtra16 = SkToU16(count - 1);
+               }
+       }
+}
+
+bool SkEventSink::hasListeners() const
+{
+       return this->findTagList(kListeners_SkTagList) != nil;
+}
+
+void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay)
+{
+       SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
+       if (list)
+       {
+               SkASSERT(list->countListners() > 0);
+               const SkEventSinkID* iter = list->fIDs;
+               const SkEventSinkID* stop = iter + list->countListners();
+               while (iter < stop)
+                       (SkNEW_ARGS(SkEvent, (evt)))->post(*iter++, delay);
+       }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkEventSink::EventResult SkEventSink::DoEvent(const SkEvent& evt, SkEventSinkID sinkID)
+{
+       SkEventSink* sink = SkEventSink::FindSink(sinkID);
+
+       if (sink)
+       {
+#ifdef SK_DEBUG
+               if (evt.isDebugTrace())
+               {
+                       SkString        etype;
+                       evt.getType(&etype);
+                       SkDebugf("SkEventTrace: dispatching event <%s> to 0x%x", etype.c_str(), sinkID);
+                       const char* idStr = evt.findString("id");
+                       if (idStr)
+                               SkDebugf(" (%s)", idStr);
+                       SkDebugf("\n");
+               }
+#endif
+               return sink->doEvent(evt) ? kHandled_EventResult : kNotHandled_EventResult;
+       }
+       else
+       {
+#ifdef SK_DEBUG
+               if (sinkID)
+                       SkDebugf("DoEvent: Can't find sink for ID(%x)\n", sinkID);
+               else
+                       SkDebugf("Event sent to 0 sinkID\n");
+
+               if (evt.isDebugTrace())
+               {
+                       SkString        etype;
+                       evt.getType(&etype);
+                       SkDebugf("SkEventTrace: eventsink not found <%s> for 0x%x\n", etype.c_str(), sinkID);
+               }
+#endif
+               return kSinkNotFound_EventResult;
+       }
+}
+
+SkEventSink* SkEventSink::FindSink(SkEventSinkID sinkID)
+{
+       if (sinkID == 0)
+               return 0;
+
+       SkEventSink_Globals&    globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
+       SkAutoMutexAcquire              ac(globals.fSinkMutex);
+       SkEventSink*                    sink = globals.fSinkHead;
+
+       while (sink)
+       {
+               if (sink->getSinkID() == sinkID)
+                       return sink;
+               sink = sink->fNextSink;
+       }
+       return nil;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////
+
+#if 0  // experimental, not tested
+
+#include "SkThread.h"
+#include "SkTDict.h"
+
+#define kMinStringBufferSize   128
+static SkMutex                                 gNamedSinkMutex;
+static SkTDict<SkEventSinkID>  gNamedSinkIDs(kMinStringBufferSize);
+
+/**    Register a name/id pair with the system. If the name already exists,
+       replace its ID with the new id. This pair will persist until UnregisterNamedSink()
+       is called.
+*/
+void SkEventSink::RegisterNamedSinkID(const char name[], SkEventSinkID id)
+{
+       if (id && name && *name)
+       {
+               SkAutoMutexAcquire      ac(gNamedSinkMutex);
+               gNamedSinkIDs.set(name, id);
+       }
+}
+
+/**    Return the id that matches the specified name (from a previous call to
+       RegisterNamedSinkID(). If no match is found, return 0
+*/
+SkEventSinkID SkEventSink::FindNamedSinkID(const char name[])
+{
+       SkEventSinkID id = 0;
+
+       if (name && *name)
+       {
+               SkAutoMutexAcquire      ac(gNamedSinkMutex);
+               (void)gNamedSinkIDs.find(name, &id);
+       }
+       return id;
+}
+
+/**    Remove all name/id pairs from the system. This is call internally
+       on shutdown, to ensure no memory leaks. It should not be called
+       before shutdown.
+*/
+void SkEventSink::RemoveAllNamedSinkIDs()
+{
+       SkAutoMutexAcquire      ac(gNamedSinkMutex);
+       (void)gNamedSinkIDs.reset();
+}
+#endif
diff --git a/libs/graphics/views/SkMetaData.cpp b/libs/graphics/views/SkMetaData.cpp
new file mode 100644 (file)
index 0000000..8692979
--- /dev/null
@@ -0,0 +1,388 @@
+#include "SkMetaData.h"
+
+SkMetaData::SkMetaData() : fRec(NULL)
+{
+}
+
+SkMetaData::SkMetaData(const SkMetaData& src) : fRec(NULL)
+{
+       *this = src;
+}
+
+SkMetaData::~SkMetaData()
+{
+       this->reset();
+}
+
+void SkMetaData::reset()
+{
+       Rec* rec = fRec;
+       while (rec)
+       {
+               Rec* next = rec->fNext;
+               Rec::Free(rec);
+               rec = next;
+       }
+       fRec = NULL;
+}
+
+SkMetaData&    SkMetaData::operator=(const SkMetaData& src)
+{
+       this->reset();
+
+       const Rec* rec = src.fRec;
+       while (rec)
+       {
+               this->set(rec->name(), rec->data(), rec->fDataLen, (Type)rec->fType, rec->fDataCount);
+               rec = rec->fNext;
+       }
+       return *this;
+}
+
+void SkMetaData::setS32(const char name[], int32_t value)
+{
+       (void)this->set(name, &value, sizeof(int32_t), kS32_Type, 1);
+}
+
+void SkMetaData::setScalar(const char name[], SkScalar value)
+{
+       (void)this->set(name, &value, sizeof(SkScalar), kScalar_Type, 1);
+}
+
+SkScalar* SkMetaData::setScalars(const char name[], int count, const SkScalar values[])
+{
+       SkASSERT(count > 0);
+       if (count > 0)
+               return (SkScalar*)this->set(name, values, sizeof(SkScalar), kScalar_Type, count);
+       return NULL;
+}
+
+void SkMetaData::setString(const char name[], const char value[])
+{
+       (void)this->set(name, value, sizeof(char), kString_Type, strlen(value) + 1);
+}
+
+void SkMetaData::setPtr(const char name[], void* ptr)
+{
+       (void)this->set(name, &ptr, sizeof(void*), kPtr_Type, 1);
+}
+
+void SkMetaData::setBool(const char name[], bool value)
+{
+       (void)this->set(name, &value, sizeof(bool), kBool_Type, 1);
+}
+
+void* SkMetaData::set(const char name[], const void* data, size_t dataSize, Type type, int count)
+{
+       SkASSERT(name);
+       SkASSERT(dataSize);
+       SkASSERT(count > 0);
+
+       (void)this->remove(name, type);
+
+       size_t  len = strlen(name);
+       Rec*    rec = Rec::Alloc(sizeof(Rec) + dataSize * count + len + 1);
+
+#ifndef SK_DEBUG
+       rec->fType = SkToU8(type);
+#else
+       rec->fType = type;
+#endif
+       rec->fDataLen = SkToU8(dataSize);
+       rec->fDataCount = SkToU16(count);
+       if (data)
+               memcpy(rec->data(), data, dataSize * count);
+       memcpy(rec->name(), name, len + 1);
+
+#ifdef SK_DEBUG
+       rec->fName = rec->name();
+       switch (type) {
+       case kS32_Type:
+               rec->fData.fS32 = *(const int32_t*)rec->data();
+               break;
+       case kScalar_Type:
+               rec->fData.fScalar = *(const SkScalar*)rec->data();
+               break;
+       case kString_Type:
+               rec->fData.fString = (const char*)rec->data();
+               break;
+       case kPtr_Type:
+               rec->fData.fPtr = *(void**)rec->data();
+               break;
+       case kBool_Type:
+               rec->fData.fBool = *(const bool*)rec->data();
+               break;
+       default:
+               SkASSERT(!"bad type");
+               break;
+       }
+#endif
+
+       rec->fNext = fRec;
+       fRec = rec;
+       return rec->data();
+}
+
+bool SkMetaData::findS32(const char name[], int32_t* value) const
+{
+       const Rec* rec = this->find(name, kS32_Type);
+       if (rec)
+       {
+               SkASSERT(rec->fDataCount == 1);
+               if (value)
+                       *value = *(const int32_t*)rec->data();
+               return true;
+       }
+       return false;
+}
+
+bool SkMetaData::findScalar(const char name[], SkScalar* value) const
+{
+       const Rec* rec = this->find(name, kScalar_Type);
+       if (rec)
+       {
+               SkASSERT(rec->fDataCount == 1);
+               if (value)
+                       *value = *(const SkScalar*)rec->data();
+               return true;
+       }
+       return false;
+}
+
+const SkScalar* SkMetaData::findScalars(const char name[], int* count, SkScalar values[]) const
+{
+       const Rec* rec = this->find(name, kScalar_Type);
+       if (rec)
+       {
+               if (count)
+                       *count = rec->fDataCount;
+               if (values)
+                       memcpy(values, rec->data(), rec->fDataCount * rec->fDataLen);
+               return (const SkScalar*)rec->data();
+       }
+       return NULL;
+}
+
+bool SkMetaData::findPtr(const char name[], void** value) const
+{
+       const Rec* rec = this->find(name, kPtr_Type);
+       if (rec)
+       {
+               SkASSERT(rec->fDataCount == 1);
+               if (value)
+                       *value = *(void**)rec->data();
+               return true;
+       }
+       return false;
+}
+
+const char* SkMetaData::findString(const char name[]) const
+{
+       const Rec* rec = this->find(name, kString_Type);
+       SkASSERT(rec == NULL || rec->fDataLen == sizeof(char));
+       return rec ? (const char*)rec->data() : NULL;
+}
+
+bool SkMetaData::findBool(const char name[], bool* value) const
+{
+       const Rec* rec = this->find(name, kBool_Type);
+       if (rec)
+       {
+               SkASSERT(rec->fDataCount == 1);
+               if (value)
+                       *value = *(const bool*)rec->data();
+               return true;
+       }
+       return false;
+}
+
+const SkMetaData::Rec* SkMetaData::find(const char name[], Type type) const
+{
+       const Rec* rec = fRec;
+       while (rec)
+       {
+               if (rec->fType == type && !strcmp(rec->name(), name))
+                       return rec;
+               rec = rec->fNext;
+       }
+       return NULL;
+}
+
+bool SkMetaData::remove(const char name[], Type type)
+{
+       Rec* rec = fRec;
+       Rec* prev = NULL;
+       while (rec)
+       {
+               Rec* next = rec->fNext;
+               if (rec->fType == type && !strcmp(rec->name(), name))
+               {
+                       if (prev)
+                               prev->fNext = next;
+                       else
+                               fRec = next;
+                       Rec::Free(rec);
+                       return true;
+               }
+               prev = rec;
+               rec = next;
+       }
+       return false;
+}
+
+bool SkMetaData::removeS32(const char name[])
+{
+       return this->remove(name, kS32_Type);
+}
+
+bool SkMetaData::removeScalar(const char name[])
+{
+       return this->remove(name, kScalar_Type);
+}
+
+bool SkMetaData::removeString(const char name[])
+{
+       return this->remove(name, kString_Type);
+}
+
+bool SkMetaData::removePtr(const char name[])
+{
+       return this->remove(name, kPtr_Type);
+}
+
+bool SkMetaData::removeBool(const char name[])
+{
+       return this->remove(name, kBool_Type);
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+
+SkMetaData::Iter::Iter(const SkMetaData& metadata)
+{
+       fRec = metadata.fRec;
+}
+
+void SkMetaData::Iter::reset(const SkMetaData& metadata)
+{
+       fRec = metadata.fRec;
+}
+
+const char* SkMetaData::Iter::next(SkMetaData::Type* t, int* count)
+{
+       const char* name = NULL;
+
+       if (fRec)
+       {
+               if (t)
+                       *t = (SkMetaData::Type)fRec->fType;
+               if (count)
+                       *count = fRec->fDataCount;
+               name = fRec->name();
+
+               fRec = fRec->fNext;
+       }
+       return name;
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+
+SkMetaData::Rec* SkMetaData::Rec::Alloc(size_t size)
+{
+       return (Rec*)sk_malloc_throw(size);
+}
+
+void SkMetaData::Rec::Free(Rec* rec)
+{
+       sk_free(rec);
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+void SkMetaData::UnitTest()
+{
+#ifdef SK_SUPPORT_UNITTEST
+       SkMetaData      m1;
+
+       SkASSERT(!m1.findS32("int"));
+       SkASSERT(!m1.findScalar("scalar"));
+       SkASSERT(!m1.findString("hello"));
+       SkASSERT(!m1.removeS32("int"));
+       SkASSERT(!m1.removeScalar("scalar"));
+       SkASSERT(!m1.removeString("hello"));
+       SkASSERT(!m1.removeString("true"));
+       SkASSERT(!m1.removeString("false"));
+
+       m1.setS32("int", 12345);
+       m1.setScalar("scalar", SK_Scalar1 * 42);
+       m1.setString("hello", "world");
+       m1.setPtr("ptr", &m1);
+       m1.setBool("true", true);
+       m1.setBool("false", false);
+
+       int32_t     n;
+       SkScalar        s;
+
+       m1.setScalar("scalar", SK_Scalar1/2);
+
+       SkASSERT(m1.findS32("int", &n) && n == 12345);
+       SkASSERT(m1.findScalar("scalar", &s) && s == SK_Scalar1/2);
+       SkASSERT(!strcmp(m1.findString("hello"), "world"));
+       SkASSERT(m1.hasBool("true", true));
+       SkASSERT(m1.hasBool("false", false));
+
+       Iter    iter(m1);
+       const char*     name;
+
+       static const struct {
+               const char*                     fName;
+               SkMetaData::Type        fType;
+               int                                     fCount;
+       } gElems[] = {
+               { "int",        SkMetaData::kS32_Type,          1 },
+               { "scalar",     SkMetaData::kScalar_Type,       1 },
+               { "ptr",        SkMetaData::kPtr_Type,          1 },
+               { "hello",      SkMetaData::kString_Type,       sizeof("world") },
+               { "true",       SkMetaData::kBool_Type,         1 },
+               { "false",      SkMetaData::kBool_Type,         1 }
+       };
+
+       int                                     loop = 0;
+       int count;
+       SkMetaData::Type        t;
+       while ((name = iter.next(&t, &count)) != NULL)
+       {
+               int match = 0;
+               for (unsigned i = 0; i < SK_ARRAY_COUNT(gElems); i++)
+               {
+                       if (!strcmp(name, gElems[i].fName))
+                       {
+                               match += 1;
+                               SkASSERT(gElems[i].fType == t);
+                               SkASSERT(gElems[i].fCount == count);
+                       }
+               }
+               SkASSERT(match == 1);
+               loop += 1;
+       }
+       SkASSERT(loop == SK_ARRAY_COUNT(gElems));
+
+       SkASSERT(m1.removeS32("int"));
+       SkASSERT(m1.removeScalar("scalar"));
+       SkASSERT(m1.removeString("hello"));
+       SkASSERT(m1.removeBool("true"));
+       SkASSERT(m1.removeBool("false"));
+
+       SkASSERT(!m1.findS32("int"));
+       SkASSERT(!m1.findScalar("scalar"));
+       SkASSERT(!m1.findString("hello"));
+       SkASSERT(!m1.findBool("true"));
+       SkASSERT(!m1.findBool("false"));
+#endif
+}
+
+#endif
+
+
diff --git a/libs/graphics/views/SkTagList.cpp b/libs/graphics/views/SkTagList.cpp
new file mode 100644 (file)
index 0000000..42a3503
--- /dev/null
@@ -0,0 +1,54 @@
+#include "SkTagList.h"
+
+SkTagList::~SkTagList()
+{
+}
+
+SkTagList* SkTagList::Find(SkTagList* rec, U8CPU tag)
+{
+       SkASSERT(tag < kSkTagListCount);
+
+       while (rec != nil)
+       {
+               if (rec->fTag == tag)
+                       break;
+               rec = rec->fNext;
+       }
+       return rec;
+}
+
+void SkTagList::DeleteTag(SkTagList** head, U8CPU tag)
+{
+       SkASSERT(tag < kSkTagListCount);
+
+       SkTagList* rec = *head;
+       SkTagList* prev = nil;
+
+       while (rec != nil)
+       {
+               SkTagList* next = rec->fNext;
+
+               if (rec->fTag == tag)
+               {
+                       if (prev)
+                               prev->fNext = next;
+                       else
+                               *head = next;
+                       delete rec;
+                       break;
+               }
+               prev = rec;
+               rec = next;
+       }
+}
+
+void SkTagList::DeleteAll(SkTagList* rec)
+{
+       while (rec)
+       {
+               SkTagList* next = rec->fNext;
+               delete rec;
+               rec = next;
+       }
+}
+
diff --git a/libs/graphics/views/SkTagList.h b/libs/graphics/views/SkTagList.h
new file mode 100644 (file)
index 0000000..937c030
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef SkTagList_DEFINED
+#define SkTagList_DEFINED
+
+#include "SkTypes.h"
+
+enum SkTagListEnum {
+       kListeners_SkTagList,
+       kViewLayout_SkTagList,
+       kViewArtist_SkTagList,
+
+       kSkTagListCount
+};
+
+struct SkTagList {
+       SkTagList*      fNext;
+       U16                     fExtra16;
+       U8                      fExtra8;
+       U8                      fTag;
+
+       SkTagList(U8CPU tag) : fTag(SkToU8(tag))
+       {
+               SkASSERT(tag < kSkTagListCount);
+               fNext           = nil;
+               fExtra16        = 0;
+               fExtra8         = 0;
+       }
+       virtual ~SkTagList();
+
+       static SkTagList*       Find(SkTagList* head, U8CPU tag);
+       static void                     DeleteTag(SkTagList** headptr, U8CPU tag);
+       static void                     DeleteAll(SkTagList* head);
+};
+
+#endif
diff --git a/libs/graphics/views/SkTextBox.cpp b/libs/graphics/views/SkTextBox.cpp
new file mode 100644 (file)
index 0000000..01d5dbe
--- /dev/null
@@ -0,0 +1,195 @@
+#include "SkTextBox.h"
+#include "SkGlyphCache.h"
+#include "SkUtils.h"
+
+static inline int is_ws(int c)
+{
+       return !((c - 1) >> 5);
+}
+
+static size_t linebreak(const char text[], const char stop[], const SkPaint& paint, SkScalar margin)
+{
+       const char* start = text;
+
+       SkAutoGlyphCache        ac(paint, nil);
+       SkGlyphCache*           cache = ac.getCache();
+       SkFixed                         w = 0;
+       SkFixed                         limit = SkScalarToFixed(margin);
+
+       const char* word_start = text;
+       int                     prevWS = true;
+
+       while (text < stop)
+       {
+        const char* prevText = text;
+               SkUnichar       uni = SkUTF8_NextUnichar(&text);
+               int                     currWS = is_ws(uni);
+
+               if (!currWS && prevWS)
+                       word_start = prevText;
+               prevWS = currWS;
+
+               w += cache->getMetrics(uni).fAdvanceX;
+               if (w > limit)
+               {
+                       if (currWS)     // eat the rest of the whitespace
+                       {
+                               while (text < stop && is_ws(SkUTF8_ToUnichar(text)))
+                                       text += SkUTF8_CountUTF8Bytes(text);
+                       }
+                       else    // backup until a whitespace (or 1 char)
+                       {
+                               if (word_start == start)
+                {
+                    if (prevText > start)
+                        text = prevText;
+                }
+                else
+                    text = word_start;
+                       }
+                       break;
+               }
+       }
+       return text - start;
+}
+
+int SkTextLineBreaker::CountLines(const char text[], size_t len, const SkPaint& paint, SkScalar width)
+{
+       const char* stop = text + len;
+       int                     count = 0;
+
+       if (width > 0)
+       {
+               do {
+                       count += 1;
+                       text += linebreak(text, stop, paint, width);
+               } while (text < stop);
+       }
+       return count;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+SkTextBox::SkTextBox()
+{
+       fBox.setEmpty();
+       fSpacingMul = SK_Scalar1;
+       fSpacingAdd = 0;
+       fMode = kLineBreak_Mode;
+       fSpacingAlign = kStart_SpacingAlign;
+}
+
+void SkTextBox::setMode(Mode mode)
+{
+       SkASSERT((unsigned)mode < kModeCount);
+       fMode = SkToU8(mode);
+}
+
+void SkTextBox::setSpacingAlign(SpacingAlign align)
+{
+       SkASSERT((unsigned)align < kSpacingAlignCount);
+       fSpacingAlign = SkToU8(align);
+}
+
+void SkTextBox::getBox(SkRect* box) const
+{
+       if (box)
+               *box = fBox;
+}
+
+void SkTextBox::setBox(const SkRect& box)
+{
+       fBox = box;
+}
+
+void SkTextBox::setBox(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom)
+{
+       fBox.set(left, top, right, bottom);
+}
+
+void SkTextBox::getSpacing(SkScalar* mul, SkScalar* add) const
+{
+       if (mul)
+               *mul = fSpacingMul;
+       if (add)
+               *add = fSpacingAdd;
+}
+
+void SkTextBox::setSpacing(SkScalar mul, SkScalar add)
+{
+       fSpacingMul = mul;
+       fSpacingAdd = add;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+
+void SkTextBox::draw(SkCanvas* canvas, const char text[], size_t len, const SkPaint& paint)
+{
+       SkASSERT(canvas && &paint && (text || len == 0));
+
+       SkScalar marginWidth = fBox.width();
+
+       if (marginWidth <= 0 || len == 0)
+               return;
+
+       const char*     textStop = text + len;
+
+       SkScalar        x, y, spacing, height, before, after;
+
+       switch (paint.getTextAlign()) {
+       case SkPaint::kLeft_Align:
+               x = 0;
+               break;
+       case SkPaint::kCenter_Align:
+               x = SkScalarHalf(marginWidth);
+               break;
+       default:
+               x = marginWidth;
+               break;
+       }
+       x += fBox.fLeft;
+
+       paint.measureText(nil, 0, &before, &after);
+       spacing = SkScalarMul(after - before, fSpacingMul) + fSpacingAdd;
+       height = fBox.height();
+
+       //      compute Y position for first line
+       {
+               SkScalar textHeight = after - before;
+
+               if (fMode == kLineBreak_Mode && fSpacingAlign != kStart_SpacingAlign)
+               {
+                       int count = SkTextLineBreaker::CountLines(text, textStop - text, paint, marginWidth);
+                       SkASSERT(count > 0);
+                       textHeight += spacing * (count - 1);
+               }
+
+               switch (fSpacingAlign) {
+               case kStart_SpacingAlign:
+                       y = 0;
+                       break;
+               case kCenter_SpacingAlign:
+                       y = SkScalarHalf(height - textHeight);
+                       break;
+               default:
+                       SkASSERT(fSpacingAlign == kEnd_SpacingAlign);
+                       y = height - textHeight;
+                       break;
+               }
+               y += fBox.fTop - before;
+       }
+
+       for (;;)
+       {
+               len = linebreak(text, textStop, paint, marginWidth);
+               if (y + after > 0)
+                       canvas->drawText(text, len, x, y, paint);
+               text += len;
+               if (text >= textStop)
+                       break;
+               y += spacing;
+               if (y + before >= height)
+                       break;
+       } 
+}
+
diff --git a/libs/graphics/xml/SkBML_Verbs.h b/libs/graphics/xml/SkBML_Verbs.h
new file mode 100644 (file)
index 0000000..b23c4de
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef SkBML_Verbs_DEFINED
+#define SkBML_Verbs_DEFINED
+
+enum Verbs {
+       kStartElem_Value_Verb,
+       kStartElem_Index_Verb,
+       kEndElem_Verb,
+       kAttr_Value_Value_Verb,
+       kAttr_Value_Index_Verb,
+       kAttr_Index_Value_Verb,
+       kAttr_Index_Index_Verb,
+
+       kVerbCount
+};
+
+#endif // SkBML_Verbs_DEFINED
diff --git a/libs/graphics/xml/SkBML_XMLParser.cpp b/libs/graphics/xml/SkBML_XMLParser.cpp
new file mode 100644 (file)
index 0000000..7901565
--- /dev/null
@@ -0,0 +1,175 @@
+#include "SkBML_XMLParser.h"
+#include "SkBML_Verbs.h"
+#include "SkStream.h"
+#include "SkXMLWriter.h"
+
+static U8 rbyte(SkStream& s)
+{
+       U8 b;
+       size_t size = s.read(&b, 1);
+       SkASSERT(size == 1);
+       return b;
+}
+
+static int rdata(SkStream& s, int data)
+{
+       SkASSERT((data & ~31) == 0);
+       if (data == 31)
+       {
+               data = rbyte(s);
+               if (data == 0xFF)
+               {
+                       data = rbyte(s);
+                       data = (data << 8) | rbyte(s);
+               }
+       }
+       return data;
+}
+
+static void set(char* array[256], int index, SkStream& s, int data)
+{
+       SkASSERT((unsigned)index <= 255);
+
+       size_t size = rdata(s, data);
+
+       if (array[index] == nil)
+               array[index] = (char*)sk_malloc_throw(size + 1);
+       else
+       {
+               if (strlen(array[index]) < size)
+                       array[index] = (char*)sk_realloc_throw(array[index], size + 1);
+       }
+
+       s.read(array[index], size);
+       array[index][size] = 0;
+}
+
+static void freeAll(char* array[256])
+{
+       for (int i = 0; i < 256; i++)
+               sk_free(array[i]);
+}
+
+struct BMLW {
+       char*   fElems[256];
+       char*   fNames[256];
+       char*   fValues[256];
+
+       // important that these are U8, so we get automatic wrap-around
+       U8      fNextElem, fNextName, fNextValue;
+
+       BMLW()
+       {
+               memset(fElems, 0, sizeof(fElems));
+               memset(fNames, 0, sizeof(fNames));
+               memset(fValues, 0, sizeof(fValues));
+
+               fNextElem = fNextName = fNextValue = 0;
+       }
+       ~BMLW()
+       {
+               freeAll(fElems);
+               freeAll(fNames);
+               freeAll(fValues);
+       }
+};
+
+static void rattr(unsigned verb, SkStream& s, BMLW& rec, SkXMLWriter& writer)
+{
+       int     data = verb & 31;
+       verb >>= 5;
+
+       int     nameIndex, valueIndex;
+
+       switch (verb) {
+       case kAttr_Value_Value_Verb:
+               nameIndex = rec.fNextName;              // record before the ++
+               set(rec.fNames, rec.fNextName++, s, data);
+               valueIndex = rec.fNextValue;    // record before the ++
+               set(rec.fValues, rec.fNextValue++, s, 31);
+               break;
+       case kAttr_Value_Index_Verb:
+               nameIndex = rec.fNextName;              // record before the ++
+               set(rec.fNames, rec.fNextName++, s, data);
+               valueIndex = rbyte(s);
+               break;
+       case kAttr_Index_Value_Verb:
+               nameIndex = rdata(s, data);
+               valueIndex = rec.fNextValue;    // record before the ++
+               set(rec.fValues, rec.fNextValue++, s, 31);
+               break;
+       case kAttr_Index_Index_Verb:
+               nameIndex = rdata(s, data);
+               valueIndex = rbyte(s);
+               break;
+       default:
+               SkASSERT(!"bad verb");
+               return;
+       }
+       writer.addAttribute(rec.fNames[nameIndex], rec.fValues[valueIndex]);
+}
+
+static void relem(unsigned verb, SkStream& s, BMLW& rec, SkXMLWriter& writer)
+{
+       int     data = verb & 31;
+       verb >>= 5;
+
+       int     elemIndex;
+
+       if (verb == kStartElem_Value_Verb)
+       {
+               elemIndex = rec.fNextElem;              // record before the ++
+               set(rec.fElems, rec.fNextElem++, s, data);
+       }
+       else
+       {
+               SkASSERT(verb == kStartElem_Index_Verb);
+               elemIndex = rdata(s, data);
+       }
+
+       writer.startElement(rec.fElems[elemIndex]);
+
+       for (;;)
+       {
+               verb = rbyte(s);
+               switch (verb >> 5) {
+               case kAttr_Value_Value_Verb:
+               case kAttr_Value_Index_Verb:
+               case kAttr_Index_Value_Verb:
+               case kAttr_Index_Index_Verb:
+                       rattr(verb, s, rec, writer);
+                       break;
+               case kStartElem_Value_Verb:
+               case kStartElem_Index_Verb:
+                       relem(verb, s, rec, writer);
+                       break;
+               case kEndElem_Verb:
+                       writer.endElement();
+                       return;
+               default:
+                       SkASSERT(!"bad verb");
+               }
+       }
+}
+
+void BML_XMLParser::Read(SkStream& s, SkXMLWriter& writer)
+{
+       BMLW rec;
+       writer.writeHeader();
+       relem(rbyte(s), s, rec, writer);
+}
+
+void BML_XMLParser::Read(SkStream& s, SkWStream& output)
+{
+       SkXMLStreamWriter writer(&output);
+       Read(s, writer);
+}
+
+void BML_XMLParser::Read(SkStream& s, SkXMLParser& output)
+{
+       SkXMLParserWriter writer(&output);
+       Read(s, writer);
+}
+
+
+
diff --git a/libs/graphics/xml/SkDOM.cpp b/libs/graphics/xml/SkDOM.cpp
new file mode 100644 (file)
index 0000000..431d781
--- /dev/null
@@ -0,0 +1,495 @@
+#include "SkDOM.h"
+
+/////////////////////////////////////////////////////////////////////////
+
+#include "SkXMLParser.h"
+
+bool SkXMLParser::parse(const SkDOM& dom, const SkDOMNode* node)
+{
+       const char* elemName = dom.getName(node);
+
+       if (this->startElement(elemName))
+               return false;
+       
+       SkDOM::AttrIter iter(dom, node);
+       const char*             name, *value;
+       
+       while ((name = iter.next(&value)) != nil)
+               if (this->addAttribute(name, value))
+                       return false;
+
+       if ((node = dom.getFirstChild(node)) != nil)
+               do {
+                       if (!this->parse(dom, node))
+                               return false;
+               } while ((node = dom.getNextSibling(node)) != nil);
+       
+       return !this->endElement(elemName);
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+struct SkDOMAttr {
+       const char*     fName;
+       const char*     fValue;
+};
+
+struct SkDOMNode {
+       const char*     fName;
+       SkDOMNode*      fFirstChild;
+       SkDOMNode*      fNextSibling;
+       U16                     fAttrCount;
+       U8                      fType;
+       U8                      fPad;
+
+       const SkDOMAttr* attrs() const
+       {
+               return (const SkDOMAttr*)(this + 1);
+       }
+       SkDOMAttr* attrs()
+       {
+               return (SkDOMAttr*)(this + 1);
+       }
+};
+
+/////////////////////////////////////////////////////////////////////////
+
+#define kMinChunkSize  512
+
+SkDOM::SkDOM() : fAlloc(kMinChunkSize), fRoot(nil)
+{
+}
+
+SkDOM::~SkDOM()
+{
+}
+
+const SkDOM::Node* SkDOM::getRootNode() const
+{
+       return fRoot;
+}
+
+const SkDOM::Node* SkDOM::getFirstChild(const Node* node, const char name[]) const
+{
+       SkASSERT(node);
+       const Node* child = node->fFirstChild;
+
+       if (name)
+       {
+               for (; child != nil; child = child->fNextSibling)
+                       if (!strcmp(name, child->fName))
+                               break;
+       }
+       return child;
+}
+
+const SkDOM::Node* SkDOM::getNextSibling(const Node* node, const char name[]) const
+{
+       SkASSERT(node);
+       const Node* sibling = node->fNextSibling;
+       if (name)
+       {
+               for (; sibling != nil; sibling = sibling->fNextSibling)
+                       if (!strcmp(name, sibling->fName))
+                               break;
+       }
+       return sibling;
+}
+
+SkDOM::Type SkDOM::getType(const Node* node) const
+{
+       SkASSERT(node);
+       return (Type)node->fType;
+}
+
+const char* SkDOM::getName(const Node* node) const
+{
+       SkASSERT(node);
+       return node->fName;
+}
+
+const char* SkDOM::findAttr(const Node* node, const char name[]) const
+{
+       SkASSERT(node);
+       const Attr*     attr = node->attrs();
+       const Attr* stop = attr + node->fAttrCount;
+
+       while (attr < stop)
+       {
+               if (!strcmp(attr->fName, name))
+                       return attr->fValue;
+               attr += 1;
+       }
+       return nil;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+const SkDOM::Attr* SkDOM::getFirstAttr(const Node* node) const
+{
+    return node->fAttrCount ? node->attrs() : nil;
+}
+
+const SkDOM::Attr* SkDOM::getNextAttr(const Node* node, const Attr* attr) const
+{
+    SkASSERT(node);
+    if (attr == nil)
+        return nil;
+    return (attr - node->attrs() + 1) < node->fAttrCount ? attr + 1 : nil;
+}
+
+const char* SkDOM::getAttrName(const Node* node, const Attr* attr) const
+{
+    SkASSERT(node);
+    SkASSERT(attr);
+    return attr->fName;
+}
+
+const char* SkDOM::getAttrValue(const Node* node, const Attr* attr) const
+{
+    SkASSERT(node);
+    SkASSERT(attr);
+    return attr->fValue;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+SkDOM::AttrIter::AttrIter(const SkDOM&, const SkDOM::Node* node)
+{
+       SkASSERT(node);
+       fAttr = node->attrs();
+       fStop = fAttr + node->fAttrCount;
+}
+
+const char* SkDOM::AttrIter::next(const char** value)
+{
+       const char* name = nil;
+
+       if (fAttr < fStop)
+       {
+               name = fAttr->fName;
+               if (value)
+                       *value = fAttr->fValue;
+               fAttr += 1;
+       }
+       return name;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+#include "SkXMLParser.h"
+#include "SkTDArray.h"
+
+static char* dupstr(SkChunkAlloc* chunk, const char src[])
+{
+       SkASSERT(chunk && src);
+       size_t  len = strlen(src);
+       char*   dst = (char*)chunk->alloc(len + 1, SkChunkAlloc::kThrow_AllocFailType);
+       memcpy(dst, src, len + 1);
+       return dst;
+}
+
+class SkDOMParser : public SkXMLParser {
+       bool fNeedToFlush;
+public:
+       SkDOMParser(SkChunkAlloc* chunk) : SkXMLParser(&fParserError), fAlloc(chunk)
+       {
+               fRoot = nil;
+               fLevel = 0;
+               fNeedToFlush = true;
+       }
+       SkDOM::Node* getRoot() const { return fRoot; }
+       SkXMLParserError fParserError;
+protected:
+       void flushAttributes()
+       {
+               int     attrCount = fAttrs.count();
+
+               SkDOM::Node* node = (SkDOM::Node*)fAlloc->alloc(sizeof(SkDOM::Node) + attrCount * sizeof(SkDOM::Attr),
+                                                                                                               SkChunkAlloc::kThrow_AllocFailType);
+
+               node->fName = fElemName;
+               node->fFirstChild = nil;
+               node->fAttrCount = SkToU16(attrCount);
+               node->fType = SkDOM::kElement_Type;
+
+               if (fRoot == nil)
+               {
+                       node->fNextSibling = nil;
+                       fRoot = node;
+               }
+               else    // this adds siblings in reverse order. gets corrected in onEndElement()
+               {
+                       SkDOM::Node* parent = fParentStack.top();
+                       SkASSERT(fRoot && parent);
+                       node->fNextSibling = parent->fFirstChild;
+                       parent->fFirstChild = node;
+               }
+               *fParentStack.push() = node;
+
+               memcpy(node->attrs(), fAttrs.begin(), attrCount * sizeof(SkDOM::Attr));
+               fAttrs.reset();
+
+       }
+       virtual bool onStartElement(const char elem[])
+       {
+               if (fLevel > 0 && fNeedToFlush)
+                       this->flushAttributes();
+               fNeedToFlush = true;
+               fElemName = dupstr(fAlloc, elem);
+               ++fLevel;
+               return false;
+       }
+       virtual bool onAddAttribute(const char name[], const char value[])
+       {
+               SkDOM::Attr* attr = fAttrs.append();
+               attr->fName = dupstr(fAlloc, name);
+               attr->fValue = dupstr(fAlloc, value);
+               return false;
+       }
+       virtual bool onEndElement(const char elem[])
+       {
+               --fLevel;
+               if (fNeedToFlush)
+                       this->flushAttributes();
+               fNeedToFlush = false;
+
+               SkDOM::Node* parent;
+
+               fParentStack.pop(&parent);
+
+               SkDOM::Node* child = parent->fFirstChild;
+               SkDOM::Node* prev = nil;
+               while (child)
+               {
+                       SkDOM::Node* next = child->fNextSibling;
+                       child->fNextSibling = prev;
+                       prev = child;
+                       child = next;
+               }
+               parent->fFirstChild = prev;
+               return false;
+       }
+private:
+       SkTDArray<SkDOM::Node*> fParentStack;
+       SkChunkAlloc*   fAlloc;
+       SkDOM::Node*    fRoot;
+
+       // state needed for flushAttributes()
+       SkTDArray<SkDOM::Attr>  fAttrs;
+       char*                                   fElemName;
+       int                                             fLevel;
+};
+
+const SkDOM::Node* SkDOM::build(const char doc[], size_t len)
+{
+       fAlloc.reset();
+       SkDOMParser     parser(&fAlloc);
+       if (!parser.parse(doc, len))
+       {
+               SkDEBUGCODE(SkDebugf("xml parse error, line %d\n", parser.fParserError.getLineNumber());)
+               fRoot = nil;
+               fAlloc.reset();
+               return nil;
+       }
+       fRoot = parser.getRoot();
+       return fRoot;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+static void walk_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLParser* parser)
+{
+       const char* elem = dom.getName(node);
+
+       parser->startElement(elem);
+       
+       SkDOM::AttrIter iter(dom, node);
+       const char*             name;
+       const char*             value;
+       while ((name = iter.next(&value)) != nil)
+               parser->addAttribute(name, value);
+
+       node = dom.getFirstChild(node, nil);
+       while (node)
+       {
+               walk_dom(dom, node, parser);
+               node = dom.getNextSibling(node, nil);
+       }
+
+       parser->endElement(elem);
+}
+
+const SkDOM::Node* SkDOM::copy(const SkDOM& dom, const SkDOM::Node* node)
+{
+       fAlloc.reset();
+       SkDOMParser     parser(&fAlloc);
+
+       walk_dom(dom, node, &parser);
+
+       fRoot = parser.getRoot();
+       return fRoot;
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+int SkDOM::countChildren(const Node* node, const char elem[]) const
+{
+       int count = 0;
+
+       node = this->getFirstChild(node, elem);
+       while (node)
+       {
+               count += 1;
+               node = this->getNextSibling(node, elem);
+       }
+       return count;
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+#include "SkParse.h"
+
+bool SkDOM::findS32(const Node* node, const char name[], int32_t* value) const
+{
+       const char* vstr = this->findAttr(node, name);
+       return vstr && SkParse::FindS32(vstr, value);
+}
+
+bool SkDOM::findScalars(const Node* node, const char name[], SkScalar value[], int count) const
+{
+       const char* vstr = this->findAttr(node, name);
+       return vstr && SkParse::FindScalars(vstr, value, count);
+}
+
+bool SkDOM::findHex(const Node* node, const char name[], uint32_t* value) const
+{
+       const char* vstr = this->findAttr(node, name);
+       return vstr && SkParse::FindHex(vstr, value);
+}
+
+bool SkDOM::findBool(const Node* node, const char name[], bool* value) const
+{
+       const char* vstr = this->findAttr(node, name);
+       return vstr && SkParse::FindBool(vstr, value);
+}
+
+int SkDOM::findList(const Node* node, const char name[], const char list[]) const
+{
+       const char* vstr = this->findAttr(node, name);
+       return vstr ? SkParse::FindList(vstr, list) : -1;
+}
+
+bool SkDOM::hasAttr(const Node* node, const char name[], const char value[]) const
+{
+       const char* vstr = this->findAttr(node, name);
+       return vstr && !strcmp(vstr, value);
+}
+
+bool SkDOM::hasS32(const Node* node, const char name[], int32_t target) const
+{
+       const char* vstr = this->findAttr(node, name);
+       int32_t     value;
+       return vstr && SkParse::FindS32(vstr, &value) && value == target;
+}
+
+bool SkDOM::hasScalar(const Node* node, const char name[], SkScalar target) const
+{
+       const char* vstr = this->findAttr(node, name);
+       SkScalar        value;
+       return vstr && SkParse::FindScalar(vstr, &value) && value == target;
+}
+
+bool SkDOM::hasHex(const Node* node, const char name[], uint32_t target) const
+{
+       const char* vstr = this->findAttr(node, name);
+       uint32_t        value;
+       return vstr && SkParse::FindHex(vstr, &value) && value == target;
+}
+
+bool SkDOM::hasBool(const Node* node, const char name[], bool target) const
+{
+       const char* vstr = this->findAttr(node, name);
+       bool            value;
+       return vstr && SkParse::FindBool(vstr, &value) && value == target;
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+static void tab(int level)
+{
+       while (--level >= 0)
+               SkDebugf("\t");
+}
+
+void SkDOM::dump(const Node* node, int level) const
+{
+       if (node == nil)
+               node = this->getRootNode();
+       if (node)
+       {
+               tab(level);
+               SkDebugf("<%s", this->getName(node));
+
+               const Attr* attr = node->attrs();
+               const Attr* stop = attr + node->fAttrCount;
+               for (; attr < stop; attr++)
+                       SkDebugf(" %s=\"%s\"", attr->fName, attr->fValue);
+
+               const Node* child = this->getFirstChild(node);
+               if (child)
+               {
+                       SkDebugf(">\n");
+                       while (child)
+                       {
+                               this->dump(child, level+1);
+                               child = this->getNextSibling(child);
+                       }
+                       tab(level);
+                       SkDebugf("</%s>\n", node->fName);
+               }
+               else
+                       SkDebugf("/>\n");
+       }
+}
+
+void SkDOM::UnitTest()
+{
+#ifdef SK_SUPPORT_UNITTEST
+       static const char gDoc[] = 
+               "<root a='1' b='2'>"
+                       "<elem1 c='3' />"
+                       "<elem2 d='4' />"
+                       "<elem3 e='5'>"
+                               "<subelem1/>"
+                               "<subelem2 f='6' g='7'/>"
+                       "</elem3>"
+                       "<elem4 h='8'/>"
+               "</root>"
+               ;
+
+       SkDOM   dom;
+
+       SkASSERT(dom.getRootNode() == nil);
+
+       const Node* root = dom.build(gDoc, sizeof(gDoc) - 1);
+       SkASSERT(root && dom.getRootNode() == root);
+
+       const char* v = dom.findAttr(root, "a");
+       SkASSERT(v && !strcmp(v, "1"));
+       v = dom.findAttr(root, "b");
+       SkASSERT(v && !strcmp(v, "2"));
+       v = dom.findAttr(root, "c");
+       SkASSERT(v == nil);
+
+       SkASSERT(dom.getFirstChild(root, "elem1"));
+       SkASSERT(!dom.getFirstChild(root, "subelem1"));
+
+       dom.dump();
+#endif
+}
+
+#endif
+
diff --git a/libs/graphics/xml/SkJS.cpp b/libs/graphics/xml/SkJS.cpp
new file mode 100644 (file)
index 0000000..06e7e83
--- /dev/null
@@ -0,0 +1,219 @@
+#include <jsapi.h>
+
+#include "SkJS.h"
+#include "SkString.h"
+
+#ifdef _WIN32_WCE
+extern "C" {
+       void abort() {
+               SkASSERT(0);
+       }
+
+       unsigned int _control87(unsigned int _new, unsigned int mask ) {
+               SkASSERT(0);
+               return 0;
+       }
+
+       time_t mktime(struct tm *timeptr ) {
+               SkASSERT(0);
+               return 0;
+       }
+
+//     int errno;
+
+       char *strdup(const char *) {
+               SkASSERT(0);
+               return 0;
+       }
+
+       char *strerror(int errnum) {
+               SkASSERT(0);
+               return 0;
+       }
+
+       int isatty(void* fd) {
+               SkASSERT(0);
+               return 0;
+       }
+
+       int putenv(const char *envstring) {
+               SkASSERT(0);
+               return 0;
+       }
+
+       char *getenv(const char *varname) {
+               SkASSERT(0);
+               return 0;
+       }
+
+       void GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime) {
+               SkASSERT(0);
+       }
+
+       struct tm * localtime(const time_t *timer) {
+               SkASSERT(0);
+               return 0;
+       }
+
+       size_t strftime(char *strDest, size_t maxsize, const char *format,
+               const struct tm *timeptr ) {
+               SkASSERT(0);
+               return 0;
+       }
+
+}
+#endif
+
+static JSBool
+global_enumerate(JSContext *cx, JSObject *obj)
+{
+#ifdef LAZY_STANDARD_CLASSES
+    return JS_EnumerateStandardClasses(cx, obj);
+#else
+    return JS_TRUE;
+#endif
+}
+
+static JSBool
+global_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp)
+{
+#ifdef LAZY_STANDARD_CLASSES
+    if ((flags & JSRESOLVE_ASSIGNING) == 0) {
+        JSBool resolved;
+
+        if (!JS_ResolveStandardClass(cx, obj, id, &resolved))
+            return JS_FALSE;
+        if (resolved) {
+            *objp = obj;
+            return JS_TRUE;
+        }
+    }
+#endif
+
+#if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX)
+    if ((flags & (JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING)) == 0) {
+        /*
+         * Do this expensive hack only for unoptimized Unix builds, which are
+         * not used for benchmarking.
+         */
+        char *path, *comp, *full;
+        const char *name;
+        JSBool ok, found;
+        JSFunction *fun;
+
+        if (!JSVAL_IS_STRING(id))
+            return JS_TRUE;
+        path = getenv("PATH");
+        if (!path)
+            return JS_TRUE;
+        path = JS_strdup(cx, path);
+        if (!path)
+            return JS_FALSE;
+        name = JS_GetStringBytes(JSVAL_TO_STRING(id));
+        ok = JS_TRUE;
+        for (comp = strtok(path, ":"); comp; comp = strtok(NULL, ":")) {
+            if (*comp != '\0') {
+                full = JS_smprintf("%s/%s", comp, name);
+                if (!full) {
+                    JS_ReportOutOfMemory(cx);
+                    ok = JS_FALSE;
+                    break;
+                }
+            } else {
+                full = (char *)name;
+            }
+            found = (access(full, X_OK) == 0);
+            if (*comp != '\0')
+                free(full);
+            if (found) {
+                fun = JS_DefineFunction(cx, obj, name, Exec, 0, JSPROP_ENUMERATE);
+                ok = (fun != NULL);
+                if (ok)
+                    *objp = obj;
+                break;
+            }
+        }
+        JS_free(cx, path);
+        return ok;
+    }
+#else
+    return JS_TRUE;
+#endif
+}
+
+JSClass global_class = {
+    "global", JSCLASS_NEW_RESOLVE,
+    JS_PropertyStub,  JS_PropertyStub,
+    JS_PropertyStub,  JS_PropertyStub,
+    global_enumerate, (JSResolveOp) global_resolve,
+    JS_ConvertStub,   JS_FinalizeStub
+};
+
+SkJS::SkJS(void* hwnd) : SkOSWindow(hwnd) {
+       if ((fRuntime = JS_NewRuntime(0x100000)) == nil) {
+               SkASSERT(0);
+               return;
+       }
+       if ((fContext = JS_NewContext(fRuntime, 0x1000)) == nil) {
+               SkASSERT(0);
+               return;
+       }
+       ;
+       if ((fGlobal = JS_NewObject(fContext, &global_class, NULL, NULL)) == nil) {
+               SkASSERT(0);
+               return;
+       }
+       if (JS_InitStandardClasses(fContext, fGlobal) == nil) {
+               SkASSERT(0);
+               return;
+       }
+       setConfig(SkBitmap::kARGB32_Config);
+       updateSize();
+       setVisibleP(true);
+       InitializeDisplayables(getBitmap(), fContext, fGlobal, NULL);
+}
+
+SkJS::~SkJS() {
+       DisposeDisplayables();
+    JS_DestroyContext(fContext);
+    JS_DestroyRuntime(fRuntime);
+    JS_ShutDown();
+}
+
+SkBool SkJS::EvaluateScript(const char* script, jsval* rVal) {
+       return JS_EvaluateScript(fContext, fGlobal, script, strlen(script),
+               "memory" /* no file name */, 0 /* no line number */, rVal);
+}
+
+SkBool SkJS::ValueToString(jsval value, SkString* string) {
+        JSString* str = JS_ValueToString(fContext, value);
+        if (str == NULL)
+                return false;
+        string->set(JS_GetStringBytes(str));
+        return true;
+}
+
+#ifdef SK_DEBUG
+void SkJS::Test(void* hwnd) {
+       SkJS js(hwnd);
+       jsval val;
+       SkBool success = js.EvaluateScript("22/7", &val);
+       SkASSERT(success);
+       SkString string;
+       success = js.ValueToString(val, &string);
+       SkASSERT(success);
+       SkASSERT(strcmp(string.c_str(), "3.142857142857143") == 0);
+       success = js.EvaluateScript(
+               "var rect = new rectangle();"
+               "rect.left = 4;"
+               "rect.top = 10;"
+               "rect.right = 20;"
+               "rect.bottom = 30;"
+               "rect.width = rect.height + 20;"
+               "rect.draw();"
+               , &val);
+       SkASSERT(success);
+       success = js.ValueToString(val, &string);
+       SkASSERT(success);
+}
+#endif
\ No newline at end of file
diff --git a/libs/graphics/xml/SkJSDisplayable.cpp b/libs/graphics/xml/SkJSDisplayable.cpp
new file mode 100644 (file)
index 0000000..6d5e10f
--- /dev/null
@@ -0,0 +1,455 @@
+#include <jsapi.h>
+#include "SkJS.h"
+#include "SkDisplayType.h"
+//#include "SkAnimateColor.h"
+#include "SkAnimateMaker.h"
+#include "SkAnimateSet.h"
+//#include "SkAnimateTransform.h"
+#include "SkCanvas.h"
+//#include "SkDimensions.h"
+#include "SkDisplayAdd.h"
+#include "SkDisplayApply.h"
+//#include "SkDisplayBefore.h"
+#include "SkDisplayEvent.h"
+//#include "SkDisplayFocus.h"
+#include "SkDisplayInclude.h"
+#include "SkDisplayPost.h"
+#include "SkDisplayRandom.h"
+#include "SkDraw3D.h"
+#include "SkDrawBitmap.h"
+#include "SkDrawClip.h"
+#include "SkDrawDash.h"
+#include "SkDrawDiscrete.h"
+#include "SkDrawEmboss.h"
+//#include "SkDrawFont.h"
+#include "SkDrawFull.h"
+#include "SkDrawGradient.h"
+#include "SkDrawLine.h"
+//#include "SkDrawMaskFilter.h"
+#include "SkDrawMatrix.h"
+#include "SkDrawOval.h"
+#include "SkDrawPaint.h"
+#include "SkDrawPath.h"
+#include "SkDrawPoint.h"
+// #include "SkDrawStroke.h"
+#include "SkDrawText.h"
+#include "SkDrawTo.h"
+//#include "SkDrawTransferMode.h"
+#include "SkDrawTransparentShader.h"
+//#include "SkDrawUse.h"
+#include "SkMatrixParts.h"
+#include "SkPathParts.h"
+#include "SkPostParts.h"
+#include "SkScript.h"
+#include "SkSnapshot.h"
+#include "SkTextOnPath.h"
+#include "SkTextToPath.h"
+
+
+class SkJSDisplayable {
+public:
+       SkJSDisplayable() : fDisplayable(nil) {}
+       ~SkJSDisplayable() { delete fDisplayable; }
+       static void Destructor(JSContext *cx, JSObject *obj);
+       static JSBool GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
+       static JSBool SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
+       static SkCanvas* gCanvas;
+       static SkPaint* gPaint;
+       static JSBool Draw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+       SkDisplayable* fDisplayable;
+};
+
+SkCanvas* SkJSDisplayable::gCanvas;
+SkPaint* SkJSDisplayable::gPaint;
+
+JSBool SkJSDisplayable::Draw(JSContext *cx, JSObject *obj, uintN argc,
+                                                                       jsval *argv, jsval *rval)
+{
+    SkJSDisplayable *p = (SkJSDisplayable*) JS_GetPrivate(cx, obj);
+    SkASSERT(p->fDisplayable->isDrawable());
+       SkDrawable* drawable = (SkDrawable*) p->fDisplayable;
+       SkAnimateMaker maker(nil, gCanvas, gPaint);
+       drawable->draw(maker);
+       return JS_TRUE;
+}
+
+
+JSFunctionSpec SkJSDisplayable_methods[] = 
+{
+       { "draw", SkJSDisplayable::Draw, 1, 0, 0 },
+       { 0 }
+};
+
+static JSPropertySpec* gDisplayableProperties[kNumberOfTypes];
+static JSClass gDisplayableClasses[kNumberOfTypes];
+
+#define JS_INIT(_prefix, _class) \
+static JSBool _class##Constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { \
+       SkJSDisplayable* jsDisplayable = new SkJSDisplayable(); \
+       jsDisplayable->fDisplayable = new _prefix##_class(); \
+       JS_SetPrivate(cx, obj, (void*) jsDisplayable); \
+       return JS_TRUE; \
+} \
+       \
+static JSObject* _class##Init(JSContext *cx, JSObject *obj, JSObject *proto) { \
+       JSObject *newProtoObj = JS_InitClass(cx, obj, proto, &gDisplayableClasses[SkType_##_class], \
+               _class##Constructor, 0, \
+               NULL, SkJSDisplayable_methods , \
+               NULL, NULL); \
+       JS_DefineProperties(cx, newProtoObj, gDisplayableProperties[SkType_##_class]); \
+    return newProtoObj; \
+}
+
+JS_INIT(Sk, Add)
+JS_INIT(Sk, AddCircle)
+JS_INIT(Sk, AddOval)
+JS_INIT(Sk, AddPath)
+JS_INIT(Sk, AddRectangle)
+JS_INIT(Sk, AddRoundRect)
+//JS_INIT(Sk, After)
+JS_INIT(Sk, Apply)
+// JS_INIT(Sk, Animate)
+//JS_INIT(Sk, AnimateColor)
+JS_INIT(Sk, AnimateField)
+//JS_INIT(Sk, AnimateRotate)
+//JS_INIT(Sk, AnimateScale)
+//JS_INIT(Sk, AnimateTranslate)
+JS_INIT(SkDraw, Bitmap)
+JS_INIT(Sk, BaseBitmap)
+//JS_INIT(Sk, Before)
+JS_INIT(SkDraw, BitmapShader)
+JS_INIT(SkDraw, Blur)
+JS_INIT(SkDraw, Clip)
+JS_INIT(SkDraw, Color)
+JS_INIT(Sk, CubicTo)
+JS_INIT(Sk, Dash)
+JS_INIT(Sk, Data)
+//JS_INIT(Sk, Dimensions)
+JS_INIT(Sk, Discrete)
+JS_INIT(Sk, DrawTo)
+JS_INIT(SkDraw, Emboss)
+JS_INIT(SkDisplay, Event)
+// JS_INIT(SkDraw, Font)
+// JS_INIT(Sk, Focus)
+JS_INIT(Sk, Image)
+JS_INIT(Sk, Include)
+// JS_INIT(Sk, Input)
+JS_INIT(Sk, Line)
+JS_INIT(Sk, LinearGradient)
+JS_INIT(Sk, LineTo)
+JS_INIT(SkDraw, Matrix)
+JS_INIT(Sk, Move)
+JS_INIT(Sk, MoveTo)
+JS_INIT(Sk, Oval)
+JS_INIT(SkDraw, Path)
+JS_INIT(SkDraw, Paint)
+JS_INIT(Sk, DrawPoint)
+JS_INIT(Sk, PolyToPoly)
+JS_INIT(Sk, Polygon)
+JS_INIT(Sk, Polyline)
+JS_INIT(Sk, Post)
+JS_INIT(Sk, QuadTo)
+JS_INIT(Sk, RadialGradient)
+JS_INIT(SkDisplay, Random)
+JS_INIT(Sk, RectToRect)
+JS_INIT(Sk, Rectangle)
+JS_INIT(Sk, Remove)
+JS_INIT(Sk, Replace)
+JS_INIT(Sk, Rotate)
+JS_INIT(Sk, RoundRect)
+JS_INIT(Sk, Scale)
+JS_INIT(Sk, Set)
+JS_INIT(Sk, Skew)
+// JS_INIT(Sk, 3D_Camera)
+// JS_INIT(Sk, 3D_Patch)
+#ifdef SK_SUPPORT_IMAGE_ENCODE
+JS_INIT(Sk, Snapshot)
+#endif
+// JS_INIT(SkDraw, Stroke)
+JS_INIT(Sk, Text)
+JS_INIT(Sk, TextOnPath)
+JS_INIT(Sk, TextToPath)
+JS_INIT(Sk, Translate)
+//JS_INIT(Sk, Use)
+
+#if SK_USE_CONDENSED_INFO == 0
+static void GenerateTables() {
+       for (int index = 0; index < kTypeNamesSize; index++) {
+               int infoCount;
+               SkDisplayTypes type = gTypeNames[index].fType;
+               const SkMemberInfo* info = SkDisplayType::GetMembers(nil /* fMaker */, type, &infoCount);
+               if (info == nil)
+                       continue;
+               gDisplayableProperties[type] = new JSPropertySpec[infoCount + 1];
+               JSPropertySpec* propertySpec = gDisplayableProperties[type];
+               memset(propertySpec, 0, sizeof (JSPropertySpec) * (infoCount + 1));
+               for (int inner = 0; inner < infoCount; inner++) {
+                       if (info[inner].fType == SkType_BaseClassInfo)
+                               continue;
+                       propertySpec[inner].name = info[inner].fName;
+                       propertySpec[inner].tinyid = inner;
+                       propertySpec[inner].flags = JSPROP_ENUMERATE;
+               }
+               gDisplayableClasses[type].name = gTypeNames[index].fName;
+               gDisplayableClasses[type].flags = JSCLASS_HAS_PRIVATE;
+               gDisplayableClasses[type].addProperty = JS_PropertyStub;
+               gDisplayableClasses[type].delProperty = JS_PropertyStub;
+               gDisplayableClasses[type].getProperty = SkJSDisplayable::GetProperty;
+               gDisplayableClasses[type].setProperty = SkJSDisplayable::SetProperty;
+               gDisplayableClasses[type].enumerate = JS_EnumerateStub;
+               gDisplayableClasses[type].resolve = JS_ResolveStub;
+               gDisplayableClasses[type].convert = JS_ConvertStub;
+               gDisplayableClasses[type].finalize = SkJSDisplayable::Destructor;
+       }
+}
+#endif
+
+void SkJSDisplayable::Destructor(JSContext *cx, JSObject *obj) {
+       delete (SkJSDisplayable*) JS_GetPrivate(cx, obj);
+}
+
+JSBool SkJSDisplayable::GetProperty(JSContext *cx, JSObject *obj, jsval id,
+                                                                jsval *vp)
+{
+       if (JSVAL_IS_INT(id) == 0)
+               return JS_TRUE; 
+       SkJSDisplayable *p = (SkJSDisplayable *) JS_GetPrivate(cx, obj);
+       SkDisplayable* displayable = p->fDisplayable;
+       SkDisplayTypes displayableType = displayable->getType();
+       int members;
+       const SkMemberInfo* info = SkDisplayType::GetMembers(nil /* fMaker */, displayableType, &members);
+       int idIndex = JSVAL_TO_INT(id);
+       SkASSERT(idIndex >= 0 && idIndex < members);
+       info = &info[idIndex];
+       SkDisplayTypes infoType = (SkDisplayTypes) info->fType;
+       SkScalar scalar = 0;
+       S32 s32 = 0;
+       SkString* string= nil;
+       JSString *str;
+       if (infoType == SkType_MemberProperty) {
+               infoType = info->propertyType();
+               switch (infoType) {
+                       case SkType_Scalar: {
+                               SkScriptValue scriptValue;
+                               bool success = displayable->getProperty(info->propertyIndex(), &scriptValue);
+                               SkASSERT(scriptValue.fType == SkType_Scalar);
+                               scalar = scriptValue.fOperand.fScalar;
+                               } break;
+                       default:
+                               SkASSERT(0); // !!! unimplemented
+               }
+       } else {
+               SkASSERT(info->fCount == 1);
+               switch (infoType) {
+                       case SkType_Boolean:
+                       case SkType_Color:
+                       case SkType_S32:
+                               s32 = *(S32*) info->memberData(displayable);
+                               break;
+                       case SkType_String:
+                               info->getString(displayable, &string);
+                               break;
+                       case SkType_Scalar:
+                               SkOperand operand;
+                               info->getValue(displayable, &operand, 1);
+                               scalar = operand.fScalar;
+                               break;
+                       default:
+                               SkASSERT(0); // !!! unimplemented
+               }
+       }
+       switch (infoType) {
+               case SkType_Boolean:
+                       *vp = BOOLEAN_TO_JSVAL(s32);
+                       break;
+               case SkType_Color:
+               case SkType_S32:
+                       *vp = INT_TO_JSVAL(s32);
+                       break;
+               case SkType_Scalar:
+                       if (SkScalarFraction(scalar) == 0)
+                               *vp = INT_TO_JSVAL(SkScalarFloor(scalar));
+                       else
+#ifdef SK_SCALAR_IS_FLOAT
+                       *vp = DOUBLE_TO_JSVAL(scalar);
+#else
+                       *vp = DOUBLE_TO_JSVAL(scalar / 65536.0f );
+#endif
+                       break;
+               case SkType_String:
+                       str = JS_NewStringCopyN(cx, string->c_str(), string->size());
+                       *vp = STRING_TO_JSVAL(str);
+                       break;
+               default:
+                       SkASSERT(0); // !!! unimplemented
+       }
+    return JS_TRUE;
+}
+
+JSBool SkJSDisplayable::SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) {
+       if (JSVAL_IS_INT(id) == 0)
+               return JS_TRUE; 
+       SkJSDisplayable *p = (SkJSDisplayable *) JS_GetPrivate(cx, obj);
+       SkDisplayable* displayable = p->fDisplayable;
+       SkDisplayTypes displayableType = displayable->getType();
+       int members;
+       const SkMemberInfo* info = SkDisplayType::GetMembers(nil /* fMaker */, displayableType, &members);
+       int idIndex = JSVAL_TO_INT(id);
+       SkASSERT(idIndex >= 0 && idIndex < members);
+       info = &info[idIndex];
+       SkDisplayTypes infoType = info->getType();
+       SkScalar scalar = 0;
+       S32 s32 = 0;
+       SkString string;
+       JSString* str;
+       jsval value = *vp;
+       switch (infoType) {
+               case SkType_Boolean:
+                       s32 = JSVAL_TO_BOOLEAN(value);
+                       break;
+               case SkType_Color:
+               case SkType_S32:
+                       s32 = JSVAL_TO_INT(value);
+                       break;
+               case SkType_Scalar:
+                       if (JSVAL_IS_INT(value))
+                               scalar = SkIntToScalar(JSVAL_TO_INT(value));
+                       else {
+                               SkASSERT(JSVAL_IS_DOUBLE(value));
+#ifdef SK_SCALAR_IS_FLOAT
+                               scalar = (float) *(double*) JSVAL_TO_DOUBLE(value);
+#else
+                               scalar = (SkFixed)  (*(double*)JSVAL_TO_DOUBLE(value) * 65536.0);
+#endif
+                       }
+                       break;
+               case SkType_String:
+                       str = JS_ValueToString(cx, value);
+                       string.set(JS_GetStringBytes(str));
+                       break;
+               default:
+                       SkASSERT(0); // !!! unimplemented
+       }
+       if (info->fType == SkType_MemberProperty) {
+               switch (infoType) {
+                       case SkType_Scalar: {
+                               SkScriptValue scriptValue;
+                               scriptValue.fType = SkType_Scalar;
+                               scriptValue.fOperand.fScalar = scalar;
+                               displayable->setProperty(-1 - (int) info->fOffset, scriptValue);
+                               } break;
+                       default:
+                               SkASSERT(0); // !!! unimplemented
+               }
+       } else {
+               SkASSERT(info->fCount == 1);
+               switch (infoType) {
+                       case SkType_Boolean:
+                       case SkType_Color:
+                       case SkType_S32:
+                               s32 = *(S32*) ((const char*) displayable + info->fOffset);
+                               break;
+                       case SkType_String:
+                               info->setString(displayable, &string);
+                               break;
+                       case SkType_Scalar:
+                               SkOperand operand;
+                               operand.fScalar = scalar;
+                               info->setValue(displayable, &operand, 1);
+                               break;
+                       default:
+                               SkASSERT(0); // !!! unimplemented
+               }
+       }
+    return JS_TRUE;
+}
+
+void SkJS::InitializeDisplayables(const SkBitmap& bitmap, JSContext *cx, JSObject *obj, JSObject *proto) {
+       SkJSDisplayable::gCanvas = new SkCanvas(bitmap);
+       SkJSDisplayable::gPaint = new SkPaint();
+#if SK_USE_CONDENSED_INFO == 0
+       GenerateTables();
+#else
+       SkASSERT(0); // !!! compressed version hasn't been implemented
+#endif
+       AddInit(cx, obj, proto);
+       AddCircleInit(cx, obj, proto);
+       AddOvalInit(cx, obj, proto);
+       AddPathInit(cx, obj, proto);
+       AddRectangleInit(cx, obj, proto);
+       AddRoundRectInit(cx, obj, proto);
+//     AfterInit(cx, obj, proto);
+       ApplyInit(cx, obj, proto);
+       // AnimateInit(cx, obj, proto);
+//     AnimateColorInit(cx, obj, proto);
+       AnimateFieldInit(cx, obj, proto);
+//     AnimateRotateInit(cx, obj, proto);
+//     AnimateScaleInit(cx, obj, proto);
+//     AnimateTranslateInit(cx, obj, proto);
+       BitmapInit(cx, obj, proto);
+//     BaseBitmapInit(cx, obj, proto);
+//     BeforeInit(cx, obj, proto);
+       BitmapShaderInit(cx, obj, proto);
+       BlurInit(cx, obj, proto);
+       ClipInit(cx, obj, proto);
+       ColorInit(cx, obj, proto);
+       CubicToInit(cx, obj, proto);
+       DashInit(cx, obj, proto);
+       DataInit(cx, obj, proto);
+//     DimensionsInit(cx, obj, proto);
+       DiscreteInit(cx, obj, proto);
+       DrawToInit(cx, obj, proto);
+       EmbossInit(cx, obj, proto);
+       EventInit(cx, obj, proto);
+//     FontInit(cx, obj, proto);
+//     FocusInit(cx, obj, proto);
+       ImageInit(cx, obj, proto);
+       IncludeInit(cx, obj, proto);
+//     InputInit(cx, obj, proto);
+       LineInit(cx, obj, proto);
+       LinearGradientInit(cx, obj, proto);
+       LineToInit(cx, obj, proto);
+       MatrixInit(cx, obj, proto);
+       MoveInit(cx, obj, proto);
+       MoveToInit(cx, obj, proto);
+       OvalInit(cx, obj, proto);
+       PathInit(cx, obj, proto);
+       PaintInit(cx, obj, proto);
+       DrawPointInit(cx, obj, proto);
+       PolyToPolyInit(cx, obj, proto);
+       PolygonInit(cx, obj, proto);
+       PolylineInit(cx, obj, proto);
+       PostInit(cx, obj, proto);
+       QuadToInit(cx, obj, proto);
+       RadialGradientInit(cx, obj, proto);
+       RandomInit(cx, obj, proto);
+       RectToRectInit(cx, obj, proto);
+       RectangleInit(cx, obj, proto);
+       RemoveInit(cx, obj, proto);
+       ReplaceInit(cx, obj, proto);
+       RotateInit(cx, obj, proto);
+       RoundRectInit(cx, obj, proto);
+       ScaleInit(cx, obj, proto);
+       SetInit(cx, obj, proto);
+       SkewInit(cx, obj, proto);
+       // 3D_CameraInit(cx, obj, proto);
+       // 3D_PatchInit(cx, obj, proto);
+       #ifdef SK_SUPPORT_IMAGE_ENCODE
+       SnapshotInit(cx, obj, proto);
+       #endif
+//     StrokeInit(cx, obj, proto);
+       TextInit(cx, obj, proto);
+       TextOnPathInit(cx, obj, proto);
+       TextToPathInit(cx, obj, proto);
+       TranslateInit(cx, obj, proto);
+//     UseInit(cx, obj, proto);
+}
+
+void SkJS::DisposeDisplayables() {
+       delete SkJSDisplayable::gPaint;
+       delete SkJSDisplayable::gCanvas;
+       for (int index = 0; index < kTypeNamesSize; index++) {
+               SkDisplayTypes type = gTypeNames[index].fType;
+               delete[] gDisplayableProperties[type];
+       }
+}
diff --git a/libs/graphics/xml/SkParse.cpp b/libs/graphics/xml/SkParse.cpp
new file mode 100644 (file)
index 0000000..b7d312c
--- /dev/null
@@ -0,0 +1,319 @@
+#include "SkParse.h"
+
+static inline bool is_between(int c, int min, int max)
+{
+       return (unsigned)(c - min) <= (unsigned)(max - min);
+}
+
+static inline bool is_ws(int c)
+{
+       return is_between(c, 1, 32);
+}
+
+static inline bool is_digit(int c)
+{
+       return is_between(c, '0', '9');
+}
+
+static inline bool is_sep(int c)
+{
+       return is_ws(c) || c == ',' || c == ';';
+}
+
+static int to_hex(int c)
+{
+       if (is_digit(c))
+               return c - '0';
+
+       c |= 0x20;      // make us lower-case
+       if (is_between(c, 'a', 'f'))
+               return c + 10 - 'a';
+       else
+               return -1;
+}
+
+static inline bool is_hex(int c)
+{
+       return to_hex(c) >= 0;
+}
+
+static const char* skip_ws(const char str[])
+{
+       SkASSERT(str);
+       while (is_ws(*str))
+               str++;
+       return str;
+}
+
+static const char* skip_sep(const char str[])
+{
+       SkASSERT(str);
+       while (is_sep(*str))
+               str++;
+       return str;
+}
+
+int SkParse::Count(const char str[]) 
+{
+       char c;
+       int count = 0;
+       goto skipLeading;
+       do {
+               count++;
+               do {
+                       if ((c = *str++) == '\0')
+                               goto goHome;
+               } while (is_sep(c) == false);
+skipLeading:
+               do {
+                       if ((c = *str++) == '\0')
+                               goto goHome;
+               } while (is_sep(c));
+       } while (true);
+goHome:
+       return count;
+}
+
+int SkParse::Count(const char str[], char separator) 
+{
+       char c;
+       int count = 0;
+       goto skipLeading;
+       do {
+               count++;
+               do {
+                       if ((c = *str++) == '\0')
+                               goto goHome;
+               } while (c != separator);
+skipLeading:
+               do {
+                       if ((c = *str++) == '\0')
+                               goto goHome;
+               } while (c == separator);
+       } while (true);
+goHome:
+       return count;
+}
+
+const char* SkParse::FindHex(const char str[], uint32_t* value)
+{
+       SkASSERT(str);
+       str = skip_ws(str);
+
+       if (!is_hex(*str))
+               return nil;
+
+       U32     n = 0;
+       int max_digits = 8;
+       int digit;
+
+       while ((digit = to_hex(*str)) >= 0)
+       {
+               if (--max_digits < 0)
+                       return nil;
+               n = (n << 4) | digit;
+               str += 1;
+       }
+
+       if (*str == 0 || is_ws(*str))
+       {
+               if (value)
+                       *value = n;
+               return str;
+       }
+       return false;
+}
+
+const char* SkParse::FindS32(const char str[], int32_t* value)
+{
+       SkASSERT(str);
+       str = skip_ws(str);
+
+       int sign = 0;
+       if (*str == '-')
+       {
+               sign = -1;
+               str += 1;
+       }
+
+       if (!is_digit(*str))
+               return nil;
+
+       int     n = 0;
+       while (is_digit(*str))
+       {
+               n = 10*n + *str - '0';
+               str += 1;
+       }
+       if (value)
+               *value = (n ^ sign) - sign;
+       return str;
+}
+
+const char* SkParse::FindMSec(const char str[], SkMSec* value)
+{
+       SkASSERT(str);
+       str = skip_ws(str);
+
+       int sign = 0;
+       if (*str == '-')
+       {
+               sign = -1;
+               str += 1;
+       }
+
+       if (!is_digit(*str))
+               return nil;
+
+       int     n = 0;
+       while (is_digit(*str))
+       {
+               n = 10*n + *str - '0';
+               str += 1;
+       }
+       int remaining10s = 3;
+       if (*str == '.') {
+               str++;
+               while (is_digit(*str))
+               {
+                       n = 10*n + *str - '0';
+                       str += 1;
+                       if (--remaining10s == 0)
+                               break;
+               }
+       }
+       while (--remaining10s >= 0)
+               n *= 10;
+       if (value)
+               *value = (n ^ sign) - sign;
+       return str;
+}
+
+const char* SkParse::FindScalar(const char str[], SkScalar* value)
+{
+       SkASSERT(str);
+       str = skip_ws(str);
+
+       int sign = 0;
+       if (*str == '-')
+       {
+               sign = -1;
+               str += 1;
+       }
+
+       if (!is_digit(*str) && *str != '.')
+               return nil;
+
+       int     n = 0;
+       while (is_digit(*str))
+       {
+               n = 10*n + *str - '0';
+               if (n > 0x7FFF)
+                       return nil;
+               str += 1;
+       }
+       n <<= 16;
+
+       if (*str == '.')
+       {
+               static const int gFractions[] = { (1 << 24)  / 10, (1 << 24)  / 100, (1 << 24)  / 1000, 
+                       (1 << 24)  / 10000, (1 << 24)  / 100000 };
+               str += 1;
+               int d = 0;
+               const int* fraction = gFractions;
+               const int* end = &fraction[SK_ARRAY_COUNT(gFractions)];
+               while (is_digit(*str) && fraction < end)
+                       d += (*str++ - '0') * *fraction++;
+               d += 0x80; // round
+               n += d >> 8;
+       }
+       while (is_digit(*str))
+               str += 1;
+       if (value)
+       {
+               n = (n ^ sign) - sign;  // apply the sign
+               *value = SkFixedToScalar(n);
+       }
+       return str;
+}
+
+const char* SkParse::FindScalars(const char str[], SkScalar value[], int count)
+{
+       SkASSERT(count >= 0);
+
+       if (count > 0)
+       {
+               for (;;)
+               {
+                       str = SkParse::FindScalar(str, value);
+                       if (--count == 0 || str == nil)
+                               break;
+
+                       // keep going
+                       str = skip_sep(str);
+                       if (value)
+                               value += 1;
+               }
+       }
+       return str;
+}
+
+static bool lookup_str(const char str[], const char** table, int count)
+{
+       while (--count >= 0)
+               if (!strcmp(str, table[count]))
+                       return true;
+       return false;
+}
+
+bool SkParse::FindBool(const char str[], bool* value)
+{
+       static const char* gYes[] = { "yes", "1", "true" };
+       static const char* gNo[] = { "no", "0", "false" };
+
+       if (lookup_str(str, gYes, SK_ARRAY_COUNT(gYes)))
+       {
+               if (value) *value = true;
+               return true;
+       }
+       else if (lookup_str(str, gNo, SK_ARRAY_COUNT(gNo)))
+       {
+               if (value) *value = false;
+               return true;
+       }
+       return false;
+}
+
+int SkParse::FindList(const char target[], const char list[])
+{
+       size_t  len = strlen(target);
+       int             index = 0;
+
+       for (;;)
+       {
+               const char* end = strchr(list, ',');
+               size_t          entryLen;
+
+               if (end == nil) // last entry
+                       entryLen = strlen(list);
+               else
+                       entryLen = end - list;
+
+               if (entryLen == len && memcmp(target, list, len) == 0)
+                       return index;
+               if (end == nil)
+                       break;
+
+               list = end + 1; // skip the ','
+               index += 1;
+       }
+       return -1;
+}
+
+#ifdef SK_SUPPORT_UNITTEST
+void SkParse::UnitTest() 
+{
+       // !!! additional parse tests go here
+       SkParse::TestColor();
+}
+#endif
diff --git a/libs/graphics/xml/SkParseColor.cpp b/libs/graphics/xml/SkParseColor.cpp
new file mode 100644 (file)
index 0000000..75da7f4
--- /dev/null
@@ -0,0 +1,529 @@
+#include "SkParse.h"
+
+#ifdef SK_DEBUG
+#include "SkString.h"
+
+       // compress names 6 chars per long (packed 5 bits/char )
+               // note: little advantage to splitting chars across longs, since 3 longs at 2 unused bits each 
+               // allow for one additional split char (vs. the 18 unsplit chars in the three longs)
+       // use extra two bits to represent:
+               // 00 : final 6 (or fewer) chars (if 'a' is 0x01, zero could have special meaning)
+               // 01 : not final 6 chars
+               // 10 : color
+               // 11 : unused, except as debugging sentinal? (could be -1 for easier test)
+       // !!! the bit to end the word (last) is at the low bit for binary search
+       // lookup first character in offset for quick start
+               // offset is 27-entry table of bytes(?) that trims linear search to at most 21 entries ('d')
+       // shift match into long; set bit 30 if it all doesn't fit
+       // while longs don't match, march forward
+               // if they do match, and bit 30 is set, advance match, clearing bit 30 if
+               // final chars, and advance to next test
+               // if they do match, and bit 30 is clear, get next long (color) and return it
+       // stop at lookup of first char + 1
+static const struct SkNameRGB {
+       const char* name;
+       int rgb;
+} colorNames[] = {
+       { "aliceblue",            0xF0F8FF },
+       { "antiquewhite",         0xFAEBD7 },
+       { "aqua",                 0x00FFFF },
+       { "aquamarine",           0x7FFFD4 },
+       { "azure",                0xF0FFFF },
+       { "beige",                0xF5F5DC },
+       { "bisque",               0xFFE4C4 },
+       { "black",                0x000000 },
+       { "blanchedalmond",       0xFFEBCD },
+       { "blue",                 0x0000FF },
+       { "blueviolet",           0x8A2BE2 },
+       { "brown",                0xA52A2A },
+       { "burlywood",            0xDEB887 },
+       { "cadetblue",            0x5F9EA0 },
+       { "chartreuse",           0x7FFF00 },
+       { "chocolate",            0xD2691E },
+       { "coral",                0xFF7F50 },
+       { "cornflowerblue",       0x6495ED },
+       { "cornsilk",             0xFFF8DC },
+       { "crimson",              0xDC143C },
+       { "cyan",                 0x00FFFF },
+       { "darkblue",             0x00008B },
+       { "darkcyan",             0x008B8B },
+       { "darkgoldenrod",        0xB8860B },
+       { "darkgray",             0xA9A9A9 },
+       { "darkgreen",            0x006400 },
+       { "darkkhaki",            0xBDB76B },
+       { "darkmagenta",          0x8B008B },
+       { "darkolivegreen",       0x556B2F },
+       { "darkorange",           0xFF8C00 },
+       { "darkorchid",           0x9932CC },
+       { "darkred",              0x8B0000 },
+       { "darksalmon",           0xE9967A },
+       { "darkseagreen",         0x8FBC8F },
+       { "darkslateblue",        0x483D8B },
+       { "darkslategray",        0x2F4F4F },
+       { "darkturquoise",        0x00CED1 },
+       { "darkviolet",           0x9400D3 },
+       { "deeppink",             0xFF1493 },
+       { "deepskyblue",          0x00BFFF },
+       { "dimgray",              0x696969 },
+       { "dodgerblue",           0x1E90FF },
+       { "firebrick",            0xB22222 },
+       { "floralwhite",          0xFFFAF0 },
+       { "forestgreen",          0x228B22 },
+       { "fuchsia",              0xFF00FF },
+       { "gainsboro",            0xDCDCDC },
+       { "ghostwhite",           0xF8F8FF },
+       { "gold",                 0xFFD700 },
+       { "goldenrod",            0xDAA520 },
+       { "gray",                 0x808080 },
+       { "green",                0x008000 },
+       { "greenyellow",          0xADFF2F },
+       { "honeydew",             0xF0FFF0 },
+       { "hotpink",              0xFF69B4 },
+       { "indianred",            0xCD5C5C },
+       { "indigo",               0x4B0082 },
+       { "ivory",                0xFFFFF0 },
+       { "khaki",                0xF0E68C },
+       { "lavender",             0xE6E6FA },
+       { "lavenderblush",        0xFFF0F5 },
+       { "lawngreen",            0x7CFC00 },
+       { "lemonchiffon",         0xFFFACD },
+       { "lightblue",            0xADD8E6 },
+       { "lightcoral",           0xF08080 },
+       { "lightcyan",            0xE0FFFF },
+       { "lightgoldenrodyellow", 0xFAFAD2 },
+       { "lightgreen",           0x90EE90 },
+       { "lightgrey",            0xD3D3D3 },
+       { "lightpink",            0xFFB6C1 },
+       { "lightsalmon",          0xFFA07A },
+       { "lightseagreen",        0x20B2AA },
+       { "lightskyblue",         0x87CEFA },
+       { "lightslategray",       0x778899 },
+       { "lightsteelblue",       0xB0C4DE },
+       { "lightyellow",          0xFFFFE0 },
+       { "lime",                 0x00FF00 },
+       { "limegreen",            0x32CD32 },
+       { "linen",                0xFAF0E6 },
+       { "magenta",              0xFF00FF },
+       { "maroon",               0x800000 },
+       { "mediumaquamarine",     0x66CDAA },
+       { "mediumblue",           0x0000CD },
+       { "mediumorchid",         0xBA55D3 },
+       { "mediumpurple",         0x9370DB },
+       { "mediumseagreen",       0x3CB371 },
+       { "mediumslateblue",      0x7B68EE },
+       { "mediumspringgreen",    0x00FA9A },
+       { "mediumturquoise",      0x48D1CC },
+       { "mediumvioletred",      0xC71585 },
+       { "midnightblue",         0x191970 },
+       { "mintcream",            0xF5FFFA },
+       { "mistyrose",            0xFFE4E1 },
+       { "moccasin",             0xFFE4B5 },
+       { "navajowhite",          0xFFDEAD },
+       { "navy",                 0x000080 },
+       { "oldlace",              0xFDF5E6 },
+       { "olive",                0x808000 },
+       { "olivedrab",            0x6B8E23 },
+       { "orange",               0xFFA500 },
+       { "orangered",            0xFF4500 },
+       { "orchid",               0xDA70D6 },
+       { "palegoldenrod",        0xEEE8AA },
+       { "palegreen",            0x98FB98 },
+       { "paleturquoise",        0xAFEEEE },
+       { "palevioletred",        0xDB7093 },
+       { "papayawhip",           0xFFEFD5 },
+       { "peachpuff",            0xFFDAB9 },
+       { "peru",                 0xCD853F },
+       { "pink",                 0xFFC0CB },
+       { "plum",                 0xDDA0DD },
+       { "powderblue",           0xB0E0E6 },
+       { "purple",               0x800080 },
+       { "red",                  0xFF0000 },
+       { "rosybrown",            0xBC8F8F },
+       { "royalblue",            0x4169E1 },
+       { "saddlebrown",          0x8B4513 },
+       { "salmon",               0xFA8072 },
+       { "sandybrown",           0xF4A460 },
+       { "seagreen",             0x2E8B57 },
+       { "seashell",             0xFFF5EE },
+       { "sienna",               0xA0522D },
+       { "silver",               0xC0C0C0 },
+       { "skyblue",              0x87CEEB },
+       { "slateblue",            0x6A5ACD },
+       { "slategray",            0x708090 },
+       { "snow",                 0xFFFAFA },
+       { "springgreen",          0x00FF7F },
+       { "steelblue",            0x4682B4 },
+       { "tan",                  0xD2B48C },
+       { "teal",                 0x008080 },
+       { "thistle",              0xD8BFD8 },
+       { "tomato",               0xFF6347 },
+       { "turquoise",            0x40E0D0 },
+       { "violet",               0xEE82EE },
+       { "wheat",                0xF5DEB3 },
+       { "white",                0xFFFFFF },
+       { "whitesmoke",           0xF5F5F5 },
+       { "yellow",               0xFFFF00 },
+       { "yellowgreen",          0x9ACD32 }
+};
+
+int colorNamesSize = sizeof(colorNames) / sizeof(colorNames[0]);
+
+static void CreateTable() {
+       SkString comment;
+       size_t originalSize = 0;
+       int replacement = 0;
+       for (int index = 0; index < colorNamesSize; index++) {
+               SkNameRGB nameRGB =  colorNames[index];
+               const char* name = nameRGB.name;
+               size_t len = strlen(name);
+               originalSize += len + 9;
+               bool first = true;
+               bool last = false;
+               do {
+                       int compressed = 0;
+                       const char* start = name;
+                       for (int chIndex = 0; chIndex < 6; chIndex++) {
+                               compressed <<= 5;
+                               compressed |= *name ? *name++ - 'a' + 1 : 0 ;
+                       }
+                       replacement += sizeof(int);
+                       compressed <<= 1;
+                       compressed |= 1;
+                       if (first) {
+                               compressed |= 0x80000000;
+                               first = false;
+                       }
+                       if (len <= 6) { // last
+                               compressed &= ~1;
+                               last = true;
+                       }
+                       len -= 6;
+                       SkDebugf("0x%08x, ", compressed);
+                       comment.append(start, name - start);
+               } while (last == false);
+               replacement += sizeof(int);
+               SkDebugf("0x%08x, ", nameRGB.rgb);
+               SkDebugf("// %s\n", comment.c_str());
+               comment.reset();
+       }
+       SkDebugf("// original = %d : replacement = %d\n", originalSize, replacement);
+       SkASSERT(0); // always stop after creating table
+}
+
+#endif
+
+static const unsigned int gColorNames[] = {
+0x85891945, 0x32a50000, 0x00f0f8ff, // aliceblue
+0x85d44c6b, 0x16e84d0a, 0x00faebd7, // antiquewhite
+0x86350800, 0x0000ffff, // aqua
+0x86350b43, 0x492e2800, 0x007fffd4, // aquamarine
+0x87559140, 0x00f0ffff, // azure
+0x88a93940, 0x00f5f5dc, // beige
+0x89338d4a, 0x00ffe4c4, // bisque
+0x89811ac0, 0x00000000, // black
+0x898170d1, 0x1481635f, 0x38800000, 0x00ffebcd, // blanchedalmond
+0x89952800, 0x000000ff, // blue
+0x89952d93, 0x3d85a000, 0x008a2be2, // blueviolet
+0x8a4fbb80, 0x00a52a2a, // brown
+0x8ab2666f, 0x3de40000, 0x00deb887, // burlywood
+0x8c242d05, 0x32a50000, 0x005f9ea0, // cadetblue
+0x8d019525, 0x16b32800, 0x007fff00, // chartreuse
+0x8d0f1bd9, 0x06850000, 0x00d2691e, // chocolate
+0x8df20b00, 0x00ff7f50, // coral
+0x8df27199, 0x3ee59099, 0x54a00000, 0x006495ed, // cornflowerblue
+0x8df274d3, 0x31600000, 0x00fff8dc, // cornsilk
+0x8e496cdf, 0x38000000, 0x00dc143c, // crimson
+0x8f217000, 0x0000ffff, // cyan
+0x90325899, 0x54a00000, 0x0000008b, // darkblue
+0x903258f3, 0x05c00000, 0x00008b8b, // darkcyan
+0x903259df, 0x3085749f, 0x10000000, 0x00b8860b, // darkgoldenrod
+0x903259e5, 0x07200000, 0x00a9a9a9, // darkgray
+0x903259e5, 0x14ae0000, 0x00006400, // darkgreen
+0x90325ad1, 0x05690000, 0x00bdb76b, // darkkhaki
+0x90325b43, 0x1caea040, 0x008b008b, // darkmagenta
+0x90325bd9, 0x26c53c8b, 0x15c00000, 0x00556b2f, // darkolivegreen
+0x90325be5, 0x05c72800, 0x00ff8c00, // darkorange
+0x90325be5, 0x0d092000, 0x009932cc, // darkorchid
+0x90325c8b, 0x10000000, 0x008b0000, // darkred
+0x90325cc3, 0x31af7000, 0x00e9967a, // darksalmon
+0x90325ccb, 0x04f2295c, 0x008fbc8f, // darkseagreen
+0x90325cd9, 0x0685132b, 0x14000000, 0x00483d8b, // darkslateblue
+0x90325cd9, 0x06853c83, 0x64000000, 0x002f4f4f, // darkslategray
+0x90325d2b, 0x4a357a67, 0x14000000, 0x0000ced1, // darkturquoise
+0x90325d93, 0x3d85a000, 0x009400d3, // darkviolet
+0x90a58413, 0x39600000, 0x00ff1493, // deeppink
+0x90a584d7, 0x644ca940, 0x0000bfff, // deepskyblue
+0x912d3c83, 0x64000000, 0x00696969, // dimgray
+0x91e43965, 0x09952800, 0x001e90ff, // dodgerblue
+0x993228a5, 0x246b0000, 0x00b22222, // firebrick
+0x998f9059, 0x5d09a140, 0x00fffaf0, // floralwhite
+0x99f22ce9, 0x1e452b80, 0x00228b22, // forestgreen
+0x9aa344d3, 0x04000000, 0x00ff00ff, // fuchsia
+0x9c2974c5, 0x3e4f0000, 0x00dcdcdc, // gainsboro
+0x9d0f9d2f, 0x21342800, 0x00f8f8ff, // ghostwhite
+0x9dec2000, 0x00ffd700, // gold
+0x9dec215d, 0x49e40000, 0x00daa520, // goldenrod
+0x9e41c800, 0x00808080, // gray
+0x9e452b80, 0x00008000, // green
+0x9e452bb3, 0x158c7dc0, 0x00adff2f, // greenyellow
+0xa1ee2e49, 0x16e00000, 0x00f0fff0, // honeydew
+0xa1f4825d, 0x2c000000, 0x00ff69b4, // hotpink
+0xa5c4485d, 0x48a40000, 0x00cd5c5c, // indianred
+0xa5c449de, 0x004b0082, // indigo
+0xa6cf9640, 0x00fffff0, // ivory
+0xad015a40, 0x00f0e68c, // khaki
+0xb0362b89, 0x16400000, 0x00e6e6fa, // lavender
+0xb0362b89, 0x16426567, 0x20000000, 0x00fff0f5, // lavenderblush
+0xb03771e5, 0x14ae0000, 0x007cfc00, // lawngreen
+0xb0ad7b87, 0x212633dc, 0x00fffacd, // lemonchiffon
+0xb1274505, 0x32a50000, 0x00add8e6, // lightblue
+0xb1274507, 0x3e416000, 0x00f08080, // lightcoral
+0xb1274507, 0x642e0000, 0x00e0ffff, // lightcyan
+0xb127450f, 0x3d842ba5, 0x3c992b19, 0x3ee00000, 0x00fafad2, // lightgoldenrodyellow
+0xb127450f, 0x48a57000, 0x0090ee90, // lightgreen
+0xb127450f, 0x48b90000, 0x00d3d3d3, // lightgrey
+0xb1274521, 0x25cb0000, 0x00ffb6c1, // lightpink
+0xb1274527, 0x058d7b80, 0x00ffa07a, // lightsalmon
+0xb1274527, 0x1427914b, 0x38000000, 0x0020b2aa, // lightseagreen
+0xb1274527, 0x2f22654a, 0x0087cefa, // lightskyblue
+0xb1274527, 0x303429e5, 0x07200000, 0x00778899, // lightslategray
+0xb1274527, 0x50a56099, 0x54a00000, 0x00b0c4de, // lightsteelblue
+0xb1274533, 0x158c7dc0, 0x00ffffe0, // lightyellow
+0xb12d2800, 0x0000ff00, // lime
+0xb12d29e5, 0x14ae0000, 0x0032cd32, // limegreen
+0xb12e2b80, 0x00faf0e6, // linen
+0xb4272ba9, 0x04000000, 0x00ff00ff, // magenta
+0xb4327bdc, 0x00800000, // maroon
+0xb4a44d5b, 0x06350b43, 0x492e2800, 0x0066cdaa, // mediumaquamarine
+0xb4a44d5b, 0x09952800, 0x000000cd, // mediumblue
+0xb4a44d5b, 0x3e434248, 0x00ba55d3, // mediumorchid
+0xb4a44d5b, 0x42b2830a, 0x009370db, // mediumpurple
+0xb4a44d5b, 0x4ca13c8b, 0x15c00000, 0x003cb371, // mediumseagreen
+0xb4a44d5b, 0x4d81a145, 0x32a50000, 0x007b68ee, // mediumslateblue
+0xb4a44d5b, 0x4e124b8f, 0x1e452b80, 0x0000fa9a, // mediumspringgreen
+0xb4a44d5b, 0x52b28d5f, 0x26650000, 0x0048d1cc, // mediumturquoise
+0xb4a44d5b, 0x592f6169, 0x48a40000, 0x00c71585, // mediumvioletred
+0xb524724f, 0x2282654a, 0x00191970, // midnightblue
+0xb52ea0e5, 0x142d0000, 0x00f5fffa, // mintcream
+0xb533a665, 0x3e650000, 0x00ffe4e1, // mistyrose
+0xb5e31867, 0x25c00000, 0x00ffe4b5, // moccasin
+0xb8360a9f, 0x5d09a140, 0x00ffdead, // navajowhite
+0xb836c800, 0x00000080, // navy
+0xbd846047, 0x14000000, 0x00fdf5e6, // oldlace
+0xbd89b140, 0x00808000, // olive
+0xbd89b149, 0x48220000, 0x006b8e23, // olivedrab
+0xbe4171ca, 0x00ffa500, // orange
+0xbe4171cb, 0x48a40000, 0x00ff4500, // orangered
+0xbe434248, 0x00da70d6, // orchid
+0xc02c29df, 0x3085749f, 0x10000000, 0x00eee8aa, // palegoldenrod
+0xc02c29e5, 0x14ae0000, 0x0098fb98, // palegreen
+0xc02c2d2b, 0x4a357a67, 0x14000000, 0x00afeeee, // paleturquoise
+0xc02c2d93, 0x3d85a48b, 0x10000000, 0x00db7093, // palevioletred
+0xc0300e43, 0x5d098000, 0x00ffefd5, // papayawhip
+0xc0a11a21, 0x54c60000, 0x00ffdab9, // peachpuff
+0xc0b2a800, 0x00cd853f, // peru
+0xc12e5800, 0x00ffc0cb, // pink
+0xc1956800, 0x00dda0dd, // plum
+0xc1f72165, 0x09952800, 0x00b0e0e6, // powderblue
+0xc2b2830a, 0x00800080, // purple
+0xc8a40000, 0x00ff0000, // red
+0xc9f3c8a5, 0x3eee0000, 0x00bc8f8f, // rosybrown
+0xc9f90b05, 0x32a50000, 0x004169e1, // royalblue
+0xcc24230b, 0x0a4fbb80, 0x008b4513, // saddlebrown
+0xcc2c6bdc, 0x00fa8072, // salmon
+0xcc2e2645, 0x49f77000, 0x00f4a460, // sandybrown
+0xcca13c8b, 0x15c00000, 0x002e8b57, // seagreen
+0xcca19a0b, 0x31800000, 0x00fff5ee, // seashell
+0xcd257382, 0x00a0522d, // sienna
+0xcd2cb164, 0x00c0c0c0, // silver
+0xcd79132b, 0x14000000, 0x0087ceeb, // skyblue
+0xcd81a145, 0x32a50000, 0x006a5acd, // slateblue
+0xcd81a14f, 0x48390000, 0x00708090, // slategray
+0xcdcfb800, 0x00fffafa, // snow
+0xce124b8f, 0x1e452b80, 0x0000ff7f, // springgreen
+0xce852b05, 0x32a50000, 0x004682b4, // steelblue
+0xd02e0000, 0x00d2b48c, // tan
+0xd0a16000, 0x00008080, // teal
+0xd1099d19, 0x14000000, 0x00d8bfd8, // thistle
+0xd1ed0d1e, 0x00ff6347, // tomato
+0xd2b28d5f, 0x26650000, 0x0040e0d0, // turquoise
+0xd92f6168, 0x00ee82ee, // violet
+0xdd050d00, 0x00f5deb3, // wheat
+0xdd09a140, 0x00ffffff, // white
+0xdd09a167, 0x35eb2800, 0x00f5f5f5, // whitesmoke
+0xe4ac63ee, 0x00ffff00, // yellow
+0xe4ac63ef, 0x1e452b80, 0x009acd32 // yellowgreen
+}; // original = 2505 : replacement = 1616
+
+
+const char* SkParse::FindNamedColor(const char* name, size_t len, SkColor* color) {
+       const char* namePtr = name;
+       unsigned int sixMatches[4];
+       unsigned int* sixMatchPtr = sixMatches;
+       bool first = true;
+       bool last = false;
+       char ch;
+       do {
+               unsigned int sixMatch = 0;
+               for (int chIndex = 0; chIndex < 6; chIndex++) {
+                       sixMatch <<= 5;
+                       ch = *namePtr  | 0x20;
+                       if (ch < 'a' || ch > 'z')
+                               ch = 0;
+                       else {
+                               ch = ch - 'a' + 1;
+                               namePtr++;
+                       }
+                       sixMatch |= ch ;  // turn 'A' (0x41) into 'a' (0x61);
+               }
+               sixMatch <<= 1;
+               sixMatch |= 1;
+               if (first) {
+                       sixMatch |= 0x80000000;
+                       first = false;
+               }
+               ch = *namePtr | 0x20;
+               last = ch < 'a' || ch > 'z';
+               if (last) 
+                       sixMatch &= ~1;
+               len -= 6;
+               *sixMatchPtr++ = sixMatch;
+       } while (last == false && len > 0);
+       const int colorNameSize = sizeof(gColorNames) / sizeof(unsigned int);
+       int lo = 0;
+       int hi = colorNameSize - 3;     // back off to beginning of yellowgreen
+       while (lo <= hi) {
+               int mid = (hi + lo) >> 1;
+               while ((int) gColorNames[mid] >= 0)
+                       --mid;
+               sixMatchPtr = sixMatches;
+               while (gColorNames[mid] == *sixMatchPtr) {
+                       ++mid;
+                       if ((*sixMatchPtr & 1) == 0) { // last
+                               *color = gColorNames[mid] | 0xFF000000;
+                               return namePtr;
+                       }
+                       ++sixMatchPtr;
+               }
+               int sixMask = *sixMatchPtr & ~0x80000000;
+               int midMask = gColorNames[mid] & ~0x80000000;
+               if (sixMask > midMask) {
+                       lo = mid + 2;   // skip color
+                       while ((int) gColorNames[lo] >= 0)
+                               ++lo;
+               } else if (hi == mid)
+                       return nil;
+               else
+                       hi = mid;
+       }
+       return nil;
+}
+
+// !!! move to char utilities
+//static int count_separators(const char* str, const char* sep) {
+//     char c;
+//     int separators = 0;
+//     while ((c = *str++) != '\0') {
+//             if (strchr(sep, c) == nil)
+//                     continue;
+//             do {
+//                     if ((c = *str++) == '\0')
+//                             goto goHome;
+//             } while (strchr(sep, c) != nil);
+//             separators++;
+//     }
+//goHome:
+//     return separators;
+//}
+
+static inline unsigned nib2byte(unsigned n)
+{
+       SkASSERT((n & ~0xF) == 0);
+       return (n << 4) | n;
+}
+
+const char* SkParse::FindColor(const char* value, SkColor* colorPtr) {
+       unsigned int oldAlpha = SkColorGetA(*colorPtr);
+       if (value[0] == '#') {
+               uint32_t        hex;
+               const char* end = SkParse::FindHex(value + 1, &hex);
+//             SkASSERT(end);
+               if (end == nil)
+                       return end;
+               size_t len = end - value - 1;
+               if (len == 3 || len == 4) {
+                       unsigned a = len == 4 ? nib2byte(hex >> 12) : oldAlpha;
+                       unsigned r = nib2byte((hex >> 8) & 0xF);
+                       unsigned g = nib2byte((hex >> 4) & 0xF);
+                       unsigned b = nib2byte(hex & 0xF);
+                       *colorPtr = SkColorSetARGB(a, r, g, b);
+                       return end;
+               } else if (len == 6 || len == 8) {
+                       if (len == 6)
+                               hex |= oldAlpha << 24;
+                       *colorPtr = hex;
+                       return end;
+               } else {
+//                     SkASSERT(0);
+                       return nil;
+               }
+//     } else if (strchr(value, ',')) {
+//             SkScalar array[4];
+//             int count = count_separators(value, ",") + 1; // !!! count commas, add 1
+//             SkASSERT(count == 3 || count == 4);
+//             array[0] = SK_Scalar1 * 255;
+//             const char* end = SkParse::FindScalars(value, &array[4 - count], count);
+//             if (end == nil)
+//                     return nil;
+               // !!! range check for errors?
+//             *colorPtr = SkColorSetARGB(SkScalarRound(array[0]), SkScalarRound(array[1]), 
+//                     SkScalarRound(array[2]), SkScalarRound(array[3]));
+//             return end;
+       } else
+               return FindNamedColor(value, strlen(value), colorPtr);
+}
+
+#ifdef SK_DEBUG
+void SkParse::TestColor() {
+       if (false)
+               CreateTable();  // regenerates data table in the output window
+       SkColor result;
+       int index;
+       for (index = 0; index < colorNamesSize; index++) {
+               result = SK_ColorBLACK;
+               SkNameRGB nameRGB = colorNames[index];
+               SkASSERT(FindColor(nameRGB.name, &result) != nil);
+               SkASSERT(result == (SkColor) (nameRGB.rgb | 0xFF000000));
+       }
+       for (index = 0; index < colorNamesSize; index++) {
+               result = SK_ColorBLACK;
+               SkNameRGB nameRGB = colorNames[index];
+               char bad[24];
+               size_t len = strlen(nameRGB.name);
+               memcpy(bad, nameRGB.name, len);
+               bad[len - 1] -= 1; 
+               SkASSERT(FindColor(bad, &result) == false);
+               bad[len - 1] += 2; 
+               SkASSERT(FindColor(bad, &result) == false);
+       }
+       result = SK_ColorBLACK;
+       SkASSERT(FindColor("lightGrey", &result));
+       SkASSERT(result == 0xffd3d3d3);
+//     SkASSERT(FindColor("12,34,56,78", &result));
+//     SkASSERT(result == ((12 << 24) | (34 << 16) | (56 << 8) | (78 << 0)));
+       result = SK_ColorBLACK;
+       SkASSERT(FindColor("#ABCdef", &result));
+       SkASSERT(result == 0XFFABCdef);
+       SkASSERT(FindColor("#12ABCdef", &result));
+       SkASSERT(result == 0X12ABCdef);
+       result = SK_ColorBLACK;
+       SkASSERT(FindColor("#123", &result));
+       SkASSERT(result == 0Xff112233);
+       SkASSERT(FindColor("#abcd", &result));
+       SkASSERT(result == 0Xaabbccdd);
+       result = SK_ColorBLACK;
+//     SkASSERT(FindColor("71,162,253", &result));
+//     SkASSERT(result == ((0xFF << 24) | (71 << 16) | (162 << 8) | (253 << 0)));
+}
+#endif
+
diff --git a/libs/graphics/xml/SkXMLParser.cpp b/libs/graphics/xml/SkXMLParser.cpp
new file mode 100644 (file)
index 0000000..fa050b0
--- /dev/null
@@ -0,0 +1,78 @@
+#include "SkXMLParser.h"
+
+static char const* const gErrorStrings[] = {
+       "empty or missing file ",
+       "unknown element ",
+       "unknown attribute name ",
+       "error in attribute value ",
+       "duplicate ID ",
+       "unknown error "
+};
+
+SkXMLParserError::SkXMLParserError() : fCode(kNoError), fLineNumber(-1),
+       fNativeCode(-1)
+{
+       reset();
+}
+
+SkXMLParserError::~SkXMLParserError()
+{
+       // need a virtual destructor for our subclasses
+}
+
+void SkXMLParserError::getErrorString(SkString* str) const
+{
+       SkASSERT(str);
+       SkString temp;
+       if (fCode != kNoError) {
+               if ((unsigned)fCode < SK_ARRAY_COUNT(gErrorStrings))
+                       temp.set(gErrorStrings[fCode - 1]);
+               temp.append(fNoun);
+       } else
+               SkXMLParser::GetNativeErrorString(fNativeCode, &temp);
+       str->append(temp);
+}
+
+void SkXMLParserError::reset() {
+       fCode = kNoError;
+       fLineNumber = -1;
+       fNativeCode = -1;
+}
+
+
+////////////////
+
+SkXMLParser::SkXMLParser(SkXMLParserError* parserError) : fParser(nil), fError(parserError)
+{
+}
+
+SkXMLParser::~SkXMLParser()
+{
+}
+
+bool SkXMLParser::startElement(const char elem[])
+{
+       return this->onStartElement(elem);
+}
+
+bool SkXMLParser::addAttribute(const char name[], const char value[])
+{
+       return this->onAddAttribute(name, value);
+}
+
+bool SkXMLParser::endElement(const char elem[])
+{
+       return this->onEndElement(elem);
+}
+
+bool SkXMLParser::text(const char text[], int len) 
+{
+       return this->onText(text, len);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool SkXMLParser::onStartElement(const char elem[]) {return false; }
+bool SkXMLParser::onAddAttribute(const char name[], const char value[]) {return false; }
+bool SkXMLParser::onEndElement(const char elem[]) { return false; }
+bool SkXMLParser::onText(const char text[], int len) {return false; }
diff --git a/libs/graphics/xml/SkXMLWriter.cpp b/libs/graphics/xml/SkXMLWriter.cpp
new file mode 100644 (file)
index 0000000..b0430d6
--- /dev/null
@@ -0,0 +1,325 @@
+#include "SkXMLWriter.h"
+#include "SkStream.h"
+
+SkXMLWriter::SkXMLWriter(bool doEscapeMarkup) : fDoEscapeMarkup(doEscapeMarkup)
+{
+}
+
+SkXMLWriter::~SkXMLWriter()
+{
+       SkASSERT(fElems.count() == 0);
+}
+
+void SkXMLWriter::flush()
+{
+       while (fElems.count())
+               this->endElement();
+}
+
+void SkXMLWriter::addAttribute(const char name[], const char value[])
+{
+       this->addAttributeLen(name, value, strlen(value));
+}
+
+void SkXMLWriter::addS32Attribute(const char name[], S32 value)
+{
+       SkString        tmp;
+       tmp.appendS32(value);
+       this->addAttribute(name, tmp.c_str());
+}
+
+void SkXMLWriter::addHexAttribute(const char name[], U32 value, int minDigits)
+{
+       SkString        tmp("0x");
+       tmp.appendHex(value, minDigits);
+       this->addAttribute(name, tmp.c_str());
+}
+
+void SkXMLWriter::addScalarAttribute(const char name[], SkScalar value)
+{
+       SkString        tmp;
+       tmp.appendScalar(value);
+       this->addAttribute(name, tmp.c_str());
+}
+
+void SkXMLWriter::doEnd(Elem* elem)
+{
+       delete elem;
+}
+
+bool SkXMLWriter::doStart(const char name[], size_t length)
+{
+       int     level = fElems.count();
+       bool firstChild = level > 0 && !fElems[level-1]->fHasChildren;
+       if (firstChild)
+               fElems[level-1]->fHasChildren = true;
+       Elem** elem = fElems.push();
+       *elem = new Elem;
+       (*elem)->fName.set(name, length);
+       (*elem)->fHasChildren = 0;
+       return firstChild;
+}
+
+SkXMLWriter::Elem* SkXMLWriter::getEnd() 
+{
+       Elem* elem;
+       fElems.pop(&elem);
+       return elem;
+}
+
+const char* SkXMLWriter::getHeader()
+{
+       static const char gHeader[] = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>";
+       return gHeader;
+}
+
+void SkXMLWriter::startElement(const char name[])
+{
+       this->startElementLen(name, strlen(name));
+}
+
+static const char* escape_char(char c, char storage[2])
+{
+       static const char* gEscapeChars[] = {
+               "<&lt;",
+               ">&gt;",
+               //"\"&quot;",
+               //"'&apos;",
+               "&&amp;"
+       };
+
+       const char** array = gEscapeChars;
+       for (unsigned i = 0; i < SK_ARRAY_COUNT(gEscapeChars); i++)
+       {
+               if (array[i][0] == c)
+                       return &array[i][1];
+       }
+       storage[0] = c;
+       storage[1] = 0;
+       return storage;
+}
+
+static size_t escape_markup(char dst[], const char src[], size_t length)
+{
+       size_t          extra = 0;
+       const char*     stop = src + length;
+
+       while (src < stop)
+       {
+               char            orig[2];
+               const char* seq = escape_char(*src, orig);
+               size_t          seqSize = strlen(seq);
+
+               if (dst)
+               {
+                       memcpy(dst, seq, seqSize);
+                       dst += seqSize;
+               }
+
+               // now record the extra size needed
+               extra += seqSize - 1;   // minus one to subtract the original char
+
+               // bump to the next src char
+               src += 1;
+       }
+       return extra;
+}
+
+void SkXMLWriter::addAttributeLen(const char name[], const char value[], size_t length)
+{
+       SkString valueStr;
+
+       if (fDoEscapeMarkup)
+       {
+               size_t   extra = escape_markup(nil, value, length);
+               if (extra)
+               {
+                       valueStr.resize(length + extra);
+                       (void)escape_markup(valueStr.writable_str(), value, length);
+                       value = valueStr.c_str();
+                       length += extra;
+               }
+       }
+       this->onAddAttributeLen(name, value, length);
+}
+
+void SkXMLWriter::startElementLen(const char elem[], size_t length)
+{
+       this->onStartElementLen(elem, length);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+static void write_dom(const SkDOM& dom, const SkDOM::Node* node, SkXMLWriter* w, bool skipRoot)
+{
+       if (!skipRoot)
+       {
+               w->startElement(dom.getName(node));
+
+               SkDOM::AttrIter iter(dom, node);
+               const char*     name;
+               const char* value;
+               while ((name = iter.next(&value)) != nil)
+                       w->addAttribute(name, value);
+       }
+
+       node = dom.getFirstChild(node, nil);
+       while (node)
+       {
+               write_dom(dom, node, w, false);
+               node = dom.getNextSibling(node, nil);
+       }
+
+       if (!skipRoot)
+               w->endElement();
+}
+
+void SkXMLWriter::writeDOM(const SkDOM& dom, const SkDOM::Node* node, bool skipRoot)
+{
+       if (node)
+               write_dom(dom, node, this, skipRoot);
+}
+
+void SkXMLWriter::writeHeader()
+{
+}
+
+// SkXMLStreamWriter
+
+static void tab(SkWStream& stream, int level)
+{
+       for (int i = 0; i < level; i++)
+               stream.writeText("\t");
+}
+
+SkXMLStreamWriter::SkXMLStreamWriter(SkWStream* stream) : fStream(*stream)
+{
+}
+
+SkXMLStreamWriter::~SkXMLStreamWriter()
+{
+       this->flush();
+}
+
+void SkXMLStreamWriter::onAddAttributeLen(const char name[], const char value[], size_t length)
+{
+       SkASSERT(!fElems.top()->fHasChildren);
+       fStream.writeText(" ");
+       fStream.writeText(name);
+       fStream.writeText("=\"");
+       fStream.write(value, length);
+       fStream.writeText("\"");
+}
+
+void SkXMLStreamWriter::onEndElement()
+{
+       Elem* elem = getEnd();
+       if (elem->fHasChildren)
+       {
+               tab(fStream, fElems.count());
+               fStream.writeText("</");
+               fStream.writeText(elem->fName.c_str());
+               fStream.writeText(">");
+       }
+       else
+               fStream.writeText("/>");
+       fStream.newline();
+       doEnd(elem);
+}
+
+void SkXMLStreamWriter::onStartElementLen(const char name[], size_t length)
+{
+       int level = fElems.count();
+       if (this->doStart(name, length))
+       {
+               // the first child, need to close with >
+               fStream.writeText(">");
+               fStream.newline();
+       }
+
+       tab(fStream, level);
+       fStream.writeText("<");
+       fStream.write(name, length);
+}
+
+void SkXMLStreamWriter::writeHeader()
+{
+       const char* header = getHeader();
+       fStream.write(header, strlen(header));
+       fStream.newline();
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkXMLParser.h"
+
+SkXMLParserWriter::SkXMLParserWriter(SkXMLParser* parser)
+       : SkXMLWriter(false), fParser(*parser)
+{
+}
+
+SkXMLParserWriter::~SkXMLParserWriter()
+{
+       this->flush();
+}
+
+void SkXMLParserWriter::onAddAttributeLen(const char name[], const char value[], size_t length)
+{
+       SkASSERT(fElems.count() == 0 || !fElems.top()->fHasChildren);
+       SkString str(value, length);
+       fParser.addAttribute(name, str.c_str());
+}
+
+void SkXMLParserWriter::onEndElement()
+{
+       Elem* elem = this->getEnd();
+       fParser.endElement(elem->fName.c_str());
+       this->doEnd(elem);
+}
+
+void SkXMLParserWriter::onStartElementLen(const char name[], size_t length)
+{
+       (void)this->doStart(name, length);
+       SkString str(name, length);
+       fParser.startElement(str.c_str());
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_DEBUG
+
+void SkXMLStreamWriter::UnitTest()
+{
+#ifdef SK_SUPPORT_UNITTEST
+       SkDebugWStream  s;
+       SkXMLStreamWriter               w(&s);
+
+       w.startElement("elem0");
+       w.addAttribute("hello", "world");
+       w.addS32Attribute("dec", 42);
+       w.addHexAttribute("hex", 0x42, 3);
+#ifdef SK_SCALAR_IS_FLOAT
+       w.addScalarAttribute("scalar", -4.2f);
+#endif
+       w.startElement("elem1");
+               w.endElement();
+               w.startElement("elem1");
+               w.addAttribute("name", "value");
+               w.endElement();
+               w.startElement("elem1");
+                       w.startElement("elem2");
+                               w.startElement("elem3");
+                               w.addAttribute("name", "value");
+                               w.endElement();
+                       w.endElement();
+                       w.startElement("elem2");
+                       w.endElement();
+               w.endElement();
+       w.endElement();
+#endif
+}
+
+#endif
+