aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDerek Sollenberger <djsollen@google.com>2012-01-18 08:56:56 -0500
committerDerek Sollenberger <derek@android.com>2012-02-06 14:14:40 -0500
commit1cab2921ab279367f8206cdadc9259d12e603548 (patch)
tree2852f9dc2481f639122e18fc7831ae6ca43d6d5a
parentd7176fd5571bc9878d3cdac8696eaa35ec170d9d (diff)
downloadexternal_skia-1cab2921ab279367f8206cdadc9259d12e603548.zip
external_skia-1cab2921ab279367f8206cdadc9259d12e603548.tar.gz
external_skia-1cab2921ab279367f8206cdadc9259d12e603548.tar.bz2
Skia merge (revision 3022)
This CL has companion changes to account for API updates in... (1) frameworks/base (2) external/webkit Change-Id: Ibb989e76e8bd24313849f9631dbef42cdef9eb7d
-rw-r--r--Android.mk350
-rw-r--r--LICENSE27
-rw-r--r--MODULE_LICENSE_BSD (renamed from MODULE_LICENSE_APACHE2)0
-rw-r--r--NOTICE256
-rw-r--r--README3
-rw-r--r--bench/AAClipBench.cpp104
-rw-r--r--bench/Android.mk36
-rw-r--r--bench/BenchGpuTimer_gl.cpp209
-rw-r--r--bench/BenchGpuTimer_gl.h31
-rw-r--r--bench/BenchGpuTimer_none.cpp14
-rw-r--r--bench/BenchGpuTimer_none.h12
-rw-r--r--bench/BenchSysTimer_c.cpp7
-rw-r--r--bench/BenchSysTimer_c.h7
-rw-r--r--bench/BenchSysTimer_mach.cpp7
-rw-r--r--bench/BenchSysTimer_mach.h7
-rw-r--r--bench/BenchSysTimer_posix.cpp7
-rw-r--r--bench/BenchSysTimer_posix.h7
-rw-r--r--bench/BenchSysTimer_windows.cpp15
-rw-r--r--bench/BenchSysTimer_windows.h9
-rw-r--r--bench/BenchTimer.cpp49
-rw-r--r--bench/BenchTimer.h14
-rw-r--r--bench/BitmapBench.cpp27
-rw-r--r--bench/BlurBench.cpp106
-rw-r--r--bench/ChromeBench.cpp498
-rw-r--r--bench/DecodeBench.cpp9
-rw-r--r--bench/FPSBench.cpp108
-rw-r--r--bench/FontScalerBench.cpp60
-rw-r--r--bench/GradientBench.cpp153
-rw-r--r--bench/Makefile.am20
-rw-r--r--bench/MathBench.cpp316
-rw-r--r--bench/MatrixBench.cpp98
-rw-r--r--bench/MutexBench.cpp43
-rw-r--r--bench/PathBench.cpp55
-rw-r--r--bench/RectBench.cpp9
-rw-r--r--bench/RepeatTileBench.cpp9
-rw-r--r--bench/ScalarBench.cpp9
-rw-r--r--bench/ShaderMaskBench.cpp109
-rw-r--r--bench/SkBenchmark.cpp7
-rw-r--r--bench/SkBenchmark.h13
-rw-r--r--bench/TextBench.cpp135
-rw-r--r--bench/VertBench.cpp99
-rw-r--r--bench/bench_compare.py109
-rw-r--r--bench/bench_graph_svg.py750
-rw-r--r--bench/bench_util.py178
-rw-r--r--bench/benchmain.cpp232
-rw-r--r--gm/Android.mk26
-rw-r--r--gm/aaclip.cpp115
-rw-r--r--gm/aarectmodes.cpp203
-rw-r--r--gm/arithmode.cpp140
-rw-r--r--gm/bitmapcopy.cpp121
-rw-r--r--gm/bitmapfilters.cpp9
-rw-r--r--gm/bitmapscroll.cpp147
-rw-r--r--gm/blurs.cpp17
-rw-r--r--gm/colormatrix.cpp118
-rw-r--r--gm/complexclip.cpp119
-rw-r--r--gm/complexclip2.cpp135
-rw-r--r--gm/cubicpaths.cpp309
-rw-r--r--gm/degeneratesegments.cpp400
-rw-r--r--gm/drawbitmaprect.cpp155
-rw-r--r--gm/emptypath.cpp133
-rw-r--r--gm/filltypes.cpp10
-rw-r--r--gm/filltypespersp.cpp128
-rw-r--r--gm/fontscaler.cpp93
-rw-r--r--gm/gm.cpp54
-rw-r--r--gm/gm.h38
-rw-r--r--gm/gm_files.mk17
-rw-r--r--gm/gmmain.cpp560
-rw-r--r--gm/gradients.cpp119
-rw-r--r--gm/gradtext.cpp97
-rw-r--r--gm/hairmodes.cpp152
-rw-r--r--gm/imageblur.cpp57
-rw-r--r--gm/lcdtext.cpp70
-rw-r--r--gm/linepaths.cpp305
-rw-r--r--gm/ninepatchstretch.cpp113
-rwxr-xr-xgm/nocolorbleed.cpp17
-rw-r--r--gm/pathfill.cpp13
-rw-r--r--gm/pathreverse.cpp118
-rw-r--r--gm/points.cpp23
-rw-r--r--gm/poly2poly.cpp17
-rw-r--r--gm/quadpaths.cpp307
-rw-r--r--gm/shadertext.cpp42
-rw-r--r--gm/shadows.cpp14
-rw-r--r--gm/shapes.cpp23
-rw-r--r--gm/strokefill.cpp81
-rw-r--r--gm/strokerects.cpp25
-rw-r--r--gm/strokes.cpp149
-rw-r--r--gm/tablecolorfilter.cpp139
-rw-r--r--gm/testimagefilters.cpp143
-rw-r--r--gm/texdata.cpp146
-rw-r--r--gm/tilemodes.cpp12
-rw-r--r--gm/tinybitmap.cpp68
-rw-r--r--gm/verttext.cpp90
-rw-r--r--gm/verttext2.cpp92
-rw-r--r--gm/xfermodes.cpp45
-rw-r--r--gpu/include/FlingState.h58
-rw-r--r--gpu/include/GrContext.h623
-rw-r--r--gpu/include/GrContext_impl.h165
-rw-r--r--gpu/include/GrDrawTarget.h1214
-rw-r--r--gpu/include/GrGLConfig.h193
-rw-r--r--gpu/include/GrGLConfig_chrome.h13
-rw-r--r--gpu/include/GrGLTexture.h242
-rw-r--r--gpu/include/GrIPoint.h35
-rw-r--r--gpu/include/GrIndexBuffer.h38
-rw-r--r--gpu/include/GrMatrix.h26
-rw-r--r--gpu/include/GrMemory.h181
-rw-r--r--gpu/include/GrMesh.h42
-rw-r--r--gpu/include/GrNoncopyable.h38
-rw-r--r--gpu/include/GrPath.h27
-rw-r--r--gpu/include/GrPathRenderer.h170
-rw-r--r--gpu/include/GrPathSink.h36
-rw-r--r--gpu/include/GrPoint.h38
-rw-r--r--gpu/include/GrRefCnt.h134
-rw-r--r--gpu/include/GrStencil.h210
-rw-r--r--gpu/include/GrStopwatch.h135
-rw-r--r--gpu/include/GrStringBuilder.h26
-rw-r--r--gpu/include/GrTArray.h331
-rw-r--r--gpu/include/GrTemplates.h108
-rw-r--r--gpu/include/GrTesselatedPathRenderer.h47
-rw-r--r--gpu/include/GrTexture.h313
-rw-r--r--gpu/include/GrTextureCache.h308
-rw-r--r--gpu/include/GrTouchGesture.h56
-rw-r--r--gpu/include/GrVertexBuffer.h31
-rw-r--r--gpu/include/SkUIView.h64
-rw-r--r--gpu/src/GrBinHashKey.h237
-rw-r--r--gpu/src/GrContext.cpp1525
-rw-r--r--gpu/src/GrCreatePathRenderer_none.cpp20
-rw-r--r--gpu/src/GrCreatePathRenderer_tesselated.cpp20
-rw-r--r--gpu/src/GrDrawMesh.cpp140
-rw-r--r--gpu/src/GrDrawTarget.cpp679
-rw-r--r--gpu/src/GrGLDefaultInterface_none.cpp18
-rw-r--r--gpu/src/GrGLIndexBuffer.cpp127
-rw-r--r--gpu/src/GrGLInterface.cpp347
-rw-r--r--gpu/src/GrGLProgram.cpp1176
-rw-r--r--gpu/src/GrGLProgram.h294
-rw-r--r--gpu/src/GrGLTexture.cpp181
-rw-r--r--gpu/src/GrGLUtil.cpp53
-rw-r--r--gpu/src/GrGLVertexBuffer.cpp126
-rw-r--r--gpu/src/GrGpuFactory.cpp80
-rw-r--r--gpu/src/GrGpuGL.cpp2076
-rw-r--r--gpu/src/GrGpuGL.h202
-rw-r--r--gpu/src/GrGpuGLFixed.cpp333
-rw-r--r--gpu/src/GrGpuGLFixed.h72
-rw-r--r--gpu/src/GrGpuGLShaders.cpp845
-rw-r--r--gpu/src/GrMemory.cpp36
-rw-r--r--gpu/src/GrPathRenderer.cpp447
-rw-r--r--gpu/src/GrPathUtils.h50
-rw-r--r--gpu/src/GrPrintf_printf.cpp36
-rw-r--r--gpu/src/GrResource.cpp41
-rw-r--r--gpu/src/GrStencil.cpp383
-rw-r--r--gpu/src/GrTesselatedPathRenderer.cpp356
-rw-r--r--gpu/src/GrTexture.cpp65
-rw-r--r--gpu/src/GrTextureCache.cpp316
-rw-r--r--gpu/src/GrTouchGesture.cpp243
-rw-r--r--gpu/src/android/GrGLDefaultInterface_android.cpp138
-rw-r--r--gpu/src/gr_files.mk32
-rw-r--r--gpu/src/mac/GrGLDefaultInterface_mac.cpp165
-rw-r--r--gpu/src/mesa/GrGLDefaultInterface_mesa.cpp184
-rw-r--r--gpu/src/skia/SkUIView.mm858
-rw-r--r--gpu/src/unix/GrGLDefaultInterface_unix.cpp184
-rw-r--r--gpu/src/win/GrGLDefaultInterface_win.cpp191
-rw-r--r--gyp/FileReaderApp.gyp78
-rw-r--r--gyp/SampleApp.gyp281
-rw-r--r--gyp/SimpleCocoaApp.gyp65
-rw-r--r--gyp/all.gyp41
-rw-r--r--gyp/android_system.gyp21
-rw-r--r--gyp/animator.gyp193
-rw-r--r--gyp/apptype_console.gypi21
-rw-r--r--gyp/bench.gyp36
-rw-r--r--gyp/bench.gypi71
-rw-r--r--gyp/common.gypi70
-rw-r--r--gyp/common_conditions.gypi212
-rw-r--r--gyp/common_variables.gypi25
-rw-r--r--gyp/core.gyp327
-rw-r--r--gyp/effects.gyp92
-rw-r--r--gyp/experimental.gyp31
-rw-r--r--gyp/freetype.gyp69
-rw-r--r--gyp/gm.gyp44
-rw-r--r--gyp/gmslides.gypi55
-rw-r--r--gyp/gpu.gyp356
-rw-r--r--gyp/iOSSampleApp.gyp279
-rw-r--r--gyp/images.gyp149
-rw-r--r--gyp/libtess.gyp59
-rw-r--r--gyp/opts.gyp81
-rw-r--r--gyp/pdf.gyp66
-rw-r--r--gyp/ports.gyp114
-rw-r--r--gyp/svg.gyp91
-rw-r--r--gyp/tests.gyp95
-rw-r--r--gyp/tools.gyp73
-rw-r--r--gyp/utils.gyp161
-rw-r--r--gyp/views.gyp118
-rw-r--r--gyp/xml.gyp58
-rw-r--r--gyp/xps.gyp67
-rw-r--r--gyp/zlib.gyp40
-rw-r--r--include/animator/SkAnimator.h17
-rw-r--r--include/animator/SkAnimatorView.h17
-rw-r--r--include/config/SkUserConfig.h153
-rw-r--r--include/config/sk_stdint.h36
-rw-r--r--include/core/Sk64.h18
-rwxr-xr-x[-rw-r--r--]include/core/SkAdvancedTypefaceMetrics.h28
-rw-r--r--include/core/SkAutoKern.h24
-rw-r--r--include/core/SkBitmap.h134
-rw-r--r--include/core/SkBlitRow.h40
-rw-r--r--include/core/SkBlitter.h107
-rw-r--r--include/core/SkBounder.h17
-rw-r--r--include/core/SkBuffer.h17
-rw-r--r--include/core/SkCanvas.h240
-rw-r--r--include/core/SkChunkAlloc.h17
-rw-r--r--include/core/SkClampRange.h19
-rw-r--r--include/core/SkClipStack.h15
-rw-r--r--include/core/SkColor.h17
-rw-r--r--include/core/SkColorFilter.h49
-rw-r--r--include/core/SkColorPriv.h47
-rw-r--r--include/core/SkColorShader.h51
-rw-r--r--include/core/SkComposeShader.h17
-rw-r--r--include/core/SkData.h137
-rw-r--r--include/core/SkDeque.h17
-rw-r--r--include/core/SkDescriptor.h17
-rw-r--r--include/core/SkDevice.h305
-rw-r--r--include/core/SkDither.h17
-rw-r--r--include/core/SkDraw.h24
-rw-r--r--include/core/SkDrawFilter.h17
-rw-r--r--include/core/SkDrawLooper.h17
-rw-r--r--include/core/SkEdgeClipper.h17
-rw-r--r--include/core/SkEmptyShader.h43
-rw-r--r--include/core/SkEndian.h30
-rw-r--r--include/core/SkFDot6.h17
-rw-r--r--include/core/SkFixed.h41
-rw-r--r--include/core/SkFlate.h43
-rw-r--r--include/core/SkFlattenable.h101
-rw-r--r--include/core/SkFloatBits.h17
-rw-r--r--include/core/SkFloatingPoint.h33
-rw-r--r--include/core/SkFontHost.h72
-rw-r--r--include/core/SkGeometry.h35
-rw-r--r--include/core/SkGlobals.h67
-rw-r--r--include/core/SkGraphics.h74
-rw-r--r--include/core/SkImageFilter.h97
-rw-r--r--include/core/SkLineClipper.h7
-rw-r--r--include/core/SkMMapStream.h18
-rw-r--r--include/core/SkMallocPixelRef.h18
-rw-r--r--include/core/SkMask.h110
-rw-r--r--include/core/SkMaskFilter.h77
-rw-r--r--include/core/SkMath.h17
-rw-r--r--include/core/SkMatrix.h150
-rw-r--r--include/core/SkMetaData.h17
-rw-r--r--include/core/SkOSFile.h25
-rw-r--r--include/core/SkPackBits.h17
-rw-r--r--include/core/SkPaint.h177
-rw-r--r--include/core/SkPath.h155
-rw-r--r--include/core/SkPathEffect.h41
-rw-r--r--include/core/SkPathMeasure.h17
-rw-r--r--include/core/SkPerspIter.h17
-rw-r--r--include/core/SkPicture.h17
-rw-r--r--include/core/SkPixelRef.h63
-rw-r--r--include/core/SkPoint.h120
-rw-r--r--include/core/SkPostConfig.h70
-rw-r--r--include/core/SkPreConfig.h45
-rw-r--r--include/core/SkPtrRecorder.h22
-rw-r--r--include/core/SkRandom.h17
-rw-r--r--include/core/SkRasterizer.h19
-rw-r--r--include/core/SkReader32.h51
-rw-r--r--include/core/SkRect.h129
-rw-r--r--include/core/SkRefCnt.h103
-rw-r--r--include/core/SkRefDict.h19
-rw-r--r--include/core/SkRegion.h25
-rw-r--r--include/core/SkRelay.h19
-rw-r--r--include/core/SkScalar.h77
-rw-r--r--include/core/SkScalarCompare.h17
-rw-r--r--include/core/SkScalerContext.h125
-rw-r--r--include/core/SkScan.h106
-rw-r--r--include/core/SkShader.h28
-rw-r--r--include/core/SkShape.h9
-rw-r--r--include/core/SkSize.h7
-rw-r--r--include/core/SkStream.h100
-rw-r--r--include/core/SkString.h38
-rw-r--r--include/core/SkStroke.h17
-rw-r--r--include/core/SkTArray.h415
-rw-r--r--include/core/SkTDArray.h29
-rw-r--r--include/core/SkTDStack.h75
-rw-r--r--include/core/SkTDict.h17
-rw-r--r--include/core/SkTLazy.h47
-rw-r--r--include/core/SkTRegistry.h19
-rw-r--r--include/core/SkTScopedPtr.h17
-rw-r--r--include/core/SkTSearch.h17
-rw-r--r--include/core/SkTemplates.h125
-rw-r--r--include/core/SkThread.h17
-rw-r--r--include/core/SkThread_platform.h60
-rw-r--r--include/core/SkTime.h17
-rw-r--r--include/core/SkTrace.h47
-rw-r--r--include/core/SkTypeface.h26
-rw-r--r--include/core/SkTypes.h150
-rw-r--r--include/core/SkUnPreMultiply.h17
-rw-r--r--include/core/SkUnitMapper.h17
-rw-r--r--include/core/SkUserConfig.h71
-rw-r--r--include/core/SkUtils.h39
-rw-r--r--include/core/SkWriter32.h29
-rw-r--r--include/core/SkXfermode.h47
-rw-r--r--include/effects/Sk1DPathEffect.h37
-rw-r--r--include/effects/Sk2DPathEffect.h57
-rw-r--r--include/effects/SkArithmeticMode.h30
-rw-r--r--include/effects/SkAvoidXfermode.h31
-rw-r--r--include/effects/SkBlurDrawLooper.h18
-rw-r--r--include/effects/SkBlurImageFilter.h40
-rw-r--r--include/effects/SkBlurMaskFilter.h19
-rw-r--r--include/effects/SkColorMatrix.h17
-rw-r--r--include/effects/SkColorMatrixFilter.h30
-rw-r--r--include/effects/SkCornerPathEffect.h27
-rw-r--r--include/effects/SkDashPathEffect.h23
-rw-r--r--include/effects/SkDiscretePathEffect.h23
-rw-r--r--include/effects/SkDrawExtraPathEffect.h17
-rw-r--r--include/effects/SkEffects.h16
-rw-r--r--include/effects/SkEmbossMaskFilter.h19
-rw-r--r--include/effects/SkGradientShader.h19
-rw-r--r--include/effects/SkGroupShape.h9
-rw-r--r--include/effects/SkKernel33MaskFilter.h17
-rw-r--r--include/effects/SkLayerDrawLooper.h22
-rw-r--r--include/effects/SkLayerRasterizer.h23
-rw-r--r--include/effects/SkPaintFlagsDrawFilter.h17
-rw-r--r--include/effects/SkPixelXorXfermode.h19
-rw-r--r--include/effects/SkPorterDuff.h19
-rw-r--r--include/effects/SkRectShape.h9
-rw-r--r--include/effects/SkTableColorFilter.h34
-rw-r--r--include/effects/SkTableMaskFilter.h17
-rwxr-xr-xinclude/effects/SkTestImageFilters.h157
-rw-r--r--include/effects/SkTransparentShader.h34
-rw-r--r--include/gpu/GrClip.h (renamed from gpu/include/GrClip.h)29
-rw-r--r--include/gpu/GrClipIterator.h (renamed from gpu/include/GrClipIterator.h)19
-rw-r--r--include/gpu/GrColor.h (renamed from gpu/include/GrColor.h)32
-rw-r--r--include/gpu/GrConfig.h (renamed from gpu/include/GrConfig.h)50
-rw-r--r--include/gpu/GrContext.h881
-rw-r--r--include/gpu/GrFontScaler.h (renamed from gpu/include/GrFontScaler.h)19
-rw-r--r--include/gpu/GrGLConfig.h252
-rw-r--r--include/gpu/GrGLConfig_chrome.h30
-rw-r--r--include/gpu/GrGLDefines.h (renamed from gpu/include/GrGLDefines.h)92
-rw-r--r--include/gpu/GrGLInterface.h (renamed from gpu/include/GrGLInterface.h)197
-rw-r--r--include/gpu/GrGlyph.h (renamed from gpu/include/GrGlyph.h)19
-rw-r--r--include/gpu/GrInstanceCounter.h (renamed from gpu/include/GrInstanceCounter.h)19
-rw-r--r--include/gpu/GrKey.h (renamed from gpu/include/GrKey.h)19
-rw-r--r--include/gpu/GrMatrix.h19
-rw-r--r--include/gpu/GrNoncopyable.h31
-rw-r--r--include/gpu/GrPaint.h (renamed from gpu/include/GrPaint.h)54
-rw-r--r--include/gpu/GrPath.h20
-rw-r--r--include/gpu/GrPoint.h31
-rw-r--r--include/gpu/GrRect.h (renamed from gpu/include/GrRect.h)19
-rw-r--r--include/gpu/GrRefCnt.h34
-rw-r--r--include/gpu/GrRenderTarget.h206
-rw-r--r--include/gpu/GrResource.h (renamed from gpu/include/GrResource.h)37
-rw-r--r--include/gpu/GrSamplerState.h (renamed from gpu/include/GrSamplerState.h)157
-rw-r--r--include/gpu/GrScalar.h (renamed from gpu/include/GrScalar.h)22
-rw-r--r--include/gpu/GrTemplates.h69
-rw-r--r--include/gpu/GrTextContext.h (renamed from gpu/include/GrTextContext.h)20
-rw-r--r--include/gpu/GrTexture.h160
-rw-r--r--include/gpu/GrTypes.h (renamed from gpu/include/GrTypes.h)323
-rw-r--r--include/gpu/GrUserConfig.h (renamed from gpu/include/GrUserConfig.h)43
-rw-r--r--include/gpu/SkGLContext.h59
-rw-r--r--include/gpu/SkGpuCanvas.h23
-rw-r--r--include/gpu/SkGpuDevice.h156
-rw-r--r--include/gpu/SkGpuDeviceFactory.h58
-rw-r--r--include/gpu/SkGr.h58
-rw-r--r--include/gpu/SkGrTexturePixelRef.h80
-rw-r--r--include/gpu/SkMesaGLContext.h50
-rw-r--r--include/gpu/SkNativeGLContext.h81
-rw-r--r--include/gpu/SkNullGLContext.h27
-rw-r--r--include/images/SkBitmapRegionDecoder.h8
-rw-r--r--include/images/SkFlipPixelRef.h21
-rw-r--r--include/images/SkImageDecoder.h17
-rw-r--r--include/images/SkImageEncoder.h7
-rw-r--r--include/images/SkImageRef.h17
-rw-r--r--include/images/SkImageRef_GlobalPool.h19
-rw-r--r--include/images/SkJpegUtility.h17
-rw-r--r--include/images/SkMovie.h17
-rw-r--r--include/images/SkPageFlipper.h17
-rwxr-xr-xinclude/pdf/SkBitSet.h78
-rw-r--r--include/pdf/SkPDFCatalog.h63
-rw-r--r--include/pdf/SkPDFDevice.h125
-rw-r--r--include/pdf/SkPDFDocument.h48
-rw-r--r--include/pdf/SkPDFFont.h197
-rw-r--r--include/pdf/SkPDFFormXObject.h37
-rw-r--r--include/pdf/SkPDFGraphicState.h33
-rw-r--r--include/pdf/SkPDFImage.h37
-rw-r--r--include/pdf/SkPDFPage.h26
-rw-r--r--include/pdf/SkPDFShader.h79
-rw-r--r--include/pdf/SkPDFStream.h56
-rw-r--r--include/pdf/SkPDFTypes.h125
-rw-r--r--include/pdf/SkPDFUtils.h19
-rw-r--r--include/pipe/SkGPipe.h31
-rw-r--r--include/ports/SkHarfBuzzFont.h30
-rw-r--r--include/ports/SkStream_Win.h17
-rw-r--r--include/ports/SkTypeface_mac.h26
-rw-r--r--include/ports/SkTypeface_win.h29
-rw-r--r--include/text/SkTextLayout.h7
-rw-r--r--include/utils/SkBoundaryPatch.h7
-rw-r--r--include/utils/SkCamera.h19
-rw-r--r--include/utils/SkCubicInterval.h7
-rw-r--r--include/utils/SkCullPoints.h17
-rw-r--r--include/utils/SkDumpCanvas.h69
-rw-r--r--include/utils/SkEGLContext.h53
-rw-r--r--include/utils/SkGLCanvas.h39
-rw-r--r--include/utils/SkInterpolator.h17
-rw-r--r--include/utils/SkJSON.h285
-rw-r--r--include/utils/SkLayer.h17
-rw-r--r--include/utils/SkMatrix44.h224
-rw-r--r--include/utils/SkMeshUtils.h7
-rw-r--r--include/utils/SkNWayCanvas.h68
-rw-r--r--include/utils/SkNinePatch.h17
-rw-r--r--include/utils/SkParse.h18
-rw-r--r--include/utils/SkParsePaint.h17
-rw-r--r--include/utils/SkParsePath.h17
-rw-r--r--include/utils/SkProxyCanvas.h73
-rw-r--r--include/utils/SkSfntUtils.h7
-rw-r--r--include/utils/SkTextBox.h17
-rw-r--r--include/utils/SkUnitMappers.h17
-rw-r--r--include/utils/SkWGL.h90
-rw-r--r--include/utils/android/AndroidKeyToSkKey.h21
-rwxr-xr-xinclude/utils/ios/SkStream_NSData.h41
-rw-r--r--include/utils/mac/SkCGUtils.h18
-rw-r--r--include/utils/unix/XkeysToSkKeys.h7
-rw-r--r--include/utils/unix/keysym2ucs.h7
-rw-r--r--include/utils/win/SkAutoCoInitialize.h30
-rw-r--r--include/utils/win/SkHRESULT.h50
-rw-r--r--include/utils/win/SkIStream.h131
-rw-r--r--include/utils/win/SkTScopedComPtr.h64
-rw-r--r--include/views/SkApplication.h19
-rw-r--r--include/views/SkBGViewArtist.h17
-rw-r--r--include/views/SkBorderView.h17
-rw-r--r--include/views/SkEvent.h252
-rw-r--r--include/views/SkEventSink.h92
-rw-r--r--include/views/SkImageView.h17
-rw-r--r--include/views/SkKey.h17
-rw-r--r--include/views/SkOSMenu.h194
-rw-r--r--include/views/SkOSWindow_Android.h25
-rw-r--r--include/views/SkOSWindow_Mac.h54
-rw-r--r--include/views/SkOSWindow_SDL.h17
-rw-r--r--include/views/SkOSWindow_Unix.h17
-rw-r--r--include/views/SkOSWindow_Win.h17
-rwxr-xr-xinclude/views/SkOSWindow_iOS.h43
-rw-r--r--include/views/SkOSWindow_wxwidgets.h23
-rw-r--r--include/views/SkProgressBarView.h17
-rw-r--r--include/views/SkScrollBarView.h17
-rw-r--r--include/views/SkStackViewLayout.h17
-rw-r--r--include/views/SkSystemEventTypes.h17
-rw-r--r--include/views/SkTouchGesture.h7
-rw-r--r--include/views/SkView.h44
-rw-r--r--include/views/SkViewInflate.h17
-rw-r--r--include/views/SkWidget.h17
-rw-r--r--include/views/SkWidgetViews.h17
-rw-r--r--include/views/SkWindow.h33
-rw-r--r--include/xml/SkBML_WXMLParser.h17
-rw-r--r--include/xml/SkBML_XMLParser.h17
-rw-r--r--include/xml/SkDOM.h18
-rw-r--r--include/xml/SkJS.h17
-rw-r--r--include/xml/SkXMLParser.h18
-rw-r--r--include/xml/SkXMLWriter.h17
-rw-r--r--samplecode/ClockFaceView.cpp7
-rw-r--r--samplecode/GMSampleView.h52
-rw-r--r--samplecode/OverView.cpp26
-rw-r--r--samplecode/Sample2PtRadial.cpp52
-rw-r--r--samplecode/SampleAAClip.cpp128
-rw-r--r--samplecode/SampleAAClip2.cpp194
-rw-r--r--samplecode/SampleAARectModes.cpp152
-rw-r--r--samplecode/SampleAARects.cpp7
-rw-r--r--samplecode/SampleAll.cpp7
-rw-r--r--samplecode/SampleAnimatedGradient.cpp7
-rw-r--r--samplecode/SampleAnimator.cpp18
-rw-r--r--samplecode/SampleApp.cpp1487
-rw-r--r--samplecode/SampleApp.h197
-rw-r--r--samplecode/SampleArc.cpp7
-rw-r--r--samplecode/SampleAvoid.cpp7
-rw-r--r--samplecode/SampleBigBlur.cpp50
-rw-r--r--samplecode/SampleBigGradient.cpp7
-rw-r--r--samplecode/SampleBitmapRect.cpp44
-rw-r--r--samplecode/SampleBlur.cpp11
-rw-r--r--samplecode/SampleBox.cpp7
-rw-r--r--samplecode/SampleCamera.cpp7
-rw-r--r--samplecode/SampleCircle.cpp7
-rw-r--r--samplecode/SampleClamp.cpp7
-rw-r--r--samplecode/SampleClip.cpp169
-rw-r--r--samplecode/SampleCode.h84
-rw-r--r--samplecode/SampleColorFilter.cpp7
-rw-r--r--samplecode/SampleComplexClip.cpp7
-rw-r--r--samplecode/SampleConcavePaths.cpp153
-rw-r--r--samplecode/SampleCull.cpp7
-rw-r--r--samplecode/SampleDash.cpp7
-rw-r--r--samplecode/SampleDecode.cpp7
-rw-r--r--samplecode/SampleDegenerateTwoPtRadials.cpp92
-rw-r--r--samplecode/SampleDither.cpp7
-rw-r--r--samplecode/SampleDitherBitmap.cpp7
-rw-r--r--samplecode/SampleDraw.cpp7
-rw-r--r--samplecode/SampleDrawBitmap.cpp84
-rw-r--r--samplecode/SampleDrawLooper.cpp7
-rw-r--r--samplecode/SampleEffects.cpp8
-rw-r--r--samplecode/SampleEmboss.cpp7
-rw-r--r--samplecode/SampleEmptyPath.cpp130
-rw-r--r--samplecode/SampleEncode.cpp7
-rw-r--r--samplecode/SampleExtractAlpha.cpp90
-rw-r--r--samplecode/SampleFillType.cpp7
-rw-r--r--samplecode/SampleFilter.cpp7
-rw-r--r--samplecode/SampleFilter2.cpp7
-rw-r--r--samplecode/SampleFontCache.cpp7
-rw-r--r--samplecode/SampleFontScalerTest.cpp71
-rw-r--r--samplecode/SampleFuzz.cpp16
-rw-r--r--samplecode/SampleGM.cpp114
-rw-r--r--samplecode/SampleGradients.cpp7
-rw-r--r--samplecode/SampleHairCurves.cpp112
-rw-r--r--samplecode/SampleHairModes.cpp150
-rw-r--r--samplecode/SampleHairline.cpp7
-rw-r--r--samplecode/SampleImage.cpp7
-rw-r--r--samplecode/SampleImageDir.cpp35
-rw-r--r--samplecode/SampleLCD.cpp7
-rw-r--r--samplecode/SampleLayerMask.cpp7
-rw-r--r--samplecode/SampleLayers.cpp7
-rw-r--r--samplecode/SampleLineClipper.cpp20
-rw-r--r--samplecode/SampleLines.cpp7
-rw-r--r--samplecode/SampleMeasure.cpp7
-rw-r--r--samplecode/SampleMipMap.cpp7
-rw-r--r--samplecode/SampleMovie.cpp7
-rw-r--r--samplecode/SampleNinePatch.cpp159
-rw-r--r--samplecode/SampleOvalTest.cpp7
-rw-r--r--samplecode/SampleOverflow.cpp7
-rw-r--r--samplecode/SamplePageFlip.cpp27
-rw-r--r--samplecode/SamplePatch.cpp7
-rw-r--r--samplecode/SamplePath.cpp7
-rw-r--r--samplecode/SamplePathClip.cpp7
-rw-r--r--samplecode/SamplePathEffects.cpp7
-rw-r--r--samplecode/SamplePathFill.cpp7
-rw-r--r--samplecode/SamplePicture.cpp73
-rw-r--r--samplecode/SamplePoints.cpp7
-rw-r--r--samplecode/SamplePolyToPoly.cpp10
-rw-r--r--samplecode/SampleRegion.cpp7
-rw-r--r--samplecode/SampleRepeatTile.cpp7
-rw-r--r--samplecode/SampleShaderText.cpp27
-rw-r--r--samplecode/SampleShaders.cpp7
-rw-r--r--samplecode/SampleShapes.cpp15
-rw-r--r--samplecode/SampleSkLayer.cpp7
-rw-r--r--samplecode/SampleSlides.cpp73
-rw-r--r--samplecode/SampleSpiral.cpp7
-rw-r--r--samplecode/SampleStrokePath.cpp7
-rw-r--r--samplecode/SampleStrokeRect.cpp7
-rw-r--r--samplecode/SampleStrokeText.cpp7
-rw-r--r--samplecode/SampleTests.cpp7
-rw-r--r--samplecode/SampleText.cpp7
-rw-r--r--samplecode/SampleTextAlpha.cpp7
-rw-r--r--samplecode/SampleTextBox.cpp34
-rw-r--r--samplecode/SampleTextEffects.cpp45
-rw-r--r--samplecode/SampleTextOnPath.cpp7
-rwxr-xr-xsamplecode/SampleTextureDomain.cpp42
-rw-r--r--samplecode/SampleTiling.cpp20
-rw-r--r--samplecode/SampleTinyBitmap.cpp7
-rw-r--r--samplecode/SampleTriangles.cpp7
-rw-r--r--samplecode/SampleTypeface.cpp7
-rw-r--r--samplecode/SampleUnitMapper.cpp7
-rw-r--r--samplecode/SampleVertices.cpp8
-rw-r--r--samplecode/SampleWarp.cpp7
-rw-r--r--samplecode/SampleWritePixels.cpp70
-rw-r--r--samplecode/SampleXfermodes.cpp7
-rw-r--r--samplecode/SampleXfermodesBlur.cpp58
-rw-r--r--samplecode/TransitionView.cpp186
-rw-r--r--samplecode/samplecode_files.mk2
-rw-r--r--samplecode/vertexdump.cpp7
-rw-r--r--src/animator/SkAnimate.h24
-rw-r--r--src/animator/SkAnimateActive.cpp35
-rw-r--r--src/animator/SkAnimateActive.h24
-rw-r--r--src/animator/SkAnimateBase.cpp24
-rw-r--r--src/animator/SkAnimateBase.h24
-rw-r--r--src/animator/SkAnimateField.cpp24
-rw-r--r--src/animator/SkAnimateMaker.cpp30
-rw-r--r--src/animator/SkAnimateMaker.h24
-rw-r--r--src/animator/SkAnimateProperties.h24
-rw-r--r--src/animator/SkAnimateSet.cpp27
-rw-r--r--src/animator/SkAnimateSet.h24
-rw-r--r--src/animator/SkAnimator.cpp32
-rw-r--r--src/animator/SkAnimatorScript.cpp26
-rw-r--r--src/animator/SkAnimatorScript.h24
-rw-r--r--src/animator/SkAnimatorScript2.cpp7
-rw-r--r--src/animator/SkAnimatorScript2.h7
-rw-r--r--src/animator/SkBase64.cpp27
-rw-r--r--src/animator/SkBase64.h24
-rw-r--r--src/animator/SkBoundable.cpp24
-rw-r--r--src/animator/SkBoundable.h24
-rw-r--r--src/animator/SkBuildCondensedInfo.cpp24
-rw-r--r--src/animator/SkCondensedDebug.cpp24
-rw-r--r--src/animator/SkCondensedRelease.cpp24
-rw-r--r--src/animator/SkDisplayAdd.cpp24
-rw-r--r--src/animator/SkDisplayAdd.h24
-rw-r--r--src/animator/SkDisplayApply.cpp27
-rw-r--r--src/animator/SkDisplayApply.h24
-rw-r--r--src/animator/SkDisplayBounds.cpp24
-rw-r--r--src/animator/SkDisplayBounds.h24
-rw-r--r--src/animator/SkDisplayEvent.cpp26
-rw-r--r--src/animator/SkDisplayEvent.h24
-rw-r--r--src/animator/SkDisplayEvents.cpp24
-rw-r--r--src/animator/SkDisplayEvents.h24
-rw-r--r--src/animator/SkDisplayInclude.cpp24
-rw-r--r--src/animator/SkDisplayInclude.h24
-rw-r--r--src/animator/SkDisplayInput.cpp24
-rw-r--r--src/animator/SkDisplayInput.h24
-rw-r--r--src/animator/SkDisplayList.cpp24
-rw-r--r--src/animator/SkDisplayList.h24
-rw-r--r--src/animator/SkDisplayMath.cpp24
-rw-r--r--src/animator/SkDisplayMath.h24
-rw-r--r--src/animator/SkDisplayMovie.cpp24
-rw-r--r--src/animator/SkDisplayMovie.h24
-rw-r--r--src/animator/SkDisplayNumber.cpp24
-rw-r--r--src/animator/SkDisplayNumber.h24
-rw-r--r--src/animator/SkDisplayPost.cpp38
-rw-r--r--src/animator/SkDisplayPost.h28
-rw-r--r--src/animator/SkDisplayRandom.cpp24
-rw-r--r--src/animator/SkDisplayRandom.h24
-rw-r--r--src/animator/SkDisplayScreenplay.cpp24
-rw-r--r--src/animator/SkDisplayScreenplay.h24
-rw-r--r--src/animator/SkDisplayType.cpp32
-rw-r--r--src/animator/SkDisplayType.h26
-rw-r--r--src/animator/SkDisplayTypes.cpp24
-rw-r--r--src/animator/SkDisplayTypes.h24
-rw-r--r--src/animator/SkDisplayXMLParser.cpp28
-rw-r--r--src/animator/SkDisplayXMLParser.h24
-rw-r--r--src/animator/SkDisplayable.cpp24
-rw-r--r--src/animator/SkDisplayable.h26
-rw-r--r--src/animator/SkDraw3D.cpp24
-rw-r--r--src/animator/SkDraw3D.h24
-rw-r--r--src/animator/SkDrawBitmap.cpp24
-rw-r--r--src/animator/SkDrawBitmap.h24
-rw-r--r--src/animator/SkDrawBlur.cpp24
-rw-r--r--src/animator/SkDrawBlur.h24
-rw-r--r--src/animator/SkDrawClip.cpp24
-rw-r--r--src/animator/SkDrawClip.h24
-rw-r--r--src/animator/SkDrawColor.cpp24
-rw-r--r--src/animator/SkDrawColor.h24
-rw-r--r--src/animator/SkDrawDash.cpp24
-rw-r--r--src/animator/SkDrawDash.h24
-rw-r--r--src/animator/SkDrawDiscrete.cpp24
-rw-r--r--src/animator/SkDrawDiscrete.h24
-rw-r--r--src/animator/SkDrawEmboss.cpp24
-rw-r--r--src/animator/SkDrawEmboss.h24
-rw-r--r--src/animator/SkDrawExtraPathEffect.cpp24
-rw-r--r--src/animator/SkDrawFull.cpp24
-rw-r--r--src/animator/SkDrawFull.h24
-rw-r--r--src/animator/SkDrawGradient.cpp24
-rw-r--r--src/animator/SkDrawGradient.h24
-rw-r--r--src/animator/SkDrawGroup.cpp24
-rw-r--r--src/animator/SkDrawGroup.h24
-rw-r--r--src/animator/SkDrawLine.cpp24
-rw-r--r--src/animator/SkDrawLine.h24
-rw-r--r--src/animator/SkDrawMatrix.cpp51
-rw-r--r--src/animator/SkDrawMatrix.h24
-rw-r--r--src/animator/SkDrawOval.cpp24
-rw-r--r--src/animator/SkDrawOval.h24
-rw-r--r--src/animator/SkDrawPaint.cpp30
-rw-r--r--src/animator/SkDrawPaint.h26
-rw-r--r--src/animator/SkDrawPath.cpp24
-rw-r--r--src/animator/SkDrawPath.h24
-rw-r--r--src/animator/SkDrawPoint.cpp24
-rw-r--r--src/animator/SkDrawPoint.h24
-rw-r--r--src/animator/SkDrawRectangle.cpp24
-rw-r--r--src/animator/SkDrawRectangle.h24
-rw-r--r--src/animator/SkDrawSaveLayer.cpp24
-rw-r--r--src/animator/SkDrawSaveLayer.h24
-rw-r--r--src/animator/SkDrawShader.cpp24
-rw-r--r--src/animator/SkDrawShader.h24
-rw-r--r--src/animator/SkDrawText.cpp24
-rw-r--r--src/animator/SkDrawText.h24
-rw-r--r--src/animator/SkDrawTextBox.cpp24
-rw-r--r--src/animator/SkDrawTextBox.h24
-rw-r--r--src/animator/SkDrawTo.cpp24
-rw-r--r--src/animator/SkDrawTo.h24
-rw-r--r--src/animator/SkDrawTransparentShader.cpp24
-rw-r--r--src/animator/SkDrawTransparentShader.h24
-rw-r--r--src/animator/SkDrawable.cpp24
-rw-r--r--src/animator/SkDrawable.h24
-rw-r--r--src/animator/SkDump.cpp24
-rw-r--r--src/animator/SkDump.h24
-rw-r--r--src/animator/SkExtras.h24
-rw-r--r--src/animator/SkGetCondensedInfo.cpp24
-rw-r--r--src/animator/SkHitClear.cpp24
-rw-r--r--src/animator/SkHitClear.h24
-rw-r--r--src/animator/SkHitTest.cpp24
-rw-r--r--src/animator/SkHitTest.h24
-rw-r--r--src/animator/SkIntArray.h28
-rw-r--r--src/animator/SkMatrixParts.cpp24
-rw-r--r--src/animator/SkMatrixParts.h24
-rw-r--r--src/animator/SkMemberInfo.cpp29
-rw-r--r--src/animator/SkMemberInfo.h24
-rw-r--r--src/animator/SkOpArray.cpp7
-rw-r--r--src/animator/SkOpArray.h7
-rw-r--r--src/animator/SkOperand.h24
-rw-r--r--src/animator/SkOperand2.h7
-rw-r--r--src/animator/SkOperandInterpolator.h24
-rw-r--r--src/animator/SkOperandIterpolator.cpp24
-rw-r--r--src/animator/SkPaintParts.cpp26
-rw-r--r--src/animator/SkPaintParts.h24
-rw-r--r--src/animator/SkParseSVGPath.cpp24
-rw-r--r--src/animator/SkPathParts.cpp24
-rw-r--r--src/animator/SkPathParts.h24
-rw-r--r--src/animator/SkPostParts.cpp40
-rw-r--r--src/animator/SkPostParts.h30
-rw-r--r--src/animator/SkScript.cpp26
-rw-r--r--src/animator/SkScript.h24
-rw-r--r--src/animator/SkScript2.h7
-rw-r--r--src/animator/SkScriptCallBack.h7
-rw-r--r--src/animator/SkScriptDecompile.cpp24
-rw-r--r--src/animator/SkScriptRuntime.cpp8
-rw-r--r--src/animator/SkScriptRuntime.h7
-rw-r--r--src/animator/SkScriptTokenizer.cpp30
-rw-r--r--src/animator/SkSnapshot.cpp24
-rw-r--r--src/animator/SkSnapshot.h24
-rw-r--r--src/animator/SkTDArray_Experimental.h24
-rw-r--r--src/animator/SkTextOnPath.cpp24
-rw-r--r--src/animator/SkTextOnPath.h24
-rw-r--r--src/animator/SkTextToPath.cpp24
-rw-r--r--src/animator/SkTextToPath.h24
-rw-r--r--src/animator/SkTime.cpp24
-rw-r--r--src/animator/SkTypedArray.cpp24
-rw-r--r--src/animator/SkTypedArray.h24
-rw-r--r--src/animator/SkXMLAnimatorWriter.cpp24
-rw-r--r--src/animator/SkXMLAnimatorWriter.h24
-rw-r--r--src/core/ARGB32_Clamp_Bilinear_BitmapShader.h7
-rw-r--r--src/core/Makefile.am91
-rw-r--r--src/core/Sk64.cpp25
-rw-r--r--src/core/SkAAClip.cpp2134
-rw-r--r--src/core/SkAAClip.h132
-rw-r--r--src/core/SkAdvancedTypefaceMetrics.cpp221
-rw-r--r--src/core/SkAlphaRuns.cpp24
-rw-r--r--src/core/SkAntiRun.h54
-rw-r--r--src/core/SkBitmap.cpp131
-rw-r--r--src/core/SkBitmapProcShader.cpp20
-rw-r--r--src/core/SkBitmapProcShader.h26
-rw-r--r--src/core/SkBitmapProcState.cpp7
-rw-r--r--src/core/SkBitmapProcState.h21
-rw-r--r--src/core/SkBitmapProcState_filter.h21
-rw-r--r--src/core/SkBitmapProcState_matrix.h20
-rw-r--r--src/core/SkBitmapProcState_sample.h7
-rw-r--r--src/core/SkBitmapProcState_shaderproc.h19
-rw-r--r--src/core/SkBitmapSampler.cpp34
-rw-r--r--src/core/SkBitmapSampler.h24
-rw-r--r--src/core/SkBitmapSamplerTemplate.h24
-rw-r--r--src/core/SkBitmapShader16BilerpTemplate.h24
-rw-r--r--src/core/SkBitmapShaderTemplate.h24
-rw-r--r--src/core/SkBitmap_scroll.cpp18
-rw-r--r--src/core/SkBlitBWMaskTemplate.h24
-rw-r--r--src/core/SkBlitMask.h70
-rw-r--r--src/core/SkBlitMask_D32.cpp683
-rw-r--r--src/core/SkBlitRow_D16.cpp7
-rw-r--r--src/core/SkBlitRow_D32.cpp93
-rw-r--r--src/core/SkBlitRow_D4444.cpp7
-rw-r--r--src/core/SkBlitter.cpp119
-rw-r--r--src/core/SkBlitter_4444.cpp24
-rw-r--r--src/core/SkBlitter_A1.cpp24
-rw-r--r--src/core/SkBlitter_A8.cpp28
-rw-r--r--src/core/SkBlitter_ARGB32.cpp325
-rw-r--r--src/core/SkBlitter_ARGB32_Subpixel.cpp144
-rw-r--r--src/core/SkBlitter_RGB16.cpp88
-rw-r--r--src/core/SkBlitter_Sprite.cpp32
-rw-r--r--src/core/SkBuffer.cpp24
-rw-r--r--src/core/SkCanvas.cpp635
-rw-r--r--src/core/SkChunkAlloc.cpp24
-rw-r--r--src/core/SkClampRange.cpp19
-rw-r--r--src/core/SkClipStack.cpp35
-rw-r--r--src/core/SkColor.cpp48
-rw-r--r--src/core/SkColorFilter.cpp34
-rw-r--r--src/core/SkColorTable.cpp17
-rw-r--r--src/core/SkComposeShader.cpp31
-rw-r--r--src/core/SkConcaveToTriangles.cpp17
-rw-r--r--src/core/SkConcaveToTriangles.h17
-rw-r--r--src/core/SkConfig8888.h287
-rw-r--r--src/core/SkCordic.cpp24
-rw-r--r--src/core/SkCordic.h24
-rw-r--r--src/core/SkCoreBlitters.h25
-rw-r--r--src/core/SkCubicClipper.cpp17
-rw-r--r--src/core/SkCubicClipper.h17
-rw-r--r--src/core/SkData.cpp103
-rw-r--r--src/core/SkDebug.cpp24
-rw-r--r--src/core/SkDeque.cpp28
-rw-r--r--src/core/SkDevice.cpp300
-rw-r--r--src/core/SkDither.cpp7
-rw-r--r--src/core/SkDraw.cpp781
-rw-r--r--src/core/SkDrawProcs.h18
-rw-r--r--src/core/SkDrawing.cpp152
-rw-r--r--src/core/SkEdge.cpp25
-rw-r--r--src/core/SkEdge.h24
-rw-r--r--src/core/SkEdgeBuilder.cpp11
-rw-r--r--src/core/SkEdgeBuilder.h7
-rw-r--r--src/core/SkEdgeClipper.cpp58
-rw-r--r--src/core/SkFP.h24
-rw-r--r--src/core/SkFilterProc.cpp24
-rw-r--r--src/core/SkFilterProc.h17
-rw-r--r--src/core/SkFlate.cpp47
-rw-r--r--src/core/SkFlattenable.cpp150
-rw-r--r--src/core/SkFloat.cpp19
-rw-r--r--src/core/SkFloat.h17
-rw-r--r--src/core/SkFloatBits.cpp7
-rw-r--r--src/core/SkFontHost.cpp24
-rw-r--r--src/core/SkGeometry.cpp50
-rw-r--r--src/core/SkGlobals.cpp92
-rw-r--r--src/core/SkGlyphCache.cpp91
-rw-r--r--src/core/SkGlyphCache.h38
-rw-r--r--src/core/SkGraphics.cpp135
-rw-r--r--src/core/SkLineClipper.cpp7
-rw-r--r--src/core/SkMMapStream.cpp23
-rw-r--r--src/core/SkMallocPixelRef.cpp11
-rw-r--r--src/core/SkMask.cpp51
-rw-r--r--src/core/SkMaskFilter.cpp43
-rw-r--r--src/core/SkMath.cpp17
-rw-r--r--src/core/SkMatrix.cpp245
-rw-r--r--src/core/SkMemory_stdlib.cpp34
-rw-r--r--src/core/SkMetaData.cpp24
-rw-r--r--src/core/SkPackBits.cpp38
-rw-r--r--src/core/SkPaint.cpp367
-rw-r--r--src/core/SkPath.cpp760
-rw-r--r--src/core/SkPathEffect.cpp42
-rw-r--r--src/core/SkPathHeap.cpp7
-rw-r--r--src/core/SkPathHeap.h7
-rw-r--r--src/core/SkPathMeasure.cpp21
-rw-r--r--src/core/SkPicture.cpp22
-rw-r--r--src/core/SkPictureFlat.cpp7
-rw-r--r--src/core/SkPictureFlat.h28
-rw-r--r--src/core/SkPicturePlayback.cpp91
-rw-r--r--src/core/SkPicturePlayback.h24
-rw-r--r--src/core/SkPictureRecord.cpp100
-rw-r--r--src/core/SkPictureRecord.h75
-rw-r--r--src/core/SkPixelRef.cpp36
-rw-r--r--src/core/SkPoint.cpp94
-rw-r--r--src/core/SkProcSpriteBlitter.cpp24
-rw-r--r--src/core/SkPtrRecorder.cpp7
-rw-r--r--src/core/SkQuadClipper.cpp17
-rw-r--r--src/core/SkQuadClipper.h17
-rw-r--r--src/core/SkRasterClip.cpp270
-rw-r--r--src/core/SkRasterClip.h139
-rw-r--r--src/core/SkRasterizer.cpp24
-rw-r--r--src/core/SkRect.cpp54
-rw-r--r--src/core/SkRefDict.cpp19
-rw-r--r--src/core/SkRegion.cpp107
-rw-r--r--src/core/SkRegionPriv.h24
-rw-r--r--src/core/SkRegion_path.cpp31
-rw-r--r--src/core/SkRegion_rects.cpp7
-rw-r--r--src/core/SkScalar.cpp20
-rw-r--r--src/core/SkScalerContext.cpp359
-rw-r--r--src/core/SkScan.cpp77
-rw-r--r--src/core/SkScanPriv.h24
-rw-r--r--src/core/SkScan_AntiPath.cpp293
-rw-r--r--src/core/SkScan_Antihair.cpp76
-rw-r--r--src/core/SkScan_Hairline.cpp127
-rw-r--r--src/core/SkScan_Path.cpp337
-rw-r--r--src/core/SkShader.cpp101
-rw-r--r--src/core/SkShape.cpp9
-rw-r--r--src/core/SkSinTable.h24
-rw-r--r--src/core/SkSpriteBlitter.h24
-rw-r--r--src/core/SkSpriteBlitterTemplate.h33
-rw-r--r--src/core/SkSpriteBlitter_ARGB32.cpp79
-rw-r--r--src/core/SkSpriteBlitter_RGB16.cpp43
-rw-r--r--src/core/SkStream.cpp264
-rw-r--r--src/core/SkString.cpp96
-rw-r--r--src/core/SkStroke.cpp67
-rw-r--r--src/core/SkStrokerPriv.cpp24
-rw-r--r--src/core/SkStrokerPriv.h24
-rw-r--r--src/core/SkTSearch.cpp24
-rw-r--r--src/core/SkTSort.h24
-rw-r--r--src/core/SkTemplatesPriv.h24
-rw-r--r--src/core/SkTextFormatParams.h17
-rw-r--r--src/core/SkTypeface.cpp58
-rw-r--r--src/core/SkTypefaceCache.cpp27
-rw-r--r--src/core/SkTypefaceCache.h27
-rw-r--r--src/core/SkUnPreMultiply.cpp7
-rw-r--r--src/core/SkUtils.cpp29
-rw-r--r--src/core/SkWriter32.cpp64
-rw-r--r--src/core/SkXfermode.cpp362
-rw-r--r--src/core/core_files.mk102
-rw-r--r--src/effects/Sk1DPathEffect.cpp113
-rw-r--r--src/effects/Sk2DPathEffect.cpp91
-rw-r--r--src/effects/SkArithmeticMode.cpp177
-rw-r--r--src/effects/SkAvoidXfermode.cpp27
-rw-r--r--src/effects/SkBitmapCache.cpp24
-rw-r--r--src/effects/SkBitmapCache.h19
-rw-r--r--src/effects/SkBlurDrawLooper.cpp16
-rw-r--r--src/effects/SkBlurImageFilter.cpp189
-rw-r--r--src/effects/SkBlurMask.cpp504
-rw-r--r--src/effects/SkBlurMask.h28
-rw-r--r--src/effects/SkBlurMaskFilter.cpp128
-rw-r--r--src/effects/SkColorFilters.cpp86
-rw-r--r--src/effects/SkColorMatrixFilter.cpp54
-rw-r--r--src/effects/SkCornerPathEffect.cpp26
-rw-r--r--src/effects/SkDashPathEffect.cpp26
-rw-r--r--src/effects/SkDiscretePathEffect.cpp28
-rw-r--r--src/effects/SkEffects.cpp53
-rw-r--r--src/effects/SkEffects_none.cpp17
-rw-r--r--src/effects/SkEmbossMask.cpp25
-rw-r--r--src/effects/SkEmbossMask.h24
-rw-r--r--src/effects/SkEmbossMaskFilter.cpp24
-rw-r--r--src/effects/SkEmbossMask_Table.h24
-rw-r--r--src/effects/SkGradientShader.cpp1250
-rw-r--r--src/effects/SkGroupShape.cpp9
-rw-r--r--src/effects/SkKernel33MaskFilter.cpp7
-rw-r--r--src/effects/SkLayerDrawLooper.cpp31
-rw-r--r--src/effects/SkLayerRasterizer.cpp43
-rw-r--r--src/effects/SkPaintFlagsDrawFilter.cpp19
-rw-r--r--src/effects/SkPixelXorXfermode.cpp23
-rw-r--r--src/effects/SkPorterDuff.cpp21
-rw-r--r--src/effects/SkRadialGradient_Table.h24
-rw-r--r--src/effects/SkRectShape.cpp21
-rw-r--r--src/effects/SkTableColorFilter.cpp220
-rw-r--r--src/effects/SkTableMaskFilter.cpp19
-rwxr-xr-xsrc/effects/SkTestImageFilters.cpp401
-rw-r--r--src/effects/SkTransparentShader.cpp36
-rw-r--r--src/effects/effects_files.mk25
-rw-r--r--src/gpu/FlingState.cpp (renamed from gpu/src/FlingState.cpp)19
-rw-r--r--src/gpu/GrAAHairLinePathRenderer.cpp730
-rw-r--r--src/gpu/GrAAHairLinePathRenderer.h59
-rw-r--r--src/gpu/GrAddPathRenderers_aahairline.cpp20
-rw-r--r--src/gpu/GrAddPathRenderers_none.cpp15
-rw-r--r--src/gpu/GrAddPathRenderers_tesselated.cpp17
-rw-r--r--src/gpu/GrAllocPool.cpp (renamed from gpu/src/GrAllocPool.cpp)19
-rw-r--r--src/gpu/GrAllocPool.h (renamed from gpu/include/GrAllocPool.h)19
-rwxr-xr-xsrc/gpu/GrAllocator.h (renamed from gpu/include/GrAllocator.h)97
-rw-r--r--src/gpu/GrAtlas.cpp (renamed from gpu/src/GrAtlas.cpp)40
-rw-r--r--src/gpu/GrAtlas.h (renamed from gpu/include/GrAtlas.h)19
-rw-r--r--src/gpu/GrBinHashKey.h95
-rw-r--r--src/gpu/GrBufferAllocPool.cpp (renamed from gpu/src/GrBufferAllocPool.cpp)114
-rw-r--r--src/gpu/GrBufferAllocPool.h (renamed from gpu/src/GrBufferAllocPool.h)33
-rw-r--r--src/gpu/GrClip.cpp (renamed from gpu/src/GrClip.cpp)46
-rw-r--r--src/gpu/GrContext.cpp2120
-rw-r--r--src/gpu/GrDefaultPathRenderer.cpp566
-rw-r--r--src/gpu/GrDefaultPathRenderer.h60
-rw-r--r--src/gpu/GrDrawState.h754
-rw-r--r--src/gpu/GrDrawTarget.cpp1215
-rw-r--r--src/gpu/GrDrawTarget.h1016
-rw-r--r--src/gpu/GrGLCreateNativeInterface_none.cpp13
-rw-r--r--src/gpu/GrGLCreateNullInterface.cpp506
-rw-r--r--src/gpu/GrGLDefaultInterface_native.cpp13
-rw-r--r--src/gpu/GrGLDefaultInterface_none.cpp13
-rw-r--r--src/gpu/GrGLIRect.h (renamed from gpu/include/GrGLIRect.h)31
-rw-r--r--src/gpu/GrGLIndexBuffer.cpp131
-rw-r--r--src/gpu/GrGLIndexBuffer.h (renamed from gpu/include/GrGLIndexBuffer.h)23
-rw-r--r--src/gpu/GrGLInterface.cpp496
-rw-r--r--src/gpu/GrGLProgram.cpp1871
-rw-r--r--src/gpu/GrGLProgram.h386
-rw-r--r--src/gpu/GrGLRenderTarget.cpp97
-rw-r--r--src/gpu/GrGLRenderTarget.h110
-rw-r--r--src/gpu/GrGLSL.cpp32
-rw-r--r--src/gpu/GrGLSL.h34
-rw-r--r--src/gpu/GrGLShaderVar.h304
-rw-r--r--src/gpu/GrGLStencilBuffer.cpp40
-rw-r--r--src/gpu/GrGLStencilBuffer.h60
-rw-r--r--src/gpu/GrGLTexture.cpp90
-rw-r--r--src/gpu/GrGLTexture.h128
-rw-r--r--src/gpu/GrGLUtil.cpp42
-rw-r--r--src/gpu/GrGLVertexBuffer.cpp126
-rw-r--r--src/gpu/GrGLVertexBuffer.h (renamed from gpu/include/GrGLVertexBuffer.h)22
-rw-r--r--src/gpu/GrGeometryBuffer.h (renamed from gpu/include/GrGeometryBuffer.h)38
-rw-r--r--src/gpu/GrGpu.cpp (renamed from gpu/src/GrGpu.cpp)618
-rw-r--r--src/gpu/GrGpu.h (renamed from gpu/include/GrGpu.h)506
-rw-r--r--src/gpu/GrGpuFactory.cpp53
-rw-r--r--src/gpu/GrGpuGL.cpp2540
-rw-r--r--src/gpu/GrGpuGL.h334
-rw-r--r--src/gpu/GrGpuGLShaders.cpp1137
-rw-r--r--src/gpu/GrGpuGLShaders.h (renamed from gpu/src/GrGpuGLShaders.h)53
-rw-r--r--src/gpu/GrGpuVertex.h (renamed from gpu/include/GrGpuVertex.h)19
-rw-r--r--src/gpu/GrInOrderDrawBuffer.cpp (renamed from gpu/src/GrInOrderDrawBuffer.cpp)395
-rw-r--r--src/gpu/GrInOrderDrawBuffer.h (renamed from gpu/include/GrInOrderDrawBuffer.h)120
-rw-r--r--src/gpu/GrIndexBuffer.h33
-rw-r--r--src/gpu/GrMatrix.cpp (renamed from gpu/src/GrMatrix.cpp)19
-rw-r--r--src/gpu/GrMemory.cpp27
-rw-r--r--src/gpu/GrPathRenderer.cpp43
-rw-r--r--src/gpu/GrPathRenderer.h218
-rw-r--r--src/gpu/GrPathRendererChain.cpp59
-rw-r--r--src/gpu/GrPathRendererChain.h65
-rw-r--r--src/gpu/GrPathUtils.cpp (renamed from gpu/src/GrPathUtils.cpp)114
-rw-r--r--src/gpu/GrPathUtils.h50
-rw-r--r--src/gpu/GrPlotMgr.h (renamed from gpu/include/GrPlotMgr.h)19
-rw-r--r--src/gpu/GrPrintf_printf.cpp29
-rw-r--r--src/gpu/GrPrintf_skia.cpp19
-rw-r--r--src/gpu/GrRandom.h (renamed from gpu/include/GrRandom.h)19
-rw-r--r--src/gpu/GrRectanizer.cpp (renamed from gpu/src/GrRectanizer.cpp)19
-rw-r--r--src/gpu/GrRectanizer.h (renamed from gpu/include/GrRectanizer.h)19
-rw-r--r--src/gpu/GrRectanizer_fifo.cpp (renamed from gpu/src/GrRectanizer_fifo.cpp)19
-rw-r--r--src/gpu/GrRedBlackTree.h (renamed from gpu/src/GrRedBlackTree.h)21
-rw-r--r--src/gpu/GrRenderTarget.cpp92
-rw-r--r--src/gpu/GrResource.cpp51
-rw-r--r--src/gpu/GrResourceCache.cpp380
-rw-r--r--src/gpu/GrResourceCache.h318
-rw-r--r--src/gpu/GrStencil.cpp355
-rw-r--r--src/gpu/GrStencil.h323
-rw-r--r--src/gpu/GrStencilBuffer.cpp55
-rw-r--r--src/gpu/GrStencilBuffer.h106
-rw-r--r--src/gpu/GrStringBuilder.h19
-rw-r--r--src/gpu/GrTBSearch.h (renamed from gpu/include/GrTBSearch.h)19
-rw-r--r--src/gpu/GrTDArray.h (renamed from gpu/include/GrTDArray.h)20
-rw-r--r--src/gpu/GrTHashCache.h (renamed from gpu/include/GrTHashCache.h)19
-rw-r--r--src/gpu/GrTLList.h (renamed from gpu/include/GrTLList.h)19
-rw-r--r--src/gpu/GrTesselatedPathRenderer.cpp606
-rw-r--r--src/gpu/GrTesselatedPathRenderer.h27
-rw-r--r--src/gpu/GrTextContext.cpp (renamed from gpu/src/GrTextContext.cpp)84
-rw-r--r--src/gpu/GrTextStrike.cpp (renamed from gpu/src/GrTextStrike.cpp)46
-rw-r--r--src/gpu/GrTextStrike.h (renamed from gpu/include/GrTextStrike.h)19
-rw-r--r--src/gpu/GrTextStrike_impl.h (renamed from gpu/src/GrTextStrike_impl.h)19
-rw-r--r--src/gpu/GrTexture.cpp58
-rw-r--r--src/gpu/GrVertexBuffer.h24
-rw-r--r--src/gpu/SkGLContext.cpp90
-rw-r--r--src/gpu/SkGpuCanvas.cpp26
-rw-r--r--src/gpu/SkGpuDevice.cpp1371
-rw-r--r--src/gpu/SkGr.cpp69
-rw-r--r--src/gpu/SkGrFontScaler.cpp21
-rw-r--r--src/gpu/SkGrTexturePixelRef.cpp118
-rw-r--r--src/gpu/SkNullGLContext.cpp13
-rw-r--r--src/gpu/android/GrGLCreateNativeInterface_android.cpp127
-rw-r--r--src/gpu/android/SkNativeGLContext_android.cpp104
-rw-r--r--src/gpu/app-android.cpp (renamed from gpu/src/app-android.cpp)12
-rw-r--r--src/gpu/gr_hello_world.cpp (renamed from gpu/src/gr_hello_world.cpp)7
-rw-r--r--src/gpu/gr_unittests.cpp (renamed from gpu/src/gr_unittests.cpp)118
-rw-r--r--src/gpu/ios/GrGLDefaultInterface_iOS.cpp140
-rw-r--r--src/gpu/mac/GrGLCreateNativeInterface_mac.cpp273
-rw-r--r--src/gpu/mac/SkNativeGLContext_mac.cpp74
-rw-r--r--src/gpu/mesa/GrGLCreateMesaInterface.cpp197
-rw-r--r--src/gpu/mesa/SkMesaGLContext.cpp103
-rw-r--r--src/gpu/skgr_files.mk8
-rw-r--r--src/gpu/unix/GrGLCreateNativeInterface_unix.cpp200
-rw-r--r--src/gpu/unix/SkNativeGLContext_unix.cpp (renamed from src/utils/unix/SkEGLContext_Unix.cpp)200
-rw-r--r--src/gpu/win/GrGLCreateNativeInterface_win.cpp206
-rw-r--r--src/gpu/win/SkNativeGLContext_win.cpp137
-rw-r--r--src/images/SkBitmap_RLEPixels.h7
-rw-r--r--src/images/SkCreateRLEPixelRef.cpp7
-rw-r--r--src/images/SkFDStream.cpp7
-rw-r--r--src/images/SkFlipPixelRef.cpp10
-rw-r--r--src/images/SkImageDecoder.cpp26
-rw-r--r--src/images/SkImageDecoder_Factory.cpp24
-rw-r--r--src/images/SkImageDecoder_fpdfemb.cpp236
-rw-r--r--src/images/SkImageDecoder_libbmp.cpp17
-rw-r--r--src/images/SkImageDecoder_libgif.cpp24
-rw-r--r--src/images/SkImageDecoder_libico.cpp29
-rw-r--r--src/images/SkImageDecoder_libjpeg.cpp33
-rw-r--r--src/images/SkImageDecoder_libpng.cpp38
-rw-r--r--src/images/SkImageDecoder_libpvjpeg.cpp206
-rw-r--r--src/images/SkImageDecoder_wbmp.cpp23
-rw-r--r--src/images/SkImageEncoder.cpp17
-rw-r--r--src/images/SkImageEncoder_Factory.cpp21
-rw-r--r--src/images/SkImageRef.cpp7
-rw-r--r--src/images/SkImageRefPool.cpp7
-rw-r--r--src/images/SkImageRefPool.h7
-rw-r--r--src/images/SkImageRef_GlobalPool.cpp10
-rw-r--r--src/images/SkJpegUtility.cpp17
-rw-r--r--src/images/SkMovie.cpp7
-rw-r--r--src/images/SkMovie_gif.cpp26
-rw-r--r--src/images/SkPageFlipper.cpp17
-rw-r--r--src/images/SkScaledBitmapSampler.cpp17
-rw-r--r--src/images/SkScaledBitmapSampler.h7
-rw-r--r--src/images/bmpdecoderhelper.cpp17
-rw-r--r--src/images/bmpdecoderhelper.h17
-rw-r--r--src/opts/SkBitmapProcState_opts_SSE2.cpp20
-rw-r--r--src/opts/SkBitmapProcState_opts_SSE2.h20
-rw-r--r--src/opts/SkBitmapProcState_opts_arm.cpp19
-rw-r--r--src/opts/SkBitmapProcState_opts_none.cpp7
-rw-r--r--src/opts/SkBlitRow_opts_SSE2.cpp29
-rw-r--r--src/opts/SkBlitRow_opts_SSE2.h27
-rw-r--r--src/opts/SkBlitRow_opts_arm.cpp39
-rw-r--r--src/opts/SkBlitRow_opts_none.cpp22
-rw-r--r--src/opts/SkUtils_opts_SSE2.cpp20
-rw-r--r--src/opts/SkUtils_opts_SSE2.h20
-rw-r--r--src/opts/SkUtils_opts_none.cpp20
-rw-r--r--src/opts/memset.arm.S23
-rw-r--r--src/opts/memset16_neon.S17
-rw-r--r--src/opts/memset32_neon.S17
-rw-r--r--src/opts/opts_check_SSE2.cpp66
-rw-r--r--src/opts/opts_check_arm.cpp53
-rw-r--r--src/opts/opts_files.mk4
-rw-r--r--src/opts/opts_sse2_files.mk5
-rwxr-xr-xsrc/pdf/SkBitSet.cpp83
-rw-r--r--src/pdf/SkPDFCatalog.cpp136
-rw-r--r--src/pdf/SkPDFDevice.cpp382
-rw-r--r--src/pdf/SkPDFDocument.cpp204
-rw-r--r--[-rwxr-xr-x]src/pdf/SkPDFFont.cpp1239
-rwxr-xr-xsrc/pdf/SkPDFFontImpl.h84
-rw-r--r--src/pdf/SkPDFFormXObject.cpp57
-rw-r--r--src/pdf/SkPDFGraphicState.cpp90
-rw-r--r--src/pdf/SkPDFImage.cpp119
-rw-r--r--src/pdf/SkPDFPage.cpp39
-rw-r--r--src/pdf/SkPDFShader.cpp279
-rw-r--r--src/pdf/SkPDFStream.cpp124
-rw-r--r--src/pdf/SkPDFTypes.cpp194
-rw-r--r--src/pdf/SkPDFUtils.cpp53
-rw-r--r--src/pdf/pdf_files.mk13
-rw-r--r--src/pipe/SkGPipePriv.h30
-rw-r--r--src/pipe/SkGPipeRead.cpp65
-rw-r--r--src/pipe/SkGPipeWrite.cpp66
-rw-r--r--src/ports/FontHostConfiguration_android.cpp39
-rw-r--r--src/ports/FontHostConfiguration_android.h15
-rw-r--r--src/ports/SkDebug_android.cpp43
-rw-r--r--src/ports/SkDebug_brew.cpp23
-rw-r--r--src/ports/SkDebug_stdio.cpp24
-rw-r--r--src/ports/SkDebug_win.cpp20
-rw-r--r--src/ports/SkFontHost_FONTPATH.cpp29
-rw-r--r--src/ports/SkFontHost_FreeType.cpp284
-rw-r--r--src/ports/SkFontHost_FreeType_Subpixel.cpp143
-rw-r--r--src/ports/SkFontHost_android.cpp18
-rw-r--r--src/ports/SkFontHost_ascender.cpp7
-rw-r--r--src/ports/SkFontHost_fontconfig.cpp46
-rw-r--r--src/ports/SkFontHost_freetype_mac.cpp111
-rw-r--r--src/ports/SkFontHost_gamma.cpp35
-rw-r--r--src/ports/SkFontHost_gamma_none.cpp27
-rw-r--r--src/ports/SkFontHost_linux.cpp39
-rwxr-xr-xsrc/ports/SkFontHost_mac.cpp23
-rw-r--r--src/ports/SkFontHost_mac_atsui.cpp100
-rw-r--r--src/ports/SkFontHost_mac_coretext.cpp1304
-rw-r--r--src/ports/SkFontHost_none.cpp55
-rw-r--r--src/ports/SkFontHost_sandbox_none.cpp14
-rw-r--r--src/ports/SkFontHost_simple.cpp34
-rw-r--r--src/ports/SkFontHost_tables.cpp7
-rwxr-xr-xsrc/ports/SkFontHost_win.cpp830
-rw-r--r--src/ports/SkGlobalInitialization_chromium.cpp33
-rw-r--r--src/ports/SkGlobalInitialization_default.cpp37
-rw-r--r--src/ports/SkGlobals_global.cpp28
-rw-r--r--src/ports/SkHarfBuzzFont.cpp17
-rw-r--r--src/ports/SkImageDecoder_CG.cpp37
-rw-r--r--src/ports/SkImageDecoder_WIC.cpp307
-rw-r--r--src/ports/SkImageDecoder_empty.cpp24
-rw-r--r--src/ports/SkImageRef_ashmem.cpp23
-rw-r--r--src/ports/SkImageRef_ashmem.h8
-rw-r--r--src/ports/SkMemory_brew.cpp28
-rw-r--r--src/ports/SkMemory_malloc.cpp11
-rw-r--r--src/ports/SkOSEvent_android.cpp155
-rw-r--r--src/ports/SkOSEvent_dummy.cpp28
-rw-r--r--src/ports/SkOSFile_brew.cpp25
-rw-r--r--src/ports/SkOSFile_stdio.cpp24
-rw-r--r--src/ports/SkThread_none.cpp24
-rw-r--r--src/ports/SkThread_pthread.cpp44
-rw-r--r--src/ports/SkThread_win.cpp24
-rw-r--r--src/ports/SkTime_Unix.cpp27
-rw-r--r--src/ports/SkTime_win.cpp24
-rw-r--r--src/ports/SkXMLParser_empty.cpp25
-rw-r--r--src/ports/SkXMLParser_expat.cpp24
-rw-r--r--src/ports/SkXMLParser_tinyxml.cpp24
-rw-r--r--src/ports/SkXMLPullParser_expat.cpp24
-rw-r--r--src/ports/ports_files.mk6
-rw-r--r--src/ports/sk_predefined_gamma.h7
-rw-r--r--src/svg/SkSVG.cpp24
-rw-r--r--src/svg/SkSVGCircle.cpp24
-rw-r--r--src/svg/SkSVGCircle.h24
-rw-r--r--src/svg/SkSVGClipPath.cpp26
-rw-r--r--src/svg/SkSVGClipPath.h24
-rw-r--r--src/svg/SkSVGDefs.cpp24
-rw-r--r--src/svg/SkSVGDefs.h24
-rw-r--r--src/svg/SkSVGElements.cpp24
-rw-r--r--src/svg/SkSVGElements.h24
-rw-r--r--src/svg/SkSVGEllipse.cpp24
-rw-r--r--src/svg/SkSVGEllipse.h24
-rw-r--r--src/svg/SkSVGFeColorMatrix.cpp24
-rw-r--r--src/svg/SkSVGFeColorMatrix.h24
-rw-r--r--src/svg/SkSVGFilter.cpp24
-rw-r--r--src/svg/SkSVGFilter.h24
-rw-r--r--src/svg/SkSVGG.cpp24
-rw-r--r--src/svg/SkSVGG.h24
-rw-r--r--src/svg/SkSVGGradient.cpp24
-rw-r--r--src/svg/SkSVGGradient.h24
-rw-r--r--src/svg/SkSVGGroup.cpp24
-rw-r--r--src/svg/SkSVGGroup.h24
-rw-r--r--src/svg/SkSVGImage.cpp24
-rw-r--r--src/svg/SkSVGImage.h24
-rw-r--r--src/svg/SkSVGLine.cpp24
-rw-r--r--src/svg/SkSVGLine.h24
-rw-r--r--src/svg/SkSVGLinearGradient.cpp24
-rw-r--r--src/svg/SkSVGLinearGradient.h24
-rw-r--r--src/svg/SkSVGMask.cpp24
-rw-r--r--src/svg/SkSVGMask.h24
-rw-r--r--src/svg/SkSVGMetadata.cpp24
-rw-r--r--src/svg/SkSVGMetadata.h24
-rw-r--r--src/svg/SkSVGPaintState.cpp24
-rw-r--r--src/svg/SkSVGParser.cpp26
-rw-r--r--src/svg/SkSVGPath.cpp24
-rw-r--r--src/svg/SkSVGPath.h24
-rw-r--r--src/svg/SkSVGPolygon.cpp24
-rw-r--r--src/svg/SkSVGPolygon.h24
-rw-r--r--src/svg/SkSVGPolyline.cpp24
-rw-r--r--src/svg/SkSVGPolyline.h24
-rw-r--r--src/svg/SkSVGRadialGradient.cpp24
-rw-r--r--src/svg/SkSVGRadialGradient.h24
-rw-r--r--src/svg/SkSVGRect.cpp24
-rw-r--r--src/svg/SkSVGRect.h24
-rw-r--r--src/svg/SkSVGSVG.cpp24
-rw-r--r--src/svg/SkSVGSVG.h24
-rw-r--r--src/svg/SkSVGStop.cpp24
-rw-r--r--src/svg/SkSVGStop.h24
-rw-r--r--src/svg/SkSVGSymbol.cpp24
-rw-r--r--src/svg/SkSVGSymbol.h24
-rw-r--r--src/svg/SkSVGText.cpp24
-rw-r--r--src/svg/SkSVGText.h24
-rw-r--r--src/svg/SkSVGUse.cpp24
-rw-r--r--src/svg/SkSVGUse.h24
-rw-r--r--src/text/SkTextLayout.cpp7
-rw-r--r--src/utils/SkBoundaryPatch.cpp7
-rw-r--r--src/utils/SkCamera.cpp26
-rw-r--r--src/utils/SkColorMatrix.cpp7
-rw-r--r--src/utils/SkCubicInterval.cpp7
-rw-r--r--src/utils/SkCullPoints.cpp24
-rw-r--r--src/utils/SkDebugTrace.h26
-rw-r--r--src/utils/SkDumpCanvas.cpp33
-rw-r--r--src/utils/SkEGLContext_none.cpp11
-rw-r--r--src/utils/SkInterpolator.cpp17
-rw-r--r--src/utils/SkJSON.cpp637
-rw-r--r--src/utils/SkLayer.cpp7
-rw-r--r--src/utils/SkMatrix44.cpp393
-rw-r--r--src/utils/SkMeshUtils.cpp7
-rw-r--r--src/utils/SkNWayCanvas.cpp26
-rw-r--r--src/utils/SkNinePatch.cpp39
-rw-r--r--src/utils/SkOSFile.cpp9
-rw-r--r--src/utils/SkParse.cpp26
-rw-r--r--src/utils/SkParseColor.cpp24
-rw-r--r--src/utils/SkParsePath.cpp7
-rw-r--r--src/utils/SkProxyCanvas.cpp24
-rw-r--r--src/utils/SkSfntUtils.cpp7
-rw-r--r--src/utils/SkUnitMappers.cpp7
-rw-r--r--src/utils/mac/SkBitmap_Mac.cpp142
-rw-r--r--src/utils/mac/SkCreateCGImageRef.cpp129
-rw-r--r--src/utils/mac/SkEGLContext_mac.cpp68
-rw-r--r--src/utils/mac/SkOSWindow_Mac.cpp534
-rw-r--r--src/utils/mac/skia_mac.cpp43
-rw-r--r--src/utils/mesa/SkEGLContext_Mesa.cpp128
-rw-r--r--src/utils/unix/SkOSWindow_Unix.cpp16
-rw-r--r--src/utils/utils_files.mk16
-rw-r--r--src/views/SkBGViewArtist.cpp7
-rw-r--r--src/views/SkBorderView.cpp7
-rw-r--r--src/views/SkEvent.cpp249
-rw-r--r--src/views/SkEventSink.cpp146
-rw-r--r--src/views/SkImageView.cpp7
-rw-r--r--src/views/SkListView.cpp7
-rw-r--r--src/views/SkListWidget.cpp7
-rw-r--r--src/views/SkOSMenu.cpp280
-rw-r--r--src/views/SkParsePaint.cpp7
-rw-r--r--src/views/SkProgressBarView.cpp7
-rw-r--r--src/views/SkProgressView.cpp8
-rw-r--r--src/views/SkScrollBarView.cpp7
-rw-r--r--src/views/SkStackViewLayout.cpp22
-rw-r--r--src/views/SkStaticTextView.cpp7
-rw-r--r--src/views/SkTagList.cpp24
-rw-r--r--src/views/SkTagList.h24
-rw-r--r--src/views/SkTextBox.cpp24
-rw-r--r--src/views/SkTouchGesture.cpp27
-rw-r--r--src/views/SkView.cpp72
-rw-r--r--src/views/SkViewInflate.cpp7
-rw-r--r--src/views/SkViewPriv.cpp7
-rw-r--r--src/views/SkViewPriv.h7
-rw-r--r--src/views/SkWidget.cpp7
-rw-r--r--src/views/SkWidgetViews.cpp9
-rw-r--r--src/views/SkWidgets.cpp7
-rw-r--r--src/views/SkWindow.cpp118
-rw-r--r--src/xml/SkBML_Verbs.h24
-rw-r--r--src/xml/SkBML_XMLParser.cpp28
-rw-r--r--src/xml/SkDOM.cpp24
-rw-r--r--src/xml/SkJS.cpp24
-rw-r--r--src/xml/SkJSDisplayable.cpp24
-rw-r--r--src/xml/SkXMLParser.cpp24
-rw-r--r--src/xml/SkXMLPullParser.cpp7
-rw-r--r--src/xml/SkXMLWriter.cpp24
-rw-r--r--tests/AAClipTest.cpp287
-rw-r--r--tests/Android.mk49
-rw-r--r--tests/BitSetTest.cpp79
-rw-r--r--tests/BitmapCopyTest.cpp9
-rw-r--r--tests/BitmapGetColorTest.cpp7
-rw-r--r--tests/BlitRowTest.cpp7
-rw-r--r--tests/BlurTest.cpp162
-rw-r--r--tests/CanvasTest.cpp67
-rw-r--r--tests/ClampRangeTest.cpp7
-rw-r--r--tests/ClipCubicTest.cpp7
-rw-r--r--tests/ClipStackTest.cpp28
-rw-r--r--tests/ClipperTest.cpp26
-rw-r--r--tests/ColorFilterTest.cpp7
-rw-r--r--tests/ColorTest.cpp8
-rw-r--r--tests/DataRefTest.cpp61
-rw-r--r--tests/DequeTest.cpp7
-rw-r--r--tests/DrawBitmapRectTest.cpp7
-rw-r--r--tests/EmptyPathTest.cpp156
-rw-r--r--tests/FillPathTest.cpp19
-rw-r--r--tests/FlateTest.cpp31
-rwxr-xr-xtests/GLInterfaceValidation.cpp64
-rw-r--r--tests/GLProgramsTest.cpp21
-rw-r--r--tests/GeometryTest.cpp25
-rw-r--r--tests/InfRectTest.cpp13
-rw-r--r--tests/MathTest.cpp107
-rw-r--r--tests/Matrix44Test.cpp83
-rw-r--r--tests/MatrixTest.cpp121
-rw-r--r--tests/MemsetTest.cpp91
-rw-r--r--tests/MetaDataTest.cpp7
-rw-r--r--tests/PDFPrimitivesTest.cpp248
-rw-r--r--tests/PackBitsTest.cpp7
-rw-r--r--tests/PaintTest.cpp62
-rw-r--r--tests/ParsePathTest.cpp7
-rw-r--r--tests/PathCoverageTest.cpp83
-rw-r--r--tests/PathMeasureTest.cpp7
-rw-r--r--tests/PathTest.cpp957
-rw-r--r--tests/PointTest.cpp46
-rw-r--r--tests/QuickRejectTest.cpp80
-rw-r--r--tests/ReadPixelsTest.cpp391
-rw-r--r--tests/Reader32Test.cpp19
-rw-r--r--tests/RefDictTest.cpp7
-rw-r--r--tests/RegionTest.cpp7
-rw-r--r--tests/ScalarTest.cpp137
-rw-r--r--tests/ShaderOpacityTest.cpp119
-rw-r--r--tests/Sk64Test.cpp7
-rw-r--r--tests/SortTest.cpp7
-rw-r--r--tests/SrcOverTest.cpp7
-rw-r--r--tests/StreamTest.cpp48
-rw-r--r--tests/StringTest.cpp51
-rw-r--r--tests/Test.cpp32
-rw-r--r--tests/Test.h21
-rw-r--r--tests/TestClassDef.h22
-rw-r--r--tests/TestSize.cpp7
-rw-r--r--tests/ToUnicode.cpp133
-rw-r--r--tests/TriangulationTest.cpp7
-rw-r--r--tests/UnicodeTest.cpp45
-rw-r--r--tests/UtilsTest.cpp7
-rw-r--r--tests/WArrayTest.cpp219
-rw-r--r--tests/WritePixelsTest.cpp419
-rw-r--r--tests/Writer32Test.cpp19
-rw-r--r--tests/XfermodeTest.cpp31
-rw-r--r--tests/skia_test.cpp59
-rw-r--r--tests/tests_files.mk39
-rw-r--r--third_party/glu/LICENSE.txt31
-rw-r--r--third_party/glu/README.skia41
-rw-r--r--third_party/glu/gluos.h115
-rw-r--r--third_party/glu/libtess/GNUmakefile110
-rw-r--r--third_party/glu/libtess/Imakefile61
-rw-r--r--third_party/glu/libtess/README447
-rw-r--r--third_party/glu/libtess/alg-outline229
-rw-r--r--third_party/glu/libtess/dict-list.h107
-rw-r--r--third_party/glu/libtess/dict.c117
-rw-r--r--third_party/glu/libtess/dict.h109
-rw-r--r--third_party/glu/libtess/geom.c271
-rw-r--r--third_party/glu/libtess/geom.h90
-rw-r--r--third_party/glu/libtess/memalloc.c62
-rw-r--r--third_party/glu/libtess/memalloc.h62
-rw-r--r--third_party/glu/libtess/mesh.c796
-rw-r--r--third_party/glu/libtess/mesh.h273
-rw-r--r--third_party/glu/libtess/normal.c259
-rw-r--r--third_party/glu/libtess/normal.h52
-rw-r--r--third_party/glu/libtess/priorityq-heap.c260
-rw-r--r--third_party/glu/libtess/priorityq-heap.h114
-rw-r--r--third_party/glu/libtess/priorityq-sort.h124
-rw-r--r--third_party/glu/libtess/priorityq.c267
-rw-r--r--third_party/glu/libtess/priorityq.h124
-rw-r--r--third_party/glu/libtess/render.c505
-rw-r--r--third_party/glu/libtess/render.h59
-rw-r--r--third_party/glu/libtess/sweep.c1362
-rw-r--r--third_party/glu/libtess/sweep.h84
-rw-r--r--third_party/glu/libtess/tess.c638
-rw-r--r--third_party/glu/libtess/tess.h172
-rw-r--r--third_party/glu/libtess/tessmono.c208
-rw-r--r--third_party/glu/libtess/tessmono.h78
-rw-r--r--third_party/glu/sk_glu.h141
1343 files changed, 80711 insertions, 41108 deletions
diff --git a/Android.mk b/Android.mk
index 8a8ed78..1282c7f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,6 +1,30 @@
BASE_PATH := $(call my-dir)
LOCAL_PATH:= $(call my-dir)
+###############################################################################
+#
+# PROBLEMS WITH SKIA DEBUGGING?? READ THIS...
+#
+# The debug build results in changes to the Skia headers. This means that those
+# using libskia must also be built with the debug version of the Skia headers.
+# There are a few scenarios where this comes into play:
+#
+# (1) You're building debug code that depends on libskia.
+# (a) If libskia is built in release, then define SK_RELEASE when building
+# your sources.
+# (b) If libskia is built with debugging (see step 2), then no changes are
+# needed since your sources and libskia have been built with SK_DEBUG.
+# (2) You're building libskia in debug mode.
+# (a) RECOMMENDED: You can build the entire system in debug mode. Do this by
+# updating your buildspec.mk to include TARGET_BUILD_TYPE=debug
+# (b) You can update all the users of libskia to define SK_DEBUG when they are
+# building their sources.
+#
+# NOTE: If neither SK_DEBUG or SK_RELEASE are defined then Skia checks NDEBUG to
+# determine which build type to use.
+###############################################################################
+
+
#############################################################
# build the skia+fretype+png+jpeg+zlib+gif+webp library
#
@@ -25,86 +49,16 @@ endif
LOCAL_SRC_FILES:= \
src/core/Sk64.cpp \
- src/core/SkBuffer.cpp \
- src/core/SkChunkAlloc.cpp \
- src/core/SkCordic.cpp \
- src/core/SkDebug.cpp \
- src/core/SkFloatBits.cpp \
- src/core/SkFontHost.cpp \
- src/core/SkPoint.cpp \
- src/core/SkRect.cpp \
- src/core/SkRegion.cpp \
- src/core/SkString.cpp \
- src/core/SkUtils.cpp \
- src/core/SkFlate.cpp \
- src/core/SkMallocPixelRef.cpp \
- src/core/SkRegion_rects.cpp \
- src/core/SkScalar.cpp \
- src/ports/SkDebug_android.cpp \
- src/effects/Sk1DPathEffect.cpp \
- src/effects/Sk2DPathEffect.cpp \
- src/effects/SkAvoidXfermode.cpp \
- src/effects/SkBitmapCache.cpp \
- src/effects/SkBlurDrawLooper.cpp \
- src/effects/SkBlurMask.cpp \
- src/effects/SkBlurMaskFilter.cpp \
- src/effects/SkColorFilters.cpp \
- src/effects/SkColorMatrixFilter.cpp \
- src/effects/SkCornerPathEffect.cpp \
- src/effects/SkDashPathEffect.cpp \
- src/effects/SkDiscretePathEffect.cpp \
- src/effects/SkEmbossMask.cpp \
- src/effects/SkEmbossMaskFilter.cpp \
- src/effects/SkGradientShader.cpp \
- src/effects/SkGroupShape.cpp \
- src/effects/SkLayerDrawLooper.cpp \
- src/effects/SkLayerRasterizer.cpp \
- src/effects/SkPaintFlagsDrawFilter.cpp \
- src/effects/SkPixelXorXfermode.cpp \
- src/effects/SkPorterDuff.cpp \
- src/effects/SkRectShape.cpp \
- src/effects/SkTableMaskFilter.cpp \
- src/effects/SkTransparentShader.cpp \
- src/images/bmpdecoderhelper.cpp \
- src/images/SkFDStream.cpp \
- src/images/SkFlipPixelRef.cpp \
- src/images/SkImageDecoder.cpp \
- src/images/SkImageDecoder_libbmp.cpp \
- src/images/SkImageDecoder_libgif.cpp \
- src/images/SkImageDecoder_libjpeg.cpp \
- src/images/SkImageDecoder_libpng.cpp \
- src/images/SkImageDecoder_libwebp.cpp \
- src/images/SkImageDecoder_libico.cpp \
- src/images/SkImageDecoder_wbmp.cpp \
- src/images/SkImageEncoder.cpp \
- src/images/SkImageRef.cpp \
- src/images/SkImageRef_GlobalPool.cpp \
- src/images/SkImageRefPool.cpp \
- src/images/SkJpegUtility.cpp \
- src/images/SkBitmapRegionDecoder.cpp \
- src/images/SkMovie.cpp \
- src/images/SkMovie_gif.cpp \
- src/images/SkPageFlipper.cpp \
- src/images/SkScaledBitmapSampler.cpp \
- src/images/SkCreateRLEPixelRef.cpp \
- src/images/SkImageDecoder_Factory.cpp \
- src/images/SkImageEncoder_Factory.cpp \
- src/ports/FontHostConfiguration_android.cpp \
- src/ports/SkFontHost_android.cpp \
- src/ports/SkFontHost_gamma.cpp \
- src/ports/SkFontHost_FreeType.cpp \
- src/ports/SkFontHost_tables.cpp \
- src/ports/SkGlobals_global.cpp \
- src/ports/SkImageRef_ashmem.cpp \
- src/ports/SkOSFile_stdio.cpp \
- src/ports/SkTime_Unix.cpp \
+ src/core/SkAAClip.cpp \
+ src/core/SkAdvancedTypefaceMetrics.cpp \
src/core/SkAlphaRuns.cpp \
src/core/SkBitmap.cpp \
- src/core/SkBitmap_scroll.cpp \
src/core/SkBitmapProcShader.cpp \
src/core/SkBitmapProcState.cpp \
src/core/SkBitmapProcState_matrixProcs.cpp \
src/core/SkBitmapSampler.cpp \
+ src/core/SkBitmap_scroll.cpp \
+ src/core/SkBlitMask_D32.cpp \
src/core/SkBlitRow_D16.cpp \
src/core/SkBlitRow_D32.cpp \
src/core/SkBlitRow_D4444.cpp \
@@ -115,35 +69,43 @@ LOCAL_SRC_FILES:= \
src/core/SkBlitter_ARGB32.cpp \
src/core/SkBlitter_RGB16.cpp \
src/core/SkBlitter_Sprite.cpp \
+ src/core/SkBuffer.cpp \
src/core/SkCanvas.cpp \
+ src/core/SkChunkAlloc.cpp \
src/core/SkClampRange.cpp \
src/core/SkClipStack.cpp \
src/core/SkColor.cpp \
src/core/SkColorFilter.cpp \
src/core/SkColorTable.cpp \
src/core/SkComposeShader.cpp \
+ src/core/SkConcaveToTriangles.cpp \
+ src/core/SkCordic.cpp \
src/core/SkCubicClipper.cpp \
+ src/core/SkData.cpp \
+ src/core/SkDebug.cpp \
src/core/SkDeque.cpp \
src/core/SkDevice.cpp \
src/core/SkDither.cpp \
src/core/SkDraw.cpp \
- src/core/SkEdge.cpp \
- src/core/SkEdgeBuilder.cpp \
+ src/core/SkEdgeBuilder.cpp \
src/core/SkEdgeClipper.cpp \
+ src/core/SkEdge.cpp \
src/core/SkFilterProc.cpp \
src/core/SkFlattenable.cpp \
+ src/core/SkFloat.cpp \
+ src/core/SkFloatBits.cpp \
+ src/core/SkFontHost.cpp \
src/core/SkGeometry.cpp \
- src/core/SkGlobals.cpp \
src/core/SkGlyphCache.cpp \
src/core/SkGraphics.cpp \
src/core/SkLineClipper.cpp \
- src/core/SkMMapStream.cpp \
+ src/core/SkMallocPixelRef.cpp \
src/core/SkMask.cpp \
src/core/SkMaskFilter.cpp \
src/core/SkMath.cpp \
src/core/SkMatrix.cpp \
- src/core/SkMemory_stdlib.cpp \
src/core/SkMetaData.cpp \
+ src/core/SkMMapStream.cpp \
src/core/SkPackBits.cpp \
src/core/SkPaint.cpp \
src/core/SkPath.cpp \
@@ -155,13 +117,18 @@ LOCAL_SRC_FILES:= \
src/core/SkPicturePlayback.cpp \
src/core/SkPictureRecord.cpp \
src/core/SkPixelRef.cpp \
+ src/core/SkPoint.cpp \
src/core/SkProcSpriteBlitter.cpp \
src/core/SkPtrRecorder.cpp \
src/core/SkQuadClipper.cpp \
+ src/core/SkRasterClip.cpp \
src/core/SkRasterizer.cpp \
+ src/core/SkRect.cpp \
src/core/SkRefDict.cpp \
+ src/core/SkRegion.cpp \
src/core/SkRegion_path.cpp \
- src/core/SkScalerContext.cpp \
+ src/core/SkScalar.cpp \
+ src/core/SkScalerContext.cpp \
src/core/SkScan.cpp \
src/core/SkScan_AntiPath.cpp \
src/core/SkScan_Antihair.cpp \
@@ -172,26 +139,101 @@ LOCAL_SRC_FILES:= \
src/core/SkSpriteBlitter_ARGB32.cpp \
src/core/SkSpriteBlitter_RGB16.cpp \
src/core/SkStream.cpp \
+ src/core/SkString.cpp \
src/core/SkStroke.cpp \
src/core/SkStrokerPriv.cpp \
src/core/SkTSearch.cpp \
src/core/SkTypeface.cpp \
src/core/SkTypefaceCache.cpp \
src/core/SkUnPreMultiply.cpp \
- src/core/SkXfermode.cpp \
+ src/core/SkUtils.cpp \
+ src/core/SkFlate.cpp \
src/core/SkWriter32.cpp \
+ src/core/SkXfermode.cpp \
+ src/effects/Sk1DPathEffect.cpp \
+ src/effects/Sk2DPathEffect.cpp \
+ src/effects/SkAvoidXfermode.cpp \
+ src/effects/SkArithmeticMode.cpp \
+ src/effects/SkBitmapCache.cpp \
+ src/effects/SkBlurDrawLooper.cpp \
+ src/effects/SkBlurImageFilter.cpp \
+ src/effects/SkBlurMask.cpp \
+ src/effects/SkBlurMaskFilter.cpp \
+ src/effects/SkColorFilters.cpp \
+ src/effects/SkColorMatrixFilter.cpp \
+ src/effects/SkCornerPathEffect.cpp \
+ src/effects/SkDashPathEffect.cpp \
+ src/effects/SkDiscretePathEffect.cpp \
+ src/effects/SkEffects.cpp \
+ src/effects/SkEmbossMask.cpp \
+ src/effects/SkEmbossMaskFilter.cpp \
+ src/effects/SkGradientShader.cpp \
+ src/effects/SkGroupShape.cpp \
+ src/effects/SkKernel33MaskFilter.cpp \
+ src/effects/SkLayerDrawLooper.cpp \
+ src/effects/SkLayerRasterizer.cpp \
+ src/effects/SkPaintFlagsDrawFilter.cpp \
+ src/effects/SkPixelXorXfermode.cpp \
+ src/effects/SkPorterDuff.cpp \
+ src/effects/SkRectShape.cpp \
+ src/effects/SkTableColorFilter.cpp \
+ src/effects/SkTableMaskFilter.cpp \
+ src/effects/SkTestImageFilters.cpp \
+ src/effects/SkTransparentShader.cpp \
+ src/images/bmpdecoderhelper.cpp \
+ src/images/SkBitmapRegionDecoder.cpp \
+ src/images/SkCreateRLEPixelRef.cpp \
+ src/images/SkFDStream.cpp \
+ src/images/SkFlipPixelRef.cpp \
+ src/images/SkImageDecoder.cpp \
+ src/images/SkImageDecoder_Factory.cpp \
+ src/images/SkImageDecoder_libbmp.cpp \
+ src/images/SkImageDecoder_libgif.cpp \
+ src/images/SkImageDecoder_libico.cpp \
+ src/images/SkImageDecoder_libjpeg.cpp \
+ src/images/SkImageDecoder_libpng.cpp \
+ src/images/SkImageDecoder_libwebp.cpp \
+ src/images/SkImageDecoder_wbmp.cpp \
+ src/images/SkImageEncoder.cpp \
+ src/images/SkImageEncoder_Factory.cpp \
+ src/images/SkImageRef.cpp \
+ src/images/SkImageRefPool.cpp \
+ src/images/SkImageRef_GlobalPool.cpp \
+ src/images/SkJpegUtility.cpp \
+ src/images/SkMovie.cpp \
+ src/images/SkMovie_gif.cpp \
+ src/images/SkPageFlipper.cpp \
+ src/images/SkScaledBitmapSampler.cpp \
+ src/ports/FontHostConfiguration_android.cpp \
+ src/ports/SkDebug_android.cpp \
+ src/ports/SkGlobalInitialization_default.cpp \
+ src/ports/SkFontHost_FreeType.cpp \
+ src/ports/SkFontHost_sandbox_none.cpp \
+ src/ports/SkFontHost_android.cpp \
+ src/ports/SkFontHost_gamma.cpp \
+ src/ports/SkFontHost_tables.cpp \
+ src/ports/SkImageRef_ashmem.cpp \
+ src/ports/SkMemory_malloc.cpp \
+ src/ports/SkOSFile_stdio.cpp \
+ src/ports/SkTime_Unix.cpp \
src/utils/SkBoundaryPatch.cpp \
src/utils/SkCamera.cpp \
+ src/utils/SkColorMatrix.cpp \
+ src/utils/SkCubicInterval.cpp \
+ src/utils/SkCullPoints.cpp \
src/utils/SkDumpCanvas.cpp \
- src/utils/SkEGLContext_none.cpp \
src/utils/SkInterpolator.cpp \
src/utils/SkLayer.cpp \
- src/utils/SkOSFile.cpp \
+ src/utils/SkMatrix44.cpp \
src/utils/SkMeshUtils.cpp \
src/utils/SkNinePatch.cpp \
+ src/utils/SkNWayCanvas.cpp \
+ src/utils/SkOSFile.cpp \
src/utils/SkParse.cpp \
+ src/utils/SkParseColor.cpp \
src/utils/SkParsePath.cpp \
src/utils/SkProxyCanvas.cpp \
+ src/utils/SkSfntUtils.cpp \
src/utils/SkUnitMappers.cpp
ifeq ($(TARGET_ARCH),arm)
@@ -203,14 +245,15 @@ LOCAL_SRC_FILES += \
endif
LOCAL_SRC_FILES += \
- src/opts/SkBlitRow_opts_arm.cpp \
- src/opts/SkBitmapProcState_opts_arm.cpp \
src/opts/opts_check_arm.cpp \
- src/opts/memset.arm.S
+ src/opts/memset.arm.S \
+ src/opts/SkBitmapProcState_opts_arm.cpp \
+ src/opts/SkBlitRow_opts_arm.cpp
else
LOCAL_SRC_FILES += \
src/opts/SkBlitRow_opts_none.cpp \
- src/opts/SkBitmapProcState_opts_none.cpp
+ src/opts/SkBitmapProcState_opts_none.cpp \
+ src/opts/SkUtils_opts_none.cpp
endif
# these are for emoji support, needed by webkit
@@ -235,6 +278,7 @@ LOCAL_STATIC_LIBRARIES := \
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/src/core \
$(LOCAL_PATH)/include/core \
+ $(LOCAL_PATH)/include/config \
$(LOCAL_PATH)/include/effects \
$(LOCAL_PATH)/include/images \
$(LOCAL_PATH)/include/utils \
@@ -271,48 +315,65 @@ ifneq ($(ARCH_ARM_HAVE_VFP),true)
endif
ifeq ($(ARCH_ARM_HAVE_NEON),true)
- LOCAL_CFLAGS += -D__ARM_HAVE_NEON
+ LOCAL_CFLAGS += -DGR_ANDROID_BUILD=1
endif
LOCAL_SRC_FILES:= \
- gpu/src/GrAllocPool.cpp \
- gpu/src/GrAtlas.cpp \
- gpu/src/GrClip.cpp \
- gpu/src/GrContext.cpp \
- gpu/src/GrCreatePathRenderer_none.cpp \
- gpu/src/GrDrawTarget.cpp \
- gpu/src/android/GrGLDefaultInterface_android.cpp \
- gpu/src/GrGLIndexBuffer.cpp \
- gpu/src/GrGLInterface.cpp \
- gpu/src/GrGLProgram.cpp \
- gpu/src/GrGLTexture.cpp \
- gpu/src/GrGLVertexBuffer.cpp \
- gpu/src/GrGpu.cpp \
- gpu/src/GrGpuGLFixed.cpp \
- gpu/src/GrGpuFactory.cpp \
- gpu/src/GrGLUtil.cpp \
- gpu/src/GrGpuGL.cpp \
- gpu/src/GrGpuGLShaders.cpp \
- gpu/src/GrInOrderDrawBuffer.cpp \
- gpu/src/GrMatrix.cpp \
- gpu/src/GrMemory.cpp \
- gpu/src/GrPathUtils.cpp \
- gpu/src/GrRectanizer_fifo.cpp \
- gpu/src/GrResource.cpp \
- gpu/src/GrTexture.cpp \
- gpu/src/GrTextureCache.cpp \
- gpu/src/GrTextContext.cpp \
- gpu/src/GrTextStrike.cpp \
- gpu/src/GrBufferAllocPool.cpp\
- gpu/src/GrPathRenderer.cpp \
- gpu/src/GrStencil.cpp \
- src/gpu/SkGpuCanvas.cpp \
+ src/gpu/GrPrintf_skia.cpp \
+ src/gpu/SkGLContext.cpp \
+ src/gpu/SkGpuCanvas.cpp \
src/gpu/SkGpuDevice.cpp \
src/gpu/SkGr.cpp \
- src/gpu/SkGrTexturePixelRef.cpp \
src/gpu/SkGrFontScaler.cpp \
- src/gpu/GrPrintf_skia.cpp
+ src/gpu/SkGrTexturePixelRef.cpp \
+ src/gpu/SkNullGLContext.cpp \
+ src/gpu/android/SkNativeGLContext_android.cpp
+LOCAL_SRC_FILES += \
+ src/gpu/GrAAHairLinePathRenderer.cpp \
+ src/gpu/GrAddPathRenderers_aahairline.cpp \
+ src/gpu/GrAllocPool.cpp \
+ src/gpu/GrAtlas.cpp \
+ src/gpu/GrBufferAllocPool.cpp \
+ src/gpu/GrClip.cpp \
+ src/gpu/GrContext.cpp \
+ src/gpu/GrDefaultPathRenderer.cpp \
+ src/gpu/GrDrawTarget.cpp \
+ src/gpu/GrGLCreateNullInterface.cpp \
+ src/gpu/GrGLDefaultInterface_native.cpp \
+ src/gpu/GrGLIndexBuffer.cpp \
+ src/gpu/GrGLInterface.cpp \
+ src/gpu/GrGLProgram.cpp \
+ src/gpu/GrGLRenderTarget.cpp \
+ src/gpu/GrGLSL.cpp \
+ src/gpu/GrGLStencilBuffer.cpp \
+ src/gpu/GrGLTexture.cpp \
+ src/gpu/GrGLUtil.cpp \
+ src/gpu/GrGLVertexBuffer.cpp \
+ src/gpu/GrGpu.cpp \
+ src/gpu/GrGpuFactory.cpp \
+ src/gpu/GrGpuGL.cpp \
+ src/gpu/GrGpuGLShaders.cpp \
+ src/gpu/GrInOrderDrawBuffer.cpp \
+ src/gpu/GrMatrix.cpp \
+ src/gpu/GrMemory.cpp \
+ src/gpu/GrPathRendererChain.cpp \
+ src/gpu/GrPathRenderer.cpp \
+ src/gpu/GrPathUtils.cpp \
+ src/gpu/GrRectanizer.cpp \
+ src/gpu/GrRenderTarget.cpp \
+ src/gpu/GrResource.cpp \
+ src/gpu/GrResourceCache.cpp \
+ src/gpu/GrStencil.cpp \
+ src/gpu/GrStencilBuffer.cpp \
+ src/gpu/GrTesselatedPathRenderer.cpp \
+ src/gpu/GrTextContext.cpp \
+ src/gpu/GrTextStrike.cpp \
+ src/gpu/GrTexture.cpp \
+ src/gpu/gr_unittests.cpp \
+ src/gpu/android/GrGLCreateNativeInterface_android.cpp
+
+LOCAL_STATIC_LIBRARIES := libskiatess
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
@@ -321,12 +382,13 @@ LOCAL_SHARED_LIBRARIES := \
libGLESv2
LOCAL_C_INCLUDES += \
- $(LOCAL_PATH)/gpu/include \
- $(LOCAL_PATH)/gpu/src \
$(LOCAL_PATH)/include/core \
+ $(LOCAL_PATH)/include/config \
$(LOCAL_PATH)/include/gpu \
$(LOCAL_PATH)/src/core \
- frameworks/base/opengl/include/GLES2
+ $(LOCAL_PATH)/src/gpu \
+ $(LOCAL_PATH)/third_party/glu \
+ frameworks/base/opengl/include
LOCAL_LDLIBS += -lpthread
@@ -336,6 +398,44 @@ LOCAL_MODULE_TAGS := optional
include $(BUILD_STATIC_LIBRARY)
#############################################################
+# Build the skia gpu (ganesh) library
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_ARM_MODE := arm
+
+LOCAL_SRC_FILES := \
+ third_party/glu/libtess/dict.c \
+ third_party/glu/libtess/geom.c \
+ third_party/glu/libtess/memalloc.c \
+ third_party/glu/libtess/mesh.c \
+ third_party/glu/libtess/normal.c \
+ third_party/glu/libtess/priorityq.c \
+ third_party/glu/libtess/render.c \
+ third_party/glu/libtess/sweep.c \
+ third_party/glu/libtess/tess.c \
+ third_party/glu/libtess/tessmono.c
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libEGL \
+ libGLESv2
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/third_party/glu \
+ $(LOCAL_PATH)/third_party/glu/libtess \
+ frameworks/base/opengl/include
+
+LOCAL_LDLIBS += -lpthread
+
+LOCAL_MODULE:= libskiatess
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
+
+#############################################################
# Build the skia tools
#
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e74c256
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_BSD
index e69de29..e69de29 100644
--- a/MODULE_LICENSE_APACHE2
+++ b/MODULE_LICENSE_BSD
diff --git a/NOTICE b/NOTICE
index c5b1efa..3106369 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,190 +1,68 @@
-
- Copyright (c) 2005-2008, The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
+// Copyright (c) 2011 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+=========================================================================
+
+The SKIA library also includes a third-party dependency on a nearly
+verbatim copy of the GLU tessellator source code from SGI's OpenGL Sample
+Implementation at http://oss.sgi.com/projects/ogl-sample/. Per
+http://oss.sgi.com/projects/FreeB/, the code is covered under the SGI
+Free Software License B, version 2.0, a copy of which is included below.
+
+SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+
+Copyright (C) [dates of first publication] Silicon Graphics, Inc. All
+Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice including the dates of first publication
+and either this permission notice or a reference to HYPERLINK
+"http://oss.sgi.com/projects/FreeB/"http://oss.sgi.com/projects/FreeB/
+shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of Silicon Graphics,
+Inc. shall not be used in advertising or otherwise to promote the
+sale, use or other dealings in this Software without prior written
+authorization from Silicon Graphics, Inc.
diff --git a/README b/README
new file mode 100644
index 0000000..84e4ecc
--- /dev/null
+++ b/README
@@ -0,0 +1,3 @@
+Skia is a complete 2D graphic library for drawing Text, Geometries, and Images.
+
+See full details, and build instructions, at http://code.google.com/p/skia/wiki/DocRoot
diff --git a/bench/AAClipBench.cpp b/bench/AAClipBench.cpp
new file mode 100644
index 0000000..39088c1
--- /dev/null
+++ b/bench/AAClipBench.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBenchmark.h"
+#include "SkAAClip.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkString.h"
+
+class AAClipBuilderBench : public SkBenchmark {
+ SkString fName;
+ SkPath fPath;
+ SkRect fRect;
+ SkRegion fRegion;
+ bool fDoPath;
+ bool fDoAA;
+
+ enum {
+ N = SkBENCHLOOP(200),
+ };
+
+public:
+ AAClipBuilderBench(void* param, bool doPath, bool doAA) : INHERITED(param) {
+ fDoPath = doPath;
+ fDoAA = doAA;
+
+ fName.printf("aaclip_build_%s_%s", doPath ? "path" : "rect",
+ doAA ? "AA" : "BW");
+
+ fRegion.setRect(0, 0, 640, 480);
+ fRect.set(fRegion.getBounds());
+ fRect.inset(SK_Scalar1/4, SK_Scalar1/4);
+ fPath.addRoundRect(fRect, SkIntToScalar(20), SkIntToScalar(20));
+ }
+
+protected:
+ virtual const char* onGetName() { return fName.c_str(); }
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+ this->setupPaint(&paint);
+
+ for (int i = 0; i < N; ++i) {
+ SkAAClip clip;
+ if (fDoPath) {
+ clip.setPath(fPath, &fRegion, fDoAA);
+ } else {
+ clip.setRect(fRect, fDoAA);
+ }
+ }
+ }
+private:
+ typedef SkBenchmark INHERITED;
+};
+
+class AAClipRegionBench : public SkBenchmark {
+public:
+ AAClipRegionBench(void* param) : INHERITED(param) {
+ SkPath path;
+ // test conversion of a complex clip to a aaclip
+ path.addCircle(0, 0, SkIntToScalar(200));
+ path.addCircle(0, 0, SkIntToScalar(180));
+ // evenodd means we've constructed basically a stroked circle
+ path.setFillType(SkPath::kEvenOdd_FillType);
+
+ SkIRect bounds;
+ path.getBounds().roundOut(&bounds);
+ fRegion.setPath(path, SkRegion(bounds));
+ }
+
+protected:
+ virtual const char* onGetName() { return "aaclip_setregion"; }
+ virtual void onDraw(SkCanvas* canvas) {
+ for (int i = 0; i < N; ++i) {
+ SkAAClip clip;
+ clip.setRegion(fRegion);
+ }
+ }
+
+private:
+ enum {
+ N = SkBENCHLOOP(400),
+ };
+ SkRegion fRegion;
+ typedef SkBenchmark INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkBenchmark* Fact0(void* p) { return SkNEW_ARGS(AAClipBuilderBench, (p, false, false)); }
+static SkBenchmark* Fact1(void* p) { return SkNEW_ARGS(AAClipBuilderBench, (p, false, true)); }
+static SkBenchmark* Fact2(void* p) { return SkNEW_ARGS(AAClipBuilderBench, (p, true, false)); }
+static SkBenchmark* Fact3(void* p) { return SkNEW_ARGS(AAClipBuilderBench, (p, true, true)); }
+
+static BenchRegistry gReg0(Fact0);
+static BenchRegistry gReg1(Fact1);
+static BenchRegistry gReg2(Fact2);
+static BenchRegistry gReg3(Fact3);
+
+static SkBenchmark* Fact01(void* p) { return SkNEW_ARGS(AAClipRegionBench, (p)); }
+static BenchRegistry gReg01(Fact01);
diff --git a/bench/Android.mk b/bench/Android.mk
index a0fe86c..ab2e588 100644
--- a/bench/Android.mk
+++ b/bench/Android.mk
@@ -3,36 +3,42 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- BenchGpuTimer_none.cpp \
- BenchSysTimer_posix.cpp \
+ benchmain.cpp \
BenchTimer.cpp \
+ BenchSysTimer_posix.cpp \
+ BenchGpuTimer_gl.cpp \
+ SkBenchmark.cpp
+
+LOCAL_SRC_FILES += \
+ AAClipBench.cpp \
BitmapBench.cpp \
+ BlurBench.cpp \
+ ChromeBench.cpp \
DecodeBench.cpp \
- FPSBench.cpp \
+ FontScalerBench.cpp \
GradientBench.cpp \
+ MathBench.cpp \
MatrixBench.cpp \
+ MutexBench.cpp \
PathBench.cpp \
RectBench.cpp \
RepeatTileBench.cpp \
+ ScalarBench.cpp \
+ ShaderMaskBench.cpp \
TextBench.cpp \
- SkBenchmark.cpp \
- benchmain.cpp
-
-# additional optional class for this tool
-LOCAL_SRC_FILES += \
- ../src/utils/SkNWayCanvas.cpp \
- ../src/utils/SkParse.cpp
+ VertBench.cpp
-LOCAL_SHARED_LIBRARIES := libcutils libskia libGLESv2
+LOCAL_SHARED_LIBRARIES := libcutils libskia libGLESv2 libEGL
LOCAL_STATIC_LIBRARIES := libskiagpu
LOCAL_C_INCLUDES := \
- external/skia/include/config \
external/skia/include/core \
+ external/skia/include/config \
+ external/skia/include/effects \
+ external/skia/include/gpu \
external/skia/include/images \
external/skia/include/utils \
- external/skia/include/effects \
- external/skia/gpu/include \
- external/skia/include/gpu
+ external/skia/src/core \
+ external/skia/src/gpu
#LOCAL_CFLAGS :=
diff --git a/bench/BenchGpuTimer_gl.cpp b/bench/BenchGpuTimer_gl.cpp
index ec2145d..885f7b2 100644
--- a/bench/BenchGpuTimer_gl.cpp
+++ b/bench/BenchGpuTimer_gl.cpp
@@ -1,159 +1,41 @@
-#include "BenchGpuTimer_gl.h"
-#include <string.h>
-
-//GL
-#define BENCH_GL_FUNCTION_TYPE
-#if defined(SK_MESA)
- #include <GL/osmesa.h>
- #define SK_BENCH_CONTEXT_CHECK (NULL != OSMesaGetCurrentContext())
-
- #define SK_GL_GET_PROC(F) gBenchGL.f ## F = (BenchGL ## F ## Proc) \
- OSMesaGetProcAddress("gl" #F);
- #define SK_GL_GET_PROC_SUFFIX(F, S) gBenchGL.f ## F = (BenchGL##F##Proc)\
- OSMesaGetProcAddress("gl" #F #S);
-
-#elif defined(SK_BUILD_FOR_WIN32)
- #define WIN32_LEAN_AND_MEAN 1
- #include <Windows.h>
- #include <GL/GL.h>
- #define SK_BENCH_CONTEXT_CHECK (NULL != wglGetCurrentContext())
-
- #undef BENCH_GL_FUNCTION_TYPE
- #define BENCH_GL_FUNCTION_TYPE __stdcall
- #define SK_GL_GET_PROC(F) gBenchGL.f ## F = (BenchGL ## F ## Proc) \
- wglGetProcAddress("gl" #F);
- #define SK_GL_GET_PROC_SUFFIX(F, S) gBenchGL.f ## F = (BenchGL##F##Proc)\
- wglGetProcAddress("gl" #F #S);
-
-#elif defined(SK_BUILD_FOR_MAC)
- #include <OpenGL/gl.h>
- #include <OpenGL/CGLCurrent.h>
- #define SK_BENCH_CONTEXT_CHECK (NULL != CGLGetCurrentContext())
-
-#elif defined(SK_BUILD_FOR_UNIX)
- #include <GL/gl.h>
- #include <GL/glx.h>
- #define SK_BENCH_CONTEXT_CHECK (NULL != glXGetCurrentContext())
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "BenchGpuTimer_gl.h"
+#include "SkGLContext.h"
+
+BenchGpuTimer::BenchGpuTimer(const SkGLContext* glctx) {
+ fContext = glctx;
+ glctx->ref();
+ glctx->makeCurrent();
+ fStarted = false;
+ fSupported = GrGLGetVersion(glctx->gl()) > GR_GL_VER(3,3) ||
+ GrGLHasExtension(glctx->gl(), "GL_ARB_timer_query") ||
+ GrGLHasExtension(glctx->gl(), "GL_EXT_timer_query");
- #define SK_GL_GET_PROC(F) gBenchGL.f ## F = (BenchGL ## F ## Proc) \
- glXGetProcAddressARB(reinterpret_cast<const GLubyte*>("gl" #F));
- #define SK_GL_GET_PROC_SUFFIX(F, S) gBenchGL.f ## F = (BenchGL##F##Proc)\
- glXGetProcAddressARB(reinterpret_cast<const GLubyte*>("gl" #F #S));
-#else
- #error unsupported platform
-#endif
-
-#define BenchGL_TIME_ELAPSED 0x88BF
-#define BenchGL_QUERY_RESULT 0x8866
-#define BenchGL_QUERY_RESULT_AVAILABLE 0x8867
-
-#if defined(SK_BUILD_FOR_WIN32)
-typedef UINT64 BenchGLuint64;
-#else
-#include <stdint.h>
-typedef uint64_t BenchGLuint64;
-#endif
-
-typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGenQueriesProc) (GLsizei n, GLuint *ids);
-typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLBeginQueryProc) (GLenum target, GLuint id);
-typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLEndQueryProc) (GLenum target);
-typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLDeleteQueriesProc) (GLsizei n, const GLuint *ids);
-typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGetQueryObjectivProc) (GLuint id, GLenum pname, GLint *params);
-typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGetQueryObjectui64vProc) (GLuint id, GLenum pname, BenchGLuint64 *params);
-
-struct BenchGLInterface {
- bool fHasTimer;
- BenchGLGenQueriesProc fGenQueries;
- BenchGLBeginQueryProc fBeginQuery;
- BenchGLEndQueryProc fEndQuery;
- BenchGLDeleteQueriesProc fDeleteQueries;
- BenchGLGetQueryObjectivProc fGetQueryObjectiv;
- BenchGLGetQueryObjectui64vProc fGetQueryObjectui64v;
-};
-
-static bool BenchGLCheckExtension(const char* ext,
- const char* extensionString) {
- int extLength = strlen(ext);
-
- while (true) {
- int n = strcspn(extensionString, " ");
- if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
- return true;
- }
- if (0 == extensionString[n]) {
- return false;
- }
- extensionString += n+1;
- }
-
- return false;
-}
-
-static BenchGLInterface gBenchGL;
-static bool gBenchGLInterfaceInit = false;
-
-static void BenchGLSetDefaultGLInterface() {
- gBenchGL.fHasTimer = false;
- if (gBenchGLInterfaceInit || !SK_BENCH_CONTEXT_CHECK) return;
-
- const char* glExts =
- reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
- const GLboolean ext =
- BenchGLCheckExtension("GL_EXT_timer_query", glExts);
- const GLboolean arb =
- BenchGLCheckExtension("GL_ARB_timer_query", glExts);
- if (ext || arb) {
-#if defined(SK_BUILD_FOR_MAC)
- #if GL_EXT_timer_query || GL_ARB_timer_query
- gBenchGL.fHasTimer = true;
- gBenchGL.fGenQueries = glGenQueries;
- gBenchGL.fBeginQuery = glBeginQuery;
- gBenchGL.fEndQuery = glEndQuery;
- gBenchGL.fDeleteQueries = glDeleteQueries;
- gBenchGL.fGetQueryObjectiv = glGetQueryObjectiv;
- #endif
- #if GL_ARB_timer_query
- gBenchGL.fGetQueryObjectui64v = glGetQueryObjectui64v;
- #elif GL_EXT_timer_query
- gBenchGL.fGetQueryObjectui64v = glGetQueryObjectui64vEXT;
- #endif
-#else
- gBenchGL.fHasTimer = true;
- SK_GL_GET_PROC(GenQueries)
- SK_GL_GET_PROC(BeginQuery)
- SK_GL_GET_PROC(EndQuery)
- SK_GL_GET_PROC(DeleteQueries)
-
- SK_GL_GET_PROC(GetQueryObjectiv)
- if (arb) {
- SK_GL_GET_PROC(GetQueryObjectui64v)
- } else {
- SK_GL_GET_PROC_SUFFIX(GetQueryObjectui64v, EXT)
- }
-#endif
- }
- gBenchGLInterfaceInit = true;
-}
-
-BenchGpuTimer::BenchGpuTimer() {
- BenchGLSetDefaultGLInterface();
- if (gBenchGL.fHasTimer) {
- gBenchGL.fGenQueries(1, &this->fQuery);
+ if (fSupported) {
+ SK_GL(*glctx, GenQueries(1, &fQuery));
}
}
BenchGpuTimer::~BenchGpuTimer() {
- if (gBenchGL.fHasTimer) {
- gBenchGL.fDeleteQueries(1, &this->fQuery);
+ if (fSupported) {
+ fContext->makeCurrent();
+ SK_GL(*fContext, DeleteQueries(1, &fQuery));
}
+ fContext->unref();
}
void BenchGpuTimer::startGpu() {
- if (!gBenchGL.fHasTimer) return;
-
- this->fStarted = true;
- gBenchGL.fBeginQuery(BenchGL_TIME_ELAPSED, this->fQuery);
+ if (fSupported) {
+ fContext->makeCurrent();
+ fStarted = true;
+ SK_GL(*fContext, BeginQuery(GR_GL_TIME_ELAPSED, fQuery));
+ }
}
/**
@@ -161,21 +43,24 @@ void BenchGpuTimer::startGpu() {
* as this will cpu wait for the gpu to finish.
*/
double BenchGpuTimer::endGpu() {
- if (!gBenchGL.fHasTimer) return 0;
-
- this->fStarted = false;
- gBenchGL.fEndQuery(BenchGL_TIME_ELAPSED);
-
- GLint available = 0;
- while (!available) {
- gBenchGL.fGetQueryObjectiv(this->fQuery
- , BenchGL_QUERY_RESULT_AVAILABLE
- , &available);
+ if (fSupported) {
+ fStarted = false;
+ fContext->makeCurrent();
+ SK_GL(*fContext, EndQuery(GR_GL_TIME_ELAPSED));
+
+ GrGLint available = 0;
+ while (!available) {
+ SK_GL(*fContext, GetQueryObjectiv(fQuery,
+ GR_GL_QUERY_RESULT_AVAILABLE,
+ &available));
+ }
+ GrGLuint64 totalGPUTimeElapsed = 0;
+ SK_GL(*fContext, GetQueryObjectui64v(fQuery,
+ GR_GL_QUERY_RESULT,
+ &totalGPUTimeElapsed));
+
+ return totalGPUTimeElapsed / 1000000.0;
+ } else {
+ return 0;
}
- BenchGLuint64 totalGPUTimeElapsed = 0;
- gBenchGL.fGetQueryObjectui64v(this->fQuery
- , BenchGL_QUERY_RESULT
- , &totalGPUTimeElapsed);
-
- return totalGPUTimeElapsed / 1000000.0;
}
diff --git a/bench/BenchGpuTimer_gl.h b/bench/BenchGpuTimer_gl.h
index ac23482..7c7b5c2 100644
--- a/bench/BenchGpuTimer_gl.h
+++ b/bench/BenchGpuTimer_gl.h
@@ -1,33 +1,26 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkBenchGpuTimer_DEFINED
#define SkBenchGpuTimer_DEFINED
-#if defined(SK_MESA)
- #include <GL/osmesa.h>
-
-#elif defined(SK_BUILD_FOR_WIN32)
- #define WIN32_LEAN_AND_MEAN 1
- #include <Windows.h>
- #include <GL/GL.h>
-
-#elif defined(SK_BUILD_FOR_MAC)
- #include <OpenGL/gl.h>
-
-#elif defined(SK_BUILD_FOR_UNIX)
- #include <GL/gl.h>
-
-#else
- #error unsupported platform
-#endif
+class SkGLContext;
class BenchGpuTimer {
public:
- BenchGpuTimer();
+ BenchGpuTimer(const SkGLContext* glctx);
~BenchGpuTimer();
void startGpu();
double endGpu();
private:
- GLuint fQuery;
+ unsigned fQuery;
int fStarted;
+ const SkGLContext* fContext;
+ bool fSupported;
};
#endif
diff --git a/bench/BenchGpuTimer_none.cpp b/bench/BenchGpuTimer_none.cpp
deleted file mode 100644
index 0dba6d7..0000000
--- a/bench/BenchGpuTimer_none.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "BenchGpuTimer_none.h"
-
-BenchGpuTimer::BenchGpuTimer() {
-}
-
-BenchGpuTimer::~BenchGpuTimer() {
-}
-
-void BenchGpuTimer::startGpu() {
-}
-
-double BenchGpuTimer::endGpu() {
- return -1.0;
-}
diff --git a/bench/BenchGpuTimer_none.h b/bench/BenchGpuTimer_none.h
deleted file mode 100644
index 7069ca4..0000000
--- a/bench/BenchGpuTimer_none.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef SkBenchGpuTimer_DEFINED
-#define SkBenchGpuTimer_DEFINED
-
-class BenchGpuTimer {
-public:
- BenchGpuTimer();
- ~BenchGpuTimer();
- void startGpu();
- double endGpu();
-};
-
-#endif
diff --git a/bench/BenchSysTimer_c.cpp b/bench/BenchSysTimer_c.cpp
index fc0850b..f4cbd39 100644
--- a/bench/BenchSysTimer_c.cpp
+++ b/bench/BenchSysTimer_c.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "BenchSysTimer_c.h"
//Time
diff --git a/bench/BenchSysTimer_c.h b/bench/BenchSysTimer_c.h
index c598f30..2ddc83d 100644
--- a/bench/BenchSysTimer_c.h
+++ b/bench/BenchSysTimer_c.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkBenchSysTimer_DEFINED
#define SkBenchSysTimer_DEFINED
diff --git a/bench/BenchSysTimer_mach.cpp b/bench/BenchSysTimer_mach.cpp
index b23897c..c837ca3 100644
--- a/bench/BenchSysTimer_mach.cpp
+++ b/bench/BenchSysTimer_mach.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "BenchSysTimer_mach.h"
//Time
diff --git a/bench/BenchSysTimer_mach.h b/bench/BenchSysTimer_mach.h
index da4fff0..44d0e5e 100644
--- a/bench/BenchSysTimer_mach.h
+++ b/bench/BenchSysTimer_mach.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkBenchSysTimer_DEFINED
#define SkBenchSysTimer_DEFINED
diff --git a/bench/BenchSysTimer_posix.cpp b/bench/BenchSysTimer_posix.cpp
index 5d28f40..e6767e5 100644
--- a/bench/BenchSysTimer_posix.cpp
+++ b/bench/BenchSysTimer_posix.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "BenchSysTimer_posix.h"
//Time
diff --git a/bench/BenchSysTimer_posix.h b/bench/BenchSysTimer_posix.h
index 09dfb0e..de793f3 100644
--- a/bench/BenchSysTimer_posix.h
+++ b/bench/BenchSysTimer_posix.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkBenchSysTimer_DEFINED
#define SkBenchSysTimer_DEFINED
diff --git a/bench/BenchSysTimer_windows.cpp b/bench/BenchSysTimer_windows.cpp
index 923754c..3635ec5 100644
--- a/bench/BenchSysTimer_windows.cpp
+++ b/bench/BenchSysTimer_windows.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "BenchSysTimer_windows.h"
//Time
@@ -35,7 +42,7 @@ void BenchSysTimer::startCpu() {
double BenchSysTimer::endCpu() {
ULONGLONG end_cpu = winCpuTime();
- return (end_cpu - this->fStartCpu) / 10000;
+ return static_cast<double>((end_cpu - this->fStartCpu)) / 10000.0L;
}
double BenchSysTimer::endWall() {
LARGE_INTEGER end_wall;
@@ -48,8 +55,10 @@ double BenchSysTimer::endWall() {
LARGE_INTEGER frequency;
if (0 == ::QueryPerformanceFrequency(&frequency)) {
- return 0;
+ return 0.0L;
} else {
- return (double)ticks_elapsed.QuadPart / frequency.QuadPart * 1000;
+ return static_cast<double>(ticks_elapsed.QuadPart)
+ / static_cast<double>(frequency.QuadPart)
+ * 1000.0L;
}
}
diff --git a/bench/BenchSysTimer_windows.h b/bench/BenchSysTimer_windows.h
index 72a3fb2..c3d0c9b 100644
--- a/bench/BenchSysTimer_windows.h
+++ b/bench/BenchSysTimer_windows.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkBenchSysTimer_DEFINED
#define SkBenchSysTimer_DEFINED
@@ -5,7 +12,7 @@
#define WIN32_LEAN_AND_MEAN 1
#include <Windows.h>
-struct BenchSysTimer {
+class BenchSysTimer {
public:
void startWall();
void startCpu();
diff --git a/bench/BenchTimer.cpp b/bench/BenchTimer.cpp
index e7b0068..c3a1190 100644
--- a/bench/BenchTimer.cpp
+++ b/bench/BenchTimer.cpp
@@ -1,48 +1,55 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "BenchTimer.h"
#if defined(SK_BUILD_FOR_WIN32)
#include "BenchSysTimer_windows.h"
#elif defined(SK_BUILD_FOR_MAC)
#include "BenchSysTimer_mach.h"
-#elif defined(SK_BUILD_FOR_UNIX)
+#elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
#include "BenchSysTimer_posix.h"
#else
#include "BenchSysTimer_c.h"
#endif
-#if defined(SK_MESA) || \
- defined(SK_BUILD_FOR_WIN32) || \
- defined(SK_BUILD_FOR_MAC) || \
- defined(SK_BUILD_FOR_UNIX)
- #include "BenchGpuTimer_gl.h"
-
-#else
- #include "BenchGpuTimer_none.h"
-#endif
+#include "BenchGpuTimer_gl.h"
-BenchTimer::BenchTimer()
+BenchTimer::BenchTimer(SkGLContext* gl)
: fCpu(-1.0)
, fWall(-1.0)
, fGpu(-1.0)
{
- this->fSysTimer = new BenchSysTimer();
- this->fGpuTimer = new BenchGpuTimer();
+ fSysTimer = new BenchSysTimer();
+ if (gl) {
+ fGpuTimer = new BenchGpuTimer(gl);
+ } else {
+ fGpuTimer = NULL;
+ }
}
BenchTimer::~BenchTimer() {
- delete this->fSysTimer;
- delete this->fGpuTimer;
+ delete fSysTimer;
+ delete fGpuTimer;
}
void BenchTimer::start() {
- this->fSysTimer->startWall();
- this->fGpuTimer->startGpu();
- this->fSysTimer->startCpu();
+ fSysTimer->startWall();
+ if (fGpuTimer) {
+ fGpuTimer->startGpu();
+ }
+ fSysTimer->startCpu();
}
void BenchTimer::end() {
- this->fCpu = this->fSysTimer->endCpu();
+ fCpu = fSysTimer->endCpu();
//It is important to stop the cpu clocks first,
//as the following will cpu wait for the gpu to finish.
- this->fGpu = this->fGpuTimer->endGpu();
- this->fWall = this->fSysTimer->endWall();
+ if (fGpuTimer) {
+ fGpu = fGpuTimer->endGpu();
+ }
+ fWall = fSysTimer->endWall();
}
diff --git a/bench/BenchTimer.h b/bench/BenchTimer.h
index eae82d5..080bc6d 100644
--- a/bench/BenchTimer.h
+++ b/bench/BenchTimer.h
@@ -1,9 +1,21 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkBenchTimer_DEFINED
#define SkBenchTimer_DEFINED
+#include <SkTypes.h>
+
+
class BenchSysTimer;
class BenchGpuTimer;
+class SkGLContext;
+
/**
* SysTimers and GpuTimers are implemented orthogonally.
* This class combines a SysTimer and a GpuTimer into one single,
@@ -11,7 +23,7 @@ class BenchGpuTimer;
*/
class BenchTimer {
public:
- BenchTimer();
+ BenchTimer(SkGLContext* gl = NULL);
~BenchTimer();
void start();
void end();
diff --git a/bench/BitmapBench.cpp b/bench/BitmapBench.cpp
index 77e7ade..3b16925 100644
--- a/bench/BitmapBench.cpp
+++ b/bench/BitmapBench.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkBitmap.h"
#include "SkPaint.h"
@@ -93,13 +100,15 @@ class BitmapBench : public SkBenchmark {
SkBitmap fBitmap;
SkPaint fPaint;
bool fIsOpaque;
+ bool fForceUpdate; //bitmap marked as dirty before each draw. forces bitmap to be updated on device cache
int fTileX, fTileY; // -1 means don't use shader
SkString fName;
- enum { N = 300 };
+ enum { N = SkBENCHLOOP(300) };
public:
BitmapBench(void* param, bool isOpaque, SkBitmap::Config c,
+ bool forceUpdate = false, bool bitmapVolatile = false,
int tx = -1, int ty = -1)
- : INHERITED(param), fIsOpaque(isOpaque), fTileX(tx), fTileY(ty) {
+ : INHERITED(param), fIsOpaque(isOpaque), fForceUpdate(forceUpdate), fTileX(tx), fTileY(ty) {
const int w = 128;
const int h = 128;
SkBitmap bm;
@@ -124,6 +133,7 @@ public:
fBitmap.getColorTable()->setIsOpaque(isOpaque);
}
fBitmap.setIsOpaque(isOpaque);
+ fBitmap.setIsVolatile(bitmapVolatile);
}
protected:
@@ -137,6 +147,11 @@ protected:
}
fName.appendf("_%s%s", gConfigName[fBitmap.config()],
fIsOpaque ? "" : "_A");
+ if (fForceUpdate)
+ fName.append("_update");
+ if (fBitmap.isVolatile())
+ fName.append("_volatile");
+
return fName.c_str();
}
@@ -154,6 +169,10 @@ protected:
for (int i = 0; i < N; i++) {
SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
+
+ if (fForceUpdate)
+ bitmap.notifyPixelsChanged();
+
canvas->drawBitmap(bitmap, x, y, &paint);
}
}
@@ -169,6 +188,8 @@ static SkBenchmark* Fact3(void* p) { return new BitmapBench(p, false, SkBitmap::
static SkBenchmark* Fact4(void* p) { return new BitmapBench(p, true, SkBitmap::kARGB_4444_Config); }
static SkBenchmark* Fact5(void* p) { return new BitmapBench(p, false, SkBitmap::kIndex8_Config); }
static SkBenchmark* Fact6(void* p) { return new BitmapBench(p, true, SkBitmap::kIndex8_Config); }
+static SkBenchmark* Fact7(void* p) { return new BitmapBench(p, true, SkBitmap::kARGB_8888_Config, true, true); }
+static SkBenchmark* Fact8(void* p) { return new BitmapBench(p, true, SkBitmap::kARGB_8888_Config, true, false); }
static BenchRegistry gReg0(Fact0);
static BenchRegistry gReg1(Fact1);
@@ -177,3 +198,5 @@ static BenchRegistry gReg3(Fact3);
static BenchRegistry gReg4(Fact4);
static BenchRegistry gReg5(Fact5);
static BenchRegistry gReg6(Fact6);
+static BenchRegistry gReg7(Fact7);
+static BenchRegistry gReg8(Fact8);
diff --git a/bench/BlurBench.cpp b/bench/BlurBench.cpp
new file mode 100644
index 0000000..de78fe1
--- /dev/null
+++ b/bench/BlurBench.cpp
@@ -0,0 +1,106 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkBenchmark.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+#include "SkShader.h"
+#include "SkString.h"
+#include "SkBlurMaskFilter.h"
+
+#define SMALL SkIntToScalar(2)
+#define REAL SkFloatToScalar(1.5f)
+#define BIG SkIntToScalar(10)
+
+static const char* gStyleName[] = {
+ "normal",
+ "solid",
+ "outer",
+ "inner"
+};
+
+class BlurBench : public SkBenchmark {
+ SkScalar fRadius;
+ SkBlurMaskFilter::BlurStyle fStyle;
+ SkString fName;
+
+public:
+ BlurBench(void* param, SkScalar rad, SkBlurMaskFilter::BlurStyle bs) : INHERITED(param) {
+ fRadius = rad;
+ fStyle = bs;
+ const char* name = rad > 0 ? gStyleName[bs] : "none";
+ if (SkScalarFraction(rad) != 0) {
+ fName.printf("blur_%.2f_%s", SkScalarToFloat(rad), name);
+ } else {
+ fName.printf("blur_%d_%s", SkScalarRound(rad), name);
+ }
+ }
+
+protected:
+ virtual const char* onGetName() {
+ return fName.c_str();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+ this->setupPaint(&paint);
+
+ paint.setAntiAlias(true);
+
+ SkRandom rand;
+ for (int i = 0; i < SkBENCHLOOP(10); i++) {
+ SkRect r = SkRect::MakeWH(rand.nextUScalar1() * 400,
+ rand.nextUScalar1() * 400);
+ r.offset(fRadius, fRadius);
+
+ if (fRadius > 0) {
+ SkMaskFilter* mf = SkBlurMaskFilter::Create(fRadius, fStyle, 0);
+ paint.setMaskFilter(mf)->unref();
+ }
+ canvas->drawOval(r, paint);
+ }
+ }
+
+private:
+ typedef SkBenchmark INHERITED;
+};
+
+static SkBenchmark* Fact00(void* p) { return new BlurBench(p, SMALL, SkBlurMaskFilter::kNormal_BlurStyle); }
+static SkBenchmark* Fact01(void* p) { return new BlurBench(p, SMALL, SkBlurMaskFilter::kSolid_BlurStyle); }
+static SkBenchmark* Fact02(void* p) { return new BlurBench(p, SMALL, SkBlurMaskFilter::kOuter_BlurStyle); }
+static SkBenchmark* Fact03(void* p) { return new BlurBench(p, SMALL, SkBlurMaskFilter::kInner_BlurStyle); }
+
+static SkBenchmark* Fact10(void* p) { return new BlurBench(p, BIG, SkBlurMaskFilter::kNormal_BlurStyle); }
+static SkBenchmark* Fact11(void* p) { return new BlurBench(p, BIG, SkBlurMaskFilter::kSolid_BlurStyle); }
+static SkBenchmark* Fact12(void* p) { return new BlurBench(p, BIG, SkBlurMaskFilter::kOuter_BlurStyle); }
+static SkBenchmark* Fact13(void* p) { return new BlurBench(p, BIG, SkBlurMaskFilter::kInner_BlurStyle); }
+
+static SkBenchmark* Fact20(void* p) { return new BlurBench(p, REAL, SkBlurMaskFilter::kNormal_BlurStyle); }
+static SkBenchmark* Fact21(void* p) { return new BlurBench(p, REAL, SkBlurMaskFilter::kSolid_BlurStyle); }
+static SkBenchmark* Fact22(void* p) { return new BlurBench(p, REAL, SkBlurMaskFilter::kOuter_BlurStyle); }
+static SkBenchmark* Fact23(void* p) { return new BlurBench(p, REAL, SkBlurMaskFilter::kInner_BlurStyle); }
+
+static SkBenchmark* FactNone(void* p) { return new BlurBench(p, 0, SkBlurMaskFilter::kNormal_BlurStyle); }
+
+static BenchRegistry gReg00(Fact00);
+static BenchRegistry gReg01(Fact01);
+static BenchRegistry gReg02(Fact02);
+static BenchRegistry gReg03(Fact03);
+
+static BenchRegistry gReg10(Fact10);
+static BenchRegistry gReg11(Fact11);
+static BenchRegistry gReg12(Fact12);
+static BenchRegistry gReg13(Fact13);
+
+static BenchRegistry gReg20(Fact20);
+static BenchRegistry gReg21(Fact21);
+static BenchRegistry gReg22(Fact22);
+static BenchRegistry gReg23(Fact23);
+
+static BenchRegistry gRegNone(FactNone);
+
diff --git a/bench/ChromeBench.cpp b/bench/ChromeBench.cpp
new file mode 100644
index 0000000..fc73d53
--- /dev/null
+++ b/bench/ChromeBench.cpp
@@ -0,0 +1,498 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkBenchmark.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkString.h"
+
+/**
+ Benchmarks that try to emulate a particular Skia call pattern observed in Chrome.
+*/
+
+/// blitRect() calls emitted by Chrome while scrolling through gmail: count, width, height.
+int gmailScrollingRectSpec [431*3] = {
+ 1, 1254, 1160,
+ 1, 64, 112,
+ 1, 1034, 261,
+ 1, 1166, 1,
+ 1, 1166, 20,
+ 1, 1254, 40,
+ 1, 140, 20,
+ 1, 22, 30,
+ 1, 22, 39,
+ 1, 294, 29,
+ 1, 336, 25,
+ 1, 336, 5,
+ 1, 37, 3,
+ 1, 37, 4,
+ 1, 37, 5,
+ 1, 41, 29,
+ 1, 57, 15,
+ 1, 72, 5,
+ 1, 72, 8,
+ 1, 76, 29,
+ 1, 981, 88,
+ 1, 990, 2,
+ 1, 990, 6,
+ 2, 220, 88,
+ 2, 294, 1,
+ 2, 37, 6,
+ 2, 391, 55,
+ 2, 57, 11,
+ 2, 57, 14,
+ 2, 57, 7,
+ 2, 981, 30,
+ 2, 990, 15,
+ 2, 990, 19,
+ 3, 114, 16,
+ 3, 1166, 39,
+ 3, 1254, 154,
+ 3, 12, 12,
+ 3, 162, 7,
+ 3, 164, 479,
+ 3, 167, 449,
+ 3, 16, 24,
+ 3, 204, 497,
+ 3, 205, 434,
+ 3, 220, 1127,
+ 3, 220, 1132,
+ 3, 220, 931,
+ 3, 220, 933,
+ 3, 220, 934,
+ 3, 297, 8,
+ 3, 72, 25,
+ 3, 87, 30,
+ 3, 981, 1,
+ 3, 981, 126,
+ 3, 990, 27,
+ 3, 990, 36,
+ 3, 991, 29,
+ 4, 1254, 306,
+ 4, 1254, 36,
+ 4, 1, 1,
+ 4, 1, 14,
+ 4, 1, 19,
+ 4, 1, 7,
+ 4, 21, 21,
+ 4, 220, 30,
+ 4, 46, 949,
+ 4, 509, 30,
+ 4, 57, 2,
+ 4, 57, 6,
+ 4, 990, 11,
+ 5, 13, 8,
+ 5, 198, 24,
+ 5, 24, 24,
+ 5, 25, 24,
+ 5, 2, 24,
+ 5, 37, 33,
+ 5, 57, 4,
+ 5, 599, 24,
+ 5, 90, 24,
+ 5, 981, 19,
+ 5, 990, 23,
+ 5, 990, 8,
+ 6, 101, 29,
+ 6, 117, 29,
+ 6, 1254, 88,
+ 6, 139, 29,
+ 6, 13, 12,
+ 6, 15, 15,
+ 6, 164, 25,
+ 6, 16, 16,
+ 6, 198, 7,
+ 6, 1, 12,
+ 6, 1, 15,
+ 6, 1, 27,
+ 6, 220, 936,
+ 6, 24, 7,
+ 6, 25, 7,
+ 6, 2, 7,
+ 6, 326, 29,
+ 6, 336, 29,
+ 6, 599, 7,
+ 6, 86, 29,
+ 6, 90, 7,
+ 6, 96, 29,
+ 6, 991, 31,
+ 7, 198, 12,
+ 7, 198, 20,
+ 7, 198, 33,
+ 7, 198, 35,
+ 7, 24, 12,
+ 7, 24, 20,
+ 7, 24, 33,
+ 7, 24, 35,
+ 7, 25, 12,
+ 7, 25, 20,
+ 7, 25, 33,
+ 7, 25, 35,
+ 7, 2, 12,
+ 7, 2, 20,
+ 7, 2, 33,
+ 7, 2, 35,
+ 7, 304, 1,
+ 7, 38, 29,
+ 7, 51, 29,
+ 7, 599, 12,
+ 7, 599, 20,
+ 7, 599, 33,
+ 7, 599, 35,
+ 7, 90, 12,
+ 7, 90, 20,
+ 7, 90, 33,
+ 7, 90, 35,
+ 8, 13, 5,
+ 8, 198, 13,
+ 8, 198, 23,
+ 8, 220, 1,
+ 8, 24, 13,
+ 8, 24, 23,
+ 8, 25, 13,
+ 8, 25, 23,
+ 8, 2, 13,
+ 8, 2, 23,
+ 8, 329, 28,
+ 8, 57, 10,
+ 8, 599, 13,
+ 8, 599, 23,
+ 8, 90, 13,
+ 8, 90, 23,
+ 9, 198, 17,
+ 9, 198, 19,
+ 9, 198, 37,
+ 9, 198, 5,
+ 9, 198, 8,
+ 9, 24, 17,
+ 9, 24, 19,
+ 9, 24, 37,
+ 9, 24, 5,
+ 9, 24, 8,
+ 9, 25, 17,
+ 9, 25, 19,
+ 9, 25, 37,
+ 9, 25, 5,
+ 9, 25, 8,
+ 9, 2, 17,
+ 9, 2, 19,
+ 9, 2, 37,
+ 9, 2, 5,
+ 9, 2, 8,
+ 9, 599, 17,
+ 9, 599, 19,
+ 9, 599, 37,
+ 9, 599, 5,
+ 9, 599, 8,
+ 9, 72, 29,
+ 9, 90, 17,
+ 9, 90, 19,
+ 9, 90, 37,
+ 9, 90, 5,
+ 9, 90, 8,
+ 10, 13, 11,
+ 10, 13, 9,
+ 10, 198, 26,
+ 10, 198, 28,
+ 10, 1, 23,
+ 10, 1, 4,
+ 10, 1, 6,
+ 10, 24, 26,
+ 10, 24, 28,
+ 10, 25, 26,
+ 10, 25, 28,
+ 10, 26, 24,
+ 10, 2, 26,
+ 10, 2, 28,
+ 10, 599, 26,
+ 10, 599, 28,
+ 10, 90, 26,
+ 10, 90, 28,
+ 11, 198, 27,
+ 11, 24, 27,
+ 11, 25, 27,
+ 11, 2, 27,
+ 11, 599, 27,
+ 11, 90, 27,
+ 12, 198, 14,
+ 12, 198, 21,
+ 12, 198, 3,
+ 12, 1, 11,
+ 12, 1, 2,
+ 12, 1, 8,
+ 12, 24, 14,
+ 12, 24, 21,
+ 12, 24, 3,
+ 12, 25, 14,
+ 12, 25, 21,
+ 12, 25, 3,
+ 12, 26, 7,
+ 12, 2, 14,
+ 12, 2, 21,
+ 12, 2, 3,
+ 12, 329, 14,
+ 12, 38, 2,
+ 12, 599, 14,
+ 12, 599, 21,
+ 12, 599, 3,
+ 12, 90, 14,
+ 12, 90, 21,
+ 12, 90, 3,
+ 13, 198, 11,
+ 13, 198, 15,
+ 13, 198, 31,
+ 13, 24, 11,
+ 13, 24, 15,
+ 13, 24, 31,
+ 13, 25, 11,
+ 13, 25, 15,
+ 13, 25, 31,
+ 13, 2, 11,
+ 13, 2, 15,
+ 13, 2, 31,
+ 13, 57, 13,
+ 13, 599, 11,
+ 13, 599, 15,
+ 13, 599, 31,
+ 13, 71, 29,
+ 13, 90, 11,
+ 13, 90, 15,
+ 13, 90, 31,
+ 14, 13, 2,
+ 14, 198, 10,
+ 14, 24, 10,
+ 14, 25, 10,
+ 14, 26, 12,
+ 14, 26, 20,
+ 14, 26, 33,
+ 14, 26, 35,
+ 14, 2, 10,
+ 14, 336, 1,
+ 14, 45, 29,
+ 14, 599, 10,
+ 14, 63, 29,
+ 14, 90, 10,
+ 15, 13, 3,
+ 15, 198, 2,
+ 15, 198, 29,
+ 15, 198, 34,
+ 15, 24, 2,
+ 15, 24, 29,
+ 15, 24, 34,
+ 15, 25, 2,
+ 15, 25, 29,
+ 15, 25, 34,
+ 15, 2, 2,
+ 15, 2, 29,
+ 15, 2, 34,
+ 15, 599, 2,
+ 15, 599, 29,
+ 15, 599, 34,
+ 15, 90, 2,
+ 15, 90, 29,
+ 15, 90, 34,
+ 16, 13, 4,
+ 16, 13, 6,
+ 16, 198, 16,
+ 16, 198, 9,
+ 16, 1, 10,
+ 16, 24, 16,
+ 16, 24, 9,
+ 16, 25, 16,
+ 16, 25, 9,
+ 16, 26, 13,
+ 16, 26, 23,
+ 16, 2, 16,
+ 16, 2, 9,
+ 16, 599, 16,
+ 16, 599, 9,
+ 16, 90, 16,
+ 16, 90, 9,
+ 17, 13, 7,
+ 17, 198, 18,
+ 17, 24, 18,
+ 17, 25, 18,
+ 17, 2, 18,
+ 17, 599, 18,
+ 17, 90, 18,
+ 18, 198, 22,
+ 18, 198, 32,
+ 18, 198, 36,
+ 18, 198, 4,
+ 18, 24, 22,
+ 18, 24, 32,
+ 18, 24, 36,
+ 18, 24, 4,
+ 18, 25, 22,
+ 18, 25, 32,
+ 18, 25, 36,
+ 18, 25, 4,
+ 18, 26, 17,
+ 18, 26, 19,
+ 18, 26, 37,
+ 18, 26, 5,
+ 18, 26, 8,
+ 18, 2, 22,
+ 18, 2, 32,
+ 18, 2, 36,
+ 18, 2, 4,
+ 18, 599, 22,
+ 18, 599, 32,
+ 18, 599, 36,
+ 18, 599, 4,
+ 18, 90, 22,
+ 18, 90, 32,
+ 18, 90, 36,
+ 18, 90, 4,
+ 19, 13, 10,
+ 20, 1254, 30,
+ 20, 16, 1007,
+ 20, 26, 26,
+ 20, 26, 28,
+ 21, 198, 6,
+ 21, 24, 6,
+ 21, 25, 6,
+ 21, 2, 6,
+ 21, 599, 6,
+ 21, 90, 6,
+ 22, 198, 38,
+ 22, 22, 40,
+ 22, 24, 38,
+ 22, 25, 38,
+ 22, 26, 27,
+ 22, 2, 38,
+ 22, 599, 38,
+ 22, 90, 38,
+ 23, 1254, 1160,
+ 24, 220, 930,
+ 24, 26, 14,
+ 24, 26, 21,
+ 24, 26, 3,
+ 26, 11, 11,
+ 26, 1, 13,
+ 26, 26, 11,
+ 26, 26, 15,
+ 26, 26, 31,
+ 28, 26, 10,
+ 30, 176, 60,
+ 30, 26, 2,
+ 30, 26, 29,
+ 30, 26, 34,
+ 32, 26, 16,
+ 32, 26, 9,
+ 34, 26, 18,
+ 36, 26, 22,
+ 36, 26, 32,
+ 36, 26, 36,
+ 36, 26, 4,
+ 36, 37, 26,
+ 42, 26, 6,
+ 43, 115, 29,
+ 44, 198, 25,
+ 44, 24, 25,
+ 44, 25, 25,
+ 44, 26, 38,
+ 44, 2, 25,
+ 44, 599, 25,
+ 44, 90, 25,
+ 46, 22, 1,
+ 47, 198, 30,
+ 47, 25, 30,
+ 47, 2, 30,
+ 47, 599, 30,
+ 47, 90, 30,
+ 48, 24, 30,
+ 52, 176, 30,
+ 58, 140, 24,
+ 58, 4, 30,
+ 63, 990, 29,
+ 64, 1254, 1,
+ 88, 26, 25,
+ 92, 198, 39,
+ 92, 25, 39,
+ 92, 2, 39,
+ 92, 599, 39,
+ 92, 90, 39,
+ 93, 24, 39,
+ 94, 26, 30,
+ 108, 1254, 1051,
+ 117, 140, 1,
+ 119, 160, 1,
+ 126, 1, 29,
+ 132, 135, 16,
+ 147, 72, 16,
+ 184, 26, 39,
+ 238, 990, 1,
+ 376, 11, 1007,
+ 380, 11, 487,
+ 1389, 1034, 1007,
+ 1870, 57, 16,
+ 4034, 1, 16,
+ 8521, 198, 40,
+ 8521, 25, 40,
+ 8521, 2, 40,
+ 8521, 599, 40,
+ 8521, 90, 40,
+ 8543, 24, 40,
+ 8883, 13, 13,
+ 17042, 26, 40,
+ 17664, 198, 1,
+ 17664, 25, 1,
+ 17664, 2, 1,
+ 17664, 599, 1,
+ 17664, 90, 1,
+ 17710, 24, 1,
+ 35328, 26, 1,
+};
+
+/// Emulates the mix of rects blitted by gmail during scrolling
+class ScrollGmailBench : public SkBenchmark {
+ enum {
+ W = 1254,
+ H = 1160,
+ N = 431
+ };
+public:
+ ScrollGmailBench(void* param) : INHERITED(param) { }
+
+protected:
+
+ virtual const char* onGetName() { return "chrome_scrollGmail"; }
+ virtual void onDraw(SkCanvas* canvas) {
+ SkDEBUGCODE(this->validateBounds(canvas));
+ SkPaint paint;
+ this->setupPaint(&paint);
+ for (int i = 0; i < N; i++) {
+ SkRect current;
+ setRectangle(current, i);
+ for (int j = 0; j < SkBENCHLOOP(gmailScrollingRectSpec[i*3]); j++) {
+ canvas->drawRect(current, paint);
+ }
+ }
+ }
+ virtual SkIPoint onGetSize() { return SkIPoint::Make(W, H); }
+
+ void setRectangle(SkRect& current, int i) {
+ current.set(0, 0,
+ SkIntToScalar(gmailScrollingRectSpec[i*3+1]), SkIntToScalar(gmailScrollingRectSpec[i*3+2]));
+ }
+ void validateBounds(SkCanvas* canvas) {
+ SkIRect bounds;
+ canvas->getClipDeviceBounds(&bounds);
+ SkASSERT(bounds.right()-bounds.left() >= W);
+ SkASSERT(bounds.bottom()-bounds.top() >= H);
+ }
+
+
+private:
+ typedef SkBenchmark INHERITED;
+};
+
+static SkBenchmark* ScrollGmailFactory(void* p) {
+ return SkNEW_ARGS(ScrollGmailBench, (p));
+}
+
+static BenchRegistry gScrollGmailReg(ScrollGmailFactory);
diff --git a/bench/DecodeBench.cpp b/bench/DecodeBench.cpp
index ac11089..6761690 100644
--- a/bench/DecodeBench.cpp
+++ b/bench/DecodeBench.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkBitmap.h"
#include "SkImageDecoder.h"
@@ -11,7 +18,7 @@ class DecodeBench : public SkBenchmark {
const char* fFilename;
SkBitmap::Config fPrefConfig;
SkString fName;
- enum { N = 10 };
+ enum { N = SkBENCHLOOP(10) };
public:
DecodeBench(void* param, SkBitmap::Config c) : SkBenchmark(param) {
fFilename = this->findDefine("decode-filename");
diff --git a/bench/FPSBench.cpp b/bench/FPSBench.cpp
deleted file mode 100644
index 28668fe..0000000
--- a/bench/FPSBench.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-#include "SkBenchmark.h"
-#include "SkCanvas.h"
-#include "SkPaint.h"
-#include "SkRandom.h"
-#include "SkString.h"
-
-class FPSBench : public SkBenchmark {
- int32_t fWidth;
- int32_t fHeight;
-public:
- FPSBench(void* p) : INHERITED(p) {
- fWidth = 640;
- (void)this->findDefine32("width", &fWidth);
- fHeight = 480;
- (void)this->findDefine32("height", &fHeight);
- }
-
- int width() const { return fWidth; }
- int height() const { return fHeight; }
-
-protected:
- virtual SkIPoint onGetSize() { return SkIPoint::Make(fWidth, fHeight); }
-
-private:
- typedef SkBenchmark INHERITED;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-class Color_FPSBench : public FPSBench {
-public:
- Color_FPSBench(void* p, SkColor c, const char name[]) : INHERITED(p) {
- fColor = c;
- fName = name;
- }
-
-protected:
- virtual const char* onGetName() { return fName; }
- virtual void onDraw(SkCanvas* canvas) {
- canvas->drawColor(fColor);
- }
-
-private:
- const char* fName;
- SkColor fColor;
-
- typedef FPSBench INHERITED;
-};
-
-class Bitmap_FPSBench : public FPSBench {
-public:
- Bitmap_FPSBench(void* p, SkBitmap::Config config, bool doOpaque, bool doScale) : INHERITED(p) {
- fBitmap.setConfig(config, this->width(), this->height());
- fBitmap.allocPixels();
- fBitmap.eraseColor(0xFFFF0000);
- if (doOpaque) {
- fBitmap.setIsOpaque(true);
- }
-
- const char* configStr = "565";
- if (config == SkBitmap::kARGB_8888_Config) {
- if (doOpaque) {
- configStr = "X888";
- } else {
- configStr = "8888";
- }
- }
- fName.printf("fps_bitmap_%s_%s", configStr,
- doScale ? "scale" : "noscale");
-
- fMatrix.reset();
- if (doScale) {
- fMatrix.setScale(SkIntToScalar(3)/2, SkIntToScalar(3)/2);
- }
- }
-
-protected:
- virtual const char* onGetName() { return fName.c_str(); }
- virtual void onDraw(SkCanvas* canvas) {
- canvas->drawBitmapMatrix(fBitmap, fMatrix);
- }
-
-private:
- SkBitmap fBitmap;
- SkMatrix fMatrix;
- SkString fName;
-
- typedef FPSBench INHERITED;
-};
-
-static SkBenchmark* FillFactory(void* p) { return SkNEW_ARGS(Color_FPSBench, (p, 0xFFFF0000, "fps_fill")); }
-static SkBenchmark* BlendFactory(void* p) { return SkNEW_ARGS(Color_FPSBench, (p, 0x80FF0000, "fps_blend")); }
-static SkBenchmark* BMFactory0(void* p) { return SkNEW_ARGS(Bitmap_FPSBench, (p, SkBitmap::kARGB_8888_Config, false, false)); }
-static SkBenchmark* BMFactory1(void* p) { return SkNEW_ARGS(Bitmap_FPSBench, (p, SkBitmap::kARGB_8888_Config, false, true)); }
-static SkBenchmark* BMFactory2(void* p) { return SkNEW_ARGS(Bitmap_FPSBench, (p, SkBitmap::kARGB_8888_Config, true, false)); }
-static SkBenchmark* BMFactory3(void* p) { return SkNEW_ARGS(Bitmap_FPSBench, (p, SkBitmap::kARGB_8888_Config, true, true)); }
-static SkBenchmark* BMFactory4(void* p) { return SkNEW_ARGS(Bitmap_FPSBench, (p, SkBitmap::kRGB_565_Config, false, false)); }
-static SkBenchmark* BMFactory5(void* p) { return SkNEW_ARGS(Bitmap_FPSBench, (p, SkBitmap::kRGB_565_Config, false, true)); }
-
-static BenchRegistry gFillReg(FillFactory);
-static BenchRegistry gBlendReg(BlendFactory);
-static BenchRegistry gBMReg0(BMFactory0);
-static BenchRegistry gBMReg1(BMFactory1);
-static BenchRegistry gBMReg2(BMFactory2);
-static BenchRegistry gBMReg3(BMFactory3);
-static BenchRegistry gBMReg4(BMFactory4);
-static BenchRegistry gBMReg5(BMFactory5);
-
diff --git a/bench/FontScalerBench.cpp b/bench/FontScalerBench.cpp
new file mode 100644
index 0000000..4ac6a35
--- /dev/null
+++ b/bench/FontScalerBench.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBenchmark.h"
+#include "SkCanvas.h"
+#include "SkGraphics.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+#include "SkString.h"
+
+extern bool gSkSuppressFontCachePurgeSpew;
+
+class FontScalerBench : public SkBenchmark {
+ SkString fName;
+ SkString fText;
+ bool fDoLCD;
+public:
+ FontScalerBench(void* param, bool doLCD) : INHERITED(param) {
+ fName.printf("fontscaler_%s", doLCD ? "lcd" : "aa");
+ fText.set("abcdefghijklmnopqrstuvwxyz01234567890");
+ fDoLCD = doLCD;
+ }
+
+protected:
+ virtual const char* onGetName() { return fName.c_str(); }
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+ this->setupPaint(&paint);
+ paint.setLCDRenderText(fDoLCD);
+
+ bool prev = gSkSuppressFontCachePurgeSpew;
+ gSkSuppressFontCachePurgeSpew = true;
+
+ // this is critical - we want to time the creation process, so we
+ // explicitly flush our cache before each run
+ SkGraphics::PurgeFontCache();
+
+ for (int ps = 9; ps <= 24; ps += 2) {
+ paint.setTextSize(SkIntToScalar(ps));
+ canvas->drawText(fText.c_str(), fText.size(),
+ 0, SkIntToScalar(20), paint);
+ }
+
+ gSkSuppressFontCachePurgeSpew = prev;
+ }
+private:
+ typedef SkBenchmark INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkBenchmark* Fact0(void* p) { return SkNEW_ARGS(FontScalerBench, (p, false)); }
+static SkBenchmark* Fact1(void* p) { return SkNEW_ARGS(FontScalerBench, (p, true)); }
+
+static BenchRegistry gReg0(Fact0);
+static BenchRegistry gReg1(Fact1);
diff --git a/bench/GradientBench.cpp b/bench/GradientBench.cpp
index 5ecca6b..a5032ea 100644
--- a/bench/GradientBench.cpp
+++ b/bench/GradientBench.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
@@ -31,23 +38,29 @@ static const GradData gGradData[] = {
{ 5, gColors, gPos2 }
};
+/// Ignores scale
static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
- SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkShader::TileMode tm, SkUnitMapper* mapper,
+ float scale) {
return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
data.fCount, tm, mapper);
}
static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
- SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkShader::TileMode tm, SkUnitMapper* mapper,
+ float scale) {
SkPoint center;
center.set(SkScalarAve(pts[0].fX, pts[1].fX),
SkScalarAve(pts[0].fY, pts[1].fY));
- return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
+ return SkGradientShader::CreateRadial(center, center.fX * scale,
+ data.fColors,
data.fPos, data.fCount, tm, mapper);
}
+/// Ignores scale
static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
- SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkShader::TileMode tm, SkUnitMapper* mapper,
+ float scale) {
SkPoint center;
center.set(SkScalarAve(pts[0].fX, pts[1].fX),
SkScalarAve(pts[0].fY, pts[1].fY));
@@ -55,21 +68,24 @@ static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
data.fPos, data.fCount, mapper);
}
+/// Ignores scale
static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
- SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkShader::TileMode tm, SkUnitMapper* mapper,
+ float scale) {
SkPoint center0, center1;
center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
SkScalarAve(pts[0].fY, pts[1].fY));
center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
return SkGradientShader::CreateTwoPointRadial(
- center1, (pts[1].fX - pts[0].fX) / 7,
- center0, (pts[1].fX - pts[0].fX) / 2,
- data.fColors, data.fPos, data.fCount, tm, mapper);
+ center1, (pts[1].fX - pts[0].fX) / 7,
+ center0, (pts[1].fX - pts[0].fX) / 2,
+ data.fColors, data.fPos, data.fCount, tm, mapper);
}
typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
- SkShader::TileMode tm, SkUnitMapper* mapper);
+ SkShader::TileMode tm, SkUnitMapper* mapper,
+ float scale);
static const struct {
GradMaker fMaker;
@@ -89,6 +105,37 @@ enum GradType { // these must match the order in gGrads
kRadial2_GradType
};
+enum GeomType {
+ kRect_GeomType,
+ kOval_GeomType
+};
+
+static const char* tilemodename(SkShader::TileMode tm) {
+ switch (tm) {
+ case SkShader::kClamp_TileMode:
+ return "clamp";
+ case SkShader::kRepeat_TileMode:
+ return "repeat";
+ case SkShader::kMirror_TileMode:
+ return "mirror";
+ default:
+ SkASSERT(!"unknown tilemode");
+ return "error";
+ }
+}
+
+static const char* geomtypename(GeomType gt) {
+ switch (gt) {
+ case kRect_GeomType:
+ return "rectangle";
+ case kOval_GeomType:
+ return "oval";
+ default:
+ SkASSERT(!"unknown geometry type");
+ return "error";
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
class GradientBench : public SkBenchmark {
@@ -101,17 +148,26 @@ class GradientBench : public SkBenchmark {
N = 1
};
public:
- GradientBench(void* param, GradType gt) : INHERITED(param) {
- fName.printf("gradient_%s", gGrads[gt].fName);
+ GradientBench(void* param, GradType gradType,
+ SkShader::TileMode tm = SkShader::kClamp_TileMode,
+ GeomType geomType = kRect_GeomType,
+ float scale = 1.0f)
+ : INHERITED(param) {
+ fName.printf("gradient_%s_%s", gGrads[gradType].fName,
+ tilemodename(tm));
+ if (geomType != kRect_GeomType) {
+ fName.append("_");
+ fName.append(geomtypename(geomType));
+ }
const SkPoint pts[2] = {
{ 0, 0 },
{ SkIntToScalar(W), SkIntToScalar(H) }
};
- fCount = N * gGrads[gt].fRepeat;
- fShader = gGrads[gt].fMaker(pts, gGradData[0],
- SkShader::kClamp_TileMode, NULL);
+ fCount = SkBENCHLOOP(N * gGrads[gradType].fRepeat);
+ fShader = gGrads[gradType].fMaker(pts, gGradData[0], tm, NULL, scale);
+ fGeomType = geomType;
}
virtual ~GradientBench() {
@@ -131,21 +187,86 @@ protected:
SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) };
for (int i = 0; i < fCount; i++) {
- canvas->drawRect(r, paint);
+ switch (fGeomType) {
+ case kRect_GeomType:
+ canvas->drawRect(r, paint);
+ break;
+ case kOval_GeomType:
+ canvas->drawOval(r, paint);
+ break;
+ }
}
}
private:
typedef SkBenchmark INHERITED;
+
+ GeomType fGeomType;
+};
+
+class Gradient2Bench : public SkBenchmark {
+public:
+ Gradient2Bench(void* param) : INHERITED(param) {}
+
+protected:
+ virtual const char* onGetName() {
+ return "gradient_create";
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+ this->setupPaint(&paint);
+
+ const SkRect r = { 0, 0, SkIntToScalar(4), SkIntToScalar(4) };
+ const SkPoint pts[] = {
+ { 0, 0 },
+ { SkIntToScalar(100), SkIntToScalar(100) },
+ };
+
+ for (int i = 0; i < SkBENCHLOOP(1000); i++) {
+ const int a = i % 256;
+ SkColor colors[] = {
+ SK_ColorBLACK,
+ SkColorSetARGB(a, a, a, a),
+ SK_ColorWHITE };
+ SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL,
+ SK_ARRAY_COUNT(colors),
+ SkShader::kClamp_TileMode);
+ paint.setShader(s)->unref();
+ canvas->drawRect(r, paint);
+ }
+ }
+
+private:
+ typedef SkBenchmark INHERITED;
};
static SkBenchmark* Fact0(void* p) { return new GradientBench(p, kLinear_GradType); }
-static SkBenchmark* Fact1(void* p) { return new GradientBench(p, kRadial_GradType); }
+static SkBenchmark* Fact01(void* p) { return new GradientBench(p, kLinear_GradType, SkShader::kMirror_TileMode); }
+
+// Draw a radial gradient of radius 1/2 on a rectangle; half the lines should
+// be completely pinned, the other half should pe partially pinned
+static SkBenchmark* Fact1(void* p) { return new GradientBench(p, kRadial_GradType, SkShader::kClamp_TileMode, kRect_GeomType, 0.5f); }
+
+// Draw a radial gradient on a circle of equal size; all the lines should
+// hit the unpinned fast path (so long as GradientBench.W == H)
+static SkBenchmark* Fact1o(void* p) { return new GradientBench(p, kRadial_GradType, SkShader::kClamp_TileMode, kOval_GeomType); }
+
+static SkBenchmark* Fact11(void* p) { return new GradientBench(p, kRadial_GradType, SkShader::kMirror_TileMode); }
static SkBenchmark* Fact2(void* p) { return new GradientBench(p, kSweep_GradType); }
static SkBenchmark* Fact3(void* p) { return new GradientBench(p, kRadial2_GradType); }
+static SkBenchmark* Fact31(void* p) { return new GradientBench(p, kRadial2_GradType, SkShader::kMirror_TileMode); }
+
+static SkBenchmark* Fact4(void* p) { return new Gradient2Bench(p); }
static BenchRegistry gReg0(Fact0);
+static BenchRegistry gReg01(Fact01);
static BenchRegistry gReg1(Fact1);
+static BenchRegistry gReg1o(Fact1o);
+static BenchRegistry gReg11(Fact11);
static BenchRegistry gReg2(Fact2);
static BenchRegistry gReg3(Fact3);
+static BenchRegistry gReg31(Fact31);
+
+static BenchRegistry gReg4(Fact4);
diff --git a/bench/Makefile.am b/bench/Makefile.am
deleted file mode 100644
index 2b67862..0000000
--- a/bench/Makefile.am
+++ /dev/null
@@ -1,20 +0,0 @@
-AM_CPPFLAGS = -I$(top_builddir)/include/core -I$(top_builddir)/include/images
-AM_LDFLAGS = -lpng -lpthread
-
-bin_PROGRAMS = Bench
-Bench_SOURCES = RectBench.cpp \
- FPSBench.cpp \
- SkBenchmark.cpp \
- BenchTool/main.cpp \
- $(top_builddir)/src/images/SkImageDecoder.cpp \
- $(top_builddir)/src/images/SkImageDecoder_libpng.cpp \
- $(top_builddir)/src/images/SkScaledBitmapSampler.cpp \
- $(top_builddir)/src/ports/SkGlobals_global.cpp \
- $(top_builddir)/src/ports/SkOSFile_stdio.cpp \
- $(top_builddir)/src/ports/SkThread_pthread.cpp \
- $(top_builddir)/src/ports/SkTime_Unix.cpp \
- $(top_builddir)/src/ports/SkFontHost_none.cpp
-
-
-Bench_LDADD = $(top_builddir)/src/core/libskia.a
-
diff --git a/bench/MathBench.cpp b/bench/MathBench.cpp
new file mode 100644
index 0000000..9feb5af
--- /dev/null
+++ b/bench/MathBench.cpp
@@ -0,0 +1,316 @@
+#include "SkBenchmark.h"
+#include "SkColorPriv.h"
+#include "SkMatrix.h"
+#include "SkRandom.h"
+#include "SkString.h"
+#include "SkPaint.h"
+
+class MathBench : public SkBenchmark {
+ enum {
+ kBuffer = 100,
+ kLoop = 10000
+ };
+ SkString fName;
+ float fSrc[kBuffer], fDst[kBuffer];
+public:
+ MathBench(void* param, const char name[]) : INHERITED(param) {
+ fName.printf("math_%s", name);
+
+ SkRandom rand;
+ for (int i = 0; i < kBuffer; ++i) {
+ fSrc[i] = rand.nextSScalar1();
+ }
+ }
+
+ virtual void performTest(float dst[], const float src[], int count) = 0;
+
+protected:
+ virtual int mulLoopCount() const { return 1; }
+
+ virtual const char* onGetName() {
+ return fName.c_str();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ int n = SkBENCHLOOP(kLoop * this->mulLoopCount());
+ for (int i = 0; i < n; i++) {
+ this->performTest(fDst, fSrc, kBuffer);
+ }
+ }
+
+private:
+ typedef SkBenchmark INHERITED;
+};
+
+class MathBenchU32 : public MathBench {
+public:
+ MathBenchU32(void* param, const char name[]) : INHERITED(param, name) {}
+
+protected:
+ virtual void performITest(uint32_t* dst, const uint32_t* src, int count) = 0;
+
+ virtual void performTest(float* SK_RESTRICT dst, const float* SK_RESTRICT src,
+ int count) SK_OVERRIDE {
+ uint32_t* d = SkTCast<uint32_t*>(dst);
+ const uint32_t* s = SkTCast<const uint32_t*>(src);
+ this->performITest(d, s, count);
+ }
+private:
+ typedef MathBench INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class NoOpMathBench : public MathBench {
+public:
+ NoOpMathBench(void* param) : INHERITED(param, "noOp") {}
+protected:
+ virtual void performTest(float dst[], const float src[], int count) {
+ for (int i = 0; i < count; ++i) {
+ dst[i] = src[i] + 1;
+ }
+ }
+private:
+ typedef MathBench INHERITED;
+};
+
+class SlowISqrtMathBench : public MathBench {
+public:
+ SlowISqrtMathBench(void* param) : INHERITED(param, "slowIsqrt") {}
+protected:
+ virtual void performTest(float dst[], const float src[], int count) {
+ for (int i = 0; i < count; ++i) {
+ dst[i] = 1.0f / sk_float_sqrt(src[i]);
+ }
+ }
+private:
+ typedef MathBench INHERITED;
+};
+
+static inline float SkFastInvSqrt(float x) {
+ float xhalf = 0.5f*x;
+ int i = *(int*)&x;
+ i = 0x5f3759df - (i>>1);
+ x = *(float*)&i;
+ x = x*(1.5f-xhalf*x*x);
+// x = x*(1.5f-xhalf*x*x); // this line takes err from 10^-3 to 10^-6
+ return x;
+}
+
+class FastISqrtMathBench : public MathBench {
+public:
+ FastISqrtMathBench(void* param) : INHERITED(param, "fastIsqrt") {}
+protected:
+ virtual void performTest(float dst[], const float src[], int count) {
+ for (int i = 0; i < count; ++i) {
+ dst[i] = SkFastInvSqrt(src[i]);
+ }
+ }
+private:
+ typedef MathBench INHERITED;
+};
+
+static inline uint32_t QMul64(uint32_t value, U8CPU alpha) {
+ SkASSERT((uint8_t)alpha == alpha);
+ const uint32_t mask = 0xFF00FF;
+
+ uint64_t tmp = value;
+ tmp = (tmp & mask) | ((tmp & ~mask) << 24);
+ tmp *= alpha;
+ return ((tmp >> 8) & mask) | ((tmp >> 32) & ~mask);
+}
+
+class QMul64Bench : public MathBenchU32 {
+public:
+ QMul64Bench(void* param) : INHERITED(param, "qmul64") {}
+protected:
+ virtual void performITest(uint32_t* SK_RESTRICT dst,
+ const uint32_t* SK_RESTRICT src,
+ int count) SK_OVERRIDE {
+ for (int i = 0; i < count; ++i) {
+ dst[i] = QMul64(src[i], (uint8_t)i);
+ }
+ }
+private:
+ typedef MathBenchU32 INHERITED;
+};
+
+class QMul32Bench : public MathBenchU32 {
+public:
+ QMul32Bench(void* param) : INHERITED(param, "qmul32") {}
+protected:
+ virtual void performITest(uint32_t* SK_RESTRICT dst,
+ const uint32_t* SK_RESTRICT src,
+ int count) SK_OVERRIDE {
+ for (int i = 0; i < count; ++i) {
+ dst[i] = SkAlphaMulQ(src[i], (uint8_t)i);
+ }
+ }
+private:
+ typedef MathBenchU32 INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static bool isFinite_int(float x) {
+ uint32_t bits = SkFloat2Bits(x); // need unsigned for our shifts
+ int exponent = bits << 1 >> 24;
+ return exponent != 0xFF;
+}
+
+static bool isFinite_float(float x) {
+ return sk_float_isfinite(x);
+}
+
+static bool isFinite_mulzero(float x) {
+ float y = x * 0;
+ return y == y;
+}
+
+static bool isfinite_and_int(const float data[4]) {
+ return isFinite_int(data[0]) && isFinite_int(data[1]) && isFinite_int(data[2]) && isFinite_int(data[3]);
+}
+
+static bool isfinite_and_float(const float data[4]) {
+ return isFinite_float(data[0]) && isFinite_float(data[1]) && isFinite_float(data[2]) && isFinite_float(data[3]);
+}
+
+static bool isfinite_and_mulzero(const float data[4]) {
+ return isFinite_mulzero(data[0]) && isFinite_mulzero(data[1]) && isFinite_mulzero(data[2]) && isFinite_mulzero(data[3]);
+}
+
+#define mulzeroadd(data) (data[0]*0 + data[1]*0 + data[2]*0 + data[3]*0)
+
+static bool isfinite_plus_int(const float data[4]) {
+ return isFinite_int(mulzeroadd(data));
+}
+
+static bool isfinite_plus_float(const float data[4]) {
+ return !sk_float_isnan(mulzeroadd(data));
+}
+
+static bool isfinite_plus_mulzero(const float data[4]) {
+ float x = mulzeroadd(data);
+ return x == x;
+}
+
+typedef bool (*IsFiniteProc)(const float[]);
+
+#define MAKEREC(name) { name, #name }
+
+static const struct {
+ IsFiniteProc fProc;
+ const char* fName;
+} gRec[] = {
+ MAKEREC(isfinite_and_int),
+ MAKEREC(isfinite_and_float),
+ MAKEREC(isfinite_and_mulzero),
+ MAKEREC(isfinite_plus_int),
+ MAKEREC(isfinite_plus_float),
+ MAKEREC(isfinite_plus_mulzero),
+};
+
+#undef MAKEREC
+
+static bool isFinite(const SkRect& r) {
+ // x * 0 will be NaN iff x is infinity or NaN.
+ // a + b will be NaN iff either a or b is NaN.
+ float value = r.fLeft * 0 + r.fTop * 0 + r.fRight * 0 + r.fBottom * 0;
+
+ // value is either NaN or it is finite (zero).
+ // value==value will be true iff value is not NaN
+ return value == value;
+}
+
+class IsFiniteBench : public SkBenchmark {
+ enum {
+ N = SkBENCHLOOP(1000),
+ NN = SkBENCHLOOP(1000),
+ };
+ float fData[N];
+public:
+
+ IsFiniteBench(void* param, int index) : INHERITED(param) {
+ SkRandom rand;
+
+ for (int i = 0; i < N; ++i) {
+ fData[i] = rand.nextSScalar1();
+ }
+
+ if (index < 0) {
+ fProc = NULL;
+ fName = "isfinite_rect";
+ } else {
+ fProc = gRec[index].fProc;
+ fName = gRec[index].fName;
+ }
+ }
+
+protected:
+ virtual void onDraw(SkCanvas* canvas) {
+ IsFiniteProc proc = fProc;
+ const float* data = fData;
+ // do this so the compiler won't throw away the function call
+ int counter = 0;
+
+ if (proc) {
+ for (int j = 0; j < NN; ++j) {
+ for (int i = 0; i < N - 4; ++i) {
+ counter += proc(&data[i]);
+ }
+ }
+ } else {
+ for (int j = 0; j < NN; ++j) {
+ for (int i = 0; i < N - 4; ++i) {
+ const SkRect* r = reinterpret_cast<const SkRect*>(&data[i]);
+ counter += r->isFinite();
+ }
+ }
+ }
+
+ SkPaint paint;
+ if (paint.getAlpha() == 0) {
+ SkDebugf("%d\n", counter);
+ }
+ }
+
+ virtual const char* onGetName() {
+ return fName;
+ }
+
+private:
+ IsFiniteProc fProc;
+ const char* fName;
+
+ typedef SkBenchmark INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkBenchmark* M0(void* p) { return new NoOpMathBench(p); }
+static SkBenchmark* M1(void* p) { return new SlowISqrtMathBench(p); }
+static SkBenchmark* M2(void* p) { return new FastISqrtMathBench(p); }
+static SkBenchmark* M3(void* p) { return new QMul64Bench(p); }
+static SkBenchmark* M4(void* p) { return new QMul32Bench(p); }
+
+static SkBenchmark* M5neg1(void* p) { return new IsFiniteBench(p, -1); }
+static SkBenchmark* M50(void* p) { return new IsFiniteBench(p, 0); }
+static SkBenchmark* M51(void* p) { return new IsFiniteBench(p, 1); }
+static SkBenchmark* M52(void* p) { return new IsFiniteBench(p, 2); }
+static SkBenchmark* M53(void* p) { return new IsFiniteBench(p, 3); }
+static SkBenchmark* M54(void* p) { return new IsFiniteBench(p, 4); }
+static SkBenchmark* M55(void* p) { return new IsFiniteBench(p, 5); }
+
+static BenchRegistry gReg0(M0);
+static BenchRegistry gReg1(M1);
+static BenchRegistry gReg2(M2);
+static BenchRegistry gReg3(M3);
+static BenchRegistry gReg4(M4);
+
+static BenchRegistry gReg5neg1(M5neg1);
+static BenchRegistry gReg50(M50);
+static BenchRegistry gReg51(M51);
+static BenchRegistry gReg52(M52);
+static BenchRegistry gReg53(M53);
+static BenchRegistry gReg54(M54);
+static BenchRegistry gReg55(M55);
diff --git a/bench/MatrixBench.cpp b/bench/MatrixBench.cpp
index dce0358..a2e459a 100644
--- a/bench/MatrixBench.cpp
+++ b/bench/MatrixBench.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkMatrix.h"
#include "SkRandom.h"
@@ -21,7 +28,7 @@ protected:
}
virtual void onDraw(SkCanvas* canvas) {
- int n = N * this->mulLoopCount();
+ int n = SkBENCHLOOP(N * this->mulLoopCount());
for (int i = 0; i < n; i++) {
this->performTest();
}
@@ -56,9 +63,6 @@ protected:
always_do(m0 == m1);
always_do(m1 == m2);
always_do(m2 == m0);
- always_do(m0.getType());
- always_do(m1.getType());
- always_do(m2.getType());
}
private:
typedef MatrixBench INHERITED;
@@ -214,26 +218,71 @@ private:
typedef MatrixBench INHERITED;
};
+class GetTypeMatrixBench : public MatrixBench {
+public:
+ GetTypeMatrixBench(void* param)
+ : INHERITED(param, "gettype") {
+ fArray[0] = (float) fRnd.nextS();
+ fArray[1] = (float) fRnd.nextS();
+ fArray[2] = (float) fRnd.nextS();
+ fArray[3] = (float) fRnd.nextS();
+ fArray[4] = (float) fRnd.nextS();
+ fArray[5] = (float) fRnd.nextS();
+ fArray[6] = (float) fRnd.nextS();
+ fArray[7] = (float) fRnd.nextS();
+ fArray[8] = (float) fRnd.nextS();
+ }
+protected:
+ // Putting random generation of the matrix inside performTest()
+ // would help us avoid anomalous runs, but takes up 25% or
+ // more of the function time.
+ virtual void performTest() {
+ fMatrix.setAll(fArray[0], fArray[1], fArray[2],
+ fArray[3], fArray[4], fArray[5],
+ fArray[6], fArray[7], fArray[8]);
+ always_do(fMatrix.getType());
+ fMatrix.dirtyMatrixTypeCache();
+ always_do(fMatrix.getType());
+ fMatrix.dirtyMatrixTypeCache();
+ always_do(fMatrix.getType());
+ fMatrix.dirtyMatrixTypeCache();
+ always_do(fMatrix.getType());
+ fMatrix.dirtyMatrixTypeCache();
+ always_do(fMatrix.getType());
+ fMatrix.dirtyMatrixTypeCache();
+ always_do(fMatrix.getType());
+ fMatrix.dirtyMatrixTypeCache();
+ always_do(fMatrix.getType());
+ fMatrix.dirtyMatrixTypeCache();
+ always_do(fMatrix.getType());
+ }
+private:
+ SkMatrix fMatrix;
+ float fArray[9];
+ SkRandom fRnd;
+ typedef MatrixBench INHERITED;
+};
+
#ifdef SK_SCALAR_IS_FLOAT
class ScaleTransMixedMatrixBench : public MatrixBench {
public:
ScaleTransMixedMatrixBench(void* p) : INHERITED(p, "scaletrans_mixed"), fCount (16) {
- fMatrix.setAll(fRandom.nextS(), fRandom.nextS(), fRandom.nextS(),
- fRandom.nextS(), fRandom.nextS(), fRandom.nextS(),
- fRandom.nextS(), fRandom.nextS(), fRandom.nextS());
+ fMatrix.setAll(fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1(),
+ fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1(),
+ fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1());
int i;
- for (i = 0; i < fCount; i++) {
- fSrc[i].fX = fRandom.nextS();
- fSrc[i].fY = fRandom.nextS();
- fDst[i].fX = fRandom.nextS();
- fDst[i].fY = fRandom.nextS();
+ for (i = 0; i < SkBENCHLOOP(fCount); i++) {
+ fSrc[i].fX = fRandom.nextSScalar1();
+ fSrc[i].fY = fRandom.nextSScalar1();
+ fDst[i].fX = fRandom.nextSScalar1();
+ fDst[i].fY = fRandom.nextSScalar1();
}
}
protected:
virtual void performTest() {
SkPoint* dst = fDst;
const SkPoint* src = fSrc;
- int count = fCount;
+ int count = SkBENCHLOOP(fCount);
float mx = fMatrix[SkMatrix::kMScaleX];
float my = fMatrix[SkMatrix::kMScaleY];
float tx = fMatrix[SkMatrix::kMTransX];
@@ -254,29 +303,28 @@ class ScaleTransMixedMatrixBench : public MatrixBench {
typedef MatrixBench INHERITED;
};
-
class ScaleTransDoubleMatrixBench : public MatrixBench {
public:
ScaleTransDoubleMatrixBench(void* p) : INHERITED(p, "scaletrans_double"), fCount (16) {
init9(fMatrix);
int i;
- for (i = 0; i < fCount; i++) {
- fSrc[i].fX = fRandom.nextS();
- fSrc[i].fY = fRandom.nextS();
- fDst[i].fX = fRandom.nextS();
- fDst[i].fY = fRandom.nextS();
+ for (i = 0; i < SkBENCHLOOP(fCount); i++) {
+ fSrc[i].fX = fRandom.nextSScalar1();
+ fSrc[i].fY = fRandom.nextSScalar1();
+ fDst[i].fX = fRandom.nextSScalar1();
+ fDst[i].fY = fRandom.nextSScalar1();
}
}
protected:
virtual void performTest() {
SkPoint* dst = fDst;
const SkPoint* src = fSrc;
- int count = fCount;
+ int count = SkBENCHLOOP(fCount);
// As doubles, on Z600 Linux systems this is 2.5x as expensive as mixed mode
- float mx = fMatrix[SkMatrix::kMScaleX];
- float my = fMatrix[SkMatrix::kMScaleY];
- float tx = fMatrix[SkMatrix::kMTransX];
- float ty = fMatrix[SkMatrix::kMTransY];
+ float mx = (float) fMatrix[SkMatrix::kMScaleX];
+ float my = (float) fMatrix[SkMatrix::kMScaleY];
+ float tx = (float) fMatrix[SkMatrix::kMTransX];
+ float ty = (float) fMatrix[SkMatrix::kMTransY];
do {
dst->fY = src->fY * my + ty;
dst->fX = src->fX * mx + tx;
@@ -303,12 +351,14 @@ static SkBenchmark* M1(void* p) { return new ScaleMatrixBench(p); }
static SkBenchmark* M2(void* p) { return new FloatConcatMatrixBench(p); }
static SkBenchmark* M3(void* p) { return new FloatDoubleConcatMatrixBench(p); }
static SkBenchmark* M4(void* p) { return new DoubleConcatMatrixBench(p); }
+static SkBenchmark* M5(void* p) { return new GetTypeMatrixBench(p); }
static BenchRegistry gReg0(M0);
static BenchRegistry gReg1(M1);
static BenchRegistry gReg2(M2);
static BenchRegistry gReg3(M3);
static BenchRegistry gReg4(M4);
+static BenchRegistry gReg5(M5);
#ifdef SK_SCALAR_IS_FLOAT
static SkBenchmark* FlM0(void* p) { return new ScaleTransMixedMatrixBench(p); }
diff --git a/bench/MutexBench.cpp b/bench/MutexBench.cpp
new file mode 100644
index 0000000..d9b427b
--- /dev/null
+++ b/bench/MutexBench.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkBenchmark.h"
+#include "SkThread.h"
+
+class MutexBench : public SkBenchmark {
+ enum {
+ N = SkBENCHLOOP(80),
+ M = SkBENCHLOOP(200)
+ };
+public:
+ MutexBench(void* param) : INHERITED(param) {
+
+ }
+protected:
+ virtual const char* onGetName() {
+ return "mutex";
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ for (int i = 0; i < N; i++) {
+ SkMutex mu;
+ for (int j = 0; j < M; j++) {
+ mu.acquire();
+ mu.release();
+ }
+ }
+ }
+
+private:
+ typedef SkBenchmark INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkBenchmark* Fact(void* p) { return new MutexBench(p); }
+
+static BenchRegistry gReg01(Fact);
+
diff --git a/bench/PathBench.cpp b/bench/PathBench.cpp
index 19e3aae..d3e01b7 100644
--- a/bench/PathBench.cpp
+++ b/bench/PathBench.cpp
@@ -1,8 +1,16 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkColorPriv.h"
#include "SkPaint.h"
+#include "SkRandom.h"
#include "SkShader.h"
#include "SkString.h"
@@ -20,7 +28,7 @@ class PathBench : public SkBenchmark {
SkPaint fPaint;
SkString fName;
Flags fFlags;
- enum { N = 1000 };
+ enum { N = SkBENCHLOOP(1000) };
public:
PathBench(void* param, Flags flags) : INHERITED(param), fFlags(flags) {
fPaint.setStyle(flags & kStroke_Flag ? SkPaint::kStroke_Style :
@@ -31,7 +39,7 @@ public:
virtual void appendName(SkString*) = 0;
virtual void makePath(SkPath*) = 0;
- virtual bool iscomplex() { return false; }
+ virtual int complexity() { return 0; }
protected:
virtual const char* onGetName() {
@@ -58,9 +66,7 @@ protected:
if (fFlags & kBig_Flag) {
count >>= 2;
}
- if (this->iscomplex()) {
- count >>= 3;
- }
+ count >>= (3 * complexity());
for (int i = 0; i < count; i++) {
canvas->drawPath(path, paint);
@@ -146,11 +152,38 @@ public:
path->lineTo(x0, y + 2 * dy);
path->close();
}
- virtual bool iscomplex() { return true; }
+ virtual int complexity() { return 1; }
private:
typedef PathBench INHERITED;
};
+class LongCurvedPathBench : public PathBench {
+public:
+ LongCurvedPathBench(void * param, Flags flags)
+ : INHERITED(param, flags) {
+ }
+
+ virtual void appendName(SkString* name) {
+ name->append("long_curved");
+ }
+ virtual void makePath(SkPath* path) {
+ SkRandom rand (12);
+ int i;
+ for (i = 0; i < 100; i++) {
+ path->quadTo(SkScalarMul(rand.nextUScalar1(), SkIntToScalar(640)),
+ SkScalarMul(rand.nextUScalar1(), SkIntToScalar(480)),
+ SkScalarMul(rand.nextUScalar1(), SkIntToScalar(640)),
+ SkScalarMul(rand.nextUScalar1(), SkIntToScalar(480)));
+ }
+ path->close();
+ }
+ virtual int complexity() { return 2; }
+private:
+ typedef PathBench INHERITED;
+};
+
+
+
static SkBenchmark* FactT00(void* p) { return new TrianglePathBench(p, FLAGS00); }
static SkBenchmark* FactT01(void* p) { return new TrianglePathBench(p, FLAGS01); }
static SkBenchmark* FactT10(void* p) { return new TrianglePathBench(p, FLAGS10); }
@@ -169,6 +202,13 @@ static SkBenchmark* FactO11(void* p) { return new OvalPathBench(p, FLAGS11); }
static SkBenchmark* FactS00(void* p) { return new SawToothPathBench(p, FLAGS00); }
static SkBenchmark* FactS01(void* p) { return new SawToothPathBench(p, FLAGS01); }
+static SkBenchmark* FactLC00(void* p) {
+ return new LongCurvedPathBench(p, FLAGS00);
+}
+static SkBenchmark* FactLC01(void* p) {
+ return new LongCurvedPathBench(p, FLAGS01);
+}
+
static BenchRegistry gRegT00(FactT00);
static BenchRegistry gRegT01(FactT01);
static BenchRegistry gRegT10(FactT10);
@@ -187,3 +227,6 @@ static BenchRegistry gRegO11(FactO11);
static BenchRegistry gRegS00(FactS00);
static BenchRegistry gRegS01(FactS01);
+static BenchRegistry gRegLC00(FactLC00);
+static BenchRegistry gRegLC01(FactLC01);
+
diff --git a/bench/RectBench.cpp b/bench/RectBench.cpp
index fb54640..cef2e22 100644
--- a/bench/RectBench.cpp
+++ b/bench/RectBench.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkCanvas.h"
#include "SkPaint.h"
@@ -11,7 +18,7 @@ public:
enum {
W = 640,
H = 480,
- N = 300
+ N = SkBENCHLOOP(300)
};
SkRect fRects[N];
SkColor fColors[N];
diff --git a/bench/RepeatTileBench.cpp b/bench/RepeatTileBench.cpp
index 97bbeb8..8470bed 100644
--- a/bench/RepeatTileBench.cpp
+++ b/bench/RepeatTileBench.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
@@ -79,7 +86,7 @@ static void convertToIndex666(const SkBitmap& src, SkBitmap* dst) {
class RepeatTileBench : public SkBenchmark {
SkPaint fPaint;
SkString fName;
- enum { N = 20 };
+ enum { N = SkBENCHLOOP(20) };
public:
RepeatTileBench(void* param, SkBitmap::Config c) : INHERITED(param) {
const int w = 50;
diff --git a/bench/ScalarBench.cpp b/bench/ScalarBench.cpp
index 29fe5c4..8bedfbd 100644
--- a/bench/ScalarBench.cpp
+++ b/bench/ScalarBench.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkFloatBits.h"
#include "SkRandom.h"
@@ -21,7 +28,7 @@ protected:
}
virtual void onDraw(SkCanvas* canvas) {
- int n = N * this->mulLoopCount();
+ int n = SkBENCHLOOP(N * this->mulLoopCount());
for (int i = 0; i < n; i++) {
this->performTest();
}
diff --git a/bench/ShaderMaskBench.cpp b/bench/ShaderMaskBench.cpp
new file mode 100644
index 0000000..62be6c5
--- /dev/null
+++ b/bench/ShaderMaskBench.cpp
@@ -0,0 +1,109 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkBenchmark.h"
+#include "SkCanvas.h"
+#include "SkColorShader.h"
+#include "SkFontHost.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+#include "SkSfntUtils.h"
+#include "SkString.h"
+#include "SkTemplates.h"
+
+#define STR "Hamburgefons"
+
+enum FontQuality {
+ kBW,
+ kAA,
+ kLCD
+};
+
+static const char* fontQualityName(const SkPaint& paint) {
+ if (!paint.isAntiAlias()) {
+ return "BW";
+ }
+ if (paint.isLCDRenderText()) {
+ return "LCD";
+ }
+ return "AA";
+}
+
+class ShaderMaskBench : public SkBenchmark {
+ SkPaint fPaint;
+ SkString fText;
+ SkString fName;
+ FontQuality fFQ;
+ enum { N = SkBENCHLOOP(500) };
+public:
+ ShaderMaskBench(void* param, bool isOpaque, FontQuality fq) : INHERITED(param) {
+ fFQ = fq;
+ fText.set(STR);
+
+ fPaint.setAntiAlias(kBW != fq);
+ fPaint.setLCDRenderText(kLCD == fq);
+ fPaint.setAlpha(isOpaque ? 0xFF : 0x80);
+ fPaint.setShader(new SkColorShader)->unref();
+ }
+
+protected:
+ virtual const char* onGetName() {
+ fName.printf("shadermask", SkScalarToFloat(fPaint.getTextSize()));
+ fName.appendf("_%s", fontQualityName(fPaint));
+ fName.appendf("_%02X", fPaint.getAlpha());
+ return fName.c_str();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ const SkIPoint dim = this->getSize();
+ SkRandom rand;
+
+ SkPaint paint(fPaint);
+ this->setupPaint(&paint);
+ // explicitly need these
+ paint.setAlpha(fPaint.getAlpha());
+ paint.setAntiAlias(kBW != fFQ);
+ paint.setLCDRenderText(kLCD == fFQ);
+
+ const SkScalar x0 = SkIntToScalar(-10);
+ const SkScalar y0 = SkIntToScalar(-10);
+
+ paint.setTextSize(SkIntToScalar(12));
+ for (int i = 0; i < N; i++) {
+ SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
+ SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
+ canvas->drawText(fText.c_str(), fText.size(), x, y, paint);
+ }
+
+ paint.setTextSize(SkIntToScalar(48));
+ for (int i = 0; i < N/4; i++) {
+ SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
+ SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
+ canvas->drawText(fText.c_str(), fText.size(), x, y, paint);
+ }
+ }
+
+private:
+ typedef SkBenchmark INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkBenchmark* Fact00(void* p) { return new ShaderMaskBench(p, true, kBW); }
+static SkBenchmark* Fact01(void* p) { return new ShaderMaskBench(p, false, kBW); }
+static SkBenchmark* Fact10(void* p) { return new ShaderMaskBench(p, true, kAA); }
+static SkBenchmark* Fact11(void* p) { return new ShaderMaskBench(p, false, kAA); }
+static SkBenchmark* Fact20(void* p) { return new ShaderMaskBench(p, true, kLCD); }
+static SkBenchmark* Fact21(void* p) { return new ShaderMaskBench(p, false, kLCD); }
+
+static BenchRegistry gReg00(Fact00);
+static BenchRegistry gReg01(Fact01);
+static BenchRegistry gReg10(Fact10);
+static BenchRegistry gReg11(Fact11);
+static BenchRegistry gReg20(Fact20);
+static BenchRegistry gReg21(Fact21);
+
diff --git a/bench/SkBenchmark.cpp b/bench/SkBenchmark.cpp
index 230a7af..a69402b 100644
--- a/bench/SkBenchmark.cpp
+++ b/bench/SkBenchmark.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkPaint.h"
#include "SkParse.h"
diff --git a/bench/SkBenchmark.h b/bench/SkBenchmark.h
index 945db80..5019b23 100644
--- a/bench/SkBenchmark.h
+++ b/bench/SkBenchmark.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkBenchmark_DEFINED
#define SkBenchmark_DEFINED
@@ -6,6 +13,12 @@
#include "SkTDict.h"
#include "SkTRegistry.h"
+#ifdef SK_DEBUG
+ #define SkBENCHLOOP(n) 1
+#else
+ #define SkBENCHLOOP(n) n
+#endif
+
class SkCanvas;
class SkPaint;
diff --git a/bench/TextBench.cpp b/bench/TextBench.cpp
index f2b9604..63a7167 100644
--- a/bench/TextBench.cpp
+++ b/bench/TextBench.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkCanvas.h"
#include "SkFontHost.h"
@@ -7,6 +14,22 @@
#include "SkString.h"
#include "SkTemplates.h"
+enum FontQuality {
+ kBW,
+ kAA,
+ kLCD
+};
+
+static const char* fontQualityName(const SkPaint& paint) {
+ if (!paint.isAntiAlias()) {
+ return "BW";
+ }
+ if (paint.isLCDRenderText()) {
+ return "LCD";
+ }
+ return "AA";
+}
+
/* Some considerations for performance:
short -vs- long strings (measuring overhead)
tiny -vs- large pointsize (measure blit -vs- overhead)
@@ -18,34 +41,35 @@
*/
class TextBench : public SkBenchmark {
SkPaint fPaint;
- int fCount;
- SkPoint* fPos;
SkString fText;
SkString fName;
- enum { N = 600 };
+ FontQuality fFQ;
+ bool fDoPos;
+ SkPoint* fPos;
+ enum { N = SkBENCHLOOP(800) };
public:
- TextBench(void* param, const char text[], int ps, bool linearText,
- bool posText, SkColor color = SK_ColorBLACK) : INHERITED(param) {
+ TextBench(void* param, const char text[], int ps,
+ SkColor color, FontQuality fq, bool doPos = false) : INHERITED(param) {
+ fFQ = fq;
+ fDoPos = doPos;
fText.set(text);
- fPaint.setAntiAlias(true);
+ fPaint.setAntiAlias(kBW != fq);
+ fPaint.setLCDRenderText(kLCD == fq);
fPaint.setTextSize(SkIntToScalar(ps));
- fPaint.setLinearText(linearText);
fPaint.setColor(color);
- if (posText) {
- SkAutoTArray<SkScalar> storage(fText.size());
- SkScalar* widths = storage.get();
- fCount = fPaint.getTextWidths(fText.c_str(), fText.size(), widths);
- fPos = new SkPoint[fCount];
+ if (doPos) {
+ size_t len = strlen(text);
+ SkScalar* adv = new SkScalar[len];
+ fPaint.getTextWidths(text, len, adv);
+ fPos = new SkPoint[len];
SkScalar x = 0;
- for (int i = 0; i < fCount; i++) {
- fPos[i].set(x, 0);
- x += widths[i];
+ for (size_t i = 0; i < len; ++i) {
+ fPos[i].set(x, SkIntToScalar(50));
+ x += adv[i];
}
- } else {
- fCount = 0;
- fPos = NULL;
+ delete[] adv;
}
}
@@ -56,15 +80,14 @@ public:
protected:
virtual const char* onGetName() {
fName.printf("text_%g", SkScalarToFloat(fPaint.getTextSize()));
- if (fPaint.isLinearText()) {
- fName.append("_linear");
- }
- if (fPos) {
- fName.append("_pos");
+ if (fDoPos) {
+ fName.appendf("_pos");
}
-
+ fName.appendf("_%s", fontQualityName(fPaint));
if (SK_ColorBLACK != fPaint.getColor()) {
fName.appendf("_%02X", fPaint.getAlpha());
+ } else {
+ fName.appendf("_BK");
}
return fName.c_str();
}
@@ -75,20 +98,26 @@ protected:
SkPaint paint(fPaint);
this->setupPaint(&paint);
- paint.setColor(fPaint.getColor()); // need our specified color
+ // explicitly need these
+ paint.setColor(fPaint.getColor());
+ paint.setAntiAlias(kBW != fFQ);
+ paint.setLCDRenderText(kLCD == fFQ);
const SkScalar x0 = SkIntToScalar(-10);
const SkScalar y0 = SkIntToScalar(-10);
+ if (fDoPos) {
+ // realistically, the matrix is often at least translated, so we
+ // do that since it exercises different code in drawPosText.
+ canvas->translate(SK_Scalar1, SK_Scalar1);
+ }
+
for (int i = 0; i < N; i++) {
- SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
- SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
- if (fPos) {
- canvas->save(SkCanvas::kMatrix_SaveFlag);
- canvas->translate(x, y);
+ if (fDoPos) {
canvas->drawPosText(fText.c_str(), fText.size(), fPos, paint);
- canvas->restore();
} else {
+ SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
+ SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
canvas->drawText(fText.c_str(), fText.size(), x, y, paint);
}
}
@@ -101,35 +130,31 @@ private:
///////////////////////////////////////////////////////////////////////////////
#define STR "Hamburgefons"
-#define SMALL 9
-#define BIG 48
-static SkBenchmark* Fact0(void* p) { return new TextBench(p, STR, SMALL, false, false); }
-static SkBenchmark* Fact01(void* p) { return new TextBench(p, STR, SMALL, false, false, 0xFFFF0000); }
-static SkBenchmark* Fact02(void* p) { return new TextBench(p, STR, SMALL, false, false, 0x88FF0000); }
+static SkBenchmark* Fact01(void* p) { return new TextBench(p, STR, 16, 0xFF000000, kBW); }
+static SkBenchmark* Fact02(void* p) { return new TextBench(p, STR, 16, 0xFFFF0000, kBW); }
+static SkBenchmark* Fact03(void* p) { return new TextBench(p, STR, 16, 0x88FF0000, kBW); }
-static SkBenchmark* Fact1(void* p) { return new TextBench(p, STR, SMALL, false, true); }
-static SkBenchmark* Fact2(void* p) { return new TextBench(p, STR, SMALL, true, false); }
-static SkBenchmark* Fact3(void* p) { return new TextBench(p, STR, SMALL, true, true); }
+static SkBenchmark* Fact11(void* p) { return new TextBench(p, STR, 16, 0xFF000000, kAA); }
+static SkBenchmark* Fact12(void* p) { return new TextBench(p, STR, 16, 0xFFFF0000, kAA); }
+static SkBenchmark* Fact13(void* p) { return new TextBench(p, STR, 16, 0x88FF0000, kAA); }
-static SkBenchmark* Fact4(void* p) { return new TextBench(p, STR, BIG, false, false); }
-static SkBenchmark* Fact41(void* p) { return new TextBench(p, STR, BIG, false, false, 0xFFFF0000); }
-static SkBenchmark* Fact42(void* p) { return new TextBench(p, STR, BIG, false, false, 0x88FF0000); }
+static SkBenchmark* Fact21(void* p) { return new TextBench(p, STR, 16, 0xFF000000, kLCD); }
+static SkBenchmark* Fact22(void* p) { return new TextBench(p, STR, 16, 0xFFFF0000, kLCD); }
+static SkBenchmark* Fact23(void* p) { return new TextBench(p, STR, 16, 0x88FF0000, kLCD); }
-static SkBenchmark* Fact5(void* p) { return new TextBench(p, STR, BIG, false, true); }
-static SkBenchmark* Fact6(void* p) { return new TextBench(p, STR, BIG, true, false); }
-static SkBenchmark* Fact7(void* p) { return new TextBench(p, STR, BIG, true, true); }
+static SkBenchmark* Fact111(void* p) { return new TextBench(p, STR, 16, 0xFF000000, kAA, true); }
-static BenchRegistry gReg0(Fact0);
static BenchRegistry gReg01(Fact01);
static BenchRegistry gReg02(Fact02);
-static BenchRegistry gReg1(Fact1);
-static BenchRegistry gReg2(Fact2);
-static BenchRegistry gReg3(Fact3);
-static BenchRegistry gReg4(Fact4);
-static BenchRegistry gReg41(Fact41);
-static BenchRegistry gReg42(Fact42);
-static BenchRegistry gReg5(Fact5);
-static BenchRegistry gReg6(Fact6);
-static BenchRegistry gReg7(Fact7);
+static BenchRegistry gReg03(Fact03);
+
+static BenchRegistry gReg11(Fact11);
+static BenchRegistry gReg12(Fact12);
+static BenchRegistry gReg13(Fact13);
+
+static BenchRegistry gReg21(Fact21);
+static BenchRegistry gReg22(Fact22);
+static BenchRegistry gReg23(Fact23);
+static BenchRegistry gReg111(Fact111);
diff --git a/bench/VertBench.cpp b/bench/VertBench.cpp
new file mode 100644
index 0000000..98df449
--- /dev/null
+++ b/bench/VertBench.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBenchmark.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+#include "SkString.h"
+#include "SkShader.h"
+
+enum VertFlags {
+ kColors_VertFlag,
+ kTexture_VertFlag,
+};
+
+class VertBench : public SkBenchmark {
+ SkString fName;
+ enum {
+ W = 640,
+ H = 480,
+ ROW = 20,
+ COL = 20,
+ PTS = (ROW + 1) * (COL + 1),
+ IDX = ROW * COL * 6,
+ N = SkBENCHLOOP(10)
+ };
+
+ SkPoint fPts[PTS];
+ SkColor fColors[PTS];
+ SkPoint fTex[PTS];
+ uint16_t fIdx[IDX];
+
+ static void load_2_tris(uint16_t idx[], int x, int y, int rb) {
+ int n = y * rb + x;
+ idx[0] = n; idx[1] = n + 1; idx[2] = rb + n + 1;
+ idx[3] = n; idx[4] = rb + n + 1; idx[5] = n + rb;
+ }
+
+public:
+ VertBench(void* param) : INHERITED(param) {
+ const SkScalar dx = SkIntToScalar(W) / COL;
+ const SkScalar dy = SkIntToScalar(H) / COL;
+
+ SkPoint* pts = fPts;
+ uint16_t* idx = fIdx;
+
+ SkScalar yy = 0;
+ for (int y = 0; y <= ROW; y++) {
+ SkScalar xx = 0;
+ for (int x = 0; x <= COL; ++x) {
+ pts->set(xx, yy);
+ pts += 1;
+ xx += dx;
+
+ if (x < COL && y < ROW) {
+ load_2_tris(idx, x, y, COL + 1);
+ for (int i = 0; i < 6; i++) {
+ SkASSERT(idx[i] < PTS);
+ }
+ idx += 6;
+ }
+ }
+ yy += dy;
+ }
+ SkASSERT(PTS == pts - fPts);
+ SkASSERT(IDX == idx - fIdx);
+
+ SkRandom rand;
+ for (int i = 0; i < PTS; ++i) {
+ fColors[i] = rand.nextU() | (0xFF << 24);
+ }
+
+ fName.set("verts");
+ }
+
+protected:
+ virtual const char* onGetName() { return fName.c_str(); }
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+ this->setupPaint(&paint);
+
+ for (int i = 0; i < N; i++) {
+ canvas->drawVertices(SkCanvas::kTriangles_VertexMode, PTS,
+ fPts, NULL, fColors, NULL, fIdx, IDX, paint);
+ }
+ }
+private:
+ typedef SkBenchmark INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkBenchmark* Fact(void* p) { return SkNEW_ARGS(VertBench, (p)); }
+
+static BenchRegistry gReg(Fact);
diff --git a/bench/bench_compare.py b/bench/bench_compare.py
index f6909b1..c1a1ff9 100644
--- a/bench/bench_compare.py
+++ b/bench/bench_compare.py
@@ -5,31 +5,7 @@ Created on May 16, 2011
'''
import sys
import getopt
-import re
-
-def parse(lines):
- """Takes iterable lines of bench output, returns {bench:{config:time}}."""
-
- benches = {}
- current_bench = None
-
- for line in lines:
- #see if this line starts a new bench
- new_bench = re.search('running bench \[\d+ \d+\] (.{28})', line)
- if new_bench:
- current_bench = new_bench.group(1)
-
- #add configs on this line to the current bench
- if current_bench:
- for new_config in re.finditer(' (.{4}): msecs = (\d+\.\d+)', line):
- current_config = new_config.group(1)
- current_time = float(new_config.group(2))
- if current_bench in benches:
- benches[current_bench][current_config] = current_time
- else:
- benches[current_bench] = {current_config : current_time}
-
- return benches
+import bench_util
def usage():
"""Prints simple usage information."""
@@ -38,20 +14,39 @@ def usage():
print '-n <file> the new bench output file.'
print '-h causes headers to be output.'
print '-f <fieldSpec> which fields to output and in what order.'
- print ' Not specifying is the same as -f "bcondp".'
+ print ' Not specifying is the same as -f "bctondp".'
print ' b: bench'
print ' c: config'
+ print ' t: time type'
print ' o: old time'
print ' n: new time'
print ' d: diff'
print ' p: percent diff'
-
+class BenchDiff:
+ """A compare between data points produced by bench.
+
+ (BenchDataPoint, BenchDataPoint)"""
+ def __init__(self, old, new):
+ self.old = old
+ self.new = new
+ self.diff = old.time - new.time
+ diffp = 0
+ if old.time != 0:
+ diffp = self.diff / old.time
+ self.diffp = diffp
+
+ def __repr__(self):
+ return "BenchDiff(%s, %s)" % (
+ str(self.new),
+ str(self.old),
+ )
+
def main():
"""Parses command line and writes output."""
try:
- opts, args = getopt.getopt(sys.argv[1:], "f:o:n:h")
+ opts, _ = getopt.getopt(sys.argv[1:], "f:o:n:h")
except getopt.GetoptError, err:
print str(err)
usage()
@@ -60,25 +55,27 @@ def main():
column_formats = {
'b' : '{bench: >28} ',
'c' : '{config: <4} ',
+ 't' : '{time_type: <4} ',
'o' : '{old_time: >10.2f} ',
'n' : '{new_time: >10.2f} ',
'd' : '{diff: >+10.2f} ',
- 'p' : '{diffp: >+7.1%} ',
+ 'p' : '{diffp: >+8.1%} ',
}
header_formats = {
'b' : '{bench: >28} ',
'c' : '{config: <4} ',
+ 't' : '{time_type: <4} ',
'o' : '{old_time: >10} ',
'n' : '{new_time: >10} ',
'd' : '{diff: >10} ',
- 'p' : '{diffp: >7} ',
+ 'p' : '{diffp: >8} ',
}
old = None
new = None
column_format = ""
header_format = ""
- columns = 'bcondp'
+ columns = 'bctondp'
header = False
for option, value in opts:
@@ -110,31 +107,43 @@ def main():
print header_format.format(
bench='bench'
, config='conf'
+ , time_type='time'
, old_time='old'
, new_time='new'
, diff='diff'
, diffp='diffP'
)
- old_benches = parse(open(old, 'r'))
- new_benches = parse(open(new, 'r'))
-
- for old_bench, old_configs in old_benches.items():
- if old_bench in new_benches:
- new_configs = new_benches[old_bench]
- for old_config, old_time in old_configs.items():
- if old_config in new_configs:
- new_time = new_configs[old_config]
- old_time = old_configs[old_config]
- print column_format.format(
- bench=old_bench.strip()
- , config=old_config.strip()
- , old_time=old_time
- , new_time=new_time
- , diff=(old_time - new_time)
- , diffp=((old_time-new_time)/old_time)
- )
-
+ old_benches = bench_util.parse({}, open(old, 'r'))
+ new_benches = bench_util.parse({}, open(new, 'r'))
+
+ bench_diffs = []
+ for old_bench in old_benches:
+ #filter new_benches for benches that match old_bench
+ new_bench_match = [bench for bench in new_benches
+ if old_bench.bench == bench.bench and
+ old_bench.config == bench.config and
+ old_bench.time_type == bench.time_type
+ ]
+ if (len(new_bench_match) < 1):
+ continue
+ bench_diffs.append(BenchDiff(old_bench, new_bench_match[0]))
+
+ bench_diffs.sort(key=lambda d : [d.diffp,
+ d.old.bench,
+ d.old.config,
+ d.old.time_type,
+ ])
+ for bench_diff in bench_diffs:
+ print column_format.format(
+ bench=bench_diff.old.bench.strip()
+ , config=bench_diff.old.config.strip()
+ , time_type=bench_diff.old.time_type
+ , old_time=bench_diff.old.time
+ , new_time=bench_diff.new.time
+ , diff=bench_diff.diff
+ , diffp=bench_diff.diffp
+ )
if __name__ == "__main__":
main()
diff --git a/bench/bench_graph_svg.py b/bench/bench_graph_svg.py
new file mode 100644
index 0000000..d8cd54b
--- /dev/null
+++ b/bench/bench_graph_svg.py
@@ -0,0 +1,750 @@
+'''
+Created on May 16, 2011
+
+@author: bungeman
+'''
+import sys
+import getopt
+import re
+import os
+import bench_util
+import json
+import xml.sax.saxutils
+
+def usage():
+ """Prints simple usage information."""
+
+ print '-d <dir> a directory containing bench_r<revision>_<scalar> files.'
+ print '-b <bench> the bench to show.'
+ print '-c <config> the config to show (GPU, 8888, 565, etc).'
+ print '-t <time> the time to show (w, c, g, etc).'
+ print '-s <setting>[=<value>] a setting to show (alpha, scalar, etc).'
+ print '-r <revision>[:<revision>] the revisions to show.'
+ print ' Negative <revision> is taken as offset from most recent revision.'
+ print '-f <revision>[:<revision>] the revisions to use for fitting.'
+ print ' Negative <revision> is taken as offset from most recent revision.'
+ print '-x <int> the desired width of the svg.'
+ print '-y <int> the desired height of the svg.'
+ print '-l <title> title to use for the output graph'
+ print '--default-setting <setting>[=<value>] setting for those without.'
+
+
+class Label:
+ """The information in a label.
+
+ (str, str, str, str, {str:str})"""
+ def __init__(self, bench, config, time_type, settings):
+ self.bench = bench
+ self.config = config
+ self.time_type = time_type
+ self.settings = settings
+
+ def __repr__(self):
+ return "Label(%s, %s, %s, %s)" % (
+ str(self.bench),
+ str(self.config),
+ str(self.time_type),
+ str(self.settings),
+ )
+
+ def __str__(self):
+ return "%s_%s_%s_%s" % (
+ str(self.bench),
+ str(self.config),
+ str(self.time_type),
+ str(self.settings),
+ )
+
+ def __eq__(self, other):
+ return (self.bench == other.bench and
+ self.config == other.config and
+ self.time_type == other.time_type and
+ self.settings == other.settings)
+
+ def __hash__(self):
+ return (hash(self.bench) ^
+ hash(self.config) ^
+ hash(self.time_type) ^
+ hash(frozenset(self.settings.iteritems())))
+
+def get_latest_revision(directory):
+ """Returns the latest revision number found within this directory.
+ """
+ latest_revision_found = -1
+ for bench_file in os.listdir(directory):
+ file_name_match = re.match('bench_r(\d+)_(\S+)', bench_file)
+ if (file_name_match is None):
+ continue
+ revision = int(file_name_match.group(1))
+ if revision > latest_revision_found:
+ latest_revision_found = revision
+ if latest_revision_found < 0:
+ return None
+ else:
+ return latest_revision_found
+
+def parse_dir(directory, default_settings, oldest_revision, newest_revision):
+ """Parses bench data from files like bench_r<revision>_<scalar>.
+
+ (str, {str, str}, Number, Number) -> {int:[BenchDataPoints]}"""
+ revision_data_points = {} # {revision : [BenchDataPoints]}
+ for bench_file in os.listdir(directory):
+ file_name_match = re.match('bench_r(\d+)_(\S+)', bench_file)
+ if (file_name_match is None):
+ continue
+
+ revision = int(file_name_match.group(1))
+ scalar_type = file_name_match.group(2)
+
+ if (revision < oldest_revision or revision > newest_revision):
+ continue
+
+ file_handle = open(directory + '/' + bench_file, 'r')
+
+ if (revision not in revision_data_points):
+ revision_data_points[revision] = []
+ default_settings['scalar'] = scalar_type
+ revision_data_points[revision].extend(
+ bench_util.parse(default_settings, file_handle))
+ file_handle.close()
+ return revision_data_points
+
+def create_lines(revision_data_points, settings
+ , bench_of_interest, config_of_interest, time_of_interest):
+ """Convert revision data into sorted line data.
+
+ ({int:[BenchDataPoints]}, {str:str}, str?, str?, str?)
+ -> {Label:[(x,y)] | [n].x <= [n+1].x}"""
+ revisions = revision_data_points.keys()
+ revisions.sort()
+ lines = {} # {Label:[(x,y)] | x[n] <= x[n+1]}
+ for revision in revisions:
+ for point in revision_data_points[revision]:
+ if (bench_of_interest is not None and
+ not bench_of_interest == point.bench):
+ continue
+
+ if (config_of_interest is not None and
+ not config_of_interest == point.config):
+ continue
+
+ if (time_of_interest is not None and
+ not time_of_interest == point.time_type):
+ continue
+
+ skip = False
+ for key, value in settings.items():
+ if key in point.settings and point.settings[key] != value:
+ skip = True
+ break
+ if skip:
+ continue
+
+ line_name = Label(point.bench
+ , point.config
+ , point.time_type
+ , point.settings)
+
+ if line_name not in lines:
+ lines[line_name] = []
+
+ lines[line_name].append((revision, point.time))
+
+ return lines
+
+def bounds(lines):
+ """Finds the bounding rectangle for the lines.
+
+ {Label:[(x,y)]} -> ((min_x, min_y),(max_x,max_y))"""
+ min_x = bench_util.Max
+ min_y = bench_util.Max
+ max_x = bench_util.Min
+ max_y = bench_util.Min
+
+ for line in lines.itervalues():
+ for x, y in line:
+ min_x = min(min_x, x)
+ min_y = min(min_y, y)
+ max_x = max(max_x, x)
+ max_y = max(max_y, y)
+
+ return ((min_x, min_y), (max_x, max_y))
+
+def create_regressions(lines, start_x, end_x):
+ """Creates regression data from line segments.
+
+ ({Label:[(x,y)] | [n].x <= [n+1].x}, Number, Number)
+ -> {Label:LinearRegression}"""
+ regressions = {} # {Label : LinearRegression}
+
+ for label, line in lines.iteritems():
+ regression_line = [p for p in line if start_x <= p[0] <= end_x]
+
+ if (len(regression_line) < 2):
+ continue
+ regression = bench_util.LinearRegression(regression_line)
+ regressions[label] = regression
+
+ return regressions
+
+def bounds_slope(regressions):
+ """Finds the extreme up and down slopes of a set of linear regressions.
+
+ ({Label:LinearRegression}) -> (max_up_slope, min_down_slope)"""
+ max_up_slope = 0
+ min_down_slope = 0
+ for regression in regressions.itervalues():
+ min_slope = regression.find_min_slope()
+ max_up_slope = max(max_up_slope, min_slope)
+ min_down_slope = min(min_down_slope, min_slope)
+
+ return (max_up_slope, min_down_slope)
+
+def main():
+ """Parses command line and writes output."""
+
+ try:
+ opts, _ = getopt.getopt(sys.argv[1:]
+ , "d:b:c:l:t:s:r:f:x:y:"
+ , "default-setting=")
+ except getopt.GetoptError, err:
+ print str(err)
+ usage()
+ sys.exit(2)
+
+ directory = None
+ config_of_interest = None
+ bench_of_interest = None
+ time_of_interest = None
+ revision_range = '0:'
+ regression_range = '0:'
+ latest_revision = None
+ requested_height = None
+ requested_width = None
+ title = 'Bench graph'
+ settings = {}
+ default_settings = {}
+
+ def parse_range(range):
+ """Takes '<old>[:<new>]' as a string and returns (old, new).
+ Any revision numbers that are dependent on the latest revision number
+ will be filled in based on latest_revision.
+ """
+ old, _, new = range.partition(":")
+ old = int(old)
+ if old < 0:
+ old += latest_revision;
+ if not new:
+ new = latest_revision;
+ new = int(new)
+ if new < 0:
+ new += latest_revision;
+ return (old, new)
+
+ def add_setting(settings, setting):
+ """Takes <key>[=<value>] adds {key:value} or {key:True} to settings."""
+ name, _, value = setting.partition('=')
+ if not value:
+ settings[name] = True
+ else:
+ settings[name] = value
+
+ try:
+ for option, value in opts:
+ if option == "-d":
+ directory = value
+ elif option == "-b":
+ bench_of_interest = value
+ elif option == "-c":
+ config_of_interest = value
+ elif option == "-t":
+ time_of_interest = value
+ elif option == "-s":
+ add_setting(settings, value)
+ elif option == "-r":
+ revision_range = value
+ elif option == "-f":
+ regression_range = value
+ elif option == "-x":
+ requested_width = int(value)
+ elif option == "-y":
+ requested_height = int(value)
+ elif option == "-l":
+ title = value
+ elif option == "--default-setting":
+ add_setting(default_settings, value)
+ else:
+ usage()
+ assert False, "unhandled option"
+ except ValueError:
+ usage()
+ sys.exit(2)
+
+ if directory is None:
+ usage()
+ sys.exit(2)
+
+ latest_revision = get_latest_revision(directory)
+ oldest_revision, newest_revision = parse_range(revision_range)
+ oldest_regression, newest_regression = parse_range(regression_range)
+
+ revision_data_points = parse_dir(directory
+ , default_settings
+ , oldest_revision
+ , newest_revision)
+
+ # Update oldest_revision and newest_revision based on the data we could find
+ all_revision_numbers = revision_data_points.keys()
+ oldest_revision = min(all_revision_numbers)
+ newest_revision = max(all_revision_numbers)
+
+ lines = create_lines(revision_data_points
+ , settings
+ , bench_of_interest
+ , config_of_interest
+ , time_of_interest)
+
+ regressions = create_regressions(lines
+ , oldest_regression
+ , newest_regression)
+
+ output_xhtml(lines, oldest_revision, newest_revision,
+ regressions, requested_width, requested_height, title)
+
+def qa(out):
+ """Stringify input and quote as an xml attribute."""
+ return xml.sax.saxutils.quoteattr(str(out))
+def qe(out):
+ """Stringify input and escape as xml data."""
+ return xml.sax.saxutils.escape(str(out))
+
+def create_select(qualifier, lines, select_id=None):
+ """Output select with options showing lines which qualifier maps to it.
+
+ ((Label) -> str, {Label:_}, str?) -> _"""
+ options = {} #{ option : [Label]}
+ for label in lines.keys():
+ option = qualifier(label)
+ if (option not in options):
+ options[option] = []
+ options[option].append(label)
+ option_list = list(options.keys())
+ option_list.sort()
+ print '<select class="lines"',
+ if select_id is not None:
+ print 'id=%s' % qa(select_id)
+ print 'multiple="true" size="10" onchange="updateSvg();">'
+ for option in option_list:
+ print '<option value=' + qa('[' +
+ reduce(lambda x,y:x+json.dumps(str(y))+',',options[option],"")[0:-1]
+ + ']') + '>'+qe(option)+'</option>'
+ print '</select>'
+
+def output_xhtml(lines, oldest_revision, newest_revision,
+ regressions, requested_width, requested_height, title):
+ """Outputs an svg/xhtml view of the data."""
+ print '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"',
+ print '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
+ print '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">'
+ print '<head>'
+ print '<title>%s</title>' % title
+ print '</head>'
+ print '<body>'
+
+ output_svg(lines, regressions, requested_width, requested_height)
+
+ #output the manipulation controls
+ print """
+<script type="text/javascript">//<![CDATA[
+ function getElementsByClass(node, searchClass, tag) {
+ var classElements = new Array();
+ var elements = node.getElementsByTagName(tag);
+ var pattern = new RegExp("^|\\s"+searchClass+"\\s|$");
+ for (var i = 0, elementsFound = 0; i < elements.length; ++i) {
+ if (pattern.test(elements[i].className)) {
+ classElements[elementsFound] = elements[i];
+ ++elementsFound;
+ }
+ }
+ return classElements;
+ }
+ function getAllLines() {
+ var selectElem = document.getElementById('benchSelect');
+ var linesObj = {};
+ for (var i = 0; i < selectElem.options.length; ++i) {
+ var lines = JSON.parse(selectElem.options[i].value);
+ for (var j = 0; j < lines.length; ++j) {
+ linesObj[lines[j]] = true;
+ }
+ }
+ return linesObj;
+ }
+ function getOptions(selectElem) {
+ var linesSelectedObj = {};
+ for (var i = 0; i < selectElem.options.length; ++i) {
+ if (!selectElem.options[i].selected) continue;
+
+ var linesSelected = JSON.parse(selectElem.options[i].value);
+ for (var j = 0; j < linesSelected.length; ++j) {
+ linesSelectedObj[linesSelected[j]] = true;
+ }
+ }
+ return linesSelectedObj;
+ }
+ function objectEmpty(obj) {
+ for (var p in obj) {
+ return false;
+ }
+ return true;
+ }
+ function markSelectedLines(selectElem, allLines) {
+ var linesSelected = getOptions(selectElem);
+ if (!objectEmpty(linesSelected)) {
+ for (var line in allLines) {
+ allLines[line] &= (linesSelected[line] == true);
+ }
+ }
+ }
+ function updateSvg() {
+ var allLines = getAllLines();
+
+ var selects = getElementsByClass(document, 'lines', 'select');
+ for (var i = 0; i < selects.length; ++i) {
+ markSelectedLines(selects[i], allLines);
+ }
+
+ for (var line in allLines) {
+ var svgLine = document.getElementById(line);
+ var display = (allLines[line] ? 'inline' : 'none');
+ svgLine.setAttributeNS(null,'display', display);
+ }
+ }
+
+ function mark(markerId) {
+ for (var line in getAllLines()) {
+ var svgLineGroup = document.getElementById(line);
+ var display = svgLineGroup.getAttributeNS(null,'display');
+ if (display == null || display == "" || display != "none") {
+ var svgLine = document.getElementById(line+'_line');
+ if (markerId == null) {
+ svgLine.removeAttributeNS(null,'marker-mid');
+ } else {
+ svgLine.setAttributeNS(null,'marker-mid', markerId);
+ }
+ }
+ }
+ }
+//]]></script>"""
+
+ print '<table border="0" width="%s">' % requested_width
+ print """
+<form>
+<tr valign="bottom" align="center">
+<td width="1">Bench&nbsp;Type</td>
+<td width="1">Bitmap Config</td>
+<td width="1">Timer&nbsp;Type (Cpu/Gpu/wall)</td>
+<td width="1"><!--buttons--></td>
+<td width="10%"><!--spacing--></td>"""
+
+ print '<td>%s<br></br>revisions r%s - r%s</td>' % (
+ title,
+ bench_util.CreateRevisionLink(oldest_revision),
+ bench_util.CreateRevisionLink(newest_revision))
+ print '</tr><tr valign="top" align="center">'
+ print '<td width="1">'
+ create_select(lambda l: l.bench, lines, 'benchSelect')
+ print '</td><td width="1">'
+ create_select(lambda l: l.config, lines)
+ print '</td><td width="1">'
+ create_select(lambda l: l.time_type, lines)
+
+ all_settings = {}
+ variant_settings = set()
+ for label in lines.keys():
+ for key, value in label.settings.items():
+ if key not in all_settings:
+ all_settings[key] = value
+ elif all_settings[key] != value:
+ variant_settings.add(key)
+
+ for k in variant_settings:
+ create_select(lambda l: l.settings[k], lines)
+
+ print '</td><td width="1"><button type="button"',
+ print 'onclick=%s' % qa("mark('url(#circleMark)'); return false;"),
+ print '>Mark Points</button>'
+ print '<button type="button" onclick="mark(null);">Clear Points</button>'
+
+ print """
+</td>
+<td width="10%"></td>
+<td align="left">
+<p>Brighter red indicates tests that have gotten worse; brighter green
+indicates tests that have gotten better.</p>
+<p>To highlight individual tests, hold down CONTROL and mouse over
+graph lines.</p>
+<p>To highlight revision numbers, hold down SHIFT and mouse over
+the graph area.</p>
+<p>To only show certain tests on the graph, select any combination of
+tests in the selectors at left. (To show all, select all.)</p>
+<p>Use buttons at left to mark/clear points on the lines for selected
+benchmarks.</p>
+</td>
+</tr>
+</form>
+</table>
+</body>
+</html>"""
+
+def compute_size(requested_width, requested_height, rev_width, time_height):
+ """Converts potentially empty requested size into a concrete size.
+
+ (Number?, Number?) -> (Number, Number)"""
+ pic_width = 0
+ pic_height = 0
+ if (requested_width is not None and requested_height is not None):
+ pic_height = requested_height
+ pic_width = requested_width
+
+ elif (requested_width is not None):
+ pic_width = requested_width
+ pic_height = pic_width * (float(time_height) / rev_width)
+
+ elif (requested_height is not None):
+ pic_height = requested_height
+ pic_width = pic_height * (float(rev_width) / time_height)
+
+ else:
+ pic_height = 800
+ pic_width = max(rev_width*3
+ , pic_height * (float(rev_width) / time_height))
+
+ return (pic_width, pic_height)
+
+def output_svg(lines, regressions, requested_width, requested_height):
+ """Outputs an svg view of the data."""
+
+ (global_min_x, _), (global_max_x, global_max_y) = bounds(lines)
+ max_up_slope, min_down_slope = bounds_slope(regressions)
+
+ #output
+ global_min_y = 0
+ x = global_min_x
+ y = global_min_y
+ w = global_max_x - global_min_x
+ h = global_max_y - global_min_y
+ font_size = 16
+ line_width = 2
+
+ pic_width, pic_height = compute_size(requested_width, requested_height
+ , w, h)
+
+ def cw(w1):
+ """Converts a revision difference to display width."""
+ return (pic_width / float(w)) * w1
+ def cx(x):
+ """Converts a revision to a horizontal display position."""
+ return cw(x - global_min_x)
+
+ def ch(h1):
+ """Converts a time difference to a display height."""
+ return -(pic_height / float(h)) * h1
+ def cy(y):
+ """Converts a time to a vertical display position."""
+ return pic_height + ch(y - global_min_y)
+
+ print '<svg',
+ print 'width=%s' % qa(str(pic_width)+'px')
+ print 'height=%s' % qa(str(pic_height)+'px')
+ print 'viewBox="0 0 %s %s"' % (str(pic_width), str(pic_height))
+ print 'onclick=%s' % qa(
+ "var event = arguments[0] || window.event;"
+ " if (event.shiftKey) { highlightRevision(null); }"
+ " if (event.ctrlKey) { highlight(null); }"
+ " return false;")
+ print 'xmlns="http://www.w3.org/2000/svg"'
+ print 'xmlns:xlink="http://www.w3.org/1999/xlink">'
+
+ print """
+<defs>
+ <marker id="circleMark"
+ viewBox="0 0 2 2" refX="1" refY="1"
+ markerUnits="strokeWidth"
+ markerWidth="2" markerHeight="2"
+ orient="0">
+ <circle cx="1" cy="1" r="1"/>
+ </marker>
+</defs>"""
+
+ #output the revisions
+ print """
+<script type="text/javascript">//<![CDATA[
+ var previousRevision;
+ var previousRevisionFill;
+ var previousRevisionStroke
+ function highlightRevision(id) {
+ if (previousRevision == id) return;
+
+ document.getElementById('revision').firstChild.nodeValue = 'r' + id;
+ document.getElementById('rev_link').setAttribute('xlink:href',
+ 'http://code.google.com/p/skia/source/detail?r=' + id);
+
+ var preRevision = document.getElementById(previousRevision);
+ if (preRevision) {
+ preRevision.setAttributeNS(null,'fill', previousRevisionFill);
+ preRevision.setAttributeNS(null,'stroke', previousRevisionStroke);
+ }
+
+ var revision = document.getElementById(id);
+ previousRevision = id;
+ if (revision) {
+ previousRevisionFill = revision.getAttributeNS(null,'fill');
+ revision.setAttributeNS(null,'fill','rgb(100%, 95%, 95%)');
+
+ previousRevisionStroke = revision.getAttributeNS(null,'stroke');
+ revision.setAttributeNS(null,'stroke','rgb(100%, 90%, 90%)');
+ }
+ }
+//]]></script>"""
+
+ def print_rect(x, y, w, h, revision):
+ """Outputs a revision rectangle in display space,
+ taking arguments in revision space."""
+ disp_y = cy(y)
+ disp_h = ch(h)
+ if disp_h < 0:
+ disp_y += disp_h
+ disp_h = -disp_h
+
+ print '<rect id=%s x=%s y=%s' % (qa(revision), qa(cx(x)), qa(disp_y),),
+ print 'width=%s height=%s' % (qa(cw(w)), qa(disp_h),),
+ print 'fill="white"',
+ print 'stroke="rgb(98%%,98%%,88%%)" stroke-width=%s' % qa(line_width),
+ print 'onmouseover=%s' % qa(
+ "var event = arguments[0] || window.event;"
+ " if (event.shiftKey) {"
+ " highlightRevision('"+str(revision)+"');"
+ " return false;"
+ " }"),
+ print ' />'
+
+ xes = set()
+ for line in lines.itervalues():
+ for point in line:
+ xes.add(point[0])
+ revisions = list(xes)
+ revisions.sort()
+
+ left = x
+ current_revision = revisions[0]
+ for next_revision in revisions[1:]:
+ width = (((next_revision - current_revision) / 2.0)
+ + (current_revision - left))
+ print_rect(left, y, width, h, current_revision)
+ left += width
+ current_revision = next_revision
+ print_rect(left, y, x+w - left, h, current_revision)
+
+ #output the lines
+ print """
+<script type="text/javascript">//<![CDATA[
+ var previous;
+ var previousColor;
+ var previousOpacity;
+ function highlight(id) {
+ if (previous == id) return;
+
+ document.getElementById('label').firstChild.nodeValue = id;
+
+ var preGroup = document.getElementById(previous);
+ if (preGroup) {
+ var preLine = document.getElementById(previous+'_line');
+ preLine.setAttributeNS(null,'stroke', previousColor);
+ preLine.setAttributeNS(null,'opacity', previousOpacity);
+
+ var preSlope = document.getElementById(previous+'_linear');
+ if (preSlope) {
+ preSlope.setAttributeNS(null,'visibility', 'hidden');
+ }
+ }
+
+ var group = document.getElementById(id);
+ previous = id;
+ if (group) {
+ group.parentNode.appendChild(group);
+
+ var line = document.getElementById(id+'_line');
+ previousColor = line.getAttributeNS(null,'stroke');
+ previousOpacity = line.getAttributeNS(null,'opacity');
+ line.setAttributeNS(null,'stroke', 'blue');
+ line.setAttributeNS(null,'opacity', '1');
+
+ var slope = document.getElementById(id+'_linear');
+ if (slope) {
+ slope.setAttributeNS(null,'visibility', 'visible');
+ }
+ }
+ }
+//]]></script>"""
+ for label, line in lines.items():
+ print '<g id=%s>' % qa(label)
+ r = 128
+ g = 128
+ b = 128
+ a = .10
+ if label in regressions:
+ regression = regressions[label]
+ min_slope = regression.find_min_slope()
+ if min_slope < 0:
+ d = max(0, (min_slope / min_down_slope))
+ g += int(d*128)
+ a += d*0.9
+ elif min_slope > 0:
+ d = max(0, (min_slope / max_up_slope))
+ r += int(d*128)
+ a += d*0.9
+
+ slope = regression.slope
+ intercept = regression.intercept
+ min_x = regression.min_x
+ max_x = regression.max_x
+ print '<polyline id=%s' % qa(str(label)+'_linear'),
+ print 'fill="none" stroke="yellow"',
+ print 'stroke-width=%s' % qa(abs(ch(regression.serror*2))),
+ print 'opacity="0.5" pointer-events="none" visibility="hidden"',
+ print 'points="',
+ print '%s,%s' % (str(cx(min_x)), str(cy(slope*min_x + intercept))),
+ print '%s,%s' % (str(cx(max_x)), str(cy(slope*max_x + intercept))),
+ print '"/>'
+
+ print '<polyline id=%s' % qa(str(label)+'_line'),
+ print 'onmouseover=%s' % qa(
+ "var event = arguments[0] || window.event;"
+ " if (event.ctrlKey) {"
+ " highlight('"+str(label).replace("'", "\\'")+"');"
+ " return false;"
+ " }"),
+ print 'fill="none" stroke="rgb(%s,%s,%s)"' % (str(r), str(g), str(b)),
+ print 'stroke-width=%s' % qa(line_width),
+ print 'opacity=%s' % qa(a),
+ print 'points="',
+ for point in line:
+ print '%s,%s' % (str(cx(point[0])), str(cy(point[1]))),
+ print '"/>'
+
+ print '</g>'
+
+ #output the labels
+ print '<text id="label" x="0" y=%s' % qa(font_size),
+ print 'font-size=%s> </text>' % qa(font_size)
+
+ print '<a id="rev_link" xlink:href="" target="_top">'
+ print '<text id="revision" x="0" y=%s style="' % qa(font_size*2)
+ print 'font-size: %s; ' % qe(font_size)
+ print 'stroke: #0000dd; text-decoration: underline; '
+ print '"> </text></a>'
+
+ print '</svg>'
+
+if __name__ == "__main__":
+ main()
diff --git a/bench/bench_util.py b/bench/bench_util.py
new file mode 100644
index 0000000..e36e6c6
--- /dev/null
+++ b/bench/bench_util.py
@@ -0,0 +1,178 @@
+'''
+Created on May 19, 2011
+
+@author: bungeman
+'''
+
+import re
+import math
+
+class BenchDataPoint:
+ """A single data point produced by bench.
+
+ (str, str, str, float, {str:str})"""
+ def __init__(self, bench, config, time_type, time, settings):
+ self.bench = bench
+ self.config = config
+ self.time_type = time_type
+ self.time = time
+ self.settings = settings
+
+ def __repr__(self):
+ return "BenchDataPoint(%s, %s, %s, %s, %s)" % (
+ str(self.bench),
+ str(self.config),
+ str(self.time_type),
+ str(self.time),
+ str(self.settings),
+ )
+
+class _ExtremeType(object):
+ """Instances of this class compare greater or less than other objects."""
+ def __init__(self, cmpr, rep):
+ object.__init__(self)
+ self._cmpr = cmpr
+ self._rep = rep
+
+ def __cmp__(self, other):
+ if isinstance(other, self.__class__) and other._cmpr == self._cmpr:
+ return 0
+ return self._cmpr
+
+ def __repr__(self):
+ return self._rep
+
+Max = _ExtremeType(1, "Max")
+Min = _ExtremeType(-1, "Min")
+
+def parse(settings, lines):
+ """Parses bench output into a useful data structure.
+
+ ({str:str}, __iter__ -> str) -> [BenchDataPoint]"""
+
+ benches = []
+ current_bench = None
+ setting_re = '([^\s=]+)(?:=(\S+))?'
+ settings_re = 'skia bench:((?:\s+' + setting_re + ')*)'
+ bench_re = 'running bench (?:\[\d+ \d+\] )?\s*(\S+)'
+ time_re = '(?:(\w*)msecs = )?\s*(\d+\.\d+)'
+ config_re = '(\S+): ((?:' + time_re + '\s+)+)'
+
+ for line in lines:
+
+ #see if this line is a settings line
+ settingsMatch = re.search(settings_re, line)
+ if (settingsMatch):
+ settings = dict(settings)
+ for settingMatch in re.finditer(setting_re, settingsMatch.group(1)):
+ if (settingMatch.group(2)):
+ settings[settingMatch.group(1)] = settingMatch.group(2)
+ else:
+ settings[settingMatch.group(1)] = True
+
+ #see if this line starts a new bench
+ new_bench = re.search(bench_re, line)
+ if new_bench:
+ current_bench = new_bench.group(1)
+
+ #add configs on this line to the current bench
+ if current_bench:
+ for new_config in re.finditer(config_re, line):
+ current_config = new_config.group(1)
+ times = new_config.group(2)
+ for new_time in re.finditer(time_re, times):
+ current_time_type = new_time.group(1)
+ current_time = float(new_time.group(2))
+ benches.append(BenchDataPoint(
+ current_bench
+ , current_config
+ , current_time_type
+ , current_time
+ , settings))
+
+ return benches
+
+class LinearRegression:
+ """Linear regression data based on a set of data points.
+
+ ([(Number,Number)])
+ There must be at least two points for this to make sense."""
+ def __init__(self, points):
+ n = len(points)
+ max_x = Min
+ min_x = Max
+
+ Sx = 0.0
+ Sy = 0.0
+ Sxx = 0.0
+ Sxy = 0.0
+ Syy = 0.0
+ for point in points:
+ x = point[0]
+ y = point[1]
+ max_x = max(max_x, x)
+ min_x = min(min_x, x)
+
+ Sx += x
+ Sy += y
+ Sxx += x*x
+ Sxy += x*y
+ Syy += y*y
+
+ B = (n*Sxy - Sx*Sy) / (n*Sxx - Sx*Sx)
+ a = (1.0/n)*(Sy - B*Sx)
+
+ se2 = 0
+ sB2 = 0
+ sa2 = 0
+ if (n >= 3):
+ se2 = (1.0/(n*(n-2)) * (n*Syy - Sy*Sy - B*B*(n*Sxx - Sx*Sx)))
+ sB2 = (n*se2) / (n*Sxx - Sx*Sx)
+ sa2 = sB2 * (1.0/n) * Sxx
+
+
+ self.slope = B
+ self.intercept = a
+ self.serror = math.sqrt(max(0, se2))
+ self.serror_slope = math.sqrt(max(0, sB2))
+ self.serror_intercept = math.sqrt(max(0, sa2))
+ self.max_x = max_x
+ self.min_x = min_x
+
+ def __repr__(self):
+ return "LinearRegression(%s, %s, %s, %s, %s)" % (
+ str(self.slope),
+ str(self.intercept),
+ str(self.serror),
+ str(self.serror_slope),
+ str(self.serror_intercept),
+ )
+
+ def find_min_slope(self):
+ """Finds the minimal slope given one standard deviation."""
+ slope = self.slope
+ intercept = self.intercept
+ error = self.serror
+ regr_start = self.min_x
+ regr_end = self.max_x
+ regr_width = regr_end - regr_start
+
+ if slope < 0:
+ lower_left_y = slope*regr_start + intercept - error
+ upper_right_y = slope*regr_end + intercept + error
+ return min(0, (upper_right_y - lower_left_y) / regr_width)
+
+ elif slope > 0:
+ upper_left_y = slope*regr_start + intercept + error
+ lower_right_y = slope*regr_end + intercept - error
+ return max(0, (lower_right_y - upper_left_y) / regr_width)
+
+ return 0
+
+def CreateRevisionLink(revision_number):
+ """Returns HTML displaying the given revision number and linking to
+ that revision's change page at code.google.com, e.g.
+ http://code.google.com/p/skia/source/detail?r=2056
+ """
+ return '<a href="http://code.google.com/p/skia/source/detail?r=%s">%s</a>'%(
+ revision_number, revision_number)
diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp
index 34f8a1a..024ad0f 100644
--- a/bench/benchmain.cpp
+++ b/bench/benchmain.cpp
@@ -1,18 +1,30 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "BenchTimer.h"
+
+#include "GrContext.h"
+#include "GrRenderTarget.h"
+
+#include "SkBenchmark.h"
#include "SkCanvas.h"
#include "SkColorPriv.h"
+#include "SkGpuDevice.h"
#include "SkGraphics.h"
#include "SkImageEncoder.h"
+#include "SkNativeGLContext.h"
+#include "SkNullGLContext.h"
#include "SkNWayCanvas.h"
#include "SkPicture.h"
#include "SkString.h"
-#include "GrContext.h"
-#include "SkGpuDevice.h"
-#include "SkEGLContext.h"
-#include "SkBenchmark.h"
-#include "BenchTimer.h"
-
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
static void log_error(const char msg[]) { SkDebugf("%s", msg); }
static void log_progress(const char msg[]) { SkDebugf("%s", msg); }
#else
@@ -161,8 +173,67 @@ enum Backend {
kPDF_Backend,
};
+class GLHelper {
+public:
+ GLHelper() {
+ }
+
+ bool init(SkGLContext* glCtx, int width, int height) {
+ GrContext* grCtx;
+ GrRenderTarget* rt;
+ if (glCtx->init(width, height)) {
+ GrPlatform3DContext ctx =
+ reinterpret_cast<GrPlatform3DContext>(glCtx->gl());
+ grCtx = GrContext::Create(kOpenGL_Shaders_GrEngine, ctx);
+ if (NULL != grCtx) {
+ GrPlatformRenderTargetDesc desc;
+ desc.fConfig = kSkia8888_PM_GrPixelConfig;
+ desc.fWidth = width;
+ desc.fHeight = height;
+ desc.fStencilBits = 8;
+ desc.fRenderTargetHandle = glCtx->getFBOID();
+ rt = grCtx->createPlatformRenderTarget(desc);
+ if (NULL == rt) {
+ grCtx->unref();
+ return false;
+ }
+ }
+ } else {
+ return false;
+ }
+ glCtx->ref();
+ fGLContext.reset(glCtx);
+ fGrContext.reset(grCtx);
+ fRenderTarget.reset(rt);
+ return true;
+ }
+
+ bool isValid() {
+ return NULL != fGLContext.get();
+ }
+
+ SkGLContext* glContext() {
+ return fGLContext.get();
+ }
+
+ GrRenderTarget* renderTarget() {
+ return fRenderTarget.get();
+ }
+
+ GrContext* grContext() {
+ return fGrContext.get();
+ }
+private:
+ SkAutoTUnref<SkGLContext> fGLContext;
+ SkAutoTUnref<GrContext> fGrContext;
+ SkAutoTUnref<GrRenderTarget> fRenderTarget;
+};
+
+static GLHelper gRealGLHelper;
+static GLHelper gNullGLHelper;
+
static SkDevice* make_device(SkBitmap::Config config, const SkIPoint& size,
- Backend backend, GrContext* context) {
+ Backend backend, GLHelper* glHelper) {
SkDevice* device = NULL;
SkBitmap bitmap;
bitmap.setConfig(config, size.fX, size.fY);
@@ -171,11 +242,11 @@ static SkDevice* make_device(SkBitmap::Config config, const SkIPoint& size,
case kRaster_Backend:
bitmap.allocPixels();
erase(bitmap);
- device = new SkDevice(NULL, bitmap, true);
+ device = new SkDevice(bitmap);
break;
case kGPU_Backend:
- device = new SkGpuDevice(context, bitmap, SkGpuDevice::Current3DApiRenderTarget());
-// device->clear(0xFFFFFFFF);
+ device = new SkGpuDevice(glHelper->grContext(),
+ glHelper->renderTarget());
break;
case kPDF_Backend:
default:
@@ -188,10 +259,12 @@ static const struct {
SkBitmap::Config fConfig;
const char* fName;
Backend fBackend;
+ GLHelper* fGLHelper;
} gConfigs[] = {
- { SkBitmap::kARGB_8888_Config, "8888", kRaster_Backend },
- { SkBitmap::kRGB_565_Config, "565", kRaster_Backend },
- { SkBitmap::kARGB_8888_Config, "GPU", kGPU_Backend },
+ { SkBitmap::kARGB_8888_Config, "8888", kRaster_Backend, NULL },
+ { SkBitmap::kRGB_565_Config, "565", kRaster_Backend, NULL },
+ { SkBitmap::kARGB_8888_Config, "GPU", kGPU_Backend, &gRealGLHelper },
+ { SkBitmap::kARGB_8888_Config, "NULLGPU", kGPU_Backend, &gNullGLHelper },
};
static int findConfig(const char config[]) {
@@ -203,6 +276,36 @@ static int findConfig(const char config[]) {
return -1;
}
+static void determine_gpu_context_size(SkTDict<const char*>& defineDict,
+ int* contextWidth,
+ int* contextHeight) {
+ Iter iter(&defineDict);
+ SkBenchmark* bench;
+ while ((bench = iter.next()) != NULL) {
+ SkIPoint dim = bench->getSize();
+ if (*contextWidth < dim.fX) {
+ *contextWidth = dim.fX;
+ }
+ if (*contextHeight < dim.fY) {
+ *contextHeight = dim.fY;
+ }
+ }
+}
+
+static bool skip_name(const SkTDArray<const char*> array, const char name[]) {
+ if (0 == array.count()) {
+ // no names, so don't skip anything
+ return false;
+ }
+ for (int i = 0; i < array.count(); ++i) {
+ if (strstr(name, array[i])) {
+ // found the name, so don't skip
+ return false;
+ }
+ }
+ return true;
+}
+
int main (int argc, char * const argv[]) {
SkAutoGraphics ag;
@@ -218,12 +321,13 @@ int main (int argc, char * const argv[]) {
bool doScale = false;
bool doRotate = false;
bool doClip = false;
- const char* matchStr = NULL;
bool hasStrokeWidth = false;
float strokeWidth;
+ SkTDArray<const char*> fMatches;
SkString outDir;
SkBitmap::Config outConfig = SkBitmap::kNo_Config;
+ GLHelper* glHelper = NULL;
const char* configName = "";
Backend backend = kRaster_Backend; // for warning
int configCount = SK_ARRAY_COUNT(gConfigs);
@@ -312,7 +416,7 @@ int main (int argc, char * const argv[]) {
} else if (strcmp(*argv, "-match") == 0) {
argv++;
if (argv < stop) {
- matchStr = *argv;
+ *fMatches.append() = *argv;
} else {
log_error("missing arg for -match\n");
return -1;
@@ -325,6 +429,7 @@ int main (int argc, char * const argv[]) {
outConfig = gConfigs[index].fConfig;
configName = gConfigs[index].fName;
backend = gConfigs[index].fBackend;
+ glHelper = gConfigs[index].fGLHelper;
configCount = 1;
} else {
SkString str;
@@ -355,19 +460,63 @@ int main (int argc, char * const argv[]) {
// report our current settings
{
SkString str;
- str.printf("skia bench: alpha=0x%02X antialias=%d filter=%d\n",
+ str.printf("skia bench: alpha=0x%02X antialias=%d filter=%d",
forceAlpha, forceAA, forceFilter);
+ str.appendf(" rotate=%d scale=%d clip=%d",
+ doRotate, doScale, doClip);
+
+ const char * ditherName;
+ switch (forceDither) {
+ case SkTriState::kDefault: ditherName = "default"; break;
+ case SkTriState::kTrue: ditherName = "true"; break;
+ case SkTriState::kFalse: ditherName = "false"; break;
+ default: ditherName = "<invalid>"; break;
+ }
+ str.appendf(" dither=%s", ditherName);
+
+ if (hasStrokeWidth) {
+ str.appendf(" strokeWidth=%f", strokeWidth);
+ } else {
+ str.append(" strokeWidth=none");
+ }
+
+#if defined(SK_SCALAR_IS_FLOAT)
+ str.append(" scalar=float");
+#elif defined(SK_SCALAR_IS_FIXED)
+ str.append(" scalar=fixed");
+#endif
+
+#if defined(SK_BUILD_FOR_WIN32)
+ str.append(" system=WIN32");
+#elif defined(SK_BUILD_FOR_MAC)
+ str.append(" system=MAC");
+#elif defined(SK_BUILD_FOR_ANDROID)
+ str.append(" system=ANDROID");
+#elif defined(SK_BUILD_FOR_UNIX)
+ str.append(" system=UNIX");
+#else
+ str.append(" system=other");
+#endif
+
+#if defined(SK_DEBUG)
+ str.append(" DEBUG");
+#endif
+ str.append("\n");
log_progress(str);
}
-
- GrContext* context = NULL;
- SkEGLContext eglContext;
- if (eglContext.init(1024, 1024)) {
- context = GrContext::CreateGLShaderContext();
- }
-
- BenchTimer timer = BenchTimer();
-
+
+ //Don't do GL when fixed.
+#if !defined(SK_SCALAR_IS_FIXED)
+ int contextWidth = 1024;
+ int contextHeight = 1024;
+ determine_gpu_context_size(defineDict, &contextWidth, &contextHeight);
+ SkAutoTUnref<SkGLContext> realGLCtx(new SkNativeGLContext);
+ SkAutoTUnref<SkGLContext> nullGLCtx(new SkNullGLContext);
+ gRealGLHelper.init(realGLCtx.get(), contextWidth, contextHeight);
+ gNullGLHelper.init(nullGLCtx.get(), contextWidth, contextHeight);
+#endif
+ BenchTimer timer = BenchTimer(gRealGLHelper.glContext());
+
Iter iter(&defineDict);
SkBenchmark* bench;
while ((bench = iter.next()) != NULL) {
@@ -385,7 +534,7 @@ int main (int argc, char * const argv[]) {
}
// only run benchmarks if their name contains matchStr
- if (matchStr && strstr(bench->getName(), matchStr) == NULL) {
+ if (skip_name(fMatches, bench->getName())) {
continue;
}
@@ -401,13 +550,15 @@ int main (int argc, char * const argv[]) {
outConfig = gConfigs[configIndex].fConfig;
configName = gConfigs[configIndex].fName;
backend = gConfigs[configIndex].fBackend;
+ glHelper = gConfigs[configIndex].fGLHelper;
}
-
- if (kGPU_Backend == backend && NULL == context) {
+
+ if (kGPU_Backend == backend &&
+ (NULL == glHelper || !glHelper->isValid())) {
continue;
}
- SkDevice* device = make_device(outConfig, dim, backend, context);
+ SkDevice* device = make_device(outConfig, dim, backend, glHelper);
SkCanvas canvas(device);
device->unref();
@@ -420,15 +571,14 @@ int main (int argc, char * const argv[]) {
if (doRotate) {
performRotate(&canvas, dim.fX, dim.fY);
}
-
- bool gpu = kGPU_Backend == backend && context;
+
//warm up caches if needed
if (repeatDraw > 1) {
SkAutoCanvasRestore acr(&canvas, true);
bench->draw(&canvas);
- if (gpu) {
- context->flush();
- glFinish();
+ if (glHelper) {
+ glHelper->grContext()->flush();
+ SK_GL(*glHelper->glContext(), Finish());
}
}
@@ -436,8 +586,14 @@ int main (int argc, char * const argv[]) {
for (int i = 0; i < repeatDraw; i++) {
SkAutoCanvasRestore acr(&canvas, true);
bench->draw(&canvas);
+ if (glHelper) {
+ glHelper->grContext()->flush();
+ }
}
- timer.end();
+ if (glHelper) {
+ SK_GL(*glHelper->glContext(), Finish());
+ }
+ timer.end();
if (repeatDraw > 1) {
SkString str;
@@ -448,7 +604,7 @@ int main (int argc, char * const argv[]) {
if (timerCpu) {
str.appendf(" cmsecs = %6.2f", timer.fCpu / repeatDraw);
}
- if (timerGpu && gpu && timer.fGpu > 0) {
+ if (timerGpu && glHelper && timer.fGpu > 0) {
str.appendf(" gmsecs = %6.2f", timer.fGpu / repeatDraw);
}
log_progress(str);
@@ -460,6 +616,6 @@ int main (int argc, char * const argv[]) {
}
log_progress("\n");
}
-
+
return 0;
}
diff --git a/gm/Android.mk b/gm/Android.mk
index acfb4a5..14f4d62 100644
--- a/gm/Android.mk
+++ b/gm/Android.mk
@@ -3,11 +3,21 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
+ aarectmodes.cpp \
bitmapfilters.cpp \
+ bitmapscroll.cpp \
blurs.cpp \
complexclip.cpp \
+ complexclip2.cpp \
+ emptypath.cpp \
filltypes.cpp \
+ filltypespersp.cpp \
+ gm.cpp \
+ gmmain.cpp \
gradients.cpp \
+ hairmodes.cpp \
+ lcdtext.cpp \
+ ninepatchstretch.cpp \
nocolorbleed.cpp \
pathfill.cpp \
points.cpp \
@@ -16,13 +26,11 @@ LOCAL_SRC_FILES := \
shadows.cpp \
shapes.cpp \
strokerects.cpp \
+ strokes.cpp \
+ texdata.cpp \
tilemodes.cpp \
- xfermodes.cpp \
- gmmain.cpp
-
-# additional optional class for this tool
-LOCAL_SRC_FILES += \
- ../src/utils/SkEGLContext_none.cpp
+ tinybitmap.cpp \
+ xfermodes.cpp
LOCAL_STATIC_LIBRARIES := libskiagpu
LOCAL_SHARED_LIBRARIES := \
@@ -35,11 +43,11 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_C_INCLUDES := \
external/skia/include/config \
external/skia/include/core \
+ external/skia/include/effects \
+ external/skia/include/gpu \
external/skia/include/images \
external/skia/include/utils \
- external/skia/include/effects \
- external/skia/gpu/include \
- external/skia/include/gpu
+ external/skia/gm
#LOCAL_CFLAGS :=
diff --git a/gm/aaclip.cpp b/gm/aaclip.cpp
new file mode 100644
index 0000000..2976560
--- /dev/null
+++ b/gm/aaclip.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkPath.h"
+
+namespace skiagm {
+
+/** Draw a 2px border around the target, then red behind the target;
+ set the clip to match the target, then draw >> the target in blue.
+*/
+
+void draw (SkCanvas* canvas, SkRect& target, int x, int y) {
+ SkPaint borderPaint;
+ borderPaint.setColor(SkColorSetRGB(0x0, 0xDD, 0x0));
+ borderPaint.setAntiAlias(true);
+ SkPaint backgroundPaint;
+ backgroundPaint.setColor(SkColorSetRGB(0xDD, 0x0, 0x0));
+ backgroundPaint.setAntiAlias(true);
+ SkPaint foregroundPaint;
+ foregroundPaint.setColor(SkColorSetRGB(0x0, 0x0, 0xDD));
+ foregroundPaint.setAntiAlias(true);
+
+ canvas->save();
+ canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
+ target.inset(SkIntToScalar(-2), SkIntToScalar(-2));
+ canvas->drawRect(target, borderPaint);
+ target.inset(SkIntToScalar(2), SkIntToScalar(2));
+ canvas->drawRect(target, backgroundPaint);
+ canvas->clipRect(target, SkRegion::kIntersect_Op, true);
+ target.inset(SkIntToScalar(-4), SkIntToScalar(-4));
+ canvas->drawRect(target, foregroundPaint);
+ canvas->restore();
+}
+
+void draw_square (SkCanvas* canvas, int x, int y) {
+ SkRect target (SkRect::MakeWH(10 * SK_Scalar1, 10 * SK_Scalar1));
+ draw(canvas, target, x, y);
+}
+
+void draw_column (SkCanvas* canvas, int x, int y) {
+ SkRect target (SkRect::MakeWH(1 * SK_Scalar1, 10 * SK_Scalar1));
+ draw(canvas, target, x, y);
+}
+
+void draw_bar (SkCanvas* canvas, int x, int y) {
+ SkRect target (SkRect::MakeWH(10 * SK_Scalar1, 1 * SK_Scalar1));
+ draw(canvas, target, x, y);
+}
+
+void draw_rect_tests (SkCanvas* canvas) {
+ draw_square(canvas, 10, 10);
+ draw_column(canvas, 30, 10);
+ draw_bar(canvas, 10, 30);
+}
+
+/**
+ Test a set of clipping problems discovered while writing blitAntiRect,
+ and test all the code paths through the clipping blitters.
+ Each region should show as a blue center surrounded by a 2px green
+ border, with no red.
+*/
+
+class AAClipGM : public GM {
+public:
+ AAClipGM() {
+
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("aaclip");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(640, 480);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ // Initial pixel-boundary-aligned draw
+ draw_rect_tests(canvas);
+
+ // Repeat 4x with .2, .4, .6, .8 px offsets
+ canvas->translate(SK_Scalar1 / 5, SK_Scalar1 / 5);
+ canvas->translate(SkIntToScalar(50), 0);
+ draw_rect_tests(canvas);
+
+ canvas->translate(SK_Scalar1 / 5, SK_Scalar1 / 5);
+ canvas->translate(SkIntToScalar(50), 0);
+ draw_rect_tests(canvas);
+
+ canvas->translate(SK_Scalar1 / 5, SK_Scalar1 / 5);
+ canvas->translate(SkIntToScalar(50), 0);
+ draw_rect_tests(canvas);
+
+ canvas->translate(SK_Scalar1 / 5, SK_Scalar1 / 5);
+ canvas->translate(SkIntToScalar(50), 0);
+ draw_rect_tests(canvas);
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new AAClipGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/aarectmodes.cpp b/gm/aarectmodes.cpp
new file mode 100644
index 0000000..f518cae
--- /dev/null
+++ b/gm/aarectmodes.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+
+static void test4(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkPoint pts[] = {
+ {10, 160}, {610, 160},
+ {610, 160}, {10, 160},
+
+ {610, 160}, {610, 160},
+ {610, 199}, {610, 199},
+
+ {10, 198}, {610, 198},
+ {610, 199}, {10, 199},
+
+ {10, 160}, {10, 160},
+ {10, 199}, {10, 199}
+ };
+ char verbs[] = {
+ 0, 1, 1, 1, 4,
+ 0, 1, 1, 1, 4,
+ 0, 1, 1, 1, 4,
+ 0, 1, 1, 1, 4
+ };
+ SkPath path;
+ SkPoint* ptPtr = pts;
+ for (size_t i = 0; i < sizeof(verbs); ++i) {
+ switch ((SkPath::Verb) verbs[i]) {
+ case SkPath::kMove_Verb:
+ path.moveTo(ptPtr->fX, ptPtr->fY);
+ ++ptPtr;
+ break;
+ case SkPath::kLine_Verb:
+ path.lineTo(ptPtr->fX, ptPtr->fY);
+ ++ptPtr;
+ break;
+ case SkPath::kClose_Verb:
+ path.close();
+ break;
+ default:
+ SkASSERT(false);
+ break;
+ }
+ }
+ SkRect clip = {0, 130, 772, 531};
+ canvas->clipRect(clip);
+ canvas->drawPath(path, paint);
+}
+
+static SkCanvas* create_canvas(int w, int h) {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, w, h);
+ bm.allocPixels();
+ bm.eraseColor(0);
+ return new SkCanvas(bm);
+}
+
+static const SkBitmap& extract_bitmap(SkCanvas* canvas) {
+ return canvas->getDevice()->accessBitmap(false);
+}
+
+static const struct {
+ SkXfermode::Mode fMode;
+ const char* fLabel;
+} gModes[] = {
+ { SkXfermode::kClear_Mode, "Clear" },
+ { SkXfermode::kSrc_Mode, "Src" },
+ { SkXfermode::kDst_Mode, "Dst" },
+ { SkXfermode::kSrcOver_Mode, "SrcOver" },
+ { SkXfermode::kDstOver_Mode, "DstOver" },
+ { SkXfermode::kSrcIn_Mode, "SrcIn" },
+ { SkXfermode::kDstIn_Mode, "DstIn" },
+ { SkXfermode::kSrcOut_Mode, "SrcOut" },
+ { SkXfermode::kDstOut_Mode, "DstOut" },
+ { SkXfermode::kSrcATop_Mode, "SrcATop" },
+ { SkXfermode::kDstATop_Mode, "DstATop" },
+ { SkXfermode::kXor_Mode, "Xor" },
+};
+
+const int gWidth = 64;
+const int gHeight = 64;
+const SkScalar W = SkIntToScalar(gWidth);
+const SkScalar H = SkIntToScalar(gHeight);
+
+static SkScalar drawCell(SkCanvas* canvas, SkXfermode* mode,
+ SkAlpha a0, SkAlpha a1) {
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ SkRect r = SkRect::MakeWH(W, H);
+ r.inset(W/10, H/10);
+
+ paint.setColor(SK_ColorBLUE);
+ paint.setAlpha(a0);
+ canvas->drawOval(r, paint);
+
+ paint.setColor(SK_ColorRED);
+ paint.setAlpha(a1);
+ paint.setXfermode(mode);
+
+ SkScalar offset = SK_Scalar1 / 3;
+ SkRect rect = SkRect::MakeXYWH(W / 4 + offset,
+ H / 4 + offset,
+ W / 2, H / 2);
+ canvas->drawRect(rect, paint);
+
+ return H;
+}
+
+static SkShader* make_bg_shader() {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
+ bm.allocPixels();
+ *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = 0xFFFFFFFF;
+ *bm.getAddr32(1, 0) = *bm.getAddr32(0, 1) = SkPackARGB32(0xFF, 0xCC,
+ 0xCC, 0xCC);
+
+ SkShader* s = SkShader::CreateBitmapShader(bm,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+
+ SkMatrix m;
+ m.setScale(SkIntToScalar(6), SkIntToScalar(6));
+ s->setLocalMatrix(m);
+ return s;
+}
+
+namespace skiagm {
+
+ class AARectModesGM : public GM {
+ SkPaint fBGPaint;
+ public:
+ AARectModesGM () {
+ fBGPaint.setShader(make_bg_shader())->unref();
+ }
+
+ protected:
+
+ virtual SkString onShortName() {
+ return SkString("aarectmodes");
+ }
+
+ virtual SkISize onISize() { return make_isize(640, 480); }
+
+ virtual void onDraw(SkCanvas* canvas) {
+// test4(canvas);
+ const SkRect bounds = SkRect::MakeWH(W, H);
+ static const SkAlpha gAlphaValue[] = { 0xFF, 0x88, 0x88 };
+
+ canvas->translate(SkIntToScalar(4), SkIntToScalar(4));
+
+ for (int alpha = 0; alpha < 4; ++alpha) {
+ canvas->save();
+ canvas->save();
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); ++i) {
+ if (6 == i) {
+ canvas->restore();
+ canvas->translate(W * 5, 0);
+ canvas->save();
+ }
+ SkXfermode* mode = SkXfermode::Create(gModes[i].fMode);
+
+ canvas->drawRect(bounds, fBGPaint);
+ canvas->saveLayer(&bounds, NULL);
+ SkScalar dy = drawCell(canvas, mode,
+ gAlphaValue[alpha & 1],
+ gAlphaValue[alpha & 2]);
+ canvas->restore();
+
+ canvas->translate(0, dy * 5 / 4);
+ SkSafeUnref(mode);
+ }
+ canvas->restore();
+ canvas->restore();
+ canvas->translate(W * 5 / 4, 0);
+ }
+ }
+
+ // disable pdf for now, since it crashes on mac
+ virtual uint32_t onGetFlags() const { return kSkipPDF_Flag; }
+
+ private:
+ typedef GM INHERITED;
+ };
+
+//////////////////////////////////////////////////////////////////////////////
+
+ static GM* MyFactory(void*) { return new AARectModesGM; }
+ static GMRegistry reg(MyFactory);
+
+}
+
diff --git a/gm/arithmode.cpp b/gm/arithmode.cpp
new file mode 100644
index 0000000..ea015c6
--- /dev/null
+++ b/gm/arithmode.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+
+#include "SkArithmeticMode.h"
+#include "SkGradientShader.h"
+#define WW 100
+#define HH 32
+
+static SkBitmap make_bm() {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, WW, HH);
+ bm.allocPixels();
+ bm.eraseColor(0);
+ return bm;
+}
+
+static SkBitmap make_src() {
+ SkBitmap bm = make_bm();
+ SkCanvas canvas(bm);
+ SkPaint paint;
+ SkPoint pts[] = { {0, 0}, {SkIntToScalar(WW), SkIntToScalar(HH)} };
+ SkColor colors[] = {
+ SK_ColorBLACK, SK_ColorGREEN, SK_ColorCYAN,
+ SK_ColorRED, SK_ColorMAGENTA, SK_ColorWHITE
+ };
+ SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, SK_ARRAY_COUNT(colors),
+ SkShader::kClamp_TileMode);
+ paint.setShader(s)->unref();
+ canvas.drawPaint(paint);
+ return bm;
+}
+
+static SkBitmap make_dst() {
+ SkBitmap bm = make_bm();
+ SkCanvas canvas(bm);
+ SkPaint paint;
+ SkPoint pts[] = { {0, SkIntToScalar(HH)}, {SkIntToScalar(WW), 0} };
+ SkColor colors[] = {
+ SK_ColorBLUE, SK_ColorYELLOW, SK_ColorBLACK, SK_ColorGREEN, SK_ColorGRAY
+ };
+ SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, SK_ARRAY_COUNT(colors),
+ SkShader::kClamp_TileMode);
+ paint.setShader(s)->unref();
+ canvas.drawPaint(paint);
+ return bm;
+}
+
+static SkBitmap make_arith(const SkBitmap& src, const SkBitmap& dst,
+ const SkScalar k[]) {
+ SkBitmap bm = make_bm();
+ SkCanvas canvas(bm);
+ SkPaint paint;
+ canvas.drawBitmap(dst, 0, 0, NULL);
+ SkXfermode* xfer = SkArithmeticMode::Create(k[0], k[1], k[2], k[3]);
+ paint.setXfermode(xfer)->unref();
+ canvas.drawBitmap(src, 0, 0, &paint);
+ return bm;
+}
+
+static void show_k_text(SkCanvas* canvas, SkScalar x, SkScalar y, const SkScalar k[]) {
+ SkPaint paint;
+ paint.setTextSize(SkIntToScalar(24));
+ paint.setAntiAlias(true);
+ for (int i = 0; i < 4; ++i) {
+ SkString str;
+ str.appendScalar(k[i]);
+ SkScalar width = paint.measureText(str.c_str(), str.size());
+ canvas->drawText(str.c_str(), str.size(), x, y + paint.getTextSize(), paint);
+ x += width + SkIntToScalar(10);
+ }
+}
+
+class ArithmodeGM : public skiagm::GM {
+public:
+ ArithmodeGM () {}
+
+protected:
+
+ virtual SkString onShortName() {
+ return SkString("arithmode");
+ }
+
+ virtual SkISize onISize() { return SkISize::Make(640, 480); }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkBitmap src = make_src();
+ SkBitmap dst = make_dst();
+
+ const SkScalar one = SK_Scalar1;
+ static const SkScalar K[] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, one,
+ 0, one, 0, 0,
+ 0, 0, one, 0,
+ 0, one, one, 0,
+ 0, one, -one, 0,
+ 0, one/2, one/2, 0,
+ 0, one/2, one/2, one/4,
+ 0, one/2, one/2, -one/4,
+ one/4, one/2, one/2, 0,
+ -one/4, one/2, one/2, 0,
+ };
+
+ const SkScalar* k = K;
+ const SkScalar* stop = k + SK_ARRAY_COUNT(K);
+ SkScalar y = 0;
+ SkScalar x = 0;
+ SkScalar gap = SkIntToScalar(src.width() + 20);
+ while (k < stop) {
+ SkScalar x = 0;
+ SkBitmap res = make_arith(src, dst, k);
+ canvas->drawBitmap(src, x, y, NULL);
+ x += gap;
+ canvas->drawBitmap(dst, x, y, NULL);
+ x += gap;
+ canvas->drawBitmap(res, x, y, NULL);
+ x += gap;
+ show_k_text(canvas, x, y, k);
+ k += 4;
+ y += SkIntToScalar(src.height() + 12);
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static skiagm::GM* MyFactory(void*) { return new ArithmodeGM; }
+static skiagm::GMRegistry reg(MyFactory);
diff --git a/gm/bitmapcopy.cpp b/gm/bitmapcopy.cpp
new file mode 100644
index 0000000..249ec43
--- /dev/null
+++ b/gm/bitmapcopy.cpp
@@ -0,0 +1,121 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+
+namespace skiagm {
+
+static const char* gConfigNames[] = {
+ "unknown config",
+ "A1",
+ "A8",
+ "Index8",
+ "565",
+ "4444",
+ "8888"
+};
+
+SkBitmap::Config gConfigs[] = {
+ SkBitmap::kRGB_565_Config,
+ SkBitmap::kARGB_4444_Config,
+ SkBitmap::kARGB_8888_Config,
+};
+
+#define NUM_CONFIGS (sizeof(gConfigs) / sizeof(SkBitmap::Config))
+
+static void draw_checks(SkCanvas* canvas, int width, int height) {
+ SkPaint paint;
+ paint.setColor(SK_ColorRED);
+ canvas->drawRectCoords(0, 0, width / 2, height / 2, paint);
+ paint.setColor(SK_ColorGREEN);
+ canvas->drawRectCoords(width / 2, 0, width, height / 2, paint);
+ paint.setColor(SK_ColorBLUE);
+ canvas->drawRectCoords(0, height / 2, width / 2, height, paint);
+ paint.setColor(SK_ColorYELLOW);
+ canvas->drawRectCoords(width / 2, height / 2, width, height, paint);
+}
+
+class BitmapCopyGM : public GM {
+public:
+ SkBitmap fDst[NUM_CONFIGS];
+
+ BitmapCopyGM() {
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("bitmapcopy");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(540, 330);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+ SkScalar horizMargin(SkIntToScalar(10));
+ SkScalar vertMargin(SkIntToScalar(10));
+
+ draw_checks(canvas, 40, 40);
+ SkBitmap src = canvas->getDevice()->accessBitmap(false);
+
+ for (unsigned i = 0; i < NUM_CONFIGS; ++i) {
+ if (!src.deepCopyTo(&fDst[i], gConfigs[i])) {
+ src.copyTo(&fDst[i], gConfigs[i]);
+ }
+ }
+
+ canvas->clear(0xFFDDDDDD);
+ paint.setAntiAlias(true);
+ SkScalar width = SkIntToScalar(40);
+ SkScalar height = SkIntToScalar(40);
+ if (paint.getFontSpacing() > height) {
+ height = paint.getFontSpacing();
+ }
+ for (unsigned i = 0; i < NUM_CONFIGS; i++) {
+ const char* name = gConfigNames[src.config()];
+ SkScalar textWidth = paint.measureText(name, strlen(name));
+ if (textWidth > width) {
+ width = textWidth;
+ }
+ }
+ SkScalar horizOffset = width + horizMargin;
+ SkScalar vertOffset = height + vertMargin;
+ canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
+
+ for (unsigned i = 0; i < NUM_CONFIGS; i++) {
+ canvas->save();
+ // Draw destination config name
+ const char* name = gConfigNames[fDst[i].config()];
+ SkScalar textWidth = paint.measureText(name, strlen(name));
+ SkScalar x = (width - textWidth) / SkScalar(2);
+ SkScalar y = paint.getFontSpacing() / SkScalar(2);
+ canvas->drawText(name, strlen(name), x, y, paint);
+
+ // Draw destination bitmap
+ canvas->translate(0, vertOffset);
+ x = (width - 40) / SkScalar(2);
+ canvas->drawBitmap(fDst[i], x, 0, &paint);
+ canvas->restore();
+
+ canvas->translate(horizOffset, 0);
+ }
+ }
+
+ virtual uint32_t onGetFlags() const { return kSkipPicture_Flag; }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new BitmapCopyGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/bitmapfilters.cpp b/gm/bitmapfilters.cpp
index 3903913..cf98dcd 100644
--- a/gm/bitmapfilters.cpp
+++ b/gm/bitmapfilters.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "gm.h"
namespace skiagm {
@@ -79,6 +86,7 @@ public:
fBM8.copyTo(&fBM4444, SkBitmap::kARGB_4444_Config);
fBM8.copyTo(&fBM16, SkBitmap::kRGB_565_Config);
fBM8.copyTo(&fBM32, SkBitmap::kARGB_8888_Config);
+ this->setBGColor(0xFFDDDDDD);
}
protected:
@@ -91,7 +99,6 @@ protected:
}
virtual void onDraw(SkCanvas* canvas) {
- canvas->drawColor(0xFFDDDDDD);
SkScalar x = SkIntToScalar(10);
SkScalar y = SkIntToScalar(10);
diff --git a/gm/bitmapscroll.cpp b/gm/bitmapscroll.cpp
new file mode 100644
index 0000000..70d1052
--- /dev/null
+++ b/gm/bitmapscroll.cpp
@@ -0,0 +1,147 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+
+namespace skiagm {
+
+/** Create a bitmap image suitable for testing SkBitmap::scrollRect().
+ *
+ * @param quarterWidth bitmap will be 4x this many pixels wide
+ * @param quarterHeight bitmap will be 4x this many pixels tall
+ * @param bitmap the bitmap data is written into this object
+ */
+static void make_bitmap(int quarterWidth, int quarterHeight, SkBitmap *bitmap) {
+ SkPaint pRed, pWhite, pGreen, pBlue, pLine, pAlphaGray;
+ pRed.setColor(0xFFFF9999);
+ pWhite.setColor(0xFFFFFFFF);
+ pGreen.setColor(0xFF99FF99);
+ pBlue.setColor(0xFF9999FF);
+ pLine.setColor(0xFF000000);
+ pLine.setStyle(SkPaint::kStroke_Style);
+ pAlphaGray.setColor(0x66888888);
+
+ // Prepare bitmap, and a canvas that draws into it.
+ bitmap->reset();
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config,
+ quarterWidth*4, quarterHeight*4);
+ bitmap->allocPixels();
+ SkCanvas canvas(*bitmap);
+
+ SkScalar w = SkIntToScalar(quarterWidth);
+ SkScalar h = SkIntToScalar(quarterHeight);
+ canvas.drawRectCoords( 0, 0, w*2, h*2, pRed);
+ canvas.drawRectCoords(w*2, 0, w*4, h*2, pGreen);
+ canvas.drawRectCoords( 0, h*2, w*2, h*4, pBlue);
+ canvas.drawRectCoords(w*2, h*2, w*4, h*4, pWhite);
+ canvas.drawRectCoords(w, h, w*3, h*3, pAlphaGray);
+ canvas.drawLine(w*2, 0, w*2, h*4, pLine);
+ canvas.drawLine( 0, h*2, w*4, h*2, pLine);
+ canvas.drawRectCoords(w, h, w*3, h*3, pLine);
+}
+
+class BitmapScrollGM : public GM {
+public:
+ BitmapScrollGM() {
+ // Create the original bitmap.
+ make_bitmap(quarterWidth, quarterHeight, &origBitmap);
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("bitmapscroll");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(800, 600);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkIRect scrollCenterRegion = SkIRect::MakeXYWH(
+ quarterWidth, quarterHeight, quarterWidth*2+1, quarterHeight*2+1);
+ int x = quarterWidth;
+ int y = quarterHeight;
+ int xSpacing = quarterWidth * 20;
+ int ySpacing = quarterHeight * 16;
+
+ // Draw left-hand text labels.
+ drawLabel(canvas, "scroll entire bitmap",
+ x, y, x, y + ySpacing);
+ drawLabel(canvas, "scroll part of bitmap",
+ x, y + ySpacing, x, y + ySpacing*2);
+ x += 30;
+
+ // Draw various permutations of scrolled bitmaps, scrolling a bit
+ // further each time.
+ draw9(canvas, x, y, NULL, quarterWidth*1/2, quarterHeight*1/2);
+ draw9(canvas, x, y+ySpacing, &scrollCenterRegion,
+ quarterWidth*1/2, quarterHeight*1/2);
+ x += xSpacing;
+ draw9(canvas, x, y, NULL, quarterWidth*3/2, quarterHeight*3/2);
+ draw9(canvas, x, y+ySpacing, &scrollCenterRegion,
+ quarterWidth*3/2, quarterHeight*3/2);
+ x += xSpacing;
+ draw9(canvas, x, y, NULL, quarterWidth*5/2, quarterHeight*5/2);
+ draw9(canvas, x, y+ySpacing, &scrollCenterRegion,
+ quarterWidth*5/2, quarterHeight*5/2);
+ x += xSpacing;
+ draw9(canvas, x, y, NULL, quarterWidth*9/2, quarterHeight*9/2);
+ draw9(canvas, x, y+ySpacing, &scrollCenterRegion,
+ quarterWidth*9/2, quarterHeight*9/2);
+ }
+
+ void drawLabel(SkCanvas* canvas, const char *text, int startX, int startY,
+ int endX, int endY) {
+ SkPaint paint;
+ paint.setColor(0xFF000000);
+ SkPath path;
+ path.moveTo(SkIntToScalar(startX), SkIntToScalar(startY));
+ path.lineTo(SkIntToScalar(endX), SkIntToScalar(endY));
+ canvas->drawTextOnPath(text, strlen(text), path, NULL, paint);
+ }
+
+ /** Stamp out 9 copies of origBitmap, scrolled in each direction (and
+ * not scrolled at all).
+ */
+ void draw9(SkCanvas* canvas, int x, int y, SkIRect* subset,
+ int scrollX, int scrollY) {
+ for (int yMult=-1; yMult<=1; yMult++) {
+ for (int xMult=-1; xMult<=1; xMult++) {
+ // Figure out the (x,y) to draw this copy at
+ SkScalar bitmapX = SkIntToScalar(
+ x + quarterWidth * 5 * (xMult+1));
+ SkScalar bitmapY = SkIntToScalar(
+ y + quarterHeight * 5 * (yMult+1));
+
+ // Scroll a new copy of the bitmap, and then draw it.
+ // scrollRect() should always return true, even if it's a no-op
+ SkBitmap scrolledBitmap;
+ bool copyToReturnValue = origBitmap.copyTo(
+ &scrolledBitmap, origBitmap.config());
+ SkASSERT(copyToReturnValue);
+ bool scrollRectReturnValue = scrolledBitmap.scrollRect(
+ subset, scrollX * xMult, scrollY * yMult);
+ SkASSERT(scrollRectReturnValue);
+ canvas->drawBitmap(scrolledBitmap, bitmapX, bitmapY);
+ }
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+ static const int quarterWidth = 10;
+ static const int quarterHeight = 14;
+ SkBitmap origBitmap;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new BitmapScrollGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/blurs.cpp b/gm/blurs.cpp
index c934178..69504f7 100644
--- a/gm/blurs.cpp
+++ b/gm/blurs.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "gm.h"
#include "SkBlurMaskFilter.h"
@@ -5,7 +12,9 @@ namespace skiagm {
class BlursGM : public GM {
public:
- BlursGM() {}
+ BlursGM() {
+ this->setBGColor(0xFFDDDDDD);
+ }
protected:
virtual SkString onShortName() {
@@ -16,13 +25,7 @@ protected:
return make_isize(700, 500);
}
- void drawBG(SkCanvas* canvas) {
- canvas->drawColor(0xFFDDDDDD);
- }
-
virtual void onDraw(SkCanvas* canvas) {
- drawBG(canvas);
-
SkBlurMaskFilter::BlurStyle NONE = SkBlurMaskFilter::BlurStyle(-999);
static const struct {
SkBlurMaskFilter::BlurStyle fStyle;
diff --git a/gm/colormatrix.cpp b/gm/colormatrix.cpp
new file mode 100644
index 0000000..0a4acfd
--- /dev/null
+++ b/gm/colormatrix.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkColorMatrixFilter.h"
+
+#define WIDTH 500
+#define HEIGHT 500
+
+namespace skiagm {
+
+class ColorMatrixGM : public GM {
+public:
+ ColorMatrixGM() {
+ this->setBGColor(0xFF808080);
+ fBitmap = createBitmap(64, 64);
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("colormatrix");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(WIDTH, HEIGHT);
+ }
+
+ SkBitmap createBitmap(int width, int height) {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+ bm.allocPixels();
+ SkCanvas canvas(bm);
+ canvas.clear(0x0);
+ for (int y = 0; y < height; ++y) {
+ for (int x = 0; x < width; ++x) {
+ SkPaint paint;
+ paint.setColor(SkColorSetARGB(255, x * 255 / width, y * 255 / height, 0));
+ canvas.drawRect(SkRect::MakeXYWH(x, y, 1, 1), paint);
+ }
+ }
+ return bm;
+ }
+ virtual void onDraw(SkCanvas* canvas) {
+
+ SkPaint paint;
+ SkColorMatrix matrix;
+ SkColorMatrixFilter* filter = new SkColorMatrixFilter();
+ paint.setColorFilter(filter)->unref();
+
+ matrix.setIdentity();
+ filter->setMatrix(matrix);
+ canvas->drawBitmap(fBitmap, 0, 0, &paint);
+
+ matrix.setRotate(SkColorMatrix::kR_Axis, 90);
+ filter->setMatrix(matrix);
+ canvas->drawBitmap(fBitmap, 80, 0, &paint);
+
+ matrix.setRotate(SkColorMatrix::kG_Axis, 90);
+ filter->setMatrix(matrix);
+ canvas->drawBitmap(fBitmap, 160, 0, &paint);
+
+ matrix.setRotate(SkColorMatrix::kB_Axis, 90);
+ filter->setMatrix(matrix);
+ canvas->drawBitmap(fBitmap, 240, 0, &paint);
+
+ matrix.setSaturation(SkFloatToScalar(0.0f));
+ filter->setMatrix(matrix);
+ canvas->drawBitmap(fBitmap, 0, 80, &paint);
+
+ matrix.setSaturation(SkFloatToScalar(0.5f));
+ filter->setMatrix(matrix);
+ canvas->drawBitmap(fBitmap, 80, 80, &paint);
+
+ matrix.setSaturation(SkFloatToScalar(1.0f));
+ filter->setMatrix(matrix);
+ canvas->drawBitmap(fBitmap, 160, 80, &paint);
+
+ matrix.setSaturation(SkFloatToScalar(2.0f));
+ filter->setMatrix(matrix);
+ canvas->drawBitmap(fBitmap, 240, 80, &paint);
+
+ matrix.setRGB2YUV();
+ filter->setMatrix(matrix);
+ canvas->drawBitmap(fBitmap, 0, 160, &paint);
+
+ matrix.setYUV2RGB();
+ filter->setMatrix(matrix);
+ canvas->drawBitmap(fBitmap, 80, 160, &paint);
+
+ SkScalar s1 = SK_Scalar1;
+ SkScalar s255 = SkIntToScalar(255);
+ // Move red into alpha, set color to white
+ SkScalar data[20] = {
+ 0, 0, 0, 0, s255,
+ 0, 0, 0, 0, s255,
+ 0, 0, 0, 0, s255,
+ s1, 0, 0, 0, 0,
+ };
+
+ filter->setArray(data);
+ canvas->drawBitmap(fBitmap, 160, 160, &paint);
+ }
+
+private:
+ SkBitmap fBitmap;
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new ColorMatrixGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/complexclip.cpp b/gm/complexclip.cpp
index 867d230..30bb50b 100644
--- a/gm/complexclip.cpp
+++ b/gm/complexclip.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "gm.h"
#include "SkCanvas.h"
//#include "SkParsePath.h"
@@ -6,22 +13,27 @@
namespace skiagm {
+static const SkColor gPathColor = SK_ColorBLACK;
+static const SkColor gClipAColor = SK_ColorBLUE;
+static const SkColor gClipBColor = SK_ColorRED;
+
class ComplexClipGM : public GM {
+ bool fDoAAClip;
public:
- ComplexClipGM() {
+ ComplexClipGM(bool aaclip) : fDoAAClip(aaclip) {
+ this->setBGColor(0xFFDDDDDD);
+// this->setBGColor(SkColorSetRGB(0xB0,0xDD,0xB0));
}
protected:
SkString onShortName() {
- return SkString("complexclip");
+ SkString str;
+ str.printf("complexclip_%s", fDoAAClip ? "aa" : "bw");
+ return str;
}
- SkISize onISize() { return make_isize(550, 1000); }
-
- void drawBG(SkCanvas* canvas) {
- canvas->drawColor(SkColorSetRGB(0xA0,0xDD,0xA0));
- }
+ SkISize onISize() { return make_isize(970, 780); }
virtual void onDraw(SkCanvas* canvas) {
SkPath path;
@@ -40,10 +52,9 @@ protected:
path.lineTo(SkIntToScalar(50), SkIntToScalar(150));
path.close();
path.setFillType(SkPath::kEvenOdd_FillType);
- SkColor pathColor = SK_ColorBLACK;
SkPaint pathPaint;
pathPaint.setAntiAlias(true);
- pathPaint.setColor(pathColor);
+ pathPaint.setColor(gPathColor);
SkPath clipA;
clipA.moveTo(SkIntToScalar(10), SkIntToScalar(20));
@@ -52,7 +63,6 @@ protected:
clipA.lineTo(SkIntToScalar(165), SkIntToScalar(177));
clipA.lineTo(SkIntToScalar(-5), SkIntToScalar(180));
clipA.close();
- SkColor colorA = SK_ColorCYAN;
SkPath clipB;
clipB.moveTo(SkIntToScalar(40), SkIntToScalar(10));
@@ -61,21 +71,10 @@ protected:
clipB.lineTo(SkIntToScalar(40), SkIntToScalar(185));
clipB.lineTo(SkIntToScalar(155), SkIntToScalar(100));
clipB.close();
- SkColor colorB = SK_ColorRED;
- drawBG(canvas);
SkPaint paint;
paint.setAntiAlias(true);
-
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setStrokeWidth(0);
-
- canvas->translate(SkIntToScalar(10),SkIntToScalar(10));
- canvas->drawPath(path, pathPaint);
- paint.setColor(colorA);
- canvas->drawPath(clipA, paint);
- paint.setColor(colorB);
- canvas->drawPath(clipB, paint);
+ paint.setTextSize(SkIntToScalar(20));
static const struct {
SkRegion::Op fOp;
@@ -88,65 +87,77 @@ protected:
{SkRegion::kReverseDifference_Op, "RDiff "}
};
- canvas->translate(0, SkIntToScalar(40));
+ canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
canvas->scale(3 * SK_Scalar1 / 4, 3 * SK_Scalar1 / 4);
- canvas->save();
- for (int invA = 0; invA < 2; ++invA) {
+ for (int invBits = 0; invBits < 4; ++invBits) {
+ canvas->save();
for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); ++op) {
- int idx = invA * SK_ARRAY_COUNT(gOps) + op;
- if (!(idx % 3)) {
- canvas->restore();
- canvas->translate(0, SkIntToScalar(250));
- canvas->save();
- }
+ this->drawHairlines(canvas, path, clipA, clipB);
+
+ bool doInvA = SkToBool(invBits & 1);
+ bool doInvB = SkToBool(invBits & 2);
canvas->save();
// set clip
- clipA.setFillType(invA ? SkPath::kInverseEvenOdd_FillType :
- SkPath::kEvenOdd_FillType);
- canvas->clipPath(clipA);
- canvas->clipPath(clipB, gOps[op].fOp);
+ clipA.setFillType(doInvA ? SkPath::kInverseEvenOdd_FillType :
+ SkPath::kEvenOdd_FillType);
+ clipB.setFillType(doInvB ? SkPath::kInverseEvenOdd_FillType :
+ SkPath::kEvenOdd_FillType);
+ canvas->clipPath(clipA, SkRegion::kIntersect_Op, fDoAAClip);
+ canvas->clipPath(clipB, gOps[op].fOp, fDoAAClip);
// draw path clipped
canvas->drawPath(path, pathPaint);
canvas->restore();
- // draw path in hairline
- paint.setColor(pathColor);
- canvas->drawPath(path, paint);
- // draw clips in hair line
- paint.setColor(colorA);
- canvas->drawPath(clipA, paint);
- paint.setColor(colorB);
- canvas->drawPath(clipB, paint);
-
- paint.setTextSize(SkIntToScalar(20));
-
- SkScalar txtX = SkIntToScalar(55);
- paint.setColor(colorA);
- const char* aTxt = invA ? "InverseA " : "A ";
+ SkScalar txtX = SkIntToScalar(45);
+ paint.setColor(gClipAColor);
+ const char* aTxt = doInvA ? "InvA " : "A ";
canvas->drawText(aTxt, strlen(aTxt), txtX, SkIntToScalar(220), paint);
txtX += paint.measureText(aTxt, strlen(aTxt));
paint.setColor(SK_ColorBLACK);
canvas->drawText(gOps[op].fName, strlen(gOps[op].fName),
txtX, SkIntToScalar(220), paint);
txtX += paint.measureText(gOps[op].fName, strlen(gOps[op].fName));
- paint.setColor(colorB);
- canvas->drawText("B", 1, txtX, SkIntToScalar(220), paint);
+ paint.setColor(gClipBColor);
+ const char* bTxt = doInvB ? "InvB " : "B ";
+ canvas->drawText(bTxt, strlen(bTxt), txtX, SkIntToScalar(220), paint);
canvas->translate(SkIntToScalar(250),0);
}
+ canvas->restore();
+ canvas->translate(0, SkIntToScalar(250));
}
- canvas->restore();
}
private:
+ void drawHairlines(SkCanvas* canvas, const SkPath& path,
+ const SkPath& clipA, const SkPath& clipB) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ const SkAlpha fade = 0x33;
+
+ // draw path in hairline
+ paint.setColor(gPathColor); paint.setAlpha(fade);
+ canvas->drawPath(path, paint);
+
+ // draw clips in hair line
+ paint.setColor(gClipAColor); paint.setAlpha(fade);
+ canvas->drawPath(clipA, paint);
+ paint.setColor(gClipBColor); paint.setAlpha(fade);
+ canvas->drawPath(clipB, paint);
+ }
+
typedef GM INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
-static GM* MyFactory(void*) { return new ComplexClipGM; }
-static GMRegistry reg(MyFactory);
+static GM* gFact0(void*) { return new ComplexClipGM(false); }
+static GM* gFact1(void*) { return new ComplexClipGM(true); }
+
+static GMRegistry gReg0(gFact0);
+static GMRegistry gReg1(gFact1);
}
diff --git a/gm/complexclip2.cpp b/gm/complexclip2.cpp
new file mode 100644
index 0000000..d6b653e
--- /dev/null
+++ b/gm/complexclip2.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+
+namespace skiagm {
+
+class ComplexClip2GM : public GM {
+public:
+ ComplexClip2GM() {
+ this->setBGColor(SkColorSetRGB(0xDD,0xA0,0xDD));
+
+ SkScalar xA = 0 * SK_Scalar1;
+ SkScalar xB = 10 * SK_Scalar1;
+ SkScalar xC = 20 * SK_Scalar1;
+ SkScalar xD = 30 * SK_Scalar1;
+ SkScalar xE = 40 * SK_Scalar1;
+ SkScalar xF = 50 * SK_Scalar1;
+
+ SkScalar yA = 0 * SK_Scalar1;
+ SkScalar yB = 10 * SK_Scalar1;
+ SkScalar yC = 20 * SK_Scalar1;
+ SkScalar yD = 30 * SK_Scalar1;
+ SkScalar yE = 40 * SK_Scalar1;
+ SkScalar yF = 50 * SK_Scalar1;
+
+ fWidth = xF - xA;
+ fHeight = yF - yA;
+
+ fRects[0].set(xB, yB, xE, yE);
+ fRectColors[0] = SK_ColorRED;
+
+ fRects[1].set(xA, yA, xD, yD);
+ fRectColors[1] = SK_ColorGREEN;
+
+ fRects[2].set(xC, yA, xF, yD);
+ fRectColors[2] = SK_ColorBLUE;
+
+ fRects[3].set(xA, yC, xD, yF);
+ fRectColors[3] = SK_ColorYELLOW;
+
+ fRects[4].set(xC, yC, xF, yF);
+ fRectColors[4] = SK_ColorCYAN;
+
+ fTotalWidth = kCols * fWidth + SK_Scalar1 * (kCols + 1) * kPadX;
+ fTotalHeight = kRows * fHeight + SK_Scalar1 * (kRows + 1) * kPadY;
+
+ SkRegion::Op ops[] = {
+ SkRegion::kDifference_Op,
+ SkRegion::kIntersect_Op,
+ SkRegion::kUnion_Op,
+ SkRegion::kXOR_Op,
+ SkRegion::kReverseDifference_Op,
+ SkRegion::kReplace_Op,
+ };
+
+ SkRandom r;
+ for (int i = 0; i < kRows; ++i) {
+ for (int j = 0; j < kCols; ++j) {
+ for (int k = 0; k < 5; ++k) {
+ fOps[j*kRows+i][k] = ops[r.nextU() % SK_ARRAY_COUNT(ops)];
+ }
+ }
+ }
+ }
+
+protected:
+
+ static const int kRows = 5;
+ static const int kCols = 5;
+ static const int kPadX = 20;
+ static const int kPadY = 20;
+
+ virtual SkString onShortName() {
+ return SkString("complexclip2");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(SkScalarRoundToInt(fTotalWidth),
+ SkScalarRoundToInt(fTotalHeight));
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint rectPaint;
+ rectPaint.setStyle(SkPaint::kStroke_Style);
+ rectPaint.setStrokeWidth(-1);
+
+ SkPaint fillPaint;
+ fillPaint.setColor(SkColorSetRGB(0xA0,0xDD,0xA0));
+
+ for (int i = 0; i < kRows; ++i) {
+ for (int j = 0; j < kCols; ++j) {
+ canvas->save();
+ canvas->translate(kPadX * SK_Scalar1 + (fWidth + kPadX * SK_Scalar1)*j,
+ kPadY * SK_Scalar1 + (fHeight + kPadY * SK_Scalar1)*i);
+ canvas->save();
+ for (int k = 0; k < 5; ++k) {
+ canvas->clipRect(fRects[k], fOps[j*kRows+i][k]);
+ }
+ canvas->drawRect(SkRect::MakeWH(fWidth, fHeight), fillPaint);
+ canvas->restore();
+ for (int k = 0; k < 5; ++k) {
+ rectPaint.setColor(fRectColors[k]);
+ canvas->drawRect(fRects[k], rectPaint);
+ }
+ canvas->restore();
+ }
+ }
+ }
+private:
+ SkRect fRects[5];
+ SkColor fRectColors[5];
+ SkRegion::Op fOps[kRows * kCols][5];
+ SkScalar fWidth;
+ SkScalar fHeight;
+ SkScalar fTotalWidth;
+ SkScalar fTotalHeight;
+
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new ComplexClip2GM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/cubicpaths.cpp b/gm/cubicpaths.cpp
new file mode 100644
index 0000000..7cd3df1
--- /dev/null
+++ b/gm/cubicpaths.cpp
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+
+namespace skiagm {
+
+class CubicPathGM : public GM {
+public:
+ CubicPathGM() {}
+
+protected:
+ SkString onShortName() {
+ return SkString("cubicpath");
+ }
+
+ SkISize onISize() { return make_isize(1240, 390); }
+
+ void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+ const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
+ SkPaint::Style style, SkPath::FillType fill,
+ SkScalar strokeWidth) {
+ path.setFillType(fill);
+ SkPaint paint;
+ paint.setStrokeCap(cap);
+ paint.setStrokeWidth(strokeWidth);
+ paint.setStrokeJoin(join);
+ paint.setColor(color);
+ paint.setStyle(style);
+ canvas->save();
+ canvas->clipRect(clip);
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ struct FillAndName {
+ SkPath::FillType fFill;
+ const char* fName;
+ };
+ static const FillAndName gFills[] = {
+ {SkPath::kWinding_FillType, "Winding"},
+ {SkPath::kEvenOdd_FillType, "Even / Odd"},
+ {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+ {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+ };
+ struct StyleAndName {
+ SkPaint::Style fStyle;
+ const char* fName;
+ };
+ static const StyleAndName gStyles[] = {
+ {SkPaint::kFill_Style, "Fill"},
+ {SkPaint::kStroke_Style, "Stroke"},
+ {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+ };
+ struct CapAndName {
+ SkPaint::Cap fCap;
+ SkPaint::Join fJoin;
+ const char* fName;
+ };
+ static const CapAndName gCaps[] = {
+ {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+ {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+ {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
+ };
+ struct PathAndName {
+ SkPath fPath;
+ const char* fName;
+ };
+ PathAndName path;
+ path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
+ path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
+ 60*SK_Scalar1, 20*SK_Scalar1,
+ 75*SK_Scalar1, 10*SK_Scalar1);
+ path.fName = "moveTo-cubic";
+
+ SkPaint titlePaint;
+ titlePaint.setColor(SK_ColorBLACK);
+ titlePaint.setAntiAlias(true);
+ titlePaint.setLCDRenderText(true);
+ titlePaint.setTextSize(15 * SK_Scalar1);
+ const char title[] = "Cubic Drawn Into Rectangle Clips With "
+ "Indicated Style, Fill and Linecaps, with stroke width 10";
+ canvas->drawText(title, strlen(title),
+ 20 * SK_Scalar1,
+ 20 * SK_Scalar1,
+ titlePaint);
+
+ SkRandom rand;
+ SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+ canvas->save();
+ canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+ canvas->save();
+ for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+ if (0 < cap) {
+ canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+ }
+ canvas->save();
+ for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+ if (0 < fill) {
+ canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+ }
+ canvas->save();
+ for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+ if (0 < style) {
+ canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
+ }
+
+ SkColor color = 0xff007000;
+ this->drawPath(path.fPath, canvas, color, rect,
+ gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+ gFills[fill].fFill, SK_Scalar1*10);
+
+ SkPaint rectPaint;
+ rectPaint.setColor(SK_ColorBLACK);
+ rectPaint.setStyle(SkPaint::kStroke_Style);
+ rectPaint.setStrokeWidth(-1);
+ rectPaint.setAntiAlias(true);
+ canvas->drawRect(rect, rectPaint);
+
+ SkPaint labelPaint;
+ labelPaint.setColor(color);
+ labelPaint.setAntiAlias(true);
+ labelPaint.setLCDRenderText(true);
+ labelPaint.setTextSize(10 * SK_Scalar1);
+ canvas->drawText(gStyles[style].fName,
+ strlen(gStyles[style].fName),
+ 0, rect.height() + 12 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gFills[fill].fName,
+ strlen(gFills[fill].fName),
+ 0, rect.height() + 24 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gCaps[cap].fName,
+ strlen(gCaps[cap].fName),
+ 0, rect.height() + 36 * SK_Scalar1,
+ labelPaint);
+ }
+ canvas->restore();
+ }
+ canvas->restore();
+ }
+ canvas->restore();
+ canvas->restore();
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+class CubicClosePathGM : public GM {
+public:
+ CubicClosePathGM() {}
+
+protected:
+ SkString onShortName() {
+ return SkString("cubicclosepath");
+ }
+
+ SkISize onISize() { return make_isize(1240, 390); }
+
+ void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+ const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
+ SkPaint::Style style, SkPath::FillType fill,
+ SkScalar strokeWidth) {
+ path.setFillType(fill);
+ SkPaint paint;
+ paint.setStrokeCap(cap);
+ paint.setStrokeWidth(strokeWidth);
+ paint.setStrokeJoin(join);
+ paint.setColor(color);
+ paint.setStyle(style);
+ canvas->save();
+ canvas->clipRect(clip);
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ struct FillAndName {
+ SkPath::FillType fFill;
+ const char* fName;
+ };
+ static const FillAndName gFills[] = {
+ {SkPath::kWinding_FillType, "Winding"},
+ {SkPath::kEvenOdd_FillType, "Even / Odd"},
+ {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+ {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+ };
+ struct StyleAndName {
+ SkPaint::Style fStyle;
+ const char* fName;
+ };
+ static const StyleAndName gStyles[] = {
+ {SkPaint::kFill_Style, "Fill"},
+ {SkPaint::kStroke_Style, "Stroke"},
+ {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+ };
+ struct CapAndName {
+ SkPaint::Cap fCap;
+ SkPaint::Join fJoin;
+ const char* fName;
+ };
+ static const CapAndName gCaps[] = {
+ {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+ {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+ {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
+ };
+ struct PathAndName {
+ SkPath fPath;
+ const char* fName;
+ };
+ PathAndName path;
+ path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
+ path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
+ 60*SK_Scalar1, 20*SK_Scalar1,
+ 75*SK_Scalar1, 10*SK_Scalar1);
+ path.fPath.close();
+ path.fName = "moveTo-cubic-close";
+
+ SkPaint titlePaint;
+ titlePaint.setColor(SK_ColorBLACK);
+ titlePaint.setAntiAlias(true);
+ titlePaint.setLCDRenderText(true);
+ titlePaint.setTextSize(15 * SK_Scalar1);
+ const char title[] = "Cubic Closed Drawn Into Rectangle Clips With "
+ "Indicated Style, Fill and Linecaps, with stroke width 10";
+ canvas->drawText(title, strlen(title),
+ 20 * SK_Scalar1,
+ 20 * SK_Scalar1,
+ titlePaint);
+
+ SkRandom rand;
+ SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+ canvas->save();
+ canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+ canvas->save();
+ for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+ if (0 < cap) {
+ canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+ }
+ canvas->save();
+ for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+ if (0 < fill) {
+ canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+ }
+ canvas->save();
+ for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+ if (0 < style) {
+ canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
+ }
+
+ SkColor color = 0xff007000;
+ this->drawPath(path.fPath, canvas, color, rect,
+ gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+ gFills[fill].fFill, SK_Scalar1*10);
+
+ SkPaint rectPaint;
+ rectPaint.setColor(SK_ColorBLACK);
+ rectPaint.setStyle(SkPaint::kStroke_Style);
+ rectPaint.setStrokeWidth(-1);
+ rectPaint.setAntiAlias(true);
+ canvas->drawRect(rect, rectPaint);
+
+ SkPaint labelPaint;
+ labelPaint.setColor(color);
+ labelPaint.setAntiAlias(true);
+ labelPaint.setLCDRenderText(true);
+ labelPaint.setTextSize(10 * SK_Scalar1);
+ canvas->drawText(gStyles[style].fName,
+ strlen(gStyles[style].fName),
+ 0, rect.height() + 12 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gFills[fill].fName,
+ strlen(gFills[fill].fName),
+ 0, rect.height() + 24 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gCaps[cap].fName,
+ strlen(gCaps[cap].fName),
+ 0, rect.height() + 36 * SK_Scalar1,
+ labelPaint);
+ }
+ canvas->restore();
+ }
+ canvas->restore();
+ }
+ canvas->restore();
+ canvas->restore();
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* CubicPathFactory(void*) { return new CubicPathGM; }
+static GMRegistry regCubicPath(CubicPathFactory);
+
+static GM* CubicClosePathFactory(void*) { return new CubicClosePathGM; }
+static GMRegistry regCubicClosePath(CubicClosePathFactory);
+
+}
diff --git a/gm/degeneratesegments.cpp b/gm/degeneratesegments.cpp
new file mode 100644
index 0000000..63d9dba
--- /dev/null
+++ b/gm/degeneratesegments.cpp
@@ -0,0 +1,400 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+
+namespace skiagm {
+
+class DegenerateSegmentsGM : public GM {
+public:
+ DegenerateSegmentsGM() {}
+
+protected:
+ struct PathAndName {
+ SkPath fPath;
+ const char* fName1;
+ const char* fName2;
+ };
+
+ SkString onShortName() {
+ return SkString("degeneratesegments");
+ }
+
+ SkISize onISize() { return make_isize(896, 930); }
+
+ typedef SkPoint (*AddSegmentFunc)(SkPath&, SkPoint&);
+
+ // We need to use explicit commands here, instead of addPath, because we
+ // do not want the moveTo that is added at the beginning of a path to
+ // appear in the appended path.
+ static SkPoint AddMove(SkPath& path, SkPoint& startPt) {
+ SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
+ path.moveTo(moveToPt);
+ return moveToPt;
+ }
+
+ static SkPoint AddMoveClose(SkPath& path, SkPoint& startPt) {
+ SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
+ path.moveTo(moveToPt);
+ path.close();
+ return moveToPt;
+ }
+
+ static SkPoint AddDegenLine(SkPath& path, SkPoint& startPt) {
+ path.lineTo(startPt);
+ return startPt;
+ }
+
+ static SkPoint AddMoveDegenLine(SkPath& path, SkPoint& startPt) {
+ SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
+ path.moveTo(moveToPt);
+ path.lineTo(moveToPt);
+ return moveToPt;
+ }
+
+ static SkPoint AddMoveDegenLineClose(SkPath& path, SkPoint& startPt) {
+ SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
+ path.moveTo(moveToPt);
+ path.lineTo(moveToPt);
+ path.close();
+ return moveToPt;
+ }
+
+ static SkPoint AddDegenQuad(SkPath& path, SkPoint& startPt) {
+ path.quadTo(startPt, startPt);
+ return startPt;
+ }
+
+ static SkPoint AddMoveDegenQuad(SkPath& path, SkPoint& startPt) {
+ SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
+ path.moveTo(moveToPt);
+ path.quadTo(moveToPt, moveToPt);
+ return moveToPt;
+ }
+
+ static SkPoint AddMoveDegenQuadClose(SkPath& path, SkPoint& startPt) {
+ SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
+ path.moveTo(moveToPt);
+ path.quadTo(moveToPt, moveToPt);
+ path.close();
+ return moveToPt;
+ }
+
+ static SkPoint AddDegenCubic(SkPath& path, SkPoint& startPt) {
+ path.cubicTo(startPt, startPt, startPt);
+ return startPt;
+ }
+
+ static SkPoint AddMoveDegenCubic(SkPath& path, SkPoint& startPt) {
+ SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
+ path.moveTo(moveToPt);
+ path.cubicTo(moveToPt, moveToPt, moveToPt);
+ return moveToPt;
+ }
+
+ static SkPoint AddMoveDegenCubicClose(SkPath& path, SkPoint& startPt) {
+ SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
+ path.moveTo(moveToPt);
+ path.cubicTo(moveToPt, moveToPt, moveToPt);
+ path.close();
+ return moveToPt;
+ }
+
+ static SkPoint AddClose(SkPath& path, SkPoint& startPt) {
+ path.close();
+ return startPt;
+ }
+
+ static SkPoint AddLine(SkPath& path, SkPoint& startPt) {
+ SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
+ path.lineTo(endPt);
+ return endPt;
+ }
+
+ static SkPoint AddMoveLine(SkPath& path, SkPoint& startPt) {
+ SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
+ SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
+ path.moveTo(moveToPt);
+ path.lineTo(endPt);
+ return endPt;
+ }
+
+ static SkPoint AddMoveLineClose(SkPath& path, SkPoint& startPt) {
+ SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
+ SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
+ path.moveTo(moveToPt);
+ path.lineTo(endPt);
+ path.close();
+ return endPt;
+ }
+
+ static SkPoint AddQuad(SkPath& path, SkPoint& startPt) {
+ SkPoint midPt = startPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
+ SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
+ path.quadTo(midPt, endPt);
+ return endPt;
+ }
+
+ static SkPoint AddMoveQuad(SkPath& path, SkPoint& startPt) {
+ SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
+ SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
+ SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
+ path.moveTo(moveToPt);
+ path.quadTo(midPt, endPt);
+ return endPt;
+ }
+
+ static SkPoint AddMoveQuadClose(SkPath& path, SkPoint& startPt) {
+ SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
+ SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
+ SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
+ path.moveTo(moveToPt);
+ path.quadTo(midPt, endPt);
+ path.close();
+ return endPt;
+ }
+
+ static SkPoint AddCubic(SkPath& path, SkPoint& startPt) {
+ SkPoint t1Pt = startPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
+ SkPoint t2Pt = startPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
+ SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
+ path.cubicTo(t1Pt, t2Pt, endPt);
+ return endPt;
+ }
+
+ static SkPoint AddMoveCubic(SkPath& path, SkPoint& startPt) {
+ SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
+ SkPoint t1Pt = moveToPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
+ SkPoint t2Pt = moveToPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
+ SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
+ path.moveTo(moveToPt);
+ path.cubicTo(t1Pt, t2Pt, endPt);
+ return endPt;
+ }
+
+ static SkPoint AddMoveCubicClose(SkPath& path, SkPoint& startPt) {
+ SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
+ SkPoint t1Pt = moveToPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
+ SkPoint t2Pt = moveToPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
+ SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
+ path.moveTo(moveToPt);
+ path.cubicTo(t1Pt, t2Pt, endPt);
+ path.close();
+ return endPt;
+ }
+
+ void drawPath(SkPath& path, SkCanvas* canvas, SkColor color,
+ const SkRect& clip, SkPaint::Cap cap, SkPaint::Join join,
+ SkPaint::Style style, SkPath::FillType fill,
+ SkScalar strokeWidth) {
+ path.setFillType(fill);
+ SkPaint paint;
+ paint.setStrokeCap(cap);
+ paint.setStrokeWidth(strokeWidth);
+ paint.setStrokeJoin(join);
+ paint.setColor(color);
+ paint.setStyle(style);
+ canvas->save();
+ canvas->clipRect(clip);
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ static const AddSegmentFunc gSegmentFunctions[] = {
+ AddMove,
+ AddMoveClose,
+ AddDegenLine,
+ AddMoveDegenLine,
+ AddMoveDegenLineClose,
+ AddDegenQuad,
+ AddMoveDegenQuad,
+ AddMoveDegenQuadClose,
+ AddDegenCubic,
+ AddMoveDegenCubic,
+ AddMoveDegenCubicClose,
+ AddClose,
+ AddLine,
+ AddMoveLine,
+ AddMoveLineClose,
+ AddQuad,
+ AddMoveQuad,
+ AddMoveQuadClose,
+ AddCubic,
+ AddMoveCubic,
+ AddMoveCubicClose
+ };
+ static const char* gSegmentNames[] = {
+ "Move",
+ "MoveClose",
+ "DegenLine",
+ "MoveDegenLine",
+ "MoveDegenLineClose",
+ "DegenQuad",
+ "MoveDegenQuad",
+ "MoveDegenQuadClose",
+ "DegenCubic",
+ "MoveDegenCubic",
+ "MoveDegenCubicClose",
+ "Close",
+ "Line",
+ "MoveLine",
+ "MoveLineClose",
+ "Quad",
+ "MoveQuad",
+ "MoveQuadClose",
+ "Cubic",
+ "MoveCubic",
+ "MoveCubicClose"
+ };
+
+ struct FillAndName {
+ SkPath::FillType fFill;
+ const char* fName;
+ };
+ static const FillAndName gFills[] = {
+ {SkPath::kWinding_FillType, "Winding"},
+ {SkPath::kEvenOdd_FillType, "Even / Odd"},
+ {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+ {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}
+ };
+ struct StyleAndName {
+ SkPaint::Style fStyle;
+ const char* fName;
+ };
+ static const StyleAndName gStyles[] = {
+ {SkPaint::kFill_Style, "Fill"},
+ {SkPaint::kStroke_Style, "Stroke 10"},
+ {SkPaint::kStrokeAndFill_Style, "Stroke 10 And Fill"}
+ };
+ struct CapAndName {
+ SkPaint::Cap fCap;
+ SkPaint::Join fJoin;
+ const char* fName;
+ };
+ static const CapAndName gCaps[] = {
+ {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+ {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+ {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
+ };
+
+ SkPaint titlePaint;
+ titlePaint.setColor(SK_ColorBLACK);
+ titlePaint.setAntiAlias(true);
+ titlePaint.setLCDRenderText(true);
+ titlePaint.setTextSize(15 * SK_Scalar1);
+ const char title[] = "Random Paths Drawn Into Rectangle Clips With "
+ "Indicated Style, Fill and Linecaps, "
+ "with Stroke width 6";
+ canvas->drawText(title, strlen(title),
+ 20 * SK_Scalar1,
+ 20 * SK_Scalar1,
+ titlePaint);
+
+ SkRandom rand;
+ SkRect rect = SkRect::MakeWH(220*SK_Scalar1, 50*SK_Scalar1);
+ canvas->save();
+ canvas->translate(2*SK_Scalar1, 30 * SK_Scalar1); // The title
+ canvas->save();
+ unsigned numSegments = SK_ARRAY_COUNT(gSegmentFunctions);
+ unsigned numCaps = SK_ARRAY_COUNT(gCaps);
+ unsigned numStyles = SK_ARRAY_COUNT(gStyles);
+ unsigned numFills = SK_ARRAY_COUNT(gFills);
+ for (size_t row = 0; row < 6; ++row) {
+ if (0 < row) {
+ canvas->translate(0, rect.height() + 100*SK_Scalar1);
+ }
+ canvas->save();
+ for (size_t column = 0; column < 4; ++column) {
+ if (0 < column) {
+ canvas->translate(rect.width() + 4*SK_Scalar1, 0);
+ }
+
+ SkColor color = 0xff007000;
+ StyleAndName style = gStyles[(rand.nextU() >> 16) % numStyles];
+ CapAndName cap = gCaps[(rand.nextU() >> 16) % numCaps];
+ FillAndName fill = gFills[(rand.nextU() >> 16) % numFills];
+ SkPath path;
+ unsigned s1 = (rand.nextU() >> 16) % numSegments;
+ unsigned s2 = (rand.nextU() >> 16) % numSegments;
+ unsigned s3 = (rand.nextU() >> 16) % numSegments;
+ unsigned s4 = (rand.nextU() >> 16) % numSegments;
+ unsigned s5 = (rand.nextU() >> 16) % numSegments;
+ SkPoint pt = SkPoint::Make(10*SK_Scalar1, 0);
+ pt = gSegmentFunctions[s1](path, pt);
+ pt = gSegmentFunctions[s2](path, pt);
+ pt = gSegmentFunctions[s3](path, pt);
+ pt = gSegmentFunctions[s4](path, pt);
+ pt = gSegmentFunctions[s5](path, pt);
+
+ this->drawPath(path, canvas, color, rect,
+ cap.fCap, cap.fJoin, style.fStyle,
+ fill.fFill, SK_Scalar1*6);
+
+ SkPaint rectPaint;
+ rectPaint.setColor(SK_ColorBLACK);
+ rectPaint.setStyle(SkPaint::kStroke_Style);
+ rectPaint.setStrokeWidth(-1);
+ rectPaint.setAntiAlias(true);
+ canvas->drawRect(rect, rectPaint);
+
+ SkPaint labelPaint;
+ labelPaint.setColor(color);
+ labelPaint.setAntiAlias(true);
+ labelPaint.setLCDRenderText(true);
+ labelPaint.setTextSize(10 * SK_Scalar1);
+ canvas->drawText(style.fName,
+ strlen(style.fName),
+ 0, rect.height() + 12 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(fill.fName,
+ strlen(fill.fName),
+ 0, rect.height() + 24 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(cap.fName,
+ strlen(cap.fName),
+ 0, rect.height() + 36 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gSegmentNames[s1],
+ strlen(gSegmentNames[s1]),
+ 0, rect.height() + 48 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gSegmentNames[s2],
+ strlen(gSegmentNames[s2]),
+ 0, rect.height() + 60 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gSegmentNames[s3],
+ strlen(gSegmentNames[s3]),
+ 0, rect.height() + 72 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gSegmentNames[s4],
+ strlen(gSegmentNames[s4]),
+ 0, rect.height() + 84 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gSegmentNames[s5],
+ strlen(gSegmentNames[s5]),
+ 0, rect.height() + 96 * SK_Scalar1,
+ labelPaint);
+ }
+ canvas->restore();
+ }
+ canvas->restore();
+ canvas->restore();
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new DegenerateSegmentsGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/drawbitmaprect.cpp b/gm/drawbitmaprect.cpp
new file mode 100644
index 0000000..5832a9c
--- /dev/null
+++ b/gm/drawbitmaprect.cpp
@@ -0,0 +1,155 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+#include "SkShader.h"
+#include "SkColorPriv.h"
+
+// effects
+#include "SkGradientShader.h"
+
+
+namespace skiagm {
+
+static void makebm(SkBitmap* bm, SkBitmap::Config config, int w, int h) {
+ bm->setConfig(config, w, h);
+ bm->allocPixels();
+ bm->eraseColor(0);
+
+ SkCanvas canvas(*bm);
+
+ SkScalar wScalar = SkIntToScalar(w);
+ SkScalar hScalar = SkIntToScalar(h);
+
+ SkPoint pt = { wScalar / 2, hScalar / 2 };
+
+ SkScalar radius = 4 * SkMaxScalar(wScalar, hScalar);
+
+ SkColor colors[] = { SK_ColorRED, SK_ColorYELLOW,
+ SK_ColorGREEN, SK_ColorMAGENTA,
+ SK_ColorBLUE, SK_ColorCYAN,
+ SK_ColorRED};
+
+ SkScalar pos[] = {0,
+ SK_Scalar1 / 6,
+ 2 * SK_Scalar1 / 6,
+ 3 * SK_Scalar1 / 6,
+ 4 * SK_Scalar1 / 6,
+ 5 * SK_Scalar1 / 6,
+ SK_Scalar1};
+
+ SkPaint paint;
+ paint.setShader(SkGradientShader::CreateRadial(
+ pt, radius,
+ colors, pos,
+ SK_ARRAY_COUNT(colors),
+ SkShader::kRepeat_TileMode))->unref();
+ SkRect rect = SkRect::MakeWH(wScalar, hScalar);
+ SkMatrix mat = SkMatrix::I();
+ for (int i = 0; i < 4; ++i) {
+ paint.getShader()->setLocalMatrix(mat);
+ canvas.drawRect(rect, paint);
+ rect.inset(wScalar / 8, hScalar / 8);
+ mat.postScale(SK_Scalar1 / 4, SK_Scalar1 / 4);
+ }
+}
+
+static const int gSize = 1024;
+
+class DrawBitmapRectGM : public GM {
+public:
+ DrawBitmapRectGM() {
+ }
+
+ SkBitmap fLargeBitmap;
+
+protected:
+ SkString onShortName() {
+ return SkString("drawbitmaprect");
+ }
+
+ SkISize onISize() { return make_isize(gSize, gSize); }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ static const int kBmpSize = 2048;
+ if (fLargeBitmap.isNull()) {
+ makebm(&fLargeBitmap,
+ SkBitmap::kARGB_8888_Config,
+ kBmpSize, kBmpSize);
+ }
+ SkRect dstRect = { 0, 0, SkIntToScalar(64), SkIntToScalar(64)};
+ static const int kMaxSrcRectSize = 1 << (SkNextLog2(kBmpSize) + 2);
+
+ static const int kPadX = 30;
+ static const int kPadY = 40;
+ SkPaint paint;
+ paint.setAlpha(0x20);
+ canvas->drawBitmapRect(fLargeBitmap, NULL,
+ SkRect::MakeWH(gSize * SK_Scalar1,
+ gSize * SK_Scalar1),
+ &paint);
+ canvas->translate(SK_Scalar1 * kPadX / 2,
+ SK_Scalar1 * kPadY / 2);
+ SkPaint blackPaint;
+ SkScalar titleHeight = SK_Scalar1 * 24;
+ blackPaint.setColor(SK_ColorBLACK);
+ blackPaint.setTextSize(titleHeight);
+ blackPaint.setAntiAlias(true);
+ SkString title;
+ title.printf("Bitmap size: %d x %d", kBmpSize, kBmpSize);
+ canvas->drawText(title.c_str(), title.size(), 0,
+ titleHeight, blackPaint);
+
+ canvas->translate(0, SK_Scalar1 * kPadY / 2 + titleHeight);
+ int rowCount = 0;
+ canvas->save();
+ for (int w = 1; w <= kMaxSrcRectSize; w *= 4) {
+ for (int h = 1; h <= kMaxSrcRectSize; h *= 4) {
+
+ SkIRect srcRect = SkIRect::MakeXYWH((kBmpSize - w) / 2,
+ (kBmpSize - h) / 2,
+ w, h);
+ canvas->drawBitmapRect(fLargeBitmap, &srcRect, dstRect);
+
+ SkString label;
+ label.appendf("%d x %d", w, h);
+ blackPaint.setAntiAlias(true);
+ blackPaint.setStyle(SkPaint::kFill_Style);
+ blackPaint.setTextSize(SK_Scalar1 * 10);
+ SkScalar baseline = dstRect.height() +
+ blackPaint.getTextSize() + SK_Scalar1 * 3;
+ canvas->drawText(label.c_str(), label.size(),
+ 0, baseline,
+ blackPaint);
+ blackPaint.setStyle(SkPaint::kStroke_Style);
+ blackPaint.setStrokeWidth(SK_Scalar1);
+ blackPaint.setAntiAlias(false);
+ canvas->drawRect(dstRect, blackPaint);
+
+ canvas->translate(dstRect.width() + SK_Scalar1 * kPadX, 0);
+ ++rowCount;
+ if ((dstRect.width() + kPadX) * rowCount > gSize) {
+ canvas->restore();
+ canvas->translate(0, dstRect.height() + SK_Scalar1 * kPadY);
+ canvas->save();
+ rowCount = 0;
+ }
+ }
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new DrawBitmapRectGM; }
+static GMRegistry reg(MyFactory);
+
+}
+
diff --git a/gm/emptypath.cpp b/gm/emptypath.cpp
new file mode 100644
index 0000000..c52932e
--- /dev/null
+++ b/gm/emptypath.cpp
@@ -0,0 +1,133 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+
+namespace skiagm {
+
+class EmptyPathGM : public GM {
+public:
+ EmptyPathGM() {}
+
+protected:
+ SkString onShortName() {
+ return SkString("emptypath");
+ }
+
+ SkISize onISize() { return make_isize(600, 280); }
+
+ void drawEmpty(SkCanvas* canvas,
+ SkColor color,
+ const SkRect& clip,
+ SkPaint::Style style,
+ SkPath::FillType fill) {
+ SkPath path;
+ path.setFillType(fill);
+ SkPaint paint;
+ paint.setColor(color);
+ paint.setStyle(style);
+ canvas->save();
+ canvas->clipRect(clip);
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ struct FillAndName {
+ SkPath::FillType fFill;
+ const char* fName;
+ };
+ static const FillAndName gFills[] = {
+ {SkPath::kWinding_FillType, "Winding"},
+ {SkPath::kEvenOdd_FillType, "Even / Odd"},
+ {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+ {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+ };
+ struct StyleAndName {
+ SkPaint::Style fStyle;
+ const char* fName;
+ };
+ static const StyleAndName gStyles[] = {
+ {SkPaint::kFill_Style, "Fill"},
+ {SkPaint::kStroke_Style, "Stroke"},
+ {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+ };
+
+ SkPaint titlePaint;
+ titlePaint.setColor(SK_ColorBLACK);
+ titlePaint.setAntiAlias(true);
+ titlePaint.setLCDRenderText(true);
+ titlePaint.setTextSize(15 * SK_Scalar1);
+ const char title[] = "Empty Paths Drawn Into Rectangle Clips With "
+ "Indicated Style and Fill";
+ canvas->drawText(title, strlen(title),
+ 20 * SK_Scalar1,
+ 20 * SK_Scalar1,
+ titlePaint);
+
+ SkRandom rand;
+ SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+ int i = 0;
+ canvas->save();
+ canvas->translate(10 * SK_Scalar1, 0);
+ canvas->save();
+ for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+ for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+ if (0 == i % 4) {
+ canvas->restore();
+ canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+ canvas->save();
+ } else {
+ canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
+ }
+ ++i;
+
+
+ SkColor color = rand.nextU();
+ color = 0xff000000| color; // force solid
+ this->drawEmpty(canvas, color, rect,
+ gStyles[style].fStyle, gFills[fill].fFill);
+
+ SkPaint rectPaint;
+ rectPaint.setColor(SK_ColorBLACK);
+ rectPaint.setStyle(SkPaint::kStroke_Style);
+ rectPaint.setStrokeWidth(-1);
+ rectPaint.setAntiAlias(true);
+ canvas->drawRect(rect, rectPaint);
+
+ SkPaint labelPaint;
+ labelPaint.setColor(color);
+ labelPaint.setAntiAlias(true);
+ labelPaint.setLCDRenderText(true);
+ labelPaint.setTextSize(12 * SK_Scalar1);
+ canvas->drawText(gStyles[style].fName,
+ strlen(gStyles[style].fName),
+ 0, rect.height() + 15 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gFills[fill].fName,
+ strlen(gFills[fill].fName),
+ 0, rect.height() + 28 * SK_Scalar1,
+ labelPaint);
+ }
+ }
+ canvas->restore();
+ canvas->restore();
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new EmptyPathGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/filltypes.cpp b/gm/filltypes.cpp
index e723f16..73c718e 100644
--- a/gm/filltypes.cpp
+++ b/gm/filltypes.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "gm.h"
namespace skiagm {
@@ -6,6 +13,7 @@ class FillTypeGM : public GM {
SkPath fPath;
public:
FillTypeGM() {
+ this->setBGColor(0xFFDDDDDD);
const SkScalar radius = SkIntToScalar(45);
fPath.addCircle(SkIntToScalar(50), SkIntToScalar(50), radius);
fPath.addCircle(SkIntToScalar(100), SkIntToScalar(100), radius);
@@ -49,8 +57,6 @@ protected:
}
virtual void onDraw(SkCanvas* canvas) {
- canvas->drawColor(0xFFDDDDDD);
-
canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
SkPaint paint;
diff --git a/gm/filltypespersp.cpp b/gm/filltypespersp.cpp
new file mode 100644
index 0000000..33f3242
--- /dev/null
+++ b/gm/filltypespersp.cpp
@@ -0,0 +1,128 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+#include "SkGradientShader.h"
+
+namespace skiagm {
+
+class FillTypePerspGM : public GM {
+ SkPath fPath;
+public:
+ FillTypePerspGM() {
+ const SkScalar radius = SkIntToScalar(45);
+ fPath.addCircle(SkIntToScalar(50), SkIntToScalar(50), radius);
+ fPath.addCircle(SkIntToScalar(100), SkIntToScalar(100), radius);
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("filltypespersp");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(835, 840);
+ }
+
+ void showPath(SkCanvas* canvas, int x, int y, SkPath::FillType ft,
+ SkScalar scale, const SkPaint& paint) {
+
+ const SkRect r = { 0, 0, SkIntToScalar(150), SkIntToScalar(150) };
+
+ canvas->save();
+ canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
+ canvas->clipRect(r);
+ canvas->drawColor(SK_ColorWHITE);
+ fPath.setFillType(ft);
+ canvas->translate(r.centerX(), r.centerY());
+ canvas->scale(scale, scale);
+ canvas->translate(-r.centerX(), -r.centerY());
+ canvas->drawPath(fPath, paint);
+ canvas->restore();
+ }
+
+ void showFour(SkCanvas* canvas, SkScalar scale, bool aa) {
+
+ SkPaint paint;
+ SkPoint center = SkPoint::Make(SkIntToScalar(100), SkIntToScalar(100));
+ SkColor colors[] = {SK_ColorBLUE, SK_ColorRED, SK_ColorGREEN};
+ SkScalar pos[] = {0, SK_ScalarHalf, SK_Scalar1};
+ SkShader* s = SkGradientShader::CreateRadial(center,
+ SkIntToScalar(100),
+ colors,
+ pos,
+ SK_ARRAY_COUNT(colors),
+ SkShader::kClamp_TileMode);
+ paint.setShader(s)->unref();
+ paint.setAntiAlias(aa);
+
+ showPath(canvas, 0, 0, SkPath::kWinding_FillType,
+ scale, paint);
+ showPath(canvas, 200, 0, SkPath::kEvenOdd_FillType,
+ scale, paint);
+ showPath(canvas, 00, 200, SkPath::kInverseWinding_FillType,
+ scale, paint);
+ showPath(canvas, 200, 200, SkPath::kInverseEvenOdd_FillType,
+ scale, paint);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ // do perspective drawPaint as the background;
+ SkPaint bkgnrd;
+ SkPoint center = SkPoint::Make(SkIntToScalar(100),
+ SkIntToScalar(100));
+ SkColor colors[] = {SK_ColorBLACK, SK_ColorCYAN,
+ SK_ColorYELLOW, SK_ColorWHITE};
+ SkScalar pos[] = {0, SK_ScalarHalf / 2,
+ 3 * SK_ScalarHalf / 2, SK_Scalar1};
+ SkShader* s = SkGradientShader::CreateRadial(center,
+ SkIntToScalar(1000),
+ colors,
+ pos,
+ SK_ARRAY_COUNT(colors),
+ SkShader::kClamp_TileMode);
+ bkgnrd.setShader(s)->unref();
+ canvas->save();
+ canvas->translate(SkIntToScalar(100), SkIntToScalar(100));
+ SkMatrix mat;
+ mat.reset();
+ mat.setPerspY(SkScalarToPersp(SK_Scalar1 / 1000));
+ canvas->concat(mat);
+ canvas->drawPaint(bkgnrd);
+ canvas->restore();
+
+ // draw the paths in perspective
+ SkMatrix persp;
+ persp.reset();
+ persp.setPerspX(SkScalarToPersp(-SK_Scalar1 / 1800));
+ persp.setPerspY(SkScalarToPersp(SK_Scalar1 / 500));
+ canvas->concat(persp);
+
+ canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
+ const SkScalar scale = SkIntToScalar(5)/4;
+
+ showFour(canvas, SK_Scalar1, false);
+ canvas->translate(SkIntToScalar(450), 0);
+ showFour(canvas, scale, false);
+
+ canvas->translate(SkIntToScalar(-450), SkIntToScalar(450));
+ showFour(canvas, SK_Scalar1, true);
+ canvas->translate(SkIntToScalar(450), 0);
+ showFour(canvas, scale, true);
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new FillTypePerspGM; }
+static GMRegistry reg(MyFactory);
+
+}
+
diff --git a/gm/fontscaler.cpp b/gm/fontscaler.cpp
new file mode 100644
index 0000000..b331bde
--- /dev/null
+++ b/gm/fontscaler.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+#include "SkTypeface.h"
+
+namespace skiagm {
+
+class FontScalerGM : public GM {
+public:
+ FontScalerGM() {
+ this->setBGColor(0xFFFFFFFF);
+ }
+
+ virtual ~FontScalerGM() {
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("fontscaler");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(1450, 750);
+ }
+
+ static void rotate_about(SkCanvas* canvas,
+ SkScalar degrees,
+ SkScalar px, SkScalar py) {
+ canvas->translate(px, py);
+ canvas->rotate(degrees);
+ canvas->translate(-px, -py);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+
+ paint.setAntiAlias(true);
+ paint.setLCDRenderText(true);
+ //With freetype the default (normal hinting) can be really ugly.
+ //Most distros now set slight (vertical hinting only) in any event.
+ paint.setHinting(SkPaint::kSlight_Hinting);
+ SkSafeUnref(paint.setTypeface(SkTypeface::CreateFromName("Times Roman", SkTypeface::kNormal)));
+
+ const char* text = "Hamburgefons ooo mmm";
+ const size_t textLen = strlen(text);
+
+ for (int j = 0; j < 2; ++j) {
+ for (int i = 0; i < 6; ++i) {
+ SkScalar x = SkIntToScalar(10);
+ SkScalar y = SkIntToScalar(20);
+
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->translate(SkIntToScalar(50 + i * 230),
+ SkIntToScalar(20));
+ rotate_about(canvas, SkIntToScalar(i * 5), x, y * 10);
+
+ {
+ SkPaint p;
+ p.setAntiAlias(true);
+ SkRect r;
+ r.set(x - SkIntToScalar(3), SkIntToScalar(15),
+ x - SkIntToScalar(1), SkIntToScalar(280));
+ canvas->drawRect(r, p);
+ }
+
+ int index = 0;
+ for (int ps = 6; ps <= 22; ps++) {
+ paint.setTextSize(SkIntToScalar(ps));
+ canvas->drawText(text, textLen, x, y, paint);
+ y += paint.getFontMetrics(NULL);
+ index += 1;
+ }
+ }
+ canvas->translate(0, SkIntToScalar(360));
+ paint.setSubpixelText(true);
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new FontScalerGM; }
+static GMRegistry reg(MyFactory);
+
+}
+
diff --git a/gm/gm.cpp b/gm/gm.cpp
new file mode 100644
index 0000000..f9c0e66
--- /dev/null
+++ b/gm/gm.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+using namespace skiagm;
+
+GM::GM() {
+ fBGColor = SK_ColorWHITE;
+}
+GM::~GM() {}
+
+void GM::draw(SkCanvas* canvas) {
+ this->drawBackground(canvas);
+ this->drawContent(canvas);
+}
+
+void GM::drawContent(SkCanvas* canvas) {
+ this->onDraw(canvas);
+}
+
+void GM::drawBackground(SkCanvas* canvas) {
+ this->onDrawBackground(canvas);
+}
+
+const char* GM::shortName() {
+ if (fShortName.size() == 0) {
+ fShortName = this->onShortName();
+ }
+ return fShortName.c_str();
+}
+
+void GM::setBGColor(SkColor color) {
+ fBGColor = color;
+}
+
+void GM::onDrawBackground(SkCanvas* canvas) {
+ canvas->drawColor(fBGColor);
+}
+
+void GM::drawSizeBounds(SkCanvas* canvas, SkColor color) {
+ SkISize size = this->getISize();
+ SkRect r = SkRect::MakeWH(SkIntToScalar(size.width()),
+ SkIntToScalar(size.height()));
+ SkPaint paint;
+ paint.setColor(color);
+ canvas->drawRect(r, paint);
+}
+
+// need to explicitly declare this, or we get some weird infinite loop llist
+template GMRegistry* SkTRegistry<GM*, void*>::gHead;
diff --git a/gm/gm.h b/gm/gm.h
index ab92ff6..b0de922 100644
--- a/gm/gm.h
+++ b/gm/gm.h
@@ -1,7 +1,16 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef skiagm_DEFINED
#define skiagm_DEFINED
+#include "SkBitmap.h"
#include "SkCanvas.h"
+#include "SkDevice.h"
#include "SkPaint.h"
#include "SkRefCnt.h"
#include "SkSize.h"
@@ -21,22 +30,39 @@ namespace skiagm {
GM();
virtual ~GM();
- void draw(SkCanvas*);
+ enum Flags {
+ kSkipPDF_Flag = 1 << 0,
+ kSkipPicture_Flag = 1 << 1
+ };
+
+ void draw(SkCanvas*);
+ void drawBackground(SkCanvas*);
+ void drawContent(SkCanvas*);
+
SkISize getISize() { return this->onISize(); }
- const char* shortName() {
- if (fShortName.size() == 0) {
- fShortName = this->onShortName();
- }
- return fShortName.c_str();
+ const char* shortName();
+
+ uint32_t getFlags() const {
+ return this->onGetFlags();
}
+
+ SkColor getBGColor() const { return fBGColor; }
+ void setBGColor(SkColor);
+
+ // helper: fill a rect in the specified color based on the
+ // GM's getISize bounds.
+ void drawSizeBounds(SkCanvas*, SkColor);
protected:
virtual void onDraw(SkCanvas*) = 0;
+ virtual void onDrawBackground(SkCanvas*);
virtual SkISize onISize() = 0;
virtual SkString onShortName() = 0;
+ virtual uint32_t onGetFlags() const { return 0; }
private:
SkString fShortName;
+ SkColor fBGColor;
};
typedef SkTRegistry<GM*, void*> GMRegistry;
diff --git a/gm/gm_files.mk b/gm/gm_files.mk
deleted file mode 100644
index fec20b6..0000000
--- a/gm/gm_files.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-SOURCE := \
- bitmapfilters.cpp \
- blurs.cpp \
- filltypes.cpp \
- gradients.cpp \
- nocolorbleed.cpp \
- pathfill.cpp \
- points.cpp \
- poly2poly.cpp \
- shadows.cpp \
- shapes.cpp \
- strokerects.cpp \
- tilemodes.cpp \
- xfermodes.cpp \
- shadertext.cpp \
- complexclip.cpp \
- gmmain.cpp
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index 37c3ee3..0af2933 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -1,31 +1,65 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "gm.h"
+#include "GrContext.h"
+#include "GrRenderTarget.h"
+
#include "SkColorPriv.h"
+#include "SkData.h"
+#include "SkDevice.h"
+#include "SkGpuCanvas.h"
+#include "SkGpuDevice.h"
#include "SkGraphics.h"
#include "SkImageDecoder.h"
#include "SkImageEncoder.h"
+#include "SkNativeGLContext.h"
+#include "SkMesaGLContext.h"
#include "SkPicture.h"
#include "SkStream.h"
#include "SkRefCnt.h"
-#include "GrContext.h"
-#include "SkGpuCanvas.h"
-#include "SkGpuDevice.h"
-#include "SkEGLContext.h"
-#include "SkDevice.h"
+static bool gForceBWtext;
+
+extern bool gSkSuppressFontCachePurgeSpew;
#ifdef SK_SUPPORT_PDF
#include "SkPDFDevice.h"
#include "SkPDFDocument.h"
#endif
-using namespace skiagm;
+#ifdef SK_SUPPORT_XPS
+ #include "SkXPSDevice.h"
+#endif
+
+#ifdef SK_BUILD_FOR_MAC
+ #include "SkCGUtils.h"
+ #define CAN_IMAGE_PDF 1
+#else
+ #define CAN_IMAGE_PDF 0
+#endif
+
+typedef int ErrorBitfield;
+const static ErrorBitfield ERROR_NONE = 0x00;
+const static ErrorBitfield ERROR_NO_GPU_CONTEXT = 0x01;
+const static ErrorBitfield ERROR_PIXEL_MISMATCH = 0x02;
+const static ErrorBitfield ERROR_DIMENSION_MISMATCH = 0x04;
+const static ErrorBitfield ERROR_READING_REFERENCE_IMAGE = 0x08;
+const static ErrorBitfield ERROR_WRITING_REFERENCE_IMAGE = 0x10;
-// need to explicitly declare this, or we get some weird infinite loop llist
-template GMRegistry* GMRegistry::gHead;
+using namespace skiagm;
class Iter {
public:
Iter() {
+ this->reset();
+ }
+
+ void reset() {
fReg = GMRegistry::Head();
}
@@ -119,34 +153,42 @@ static void compute_diff(const SkBitmap& target, const SkBitmap& base,
}
}
-static bool compare(const SkBitmap& target, const SkBitmap& base,
- const SkString& name, const char* renderModeDescriptor,
- SkBitmap* diff) {
+static ErrorBitfield compare(const SkBitmap& target, const SkBitmap& base,
+ const SkString& name,
+ const char* renderModeDescriptor,
+ SkBitmap* diff) {
SkBitmap copy;
const SkBitmap* bm = &target;
if (target.config() != SkBitmap::kARGB_8888_Config) {
target.copyTo(&copy, SkBitmap::kARGB_8888_Config);
bm = &copy;
}
+ SkBitmap baseCopy;
+ const SkBitmap* bp = &base;
+ if (base.config() != SkBitmap::kARGB_8888_Config) {
+ base.copyTo(&baseCopy, SkBitmap::kARGB_8888_Config);
+ bp = &baseCopy;
+ }
force_all_opaque(*bm);
+ force_all_opaque(*bp);
const int w = bm->width();
const int h = bm->height();
- if (w != base.width() || h != base.height()) {
+ if (w != bp->width() || h != bp->height()) {
SkDebugf(
"---- %s dimensions mismatch for %s base [%d %d] current [%d %d]\n",
renderModeDescriptor, name.c_str(),
- base.width(), base.height(), w, h);
- return false;
+ bp->width(), bp->height(), w, h);
+ return ERROR_DIMENSION_MISMATCH;
}
SkAutoLockPixels bmLock(*bm);
- SkAutoLockPixels baseLock(base);
+ SkAutoLockPixels baseLock(*bp);
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
- SkPMColor c0 = *base.getAddr32(x, y);
+ SkPMColor c0 = *bp->getAddr32(x, y);
SkPMColor c1 = *bm->getAddr32(x, y);
if (c0 != c1) {
SkDebugf(
@@ -156,26 +198,29 @@ static bool compare(const SkBitmap& target, const SkBitmap& base,
if (diff) {
diff->setConfig(SkBitmap::kARGB_8888_Config, w, h);
diff->allocPixels();
- compute_diff(*bm, base, diff);
+ compute_diff(*bm, *bp, diff);
}
- return false;
+ return ERROR_PIXEL_MISMATCH;
}
}
}
// they're equal
- return true;
+ return ERROR_NONE;
}
-static bool write_pdf(const SkString& path, const SkDynamicMemoryWStream& pdf) {
+static bool write_document(const SkString& path,
+ const SkDynamicMemoryWStream& document) {
SkFILEWStream stream(path.c_str());
- return stream.write(pdf.getStream(), pdf.getOffset());
+ SkAutoDataUnref data(document.copyToData());
+ return stream.writeData(data.get());
}
enum Backend {
kRaster_Backend,
kGPU_Backend,
kPDF_Backend,
+ kXPS_Backend,
};
struct ConfigData {
@@ -197,32 +242,54 @@ static void setup_bitmap(const ConfigData& gRec, SkISize& size,
bitmap->eraseColor(0);
}
-// Returns true if the test should continue, false if the test should
-// halt.
-static bool generate_image(GM* gm, const ConfigData& gRec,
- GrContext* context,
- SkBitmap& bitmap) {
+#include "SkDrawFilter.h"
+class BWTextDrawFilter : public SkDrawFilter {
+public:
+ virtual void filter(SkPaint*, Type) SK_OVERRIDE;
+};
+void BWTextDrawFilter::filter(SkPaint* p, Type t) {
+ if (kText_Type == t) {
+ p->setAntiAlias(false);
+ }
+}
+
+static void installFilter(SkCanvas* canvas) {
+ if (gForceBWtext) {
+ canvas->setDrawFilter(new BWTextDrawFilter)->unref();
+ }
+}
+
+static void invokeGM(GM* gm, SkCanvas* canvas) {
+ installFilter(canvas);
+ gm->draw(canvas);
+ canvas->setDrawFilter(NULL);
+}
+
+static ErrorBitfield generate_image(GM* gm, const ConfigData& gRec,
+ GrContext* context,
+ GrRenderTarget* rt,
+ SkBitmap* bitmap) {
SkISize size (gm->getISize());
- setup_bitmap(gRec, size, &bitmap);
- SkCanvas canvas(bitmap);
+ setup_bitmap(gRec, size, bitmap);
+ SkCanvas canvas(*bitmap);
if (gRec.fBackend == kRaster_Backend) {
- gm->draw(&canvas);
+ invokeGM(gm, &canvas);
} else { // GPU
if (NULL == context) {
- return false;
+ return ERROR_NO_GPU_CONTEXT;
}
- SkGpuCanvas gc(context,
- SkGpuDevice::Current3DApiRenderTarget());
- gc.setDevice(gc.createDevice(bitmap.config(),
- bitmap.width(),
- bitmap.height(),
- bitmap.isOpaque(),
- false))->unref();
- gm->draw(&gc);
- gc.readPixels(&bitmap); // overwrite our previous allocation
+ SkGpuCanvas gc(context, rt);
+ gc.setDevice(new SkGpuDevice(context, rt))->unref();
+ invokeGM(gm, &gc);
+ // the device is as large as the current rendertarget, so we explicitly
+ // only readback the amount we expect (in size)
+ // overwrite our previous allocation
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config, size.fWidth,
+ size.fHeight);
+ gc.readPixels(bitmap, 0, 0);
}
- return true;
+ return ERROR_NONE;
}
static void generate_image_from_picture(GM* gm, const ConfigData& gRec,
@@ -230,6 +297,7 @@ static void generate_image_from_picture(GM* gm, const ConfigData& gRec,
SkISize size = gm->getISize();
setup_bitmap(gRec, size, bitmap);
SkCanvas canvas(*bitmap);
+ installFilter(&canvas);
canvas.drawPicture(*pict);
}
@@ -242,7 +310,7 @@ static void generate_pdf(GM* gm, SkDynamicMemoryWStream& pdf) {
SkAutoUnref aur(dev);
SkCanvas c(dev);
- gm->draw(&c);
+ invokeGM(gm, &c);
SkPDFDocument doc;
doc.appendPage(dev);
@@ -250,78 +318,133 @@ static void generate_pdf(GM* gm, SkDynamicMemoryWStream& pdf) {
#endif
}
-static bool write_reference_image(const ConfigData& gRec,
- const char writePath [],
- const char renderModeDescriptor [],
- const SkString& name,
- SkBitmap& bitmap,
- SkDynamicMemoryWStream* pdf) {
+static void generate_xps(GM* gm, SkDynamicMemoryWStream& xps) {
+#ifdef SK_SUPPORT_XPS
+ SkISize size = gm->getISize();
+
+ SkSize trimSize = SkSize::Make(SkIntToScalar(size.width()),
+ SkIntToScalar(size.height()));
+ static const SkScalar inchesPerMeter = SkScalarDiv(10000, 254);
+ static const SkScalar upm = 72 * inchesPerMeter;
+ SkVector unitsPerMeter = SkPoint::Make(upm, upm);
+ static const SkScalar ppm = 200 * inchesPerMeter;
+ SkVector pixelsPerMeter = SkPoint::Make(ppm, ppm);
+
+ SkXPSDevice* dev = new SkXPSDevice();
+ SkAutoUnref aur(dev);
+
+ SkCanvas c(dev);
+ dev->beginPortfolio(&xps);
+ dev->beginSheet(unitsPerMeter, pixelsPerMeter, trimSize);
+ invokeGM(gm, &c);
+ dev->endSheet();
+ dev->endPortfolio();
+
+#endif
+}
+
+static ErrorBitfield write_reference_image(const ConfigData& gRec,
+ const char writePath [],
+ const char renderModeDescriptor [],
+ const SkString& name,
+ SkBitmap& bitmap,
+ SkDynamicMemoryWStream* document) {
SkString path;
bool success = false;
- if (gRec.fBackend != kPDF_Backend) {
+ if (gRec.fBackend == kRaster_Backend ||
+ gRec.fBackend == kGPU_Backend ||
+ (gRec.fBackend == kPDF_Backend && CAN_IMAGE_PDF)) {
+
path = make_filename(writePath, renderModeDescriptor, name, "png");
success = write_bitmap(path, bitmap);
- } else if (pdf) {
+ }
+ if (kPDF_Backend == gRec.fBackend) {
path = make_filename(writePath, renderModeDescriptor, name, "pdf");
- success = write_pdf(path, *pdf);
+ success = write_document(path, *document);
}
- if (!success) {
+ if (kXPS_Backend == gRec.fBackend) {
+ path = make_filename(writePath, renderModeDescriptor, name, "xps");
+ success = write_document(path, *document);
+ }
+ if (success) {
+ return ERROR_NONE;
+ } else {
fprintf(stderr, "FAILED to write %s\n", path.c_str());
+ return ERROR_WRITING_REFERENCE_IMAGE;
}
- return success;
}
-static bool compare_to_reference_image(const char readPath [],
- const SkString& name,
- SkBitmap &bitmap,
- const char diffPath [],
- const char renderModeDescriptor []) {
+static ErrorBitfield compare_to_reference_image(const SkString& name,
+ SkBitmap &bitmap,
+ const SkBitmap& comparisonBitmap,
+ const char diffPath [],
+ const char renderModeDescriptor []) {
+ ErrorBitfield errors;
+ SkBitmap diffBitmap;
+ errors = compare(bitmap, comparisonBitmap, name, renderModeDescriptor,
+ diffPath ? &diffBitmap : NULL);
+ if ((ERROR_NONE == errors) && diffPath) {
+ SkString diffName = make_filename(diffPath, "", name, ".diff.png");
+ if (!write_bitmap(diffName, diffBitmap)) {
+ errors |= ERROR_WRITING_REFERENCE_IMAGE;
+ }
+ }
+ return errors;
+}
+
+static ErrorBitfield compare_to_reference_image(const char readPath [],
+ const SkString& name,
+ SkBitmap &bitmap,
+ const char diffPath [],
+ const char renderModeDescriptor []) {
SkString path = make_filename(readPath, "", name, "png");
SkBitmap orig;
- bool success = SkImageDecoder::DecodeFile(path.c_str(), &orig,
- SkBitmap::kARGB_8888_Config,
- SkImageDecoder::kDecodePixels_Mode, NULL);
- if (success) {
- SkBitmap diffBitmap;
- success = compare(bitmap, orig, name, renderModeDescriptor,
- diffPath ? &diffBitmap : NULL);
- if (!success && diffPath) {
- SkString diffName = make_filename(diffPath, "", name, ".diff.png");
- fprintf(stderr, "Writing %s\n", diffName.c_str());
- write_bitmap(diffName, diffBitmap);
- }
+ if (SkImageDecoder::DecodeFile(path.c_str(), &orig,
+ SkBitmap::kARGB_8888_Config,
+ SkImageDecoder::kDecodePixels_Mode, NULL)) {
+ return compare_to_reference_image(name, bitmap,
+ orig, diffPath,
+ renderModeDescriptor);
} else {
fprintf(stderr, "FAILED to read %s\n", path.c_str());
+ return ERROR_READING_REFERENCE_IMAGE;
}
- return success;
}
-static bool handle_test_results(GM* gm,
- const ConfigData& gRec,
- const char writePath [],
- const char readPath [],
- const char diffPath [],
- const char renderModeDescriptor [],
- SkBitmap& bitmap,
- SkDynamicMemoryWStream* pdf) {
+static ErrorBitfield handle_test_results(GM* gm,
+ const ConfigData& gRec,
+ const char writePath [],
+ const char readPath [],
+ const char diffPath [],
+ const char renderModeDescriptor [],
+ SkBitmap& bitmap,
+ SkDynamicMemoryWStream* pdf,
+ const SkBitmap* comparisonBitmap) {
SkString name = make_name(gm->shortName(), gRec.fName);
if (writePath) {
- write_reference_image(gRec, writePath, renderModeDescriptor,
- name, bitmap, pdf);
- // TODO: Figure out a way to compare PDFs.
- } else if (readPath && gRec.fBackend != kPDF_Backend) {
+ return write_reference_image(gRec, writePath, renderModeDescriptor,
+ name, bitmap, pdf);
+ } else if (readPath && (
+ gRec.fBackend == kRaster_Backend ||
+ gRec.fBackend == kGPU_Backend ||
+ (gRec.fBackend == kPDF_Backend && CAN_IMAGE_PDF))) {
return compare_to_reference_image(readPath, name, bitmap,
diffPath, renderModeDescriptor);
+ } else if (comparisonBitmap) {
+ return compare_to_reference_image(name, bitmap,
+ *comparisonBitmap, diffPath,
+ renderModeDescriptor);
+ } else {
+ return ERROR_NONE;
}
- return true;
}
static SkPicture* generate_new_picture(GM* gm) {
// Pictures are refcounted so must be on heap
SkPicture* pict = new SkPicture;
SkCanvas* cv = pict->beginRecording(1000, 1000);
- gm->draw(cv);
+ invokeGM(gm, cv);
pict->endRecording();
return pict;
@@ -352,51 +475,60 @@ static SkPicture* stream_to_new_picture(const SkPicture& src) {
// Test: draw into a bitmap or pdf.
// Depending on flags, possibly compare to an expected image
// and possibly output a diff image if it fails to match.
-static bool test_drawing(GM* gm,
- const ConfigData& gRec,
- const char writePath [],
- const char readPath [],
- const char diffPath [],
- GrContext* context) {
- SkBitmap bitmap;
- SkDynamicMemoryWStream pdf;
+static ErrorBitfield test_drawing(GM* gm,
+ const ConfigData& gRec,
+ const char writePath [],
+ const char readPath [],
+ const char diffPath [],
+ GrContext* context,
+ GrRenderTarget* rt,
+ SkBitmap* bitmap) {
+ SkDynamicMemoryWStream document;
if (gRec.fBackend == kRaster_Backend ||
- gRec.fBackend == kGPU_Backend) {
- // Early exit if we can't generate the image, but this is
- // expected in some cases, so don't report a test failure.
- if (!generate_image(gm, gRec, context, bitmap)) {
- return true;
+ gRec.fBackend == kGPU_Backend) {
+ // Early exit if we can't generate the image.
+ ErrorBitfield errors = generate_image(gm, gRec, context, rt, bitmap);
+ if (ERROR_NONE != errors) {
+ return errors;
}
- }
- // TODO: Figure out a way to compare PDFs.
- if (gRec.fBackend == kPDF_Backend && writePath) {
- generate_pdf(gm, pdf);
+ } else if (gRec.fBackend == kPDF_Backend) {
+ generate_pdf(gm, document);
+#if CAN_IMAGE_PDF
+ SkAutoDataUnref data(document.copyToData());
+ SkMemoryStream stream(data.data(), data.size());
+ SkPDFDocumentToBitmap(&stream, bitmap);
+#endif
+ } else if (gRec.fBackend == kXPS_Backend) {
+ generate_xps(gm, document);
}
return handle_test_results(gm, gRec, writePath, readPath, diffPath,
- "", bitmap, &pdf);
+ "", *bitmap, &document, NULL);
}
-static bool test_picture_playback(GM* gm,
- const ConfigData& gRec,
- const char readPath [],
- const char diffPath []) {
+static ErrorBitfield test_picture_playback(GM* gm,
+ const ConfigData& gRec,
+ const SkBitmap& comparisonBitmap,
+ const char readPath [],
+ const char diffPath []) {
SkPicture* pict = generate_new_picture(gm);
SkAutoUnref aur(pict);
if (kRaster_Backend == gRec.fBackend) {
SkBitmap bitmap;
generate_image_from_picture(gm, gRec, pict, &bitmap);
- return handle_test_results(gm, gRec, NULL, readPath, diffPath,
- "-replay", bitmap, NULL);
+ return handle_test_results(gm, gRec, NULL, NULL, diffPath,
+ "-replay", bitmap, NULL, &comparisonBitmap);
+ } else {
+ return ERROR_NONE;
}
- return true;
}
-static bool test_picture_serialization(GM* gm,
- const ConfigData& gRec,
- const char readPath [],
- const char diffPath []) {
+static ErrorBitfield test_picture_serialization(GM* gm,
+ const ConfigData& gRec,
+ const SkBitmap& comparisonBitmap,
+ const char readPath [],
+ const char diffPath []) {
SkPicture* pict = generate_new_picture(gm);
SkAutoUnref aurp(pict);
SkPicture* repict = stream_to_new_picture(*pict);
@@ -405,10 +537,11 @@ static bool test_picture_serialization(GM* gm,
if (kRaster_Backend == gRec.fBackend) {
SkBitmap bitmap;
generate_image_from_picture(gm, gRec, repict, &bitmap);
- return handle_test_results(gm, gRec, NULL, readPath, diffPath,
- "-serialize", bitmap, NULL);
+ return handle_test_results(gm, gRec, NULL, NULL, diffPath,
+ "-serialize", bitmap, NULL, &comparisonBitmap);
+ } else {
+ return ERROR_NONE;
}
- return true;
}
static void usage(const char * argv0) {
@@ -422,27 +555,64 @@ static void usage(const char * argv0) {
SkDebugf(" --replay: exercise SkPicture replay.\n");
SkDebugf(
" --serialize: exercise SkPicture serialization & deserialization.\n");
+ SkDebugf(" --match foo will only run tests that substring match foo.\n");
+#if SK_MESA
+ SkDebugf(" --mesagl will run using the osmesa sw gl rasterizer.\n");
+#endif
}
static const ConfigData gRec[] = {
{ SkBitmap::kARGB_8888_Config, kRaster_Backend, "8888" },
{ SkBitmap::kARGB_4444_Config, kRaster_Backend, "4444" },
{ SkBitmap::kRGB_565_Config, kRaster_Backend, "565" },
+#ifdef SK_SCALAR_IS_FLOAT
{ SkBitmap::kARGB_8888_Config, kGPU_Backend, "gpu" },
+#endif
#ifdef SK_SUPPORT_PDF
{ SkBitmap::kARGB_8888_Config, kPDF_Backend, "pdf" },
#endif
+#ifdef SK_SUPPORT_XPS
+ { SkBitmap::kARGB_8888_Config, kXPS_Backend, "xps" },
+#endif
};
+static bool skip_name(const SkTDArray<const char*> array, const char name[]) {
+ if (0 == array.count()) {
+ // no names, so don't skip anything
+ return false;
+ }
+ for (int i = 0; i < array.count(); ++i) {
+ if (strstr(name, array[i])) {
+ // found the name, so don't skip
+ return false;
+ }
+ }
+ return true;
+}
+
+namespace skiagm {
+static GrContext* gGrContext;
+GrContext* GetGr() {
+ return gGrContext;
+}
+}
+
int main(int argc, char * const argv[]) {
SkAutoGraphics ag;
+ // we don't need to see this during a run
+ gSkSuppressFontCachePurgeSpew = true;
const char* writePath = NULL; // if non-null, where we write the originals
const char* readPath = NULL; // if non-null, were we read from to compare
const char* diffPath = NULL; // if non-null, where we write our diffs (from compare)
+ SkTDArray<const char*> fMatches;
+
+ bool doPDF = true;
bool doReplay = true;
bool doSerialize = false;
+ bool useMesa = false;
+
const char* const commandName = argv[0];
char* const* stop = argv + argc;
for (++argv; argv < stop; ++argv) {
@@ -461,10 +631,24 @@ int main(int argc, char * const argv[]) {
if (argv < stop && **argv) {
diffPath = *argv;
}
+ } else if (strcmp(*argv, "--forceBWtext") == 0) {
+ gForceBWtext = true;
} else if (strcmp(*argv, "--noreplay") == 0) {
doReplay = false;
+ } else if (strcmp(*argv, "--nopdf") == 0) {
+ doPDF = false;
} else if (strcmp(*argv, "--serialize") == 0) {
doSerialize = true;
+ } else if (strcmp(*argv, "--match") == 0) {
+ ++argv;
+ if (argv < stop && **argv) {
+ // just record the ptr, no need for a deep copy
+ *fMatches.append() = *argv;
+ }
+#if SK_MESA
+ } else if (strcmp(*argv, "--mesagl") == 0) {
+ useMesa = true;
+#endif
} else {
usage(commandName);
return -1;
@@ -475,15 +659,39 @@ int main(int argc, char * const argv[]) {
return -1;
}
+ int maxW = -1;
+ int maxH = -1;
+ Iter iter;
+ GM* gm;
+ while ((gm = iter.next()) != NULL) {
+ SkISize size = gm->getISize();
+ maxW = SkMax32(size.width(), maxW);
+ maxH = SkMax32(size.height(), maxH);
+ }
// setup a GL context for drawing offscreen
- GrContext* context = NULL;
- SkEGLContext eglContext;
- if (eglContext.init(1024, 1024)) {
- context = GrContext::CreateGLShaderContext();
+ SkAutoTUnref<SkGLContext> glContext;
+#if SK_MESA
+ if (useMesa) {
+ glContext.reset(new SkMesaGLContext());
+ } else
+#endif
+ {
+ glContext.reset(new SkNativeGLContext());
}
- Iter iter;
- GM* gm;
+ GrPlatformRenderTargetDesc rtDesc;
+ if (glContext.get()->init(maxW, maxH)) {
+ GrPlatform3DContext ctx =
+ reinterpret_cast<GrPlatform3DContext>(glContext.get()->gl());
+ gGrContext = GrContext::Create(kOpenGL_Shaders_GrEngine, ctx);
+ if (NULL != gGrContext) {
+ rtDesc.fConfig = kSkia8888_PM_GrPixelConfig;
+ rtDesc.fStencilBits = 8;
+ rtDesc.fRenderTargetHandle = glContext.get()->getFBOID();
+ }
+ } else {
+ fprintf(stderr, "could not create GL context.\n");
+ }
if (readPath) {
fprintf(stderr, "reading from %s\n", readPath);
@@ -491,45 +699,95 @@ int main(int argc, char * const argv[]) {
fprintf(stderr, "writing to %s\n", writePath);
}
- // Accumulate success of all tests so we can flag error in any
- // one with the return value.
- bool overallSuccess = true;
+ // Accumulate success of all tests.
+ int testsRun = 0;
+ int testsPassed = 0;
+ int testsFailed = 0;
+ int testsMissingReferenceImages = 0;
+
+ iter.reset();
while ((gm = iter.next()) != NULL) {
+ const char* shortName = gm->shortName();
+ if (skip_name(fMatches, shortName)) {
+ SkDELETE(gm);
+ continue;
+ }
+
SkISize size = gm->getISize();
- SkDebugf("drawing... %s [%d %d]\n", gm->shortName(),
+ SkDebugf("drawing... %s [%d %d]\n", shortName,
size.width(), size.height());
+ SkBitmap forwardRenderedBitmap;
+
+ // Above we created an fbo for the context at maxW x maxH size.
+ // Here we lie about the size of the rt. We claim it is the size
+ // desired by the test. The reason is that rasterization may change
+ // slightly when the viewport dimensions change. Previously, whenever
+ // a new test was checked in that bumped maxW or maxH several images
+ // would slightly change.
+ rtDesc.fWidth = size.width();
+ rtDesc.fHeight = size.height();
+ SkAutoTUnref<GrRenderTarget> rt;
+ if (gGrContext) {
+ rt.reset(gGrContext->createPlatformRenderTarget(rtDesc));
+ }
for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
- bool testSuccess = test_drawing(gm, gRec[i],
- writePath, readPath, diffPath, context);
- overallSuccess &= testSuccess;
-
- if (doReplay && testSuccess) {
- testSuccess = test_picture_playback(gm, gRec[i],
- readPath, diffPath);
- overallSuccess &= testSuccess;
+ // Skip any tests that we don't even need to try.
+ uint32_t gmFlags = gm->getFlags();
+ if ((kPDF_Backend == gRec[i].fBackend) &&
+ (!doPDF || (gmFlags & GM::kSkipPDF_Flag)))
+ {
+ continue;
}
- if (doSerialize && testSuccess) {
- overallSuccess &= test_picture_serialization(gm, gRec[i],
- readPath, diffPath);
+ // Now we know that we want to run this test and record its
+ // success or failure.
+ ErrorBitfield testErrors = ERROR_NONE;
+
+ if ((ERROR_NONE == testErrors) &&
+ (kGPU_Backend == gRec[i].fBackend) &&
+ (NULL == rt.get())) {
+ fprintf(stderr, "Could not create render target for gpu.\n");
+ testErrors |= ERROR_NO_GPU_CONTEXT;
}
- }
- SkDELETE(gm);
- }
- if (false == overallSuccess) {
- return -1;
- }
- return 0;
-}
-///////////////////////////////////////////////////////////////////////////////
+ if (ERROR_NONE == testErrors) {
+ testErrors |= test_drawing(gm, gRec[i],
+ writePath, readPath, diffPath,
+ gGrContext,
+ rt.get(), &forwardRenderedBitmap);
+ }
-using namespace skiagm;
+ if ((ERROR_NONE == testErrors) && doReplay &&
+ !(gmFlags & GM::kSkipPicture_Flag)) {
+ testErrors |= test_picture_playback(gm, gRec[i],
+ forwardRenderedBitmap,
+ readPath, diffPath);
+ }
-GM::GM() {}
-GM::~GM() {}
+ if ((ERROR_NONE == testErrors) && doSerialize) {
+ testErrors |= test_picture_serialization(gm, gRec[i],
+ forwardRenderedBitmap,
+ readPath, diffPath);
+ }
-void GM::draw(SkCanvas* canvas) {
- this->onDraw(canvas);
+ // Update overall results.
+ // We only tabulate the particular error types that we currently
+ // care about (e.g., missing reference images). Later on, if we
+ // want to also tabulate pixel mismatches vs dimension mistmatches
+ // (or whatever else), we can do so.
+ testsRun++;
+ if (ERROR_NONE == testErrors) {
+ testsPassed++;
+ } else if (ERROR_READING_REFERENCE_IMAGE & testErrors) {
+ testsMissingReferenceImages++;
+ } else {
+ testsFailed++;
+ }
+ }
+ SkDELETE(gm);
+ }
+ printf("Ran %d tests: %d passed, %d failed, %d missing reference images\n",
+ testsRun, testsPassed, testsFailed, testsMissingReferenceImages);
+ return (0 == testsFailed) ? 0 : -1;
}
diff --git a/gm/gradients.cpp b/gm/gradients.cpp
index 26eee9d..aac8a96 100644
--- a/gm/gradients.cpp
+++ b/gm/gradients.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "gm.h"
#include "SkGradientShader.h"
@@ -73,21 +80,18 @@ static const GradMaker gGradMakers[] = {
class GradientsGM : public GM {
public:
- GradientsGM() {}
+ GradientsGM() {
+ this->setBGColor(0xFFDDDDDD);
+ }
protected:
SkString onShortName() {
return SkString("gradients");
}
- SkISize onISize() { return make_isize(640, 510); }
-
- void drawBG(SkCanvas* canvas) {
- canvas->drawColor(0xFFDDDDDD);
- }
-
+ virtual SkISize onISize() { return make_isize(640, 510); }
+
virtual void onDraw(SkCanvas* canvas) {
- this->drawBG(canvas);
SkPoint pts[2] = {
{ 0, 0 },
@@ -117,10 +121,109 @@ private:
typedef GM INHERITED;
};
+/*
+ Inspired by this <canvas> javascript, where we need to detect that we are not
+ solving a quadratic equation, but must instead solve a linear (since our X^2
+ coefficient is 0)
+
+ ctx.fillStyle = '#f00';
+ ctx.fillRect(0, 0, 100, 50);
+
+ var g = ctx.createRadialGradient(-80, 25, 70, 0, 25, 150);
+ g.addColorStop(0, '#f00');
+ g.addColorStop(0.01, '#0f0');
+ g.addColorStop(0.99, '#0f0');
+ g.addColorStop(1, '#f00');
+ ctx.fillStyle = g;
+ ctx.fillRect(0, 0, 100, 50);
+ */
+class GradientsDegenrate2PointGM : public GM {
+public:
+ GradientsDegenrate2PointGM() {}
+
+protected:
+ SkString onShortName() {
+ return SkString("gradients_degenerate_2pt");
+ }
+
+ virtual SkISize onISize() { return make_isize(320, 320); }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorBLUE);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ this->drawBG(canvas);
+
+ SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorRED };
+ SkScalar pos[] = { 0, SkFloatToScalar(0.01f), SkFloatToScalar(0.99f), SK_Scalar1 };
+ SkPoint c0;
+ c0.iset(-80, 25);
+ SkScalar r0 = SkIntToScalar(70);
+ SkPoint c1;
+ c1.iset(0, 25);
+ SkScalar r1 = SkIntToScalar(150);
+ SkShader* s = SkGradientShader::CreateTwoPointRadial(c0, r0, c1, r1, colors,
+ pos, SK_ARRAY_COUNT(pos),
+ SkShader::kClamp_TileMode);
+ SkPaint paint;
+ paint.setShader(s)->unref();
+ canvas->drawPaint(paint);
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+/// Tests correctness of *optimized* codepaths in gradients.
+
+class ClampedGradientsGM : public GM {
+public:
+ ClampedGradientsGM() {}
+
+protected:
+ SkString onShortName() { return SkString("clamped_gradients"); }
+
+ virtual SkISize onISize() { return make_isize(640, 510); }
+
+ void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(0xFFDDDDDD);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ this->drawBG(canvas);
+
+ SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(300) };
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ SkPoint center;
+ center.iset(0, 300);
+ canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
+ SkShader* shader = SkGradientShader::CreateRadial(
+ SkPoint(center),
+ SkIntToScalar(200), gColors, NULL, 5,
+ SkShader::kClamp_TileMode, NULL);
+ paint.setShader(shader);
+ canvas->drawRect(r, paint);
+ shader->unref();
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+
///////////////////////////////////////////////////////////////////////////////
static GM* MyFactory(void*) { return new GradientsGM; }
static GMRegistry reg(MyFactory);
+static GM* MyFactory2(void*) { return new GradientsDegenrate2PointGM; }
+static GMRegistry reg2(MyFactory2);
+
+static GM* MyFactory3(void*) { return new ClampedGradientsGM; }
+static GMRegistry reg3(MyFactory3);
+
}
diff --git a/gm/gradtext.cpp b/gm/gradtext.cpp
new file mode 100644
index 0000000..a3769d2
--- /dev/null
+++ b/gm/gradtext.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+
+// test shader w/ transparency
+static SkShader* make_grad(SkScalar width) {
+ SkColor colors[] = { SK_ColorRED, 0x0000FF00, SK_ColorBLUE };
+ SkPoint pts[] = { { 0, 0 }, { width, 0 } };
+ return SkGradientShader::CreateLinear(pts, colors, NULL,
+ SK_ARRAY_COUNT(colors),
+ SkShader::kMirror_TileMode);
+}
+
+// test opaque shader
+static SkShader* make_grad2(SkScalar width) {
+ SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
+ SkPoint pts[] = { { 0, 0 }, { width, 0 } };
+ return SkGradientShader::CreateLinear(pts, colors, NULL,
+ SK_ARRAY_COUNT(colors),
+ SkShader::kMirror_TileMode);
+}
+
+namespace skiagm {
+
+class GradTextGM : public GM {
+public:
+ GradTextGM () {}
+
+protected:
+
+ virtual SkString onShortName() {
+ return SkString("gradtext");
+ }
+
+ virtual SkISize onISize() { return make_isize(500, 480); }
+
+ static void draw_text(SkCanvas* canvas, const SkPaint& paint) {
+ const char* text = "When in the course of human events";
+ size_t len = strlen(text);
+ canvas->drawText(text, len, 0, 0, paint);
+ }
+
+ static void draw_text3(SkCanvas* canvas, const SkPaint& paint) {
+ SkPaint p(paint);
+
+ p.setAntiAlias(false);
+ draw_text(canvas, p);
+ p.setAntiAlias(true);
+ canvas->translate(0, paint.getTextSize() * 4/3);
+ draw_text(canvas, p);
+ p.setLCDRenderText(true);
+ canvas->translate(0, paint.getTextSize() * 4/3);
+ draw_text(canvas, p);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setTextSize(SkIntToScalar(26));
+
+ const SkISize& size = this->getISize();
+ SkRect r = SkRect::MakeWH(SkIntToScalar(size.width()),
+ SkIntToScalar(size.height()) / 2);
+ canvas->drawRect(r, paint);
+
+ canvas->translate(SkIntToScalar(20), paint.getTextSize());
+
+ for (int i = 0; i < 2; ++i) {
+ paint.setShader(make_grad(SkIntToScalar(80)))->unref();
+ draw_text3(canvas, paint);
+
+ canvas->translate(0, paint.getTextSize() * 2);
+
+ paint.setShader(make_grad2(SkIntToScalar(80)))->unref();
+ draw_text3(canvas, paint);
+
+ canvas->translate(0, paint.getTextSize() * 2);
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new GradTextGM; }
+static GMRegistry reg(MyFactory);
+
+}
+
diff --git a/gm/hairmodes.cpp b/gm/hairmodes.cpp
new file mode 100644
index 0000000..8bfa186
--- /dev/null
+++ b/gm/hairmodes.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+
+static SkCanvas* create_canvas(int w, int h) {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, w, h);
+ bm.allocPixels();
+ bm.eraseColor(0);
+ return new SkCanvas(bm);
+}
+
+static const SkBitmap& extract_bitmap(SkCanvas* canvas) {
+ return canvas->getDevice()->accessBitmap(false);
+}
+
+static const struct {
+ SkXfermode::Mode fMode;
+ const char* fLabel;
+} gModes[] = {
+ { SkXfermode::kClear_Mode, "Clear" },
+ { SkXfermode::kSrc_Mode, "Src" },
+ { SkXfermode::kDst_Mode, "Dst" },
+ { SkXfermode::kSrcOver_Mode, "SrcOver" },
+ { SkXfermode::kDstOver_Mode, "DstOver" },
+ { SkXfermode::kSrcIn_Mode, "SrcIn" },
+ { SkXfermode::kDstIn_Mode, "DstIn" },
+ { SkXfermode::kSrcOut_Mode, "SrcOut" },
+ { SkXfermode::kDstOut_Mode, "DstOut" },
+ { SkXfermode::kSrcATop_Mode, "SrcATop" },
+ { SkXfermode::kDstATop_Mode, "DstATop" },
+ { SkXfermode::kXor_Mode, "Xor" },
+};
+
+const int gWidth = 64;
+const int gHeight = 64;
+const SkScalar W = SkIntToScalar(gWidth);
+const SkScalar H = SkIntToScalar(gHeight);
+
+static SkScalar drawCell(SkCanvas* canvas, SkXfermode* mode, SkAlpha a0, SkAlpha a1) {
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ SkRect r = SkRect::MakeWH(W, H);
+ r.inset(W/10, H/10);
+
+ paint.setColor(SK_ColorBLUE);
+ paint.setAlpha(a0);
+ canvas->drawOval(r, paint);
+
+ paint.setColor(SK_ColorRED);
+ paint.setAlpha(a1);
+ paint.setXfermode(mode);
+ for (int angle = 0; angle < 24; ++angle) {
+ SkScalar x = SkScalarCos(SkIntToScalar(angle) * (SK_ScalarPI * 2) / 24) * gWidth;
+ SkScalar y = SkScalarSin(SkIntToScalar(angle) * (SK_ScalarPI * 2) / 24) * gHeight;
+ paint.setStrokeWidth(SK_Scalar1 * angle * 2 / 24);
+ canvas->drawLine(W/2, H/2, W/2 + x, H/2 + y, paint);
+ }
+
+ return H;
+}
+
+static SkShader* make_bg_shader() {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
+ bm.allocPixels();
+ *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = 0xFFFFFFFF;
+ *bm.getAddr32(1, 0) = *bm.getAddr32(0, 1) = SkPackARGB32(0xFF, 0xCC, 0xCC, 0xCC);
+
+ SkShader* s = SkShader::CreateBitmapShader(bm,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+
+ SkMatrix m;
+ m.setScale(SkIntToScalar(6), SkIntToScalar(6));
+ s->setLocalMatrix(m);
+ return s;
+}
+
+namespace skiagm {
+
+ class HairModesGM : public GM {
+ SkPaint fBGPaint;
+ public:
+ HairModesGM() {
+ fBGPaint.setShader(make_bg_shader())->unref();
+ }
+
+ protected:
+
+ virtual SkString onShortName() {
+ return SkString("hairmodes");
+ }
+
+ virtual SkISize onISize() { return make_isize(640, 480); }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ const SkRect bounds = SkRect::MakeWH(W, H);
+ static const SkAlpha gAlphaValue[] = { 0xFF, 0x88, 0x88 };
+
+ canvas->translate(SkIntToScalar(4), SkIntToScalar(4));
+
+ for (int alpha = 0; alpha < 4; ++alpha) {
+ canvas->save();
+ canvas->save();
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); ++i) {
+ if (6 == i) {
+ canvas->restore();
+ canvas->translate(W * 5, 0);
+ canvas->save();
+ }
+ SkXfermode* mode = SkXfermode::Create(gModes[i].fMode);
+
+ canvas->drawRect(bounds, fBGPaint);
+ canvas->saveLayer(&bounds, NULL);
+ SkScalar dy = drawCell(canvas, mode,
+ gAlphaValue[alpha & 1],
+ gAlphaValue[alpha & 2]);
+ canvas->restore();
+
+ canvas->translate(0, dy * 5 / 4);
+ SkSafeUnref(mode);
+ }
+ canvas->restore();
+ canvas->restore();
+ canvas->translate(W * 5 / 4, 0);
+ }
+ }
+
+ // disable pdf for now, since it crashes on mac
+ virtual uint32_t onGetFlags() const { return kSkipPDF_Flag; }
+
+ private:
+ typedef GM INHERITED;
+ };
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ static GM* MyFactory(void*) { return new HairModesGM; }
+ static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/imageblur.cpp b/gm/imageblur.cpp
new file mode 100644
index 0000000..841441e
--- /dev/null
+++ b/gm/imageblur.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkBlurImageFilter.h"
+
+#define WIDTH 500
+#define HEIGHT 500
+
+namespace skiagm {
+
+class ImageBlurGM : public GM {
+public:
+ ImageBlurGM() {
+ this->setBGColor(0xFF000000);
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("imageblur");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(WIDTH, HEIGHT);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setImageFilter(new SkBlurImageFilter(24.0f, 0.0f))->unref();
+ canvas->saveLayer(NULL, &paint);
+ paint.setAntiAlias(true);
+ const char* str = "The quick brown fox jumped over the lazy dog.";
+ srand(1234);
+ for (int i = 0; i < 25; ++i) {
+ int x = rand() % WIDTH;
+ int y = rand() % HEIGHT;
+ paint.setColor(rand() % 0x1000000 | 0xFF000000);
+ paint.setTextSize(rand() % 300);
+ canvas->drawText(str, strlen(str), x, y, paint);
+ }
+ canvas->restore();
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new ImageBlurGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/lcdtext.cpp b/gm/lcdtext.cpp
new file mode 100644
index 0000000..ab8b8e4
--- /dev/null
+++ b/gm/lcdtext.cpp
@@ -0,0 +1,70 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+/* Tests text rendering with LCD and subpixel rendering turned on and off.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+
+namespace skiagm {
+
+class LcdTextGM : public GM {
+public:
+ LcdTextGM() {
+ const int pointSize = 36;
+ textHeight = SkIntToScalar(pointSize);
+ }
+
+protected:
+
+ SkString onShortName() {
+ return SkString("lcdtext");
+ }
+
+ SkISize onISize() { return make_isize(640, 480); }
+
+ virtual void onDraw(SkCanvas* canvas) {
+
+ y = textHeight;
+ drawText(canvas, SkString("TEXT: SubpixelTrue LCDRenderTrue"),
+ true, true);
+ drawText(canvas, SkString("TEXT: SubpixelTrue LCDRenderFalse"),
+ true, false);
+ drawText(canvas, SkString("TEXT: SubpixelFalse LCDRenderTrue"),
+ false, true);
+ drawText(canvas, SkString("TEXT: SubpixelFalse LCDRenderFalse"),
+ false, false);
+ }
+
+ void drawText(SkCanvas* canvas, const SkString& string,
+ bool subpixelTextEnabled, bool lcdRenderTextEnabled) {
+ SkPaint paint;
+ paint.setColor(SK_ColorBLACK);
+ paint.setDither(true);
+ paint.setAntiAlias(true);
+ paint.setSubpixelText(subpixelTextEnabled);
+ paint.setLCDRenderText(lcdRenderTextEnabled);
+ paint.setTextSize(textHeight);
+
+ canvas->drawText(string.c_str(), string.size(), 0, y, paint);
+ y += textHeight;
+ }
+
+private:
+ typedef GM INHERITED;
+ SkScalar y, textHeight;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new LcdTextGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/linepaths.cpp b/gm/linepaths.cpp
new file mode 100644
index 0000000..3d84c37
--- /dev/null
+++ b/gm/linepaths.cpp
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+
+namespace skiagm {
+
+class LinePathGM : public GM {
+public:
+ LinePathGM() {}
+
+protected:
+ SkString onShortName() {
+ return SkString("linepath");
+ }
+
+ SkISize onISize() { return make_isize(1240, 390); }
+
+ void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+ const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
+ SkPaint::Style style, SkPath::FillType fill,
+ SkScalar strokeWidth) {
+ path.setFillType(fill);
+ SkPaint paint;
+ paint.setStrokeCap(cap);
+ paint.setStrokeWidth(strokeWidth);
+ paint.setStrokeJoin(join);
+ paint.setColor(color);
+ paint.setStyle(style);
+ canvas->save();
+ canvas->clipRect(clip);
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ struct FillAndName {
+ SkPath::FillType fFill;
+ const char* fName;
+ };
+ static const FillAndName gFills[] = {
+ {SkPath::kWinding_FillType, "Winding"},
+ {SkPath::kEvenOdd_FillType, "Even / Odd"},
+ {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+ {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+ };
+ struct StyleAndName {
+ SkPaint::Style fStyle;
+ const char* fName;
+ };
+ static const StyleAndName gStyles[] = {
+ {SkPaint::kFill_Style, "Fill"},
+ {SkPaint::kStroke_Style, "Stroke"},
+ {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+ };
+ struct CapAndName {
+ SkPaint::Cap fCap;
+ SkPaint::Join fJoin;
+ const char* fName;
+ };
+ static const CapAndName gCaps[] = {
+ {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+ {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+ {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
+ };
+ struct PathAndName {
+ SkPath fPath;
+ const char* fName;
+ };
+ PathAndName path;
+ path.fPath.moveTo(25*SK_Scalar1, 15*SK_Scalar1);
+ path.fPath.lineTo(75*SK_Scalar1, 15*SK_Scalar1);
+ path.fName = "moveTo-line";
+
+ SkPaint titlePaint;
+ titlePaint.setColor(SK_ColorBLACK);
+ titlePaint.setAntiAlias(true);
+ titlePaint.setLCDRenderText(true);
+ titlePaint.setTextSize(15 * SK_Scalar1);
+ const char title[] = "Line Drawn Into Rectangle Clips With "
+ "Indicated Style, Fill and Linecaps, with stroke width 10";
+ canvas->drawText(title, strlen(title),
+ 20 * SK_Scalar1,
+ 20 * SK_Scalar1,
+ titlePaint);
+
+ SkRandom rand;
+ SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+ canvas->save();
+ canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+ canvas->save();
+ for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+ if (0 < cap) {
+ canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+ }
+ canvas->save();
+ for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+ if (0 < fill) {
+ canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+ }
+ canvas->save();
+ for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+ if (0 < style) {
+ canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
+ }
+
+ SkColor color = 0xff007000;
+ this->drawPath(path.fPath, canvas, color, rect,
+ gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+ gFills[fill].fFill, SK_Scalar1*10);
+
+ SkPaint rectPaint;
+ rectPaint.setColor(SK_ColorBLACK);
+ rectPaint.setStyle(SkPaint::kStroke_Style);
+ rectPaint.setStrokeWidth(-1);
+ rectPaint.setAntiAlias(true);
+ canvas->drawRect(rect, rectPaint);
+
+ SkPaint labelPaint;
+ labelPaint.setColor(color);
+ labelPaint.setAntiAlias(true);
+ labelPaint.setLCDRenderText(true);
+ labelPaint.setTextSize(10 * SK_Scalar1);
+ canvas->drawText(gStyles[style].fName,
+ strlen(gStyles[style].fName),
+ 0, rect.height() + 12 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gFills[fill].fName,
+ strlen(gFills[fill].fName),
+ 0, rect.height() + 24 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gCaps[cap].fName,
+ strlen(gCaps[cap].fName),
+ 0, rect.height() + 36 * SK_Scalar1,
+ labelPaint);
+ }
+ canvas->restore();
+ }
+ canvas->restore();
+ }
+ canvas->restore();
+ canvas->restore();
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+class LineClosePathGM : public GM {
+public:
+ LineClosePathGM() {}
+
+protected:
+ SkString onShortName() {
+ return SkString("lineclosepath");
+ }
+
+ SkISize onISize() { return make_isize(1240, 390); }
+
+ void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+ const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
+ SkPaint::Style style, SkPath::FillType fill,
+ SkScalar strokeWidth) {
+ path.setFillType(fill);
+ SkPaint paint;
+ paint.setStrokeCap(cap);
+ paint.setStrokeWidth(strokeWidth);
+ paint.setStrokeJoin(join);
+ paint.setColor(color);
+ paint.setStyle(style);
+ canvas->save();
+ canvas->clipRect(clip);
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ struct FillAndName {
+ SkPath::FillType fFill;
+ const char* fName;
+ };
+ static const FillAndName gFills[] = {
+ {SkPath::kWinding_FillType, "Winding"},
+ {SkPath::kEvenOdd_FillType, "Even / Odd"},
+ {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+ {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+ };
+ struct StyleAndName {
+ SkPaint::Style fStyle;
+ const char* fName;
+ };
+ static const StyleAndName gStyles[] = {
+ {SkPaint::kFill_Style, "Fill"},
+ {SkPaint::kStroke_Style, "Stroke"},
+ {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+ };
+ struct CapAndName {
+ SkPaint::Cap fCap;
+ SkPaint::Join fJoin;
+ const char* fName;
+ };
+ static const CapAndName gCaps[] = {
+ {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+ {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+ {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
+ };
+ struct PathAndName {
+ SkPath fPath;
+ const char* fName;
+ };
+ PathAndName path;
+ path.fPath.moveTo(25*SK_Scalar1, 15*SK_Scalar1);
+ path.fPath.lineTo(75*SK_Scalar1, 15*SK_Scalar1);
+ path.fPath.close();
+ path.fName = "moveTo-line-close";
+
+ SkPaint titlePaint;
+ titlePaint.setColor(SK_ColorBLACK);
+ titlePaint.setAntiAlias(true);
+ titlePaint.setLCDRenderText(true);
+ titlePaint.setTextSize(15 * SK_Scalar1);
+ const char title[] = "Line Closed Drawn Into Rectangle Clips With "
+ "Indicated Style, Fill and Linecaps, with stroke width 10";
+ canvas->drawText(title, strlen(title),
+ 20 * SK_Scalar1,
+ 20 * SK_Scalar1,
+ titlePaint);
+
+ SkRandom rand;
+ SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+ canvas->save();
+ canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+ canvas->save();
+ for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+ if (0 < cap) {
+ canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+ }
+ canvas->save();
+ for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+ if (0 < fill) {
+ canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+ }
+ canvas->save();
+ for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+ if (0 < style) {
+ canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
+ }
+
+ SkColor color = 0xff007000;
+ this->drawPath(path.fPath, canvas, color, rect,
+ gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+ gFills[fill].fFill, SK_Scalar1*10);
+
+ SkPaint rectPaint;
+ rectPaint.setColor(SK_ColorBLACK);
+ rectPaint.setStyle(SkPaint::kStroke_Style);
+ rectPaint.setStrokeWidth(-1);
+ rectPaint.setAntiAlias(true);
+ canvas->drawRect(rect, rectPaint);
+
+ SkPaint labelPaint;
+ labelPaint.setColor(color);
+ labelPaint.setAntiAlias(true);
+ labelPaint.setLCDRenderText(true);
+ labelPaint.setTextSize(10 * SK_Scalar1);
+ canvas->drawText(gStyles[style].fName,
+ strlen(gStyles[style].fName),
+ 0, rect.height() + 12 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gFills[fill].fName,
+ strlen(gFills[fill].fName),
+ 0, rect.height() + 24 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gCaps[cap].fName,
+ strlen(gCaps[cap].fName),
+ 0, rect.height() + 36 * SK_Scalar1,
+ labelPaint);
+ }
+ canvas->restore();
+ }
+ canvas->restore();
+ }
+ canvas->restore();
+ canvas->restore();
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* LinePathFactory(void*) { return new LinePathGM; }
+static GMRegistry regLinePath(LinePathFactory);
+
+static GM* LineClosePathFactory(void*) { return new LineClosePathGM; }
+static GMRegistry regLineClosePath(LineClosePathFactory);
+
+}
diff --git a/gm/ninepatchstretch.cpp b/gm/ninepatchstretch.cpp
new file mode 100644
index 0000000..d1d4dda
--- /dev/null
+++ b/gm/ninepatchstretch.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+
+#include "SkGpuDevice.h"
+
+static void make_bitmap(SkBitmap* bitmap, GrContext* ctx, SkIRect* center) {
+ SkDevice* dev;
+ SkCanvas canvas;
+
+ const int kFixed = 28;
+ const int kStretchy = 8;
+ const int kSize = 2*kFixed + kStretchy;
+
+ if (ctx) {
+ dev = new SkGpuDevice(ctx, SkBitmap::kARGB_8888_Config, kSize, kSize);
+ *bitmap = dev->accessBitmap(false);
+ } else {
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config, kSize, kSize);
+ bitmap->allocPixels();
+ dev = new SkDevice(*bitmap);
+ }
+
+ canvas.setDevice(dev)->unref();
+ canvas.clear(0);
+
+ SkRect r = SkRect::MakeWH(SkIntToScalar(kSize), SkIntToScalar(kSize));
+ const SkScalar strokeWidth = SkIntToScalar(6);
+ const SkScalar radius = SkIntToScalar(kFixed) - strokeWidth/2;
+
+ center->setXYWH(kFixed, kFixed, kStretchy, kStretchy);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ paint.setColor(0xFFFF0000);
+ canvas.drawRoundRect(r, radius, radius, paint);
+ r.setXYWH(SkIntToScalar(kFixed), 0, SkIntToScalar(kStretchy), SkIntToScalar(kSize));
+ paint.setColor(0x8800FF00);
+ canvas.drawRect(r, paint);
+ r.setXYWH(0, SkIntToScalar(kFixed), SkIntToScalar(kSize), SkIntToScalar(kStretchy));
+ paint.setColor(0x880000FF);
+ canvas.drawRect(r, paint);
+}
+
+namespace skiagm {
+
+class NinePatchStretchGM : public GM {
+public:
+ SkBitmap fBM;
+
+ NinePatchStretchGM() {}
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("ninepatch-stretch");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(400, 400);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkBitmap bm;
+ SkIRect center;
+ make_bitmap(&bm, NULL /*SampleCode::GetGr()*/, &center);
+
+ // amount of bm that should not be stretched (unless we have to)
+ const SkScalar fixed = SkIntToScalar(bm.width() - center.width());
+
+ const SkTSize<SkScalar> size[] = {
+ { fixed * 4 / 5, fixed * 4 / 5 }, // shrink in both axes
+ { fixed * 4 / 5, fixed * 4 }, // shrink in X
+ { fixed * 4, fixed * 4 / 5 }, // shrink in Y
+ { fixed * 4, fixed * 4 }
+ };
+
+ canvas->drawBitmap(bm, SkIntToScalar(10), SkIntToScalar(10), NULL);
+
+ SkScalar x = SkIntToScalar(100);
+ SkScalar y = SkIntToScalar(100);
+
+ SkPaint paint;
+ paint.setFilterBitmap(true);
+
+ for (int iy = 0; iy < 2; ++iy) {
+ for (int ix = 0; ix < 2; ++ix) {
+ int i = ix * 2 + iy;
+ SkRect r = SkRect::MakeXYWH(x + ix * fixed, y + iy * fixed,
+ size[i].width(), size[i].height());
+ canvas->drawBitmapNine(bm, center, r, &paint);
+ }
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new NinePatchStretchGM; }
+static GMRegistry reg(MyFactory);
+
+}
+
+
+
diff --git a/gm/nocolorbleed.cpp b/gm/nocolorbleed.cpp
index 3dec7cc..26b8184 100755
--- a/gm/nocolorbleed.cpp
+++ b/gm/nocolorbleed.cpp
@@ -1,10 +1,19 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "gm.h"
namespace skiagm {
class NoColorBleedGM : public GM {
public:
- NoColorBleedGM() {}
+ NoColorBleedGM() {
+ this->setBGColor(0xFFDDDDDD);
+ }
protected:
virtual SkString onShortName() {
@@ -15,13 +24,7 @@ protected:
return make_isize(200, 200);
}
- void drawBG(SkCanvas* canvas) {
- canvas->drawColor(0xFFDDDDDD);
- }
-
virtual void onDraw(SkCanvas* canvas) {
- drawBG(canvas);
-
SkBitmap sprite;
sprite.setConfig(SkBitmap::kARGB_8888_Config, 4, 4, 4*sizeof(SkColor));
const SkColor spriteData[16] = {
diff --git a/gm/pathfill.cpp b/gm/pathfill.cpp
index 713847f..9d4b3c8 100644
--- a/gm/pathfill.cpp
+++ b/gm/pathfill.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "gm.h"
#include "SkPicture.h"
#include "SkRectShape.h"
@@ -118,13 +125,7 @@ protected:
return make_isize(640, 480);
}
- void drawBG(SkCanvas* canvas) {
- canvas->drawColor(SK_ColorWHITE);
- }
-
virtual void onDraw(SkCanvas* canvas) {
- this->drawBG(canvas);
-
SkPaint paint;
paint.setAntiAlias(true);
diff --git a/gm/pathreverse.cpp b/gm/pathreverse.cpp
new file mode 100644
index 0000000..fc8028e
--- /dev/null
+++ b/gm/pathreverse.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkPath.h"
+#include "SkTypeface.h"
+
+static void test_path(SkCanvas* canvas, const SkPath& path) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ canvas->drawPath(path, paint);
+
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(SK_ColorRED);
+ canvas->drawPath(path, paint);
+}
+
+static void test_rev(SkCanvas* canvas, const SkPath& path) {
+ test_path(canvas, path);
+
+ SkPath rev;
+ rev.reverseAddPath(path);
+ canvas->save();
+ canvas->translate(150, 0);
+ test_path(canvas, rev);
+ canvas->restore();
+}
+
+static void test_rev(SkCanvas* canvas) {
+ SkRect r = { 10, 10, 100, 60 };
+
+ SkPath path;
+
+ path.addRect(r); test_rev(canvas, path);
+
+ canvas->translate(0, 100);
+ path.offset(20, 20);
+ path.addRect(r); test_rev(canvas, path);
+
+ canvas->translate(0, 100);
+ path.reset();
+ path.moveTo(10, 10); path.lineTo(30, 30);
+ path.addOval(r);
+ r.offset(50, 20);
+ path.addOval(r);
+ test_rev(canvas, path);
+
+ SkPaint paint;
+ paint.setTextSize(SkIntToScalar(100));
+ SkTypeface* hira = SkTypeface::CreateFromName("Hiragino Maru Gothic Pro", SkTypeface::kNormal);
+ SkSafeUnref(paint.setTypeface(hira));
+ path.reset();
+ paint.getTextPath("e", 1, 50, 50, &path);
+ canvas->translate(0, 100);
+ test_rev(canvas, path);
+}
+
+namespace skiagm {
+
+class PathReverseGM : public GM {
+public:
+ PathReverseGM() {
+
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("path-reverse");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(640, 480);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkRect r = { 10, 10, 100, 60 };
+
+ SkPath path;
+
+ path.addRect(r); test_rev(canvas, path);
+
+ canvas->translate(0, 100);
+ path.offset(20, 20);
+ path.addRect(r); test_rev(canvas, path);
+
+ canvas->translate(0, 100);
+ path.reset();
+ path.moveTo(10, 10); path.lineTo(30, 30);
+ path.addOval(r);
+ r.offset(50, 20);
+ path.addOval(r);
+ test_rev(canvas, path);
+
+ SkPaint paint;
+ paint.setTextSize(SkIntToScalar(100));
+ SkTypeface* hira = SkTypeface::CreateFromName("Hiragino Maru Gothic Pro", SkTypeface::kNormal);
+ SkSafeUnref(paint.setTypeface(hira));
+ path.reset();
+ paint.getTextPath("e", 1, 50, 50, &path);
+ canvas->translate(0, 100);
+ test_rev(canvas, path);
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new PathReverseGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/points.cpp b/gm/points.cpp
index 48d8fec..e4f3c2e 100644
--- a/gm/points.cpp
+++ b/gm/points.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "gm.h"
#include "SkRandom.h"
@@ -16,18 +23,18 @@ protected:
return make_isize(640, 490);
}
- void drawBG(SkCanvas* canvas) {
- canvas->drawColor(SK_ColorWHITE);
- }
-
static void fill_pts(SkPoint pts[], size_t n, SkRandom* rand) {
- for (size_t i = 0; i < n; i++)
- pts[i].set(rand->nextUScalar1() * 640, rand->nextUScalar1() * 480);
+ for (size_t i = 0; i < n; i++) {
+ // Compute these independently and store in variables, rather
+ // than in the parameter-passing expression, to get consistent
+ // evaluation order across compilers.
+ SkScalar y = rand->nextUScalar1() * 480;
+ SkScalar x = rand->nextUScalar1() * 640;
+ pts[i].set(x, y);
+ }
}
virtual void onDraw(SkCanvas* canvas) {
- this->drawBG(canvas);
-
canvas->translate(SK_Scalar1, SK_Scalar1);
SkRandom rand;
diff --git a/gm/poly2poly.cpp b/gm/poly2poly.cpp
index 193ede7..df824b5 100644
--- a/gm/poly2poly.cpp
+++ b/gm/poly2poly.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "gm.h"
namespace skiagm {
@@ -14,10 +21,6 @@ protected:
virtual SkISize onISize() {
return make_isize(835, 840);
}
-
- void drawBG(SkCanvas* canvas) {
- canvas->drawColor(SK_ColorWHITE);
- }
static void doDraw(SkCanvas* canvas, SkPaint* paint, const int isrc[],
const int idst[], int count) {
@@ -45,7 +48,7 @@ protected:
paint->setColor(SK_ColorRED);
paint->setStyle(SkPaint::kFill_Style);
SkScalar x = D/2;
- float y = D/2 - (fm.fAscent + fm.fDescent)/2;
+ SkScalar y = D/2 - (fm.fAscent + fm.fDescent)/2;
SkString str;
str.appendS32(count);
canvas->drawText(str.c_str(), str.size(), x, y, *paint);
@@ -53,9 +56,7 @@ protected:
canvas->restore();
}
- virtual void onDraw(SkCanvas* canvas) {
- this->drawBG(canvas);
-
+ virtual void onDraw(SkCanvas* canvas) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setStrokeWidth(SkIntToScalar(4));
diff --git a/gm/quadpaths.cpp b/gm/quadpaths.cpp
new file mode 100644
index 0000000..f8b172b
--- /dev/null
+++ b/gm/quadpaths.cpp
@@ -0,0 +1,307 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+
+namespace skiagm {
+
+class QuadPathGM : public GM {
+public:
+ QuadPathGM() {}
+
+protected:
+ SkString onShortName() {
+ return SkString("quadpath");
+ }
+
+ SkISize onISize() { return make_isize(1240, 390); }
+
+ void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+ const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
+ SkPaint::Style style, SkPath::FillType fill,
+ SkScalar strokeWidth) {
+ path.setFillType(fill);
+ SkPaint paint;
+ paint.setStrokeCap(cap);
+ paint.setStrokeWidth(strokeWidth);
+ paint.setStrokeJoin(join);
+ paint.setColor(color);
+ paint.setStyle(style);
+ canvas->save();
+ canvas->clipRect(clip);
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ struct FillAndName {
+ SkPath::FillType fFill;
+ const char* fName;
+ };
+ static const FillAndName gFills[] = {
+ {SkPath::kWinding_FillType, "Winding"},
+ {SkPath::kEvenOdd_FillType, "Even / Odd"},
+ {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+ {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+ };
+ struct StyleAndName {
+ SkPaint::Style fStyle;
+ const char* fName;
+ };
+ static const StyleAndName gStyles[] = {
+ {SkPaint::kFill_Style, "Fill"},
+ {SkPaint::kStroke_Style, "Stroke"},
+ {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+ };
+ struct CapAndName {
+ SkPaint::Cap fCap;
+ SkPaint::Join fJoin;
+ const char* fName;
+ };
+ static const CapAndName gCaps[] = {
+ {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+ {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+ {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
+ };
+ struct PathAndName {
+ SkPath fPath;
+ const char* fName;
+ };
+ PathAndName path;
+ path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
+ path.fPath.quadTo(50*SK_Scalar1, 20*SK_Scalar1,
+ 75*SK_Scalar1, 10*SK_Scalar1);
+ path.fName = "moveTo-quad";
+
+ SkPaint titlePaint;
+ titlePaint.setColor(SK_ColorBLACK);
+ titlePaint.setAntiAlias(true);
+ titlePaint.setLCDRenderText(true);
+ titlePaint.setTextSize(15 * SK_Scalar1);
+ const char title[] = "Quad Drawn Into Rectangle Clips With "
+ "Indicated Style, Fill and Linecaps, with stroke width 10";
+ canvas->drawText(title, strlen(title),
+ 20 * SK_Scalar1,
+ 20 * SK_Scalar1,
+ titlePaint);
+
+ SkRandom rand;
+ SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+ canvas->save();
+ canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+ canvas->save();
+ for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+ if (0 < cap) {
+ canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+ }
+ canvas->save();
+ for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+ if (0 < fill) {
+ canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+ }
+ canvas->save();
+ for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+ if (0 < style) {
+ canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
+ }
+
+ SkColor color = 0xff007000;
+ this->drawPath(path.fPath, canvas, color, rect,
+ gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+ gFills[fill].fFill, SK_Scalar1*10);
+
+ SkPaint rectPaint;
+ rectPaint.setColor(SK_ColorBLACK);
+ rectPaint.setStyle(SkPaint::kStroke_Style);
+ rectPaint.setStrokeWidth(-1);
+ rectPaint.setAntiAlias(true);
+ canvas->drawRect(rect, rectPaint);
+
+ SkPaint labelPaint;
+ labelPaint.setColor(color);
+ labelPaint.setAntiAlias(true);
+ labelPaint.setLCDRenderText(true);
+ labelPaint.setTextSize(10 * SK_Scalar1);
+ canvas->drawText(gStyles[style].fName,
+ strlen(gStyles[style].fName),
+ 0, rect.height() + 12 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gFills[fill].fName,
+ strlen(gFills[fill].fName),
+ 0, rect.height() + 24 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gCaps[cap].fName,
+ strlen(gCaps[cap].fName),
+ 0, rect.height() + 36 * SK_Scalar1,
+ labelPaint);
+ }
+ canvas->restore();
+ }
+ canvas->restore();
+ }
+ canvas->restore();
+ canvas->restore();
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+class QuadClosePathGM : public GM {
+public:
+ QuadClosePathGM() {}
+
+protected:
+ SkString onShortName() {
+ return SkString("quadclosepath");
+ }
+
+ SkISize onISize() { return make_isize(1240, 390); }
+
+ void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
+ const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
+ SkPaint::Style style, SkPath::FillType fill,
+ SkScalar strokeWidth) {
+ path.setFillType(fill);
+ SkPaint paint;
+ paint.setStrokeCap(cap);
+ paint.setStrokeWidth(strokeWidth);
+ paint.setStrokeJoin(join);
+ paint.setColor(color);
+ paint.setStyle(style);
+ canvas->save();
+ canvas->clipRect(clip);
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ struct FillAndName {
+ SkPath::FillType fFill;
+ const char* fName;
+ };
+ static const FillAndName gFills[] = {
+ {SkPath::kWinding_FillType, "Winding"},
+ {SkPath::kEvenOdd_FillType, "Even / Odd"},
+ {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+ {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+ };
+ struct StyleAndName {
+ SkPaint::Style fStyle;
+ const char* fName;
+ };
+ static const StyleAndName gStyles[] = {
+ {SkPaint::kFill_Style, "Fill"},
+ {SkPaint::kStroke_Style, "Stroke"},
+ {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+ };
+ struct CapAndName {
+ SkPaint::Cap fCap;
+ SkPaint::Join fJoin;
+ const char* fName;
+ };
+ static const CapAndName gCaps[] = {
+ {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
+ {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
+ {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
+ };
+ struct PathAndName {
+ SkPath fPath;
+ const char* fName;
+ };
+ PathAndName path;
+ path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
+ path.fPath.quadTo(50*SK_Scalar1, 20*SK_Scalar1,
+ 75*SK_Scalar1, 10*SK_Scalar1);
+ path.fPath.close();
+ path.fName = "moveTo-quad-close";
+
+ SkPaint titlePaint;
+ titlePaint.setColor(SK_ColorBLACK);
+ titlePaint.setAntiAlias(true);
+ titlePaint.setLCDRenderText(true);
+ titlePaint.setTextSize(15 * SK_Scalar1);
+ const char title[] = "Quad Closed Drawn Into Rectangle Clips With "
+ "Indicated Style, Fill and Linecaps, with stroke width 10";
+ canvas->drawText(title, strlen(title),
+ 20 * SK_Scalar1,
+ 20 * SK_Scalar1,
+ titlePaint);
+
+ SkRandom rand;
+ SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
+ canvas->save();
+ canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
+ canvas->save();
+ for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+ if (0 < cap) {
+ canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
+ }
+ canvas->save();
+ for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+ if (0 < fill) {
+ canvas->translate(0, rect.height() + 40 * SK_Scalar1);
+ }
+ canvas->save();
+ for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+ if (0 < style) {
+ canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
+ }
+
+ SkColor color = 0xff007000;
+ this->drawPath(path.fPath, canvas, color, rect,
+ gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
+ gFills[fill].fFill, SK_Scalar1*10);
+
+ SkPaint rectPaint;
+ rectPaint.setColor(SK_ColorBLACK);
+ rectPaint.setStyle(SkPaint::kStroke_Style);
+ rectPaint.setStrokeWidth(-1);
+ rectPaint.setAntiAlias(true);
+ canvas->drawRect(rect, rectPaint);
+
+ SkPaint labelPaint;
+ labelPaint.setColor(color);
+ labelPaint.setAntiAlias(true);
+ labelPaint.setLCDRenderText(true);
+ labelPaint.setTextSize(10 * SK_Scalar1);
+ canvas->drawText(gStyles[style].fName,
+ strlen(gStyles[style].fName),
+ 0, rect.height() + 12 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gFills[fill].fName,
+ strlen(gFills[fill].fName),
+ 0, rect.height() + 24 * SK_Scalar1,
+ labelPaint);
+ canvas->drawText(gCaps[cap].fName,
+ strlen(gCaps[cap].fName),
+ 0, rect.height() + 36 * SK_Scalar1,
+ labelPaint);
+ }
+ canvas->restore();
+ }
+ canvas->restore();
+ }
+ canvas->restore();
+ canvas->restore();
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* QuadPathFactory(void*) { return new QuadPathGM; }
+static GMRegistry regQuadPath(QuadPathFactory);
+
+static GM* QuadClosePathFactory(void*) { return new QuadClosePathGM; }
+static GMRegistry regQuadClosePath(QuadClosePathFactory);
+
+}
diff --git a/gm/shadertext.cpp b/gm/shadertext.cpp
index ea87823..b574ab6 100644
--- a/gm/shadertext.cpp
+++ b/gm/shadertext.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "gm.h"
#include "SkCanvas.h"
#include "SkGradientShader.h"
@@ -102,7 +109,9 @@ static const GradMaker gGradMakers[] = {
class ShaderTextGM : public GM {
public:
- ShaderTextGM() {}
+ ShaderTextGM() {
+ this->setBGColor(0xFFDDDDDD);
+ }
protected:
@@ -110,18 +119,12 @@ protected:
return SkString("shadertext");
}
- SkISize onISize() { return make_isize(950, 500); }
-
- void drawBG(SkCanvas* canvas) {
- canvas->drawColor(0xFFDDDDDD);
- }
+ SkISize onISize() { return make_isize(1450, 500); }
virtual void onDraw(SkCanvas* canvas) {
- this->drawBG(canvas);
-
const char text[] = "Shaded Text";
const int textLen = SK_ARRAY_COUNT(text) - 1;
- const int pointSize = 48;
+ const int pointSize = 36;
int w = pointSize * textLen;
int h = pointSize;
@@ -169,19 +172,34 @@ protected:
canvas->save();
canvas->translate(SkIntToScalar(20), SkIntToScalar(10));
+ SkPath path;
+ path.arcTo(SkRect::MakeXYWH(SkIntToScalar(-40), SkIntToScalar(15),
+ SkIntToScalar(300), SkIntToScalar(90)),
+ SkIntToScalar(225), SkIntToScalar(90),
+ false);
+ path.close();
+
static const int testsPerCol = 8;
static const int rowHeight = 60;
static const int colWidth = 300;
canvas->save();
for (size_t s = 0; s < SK_ARRAY_COUNT(shaders); s++) {
canvas->save();
- canvas->translate(SkIntToScalar((s / testsPerCol) * colWidth),
- SkIntToScalar((s % testsPerCol) * rowHeight));
- paint.setShader(shaders[s])->ref();
+ int i = 2*s;
+ canvas->translate(SkIntToScalar((i / testsPerCol) * colWidth),
+ SkIntToScalar((i % testsPerCol) * rowHeight));
+ paint.setShader(shaders[s])->unref();
canvas->drawText(text, textLen, 0, textBase, paint);
canvas->restore();
+ canvas->save();
+ ++i;
+ canvas->translate(SkIntToScalar((i / testsPerCol) * colWidth),
+ SkIntToScalar((i % testsPerCol) * rowHeight));
+ canvas->drawTextOnPath(text, textLen, path, NULL, paint);
+ canvas->restore();
}
canvas->restore();
+
}
private:
diff --git a/gm/shadows.cpp b/gm/shadows.cpp
index bba997f..d4dd72f 100644
--- a/gm/shadows.cpp
+++ b/gm/shadows.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "gm.h"
#include "SkBlurDrawLooper.h"
@@ -21,6 +28,7 @@ public:
SkRect fRect;
ShadowsGM() {
+ this->setBGColor(0xFFDDDDDD);
fCirclePath.addCircle(SkIntToScalar(20), SkIntToScalar(20), SkIntToScalar(10) );
fRect.set(SkIntToScalar(10), SkIntToScalar(10),
SkIntToScalar(30), SkIntToScalar(30));
@@ -35,13 +43,7 @@ protected:
return make_isize(200, 80);
}
- void drawBG(SkCanvas* canvas) {
- canvas->drawColor(0xFFDDDDDD);
- }
-
virtual void onDraw(SkCanvas* canvas) {
- this->drawBG(canvas);
-
SkBlurDrawLooper* shadowLoopers[5];
shadowLoopers[0] =
new SkBlurDrawLooper (SkIntToScalar(10), SkIntToScalar(5),
diff --git a/gm/shapes.cpp b/gm/shapes.cpp
index 5daea0a..0f46355 100644
--- a/gm/shapes.cpp
+++ b/gm/shapes.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "gm.h"
#include "SkPicture.h"
#include "SkRectShape.h"
@@ -43,6 +50,8 @@ class ShapesGM : public GM {
SkMatrixRef* fMatrixRefs[4];
public:
ShapesGM() {
+ this->setBGColor(0xFFDDDDDD);
+
SkMatrix m;
fGroup.appendShape(make_shape0(false))->unref();
m.setRotate(SkIntToScalar(30), SkIntToScalar(50), SkIntToScalar(50));
@@ -76,13 +85,7 @@ protected:
return make_isize(380, 480);
}
- void drawBG(SkCanvas* canvas) {
- canvas->drawColor(0xFFDDDDDD);
- }
-
virtual void onDraw(SkCanvas* canvas) {
- this->drawBG(canvas);
-
SkMatrix matrix;
SkGroupShape* gs = new SkGroupShape;
@@ -95,16 +98,14 @@ protected:
matrix.preScale(SK_Scalar1*2, SK_Scalar1*2);
gs->appendShape(&fGroup, matrix);
-#if 0
- canvas->drawShape(gs);
-#else
+#if 1
SkPicture* pict = new SkPicture;
SkCanvas* cv = pict->beginRecording(1000, 1000);
cv->scale(SK_ScalarHalf, SK_ScalarHalf);
- cv->drawShape(gs);
+ gs->draw(cv);
cv->translate(SkIntToScalar(680), SkIntToScalar(480));
cv->scale(-SK_Scalar1, SK_Scalar1);
- cv->drawShape(gs);
+ gs->draw(cv);
pict->endRecording();
canvas->drawPicture(*pict);
pict->unref();
diff --git a/gm/strokefill.cpp b/gm/strokefill.cpp
new file mode 100644
index 0000000..a37af80
--- /dev/null
+++ b/gm/strokefill.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkPath.h"
+#include "SkTypeface.h"
+
+namespace skiagm {
+
+class StrokeFillGM : public GM {
+public:
+ StrokeFillGM() {
+
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("stroke-fill");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(640, 480);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+ const char text[] = "Hello"; // "Hello";
+ const size_t len = sizeof(text) - 1;
+ paint.setAntiAlias(true);
+ paint.setTextSize(SkIntToScalar(100));
+// SkTypeface* hira = SkTypeface::CreateFromName("Hiragino Maru Gothic Pro", SkTypeface::kNormal);
+ SkTypeface* hira = SkTypeface::CreateFromName("Papyrus", SkTypeface::kNormal);
+ paint.setTypeface(hira);
+ SkScalar x = SkIntToScalar(180);
+ SkScalar y = SkIntToScalar(88);
+
+ canvas->drawText(text, len, x, y, paint);
+ paint.setFakeBoldText(true);
+ canvas->drawText(text, len, x, y + SkIntToScalar(100), paint);
+ paint.setStyle(SkPaint::kStrokeAndFill_Style);
+ paint.setStrokeWidth(SkIntToScalar(5));
+
+ SkPath path;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.addCircle(x, y + SkIntToScalar(200), SkIntToScalar(50), SkPath::kCW_Direction);
+ path.addCircle(x, y + SkIntToScalar(200), SkIntToScalar(40), SkPath::kCCW_Direction);
+ canvas->drawPath(path, paint);
+
+ SkPath path2;
+ path2.setFillType(SkPath::kWinding_FillType);
+ path2.addCircle(x + SkIntToScalar(120), y + SkIntToScalar(200), SkIntToScalar(50), SkPath::kCCW_Direction);
+ path2.addCircle(x + SkIntToScalar(120), y + SkIntToScalar(200), SkIntToScalar(40), SkPath::kCW_Direction);
+ canvas->drawPath(path2, paint);
+
+ path2.reset();
+ path2.addCircle(x + SkIntToScalar(240), y + SkIntToScalar(200), SkIntToScalar(50), SkPath::kCCW_Direction);
+ canvas->drawPath(path2, paint);
+ SkASSERT(path2.cheapIsDirection(SkPath::kCCW_Direction));
+
+ path2.reset();
+ SkASSERT(!path2.cheapComputeDirection(NULL));
+ path2.addCircle(x + SkIntToScalar(360), y + SkIntToScalar(200), SkIntToScalar(50), SkPath::kCW_Direction);
+ SkASSERT(path2.cheapIsDirection(SkPath::kCW_Direction));
+ canvas->drawPath(path2, paint);
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new StrokeFillGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/strokerects.cpp b/gm/strokerects.cpp
index 891b95a..92f2a18 100644
--- a/gm/strokerects.cpp
+++ b/gm/strokerects.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "gm.h"
#include "SkRandom.h"
@@ -45,14 +38,14 @@ protected:
SkScalar y = rand.nextUScalar1() * H;
SkScalar w = rand.nextUScalar1() * (W >> 2);
SkScalar h = rand.nextUScalar1() * (H >> 2);
+ SkScalar hoffset = rand.nextSScalar1();
+ SkScalar woffset = rand.nextSScalar1();
r->set(x, y, x + w, y + h);
- r->offset(-w/2 + rand.nextSScalar1(), -h/2 + + rand.nextSScalar1());
+ r->offset(-w/2 + woffset, -h/2 + hoffset);
}
virtual void onDraw(SkCanvas* canvas) {
- canvas->drawColor(SK_ColorWHITE);
-
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
diff --git a/gm/strokes.cpp b/gm/strokes.cpp
new file mode 100644
index 0000000..ec265ad
--- /dev/null
+++ b/gm/strokes.cpp
@@ -0,0 +1,149 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#include "gm.h"
+#include "SkRandom.h"
+
+namespace skiagm {
+
+#define W 400
+#define H 400
+#define N 50
+
+static const SkScalar SW = SkIntToScalar(W);
+static const SkScalar SH = SkIntToScalar(H);
+
+static void rnd_rect(SkRect* r, SkPaint* paint, SkRandom& rand) {
+ SkScalar x = rand.nextUScalar1() * W;
+ SkScalar y = rand.nextUScalar1() * H;
+ SkScalar w = rand.nextUScalar1() * (W >> 2);
+ SkScalar h = rand.nextUScalar1() * (H >> 2);
+ SkScalar hoffset = rand.nextSScalar1();
+ SkScalar woffset = rand.nextSScalar1();
+
+ r->set(x, y, x + w, y + h);
+ r->offset(-w/2 + woffset, -h/2 + hoffset);
+
+ paint->setColor(rand.nextU());
+ paint->setAlpha(0xFF);
+}
+
+
+class StrokesGM : public GM {
+public:
+ StrokesGM() {}
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("strokes_round");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(W, H*2);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkIntToScalar(9)/2);
+
+ for (int y = 0; y < 2; y++) {
+ paint.setAntiAlias(!!y);
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->translate(0, SH * y);
+ canvas->clipRect(SkRect::MakeLTRB(
+ SkIntToScalar(2), SkIntToScalar(2)
+ , SW - SkIntToScalar(2), SH - SkIntToScalar(2)
+ ));
+
+ SkRandom rand;
+ for (int i = 0; i < N; i++) {
+ SkRect r;
+ rnd_rect(&r, &paint, rand);
+ canvas->drawOval(r, paint);
+ rnd_rect(&r, &paint, rand);
+ canvas->drawRoundRect(r, r.width()/4, r.height()/4, paint);
+ rnd_rect(&r, &paint, rand);
+ }
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+class Strokes2GM : public GM {
+ SkPath fPath;
+public:
+ Strokes2GM() {
+ SkRandom rand;
+ fPath.moveTo(0, 0);
+ for (int i = 0; i < 13; i++) {
+ SkScalar x = rand.nextUScalar1() * (W >> 1);
+ SkScalar y = rand.nextUScalar1() * (H >> 1);
+ fPath.lineTo(x, y);
+ }
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("strokes_poly");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(W, H*2);
+ }
+
+ static void rotate(SkScalar angle, SkScalar px, SkScalar py, SkCanvas* canvas) {
+ SkMatrix matrix;
+ matrix.setRotate(angle, px, py);
+ canvas->concat(matrix);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorWHITE);
+
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkIntToScalar(9)/2);
+
+ for (int y = 0; y < 2; y++) {
+ paint.setAntiAlias(!!y);
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->translate(0, SH * y);
+ canvas->clipRect(SkRect::MakeLTRB(SkIntToScalar(2),
+ SkIntToScalar(2),
+ SW - SkIntToScalar(2),
+ SH - SkIntToScalar(2)));
+
+ SkRandom rand;
+ for (int i = 0; i < N/2; i++) {
+ SkRect r;
+ rnd_rect(&r, &paint, rand);
+ rotate(SkIntToScalar(15), SW/2, SH/2, canvas);
+ canvas->drawPath(fPath, paint);
+ }
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new StrokesGM; }
+static GMRegistry reg(MyFactory);
+
+static GM* MyFactory2(void*) { return new Strokes2GM; }
+static GMRegistry reg2(MyFactory2);
+
+}
+
diff --git a/gm/tablecolorfilter.cpp b/gm/tablecolorfilter.cpp
new file mode 100644
index 0000000..df33337
--- /dev/null
+++ b/gm/tablecolorfilter.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkTableColorFilter.h"
+
+static void make_bm0(SkBitmap* bm) {
+ int W = 120;
+ int H = 120;
+ bm->setConfig(SkBitmap::kARGB_8888_Config, W, H);
+ bm->allocPixels();
+ bm->eraseColor(0);
+
+ SkCanvas canvas(*bm);
+ SkPaint paint;
+ SkPoint pts[] = { {0, 0}, {SkIntToScalar(W), SkIntToScalar(H)} };
+ SkColor colors[] = {
+ SK_ColorBLACK, SK_ColorGREEN, SK_ColorCYAN,
+ SK_ColorRED, 0, SK_ColorBLUE, SK_ColorWHITE
+ };
+ SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, SK_ARRAY_COUNT(colors),
+ SkShader::kClamp_TileMode);
+ paint.setShader(s)->unref();
+ canvas.drawPaint(paint);
+}
+static void make_bm1(SkBitmap* bm) {
+ int W = 120;
+ int H = 120;
+ bm->setConfig(SkBitmap::kARGB_8888_Config, W, H);
+ bm->allocPixels();
+ bm->eraseColor(0);
+
+ SkCanvas canvas(*bm);
+ SkPaint paint;
+ SkScalar cx = SkIntToScalar(W)/2;
+ SkScalar cy = SkIntToScalar(H)/2;
+ SkColor colors[] = {
+ SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE,
+ };
+ SkShader* s = SkGradientShader::CreateRadial(SkPoint::Make(SkIntToScalar(W)/2,
+ SkIntToScalar(H)/2),
+ SkIntToScalar(W)/2, colors, NULL, SK_ARRAY_COUNT(colors),
+ SkShader::kClamp_TileMode);
+ paint.setShader(s)->unref();
+ paint.setAntiAlias(true);
+ canvas.drawCircle(cx, cy, cx, paint);
+}
+
+static void make_table0(uint8_t table[]) {
+ for (int i = 0; i < 256; ++i) {
+ int n = i >> 5;
+ table[i] = (n << 5) | (n << 2) | (n >> 1);
+ }
+}
+static void make_table1(uint8_t table[]) {
+ for (int i = 0; i < 256; ++i) {
+ table[i] = i * i / 255;
+ }
+}
+static void make_table2(uint8_t table[]) {
+ for (int i = 0; i < 256; ++i) {
+ float fi = i / 255.0f;
+ table[i] = sqrtf(fi) * 255;
+ }
+}
+
+static SkColorFilter* make_cf0() {
+ uint8_t table[256]; make_table0(table);
+ return SkTableColorFilter::Create(table);
+}
+static SkColorFilter* make_cf1() {
+ uint8_t table[256]; make_table1(table);
+ return SkTableColorFilter::Create(table);
+}
+static SkColorFilter* make_cf2() {
+ uint8_t table[256]; make_table2(table);
+ return SkTableColorFilter::Create(table);
+}
+static SkColorFilter* make_cf3() {
+ uint8_t table0[256]; make_table0(table0);
+ uint8_t table1[256]; make_table1(table1);
+ uint8_t table2[256]; make_table2(table2);
+ return SkTableColorFilter::CreateARGB(NULL, table0, table1, table2);
+}
+
+class TableColorFilterGM : public skiagm::GM {
+public:
+ TableColorFilterGM() {}
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("tablecolorfilter");
+ }
+
+ virtual SkISize onISize() {
+ return SkISize::Make(640, 480);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ canvas->drawColor(0xFFDDDDDD);
+ canvas->translate(20, 20);
+
+ SkScalar x = 0, y = 0;
+
+ static void (*gMakers[])(SkBitmap*) = { make_bm0, make_bm1 };
+ for (size_t maker = 0; maker < SK_ARRAY_COUNT(gMakers); ++maker) {
+ SkBitmap bm;
+ gMakers[maker](&bm);
+
+ SkPaint paint;
+ x = 0;
+ canvas->drawBitmap(bm, x, y, &paint);
+ paint.setColorFilter(make_cf0())->unref(); x += bm.width() * 9 / 8;
+ canvas->drawBitmap(bm, x, y, &paint);
+ paint.setColorFilter(make_cf1())->unref(); x += bm.width() * 9 / 8;
+ canvas->drawBitmap(bm, x, y, &paint);
+ paint.setColorFilter(make_cf2())->unref(); x += bm.width() * 9 / 8;
+ canvas->drawBitmap(bm, x, y, &paint);
+ paint.setColorFilter(make_cf3())->unref(); x += bm.width() * 9 / 8;
+ canvas->drawBitmap(bm, x, y, &paint);
+
+ y += bm.height() * 9 / 8;
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static skiagm::GM* MyFactory(void*) { return new TableColorFilterGM; }
+static skiagm::GMRegistry reg(MyFactory);
diff --git a/gm/testimagefilters.cpp b/gm/testimagefilters.cpp
new file mode 100644
index 0000000..fc71d30
--- /dev/null
+++ b/gm/testimagefilters.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkColorFilter.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+
+#include "SkBlurImageFilter.h"
+#include "SkTestImageFilters.h"
+
+#define FILTER_WIDTH SkIntToScalar(150)
+#define FILTER_HEIGHT SkIntToScalar(200)
+
+static SkImageFilter* make0() { return new SkDownSampleImageFilter(SK_Scalar1 / 5); }
+static SkImageFilter* make1() { return new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16)); }
+static SkImageFilter* make2() {
+ SkColorFilter* cf = SkColorFilter::CreateModeFilter(SK_ColorBLUE,
+ SkXfermode::kSrcIn_Mode);
+ SkAutoUnref aur(cf);
+ return new SkColorFilterImageFilter(cf);
+}
+static SkImageFilter* make3() {
+ return new SkBlurImageFilter(8, 0);
+}
+
+static SkImageFilter* make4() {
+ SkImageFilter* outer = new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16));
+ SkImageFilter* inner = new SkDownSampleImageFilter(SK_Scalar1 / 5);
+ SkAutoUnref aur0(outer);
+ SkAutoUnref aur1(inner);
+ return new SkComposeImageFilter(outer, inner);
+}
+static SkImageFilter* make5() {
+ SkImageFilter* first = new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16));
+ SkImageFilter* second = new SkDownSampleImageFilter(SK_Scalar1 / 5);
+ SkAutoUnref aur0(first);
+ SkAutoUnref aur1(second);
+ return new SkMergeImageFilter(first, second);
+}
+
+static SkImageFilter* make6() {
+ SkImageFilter* outer = new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16));
+ SkImageFilter* inner = new SkDownSampleImageFilter(SK_Scalar1 / 5);
+ SkAutoUnref aur0(outer);
+ SkAutoUnref aur1(inner);
+ SkImageFilter* compose = new SkComposeImageFilter(outer, inner);
+ SkAutoUnref aur2(compose);
+
+ SkColorFilter* cf = SkColorFilter::CreateModeFilter(0x880000FF,
+ SkXfermode::kSrcIn_Mode);
+ SkAutoUnref aur3(cf);
+ SkImageFilter* blue = new SkColorFilterImageFilter(cf);
+ SkAutoUnref aur4(blue);
+
+ return new SkMergeImageFilter(compose, blue);
+}
+
+static SkImageFilter* make7() {
+ SkImageFilter* outer = new SkOffsetImageFilter(SkIntToScalar(16), SkIntToScalar(16));
+ SkImageFilter* inner = make3();
+ SkAutoUnref aur0(outer);
+ SkAutoUnref aur1(inner);
+ SkImageFilter* compose = new SkComposeImageFilter(outer, inner);
+ SkAutoUnref aur2(compose);
+
+ SkColorFilter* cf = SkColorFilter::CreateModeFilter(0x880000FF,
+ SkXfermode::kSrcIn_Mode);
+ SkAutoUnref aur3(cf);
+ SkImageFilter* blue = new SkColorFilterImageFilter(cf);
+ SkAutoUnref aur4(blue);
+
+ return new SkMergeImageFilter(compose, blue);
+}
+
+static void draw0(SkCanvas* canvas) {
+ SkPaint p;
+ p.setAntiAlias(true);
+ SkRect r = SkRect::MakeWH(FILTER_WIDTH, FILTER_HEIGHT);
+ r.inset(SK_Scalar1 * 12, SK_Scalar1 * 12);
+ p.setColor(SK_ColorRED);
+ canvas->drawOval(r, p);
+}
+
+class TestImageFiltersGM : public skiagm::GM {
+public:
+ TestImageFiltersGM () {}
+
+protected:
+
+ virtual SkString onShortName() {
+ return SkString("testimagefilters");
+ }
+
+ virtual SkISize onISize() { return SkISize::Make(700, 460); }
+
+ virtual void onDraw(SkCanvas* canvas) {
+// this->drawSizeBounds(canvas, 0xFFCCCCCC);
+
+ static SkImageFilter* (*gFilterProc[])() = {
+ make0, make1, make2, make3, make4, make5, make6, make7
+ };
+
+ const SkRect bounds = SkRect::MakeWH(FILTER_WIDTH, FILTER_HEIGHT);
+
+ const SkScalar dx = bounds.width() * 8 / 7;
+ const SkScalar dy = bounds.height() * 8 / 7;
+
+ canvas->translate(SkIntToScalar(8), SkIntToScalar(8));
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gFilterProc); ++i) {
+ int ix = i % 4;
+ int iy = i / 4;
+
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->translate(ix * dx, iy * dy);
+
+ SkPaint p;
+ p.setStyle(SkPaint::kStroke_Style);
+ canvas->drawRect(bounds, p);
+
+ SkPaint paint;
+ paint.setImageFilter(gFilterProc[i]())->unref();
+ canvas->saveLayer(&bounds, &paint);
+ draw0(canvas);
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static skiagm::GM* MyFactory(void*) { return new TestImageFiltersGM; }
+static skiagm::GMRegistry reg(MyFactory);
+
+
diff --git a/gm/texdata.cpp b/gm/texdata.cpp
new file mode 100644
index 0000000..c68a16a
--- /dev/null
+++ b/gm/texdata.cpp
@@ -0,0 +1,146 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+#include "GrContext.h"
+#include "SkColorPriv.h"
+#include "SkDevice.h"
+
+namespace skiagm {
+
+extern GrContext* GetGr();
+
+static const int S = 200;
+
+class TexDataGM : public GM {
+public:
+ TexDataGM() {
+ this->setBGColor(0xff000000);
+ }
+
+protected:
+ virtual SkString onShortName() {
+ return SkString("texdata");
+ }
+
+ virtual SkISize onISize() {
+ return make_isize(2*S, 2*S);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkDevice* device = canvas->getDevice();
+ GrRenderTarget* target = (GrRenderTarget*) device->accessRenderTarget();
+ GrContext* ctx = GetGr();
+ if (ctx && target) {
+ SkPMColor gTextureData[(2 * S) * (2 * S)];
+ static const int stride = 2 * S;
+ static const SkPMColor gray = SkPackARGB32(0x40, 0x40, 0x40, 0x40);
+ static const SkPMColor white = SkPackARGB32(0xff, 0xff, 0xff, 0xff);
+ static const SkPMColor red = SkPackARGB32(0x80, 0x80, 0x00, 0x00);
+ static const SkPMColor blue = SkPackARGB32(0x80, 0x00, 0x00, 0x80);
+ static const SkPMColor green = SkPackARGB32(0x80, 0x00, 0x80, 0x00);
+ static const SkPMColor black = SkPackARGB32(0x00, 0x00, 0x00, 0x00);
+ for (int i = 0; i < 2; ++i) {
+ int offset = 0;
+ // fill upper-left
+ for (int y = 0; y < S; ++y) {
+ for (int x = 0; x < S; ++x) {
+ gTextureData[offset + y * stride + x] = gray;
+ }
+ }
+ // fill upper-right
+ offset = S;
+ for (int y = 0; y < S; ++y) {
+ for (int x = 0; x < S; ++x) {
+ gTextureData[offset + y * stride + x] = white;
+ }
+ }
+ // fill lower left
+ offset = S * stride;
+ for (int y = 0; y < S; ++y) {
+ for (int x = 0; x < S; ++x) {
+ gTextureData[offset + y * stride + x] = black;
+ }
+ }
+ // fill lower right
+ offset = S * stride + S;
+ for (int y = 0; y < S; ++y) {
+ for (int x = 0; x < S; ++x) {
+ gTextureData[offset + y * stride + x] = gray;
+ }
+ }
+
+ GrTextureDesc desc;
+ desc.fAALevel = kNone_GrAALevel;
+ // use RT flag bit because in GL it makes the texture be bottom-up
+ desc.fFlags = i ? kRenderTarget_GrTextureFlagBit :
+ kNone_GrTextureFlags;
+ desc.fConfig = kSkia8888_PM_GrPixelConfig;
+ desc.fWidth = 2 * S;
+ desc.fHeight = 2 * S;
+ GrTexture* texture =
+ ctx->createUncachedTexture(desc, gTextureData, 0);
+
+ if (!texture) {
+ return;
+ }
+ GrAutoUnref au(texture);
+
+ ctx->setClip(GrRect::MakeWH(2*S, 2*S));
+ ctx->setRenderTarget(target);
+
+ GrPaint paint;
+ paint.reset();
+ paint.fColor = 0xffffffff;
+ paint.fSrcBlendCoeff = kOne_BlendCoeff;
+ paint.fDstBlendCoeff = kISA_BlendCoeff;
+ GrMatrix vm;
+ if (i) {
+ vm.setRotate(90 * SK_Scalar1,
+ S * SK_Scalar1,
+ S * SK_Scalar1);
+ } else {
+ vm.reset();
+ }
+ ctx->setMatrix(vm);
+ GrMatrix tm;
+ tm = vm;
+ GrMatrix* sampleMat = paint.textureSampler(0)->matrix();
+ *sampleMat = vm;
+ sampleMat->postIDiv(2*S, 2*S);
+ paint.setTexture(0, texture);
+
+ ctx->drawRect(paint, GrRect::MakeWH(2*S, 2*S));
+
+ // now update the lower right of the texture in first pass
+ // or upper right in second pass
+ offset = 0;
+ for (int y = 0; y < S; ++y) {
+ for (int x = 0; x < S; ++x) {
+ gTextureData[offset + y * stride + x] =
+ ((x + y) % 2) ? (i ? green : red) : blue;
+ }
+ }
+ texture->writePixels(S, (i ? 0 : S), S, S,
+ texture->config(), gTextureData,
+ 4 * stride);
+ ctx->drawRect(paint, GrRect::MakeWH(2*S, 2*S));
+ }
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new TexDataGM; }
+static GMRegistry reg(MyFactory);
+
+}
+
diff --git a/gm/tilemodes.cpp b/gm/tilemodes.cpp
index d836ea5..289caae 100644
--- a/gm/tilemodes.cpp
+++ b/gm/tilemodes.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "gm.h"
#include "SkPath.h"
#include "SkRegion.h"
@@ -73,12 +80,7 @@ protected:
SkISize onISize() { return make_isize(880, 560); }
- void drawBG(SkCanvas* canvas) {
- canvas->drawColor(SK_ColorWHITE);
- }
-
virtual void onDraw(SkCanvas* canvas) {
- this->drawBG(canvas);
SkRect r = { 0, 0, SkIntToScalar(gWidth*2), SkIntToScalar(gHeight*2) };
diff --git a/gm/tinybitmap.cpp b/gm/tinybitmap.cpp
new file mode 100644
index 0000000..d532b5b
--- /dev/null
+++ b/gm/tinybitmap.cpp
@@ -0,0 +1,68 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+#include "SkCanvas.h"
+#include "SkUtils.h"
+
+namespace skiagm {
+
+static SkBitmap make_bitmap() {
+ SkBitmap bm;
+
+ SkColorTable* ctable = new SkColorTable(1);
+ SkPMColor* c = ctable->lockColors();
+ c[0] = SkPackARGB32(0x80, 0x80, 0, 0);
+ ctable->unlockColors(true);
+
+ bm.setConfig(SkBitmap::kIndex8_Config, 1, 1);
+ bm.allocPixels(ctable);
+ ctable->unref();
+
+ bm.lockPixels();
+ *bm.getAddr8(0, 0) = 0;
+ bm.unlockPixels();
+ return bm;
+}
+
+class TinyBitmapGM : public GM {
+ SkBitmap fBM;
+public:
+ TinyBitmapGM() {
+ this->setBGColor(0xFFDDDDDD);
+ fBM = make_bitmap();
+ }
+
+protected:
+ SkString onShortName() {
+ return SkString("tinybitmap");
+ }
+
+ virtual SkISize onISize() { return make_isize(100, 100); }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkShader* s =
+ SkShader::CreateBitmapShader(fBM, SkShader::kRepeat_TileMode,
+ SkShader::kMirror_TileMode);
+ SkPaint paint;
+ paint.setAlpha(0x80);
+ paint.setShader(s)->unref();
+ canvas->drawPaint(paint);
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new TinyBitmapGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/verttext.cpp b/gm/verttext.cpp
new file mode 100644
index 0000000..0f3cb3b
--- /dev/null
+++ b/gm/verttext.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "gm.h"
+#include "SkCanvas.h"
+
+namespace skiagm {
+
+#define TEXT_SIZE 48
+static const char gText[] = "Hello";
+static const size_t gLen = sizeof(gText) - 1;
+
+class VertTextGM : public GM {
+public:
+ VertTextGM() {}
+
+protected:
+
+ SkString onShortName() {
+ return SkString("verttext");
+ }
+
+ SkISize onISize() { return make_isize(640, 480); }
+
+ static void drawBaseline(SkCanvas* canvas, const SkPaint& paint,
+ SkScalar x, SkScalar y) {
+ SkScalar total = paint.measureText(gText, gLen);
+
+ SkPaint p;
+ p.setAntiAlias(true);
+ p.setColor(0x80FF0000);
+ canvas->drawLine(x, y,
+ paint.isVerticalText() ? x : x + total,
+ paint.isVerticalText() ? y + total : y,
+ p);
+
+ p.setColor(0xFF0000FF);
+ SkScalar adv[gLen];
+ paint.getTextWidths(gText, gLen, adv, NULL);
+ for (size_t i = 0; i < gLen; ++i) {
+ canvas->drawCircle(x, y, SK_Scalar1 * 3 / 2, p);
+ if (paint.isVerticalText()) {
+ y += adv[i];
+ } else {
+ x += adv[i];
+ }
+ }
+ canvas->drawCircle(x, y, SK_Scalar1 * 3 / 2, p);
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkScalar x = SkIntToScalar(100);
+ SkScalar y = SkIntToScalar(50);
+
+ for (int i = 0; i < 4; ++i) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setTextSize(SkIntToScalar(TEXT_SIZE));
+
+
+ paint.setVerticalText(false);
+ drawBaseline(canvas, paint, x, y);
+ canvas->drawText(gText, gLen, x, y, paint);
+
+ paint.setVerticalText(true);
+ drawBaseline(canvas, paint, x, y);
+ canvas->drawText(gText, gLen, x, y, paint);
+
+ x += SkIntToScalar(40);
+ y += SkIntToScalar(120);
+
+ canvas->rotate(SkIntToScalar(-15));
+ }
+ }
+
+private:
+ typedef GM INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new VertTextGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/verttext2.cpp b/gm/verttext2.cpp
new file mode 100644
index 0000000..3bfb471
--- /dev/null
+++ b/gm/verttext2.cpp
@@ -0,0 +1,92 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+/* Tests text vertical text rendering with different fonts and centering.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkTypeface.h"
+
+namespace skiagm {
+
+class VertText2GM : public GM {
+public:
+ VertText2GM() {
+ const int pointSize = 24;
+ textHeight = SkIntToScalar(pointSize);
+ prop = SkTypeface::CreateFromName("Helvetica", SkTypeface::kNormal);
+ mono = SkTypeface::CreateFromName("Courier New", SkTypeface::kNormal);
+ }
+
+protected:
+
+ SkString onShortName() {
+ return SkString("verttext2");
+ }
+
+ SkISize onISize() { return make_isize(640, 480); }
+
+ virtual void onDraw(SkCanvas* canvas) {
+
+ for (int i = 0; i < 3; ++i) {
+ SkPaint paint;
+ paint.setColor(SK_ColorRED);
+ paint.setAntiAlias(true);
+ y = textHeight;
+ canvas->drawLine(0, SkIntToScalar(10),
+ SkIntToScalar(110), SkIntToScalar(10), paint);
+ canvas->drawLine(0, SkIntToScalar(240),
+ SkIntToScalar(110), SkIntToScalar(240), paint);
+ canvas->drawLine(0, SkIntToScalar(470),
+ SkIntToScalar(110), SkIntToScalar(470), paint);
+ drawText(canvas, SkString("Proportional / Top Aligned"),
+ prop, SkPaint::kLeft_Align);
+ drawText(canvas, SkString("< Proportional / Centered >"),
+ prop, SkPaint::kCenter_Align);
+ drawText(canvas, SkString("Monospaced / Top Aligned"),
+ mono, SkPaint::kLeft_Align);
+ drawText(canvas, SkString("< Monospaced / Centered >"),
+ mono, SkPaint::kCenter_Align);
+ canvas->rotate(SkIntToScalar(-15));
+ canvas->translate(textHeight * 4, SkIntToScalar(50));
+ if (i > 0) {
+ canvas->translate(0, SkIntToScalar(50));
+ }
+ }
+ }
+
+ void drawText(SkCanvas* canvas, const SkString& string,
+ SkTypeface* family, SkPaint::Align alignment) {
+ SkPaint paint;
+ paint.setColor(SK_ColorBLACK);
+ paint.setAntiAlias(true);
+ paint.setVerticalText(true);
+ paint.setTextAlign(alignment);
+ paint.setTypeface(family);
+ paint.setTextSize(textHeight);
+
+ canvas->drawText(string.c_str(), string.size(), y,
+ alignment == SkPaint::kLeft_Align ? 10 : 240, paint);
+ y += textHeight;
+ }
+
+private:
+ typedef GM INHERITED;
+ SkScalar y, textHeight;
+ SkTypeface* prop;
+ SkTypeface* mono;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new VertText2GM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gm/xfermodes.cpp b/gm/xfermodes.cpp
index b8565a3..42b8a6a 100644
--- a/gm/xfermodes.cpp
+++ b/gm/xfermodes.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "gm.h"
#include "SkBitmap.h"
#include "SkShader.h"
@@ -31,11 +38,10 @@ static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst) {
c.drawRect(r, p);
}
-static uint16_t gBG[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF };
-
class XfermodesGM : public GM {
SkBitmap fBG;
SkBitmap fSrcB, fDstB;
+ bool fOnce;
void draw_mode(SkCanvas* canvas, SkXfermode* mode, int alpha,
SkScalar x, SkScalar y) {
@@ -47,20 +53,25 @@ class XfermodesGM : public GM {
canvas->drawBitmap(fDstB, x, y, &p);
}
+ void init() {
+ if (!fOnce) {
+ // Do all this work in a temporary so we get a deep copy
+ uint16_t localData[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF };
+ SkBitmap scratchBitmap;
+ scratchBitmap.setConfig(SkBitmap::kARGB_4444_Config, 2, 2, 4);
+ scratchBitmap.setPixels(localData);
+ scratchBitmap.setIsOpaque(true);
+ scratchBitmap.copyTo(&fBG, SkBitmap::kARGB_4444_Config);
+
+ make_bitmaps(W, H, &fSrcB, &fDstB);
+ fOnce = true;
+ }
+ }
+
public:
const static int W = 64;
const static int H = 64;
- XfermodesGM() {
- // Do all this work in a temporary so we get a deep copy,
- // especially of gBG.
- SkBitmap scratchBitmap;
- scratchBitmap.setConfig(SkBitmap::kARGB_4444_Config, 2, 2, 4);
- scratchBitmap.setPixels(gBG);
- scratchBitmap.setIsOpaque(true);
- scratchBitmap.copyTo(&fBG, SkBitmap::kARGB_4444_Config);
-
- make_bitmaps(W, H, &fSrcB, &fDstB);
- }
+ XfermodesGM() : fOnce(false) {}
protected:
virtual SkString onShortName() {
@@ -71,14 +82,10 @@ protected:
return make_isize(790, 640);
}
- void drawBG(SkCanvas* canvas) {
- canvas->drawColor(SK_ColorWHITE);
- }
-
virtual void onDraw(SkCanvas* canvas) {
- canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
+ this->init();
- this->drawBG(canvas);
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
const struct {
SkXfermode::Mode fMode;
diff --git a/gpu/include/FlingState.h b/gpu/include/FlingState.h
deleted file mode 100644
index 3923f27..0000000
--- a/gpu/include/FlingState.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef SkFlingState_DEFINED
-#define SkFlingState_DEFINED
-
-#include "SkScalar.h"
-#include "SkPoint.h"
-
-class SkMatrix;
-
-struct FlingState {
- FlingState() : fActive(false) {}
-
- bool isActive() const { return fActive; }
- void stop() { fActive = false; }
-
- void reset(float sx, float sy);
- bool evaluateMatrix(SkMatrix* matrix);
-
-private:
- SkPoint fDirection;
- SkScalar fSpeed0;
- double fTime0;
- bool fActive;
-};
-
-class GrAnimateFloat {
-public:
- GrAnimateFloat();
-
- void start(float v0, float v1, float duration);
- bool isActive() const { return fTime0 != 0; }
- void stop() { fTime0 = 0; }
-
- float evaluate();
-
-private:
- float fValue0, fValue1, fDuration;
- SkMSec fTime0;
-};
-
-#endif
-
diff --git a/gpu/include/GrContext.h b/gpu/include/GrContext.h
deleted file mode 100644
index 8809271..0000000
--- a/gpu/include/GrContext.h
+++ /dev/null
@@ -1,623 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#ifndef GrContext_DEFINED
-#define GrContext_DEFINED
-
-#include "GrClip.h"
-#include "GrTextureCache.h"
-#include "GrPaint.h"
-#include "GrPathRenderer.h"
-
-class GrFontCache;
-class GrGpu;
-struct GrGpuStats;
-class GrVertexBufferAllocPool;
-class GrIndexBufferAllocPool;
-class GrInOrderDrawBuffer;
-
-class GR_API GrContext : public GrRefCnt {
-public:
- /**
- * Creates a GrContext from within a 3D context.
- */
- static GrContext* Create(GrEngine engine,
- GrPlatform3DContext context3D);
-
- /**
- * Helper to create a opengl-shader based context
- */
- static GrContext* CreateGLShaderContext();
-
- virtual ~GrContext();
-
- /**
- * The GrContext normally assumes that no outsider is setting state
- * within the underlying 3D API's context/device/whatever. This call informs
- * the context that the state was modified and it should resend. Shouldn't
- * be called frequently for good performance.
- */
- void resetContext();
-
- /**
- * Abandons all gpu resources, assumes 3D API state is unknown. Call this
- * if you have lost the associated GPU context, and thus internal texture,
- * buffer, etc. references/IDs are now invalid. Should be called even when
- * GrContext is no longer going to be used for two reasons:
- * 1) ~GrContext will not try to free the objects in the 3D API.
- * 2) If you've created GrResources that outlive the GrContext they will
- * be marked as invalid (GrResource::isValid()) and won't attempt to
- * free their underlying resource in the 3D API.
- * Content drawn since the last GrContext::flush() may be lost.
- */
- void contextLost();
-
- /**
- * Similar to contextLost, but makes no attempt to reset state.
- * Use this method when GrContext destruction is pending, but
- * the graphics context is destroyed first.
- */
- void contextDestroyed();
-
- /**
- * Frees gpu created by the context. Can be called to reduce GPU memory
- * pressure.
- */
- void freeGpuResources();
-
- ///////////////////////////////////////////////////////////////////////////
- // Textures
-
- /**
- * Search for an entry with the same Key. If found, "lock" it and return it.
- * If not found, return null.
- */
- GrTextureEntry* findAndLockTexture(GrTextureKey*,
- const GrSamplerState&);
-
-
- /**
- * Create a new entry, based on the specified key and texture, and return
- * its "locked" entry.
- *
- * Ownership of the texture is transferred to the Entry, which will unref()
- * it when we are purged or deleted.
- */
- GrTextureEntry* createAndLockTexture(GrTextureKey* key,
- const GrSamplerState&,
- const GrTextureDesc&,
- void* srcData, size_t rowBytes);
-
- /**
- * Returns a texture matching the desc. It's contents are unknown. Subsequent
- * requests with the same descriptor are not guaranteed to return the same
- * texture. The same texture is guaranteed not be returned again until it is
- * unlocked.
- *
- * Textures created by createAndLockTexture() hide the complications of
- * tiling non-power-of-two textures on APIs that don't support this (e.g.
- * unextended GLES2). Tiling a npot texture created by lockKeylessTexture on
- * such an API will create gaps in the tiling pattern. This includes clamp
- * mode. (This may be addressed in a future update.)
- */
- GrTextureEntry* lockKeylessTexture(const GrTextureDesc& desc);
-
- /**
- * When done with an entry, call unlockTexture(entry) on it, which returns
- * it to the cache, where it may be purged.
- */
- void unlockTexture(GrTextureEntry* entry);
-
- /**
- * Creates a texture that is outside the cache. Does not count against
- * cache's budget.
- */
- GrTexture* createUncachedTexture(const GrTextureDesc&,
- void* srcData,
- size_t rowBytes);
-
- /**
- * Returns true if the specified use of an indexed texture is supported.
- */
- bool supportsIndex8PixelConfig(const GrSamplerState&, int width, int height);
-
- /**
- * Return the current texture cache limits.
- *
- * @param maxTextures If non-null, returns maximum number of textures that
- * can be held in the cache.
- * @param maxTextureBytes If non-null, returns maximum number of bytes of
- * texture memory that can be held in the cache.
- */
- void getTextureCacheLimits(int* maxTextures, size_t* maxTextureBytes) const;
-
- /**
- * Specify the texture cache limits. If the current cache exceeds either
- * of these, it will be purged (LRU) to keep the cache within these limits.
- *
- * @param maxTextures The maximum number of textures that can be held in
- * the cache.
- * @param maxTextureBytes The maximum number of bytes of texture memory
- * that can be held in the cache.
- */
- void setTextureCacheLimits(int maxTextures, size_t maxTextureBytes);
-
- /**
- * Return the max width or height of a texture supported by the current gpu
- */
- int getMaxTextureDimension();
-
- ///////////////////////////////////////////////////////////////////////////
- // Render targets
-
- /**
- * Sets the render target.
- * @param target the render target to set. (should not be NULL.)
- */
- void setRenderTarget(GrRenderTarget* target);
-
- /**
- * Gets the current render target.
- * @return the currently bound render target. Should never be NULL.
- */
- const GrRenderTarget* getRenderTarget() const;
- GrRenderTarget* getRenderTarget();
-
- ///////////////////////////////////////////////////////////////////////////
- // Platform Surfaces
-
- // GrContext provides an interface for wrapping externally created textures
- // and rendertargets in their Gr-equivalents.
-
- /**
- * Wraps an existing 3D API surface in a GrObject. desc.fFlags determines
- * the type of object returned. If kIsTexture is set the returned object
- * will be a GrTexture*. Otherwise, it will be a GrRenderTarget*. If both
- * are set the render target object is accessible by
- * GrTexture::asRenderTarget().
- *
- * GL: if the object is a texture Gr may change its GL texture parameters
- * when it is drawn.
- *
- * @param desc description of the object to create.
- * @return either a GrTexture* or GrRenderTarget* depending on desc. NULL
- * on failure.
- */
- GrResource* createPlatformSurface(const GrPlatformSurfaceDesc& desc);
- /**
- * Reads the current target object (e.g. FBO or IDirect3DSurface9*) and
- * viewport state from the underlying 3D API and wraps it in a
- * GrRenderTarget. The GrRenderTarget will not attempt to delete/destroy the
- * underlying object in its destructor and it is up to caller to guarantee
- * that it remains valid while the GrRenderTarget is used.
- *
- * Will not detect that the render target is also a texture. If you need
- * to also use the render target as a GrTexture use createPlatformSurface.
- *
- * @return the newly created GrRenderTarget
- */
- GrRenderTarget* createRenderTargetFrom3DApiState();
-
- ///////////////////////////////////////////////////////////////////////////
- // Matrix state
-
- /**
- * Gets the current transformation matrix.
- * @return the current matrix.
- */
- const GrMatrix& getMatrix() const;
-
- /**
- * Sets the transformation matrix.
- * @param m the matrix to set.
- */
- void setMatrix(const GrMatrix& m);
-
- /**
- * Concats the current matrix. The passed matrix is applied before the
- * current matrix.
- * @param m the matrix to concat.
- */
- void concatMatrix(const GrMatrix& m) const;
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Clip state
- /**
- * Gets the current clip.
- * @return the current clip.
- */
- const GrClip& getClip() const;
-
- /**
- * Sets the clip.
- * @param clip the clip to set.
- */
- void setClip(const GrClip& clip);
-
- /**
- * Convenience method for setting the clip to a rect.
- * @param rect the rect to set as the new clip.
- */
- void setClip(const GrIRect& rect);
-
- ///////////////////////////////////////////////////////////////////////////
- // Draws
-
- /**
- * Clear the entire or rect of the render target, ignoring any clips.
- * @param rect the rect to clear or the whole thing if rect is NULL.
- * @param color the color to clear to.
- */
- void clear(const GrIRect* rect, GrColor color);
-
- /**
- * Draw everywhere (respecting the clip) with the paint.
- */
- void drawPaint(const GrPaint& paint);
-
- /**
- * Draw the rect using a paint.
- * @param paint describes how to color pixels.
- * @param strokeWidth If strokeWidth < 0, then the rect is filled, else
- * the rect is mitered stroked based on strokeWidth. If
- * strokeWidth == 0, then the stroke is always a single
- * pixel thick.
- * @param matrix Optional matrix applied to the rect. Applied before
- * context's matrix or the paint's matrix.
- * The rects coords are used to access the paint (through texture matrix)
- */
- void drawRect(const GrPaint& paint,
- const GrRect&,
- GrScalar strokeWidth = -1,
- const GrMatrix* matrix = NULL);
-
- /**
- * Maps a rect of paint coordinates onto the a rect of destination
- * coordinates. Each rect can optionally be transformed. The srcRect
- * is stretched over the dstRect. The dstRect is transformed by the
- * context's matrix and the srcRect is transformed by the paint's matrix.
- * Additional optional matrices can be provided by parameters.
- *
- * @param paint describes how to color pixels.
- * @param dstRect the destination rect to draw.
- * @param srcRect rect of paint coordinates to be mapped onto dstRect
- * @param dstMatrix Optional matrix to transform dstRect. Applied before
- * context's matrix.
- * @param srcMatrix Optional matrix to transform srcRect Applied before
- * paint's matrix.
- */
- void drawRectToRect(const GrPaint& paint,
- const GrRect& dstRect,
- const GrRect& srcRect,
- const GrMatrix* dstMatrix = NULL,
- const GrMatrix* srcMatrix = NULL);
-
- /**
- * Draws a path.
- *
- * @param paint describes how to color pixels.
- * @param path the path to draw
- * @param fill the path filling rule to use.
- * @param translate optional additional translation applied to the
- * path.
- */
- void drawPath(const GrPaint& paint, const GrPath& path, GrPathFill fill,
- const GrPoint* translate = NULL);
-
- /**
- * Draws vertices with a paint.
- *
- * @param paint describes how to color pixels.
- * @param primitiveType primitives type to draw.
- * @param vertexCount number of vertices.
- * @param positions array of vertex positions, required.
- * @param texCoords optional array of texture coordinates used
- * to access the paint.
- * @param colors optional array of per-vertex colors, supercedes
- * the paint's color field.
- * @param indices optional array of indices. If NULL vertices
- * are drawn non-indexed.
- * @param indexCount if indices is non-null then this is the
- * number of indices.
- */
- void drawVertices(const GrPaint& paint,
- GrPrimitiveType primitiveType,
- int vertexCount,
- const GrPoint positions[],
- const GrPoint texs[],
- const GrColor colors[],
- const uint16_t indices[],
- int indexCount);
-
- /**
- * Similar to drawVertices but caller provides objects that convert to Gr
- * types. The count of vertices is given by posSrc.
- *
- * @param paint describes how to color pixels.
- * @param primitiveType primitives type to draw.
- * @param posSrc Source of vertex positions. Must implement
- * int count() const;
- * void writeValue(int i, GrPoint* point) const;
- * count returns the total number of vertices and
- * writeValue writes a vertex position to point.
- * @param texSrc optional, pass NULL to not use explicit tex
- * coords. If present provides tex coords with
- * method:
- * void writeValue(int i, GrPoint* point) const;
- * @param texSrc optional, pass NULL to not use per-vertex colors
- * If present provides colors with method:
- * void writeValue(int i, GrColor* point) const;
- * @param indices optional, pass NULL for non-indexed drawing. If
- * present supplies indices for indexed drawing
- * with following methods:
- * int count() const;
- * void writeValue(int i, uint16_t* point) const;
- * count returns the number of indices and
- * writeValue supplies each index.
- */
- template <typename POS_SRC,
- typename TEX_SRC,
- typename COL_SRC,
- typename IDX_SRC>
- void drawCustomVertices(const GrPaint& paint,
- GrPrimitiveType primitiveType,
- const POS_SRC& posSrc,
- const TEX_SRC* texCoordSrc,
- const COL_SRC* colorSrc,
- const IDX_SRC* idxSrc);
- /**
- * To avoid the problem of having to create a typename for NULL parameters,
- * these reduced versions of drawCustomVertices are provided.
- */
- template <typename POS_SRC>
- void drawCustomVertices(const GrPaint& paint,
- GrPrimitiveType primitiveType,
- const POS_SRC& posSrc);
- template <typename POS_SRC, typename TEX_SRC>
- void drawCustomVertices(const GrPaint& paint,
- GrPrimitiveType primitiveType,
- const POS_SRC& posSrc,
- const TEX_SRC* texCoordSrc);
- template <typename POS_SRC, typename TEX_SRC, typename COL_SRC>
- void drawCustomVertices(const GrPaint& paint,
- GrPrimitiveType primitiveType,
- const POS_SRC& posSrc,
- const TEX_SRC* texCoordSrc,
- const COL_SRC* colorSrc);
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Misc.
-
- /**
- * Flags that affect flush() behavior.
- */
- enum FlushBits {
- /**
- * A client may want Gr to bind a GrRenderTarget in the 3D API so that
- * it can be rendered to directly. However, Gr lazily sets state. Simply
- * calling setRenderTarget() followed by flush() without flags may not
- * bind the render target. This flag forces the context to bind the last
- * set render target in the 3D API.
- */
- kForceCurrentRenderTarget_FlushBit = 0x1,
- /**
- * A client may reach a point where it has partially rendered a frame
- * through a GrContext that it knows the user will never see. This flag
- * causes the flush to skip submission of deferred content to the 3D API
- * during the flush.
- */
- kDiscard_FlushBit = 0x2,
- };
-
- /**
- * Call to ensure all drawing to the context has been issued to the
- * underlying 3D API.
- * @param flagsBitfield flags that control the flushing behavior. See
- * FlushBits.
- */
- void flush(int flagsBitfield = 0);
-
- /**
- * Reads a rectangle of pixels from a render target.
- * @param renderTarget the render target to read from. NULL means the
- * current render target.
- * @param left left edge of the rectangle to read (inclusive)
- * @param top top edge of the rectangle to read (inclusive)
- * @param width width of rectangle to read in pixels.
- * @param height height of rectangle to read in pixels.
- * @param config the pixel config of the destination buffer
- * @param buffer memory to read the rectangle into.
- *
- * @return true if the read succeeded, false if not. The read can fail
- * because of a unsupported pixel config or because no render
- * target is currently set.
- */
- bool readRenderTargetPixels(GrRenderTarget* target,
- int left, int top, int width, int height,
- GrPixelConfig config, void* buffer);
-
- /**
- * Reads a rectangle of pixels from a texture.
- * @param texture the render target to read from.
- * @param left left edge of the rectangle to read (inclusive)
- * @param top top edge of the rectangle to read (inclusive)
- * @param width width of rectangle to read in pixels.
- * @param height height of rectangle to read in pixels.
- * @param config the pixel config of the destination buffer
- * @param buffer memory to read the rectangle into.
- *
- * @return true if the read succeeded, false if not. The read can fail
- * because of a unsupported pixel config.
- */
- bool readTexturePixels(GrTexture* target,
- int left, int top, int width, int height,
- GrPixelConfig config, void* buffer);
-
- /**
- * Copy the src pixels [buffer, stride, pixelconfig] into the current
- * render-target at the specified rectangle.
- */
- void writePixels(int left, int top, int width, int height,
- GrPixelConfig, const void* buffer, size_t stride);
-
- ///////////////////////////////////////////////////////////////////////////
- // Helpers
-
- class AutoRenderTarget : ::GrNoncopyable {
- public:
- AutoRenderTarget(GrContext* context, GrRenderTarget* target) {
- fContext = NULL;
- fPrevTarget = context->getRenderTarget();
- if (fPrevTarget != target) {
- context->setRenderTarget(target);
- fContext = context;
- }
- }
- ~AutoRenderTarget() {
- if (fContext) {
- fContext->setRenderTarget(fPrevTarget);
- }
- }
- private:
- GrContext* fContext;
- GrRenderTarget* fPrevTarget;
- };
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Functions intended for internal use only.
- GrGpu* getGpu() { return fGpu; }
- GrFontCache* getFontCache() { return fFontCache; }
- GrDrawTarget* getTextTarget(const GrPaint& paint);
- void flushText();
- const GrIndexBuffer* getQuadIndexBuffer() const;
- void resetStats();
- const GrGpuStats& getStats() const;
- void printStats() const;
-
-private:
- // used to keep track of when we need to flush the draw buffer
- enum DrawCategory {
- kBuffered_DrawCategory, // last draw was inserted in draw buffer
- kUnbuffered_DrawCategory, // last draw was not inserted in the draw buffer
- kText_DrawCategory // text context was last to draw
- };
- DrawCategory fLastDrawCategory;
-
- GrGpu* fGpu;
- GrTextureCache* fTextureCache;
- GrFontCache* fFontCache;
-
- GrPathRenderer* fCustomPathRenderer;
- GrDefaultPathRenderer fDefaultPathRenderer;
-
- GrVertexBufferAllocPool* fDrawBufferVBAllocPool;
- GrIndexBufferAllocPool* fDrawBufferIBAllocPool;
- GrInOrderDrawBuffer* fDrawBuffer;
-
- GrIndexBuffer* fAAFillRectIndexBuffer;
- GrIndexBuffer* fAAStrokeRectIndexBuffer;
-
- GrContext(GrGpu* gpu);
-
- void fillAARect(GrDrawTarget* target,
- const GrPaint& paint,
- const GrRect& devRect);
-
- void strokeAARect(GrDrawTarget* target,
- const GrPaint& paint,
- const GrRect& devRect,
- const GrVec& devStrokeSize);
-
- inline int aaFillRectIndexCount() const;
- GrIndexBuffer* aaFillRectIndexBuffer();
-
- inline int aaStrokeRectIndexCount() const;
- GrIndexBuffer* aaStrokeRectIndexBuffer();
-
- void setupDrawBuffer();
-
- void flushDrawBuffer();
-
- static void SetPaint(const GrPaint& paint, GrDrawTarget* target);
-
- bool finalizeTextureKey(GrTextureKey*,
- const GrSamplerState&,
- bool keyless) const;
-
- GrDrawTarget* prepareToDraw(const GrPaint& paint, DrawCategory drawType);
-
- void drawClipIntoStencil();
-
- GrPathRenderer* getPathRenderer(const GrDrawTarget*, const GrPath&, GrPathFill);
-
- struct OffscreenRecord;
-
- bool doOffscreenAA(GrDrawTarget* target,
- const GrPaint& paint,
- bool isLines) const;
-
- // sets up target to draw coverage to the supersampled render target
- bool setupOffscreenAAPass1(GrDrawTarget* target,
- bool requireStencil,
- const GrIRect& boundRect,
- OffscreenRecord* record);
-
- // sets up target to sample coverage of supersampled render target back
- // to the main render target using stage kOffscreenStage.
- void offscreenAAPass2(GrDrawTarget* target,
- const GrPaint& paint,
- const GrIRect& boundRect,
- OffscreenRecord* record);
-
- // computes vertex layout bits based on the paint. If paint expresses
- // a texture for a stage, the stage coords will be bound to postitions
- // unless hasTexCoords[s]==true in which case stage s's input coords
- // are bound to tex coord index s. hasTexCoords == NULL is a shortcut
- // for an array where all the values are false.
- static int PaintStageVertexLayoutBits(
- const GrPaint& paint,
- const bool hasTexCoords[GrPaint::kTotalStages]);
-
-};
-
-/**
- * Save/restore the view-matrix in the context.
- */
-class GrAutoMatrix : GrNoncopyable {
-public:
- GrAutoMatrix(GrContext* ctx) : fContext(ctx) {
- fMatrix = ctx->getMatrix();
- }
- GrAutoMatrix(GrContext* ctx, const GrMatrix& matrix) : fContext(ctx) {
- fMatrix = ctx->getMatrix();
- ctx->setMatrix(matrix);
- }
- ~GrAutoMatrix() {
- fContext->setMatrix(fMatrix);
- }
-
-private:
- GrContext* fContext;
- GrMatrix fMatrix;
-};
-
-#endif
-
-#include "GrContext_impl.h"
-
diff --git a/gpu/include/GrContext_impl.h b/gpu/include/GrContext_impl.h
deleted file mode 100644
index c79a191..0000000
--- a/gpu/include/GrContext_impl.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#ifndef GrContext_impl_DEFINED
-#define GrContext_impl_DEFINED
-
-struct GrContext::OffscreenRecord {
- OffscreenRecord() { fEntry0 = NULL; fEntry1 = NULL; }
- ~OffscreenRecord() { GrAssert(NULL == fEntry0 && NULL == fEntry1); }
-
- enum Downsample {
- k4x4TwoPass_Downsample,
- k4x4SinglePass_Downsample,
- kFSAA_Downsample
- } fDownsample;
- GrTextureEntry* fEntry0;
- GrTextureEntry* fEntry1;
- GrDrawTarget::SavedDrawState fSavedState;
-};
-
-template <typename POS_SRC, typename TEX_SRC,
- typename COL_SRC, typename IDX_SRC>
-inline void GrContext::drawCustomVertices(const GrPaint& paint,
- GrPrimitiveType primitiveType,
- const POS_SRC& posSrc,
- const TEX_SRC* texCoordSrc,
- const COL_SRC* colorSrc,
- const IDX_SRC* idxSrc) {
-
- GrDrawTarget::AutoReleaseGeometry geo;
-
- GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
-
- bool hasTexCoords[GrPaint::kTotalStages] = {
- NULL != texCoordSrc, // texCoordSrc provides explicit stage 0 coords
- 0 // remaining stages use positions
- };
- GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
-
- if (NULL != colorSrc) {
- layout |= GrDrawTarget::kColor_VertexLayoutBit;
- }
-
- int vertexCount = posSrc.count();
- int indexCount = (NULL != idxSrc) ? idxSrc->count() : 0;
-
- if (!geo.set(target, layout, vertexCount, indexCount)) {
- GrPrintf("Failed to get space for vertices!");
- return;
- }
-
- int texOffsets[GrDrawTarget::kMaxTexCoords];
- int colorOffset;
- int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
- texOffsets,
- &colorOffset);
- void* curVertex = geo.vertices();
-
- for (int i = 0; i < vertexCount; ++i) {
- posSrc.writeValue(i, (GrPoint*)curVertex);
-
- if (texOffsets[0] > 0) {
- texCoordSrc->writeValue(i, (GrPoint*)((intptr_t)curVertex + texOffsets[0]));
- }
- if (colorOffset > 0) {
- colorSrc->writeValue(i, (GrColor*)((intptr_t)curVertex + colorOffset));
- }
- curVertex = (void*)((intptr_t)curVertex + vsize);
- }
-
- uint16_t* indices = (uint16_t*) geo.indices();
- for (int i = 0; i < indexCount; ++i) {
- idxSrc->writeValue(i, indices + i);
- }
-
- bool doAA = false;
- OffscreenRecord record;
- GrIRect bounds;
-
- if (-1 == texOffsets[0] && -1 == colorOffset &&
- this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) {
- GrRect b;
- b.setBounds(geo.positions(), vertexCount);
- target->getViewMatrix().mapRect(&b);
- b.roundOut(&bounds);
- if (this->setupOffscreenAAPass1(target, false, bounds, &record)) {
- doAA = true;
- }
- }
-
- if (NULL == idxSrc) {
- target->drawNonIndexed(primitiveType, 0, vertexCount);
- } else {
- target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
- }
-
- if (doAA) {
- geo.set(NULL, 0, 0, 0); // have to release geom before can draw again
- this->offscreenAAPass2(target, paint, bounds, &record);
- }
-}
-
-class GrNullTexCoordSource {
-public:
- void writeValue(int i, GrPoint* dstCoord) const { GrAssert(false); }
-};
-
-class GrNullColorSource {
-public:
- void writeValue(int i, GrColor* dstColor) const { GrAssert(false); }
-};
-
-class GrNullIndexSource {
-public:
- void writeValue(int i, uint16_t* dstIndex) const { GrAssert(false); }
- int count() const { GrAssert(false); return 0; }
-};
-
-template <typename POS_SRC>
-inline void GrContext::drawCustomVertices(const GrPaint& paint,
- GrPrimitiveType primitiveType,
- const POS_SRC& posSrc) {
- this->drawCustomVertices<POS_SRC,
- GrNullTexCoordSource,
- GrNullColorSource,
- GrNullIndexSource>(paint, primitiveType, posSrc,
- NULL, NULL, NULL);
-}
-
-template <typename POS_SRC, typename TEX_SRC>
-inline void GrContext::drawCustomVertices(const GrPaint& paint,
- GrPrimitiveType primitiveType,
- const POS_SRC& posSrc,
- const TEX_SRC* texCoordSrc) {
- this->drawCustomVertices<POS_SRC, TEX_SRC,
- GrNullColorSource,
- GrNullIndexSource>(paint, primitiveType, posSrc,
- texCoordSrc, NULL, NULL);
-}
-
-template <typename POS_SRC, typename TEX_SRC, typename COL_SRC>
-inline void GrContext::drawCustomVertices(const GrPaint& paint,
- GrPrimitiveType primitiveType,
- const POS_SRC& posSrc,
- const TEX_SRC* texCoordSrc,
- const COL_SRC* colorSrc) {
- drawCustomVertices<POS_SRC, TEX_SRC, COL_SRC,
- GrNullIndexSource>(paint, primitiveType, posSrc,
- texCoordSrc, colorSrc, NULL);
-}
-
-#endif
diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h
deleted file mode 100644
index cd70d3e..0000000
--- a/gpu/include/GrDrawTarget.h
+++ /dev/null
@@ -1,1214 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrDrawTarget_DEFINED
-#define GrDrawTarget_DEFINED
-
-#include "GrMatrix.h"
-#include "GrColor.h"
-#include "GrRefCnt.h"
-#include "GrSamplerState.h"
-#include "GrClip.h"
-#include "GrTexture.h"
-#include "GrStencil.h"
-
-#include "SkXfermode.h"
-
-class GrTexture;
-class GrClipIterator;
-class GrVertexBuffer;
-class GrIndexBuffer;
-
-class GrDrawTarget : public GrRefCnt {
-public:
- /**
- * Number of texture stages. Each stage takes as input a color and
- * 2D texture coordinates. The color input to the first enabled stage is the
- * per-vertex color or the constant color (setColor/setAlpha) if there are
- * no per-vertex colors. For subsequent stages the input color is the output
- * color from the previous enabled stage. The output color of each stage is
- * the input color modulated with the result of a texture lookup. Texture
- * lookups are specified by a texture a sampler (setSamplerState). Texture
- * coordinates for each stage come from the vertices based on a
- * GrVertexLayout bitfield. The output fragment color is the output color of
- * the last enabled stage. The presence or absence of texture coordinates
- * for each stage in the vertex layout indicates whether a stage is enabled
- * or not.
- */
- enum {
- kNumStages = 3,
- kMaxTexCoords = kNumStages
- };
-
-
- /**
- * The absolute maximum number of edges that may be specified for
- * a single draw call when performing edge antialiasing. This is used for
- * the size of several static buffers, so implementations of getMaxEdges()
- * (below) should clamp to this value.
- */
- enum {
- kMaxEdges = 32
- };
-
- /**
- * Bitfield used to indicate which stages are in use.
- */
- typedef int StageBitfield;
- GR_STATIC_ASSERT(sizeof(StageBitfield)*8 >= kNumStages);
-
- /**
- * Flags that affect rendering. Controlled using enable/disableState(). All
- * default to disabled.
- */
- enum StateBits {
- kDither_StateBit = 0x01, //<! Perform color dithering
- kAntialias_StateBit = 0x02, //<! Perform anti-aliasing. The render-
- // target must support some form of AA
- // (msaa, coverage sampling, etc). For
- // GrGpu-created rendertarget/textures
- // this is controlled by parameters
- // passed to createTexture.
- kClip_StateBit = 0x04, //<! Controls whether drawing is clipped
- // against the region specified by
- // setClip.
- kNoColorWrites_StateBit = 0x08, //<! If set it disables writing colors.
- // Useful while performing stencil
- // ops.
-
- // subclass may use additional bits internally
- kDummyStateBit,
- kLastPublicStateBit = kDummyStateBit-1
- };
-
- enum DrawFace {
- kBoth_DrawFace,
- kCCW_DrawFace,
- kCW_DrawFace,
- };
-
- /**
- * The DrawTarget may reserve some of the high bits of the stencil. The draw
- * target will automatically trim reference and mask values so that the
- * client doesn't overwrite these bits.
- * The number of bits available is relative to the currently set render
- *target.
- * @return the number of bits usable by the draw target client.
- */
- int getUsableStencilBits() const {
- int bits = fCurrDrawState.fRenderTarget->stencilBits();
- if (bits) {
- return bits - 1;
- } else {
- return 0;
- }
- }
-
- /**
- * Sets the stencil settings to use for the next draw.
- * Changing the clip has the side-effect of possibly zeroing
- * out the client settable stencil bits. So multipass algorithms
- * using stencil should not change the clip between passes.
- * @param settings the stencil settings to use.
- */
- void setStencil(const GrStencilSettings& settings) {
- fCurrDrawState.fStencilSettings = settings;
- }
-
- /**
- * Shortcut to disable stencil testing and ops.
- */
- void disableStencil() {
- fCurrDrawState.fStencilSettings.setDisabled();
- }
-
- class Edge {
- public:
- Edge() {}
- Edge(float x, float y, float z) : fX(x), fY(y), fZ(z) {}
- GrPoint intersect(const Edge& other) {
- return GrPoint::Make(
- (fY * other.fZ - other.fY * fZ) /
- (fX * other.fY - other.fX * fY),
- (fX * other.fZ - other.fX * fZ) /
- (other.fX * fY - fX * other.fY));
- }
- float fX, fY, fZ;
- };
-
-protected:
-
- struct DrState {
- DrState() {
- // make sure any pad is zero for memcmp
- // all DrState members should default to something
- // valid by the memset
- memset(this, 0, sizeof(DrState));
-
- // memset exceptions
- fColorFilterXfermode = SkXfermode::kDstIn_Mode;
- fFirstCoverageStage = kNumStages;
-
- // pedantic assertion that our ptrs will
- // be NULL (0 ptr is mem addr 0)
- GrAssert((intptr_t)(void*)NULL == 0LL);
-
- // default stencil setting should be disabled
- GrAssert(fStencilSettings.isDisabled());
- fFirstCoverageStage = kNumStages;
- }
- uint32_t fFlagBits;
- GrBlendCoeff fSrcBlend;
- GrBlendCoeff fDstBlend;
- GrColor fBlendConstant;
- GrTexture* fTextures[kNumStages];
- GrSamplerState fSamplerStates[kNumStages];
- int fFirstCoverageStage;
- GrRenderTarget* fRenderTarget;
- GrColor fColor;
- DrawFace fDrawFace;
- GrColor fColorFilterColor;
- SkXfermode::Mode fColorFilterXfermode;
-
- GrStencilSettings fStencilSettings;
- GrMatrix fViewMatrix;
- Edge fEdgeAAEdges[kMaxEdges];
- int fEdgeAANumEdges;
- bool operator ==(const DrState& s) const {
- return 0 == memcmp(this, &s, sizeof(DrState));
- }
- bool operator !=(const DrState& s) const { return !(*this == s); }
- };
-
-public:
- ///////////////////////////////////////////////////////////////////////////
-
- GrDrawTarget();
-
- /**
- * Sets the current clip to the region specified by clip. All draws will be
- * clipped against this clip if kClip_StateBit is enabled.
- *
- * Setting the clip may (or may not) zero out the client's stencil bits.
- *
- * @param description of the clipping region
- */
- void setClip(const GrClip& clip);
-
- /**
- * Gets the current clip.
- *
- * @return the clip.
- */
- const GrClip& getClip() const;
-
- /**
- * Sets the texture used at the next drawing call
- *
- * @param stage The texture stage for which the texture will be set
- *
- * @param texture The texture to set. Can be NULL though there is no advantage
- * to settings a NULL texture if doing non-textured drawing
- */
- void setTexture(int stage, GrTexture* texture);
-
- /**
- * Retrieves the currently set texture.
- *
- * @return The currently set texture. The return value will be NULL if no
- * texture has been set, NULL was most recently passed to
- * setTexture, or the last setTexture was destroyed.
- */
- const GrTexture* getTexture(int stage) const;
- GrTexture* getTexture(int stage);
-
- /**
- * Sets the rendertarget used at the next drawing call
- *
- * @param target The render target to set.
- */
- void setRenderTarget(GrRenderTarget* target);
-
- /**
- * Retrieves the currently set rendertarget.
- *
- * @return The currently set render target.
- */
- const GrRenderTarget* getRenderTarget() const;
- GrRenderTarget* getRenderTarget();
-
- /**
- * Sets the sampler state for a stage used in subsequent draws.
- *
- * The sampler state determines how texture coordinates are
- * intepretted and used to sample the texture.
- *
- * @param stage the stage of the sampler to set
- * @param samplerState Specifies the sampler state.
- */
- void setSamplerState(int stage, const GrSamplerState& samplerState);
-
- /**
- * Concats the matrix of a stage's sampler.
- *
- * @param stage the stage of the sampler to set
- * @param matrix the matrix to concat
- */
- void preConcatSamplerMatrix(int stage, const GrMatrix& matrix) {
- GrAssert(stage >= 0 && stage < kNumStages);
- fCurrDrawState.fSamplerStates[stage].preConcatMatrix(matrix);
- }
-
- /**
- * Shortcut for preConcatSamplerMatrix on all stages in mask with same
- * matrix
- */
- void preConcatSamplerMatrices(int stageMask, const GrMatrix& matrix) {
- for (int i = 0; i < kNumStages; ++i) {
- if ((1 << i) & stageMask) {
- this->preConcatSamplerMatrix(i, matrix);
- }
- }
- }
-
- /**
- * Gets the matrix of a stage's sampler
- *
- * @param stage the stage to of sampler to get
- * @return the sampler state's matrix
- */
- const GrMatrix& getSamplerMatrix(int stage) const {
- return fCurrDrawState.fSamplerStates[stage].getMatrix();
- }
-
- /**
- * Sets the matrix of a stage's sampler
- *
- * @param stage the stage of sampler set
- * @param matrix the matrix to set
- */
- void setSamplerMatrix(int stage, const GrMatrix& matrix) {
- fCurrDrawState.fSamplerStates[stage].setMatrix(matrix);
- }
-
- /**
- * Sets the matrix applied to veretx positions.
- *
- * In the post-view-matrix space the rectangle [0,w]x[0,h]
- * fully covers the render target. (w and h are the width and height of the
- * the rendertarget.)
- *
- * @param m the matrix used to transform the vertex positions.
- */
- void setViewMatrix(const GrMatrix& m);
-
- /**
- * Multiplies the current view matrix by a matrix
- *
- * After this call V' = V*m where V is the old view matrix,
- * m is the parameter to this function, and V' is the new view matrix.
- * (We consider positions to be column vectors so position vector p is
- * transformed by matrix X as p' = X*p.)
- *
- * @param m the matrix used to modify the view matrix.
- */
- void preConcatViewMatrix(const GrMatrix& m);
-
- /**
- * Multiplies the current view matrix by a matrix
- *
- * After this call V' = m*V where V is the old view matrix,
- * m is the parameter to this function, and V' is the new view matrix.
- * (We consider positions to be column vectors so position vector p is
- * transformed by matrix X as p' = X*p.)
- *
- * @param m the matrix used to modify the view matrix.
- */
- void postConcatViewMatrix(const GrMatrix& m);
-
- /**
- * Retrieves the current view matrix
- * @return the current view matrix.
- */
- const GrMatrix& getViewMatrix() const;
-
- /**
- * Retrieves the inverse of the current view matrix.
- *
- * If the current view matrix is invertible, return true, and if matrix
- * is non-null, copy the inverse into it. If the current view matrix is
- * non-invertible, return false and ignore the matrix parameter.
- *
- * @param matrix if not null, will receive a copy of the current inverse.
- */
- bool getViewInverse(GrMatrix* matrix) const;
-
- /**
- * Sets color for next draw to a premultiplied-alpha color.
- *
- * @param the color to set.
- */
- void setColor(GrColor);
-
- /**
- * Add a color filter that can be represented by a color and a mode.
- */
- void setColorFilter(GrColor, SkXfermode::Mode);
-
- /**
- * Sets the color to be used for the next draw to be
- * (r,g,b,a) = (alpha, alpha, alpha, alpha).
- *
- * @param alpha The alpha value to set as the color.
- */
- void setAlpha(uint8_t alpha);
-
- /**
- * Controls whether clockwise, counterclockwise, or both faces are drawn.
- * @param face the face(s) to draw.
- */
- void setDrawFace(DrawFace face) { fCurrDrawState.fDrawFace = face; }
-
- /**
- * A common pattern is to compute a color with the initial stages and then
- * modulate that color by a coverage value in later stage(s) (AA, mask-
- * filters, glyph mask, etc). Color-filters, xfermodes, etc should be
- * computed based on the pre-coverage-modulated color. The division of
- * stages between color-computing and coverage-computing is specified by
- * this method. Initially this is kNumStages (all stages are color-
- * computing).
- */
- void setFirstCoverageStage(int firstCoverageStage) {
- fCurrDrawState.fFirstCoverageStage = firstCoverageStage;
- }
-
- /**
- * Gets the index of the first coverage-computing stage.
- */
- int getFirstCoverageStage() const {
- return fCurrDrawState.fFirstCoverageStage;
- }
-
- /**
- * Gets whether the target is drawing clockwise, counterclockwise,
- * or both faces.
- * @return the current draw face(s).
- */
- DrawFace getDrawFace() const { return fCurrDrawState.fDrawFace; }
-
- /**
- * Enable render state settings.
- *
- * @param flags bitfield of StateBits specifing the states to enable
- */
- void enableState(uint32_t stateBits);
-
- /**
- * Disable render state settings.
- *
- * @param flags bitfield of StateBits specifing the states to disable
- */
- void disableState(uint32_t stateBits);
-
- bool isDitherState() const {
- return 0 != (fCurrDrawState.fFlagBits & kDither_StateBit);
- }
-
- bool isAntialiasState() const {
- return 0 != (fCurrDrawState.fFlagBits & kAntialias_StateBit);
- }
-
- bool isClipState() const {
- return 0 != (fCurrDrawState.fFlagBits & kClip_StateBit);
- }
-
- bool isColorWriteDisabled() const {
- return 0 != (fCurrDrawState.fFlagBits & kNoColorWrites_StateBit);
- }
-
- /**
- * Sets the blending function coeffecients.
- *
- * The blend function will be:
- * D' = sat(S*srcCoef + D*dstCoef)
- *
- * where D is the existing destination color, S is the incoming source
- * color, and D' is the new destination color that will be written. sat()
- * is the saturation function.
- *
- * @param srcCoef coeffecient applied to the src color.
- * @param dstCoef coeffecient applied to the dst color.
- */
- void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff);
-
- /**
- * Sets the blending function constant referenced by the following blending
- * coeffecients:
- * kConstC_BlendCoeff
- * kIConstC_BlendCoeff
- * kConstA_BlendCoeff
- * kIConstA_BlendCoeff
- *
- * @param constant the constant to set
- */
- void setBlendConstant(GrColor constant) { fCurrDrawState.fBlendConstant = constant; }
-
- /**
- * Retrieves the last value set by setBlendConstant()
- * @return the blending constant value
- */
- GrColor getBlendConstant() const { return fCurrDrawState.fBlendConstant; }
-
- /**
- * Used to save and restore the GrGpu's drawing state
- */
- struct SavedDrawState {
- private:
- DrState fState;
- friend class GrDrawTarget;
- };
-
- /**
- * Saves the current draw state. The state can be restored at a later time
- * with restoreDrawState.
- *
- * See also AutoStateRestore class.
- *
- * @param state will hold the state after the function returns.
- */
- void saveCurrentDrawState(SavedDrawState* state) const;
-
- /**
- * Restores previously saved draw state. The client guarantees that state
- * was previously passed to saveCurrentDrawState and that the rendertarget
- * and texture set at save are still valid.
- *
- * See also AutoStateRestore class.
- *
- * @param state the previously saved state to restore.
- */
- void restoreDrawState(const SavedDrawState& state);
-
- /**
- * Copies the draw state from another target to this target.
- *
- * @param srcTarget draw target used as src of the draw state.
- */
- void copyDrawState(const GrDrawTarget& srcTarget);
-
- /**
- * The format of vertices is represented as a bitfield of flags.
- * Flags that indicate the layout of vertex data. Vertices always contain
- * positions and may also contain up to kMaxTexCoords sets of 2D texture
- * coordinates and per-vertex colors. Each stage can use any of the texture
- * coordinates as its input texture coordinates or it may use the positions.
- *
- * If no texture coordinates are specified for a stage then the stage is
- * disabled.
- *
- * Only one type of texture coord can be specified per stage. For
- * example StageTexCoordVertexLayoutBit(0, 2) and
- * StagePosAsTexCoordVertexLayoutBit(0) cannot both be specified.
- *
- * The order in memory is always (position, texture coord 0, ..., color)
- * with any unused fields omitted. Note that this means that if only texture
- * coordinates 1 is referenced then there is no texture coordinates 0 and
- * the order would be (position, texture coordinate 1[, color]).
- */
-
- /**
- * Generates a bit indicating that a texture stage uses texture coordinates
- *
- * @param stage the stage that will use texture coordinates.
- * @param texCoordIdx the index of the texture coordinates to use
- *
- * @return the bit to add to a GrVertexLayout bitfield.
- */
- static int StageTexCoordVertexLayoutBit(int stage, int texCoordIdx) {
- GrAssert(stage < kNumStages);
- GrAssert(texCoordIdx < kMaxTexCoords);
- return 1 << (stage + (texCoordIdx * kNumStages));
- }
-
- /**
- * Determines if blend is effectively disabled.
- *
- * @return true if blend can be disabled without changing the rendering
- * result given the current state including the vertex layout specified
- * with the vertex source.
- */
- bool canDisableBlend() const;
-
- /**
- * Sets the edge data required for edge antialiasing.
- *
- * @param edges 3 * 6 float values, representing the edge
- * equations in Ax + By + C form
- */
- void setEdgeAAData(const Edge* edges, int numEdges);
-
-private:
- static const int TEX_COORD_BIT_CNT = kNumStages*kMaxTexCoords;
-public:
- /**
- * Generates a bit indicating that a texture stage uses the position
- * as its texture coordinate.
- *
- * @param stage the stage that will use position as texture
- * coordinates.
- *
- * @return the bit to add to a GrVertexLayout bitfield.
- */
- static int StagePosAsTexCoordVertexLayoutBit(int stage) {
- GrAssert(stage < kNumStages);
- return (1 << (TEX_COORD_BIT_CNT + stage));
- }
-private:
- static const int STAGE_BIT_CNT = TEX_COORD_BIT_CNT + kNumStages;
-
-public:
-
- /**
- * Additional Bits that can be specified in GrVertexLayout.
- */
- enum VertexLayoutBits {
-
- kColor_VertexLayoutBit = 1 << (STAGE_BIT_CNT + 0),
- //<! vertices have colors
- kTextFormat_VertexLayoutBit = 1 << (STAGE_BIT_CNT + 1),
- //<! use text vertices. (Pos
- // and tex coords may be
- // a different type for
- // text [GrGpuTextVertex vs
- // GrPoint].)
- // for below assert
- kDummyVertexLayoutBit,
- kHighVertexLayoutBit = kDummyVertexLayoutBit - 1
- };
- // make sure we haven't exceeded the number of bits in GrVertexLayout.
- GR_STATIC_ASSERT(kHighVertexLayoutBit < ((uint64_t)1 << 8*sizeof(GrVertexLayout)));
-
- /**
- * There are three paths for specifying geometry (vertices and optionally
- * indices) to the draw target. When indexed drawing the indices and vertices
- * can be each use a different path.
- *
- * 1. Provide a cpu array (set*SourceToArray). This is useful when the
- * caller's client has already provided vertex data in a format
- * the time compatible with a GrVertexLayout. The array must contain the
- * data at set*SourceToArray is called. The source stays in effect for
- * drawIndexed & drawNonIndexed calls until set*SourceToArray is called
- * again or one of the other two paths is chosen.
- *
- * 2. Reserve and Lock. This is most useful when the caller has data it must
- * transform before drawing and will not likely render it again. The
- * caller requests that the draw target make room for some amount of
- * vertex and/or index data. The target provides ptrs to hold the data
- * data. The caller can write the data into the pts up until the first
- * drawIndexed or drawNonIndexed call. At this point the data is frozen
- * and the ptrs are no longer guaranteed to be valid. All subsequent
- * drawIndexed & drawNonIndexed calls will use this data until
- * releaseReserved geometry is called. This must be called before another
- * source is set.
- *
- * 3. Vertex and Index Buffers. This is most useful for geometry that will
- * be rendered multiple times. SetVertexSourceToBuffer &
- * SetIndexSourceToBuffer are used to set the buffer and subsequent
- * drawIndexed and drawNonIndexed calls use this source until another
- * source is set.
- */
-
- /**
- * Reserves space for vertices and/or indices. Draw target will use
- * reserved vertices / indices at next draw.
- *
- * If succeeds:
- * if vertexCount is nonzero, *vertices will be the array
- * of vertices to be filled by caller. The next draw will read
- * these vertices.
- *
- * if indexCount is nonzero, *indices will be the array of indices
- * to be filled by caller. The next indexed draw will read from
- * these indices.
- *
- * If a client does not already have a vertex buffer then this is the
- * preferred way to allocate vertex/index array. It allows the subclass of
- * GrDrawTarget to decide whether to put data in buffers, to group vertex
- * data that uses the same state (e.g. for deferred rendering), etc.
- *
- * Following the first draw after reserveAndLockGeometry the ptrs returned
- * by releaseReservedGeometry are no longer valid and the geometry data
- * cannot be further modified. The contents that were put in the reserved
- * space can be drawn by multiple draws, however.
- *
- * reserveAndLockGeometry must be matched with a releaseReservedGeometry
- * call after all draws that reference the reserved geometry data have
- * been called.
- *
- * AutoGeometryRelease can be used to automatically call the release.
- *
- * @param vertexCount the number of vertices to reserve space for. Can be 0.
- * @param indexCount the number of indices to reserve space for. Can be 0.
- * @param vertexLayout the format of vertices (ignored if vertexCount == 0).
- * @param vertices will point to reserved vertex space if vertexCount is
- * non-zero. Illegal to pass NULL if vertexCount > 0.
- * @param indices will point to reserved index space if indexCount is
- * non-zero. Illegal to pass NULL if indexCount > 0.
- *
- * @return true if succeeded in allocating space for the vertices and false
- * if not.
- */
- bool reserveAndLockGeometry(GrVertexLayout vertexLayout,
- uint32_t vertexCount,
- uint32_t indexCount,
- void** vertices,
- void** indices);
- /**
- * Provides hints to caller about the number of vertices and indices
- * that can be allocated cheaply. This can be useful if caller is reserving
- * space but doesn't know exactly how much geometry is needed.
- *
- * Also may hint whether the draw target should be flushed first. This is
- * useful for deferred targets.
- *
- * @param vertexLayout layout of vertices caller would like to reserve
- * @param vertexCount in: hint about how many vertices the caller would
- * like to allocate.
- * out: a hint about the number of vertices that can be
- * allocated cheaply. Negative means no hint.
- * Ignored if NULL.
- * @param indexCount in: hint about how many indices the caller would
- * like to allocate.
- * out: a hint about the number of indices that can be
- * allocated cheaply. Negative means no hint.
- * Ignored if NULL.
- *
- * @return true if target should be flushed based on the input values.
- */
- virtual bool geometryHints(GrVertexLayout vertexLayout,
- int* vertexCount,
- int* indexCount) const;
-
- /**
- * Releases reserved vertex/index data from reserveAndLockGeometry().
- */
- void releaseReservedGeometry();
-
- /**
- * Sets source of vertex data for the next draw. Array must contain
- * the vertex data when this is called.
- *
- * @param array cpu array containing vertex data.
- * @param size size of the vertex data.
- * @param vertexCount the number of vertices in the array.
- */
- void setVertexSourceToArray(GrVertexLayout vertexLayout,
- const void* vertexArray,
- int vertexCount);
-
- /**
- * Sets source of index data for the next indexed draw. Array must contain
- * the indices when this is called.
- *
- * @param array cpu array containing index data.
- * @param indexCount the number of indices in the array.
- */
- void setIndexSourceToArray(const void* indexArray, int indexCount);
-
- /**
- * Sets source of vertex data for the next draw. Data does not have to be
- * in the buffer until drawIndexed or drawNonIndexed.
- *
- * @param buffer vertex buffer containing vertex data. Must be
- * unlocked before draw call.
- * @param vertexLayout layout of the vertex data in the buffer.
- */
- void setVertexSourceToBuffer(GrVertexLayout vertexLayout,
- const GrVertexBuffer* buffer);
-
- /**
- * Sets source of index data for the next indexed draw. Data does not have
- * to be in the buffer until drawIndexed or drawNonIndexed.
- *
- * @param buffer index buffer containing indices. Must be unlocked
- * before indexed draw call.
- */
- void setIndexSourceToBuffer(const GrIndexBuffer* buffer);
-
- /**
- * Draws indexed geometry using the current state and current vertex / index
- * sources.
- *
- * @param type The type of primitives to draw.
- * @param startVertex the vertex in the vertex array/buffer corresponding
- * to index 0
- * @param startIndex first index to read from index src.
- * @param vertexCount one greater than the max index.
- * @param indexCount the number of index elements to read. The index count
- * is effectively trimmed to the last completely
- * specified primitive.
- */
- virtual void drawIndexed(GrPrimitiveType type,
- int startVertex,
- int startIndex,
- int vertexCount,
- int indexCount) = 0;
-
- /**
- * Draws non-indexed geometry using the current state and current vertex
- * sources.
- *
- * @param type The type of primitives to draw.
- * @param startVertex the vertex in the vertex array/buffer corresponding
- * to index 0
- * @param vertexCount one greater than the max index.
- */
- virtual void drawNonIndexed(GrPrimitiveType type,
- int startVertex,
- int vertexCount) = 0;
-
- /**
- * Helper function for drawing rects. This does not use the current index
- * and vertex sources. After returning, the vertex and index sources may
- * have changed. They should be reestablished before the next drawIndexed
- * or drawNonIndexed. This cannot be called between reserving and releasing
- * geometry. The GrDrawTarget subclass may be able to perform additional
- * optimizations if drawRect is used rather than drawIndexed or
- * drawNonIndexed.
- * @param rect the rect to draw
- * @param matrix optional matrix applied to rect (before viewMatrix)
- * @param stageEnableBitfield bitmask indicating which stages are enabled.
- * Bit i indicates whether stage i is enabled.
- * @param srcRects specifies rects for stages enabled by stageEnableMask.
- * if stageEnableMask bit i is 1, srcRects is not NULL,
- * and srcRects[i] is not NULL, then srcRects[i] will be
- * used as coordinates for stage i. Otherwise, if stage i
- * is enabled then rect is used as the coordinates.
- * @param srcMatrices optional matrices applied to srcRects. If
- * srcRect[i] is non-NULL and srcMatrices[i] is
- * non-NULL then srcRect[i] will be transformed by
- * srcMatrix[i]. srcMatrices can be NULL when no
- * srcMatrices are desired.
- */
- virtual void drawRect(const GrRect& rect,
- const GrMatrix* matrix,
- StageBitfield stageEnableBitfield,
- const GrRect* srcRects[],
- const GrMatrix* srcMatrices[]);
-
- /**
- * Helper for drawRect when the caller doesn't need separate src rects or
- * matrices.
- */
- void drawSimpleRect(const GrRect& rect,
- const GrMatrix* matrix,
- StageBitfield stageEnableBitfield) {
- drawRect(rect, matrix, stageEnableBitfield, NULL, NULL);
- }
-
- /**
- * Clear the render target. Ignores the clip and all other draw state
- * (blend mode, stages, etc). Clears the whole thing if rect is NULL,
- * otherwise just the rect.
- */
- virtual void clear(const GrIRect* rect, GrColor color) = 0;
-
- /**
- * Returns the maximum number of edges that may be specified in a single
- * draw call when performing edge antialiasing. This is usually limited
- * by the number of fragment uniforms which may be uploaded. Must be a
- * minimum of six, since a triangle's vertices each belong to two boundary
- * edges which may be distinct.
- */
- virtual int getMaxEdges() const { return 6; }
-
- ///////////////////////////////////////////////////////////////////////////
-
- class AutoStateRestore : ::GrNoncopyable {
- public:
- AutoStateRestore();
- AutoStateRestore(GrDrawTarget* target);
- ~AutoStateRestore();
-
- /**
- * if this object is already saving state for param target then
- * this does nothing. Otherise, it restores previously saved state on
- * previous target (if any) and saves current state on param target.
- */
- void set(GrDrawTarget* target);
-
- private:
- GrDrawTarget* fDrawTarget;
- SavedDrawState fDrawState;
- };
-
- ///////////////////////////////////////////////////////////////////////////
-
- class AutoViewMatrixRestore : ::GrNoncopyable {
- public:
- AutoViewMatrixRestore() {
- fDrawTarget = NULL;
- }
-
- AutoViewMatrixRestore(GrDrawTarget* target)
- : fDrawTarget(target), fMatrix(fDrawTarget->getViewMatrix()) {
- GrAssert(NULL != target);
- }
-
- void set(GrDrawTarget* target) {
- GrAssert(NULL != target);
- if (NULL != fDrawTarget) {
- fDrawTarget->setViewMatrix(fMatrix);
- }
- fDrawTarget = target;
- fMatrix = target->getViewMatrix();
- }
-
- ~AutoViewMatrixRestore() {
- if (NULL != fDrawTarget) {
- fDrawTarget->setViewMatrix(fMatrix);
- }
- }
-
- private:
- GrDrawTarget* fDrawTarget;
- GrMatrix fMatrix;
- };
-
- ///////////////////////////////////////////////////////////////////////////
-
- class AutoReleaseGeometry : ::GrNoncopyable {
- public:
- AutoReleaseGeometry(GrDrawTarget* target,
- GrVertexLayout vertexLayout,
- uint32_t vertexCount,
- uint32_t indexCount) {
- fTarget = NULL;
- this->set(target, vertexLayout, vertexCount, indexCount);
- }
-
- AutoReleaseGeometry() {
- fTarget = NULL;
- }
-
- ~AutoReleaseGeometry() {
- if (NULL != fTarget) {
- fTarget->releaseReservedGeometry();
- }
- }
-
- bool set(GrDrawTarget* target,
- GrVertexLayout vertexLayout,
- uint32_t vertexCount,
- uint32_t indexCount) {
- if (NULL != fTarget) {
- fTarget->releaseReservedGeometry();
- }
- fTarget = target;
- if (NULL != fTarget) {
- if (!fTarget->reserveAndLockGeometry(vertexLayout,
- vertexCount,
- indexCount,
- &fVertices,
- &fIndices)) {
- fTarget = NULL;
- }
- }
- return NULL != fTarget;
- }
-
- bool succeeded() const { return NULL != fTarget; }
- void* vertices() const { return fVertices; }
- void* indices() const { return fIndices; }
-
- GrPoint* positions() const {
- return static_cast<GrPoint*>(fVertices);
- }
-
- private:
- GrDrawTarget* fTarget;
- void* fVertices;
- void* fIndices;
- };
-
- ///////////////////////////////////////////////////////////////////////////
-
- class AutoClipRestore : ::GrNoncopyable {
- public:
- AutoClipRestore(GrDrawTarget* target) {
- fTarget = target;
- fClip = fTarget->getClip();
- }
-
- ~AutoClipRestore() {
- fTarget->setClip(fClip);
- }
- private:
- GrDrawTarget* fTarget;
- GrClip fClip;
- };
-
- ////////////////////////////////////////////////////////////////////////////
- // Helpers for picking apart vertex layouts
-
- /**
- * Helper function to compute the size of a vertex from a vertex layout
- * @return size of a single vertex.
- */
- static size_t VertexSize(GrVertexLayout vertexLayout);
-
- /**
- * Helper function for determining the index of texture coordinates that
- * is input for a texture stage. Note that a stage may instead use positions
- * as texture coordinates, in which case the result of the function is
- * indistinguishable from the case when the stage is disabled.
- *
- * @param stage the stage to query
- * @param vertexLayout layout to query
- *
- * @return the texture coordinate index or -1 if the stage doesn't use
- * separate (non-position) texture coordinates.
- */
- static int VertexTexCoordsForStage(int stage, GrVertexLayout vertexLayout);
-
- /**
- * Helper function to compute the offset of texture coordinates in a vertex
- * @return offset of texture coordinates in vertex layout or -1 if the
- * layout has no texture coordinates. Will be 0 if positions are
- * used as texture coordinates for the stage.
- */
- static int VertexStageCoordOffset(int stage, GrVertexLayout vertexLayout);
-
- /**
- * Helper function to compute the offset of the color in a vertex
- * @return offset of color in vertex layout or -1 if the
- * layout has no color.
- */
- static int VertexColorOffset(GrVertexLayout vertexLayout);
-
- /**
- * Helper function to determine if vertex layout contains explicit texture
- * coordinates of some index.
- *
- * @param coordIndex the tex coord index to query
- * @param vertexLayout layout to query
- *
- * @return true if vertex specifies texture coordinates for the index,
- * false otherwise.
- */
- static bool VertexUsesTexCoordIdx(int coordIndex,
- GrVertexLayout vertexLayout);
-
- /**
- * Helper function to determine if vertex layout contains either explicit or
- * implicit texture coordinates for a stage.
- *
- * @param stage the stage to query
- * @param vertexLayout layout to query
- *
- * @return true if vertex specifies texture coordinates for the stage,
- * false otherwise.
- */
- static bool VertexUsesStage(int stage, GrVertexLayout vertexLayout);
-
- /**
- * Helper function to compute the size of each vertex and the offsets of
- * texture coordinates and color. Determines tex coord offsets by tex coord
- * index rather than by stage. (Each stage can be mapped to any t.c. index
- * by StageTexCoordVertexLayoutBit.)
- *
- * @param vertexLayout the layout to query
- * @param texCoordOffsetsByIdx after return it is the offset of each
- * tex coord index in the vertex or -1 if
- * index isn't used.
- * @return size of a single vertex
- */
- static int VertexSizeAndOffsetsByIdx(GrVertexLayout vertexLayout,
- int texCoordOffsetsByIdx[kMaxTexCoords],
- int *colorOffset);
-
- /**
- * Helper function to compute the size of each vertex and the offsets of
- * texture coordinates and color. Determines tex coord offsets by stage
- * rather than by index. (Each stage can be mapped to any t.c. index
- * by StageTexCoordVertexLayoutBit.) If a stage uses positions for
- * tex coords then that stage's offset will be 0 (positions are always at 0).
- *
- * @param vertexLayout the layout to query
- * @param texCoordOffsetsByStage after return it is the offset of each
- * tex coord index in the vertex or -1 if
- * index isn't used.
- * @return size of a single vertex
- */
- static int VertexSizeAndOffsetsByStage(GrVertexLayout vertexLayout,
- int texCoordOffsetsByStage[kNumStages],
- int *colorOffset);
-
- /**
- * Accessing positions, texture coords, or colors, of a vertex within an
- * array is a hassle involving casts and simple math. These helpers exist
- * to keep GrDrawTarget clients' code a bit nicer looking.
- */
-
- /**
- * Gets a pointer to a GrPoint of a vertex's position or texture
- * coordinate.
- * @param vertices the vetex array
- * @param vertexIndex the index of the vertex in the array
- * @param vertexSize the size of each vertex in the array
- * @param offset the offset in bytes of the vertex component.
- * Defaults to zero (corresponding to vertex position)
- * @return pointer to the vertex component as a GrPoint
- */
- static GrPoint* GetVertexPoint(void* vertices,
- int vertexIndex,
- int vertexSize,
- int offset = 0) {
- intptr_t start = GrTCast<intptr_t>(vertices);
- return GrTCast<GrPoint*>(start + offset +
- vertexIndex * vertexSize);
- }
- static const GrPoint* GetVertexPoint(const void* vertices,
- int vertexIndex,
- int vertexSize,
- int offset = 0) {
- intptr_t start = GrTCast<intptr_t>(vertices);
- return GrTCast<const GrPoint*>(start + offset +
- vertexIndex * vertexSize);
- }
-
- /**
- * Gets a pointer to a GrColor inside a vertex within a vertex array.
- * @param vertices the vetex array
- * @param vertexIndex the index of the vertex in the array
- * @param vertexSize the size of each vertex in the array
- * @param offset the offset in bytes of the vertex color
- * @return pointer to the vertex component as a GrColor
- */
- static GrColor* GetVertexColor(void* vertices,
- int vertexIndex,
- int vertexSize,
- int offset) {
- intptr_t start = GrTCast<intptr_t>(vertices);
- return GrTCast<GrColor*>(start + offset +
- vertexIndex * vertexSize);
- }
- static const GrColor* GetVertexColor(const void* vertices,
- int vertexIndex,
- int vertexSize,
- int offset) {
- const intptr_t start = GrTCast<intptr_t>(vertices);
- return GrTCast<const GrColor*>(start + offset +
- vertexIndex * vertexSize);
- }
-
- static void VertexLayoutUnitTest();
-
-protected:
- // given a vertex layout and a draw state, will a stage be used?
- static bool StageWillBeUsed(int stage, GrVertexLayout layout,
- const DrState& state) {
- return NULL != state.fTextures[stage] && VertexUsesStage(stage, layout);
- }
-
- bool isStageEnabled(int stage) const {
- return StageWillBeUsed(stage, fGeometrySrc.fVertexLayout, fCurrDrawState);
- }
-
- // Helpers for GrDrawTarget subclasses that won't have private access to
- // SavedDrawState but need to peek at the state values.
- static DrState& accessSavedDrawState(SavedDrawState& sds)
- { return sds.fState; }
- static const DrState& accessSavedDrawState(const SavedDrawState& sds)
- { return sds.fState; }
-
- // implemented by subclass
- virtual bool onAcquireGeometry(GrVertexLayout vertexLayout,
- void** vertices,
- void** indices) = 0;
-
- virtual void onReleaseGeometry() = 0;
-
- // subclass overrides to be notified when clip is set.
- virtual void clipWillBeSet(const GrClip& clip) = 0;
-
- virtual void onSetVertexSourceToArray(const void* vertexArray,
- int vertexCount) = 0;
-
- virtual void onSetIndexSourceToArray(const void* indexArray,
- int indexCount) = 0;
-
- // Helpers for drawRect, protected so subclasses that override drawRect
- // can use them.
- static GrVertexLayout GetRectVertexLayout(StageBitfield stageEnableBitfield,
- const GrRect* srcRects[]);
-
- static void SetRectVertices(const GrRect& rect,
- const GrMatrix* matrix,
- const GrRect* srcRects[],
- const GrMatrix* srcMatrices[],
- GrVertexLayout layout,
- void* vertices);
-
- enum GeometrySrcType {
- kReserved_GeometrySrcType, // src was set using reserveAndLockGeometry
- kArray_GeometrySrcType, // src was set using set*SourceToArray
- kBuffer_GeometrySrcType // src was set using set*SourceToBuffer
- };
-
- struct ReservedGeometry {
- bool fLocked;
- uint32_t fVertexCount;
- uint32_t fIndexCount;
- } fReservedGeometry;
-
- struct GeometrySrc {
- GeometrySrcType fVertexSrc;
- const GrVertexBuffer* fVertexBuffer; // valid if src type is buffer
- GeometrySrcType fIndexSrc;
- const GrIndexBuffer* fIndexBuffer; // valid if src type is buffer
- GrVertexLayout fVertexLayout;
- } fGeometrySrc;
-
- GrClip fClip;
-
- DrState fCurrDrawState;
-
- // Not meant for external use. Only setVertexSourceToBuffer and
- // setIndexSourceToBuffer will work since GrDrawTarget subclasses don't
- // support nested reserveAndLockGeometry (and cpu arrays internally use the
- // same path).
- class AutoGeometrySrcRestore {
- public:
- AutoGeometrySrcRestore(GrDrawTarget* target) {
- fTarget = target;
- fGeometrySrc = fTarget->fGeometrySrc;
- }
- ~AutoGeometrySrcRestore() {
- fTarget->fGeometrySrc = fGeometrySrc;
- }
- private:
- GrDrawTarget *fTarget;
- GeometrySrc fGeometrySrc;
-
- AutoGeometrySrcRestore();
- AutoGeometrySrcRestore(const AutoGeometrySrcRestore&);
- AutoGeometrySrcRestore& operator =(AutoGeometrySrcRestore&);
- };
-};
-
-#endif
diff --git a/gpu/include/GrGLConfig.h b/gpu/include/GrGLConfig.h
deleted file mode 100644
index b4ca78c..0000000
--- a/gpu/include/GrGLConfig.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrGLConfig_DEFINED
-#define GrGLConfig_DEFINED
-
-#include "GrTypes.h"
-#include "GrGLDefines.h"
-
-/**
- * Optional GL config file.
- */
-#ifdef GR_GL_CUSTOM_SETUP_HEADER
- #include GR_GL_CUSTOM_SETUP_HEADER
-#endif
-
-#if !defined(GR_GL_FUNCTION_TYPE)
- #define GR_GL_FUNCTION_TYPE
-#endif
-
-/**
- * The following are optional defines that can be enabled at the compiler
- * command line, in a IDE project, in a GrUserConfig.h file, or in a GL custom
- * file (if one is in use). If a GR_GL_CUSTOM_SETUP_HEADER is used they can
- * also be placed there.
- *
- * GR_GL_LOG_CALLS: if 1 Gr can print every GL call using GrPrintf. Defaults to
- * 0. Logging can be enabled and disabled at runtime using a debugger via to
- * global gLogCallsGL. The initial value of gLogCallsGL is controlled by
- * GR_GL_LOG_CALLS_START.
- *
- * GR_GL_LOG_CALLS_START: controls the initial value of gLogCallsGL when
- * GR_GL_LOG_CALLS is 1. Defaults to 0.
- *
- * GR_GL_CHECK_ERROR: if enabled Gr can do a glGetError() after every GL call.
- * Defaults to 1 if GR_DEBUG is set, otherwise 0. When GR_GL_CHECK_ERROR is 1
- * this can be toggled in a debugger using the gCheckErrorGL global. The initial
- * value of gCheckErrorGL is controlled by by GR_GL_CHECK_ERROR_START.
- *
- * GR_GL_CHECK_ERROR_START: controls the initial value of gCheckErrorGL
- * when GR_GL_CHECK_ERROR is 1. Defaults to 1.
- *
- * GR_GL_NO_CONSTANT_ATTRIBUTES: if this evaluates to true then the GL backend
- * will use uniforms instead of attributes in all cases when there is not
- * per-vertex data. This is important when the underlying GL implementation
- * doesn't actually support immediate style attribute values (e.g. when
- * the GL stream is converted to DX as in ANGLE on Chrome). Defaults to 0.
- *
- * GR_GL_ATTRIBUTE_MATRICES: If changing uniforms is very expensive it may be
- * faster to use vertex attributes for matrices (set via glVertexAttrib3fv).
- * Setting this build flag enables this behavior. GR_GL_NO_CONSTANT_ATTRIBUTES
- * must not be set since this uses constant attributes for the matrices.
- * Defaults to 0.
- */
-
-#if !defined(GR_GL_LOG_CALLS)
- #define GR_GL_LOG_CALLS 0
-#endif
-
-#if !defined(GR_GL_LOG_CALLS_START)
- #define GR_GL_LOG_CALLS_START 0
-#endif
-
-#if !defined(GR_GL_CHECK_ERROR)
- #define GR_GL_CHECK_ERROR GR_DEBUG
-#endif
-
-#if !defined(GR_GL_CHECK_ERROR_START)
- #define GR_GL_CHECK_ERROR_START 1
-#endif
-
-#if !defined(GR_GL_NO_CONSTANT_ATTRIBUTES)
- #define GR_GL_NO_CONSTANT_ATTRIBUTES 0
-#endif
-
-#if !defined(GR_GL_ATTRIBUTE_MATRICES)
- #define GR_GL_ATTRIBUTE_MATRICES 0
-#endif
-
-#if(GR_GL_NO_CONSTANT_ATTRIBUTES) && (GR_GL_ATTRIBUTE_MATRICES)
- #error "Cannot combine GR_GL_NO_CONSTANT_ATTRIBUTES and GR_GL_ATTRIBUTE_MATRICES"
-#endif
-
-////////////////////////////////////////////////////////////////////////////////
-
-/**
- * The following macros are used to staticlly configure the default
- * GrGLInterface, but should not be used outside of the GrGLInterface
- * scaffolding. Undefine here to prevent accidental use.
- */
-#undef GR_SUPPORT_GLDESKTOP
-#undef GR_SUPPORT_GLES1
-#undef GR_SUPPORT_GLES2
-#undef GR_SUPPORT_GLES
-
-////////////////////////////////////////////////////////////////////////////////
-
-#if GR_SCALAR_IS_FIXED
- #define GrGLType GL_FIXED
-#elif GR_SCALAR_IS_FLOAT
- #define GrGLType GR_GL_FLOAT
-#else
- #error "unknown GR_SCALAR type"
-#endif
-
-#if GR_TEXT_SCALAR_IS_USHORT
- #define GrGLTextType GR_GL_UNSIGNED_SHORT
- #define GR_GL_TEXT_TEXTURE_NORMALIZED 1
-#elif GR_TEXT_SCALAR_IS_FLOAT
- #define GrGLTextType GR_GL_FLOAT
- #define GR_GL_TEXT_TEXTURE_NORMALIZED 0
-#elif GR_TEXT_SCALAR_IS_FIXED
- #define GrGLTextType GR_GL_FIXED
- #define GR_GL_TEXT_TEXTURE_NORMALIZED 0
-#else
- #error "unknown GR_TEXT_SCALAR type"
-#endif
-
-// Pick a pixel config for 32bit bitmaps. Our default is GL_RGBA (except on
-// Windows where we match GDI's order).
-#ifndef GR_GL_32BPP_COLOR_FORMAT
- #if GR_WIN32_BUILD || GR_LINUX_BUILD
- #define GR_GL_32BPP_COLOR_FORMAT GR_GL_BGRA
- #else
- #define GR_GL_32BPP_COLOR_FORMAT GR_GL_RGBA
- #endif
-#endif
-
-////////////////////////////////////////////////////////////////////////////////
-
-extern void GrGLCheckErr(const char* location, const char* call);
-
-extern void GrGLClearErr();
-
-#if GR_GL_CHECK_ERROR
- extern bool gCheckErrorGL;
- #define GR_GL_CHECK_ERROR_IMPL(X) if (gCheckErrorGL) GrGLCheckErr(GR_FILE_AND_LINE_STR, #X)
-#else
- #define GR_GL_CHECK_ERROR_IMPL(X)
-#endif
-
-#if GR_GL_LOG_CALLS
- extern bool gLogCallsGL;
- #define GR_GL_LOG_CALLS_IMPL(X) if (gLogCallsGL) GrPrintf(GR_FILE_AND_LINE_STR "GL: " #X "\n")
-#else
- #define GR_GL_LOG_CALLS_IMPL(X)
-#endif
-
-#define GR_GL(X) GrGLGetGLInterface()->f##X;; GR_GL_LOG_CALLS_IMPL(X); GR_GL_CHECK_ERROR_IMPL(X);
-#define GR_GL_NO_ERR(X) GrGLGetGLInterface()->f##X;; GR_GL_LOG_CALLS_IMPL(X);
-
-#define GR_GL_SUPPORT_DESKTOP (kDesktop_GrGLBinding == GrGLGetGLInterface()->fBindingsExported)
-#define GR_GL_SUPPORT_ES1 (kES1_GrGLBinding == GrGLGetGLInterface()->fBindingsExported)
-#define GR_GL_SUPPORT_ES2 (kES2_GrGLBinding == GrGLGetGLInterface()->fBindingsExported)
-#define GR_GL_SUPPORT_ES (GR_GL_SUPPORT_ES1 || GR_GL_SUPPORT_ES2)
-
-////////////////////////////////////////////////////////////////////////////////
-
-/**
- * GrGLRestoreResetRowLength() will reset GL_UNPACK_ROW_LENGTH to 0. We write
- * this wrapper, since GL_UNPACK_ROW_LENGTH is not available on all GL versions
- */
-extern void GrGLRestoreResetRowLength();
-
-////////////////////////////////////////////////////////////////////////////////
-
-/**
- * Some drivers want the var-int arg to be zero-initialized on input.
- */
-#define GR_GL_INIT_ZERO 0
-#define GR_GL_GetIntegerv(e, p) \
- do { \
- *(p) = GR_GL_INIT_ZERO; \
- GR_GL(GetIntegerv(e, p)); \
- } while (0)
-
-////////////////////////////////////////////////////////////////////////////////
-
-#endif
diff --git a/gpu/include/GrGLConfig_chrome.h b/gpu/include/GrGLConfig_chrome.h
deleted file mode 100644
index 738e801..0000000
--- a/gpu/include/GrGLConfig_chrome.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef GrGLConfig_chrome_DEFINED
-#define GrGLConfig_chrome_DEFINED
-
-// chrome always assumes BGRA
-#define GR_GL_32BPP_COLOR_FORMAT GR_GL_BGRA
-
-// glGetError() forces a sync with gpu process on chrome
-#define GR_GL_CHECK_ERROR_START 0
-
-// ANGLE creates a temp VB for vertex attributes not specified per-vertex.
-#define GR_GL_NO_CONSTANT_ATTRIBUTES GR_WIN32_BUILD
-
-#endif
diff --git a/gpu/include/GrGLTexture.h b/gpu/include/GrGLTexture.h
deleted file mode 100644
index cb50a1e..0000000
--- a/gpu/include/GrGLTexture.h
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#ifndef GrGLTexture_DEFINED
-#define GrGLTexture_DEFINED
-
-#include "GrTexture.h"
-#include "GrScalar.h"
-#include "GrGLIRect.h"
-
-class GrGpuGL;
-class GrGLTexture;
-
-/**
- * A ref counted tex id that deletes the texture in its destructor.
- */
-class GrGLTexID : public GrRefCnt {
-
-public:
- GrGLTexID(GrGLuint texID, bool ownsID) : fTexID(texID), fOwnsID(ownsID) {}
-
- virtual ~GrGLTexID() {
- if (0 != fTexID && fOwnsID) {
- GR_GL(DeleteTextures(1, &fTexID));
- }
- }
-
- void abandon() { fTexID = 0; }
- GrGLuint id() const { return fTexID; }
-
-private:
- GrGLuint fTexID;
- bool fOwnsID;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-class GrGLRenderTarget : public GrRenderTarget {
-
-public:
- // set fTexFBOID to this value to indicate that it is multisampled but
- // Gr doesn't know how to resolve it.
- enum { kUnresolvableFBOID = 0 };
-
- struct GLRenderTargetIDs {
- GrGLuint fRTFBOID;
- GrGLuint fTexFBOID;
- GrGLuint fStencilRenderbufferID;
- GrGLuint fMSColorRenderbufferID;
- bool fOwnIDs;
- void reset() { memset(this, 0, sizeof(GLRenderTargetIDs)); }
- };
-
- GrGLRenderTarget(GrGpuGL* gpu,
- const GLRenderTargetIDs& ids,
- GrGLTexID* texID,
- GrGLuint stencilBits,
- bool isMultisampled,
- const GrGLIRect& fViewport,
- GrGLTexture* texture);
-
- virtual ~GrGLRenderTarget() { this->release(); }
-
- void setViewport(const GrGLIRect& rect) { fViewport = rect; }
- const GrGLIRect& getViewport() const { return fViewport; }
-
- // The following two functions return the same ID when a
- // texture-rendertarget is multisampled, and different IDs when
- // it is.
- // FBO ID used to render into
- GrGLuint renderFBOID() const { return fRTFBOID; }
- // FBO ID that has texture ID attached.
- GrGLuint textureFBOID() const { return fTexFBOID; }
-
- // override of GrRenderTarget
- virtual ResolveType getResolveType() const {
- if (fRTFBOID == fTexFBOID) {
- // catches FBO 0 and non MSAA case
- return kAutoResolves_ResolveType;
- } else if (kUnresolvableFBOID == fTexFBOID) {
- return kCantResolve_ResolveType;
- } else {
- return kCanResolve_ResolveType;
- }
- }
-
-protected:
- // override of GrResource
- virtual void onAbandon();
- virtual void onRelease();
-
-private:
- GrGLuint fRTFBOID;
- GrGLuint fTexFBOID;
- GrGLuint fStencilRenderbufferID;
- GrGLuint fMSColorRenderbufferID;
-
- // Should this object delete IDs when it is destroyed or does someone
- // else own them.
- bool fOwnIDs;
-
- // when we switch to this rendertarget we want to set the viewport to
- // only render to to content area (as opposed to the whole allocation) and
- // we want the rendering to be at top left (GL has origin in bottom left)
- GrGLIRect fViewport;
-
- // non-NULL if this RT was created by Gr with an associated GrGLTexture.
- GrGLTexID* fTexIDObj;
-
- typedef GrRenderTarget INHERITED;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-class GrGLTexture : public GrTexture {
-
-public:
- enum Orientation {
- kBottomUp_Orientation,
- kTopDown_Orientation,
- };
-
- struct TexParams {
- GrGLenum fFilter;
- GrGLenum fWrapS;
- GrGLenum fWrapT;
- void invalidate() { memset(this, 0xff, sizeof(TexParams)); }
- };
-
- struct GLTextureDesc {
- uint32_t fContentWidth;
- uint32_t fContentHeight;
- uint32_t fAllocWidth;
- uint32_t fAllocHeight;
- GrPixelConfig fFormat;
- GrGLuint fTextureID;
- bool fOwnsID;
- GrGLenum fUploadFormat;
- GrGLenum fUploadByteCount;
- GrGLenum fUploadType;
- GrGLuint fStencilBits;
- Orientation fOrientation;
- };
-
- typedef GrGLRenderTarget::GLRenderTargetIDs GLRenderTargetIDs;
-
- GrGLTexture(GrGpuGL* gpu,
- const GLTextureDesc& textureDesc,
- const GLRenderTargetIDs& rtIDs,
- const TexParams& initialTexParams);
-
- virtual ~GrGLTexture() { this->release(); }
-
- // overrides of GrTexture
- virtual void uploadTextureData(uint32_t x,
- uint32_t y,
- uint32_t width,
- uint32_t height,
- const void* srcData);
- virtual intptr_t getTextureHandle();
-
- const TexParams& getTexParams() const { return fTexParams; }
- void setTexParams(const TexParams& texParams) { fTexParams = texParams; }
- GrGLuint textureID() const { return fTexIDObj->id(); }
-
- GrGLenum uploadFormat() const { return fUploadFormat; }
- GrGLenum uploadByteCount() const { return fUploadByteCount; }
- GrGLenum uploadType() const { return fUploadType; }
-
- /**
- * Retrieves the texture width actually allocated in texels.
- *
- * @return the width in texels
- */
- int allocWidth() const { return fAllocWidth; }
-
- /**
- * Retrieves the texture height actually allocated in texels.
- *
- * @return the height in texels
- */
- int allocHeight() const { return fAllocHeight; }
-
- /**
- * @return width() / allocWidth()
- */
- GrScalar contentScaleX() const { return fScaleX; }
-
- /**
- * @return height() / allocHeight()
- */
- GrScalar contentScaleY() const { return fScaleY; }
-
- // Ganesh assumes texture coordinates have their origin
- // in the top-left corner of the image. OpenGL, however,
- // has the origin in the lower-left corner. For content that
- // is loaded by Ganesh we just push the content "upside down"
- // (by GL's understanding of the world ) in glTex*Image and the
- // addressing just works out. However, content generated by GL
- // (FBO or externally imported texture) will be updside down
- // and it is up to the GrGpuGL derivative to handle y-mirroing.
- Orientation orientation() const { return fOrientation; }
-
- static const GrGLenum* WrapMode2GLWrap();
-
-protected:
-
- // overrides of GrTexture
- virtual void onAbandon();
- virtual void onRelease();
-
-private:
- TexParams fTexParams;
- GrGLTexID* fTexIDObj;
- GrGLenum fUploadFormat;
- GrGLenum fUploadByteCount;
- GrGLenum fUploadType;
- int fAllocWidth;
- int fAllocHeight;
- // precomputed content / alloc ratios
- GrScalar fScaleX;
- GrScalar fScaleY;
- Orientation fOrientation;
- GrGpuGL* fGpuGL;
-
- typedef GrTexture INHERITED;
-};
-
-#endif
diff --git a/gpu/include/GrIPoint.h b/gpu/include/GrIPoint.h
deleted file mode 100644
index b979a09..0000000
--- a/gpu/include/GrIPoint.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrIPoint_DEFINED
-#define GrIPoint_DEFINED
-
-#include "GrTypes.h"
-
-struct GrIPoint {
-public:
- int32_t fX, fY;
-
- GrIPoint(int32_t x, int32_t y) : fX(x), fY(y) {}
-
- void set(int32_t x, int32_t y) {
- fX = x;
- fY = y;
- }
-};
-
-#endif
diff --git a/gpu/include/GrIndexBuffer.h b/gpu/include/GrIndexBuffer.h
deleted file mode 100644
index 366640e..0000000
--- a/gpu/include/GrIndexBuffer.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrIndexBuffer_DEFINED
-#define GrIndexBuffer_DEFINED
-
-#include "GrGeometryBuffer.h"
-
-class GrIndexBuffer : public GrGeometryBuffer {
-public:
- /**
- * Retrieves the maximum number of quads that could be rendered
- * from the index buffer (using kTriangles_PrimitiveType).
- * @return the maximum number of quads using full size of index buffer.
- */
- int maxQuads() const { return size() / (sizeof(uint16_t) * 6); }
-protected:
- GrIndexBuffer(GrGpu* gpu, size_t sizeInBytes, bool dynamic)
- : INHERITED(gpu, sizeInBytes, dynamic) {}
-private:
- typedef GrGeometryBuffer INHERITED;
-};
-
-#endif
diff --git a/gpu/include/GrMatrix.h b/gpu/include/GrMatrix.h
deleted file mode 100644
index a879ed0..0000000
--- a/gpu/include/GrMatrix.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrMatrix_DEFINED
-#define GrMatrix_DEFINED
-
-#include "GrRect.h"
-#include "SkMatrix.h"
-
-typedef SkMatrix GrMatrix;
-
-#endif
diff --git a/gpu/include/GrMemory.h b/gpu/include/GrMemory.h
deleted file mode 100644
index be8b1d7..0000000
--- a/gpu/include/GrMemory.h
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrMemory_DEFINED
-#define GrMemory_DEFINED
-
-#include "GrNoncopyable.h"
-
-class GrAutoMalloc : GrNoncopyable {
-public:
- GrAutoMalloc() : fPtr(NULL), fAllocatedBytes(0){
- }
-
- GrAutoMalloc(size_t bytes) : fPtr(GrMalloc(bytes)), fAllocatedBytes(bytes) {}
- ~GrAutoMalloc() { GrFree(fPtr); }
-
- /**
- * Return the allocated memory, or NULL if it has already been freed or
- * detached.
- */
- void* get() const { return fPtr; }
-
- size_t size() const { return fAllocatedBytes; }
-
- /**
- * transfer ownership of the memory to the caller. It must be freed with
- * a call to GrFree()
- */
- void* detach() {
- void* ptr = fPtr;
- fPtr = NULL; // we no longer own the block
- fAllocatedBytes = 0;
- return ptr;
- }
-
- /**
- * Reallocates to a new size. May or may not call malloc. The contents
- * are not preserved. If growOnly is true it will never reduce the
- * allocated size.
- */
- void* realloc(size_t newSize, bool growOnly = false) {
- bool alloc;
- if (growOnly) {
- alloc = newSize > fAllocatedBytes;
- } else {
- alloc = newSize != fAllocatedBytes;
- }
- if (alloc) {
- GrFree(fPtr);
- fPtr = newSize ? GrMalloc(newSize) : NULL;
- fAllocatedBytes = newSize;
- }
- GrAssert(fAllocatedBytes >= newSize);
- GR_DEBUGCODE(memset(fPtr, 0xEF, fAllocatedBytes));
- return fPtr;
- }
-
- /**
- * free the block now. get() will now return NULL
- */
- void free() {
- GrFree(fPtr);
- fPtr = NULL;
- fAllocatedBytes = 0;
- }
-
-private:
- void* fPtr;
- size_t fAllocatedBytes;
-};
-
-/**
- * Variant of GrAutoMalloc with a compile-time specified byte size that is
- * pre-allocated in the class object, avoiding a call to to GrMalloc if
- * possible.
- */
-template <size_t SIZE> class GrAutoSMalloc : GrNoncopyable {
-public:
- GrAutoSMalloc() {
- fPtr = fStorage;
- fAllocatedBytes = SIZE;
- }
-
- explicit GrAutoSMalloc(size_t bytes) {
- if (bytes > SIZE) {
- fPtr = GrMalloc(bytes);
- fAllocatedBytes = bytes;
- } else {
- fPtr = fStorage;
- fAllocatedBytes = SIZE;
- }
- }
-
- ~GrAutoSMalloc() {
- if (fPtr != (void*)fStorage) {
- GrFree(fPtr);
- }
- }
-
- /**
- * Return the allocated memory, or NULL if it has already been freed or
- * detached.
- */
- void* get() const { return fPtr; }
-
- /**
- * Reallocates to a new size. May or may not call malloc. The contents
- * are not preserved. If growOnly is true it will never reduce the
- * allocated size.
- */
- void* realloc(size_t newSize, bool growOnly = false) {
- if (newSize <= SIZE) {
- if (NULL == fPtr) {
- fPtr = fStorage;
- fAllocatedBytes = SIZE;
- } else if (!growOnly && fPtr != (void*)fStorage) {
- GrFree(fPtr);
- fPtr = fStorage;
- fAllocatedBytes = SIZE;
- }
- } else if ((newSize > fAllocatedBytes) ||
- (!growOnly && newSize < (fAllocatedBytes >> 1))) {
- if (NULL != fPtr && fPtr != (void*)fStorage) {
- GrFree(fPtr);
- }
- fPtr = GrMalloc(newSize);
- fAllocatedBytes = newSize;
- }
- GrAssert(fAllocatedBytes >= newSize);
- GrAssert((fPtr == fStorage) == (fAllocatedBytes == SIZE));
- GR_DEBUGCODE(memset(fPtr, 0xEF, fAllocatedBytes));
- return fPtr;
- }
-
- /**
- * free the block now. get() will now return NULL
- */
- void free() {
- if (fPtr != (void*)fStorage) {
- GrFree(fPtr);
- }
- fAllocatedBytes = 0;
- fPtr = NULL;
- }
-
-private:
- void* fPtr;
- uint32_t fAllocatedBytes;
- uint32_t fStorage[GrALIGN4(SIZE) >> 2];
-};
-
-/**
- * Variant of GrAutoMalloc with a compile-time specified byte size that is
- * pre-allocated in the class object, avoiding a call to to GrMalloc if
- * possible.
- */
-template <int COUNT, typename T>
-class GrAutoSTMalloc : public GrAutoSMalloc<COUNT * sizeof(T)> {
-public:
- GrAutoSTMalloc(int count) : GrAutoSMalloc<COUNT * sizeof(T)>(count * sizeof(T)) {}
-
- operator T*() { return (T*)this->get(); }
-};
-
-
-#endif
-
diff --git a/gpu/include/GrMesh.h b/gpu/include/GrMesh.h
deleted file mode 100644
index 4d904e4..0000000
--- a/gpu/include/GrMesh.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef GrMesh_DEFINED
-#define GrMesh_DEFINED
-
-#include "SkRect.h"
-#include "SkPoint.h"
-
-class SkCanvas;
-class SkPaint;
-
-class GrMesh {
-public:
- GrMesh();
- ~GrMesh();
-
- GrMesh& operator=(const GrMesh& src);
-
- void init(const SkRect& bounds, int rows, int cols,
- const SkRect& texture);
-
- const SkRect& bounds() const { return fBounds; }
-
- int rows() const { return fRows; }
- int cols() const { return fCols; }
- SkPoint& pt(int row, int col) {
- return fPts[row * (fRows + 1) + col];
- }
-
- void draw(SkCanvas*, const SkPaint&);
- void drawWireframe(SkCanvas* canvas, const SkPaint& paint);
-
-private:
- SkRect fBounds;
- int fRows, fCols;
- SkPoint* fPts;
- SkPoint* fTex; // just points into fPts, not separately allocated
- int fCount;
- uint16_t* fIndices;
- int fIndexCount;
-};
-
-#endif
-
diff --git a/gpu/include/GrNoncopyable.h b/gpu/include/GrNoncopyable.h
deleted file mode 100644
index ab5d8ec..0000000
--- a/gpu/include/GrNoncopyable.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrNoncopyable_DEFINED
-#define GrNoncopyable_DEFINED
-
-#include "GrTypes.h"
-
-/**
- * Base for classes that want to disallow copying themselves. It makes its
- * copy-constructor and assignment operators private (and unimplemented).
- */
-class GR_API GrNoncopyable {
-public:
- GrNoncopyable() {}
-
-private:
- // illegal
- GrNoncopyable(const GrNoncopyable&);
- GrNoncopyable& operator=(const GrNoncopyable&);
-};
-
-#endif
-
diff --git a/gpu/include/GrPath.h b/gpu/include/GrPath.h
deleted file mode 100644
index c23cfc4..0000000
--- a/gpu/include/GrPath.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrPath_DEFINED
-#define GrPath_DEFINED
-
-#include "GrTypes.h"
-#include "SkPath.h"
-
-typedef SkPath GrPath;
-
-#endif
-
diff --git a/gpu/include/GrPathRenderer.h b/gpu/include/GrPathRenderer.h
deleted file mode 100644
index 1ebad4f..0000000
--- a/gpu/include/GrPathRenderer.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#ifndef GrPathRenderer_DEFINED
-#define GrPathRenderer_DEFINED
-
-#include "GrDrawTarget.h"
-
-class SkPath;
-struct GrPoint;
-
-/**
- * Base class for drawing paths into a GrDrawTarget.
- */
-class GR_API GrPathRenderer : public GrRefCnt {
-public:
- /**
- * Returns true if this path renderer is able to render the path.
- * Returning false allows the caller to fallback to another path renderer.
- *
- * @param target The target to draw into
- * @param path The path to draw
- * @param fill The fill rule to use
- *
- * @return true if the path can be drawn by this object, false otherwise.
- */
- virtual bool canDrawPath(const GrDrawTarget* target, const SkPath& path,
- GrPathFill fill) const = 0;
-
- /**
- * Draws a path into the draw target. The target will already have its draw
- * state configured for the draw.
- * @param target the target to draw into.
- * @param stages indicates which stages the are already
- * in use. All enabled stages expect positions
- * as texture coordinates. The path renderer
- * use the remaining stages for its path
- * filling algorithm.
- * @param path the path to draw.
- * @param fill the fill rule to apply.
- * @param translate optional additional translation to apply to
- * the path. NULL means (0,0).
- */
- virtual void drawPath(GrDrawTarget* target,
- GrDrawTarget::StageBitfield stages,
- const SkPath& path,
- GrPathFill fill,
- const GrPoint* translate) = 0;
-
- /**
- * For complex clips Gr uses the stencil buffer. The path renderer must be
- * able to render paths into the stencil buffer. However, the path renderer
- * itself may require the stencil buffer to resolve the path fill rule. This
- * function queries whether the path render needs its own stencil
- * pass. If this returns false then drawPath() should not modify the
- * the target's stencil settings but use those already set on target.
- *
- * @param target target that the path will be rendered to
- * @param path the path that will be drawn
- * @param fill the fill rule that will be used, will never be an inverse
- * rule.
- *
- * @return false if this path renderer can generate interior-only fragments
- * without changing the stencil settings on the target. If it
- * returns true the drawPathToStencil will be used when rendering
- * clips.
- */
- virtual bool requiresStencilPass(const GrDrawTarget* target,
- const SkPath& path,
- GrPathFill fill) const { return false; }
-
- /**
- * Draws a path to the stencil buffer. Assume the writable stencil bits
- * are already initialized to zero. Fill will always be either
- * kWinding_PathFill or kEvenOdd_PathFill.
- *
- * Only called if requiresStencilPass returns true for the same combo of
- * target, path, and fill. Never called with an inverse fill.
- *
- * The default implementation assumes the path filling algorithm doesn't
- * require a separate stencil pass and so crashes.
- *
- *
- * @param target the target to draw into.
- * @param path the path to draw.
- * @param fill the fill rule to apply.
- * @param translate optional additional translation to apply to
- * the path. NULL means (0,0).
- */
- virtual void drawPathToStencil(GrDrawTarget* target,
- const SkPath& path,
- GrPathFill fill,
- const GrPoint* translate) {
- GrCrash("Unexpected call to drawPathToStencil.");
- }
-
- /**
- * @return true if the path renderer can perform anti-aliasing (aside from
- * having FSAA enabled for a render target)
- */
- virtual bool supportsAA(GrDrawTarget* target,
- const SkPath& path,
- GrPathFill fill) { return false; }
-
- /**
- * This is called to install a custom path renderer in every GrContext at
- * create time. The default implementation in GrCreatePathRenderer_none.cpp
- * returns NULL. Link against another implementation to install your own.
- */
- static GrPathRenderer* CreatePathRenderer();
-
-private:
-
- typedef GrRefCnt INHERITED;
-};
-
-/**
- * Subclass that renders the path using the stencil buffer to resolve fill
- * rules (e.g. winding, even-odd)
- */
-class GR_API GrDefaultPathRenderer : public GrPathRenderer {
-public:
- GrDefaultPathRenderer(bool separateStencilSupport,
- bool stencilWrapOpsSupport);
-
- virtual bool canDrawPath(const GrDrawTarget* target,
- const SkPath& path,
- GrPathFill fill) const { return true; }
-
- virtual void drawPath(GrDrawTarget* target,
- GrDrawTarget::StageBitfield stages,
- const SkPath& path,
- GrPathFill fill,
- const GrPoint* translate);
- virtual bool requiresStencilPass(const GrDrawTarget* target,
- const SkPath& path,
- GrPathFill fill) const;
- virtual void drawPathToStencil(GrDrawTarget* target,
- const SkPath& path,
- GrPathFill fill,
- const GrPoint* translate);
-private:
-
- void onDrawPath(GrDrawTarget* target,
- GrDrawTarget::StageBitfield stages,
- const SkPath& path,
- GrPathFill fill,
- const GrPoint* translate,
- bool stencilOnly);
-
- bool fSeparateStencil;
- bool fStencilWrapOps;
-
- typedef GrPathRenderer INHERITED;
-};
-
-#endif
diff --git a/gpu/include/GrPathSink.h b/gpu/include/GrPathSink.h
deleted file mode 100644
index 4e8a0c2..0000000
--- a/gpu/include/GrPathSink.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrPathSink_DEFINED
-#define GrPathSink_DEFINED
-
-#include "GrScalar.h"
-
-class GrPathSink {
-public:
- virtual ~GrPathSink() {}
-
- virtual void moveTo(GrScalar x, GrScalar y) = 0;
- virtual void lineTo(GrScalar x, GrScalar y) = 0;
- virtual void quadTo(GrScalar x0, GrScalar y0, GrScalar x1, GrScalar y1) = 0;
- virtual void cubicTo(GrScalar x0, GrScalar y0, GrScalar x1, GrScalar y1,
- GrScalar x2, GrScalar y2) = 0;
- virtual void close() = 0;
-};
-
-#endif
-
diff --git a/gpu/include/GrPoint.h b/gpu/include/GrPoint.h
deleted file mode 100644
index 472efb3..0000000
--- a/gpu/include/GrPoint.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrPoint_DEFINED
-#define GrPoint_DEFINED
-
-#include "GrTypes.h"
-#include "GrScalar.h"
-#include "SkPoint.h"
-
-#define GrPoint SkPoint
-#define GrVec SkVector
-
-struct GrIPoint16 {
- int16_t fX, fY;
-
- void set(intptr_t x, intptr_t y) {
- fX = GrToS16(x);
- fY = GrToS16(y);
- }
-};
-
-#endif
-
diff --git a/gpu/include/GrRefCnt.h b/gpu/include/GrRefCnt.h
deleted file mode 100644
index 9c9fed1..0000000
--- a/gpu/include/GrRefCnt.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrRefCnt_DEFINED
-#define GrRefCnt_DEFINED
-
-#include "GrTypes.h"
-#include "GrNoncopyable.h"
-
-/**
- * Base class for reference counting. When an object is first instantiated,
- * its reference count is 1. If the object may be null, use GrSafeRef() and
- * GrSafeUnref().
- *
- * It is an error (though only checked for in the debug build) to call unref()
- * such that the reference count becomes 0.
- */
-class GR_API GrRefCnt : GrNoncopyable {
-public:
- GrRefCnt() : fRefCnt(1) {}
- virtual ~GrRefCnt() {
- GrAssert(1 == fRefCnt);
-#if GR_DEBUG
- fRefCnt = 0; // force validate() to trigger if called afterwards
-#endif
- }
-
- int32_t refcnt() const { return fRefCnt; }
-
- void ref() const {
- GrAssert(fRefCnt > 0);
- ++fRefCnt;
- }
-
- void unref() const {
- GrAssert(fRefCnt > 0);
- if (1 == fRefCnt) {
- delete this;
- } else {
- --fRefCnt;
- }
- }
-
-#if GR_DEBUG
- void validate() const {
- GrAssert(fRefCnt > 0);
- }
-#else
- void validate() const {}
-#endif
-
-private:
- mutable int32_t fRefCnt;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Call with instance/subclass of GrRefCnt. This does nothing if obj is null,
- * but otherwise it calls ref().
- */
-static inline void GrSafeRef(const GrRefCnt* obj) {
- if (obj) {
- obj->ref();
- }
-}
-
-/**
- * Call with instance/subclass of GrRefCnt. This does nothing if obj is null,
- * but otherwise it calls unref().
- */
-static inline void GrSafeUnref(const GrRefCnt* obj) {
- if (obj) {
- obj->unref();
- }
-}
-
-/**
- * Assigns src to dst, checking for NULLs in each, and correctly incrementing
- * the reference count of src, and decrementing the reference count of dst
- */
-template<typename T>
-static inline void GrSafeAssign(T*& dst, T* src) {
- if (src) {
- src->ref();
- }
- if (dst) {
- dst->unref();
- }
- dst = src;
-}
-
-template<typename T>
-static inline void GrSafeSetNull(T*& obj) {
- if (NULL != obj) {
- obj->unref();
- obj = NULL;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-class GrAutoRef : GrNoncopyable {
-public:
- GrAutoRef(GrRefCnt* obj) : fObj(obj) { GrSafeRef(obj); }
- ~GrAutoRef() { GrSafeUnref(fObj); }
-private:
- GrRefCnt* fObj;
-};
-
-class GrAutoUnref : GrNoncopyable {
-public:
- GrAutoUnref(GrRefCnt* obj) : fObj(obj) {}
- ~GrAutoUnref() { GrSafeUnref(fObj); }
-private:
- GrRefCnt* fObj;
-};
-
-#endif
-
diff --git a/gpu/include/GrStencil.h b/gpu/include/GrStencil.h
deleted file mode 100644
index 44a390d..0000000
--- a/gpu/include/GrStencil.h
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#ifndef GrStencil_DEFINED
-#define GrStencil_DEFINED
-
-#include "GrTypes.h"
-/**
- * Gr uses the stencil buffer to implement complex clipping inside the
- * GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer
- * bits available for other uses by external code (clients). Client code can
- * modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits
- * provided by clients that overlap the bits used to implement clipping. The
- * client can use the getUsableStencilBits() function to find out how many
- * client accessible stencil bits are available.
- *
- * When code outside the GrDrawTarget class uses the stencil buffer the contract
- * is as follows:
- *
- * > Normal stencil funcs allow the GrGpu client to modify the client bits of
- * the stencil buffer outside of the clip.
- * > Special functions allow a test against the clip. These are more limited
- * than the general stencil functions.
- * > Client can assume all client bits are zero initially.
- * > Client must ensure that after all its passes are finished it has only
- * written to the color buffer in the region inside the clip. Furthermore, it
- * must zero all client bits that were modifed (both inside and outside the
- * clip).
- */
-
-/**
- * Determines which pixels pass / fail the stencil test.
- * Stencil test passes if (ref & mask) FUNC (stencil & mask) is true
- */
-enum GrStencilFunc {
- kAlways_StencilFunc = 0,
- kNever_StencilFunc,
- kGreater_StencilFunc,
- kGEqual_StencilFunc,
- kLess_StencilFunc,
- kLEqual_StencilFunc,
- kEqual_StencilFunc,
- kNotEqual_StencilFunc,
-
- // Gr stores the current clip in the
- // stencil buffer in the high bits that
- // are not directly accessible modifiable
- // via the GrDrawTarget interface. The below
- // stencil funcs test against the current
- // clip in addition to the GrDrawTarget
- // client's stencil bits.
-
- // pass if inside the clip
- kAlwaysIfInClip_StencilFunc,
- kEqualIfInClip_StencilFunc,
- kLessIfInClip_StencilFunc,
- kLEqualIfInClip_StencilFunc,
- kNonZeroIfInClip_StencilFunc, // this one forces the ref to be 0
-
- // counts
- kStencilFuncCount,
- kClipStencilFuncCount = kNonZeroIfInClip_StencilFunc -
- kAlwaysIfInClip_StencilFunc + 1,
- kBasicStencilFuncCount = kStencilFuncCount - kClipStencilFuncCount
-};
-
-/**
- * Operations to perform based on whether stencil test passed failed.
- */
-enum GrStencilOp {
- kKeep_StencilOp = 0, // preserve existing stencil value
- kReplace_StencilOp, // replace with reference value from stencl test
- kIncWrap_StencilOp, // increment and wrap at max
- kIncClamp_StencilOp, // increment and clamp at max
- kDecWrap_StencilOp, // decrement and wrap at 0
- kDecClamp_StencilOp, // decrement and clamp at 0
- kZero_StencilOp, // zero stencil bits
- kInvert_StencilOp, // invert stencil bits
-
- kStencilOpCount
-};
-
-/**
- * Struct representing stencil state.
- */
-struct GrStencilSettings {
- GrStencilOp fFrontPassOp; // op to perform when front faces pass
- GrStencilOp fBackPassOp; // op to perform when back faces pass
- GrStencilOp fFrontFailOp; // op to perform when front faces fail
- GrStencilOp fBackFailOp; // op to perform when back faces fail
- GrStencilFunc fFrontFunc; // test function for front faces
- GrStencilFunc fBackFunc; // test function for back faces
- unsigned int fFrontFuncMask; // mask for front face test
- unsigned int fBackFuncMask; // mask for back face test
- unsigned int fFrontFuncRef; // reference value for front face test
- unsigned int fBackFuncRef; // reference value for back face test
- unsigned int fFrontWriteMask; // stencil write mask for front faces
- unsigned int fBackWriteMask; // stencil write mask for back faces
-
- bool operator == (const GrStencilSettings& s) const {
- // make sure this is tightly packed.
- GR_STATIC_ASSERT(0 == sizeof(GrStencilOp)%4);
- GR_STATIC_ASSERT(0 == sizeof(GrStencilFunc)%4);
- GR_STATIC_ASSERT(sizeof(GrStencilSettings) ==
- 4*sizeof(GrStencilOp) +
- 2*sizeof(GrStencilFunc) +
- 6*sizeof(unsigned int));
- return 0 == memcmp(this, &s, sizeof(GrStencilSettings));
- }
-
- bool operator != (const GrStencilSettings& s) const {
- return !(*this == s);
- }
-
- GrStencilSettings& operator =(const GrStencilSettings& s) {
- memcpy(this, &s, sizeof(GrStencilSettings));
- return *this;
- }
-
- void setSame(GrStencilOp passOp,
- GrStencilOp failOp,
- GrStencilFunc func,
- unsigned int funcMask,
- unsigned int funcRef,
- unsigned int writeMask) {
- fFrontPassOp = passOp;
- fBackPassOp = passOp;
- fFrontFailOp = failOp;
- fBackFailOp = failOp;
- fFrontFunc = func;
- fBackFunc = func;
- fFrontFuncMask = funcMask;
- fBackFuncMask = funcMask;
- fFrontFuncRef = funcRef;
- fBackFuncRef = funcRef;
- fFrontWriteMask = writeMask;
- fBackWriteMask = writeMask;
- }
-
- // canonical value for disabled stenciling
- static const GrStencilSettings gDisabled;
- void setDisabled() {
- *this = gDisabled;
- }
- bool isDisabled() const {
- return kKeep_StencilOp == fFrontPassOp &&
- kKeep_StencilOp == fBackPassOp &&
- kKeep_StencilOp == fFrontFailOp &&
- kKeep_StencilOp == fBackFailOp &&
- kAlways_StencilFunc == fFrontFunc &&
- kAlways_StencilFunc == fBackFunc;
- }
- void invalidate() {
- // just write an illegal value to the first member
- fFrontPassOp = (GrStencilOp)-1;
- }
-
-private:
- friend class GrGpu;
-
- enum {
- kMaxStencilClipPasses = 2 // maximum number of passes to add a clip
- // element to the stencil buffer.
- };
-
- /**
- * Given a thing to draw into the stencil clip, a fill type, and a set op
- * this function determines:
- * 1. Whether the thing can be draw directly to the stencil clip or
- * needs to be drawn to the client portion of the stencil first.
- * 2. How many passes are needed.
- * 3. What those passes are.
- * 4. The fill rule that should actually be used to render (will
- * always be non-inverted).
- *
- * @param op the set op to combine this element with the
- * existing clip
- * @param stencilClipMask mask with just the stencil bit used for clipping
- * enabled.
- * @param invertedFill is this path inverted
- * @param numPasses out: the number of passes needed to add the
- * element to the clip.
- * @param settings out: the stencil settings to use for each pass
- *
- * @return true if the clip element's geometry can be drawn directly to the
- * stencil clip bit. Will only be true if canBeDirect is true.
- * numPasses will be 1 if return value is true.
- */
- static bool GetClipPasses(GrSetOp op,
- bool canBeDirect,
- unsigned int stencilClipMask,
- bool invertedFill,
- int* numPasses,
- GrStencilSettings settings[kMaxStencilClipPasses]);
-};
-
-#endif
diff --git a/gpu/include/GrStopwatch.h b/gpu/include/GrStopwatch.h
deleted file mode 100644
index 4945897..0000000
--- a/gpu/include/GrStopwatch.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrStopwatch_DEFINED
-#define GrStopwatch_DEFINED
-
-#include "GrTypes.h"
-
-template <typename PLATFORM_TIMER>
-/**
- * Base class for stopwatch. Relies on PLATFORM_TIMER for platform-specific
- * timer functions. PLATFORM_TIMER provides:
- * - typename TIMESTAMP : a timestamp value that can be used with Diff()
- * - static TIMESTAMP Now() : gets current timestamp
- * - static double Diff(const TIMESTAMP& begin, const TIMESTAMP& end) :
- * computes delta in seconds between two timestamps
- */
-class GrStopwatchBase {
-public:
- /**
- * Contructor - implicit reset()
- */
- GrStopwatchBase() {
- fRunning = false;
- fTotalElapsed = 0.0;
- }
-
- /**
- * begins a new lap
- */
- void start() {
- double lastLap = lapTime();
- fTotalElapsed += lastLap;
- fRunning = true;
- fLastStart = PLATFORM_TIMER::Now();
- }
-
- /**
- * ends current lap (or no effect if lap not started)
- */
- void stop() {
- double lastLap = lapTime();
- fTotalElapsed += lastLap;
- fRunning = false;
- }
-
- /**
- * ends current lap, resets total time
- */
- void reset() {
- fRunning = false;
- fTotalElapsed = 0.f;
- }
-
- /**
- * Computes the time of all laps since last reset() including current lap
- * if lap is still running.
- *
- * @return the sum time in seconds of all laps since last reset().
- */
- double totalTime() const {
- return fTotalElapsed + lapTime();
- }
-
- /**
- * Current lap time.
- *
- * @return time in seconds of current lap if one is running otherwise 0.
- */
- double lapTime() const {
- if (fRunning) {
- PLATFORM_TIMER::Timestamp now = PLATFORM_TIMER::Now();
- return PLATFORM_TIMER::Elapsed(fLastStart, now);
- }
- return 0.0;
- }
-
-private:
- double fTotalElapsed;
-
- typename PLATFORM_TIMER::Timestamp fLastStart;
- bool fRunning;
-};
-
-#if GR_WIN32_BUILD
-
- #include <Windows.h>
-
- class GrWin32Timer {
- public:
- typedef LARGE_INTEGER Timestamp;
-
- static Timestamp Now() {
- LARGE_INTEGER now;
- QueryPerformanceCounter(&now);
- return now;
- }
-
- static double Elapsed(const Timestamp& begin, const Timestamp& end) {
- double diff = (double)(end.QuadPart - begin.QuadPart);
- return diff * Scale();
- }
- private:
- static double Scale() {
- static double scale;
- if (0.0 == scale) {
- LARGE_INTEGER freq;
- QueryPerformanceFrequency(&freq);
- GrAssert(0 != freq.QuadPart);
- scale = 1 / (double) freq.QuadPart;
- }
- return scale;
- }
- };
- typedef GrStopwatchBase<GrWin32Timer> GrStopwatch;
-#else
- #error "Implement platform timer for stopwatch"
-#endif
-
-
-#endif
diff --git a/gpu/include/GrStringBuilder.h b/gpu/include/GrStringBuilder.h
deleted file mode 100644
index 73b3796..0000000
--- a/gpu/include/GrStringBuilder.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrStringBuilder_DEFINED
-#define GrStringBuilder_DEFINED
-
-#include "SkString.h"
-
-typedef SkString GrStringBuilder;
-
-#endif
-
diff --git a/gpu/include/GrTArray.h b/gpu/include/GrTArray.h
deleted file mode 100644
index 821424b..0000000
--- a/gpu/include/GrTArray.h
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrTArray_DEFINED
-#define GrTArray_DEFINED
-
-#include <new>
-#include "GrTypes.h"
-#include "GrTemplates.h"
-
-// DATA_TYPE indicates that T has a trivial cons, destructor
-// and can be shallow-copied
-template <typename T, bool DATA_TYPE = false> class GrTArray {
-public:
- GrTArray() {
- fCount = 0;
- fReserveCount = MIN_ALLOC_COUNT;
- fAllocCount = 0;
- fMemArray = NULL;
- fPreAllocMemArray = NULL;
- }
-
- explicit GrTArray(int reserveCount) {
- GrAssert(reserveCount >= 0);
- fCount = 0;
- fReserveCount = reserveCount > MIN_ALLOC_COUNT ? reserveCount :
- MIN_ALLOC_COUNT;
- fAllocCount = fReserveCount;
- fMemArray = GrMalloc(sizeof(T) * fReserveCount);
- fPreAllocMemArray = NULL;
- }
-
- template <int N>
- GrTArray(GrAlignedSTStorage<N,T>* storage) {
- GrAssert(N > 0);
- fCount = 0;
- fReserveCount = N;
- fAllocCount = N;
- fMemArray = storage->get();
- fPreAllocMemArray = storage->get();
- }
-
- GrTArray(void* preAllocStorage, int preAllocCount) {
- GrAssert(preAllocCount >= 0);
- // we allow NULL,0 args and revert to the default cons. behavior
- // this makes it possible for a owner-object to use same constructor
- // to get either prealloc or nonprealloc behavior based using same line
- GrAssert((NULL == preAllocStorage) == !preAllocCount);
-
- fCount = 0;
- fReserveCount = preAllocCount > 0 ? preAllocCount :
- MIN_ALLOC_COUNT;
- fAllocCount = preAllocCount;
- fMemArray = preAllocStorage;
- fPreAllocMemArray = preAllocStorage;
- }
-
- explicit GrTArray(const GrTArray& array) {
- fCount = array.count();
- fReserveCount = MIN_ALLOC_COUNT;
- fAllocCount = GrMax(fReserveCount, fCount);
- fMemArray = GrMalloc(sizeof(T) * fAllocCount);
- fPreAllocMemArray = NULL;
-
- if (DATA_TYPE) {
- memcpy(fMemArray, array.fMemArray, sizeof(T) * fCount);
- } else {
- for (int i = 0; i < fCount; ++i) {
- new (fItemArray + i) T(array[i]);
- }
- }
- }
-
- GrTArray(const T* array, int count) {
- GrAssert(count >= 0);
- fCount = count;
- fReserveCount = MIN_ALLOC_COUNT;
- fAllocCount = GrMax(fReserveCount, fCount);
- fMemArray = GrMalloc(sizeof(T) * fAllocCount);
- fPreAllocMemArray = NULL;
- if (DATA_TYPE) {
- memcpy(fMemArray, array, sizeof(T) * fCount);
- } else {
- for (int i = 0; i < fCount; ++i) {
- new (fItemArray + i) T(array[i]);
- }
- }
- }
-
- GrTArray(const GrTArray& array,
- void* preAllocStorage, int preAllocCount) {
-
- GrAssert(preAllocCount >= 0);
-
- // for same reason as non-copying cons we allow NULL, 0 for prealloc
- GrAssert((NULL == preAllocStorage) == !preAllocCount);
-
- fCount = array.count();
- fReserveCount = preAllocCount > 0 ? preAllocCount :
- MIN_ALLOC_COUNT;
- fPreAllocMemArray = preAllocStorage;
-
- if (fReserveCount >= fCount && preAllocCount) {
- fAllocCount = fReserveCount;
- fMemArray = preAllocStorage;
- } else {
- fAllocCount = GrMax(fCount, fReserveCount);
- fMemArray = GrMalloc(fAllocCount * sizeof(T));
- }
-
- if (DATA_TYPE) {
- memcpy(fMemArray, array.fMemArray, sizeof(T) * fCount);
- } else {
- for (int i = 0; i < fCount; ++i) {
- new (fItemArray + i) T(array[i]);
- }
- }
- }
-
- GrTArray(const T* array, int count,
- void* preAllocStorage, int preAllocCount) {
-
- GrAssert(count >= 0);
- GrAssert(preAllocCount >= 0);
-
- // for same reason as non-copying cons we allow NULL, 0 for prealloc
- GrAssert((NULL == preAllocStorage) == !preAllocCount);
-
- fCount = count;
- fReserveCount = (preAllocCount > 0) ? preAllocCount :
- MIN_ALLOC_COUNT;
- fPreAllocMemArray = preAllocStorage;
-
- if (fReserveCount >= fCount && preAllocCount) {
- fAllocCount = fReserveCount;
- fMemArray = preAllocStorage;
- } else {
- fAllocCount = GrMax(fCount, fReserveCount);
- fMemArray = GrMalloc(fAllocCount * sizeof(T));
- }
-
- if (DATA_TYPE) {
- memcpy(fMemArray, array, sizeof(T) * fCount);
- } else {
- for (int i = 0; i < fCount; ++i) {
- new (fItemArray + i) T(array[i]);
- }
- }
- }
-
- GrTArray& operator =(const GrTArray& array) {
- for (int i = 0; i < fCount; ++i) {
- fItemArray[i].~T();
- }
- fCount = 0;
- checkRealloc((int)array.count());
- fCount = array.count();
- if (DATA_TYPE) {
- memcpy(fMemArray, array.fMemArray, sizeof(T) * fCount);
- } else {
- for (int i = 0; i < fCount; ++i) {
- new (fItemArray + i) T(array[i]);
- }
- }
- return *this;
- }
-
- ~GrTArray() {
- for (int i = 0; i < fCount; ++i) {
- fItemArray[i].~T();
- }
- if (fMemArray != fPreAllocMemArray) {
- GrFree(fMemArray);
- }
- }
-
- void reset() { this->pop_back_n(fCount); }
-
- int count() const { return fCount; }
-
- bool empty() const { return !fCount; }
-
- T& push_back() {
- checkRealloc(1);
- new ((char*)fMemArray+sizeof(T)*fCount) T;
- ++fCount;
- return fItemArray[fCount-1];
- }
-
- void push_back_n(int n) {
- GrAssert(n >= 0);
- checkRealloc(n);
- for (int i = 0; i < n; ++i) {
- new (fItemArray + fCount + i) T;
- }
- fCount += n;
- }
-
- void pop_back() {
- GrAssert(fCount > 0);
- --fCount;
- fItemArray[fCount].~T();
- checkRealloc(0);
- }
-
- void pop_back_n(int n) {
- GrAssert(n >= 0);
- GrAssert(fCount >= n);
- fCount -= n;
- for (int i = 0; i < n; ++i) {
- fItemArray[i].~T();
- }
- checkRealloc(0);
- }
-
- // pushes or pops from the back to resize
- void resize_back(int newCount) {
- GrAssert(newCount >= 0);
-
- if (newCount > fCount) {
- push_back_n(newCount - fCount);
- } else if (newCount < fCount) {
- pop_back_n(fCount - newCount);
- }
- }
-
- T& operator[] (int i) {
- GrAssert(i < fCount);
- GrAssert(i >= 0);
- return fItemArray[i];
- }
-
- const T& operator[] (int i) const {
- GrAssert(i < fCount);
- GrAssert(i >= 0);
- return fItemArray[i];
- }
-
- T& front() { GrAssert(fCount > 0); return fItemArray[0];}
-
- const T& front() const { GrAssert(fCount > 0); return fItemArray[0];}
-
- T& back() { GrAssert(fCount); return fItemArray[fCount - 1];}
-
- const T& back() const { GrAssert(fCount > 0); return fItemArray[fCount - 1];}
-
- T& fromBack(int i) {
- GrAssert(i >= 0);
- GrAssert(i < fCount);
- return fItemArray[fCount - i - 1];
- }
-
- const T& fromBack(int i) const {
- GrAssert(i >= 0);
- GrAssert(i < fCount);
- return fItemArray[fCount - i - 1];
- }
-
-private:
-
- static const int MIN_ALLOC_COUNT = 8;
-
- inline void checkRealloc(int delta) {
- GrAssert(fCount >= 0);
- GrAssert(fAllocCount >= 0);
-
- GrAssert(-delta <= fCount);
-
- int newCount = fCount + delta;
- int fNewAllocCount = fAllocCount;
-
- if (newCount > fAllocCount) {
- fNewAllocCount = GrMax(newCount + ((newCount + 1) >> 1),
- fReserveCount);
- } else if (newCount < fAllocCount / 3) {
- fNewAllocCount = GrMax(fAllocCount / 2, fReserveCount);
- }
-
- if (fNewAllocCount != fAllocCount) {
-
- fAllocCount = fNewAllocCount;
- char* fNewMemArray;
-
- if (fAllocCount == fReserveCount && NULL != fPreAllocMemArray) {
- fNewMemArray = (char*) fPreAllocMemArray;
- } else {
- fNewMemArray = (char*) GrMalloc(fAllocCount*sizeof(T));
- }
-
- if (DATA_TYPE) {
- memcpy(fNewMemArray, fMemArray, fCount * sizeof(T));
- } else {
- for (int i = 0; i < fCount; ++i) {
- new (fNewMemArray + sizeof(T) * i) T(fItemArray[i]);
- fItemArray[i].~T();
- }
- }
-
- if (fMemArray != fPreAllocMemArray) {
- GrFree(fMemArray);
- }
- fMemArray = fNewMemArray;
- }
- }
-
- int fReserveCount;
- int fCount;
- int fAllocCount;
- void* fPreAllocMemArray;
- union {
- T* fItemArray;
- void* fMemArray;
- };
-};
-
-#endif
-
diff --git a/gpu/include/GrTemplates.h b/gpu/include/GrTemplates.h
deleted file mode 100644
index 07e3da6..0000000
--- a/gpu/include/GrTemplates.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#ifndef GrTemplates_DEFINED
-#define GrTemplates_DEFINED
-
-#include "GrNoncopyable.h"
-
-/**
- * Use to cast a ptr to a different type, and maintain strict-aliasing
- */
-template <typename Dst, typename Src> Dst GrTCast(Src src) {
- union {
- Src src;
- Dst dst;
- } data;
- data.src = src;
- return data.dst;
-}
-
-/**
- * Reserves memory that is aligned on double and pointer boundaries.
- * Hopefully this is sufficient for all practical purposes.
- */
-template <size_t N> class GrAlignedSStorage : GrNoncopyable {
-public:
- void* get() { return fData; }
-private:
- union {
- void* fPtr;
- double fDouble;
- char fData[N];
- };
-};
-
-/**
- * Reserves memory that is aligned on double and pointer boundaries.
- * Hopefully this is sufficient for all practical purposes. Otherwise,
- * we have to do some arcane trickery to determine alignment of non-POD
- * types. Lifetime of the memory is the lifetime of the object.
- */
-template <int N, typename T> class GrAlignedSTStorage : GrNoncopyable {
-public:
- /**
- * Returns void* because this object does not initialize the
- * memory. Use placement new for types that require a cons.
- */
- void* get() { return fStorage.get(); }
-private:
- GrAlignedSStorage<sizeof(T)*N> fStorage;
-};
-
-/**
- * saves value of T* in and restores in destructor
- * e.g.:
- * {
- * GrAutoTPtrValueRestore<int*> autoCountRestore;
- * if (useExtra) {
- * autoCountRestore.save(&fCount);
- * fCount += fExtraCount;
- * }
- * ...
- * } // fCount is restored
- */
-template <typename T> class GrAutoTPtrValueRestore : public GrNoncopyable {
-public:
- GrAutoTPtrValueRestore() : fPtr(NULL), fVal() {}
-
- GrAutoTPtrValueRestore(T* ptr) {
- fPtr = ptr;
- if (NULL != ptr) {
- fVal = *ptr;
- }
- }
-
- ~GrAutoTPtrValueRestore() {
- if (NULL != fPtr) {
- *fPtr = fVal;
- }
- }
-
- // restores previously saved value (if any) and saves value for passed T*
- void save(T* ptr) {
- if (NULL != fPtr) {
- *fPtr = fVal;
- }
- fPtr = ptr;
- fVal = *ptr;
- }
-private:
- T* fPtr;
- T fVal;
-};
-
-#endif
diff --git a/gpu/include/GrTesselatedPathRenderer.h b/gpu/include/GrTesselatedPathRenderer.h
deleted file mode 100644
index e37e66b..0000000
--- a/gpu/include/GrTesselatedPathRenderer.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#ifndef GrTesselatedPathRenderer_DEFINED
-#define GrTesselatedPathRenderer_DEFINED
-
-#include "GrPathRenderer.h"
-
-class GrTesselatedPathRenderer : public GrPathRenderer {
-public:
- GrTesselatedPathRenderer();
-
- virtual void drawPath(GrDrawTarget* target,
- GrDrawTarget::StageBitfield stages,
- const GrPath& path,
- GrPathFill fill,
- const GrPoint* translate);
- virtual bool canDrawPath(const GrDrawTarget* target,
- const GrPath& path,
- GrPathFill fill) const;
-
- virtual bool requiresStencilPass(const GrDrawTarget* target,
- const GrPath& path,
- GrPathFill fill) const { return false; }
- virtual void drawPathToStencil(GrDrawTarget* target,
- const GrPath& path,
- GrPathFill fill,
- const GrPoint* translate);
- virtual bool supportsAA(GrDrawTarget* target,
- const GrPath& path,
- GrPathFill fill);
-};
-
-#endif
diff --git a/gpu/include/GrTexture.h b/gpu/include/GrTexture.h
deleted file mode 100644
index 0e2f369..0000000
--- a/gpu/include/GrTexture.h
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrTexture_DEFINED
-#define GrTexture_DEFINED
-
-#include "GrRefCnt.h"
-#include "GrClip.h"
-#include "GrResource.h"
-
-class GrTexture;
-
-/**
- * GrRenderTarget represents a 2D buffer of pixels that can be rendered to.
- * A context's render target is set by setRenderTarget(). Render targets are
- * created by a createTexture with the kRenderTarget_TextureFlag flag.
- * Additionally, GrContext provides methods for creating GrRenderTargets
- * that wrap externally created render targets.
- */
-class GrRenderTarget : public GrResource {
-
-public:
- /**
- * @return the width of the rendertarget
- */
- int width() const { return fWidth; }
- /**
- * @return the height of the rendertarget
- */
- int height() const { return fHeight; }
-
- /**
- * @return the number of stencil bits in the rendertarget
- */
- int stencilBits() const { return fStencilBits; }
-
- /**
- * @return the texture associated with the rendertarget, may be NULL.
- */
- GrTexture* asTexture() {return fTexture;}
-
- /**
- * @return true if the render target is multisampled, false otherwise
- */
- bool isMultisampled() { return fIsMultisampled; }
-
- /**
- * Call to indicate the multisample contents were modified such that the
- * render target needs to be resolved before it can be used as texture. Gr
- * tracks this for its own drawing and thus this only needs to be called
- * when the render target has been modified outside of Gr. Only meaningful
- * for Gr-created RT/Textures and Platform RT/Textures created with the
- * kGrCanResolve flag.
- * @param rect a rect bounding the area needing resolve. NULL indicates
- * the whole RT needs resolving.
- */
- void flagAsNeedingResolve(const GrIRect* rect = NULL);
-
- /**
- * Call to override the region that needs to be resolved.
- */
- void overrideResolveRect(const GrIRect rect);
-
- /**
- * Call to indicate that GrRenderTarget was externally resolved. This may
- * allow Gr to skip a redundant resolve step.
- */
- void flagAsResolved() { fResolveRect.setLargestInverted(); }
-
- /**
- * @return true if the GrRenderTarget requires MSAA resolving
- */
- bool needsResolve() const { return !fResolveRect.isEmpty(); }
-
- /**
- * Returns a rect bounding the region needing resolving.
- */
- const GrIRect& getResolveRect() const { return fResolveRect; }
-
- /**
- * Reads a rectangle of pixels from the render target.
- * @param left left edge of the rectangle to read (inclusive)
- * @param top top edge of the rectangle to read (inclusive)
- * @param width width of rectangle to read in pixels.
- * @param height height of rectangle to read in pixels.
- * @param config the pixel config of the destination buffer
- * @param buffer memory to read the rectangle into.
- *
- * @return true if the read succeeded, false if not. The read can fail
- * because of a unsupported pixel config.
- */
- bool readPixels(int left, int top, int width, int height,
- GrPixelConfig config, void* buffer);
-
- // a MSAA RT may require explicit resolving , it may auto-resolve (e.g. FBO
- // 0 in GL), or be unresolvable because the client didn't give us the
- // resolve destination.
- enum ResolveType {
- kCanResolve_ResolveType,
- kAutoResolves_ResolveType,
- kCantResolve_ResolveType,
- };
- virtual ResolveType getResolveType() const = 0;
-
-protected:
- GrRenderTarget(GrGpu* gpu,
- GrTexture* texture,
- int width,
- int height,
- int stencilBits,
- bool isMultisampled)
- : INHERITED(gpu)
- , fTexture(texture)
- , fWidth(width)
- , fHeight(height)
- , fStencilBits(stencilBits)
- , fIsMultisampled(isMultisampled)
- {
- fResolveRect.setLargestInverted();
- }
-
- friend class GrTexture;
- // When a texture unrefs an owned rendertarget this func
- // removes the back pointer. This could be done called from
- // texture's destructor but would have to be done in derived
- // class. By the time of texture base destructor it has already
- // lost its pointer to the rt.
- void onTextureReleaseRenderTarget() {
- GrAssert(NULL != fTexture);
- fTexture = NULL;
- }
-
-private:
- GrTexture* fTexture; // not ref'ed
- int fWidth;
- int fHeight;
- int fStencilBits;
- bool fIsMultisampled;
- GrIRect fResolveRect;
-
- // GrGpu keeps a cached clip in the render target to avoid redundantly
- // rendering the clip into the same stencil buffer.
- friend class GrGpu;
- GrClip fLastStencilClip;
-
- typedef GrResource INHERITED;
-};
-
-class GrTexture : public GrResource {
-
-public:
- /**
- * Retrieves the width of the texture.
- *
- * @return the width in texels
- */
- int width() const { return fWidth; }
-
- /**
- * Retrieves the height of the texture.
- *
- * @return the height in texels
- */
- int height() const { return fHeight; }
-
- /**
- * Convert from texels to normalized texture coords for POT textures
- * only.
- */
- GrFixed normalizeFixedX(GrFixed x) const { GrAssert(GrIsPow2(fWidth));
- return x >> fShiftFixedX; }
- GrFixed normalizeFixedY(GrFixed y) const { GrAssert(GrIsPow2(fHeight));
- return y >> fShiftFixedY; }
-
- /**
- * Retrieves the pixel config specified when the texture was created.
- */
- GrPixelConfig config() const { return fConfig; }
-
- /**
- * Approximate number of bytes used by the texture
- */
- size_t sizeInBytes() const {
- return fWidth * fHeight * GrBytesPerPixel(fConfig);
- }
-
- /**
- * Updates a subrectangle of texels in the texture.
- *
- * @param x left edge of rectangle to update
- * @param y top edge of rectangle to update
- * @param width width of rectangle to update
- * @param height height of rectangle to update
- * @param srcData width*height texels of data in same format that was used
- * at texture creation.
- */
- virtual void uploadTextureData(uint32_t x,
- uint32_t y,
- uint32_t width,
- uint32_t height,
- const void* srcData) = 0;
-
- /**
- * Reads a rectangle of pixels from the texture.
- * @param left left edge of the rectangle to read (inclusive)
- * @param top top edge of the rectangle to read (inclusive)
- * @param width width of rectangle to read in pixels.
- * @param height height of rectangle to read in pixels.
- * @param config the pixel config of the destination buffer
- * @param buffer memory to read the rectangle into.
- *
- * @return true if the read succeeded, false if not. The read can fail
- * because of a unsupported pixel config.
- */
- bool readPixels(int left, int top, int width, int height,
- GrPixelConfig config, void* buffer);
-
- /**
- * Retrieves the render target underlying this texture that can be passed to
- * GrGpu::setRenderTarget().
- *
- * @return handle to render target or NULL if the texture is not a
- * render target
- */
- GrRenderTarget* asRenderTarget() { return fRenderTarget; }
-
- /**
- * Removes the reference on the associated GrRenderTarget held by this
- * texture. Afterwards asRenderTarget() will return NULL. The
- * GrRenderTarget survives the release if another ref is held on it.
- */
- void releaseRenderTarget() {
- if (NULL != fRenderTarget) {
- GrAssert(fRenderTarget->asTexture() == this);
- fRenderTarget->onTextureReleaseRenderTarget();
- fRenderTarget->unref();
- fRenderTarget = NULL;
- }
- }
-
- /**
- * Return the native ID or handle to the texture, depending on the
- * platform. e.g. on opengl, return the texture ID.
- */
- virtual intptr_t getTextureHandle() = 0;
-
-#if GR_DEBUG
- void validate() const {
- this->INHERITED::validate();
- }
-#else
- void validate() const {}
-#endif
-
-protected:
- GrRenderTarget* fRenderTarget; // texture refs its rt representation
- // base class cons sets to NULL
- // subclass cons can create and set
-
- GrTexture(GrGpu* gpu,
- int width,
- int height,
- GrPixelConfig config)
- : INHERITED(gpu)
- , fRenderTarget(NULL)
- , fWidth(width)
- , fHeight(height)
- , fConfig(config) {
- // only make sense if alloc size is pow2
- fShiftFixedX = 31 - Gr_clz(fWidth);
- fShiftFixedY = 31 - Gr_clz(fHeight);
- }
-
- // GrResource overrides
- virtual void onRelease() {
- releaseRenderTarget();
- }
-
- virtual void onAbandon() {
- if (NULL != fRenderTarget) {
- fRenderTarget->abandon();
- }
- }
-
-private:
- int fWidth;
- int fHeight;
- // these two shift a fixed-point value into normalized coordinates
- // for this texture if the texture is power of two sized.
- int fShiftFixedX;
- int fShiftFixedY;
-
- GrPixelConfig fConfig;
-
- typedef GrResource INHERITED;
-};
-
-#endif
-
diff --git a/gpu/include/GrTextureCache.h b/gpu/include/GrTextureCache.h
deleted file mode 100644
index 444ffea..0000000
--- a/gpu/include/GrTextureCache.h
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrTextureCache_DEFINED
-#define GrTextureCache_DEFINED
-
-#include "GrTypes.h"
-#include "GrTHashCache.h"
-
-class GrTexture;
-
-// return true if a<b, or false if b<a
-//
-#define RET_IF_LT_OR_GT(a, b) \
- do { \
- if ((a) < (b)) { \
- return true; \
- } \
- if ((b) < (a)) { \
- return false; \
- } \
- } while (0)
-
-/**
- * Helper class for GrTextureCache, the Key is used to identify src data for
- * a texture. It is identified by 2 32bit data fields which can hold any
- * data (uninterpreted by the cache) and a width/height.
- */
-class GrTextureKey {
-public:
- enum {
- kHashBits = 7,
- kHashCount = 1 << kHashBits,
- kHashMask = kHashCount - 1
- };
-
- GrTextureKey(uint32_t p0, uint32_t p1, uint16_t width, uint16_t height) {
- fP0 = p0;
- fP1 = p1;
- fP2 = width | (height << 16);
- GR_DEBUGCODE(fHashIndex = -1);
- }
-
- GrTextureKey(const GrTextureKey& src) {
- fP0 = src.fP0;
- fP1 = src.fP1;
- fP2 = src.fP2;
- finalize(src.fPrivateBits);
- }
-
- //!< returns hash value [0..kHashMask] for the key
- int hashIndex() const { return fHashIndex; }
-
- friend bool operator==(const GrTextureKey& a, const GrTextureKey& b) {
- GR_DEBUGASSERT(-1 != a.fHashIndex && -1 != b.fHashIndex);
- return a.fP0 == b.fP0 && a.fP1 == b.fP1 && a.fP2 == b.fP2 &&
- a.fPrivateBits == b.fPrivateBits;
- }
-
- friend bool operator!=(const GrTextureKey& a, const GrTextureKey& b) {
- GR_DEBUGASSERT(-1 != a.fHashIndex && -1 != b.fHashIndex);
- return !(a == b);
- }
-
- friend bool operator<(const GrTextureKey& a, const GrTextureKey& b) {
- RET_IF_LT_OR_GT(a.fP0, b.fP0);
- RET_IF_LT_OR_GT(a.fP1, b.fP1);
- RET_IF_LT_OR_GT(a.fP2, b.fP2);
- return a.fPrivateBits < b.fPrivateBits;
- }
-
-private:
- void finalize(uint32_t privateBits) {
- fPrivateBits = privateBits;
- this->computeHashIndex();
- }
-
- uint16_t width() const { return fP2 & 0xffff; }
- uint16_t height() const { return (fP2 >> 16); }
-
- uint32_t getPrivateBits() const { return fPrivateBits; }
-
- static uint32_t rol(uint32_t x) {
- return (x >> 24) | (x << 8);
- }
- static uint32_t ror(uint32_t x) {
- return (x >> 8) | (x << 24);
- }
- static uint32_t rohalf(uint32_t x) {
- return (x >> 16) | (x << 16);
- }
-
- void computeHashIndex() {
- uint32_t hash = fP0 ^ rol(fP1) ^ ror(fP2) ^ rohalf(fPrivateBits);
- // this way to mix and reduce hash to its index may have to change
- // depending on how many bits we allocate to the index
- hash ^= hash >> 16;
- hash ^= hash >> 8;
- fHashIndex = hash & kHashMask;
- }
-
- uint32_t fP0;
- uint32_t fP1;
- uint32_t fP2;
- uint32_t fPrivateBits;
-
- // this is computed from the fP... fields
- int fHashIndex;
-
- friend class GrContext;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-class GrTextureEntry {
-public:
- GrTexture* texture() const { return fTexture; }
- const GrTextureKey& key() const { return fKey; }
-
-#if GR_DEBUG
- GrTextureEntry* next() const { return fNext; }
- GrTextureEntry* prev() const { return fPrev; }
-#endif
-
-#if GR_DEBUG
- void validate() const;
-#else
- void validate() const {}
-#endif
-
-private:
- GrTextureEntry(const GrTextureKey& key, GrTexture* texture);
- ~GrTextureEntry();
-
- bool isLocked() const { return fLockCount != 0; }
- void lock() { ++fLockCount; }
- void unlock() {
- GrAssert(fLockCount > 0);
- --fLockCount;
- }
-
- GrTextureKey fKey;
- GrTexture* fTexture;
-
- // track if we're in use, used when we need to purge
- // we only purge unlocked entries
- int fLockCount;
-
- // we're a dlinklist
- GrTextureEntry* fPrev;
- GrTextureEntry* fNext;
-
- friend class GrTextureCache;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-#include "GrTHashCache.h"
-
-/**
- * Cache of GrTexture objects.
- *
- * These have a corresponding GrTextureKey, built from 96bits identifying the
- * texture/bitmap.
- *
- * The cache stores the entries in a double-linked list, which is its LRU.
- * When an entry is "locked" (i.e. given to the caller), it is moved to the
- * head of the list. If/when we must purge some of the entries, we walk the
- * list backwards from the tail, since those are the least recently used.
- *
- * For fast searches, we maintain a sorted array (based on the GrTextureKey)
- * which we can bsearch. When a new entry is added, it is inserted into this
- * array.
- *
- * For even faster searches, a hash is computed from the Key. If there is
- * a collision between two keys with the same hash, we fall back on the
- * bsearch, and update the hash to reflect the most recent Key requested.
- */
-class GrTextureCache {
-public:
- GrTextureCache(int maxCount, size_t maxBytes);
- ~GrTextureCache();
-
- /**
- * Return the current texture cache limits.
- *
- * @param maxTextures If non-null, returns maximum number of textures that
- * can be held in the cache.
- * @param maxTextureBytes If non-null, returns maximum number of bytes of
- * texture memory that can be held in the cache.
- */
- void getLimits(int* maxTextures, size_t* maxTextureBytes) const;
-
- /**
- * Specify the texture cache limits. If the current cache exceeds either
- * of these, it will be purged (LRU) to keep the cache within these limits.
- *
- * @param maxTextures The maximum number of textures that can be held in
- * the cache.
- * @param maxTextureBytes The maximum number of bytes of texture memory
- * that can be held in the cache.
- */
- void setLimits(int maxTextures, size_t maxTextureBytes);
-
- /**
- * Search for an entry with the same Key. If found, "lock" it and return it.
- * If not found, return null.
- */
- GrTextureEntry* findAndLock(const GrTextureKey&);
-
- /**
- * Create a new entry, based on the specified key and texture, and return
- * its "locked" entry.
- *
- * Ownership of the texture is transferred to the Entry, which will unref()
- * it when we are purged or deleted.
- */
- GrTextureEntry* createAndLock(const GrTextureKey&, GrTexture*);
-
- /**
- * Detach removes an entry from the cache. This prevents the entry from
- * being found by a subsequent findAndLock() until it is reattached. The
- * entry still counts against the cache's budget and should be reattached
- * when exclusive access is no longer needed.
- */
- void detach(GrTextureEntry*);
-
- /**
- * Reattaches a texture to the cache and unlocks it. Allows it to be found
- * by a subsequent findAndLock or be purged (provided its lock count is
- * now 0.)
- */
- void reattachAndUnlock(GrTextureEntry*);
-
- /**
- * When done with an entry, call unlock(entry) on it, which returns it to
- * a purgable state.
- */
- void unlock(GrTextureEntry*);
-
- void removeAll();
-
-#if GR_DEBUG
- void validate() const;
-#else
- void validate() const {}
-#endif
-
-private:
- void internalDetach(GrTextureEntry*, bool);
- void attachToHead(GrTextureEntry*, bool);
- void purgeAsNeeded(); // uses kFreeTexture_DeleteMode
-
- class Key;
- GrTHashTable<GrTextureEntry, Key, 8> fCache;
-
- // manage the dlink list
- GrTextureEntry* fHead;
- GrTextureEntry* fTail;
-
- // our budget, used in purgeAsNeeded()
- int fMaxCount;
- size_t fMaxBytes;
-
- // our current stats, related to our budget
- int fEntryCount;
- size_t fEntryBytes;
- int fClientDetachedCount;
- size_t fClientDetachedBytes;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-#if GR_DEBUG
- class GrAutoTextureCacheValidate {
- public:
- GrAutoTextureCacheValidate(GrTextureCache* cache) : fCache(cache) {
- cache->validate();
- }
- ~GrAutoTextureCacheValidate() {
- fCache->validate();
- }
- private:
- GrTextureCache* fCache;
- };
-#else
- class GrAutoTextureCacheValidate {
- public:
- GrAutoTextureCacheValidate(GrTextureCache*) {}
- };
-#endif
-
-#endif
-
diff --git a/gpu/include/GrTouchGesture.h b/gpu/include/GrTouchGesture.h
deleted file mode 100644
index 03f970b..0000000
--- a/gpu/include/GrTouchGesture.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef GrTouchGesture_DEFINED
-#define GrTouchGesture_DEFINED
-
-#include "GrTypes.h"
-#include "SkTDArray.h"
-#include "SkMatrix.h"
-
-#include "FlingState.h"
-
-class GrTouchGesture {
-public:
- GrTouchGesture();
- ~GrTouchGesture();
-
- void touchBegin(void* owner, float x, float y);
- void touchMoved(void* owner, float x, float y);
- void touchEnd(void* owner);
- void reset();
-
- const SkMatrix& localM();
- const SkMatrix& globalM() const { return fGlobalM; }
-
-private:
- enum State {
- kEmpty_State,
- kTranslate_State,
- kZoom_State,
- };
-
- struct Rec {
- void* fOwner;
- float fStartX, fStartY;
- float fPrevX, fPrevY;
- float fLastX, fLastY;
- SkMSec fPrevT, fLastT;
- };
- SkTDArray<Rec> fTouches;
-
- State fState;
- SkMatrix fLocalM, fGlobalM;
- FlingState fFlinger;
- SkMSec fLastUpT;
- SkPoint fLastUpP;
-
-
- void flushLocalM();
- int findRec(void* owner) const;
- void appendNewRec(void* owner, float x, float y);
- float computePinch(const Rec&, const Rec&);
- float limitTotalZoom(float scale) const;
- bool handleDblTap(float, float);
-};
-
-#endif
-
-
diff --git a/gpu/include/GrVertexBuffer.h b/gpu/include/GrVertexBuffer.h
deleted file mode 100644
index 34abe2c..0000000
--- a/gpu/include/GrVertexBuffer.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrVertexBuffer_DEFINED
-#define GrVertexBuffer_DEFINED
-
-#include "GrGeometryBuffer.h"
-
-class GrVertexBuffer : public GrGeometryBuffer {
-protected:
- GrVertexBuffer(GrGpu* gpu, size_t sizeInBytes, bool dynamic)
- : INHERITED(gpu, sizeInBytes, dynamic) {}
-private:
- typedef GrGeometryBuffer INHERITED;
-};
-
-#endif
diff --git a/gpu/include/SkUIView.h b/gpu/include/SkUIView.h
deleted file mode 100644
index 5e12e00..0000000
--- a/gpu/include/SkUIView.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#import <UIKit/UIKit.h>
-
-#include "SkMatrix.h"
-#include "FlingState.h"
-
-#import <OpenGLES/EAGL.h>
-#import <OpenGLES/ES1/gl.h>
-#import <OpenGLES/ES1/glext.h>
-
-class SkOSWindow;
-class SkEvent;
-
-@interface SkUIView : UIView <UIAccelerometerDelegate> {
- BOOL fRedrawRequestPending;
- SkOSWindow* fWind;
- SkMatrix fMatrix, fLocalMatrix;
- bool fNeedGestureEnded;
-
- SkMatrix fRotateMatrix;
-
- float fFirstPinchX, fFirstPinchY;
- bool fNeedFirstPinch;
-
- float fZoomAroundX, fZoomAroundY;
- bool fZoomAround;
-
- FlingState fFlingState;
-
- GrAnimateFloat fWarpState;
- bool fUseWarp;
-
- struct {
- EAGLContext* fContext;
- GLuint fRenderbuffer;
- GLuint fStencilbuffer;
- GLuint fFramebuffer;
- GLint fWidth;
- GLint fHeight;
- } fGL;
-
- UILabel* fTitleLabel;
-
- enum Backend {
- kGL_Backend,
- kRaster_Backend,
- };
-
- // these are visible to DetailViewController
- Backend fBackend;
- bool fComplexClip;
-}
-
-@property (nonatomic, assign) SkOSWindow *fWind;
-@property (nonatomic, retain) UILabel* fTitleLabel;
-@property (nonatomic, assign) Backend fBackend;
-@property (nonatomic, assign) bool fComplexClip;
-@property (nonatomic, assign, setter=setWarpState) bool fUseWarp;
-
-- (void)setSkTitle:(const char*)title;
-- (void)postInvalWithRect:(const SkIRect*)rectOrNil;
-- (BOOL)onHandleEvent:(const SkEvent&)event;
-
-@end
-
diff --git a/gpu/src/GrBinHashKey.h b/gpu/src/GrBinHashKey.h
deleted file mode 100644
index 565b460..0000000
--- a/gpu/src/GrBinHashKey.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#ifndef GrBinHashKey_DEFINED
-#define GrBinHashKey_DEFINED
-
-#include "GrTypes.h"
-
-/**
- * Abstract base class that presents the building interface of GrBinHashKey.
- * This base class allows builder methods to not know the exact template
- * parameters of GrBinHashKey
- */
-class GrBinHashKeyBuilder {
-public:
- GrBinHashKeyBuilder() {}
- virtual ~GrBinHashKeyBuilder() {}
- virtual void keyData(const uint32_t *dataToAdd, size_t len) = 0;
-};
-
-/**
- * Hash function class than can take a data stream of indeterminate length.
- * It also has the ability to recieve data in several chunks (steamed). The
- * hash function used is the One-at-a-Time Hash
- * (http://burtleburtle.net/bob/hash/doobs.html).
- *
- * Keys are built in two passes the first pass builds the key until the
- * allocated storage for the key runs out, raw data accumulation stops, but
- * the calculation of the 32-bit hash value and total key length continue.
- * The second pass is only necessary if storage ran-out during the first pass.
- * If that is the case, the heap storage portion of the key will be
- * re-allocated so that the entire key can be stored in the second pass.
- *
- * Code for building a key:
- *
- * GrBinHashKey<MyEntryStruct, MyStackSize> MyKey;
- * while( MyKey->doPass() )
- * {
- * MyObject->buildKey(&MyKey); //invoke a builder method
- * }
- *
- * All the builder method needs to do is make calls to the keyData method to
- * append binary data to the key.
- */
-template<typename Entry, size_t StackSize>
-class GrBinHashKey : public GrBinHashKeyBuilder {
-public:
- GrBinHashKey()
- : fA(0)
- , fLength(0)
- , fHeapData(NULL)
- , fPhysicalSize(StackSize)
- , fUseHeap(false)
- , fPass(0)
-#if GR_DEBUG
- , fIsValid(true)
-#endif
- {}
-
-private:
- // Illegal: must choose explicitly between copyAndTakeOwnership
- // and deepCopyFrom.
- // Not inheriting GrNoncopyable, because it causes very obscure compiler
- // errors with template classes, which are hard to trace back to the use
- // of assignment.
- GrBinHashKey(const GrBinHashKey<Entry, StackSize>&) {}
- GrBinHashKey<Entry, StackSize>& operator=(const GrBinHashKey<Entry,
- StackSize>&) {
- return this;
- }
-
-public:
- void copyAndTakeOwnership(GrBinHashKey<Entry, StackSize>& key) {
- GrAssert(key.fIsValid);
- copyFields(key);
- if (fUseHeap) {
- key.fHeapData = NULL; // ownership transfer
- }
- // Consistency Checking
- // To avoid the overhead of copying or ref-counting the dynamically
- // allocated portion of the key, we use ownership transfer
- // Key usability is only tracked in debug builds.
- GR_DEBUGCODE(key.fIsValid = false;)
- }
-
- void deepCopyFrom(const GrBinHashKey<Entry, StackSize>& key) {
- GrAssert(key.fIsValid);
- copyFields(key);
- if (fUseHeap) {
- fHeapData = reinterpret_cast<uint8_t*>(
- GrMalloc(sizeof(uint8_t) * fPhysicalSize));
- memcpy(fHeapData, key.fHeapData, fLength);
- }
- }
-
- virtual ~GrBinHashKey() {
- if (fUseHeap) {
- GrFree(fHeapData);
- }
- }
-
- bool doPass() {
- GrAssert(fIsValid);
- if (0 == fPass) {
- fPass++;
- return true;
- }
- if (1 == fPass) {
- bool passNeeded = false;
- if (fLength > fPhysicalSize) {
- // If the first pass ran out of space the we need to
- // re-allocate and perform a second pass
- GrFree(fHeapData);
- fHeapData = reinterpret_cast<uint8_t*>(
- GrMalloc(sizeof(uint8_t) * fLength));
- fPhysicalSize = fLength;
- fUseHeap = true;
- passNeeded = true;
- fLength = 0;
- }
- fPass++;
- return passNeeded;
- }
- return false;
- }
-
- void keyData(const uint32_t *dataToAdd, size_t len) {
- GrAssert(fIsValid);
- GrAssert(fPass);
- GrAssert(GrIsALIGN4(len));
- if (fUseHeap) {
- GrAssert(fHeapData);
- GrAssert(fLength + len <= fPhysicalSize);
- memcpy(&fHeapData[fLength], dataToAdd, len );
- } else {
- if (fLength + len <= StackSize) {
- memcpy(&fStackData[fLength], dataToAdd, len);
- } else {
- GrAssert(1 == fPass);
- }
- }
-
- fLength += len;
-
- if (1 == fPass) {
- uint32_t a = fA;
- while (len >= 4) {
- a += *dataToAdd++;
- a += (a << 10);
- a ^= (a >> 6);
- len -= 4;
- }
- a += (a << 3);
- a ^= (a >> 11);
- a += (a << 15);
-
- fA = a;
- }
- }
-
- int compare(const GrBinHashKey<Entry, StackSize>& key) const {
- GrAssert(fIsValid);
- if (fLength == key.fLength) {
- GrAssert(fUseHeap == key.fUseHeap);
- if(fUseHeap) {
- return memcmp(fHeapData, key.fHeapData, fLength);
- } else {
- return memcmp(fStackData, key.fStackData, fLength);
- }
- }
-
- return (fLength - key.fLength);
- }
-
- static bool
- EQ(const Entry& entry, const GrBinHashKey<Entry, StackSize>& key) {
- GrAssert(key.fIsValid);
- return 0 == entry.compare(key);
- }
-
- static bool
- LT(const Entry& entry, const GrBinHashKey<Entry, StackSize>& key) {
- GrAssert(key.fIsValid);
- return entry.compare(key) < 0;
- }
-
- uint32_t getHash() const {
- GrAssert(fIsValid);
- return fA;
- }
-
-private:
- void copyFields(const GrBinHashKey<Entry, StackSize>& src) {
- if (fUseHeap) {
- GrFree(fHeapData);
- }
- // We do a field-by-field copy because this is a non-POD
- // class, and therefore memcpy would be bad
- fA = src.fA;
- fLength = src.fLength;
- memcpy(fStackData, src.fStackData, StackSize);
- fHeapData = src.fHeapData;
- fPhysicalSize = src.fPhysicalSize;
- fUseHeap = src.fUseHeap;
- fPass = src.fPass;
- }
-
- uint32_t fA;
-
- // For accumulating the variable length binary key
- size_t fLength; // length of data accumulated so far
- uint8_t fStackData[StackSize]; //Buffer for key storage
- uint8_t* fHeapData; //Dynamically allocated extended key storage
- size_t fPhysicalSize; //Total size available for key storage
- bool fUseHeap; //Using a dynamically allocated key storage
- int fPass; //Key generation pass counter
-
-#if GR_DEBUG
-public:
- bool fIsValid;
-#endif
-};
-
-#endif
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
deleted file mode 100644
index 4ebf225..0000000
--- a/gpu/src/GrContext.cpp
+++ /dev/null
@@ -1,1525 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "GrContext.h"
-#include "GrGpu.h"
-#include "GrTextureCache.h"
-#include "GrTextStrike.h"
-#include "GrMemory.h"
-#include "GrClipIterator.h"
-#include "GrIndexBuffer.h"
-#include "GrInOrderDrawBuffer.h"
-#include "GrBufferAllocPool.h"
-#include "GrPathRenderer.h"
-
-// larger than this, and we don't AA. set to 0 for no AA
-#ifndef GR_MAX_OFFSCREEN_AA_DIM
- #define GR_MAX_OFFSCREEN_AA_DIM 0
-#endif
-
-#define DEFER_TEXT_RENDERING 1
-
-#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
-
-static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
-static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
-
-static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
-static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
-
-// We are currently only batching Text and drawRectToRect, both
-// of which use the quad index buffer.
-static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
-static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
-
-GrContext* GrContext::Create(GrEngine engine,
- GrPlatform3DContext context3D) {
- GrContext* ctx = NULL;
- GrGpu* fGpu = GrGpu::Create(engine, context3D);
- if (NULL != fGpu) {
- ctx = new GrContext(fGpu);
- fGpu->unref();
- }
- return ctx;
-}
-
-GrContext* GrContext::CreateGLShaderContext() {
- return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
-}
-
-GrContext::~GrContext() {
- this->flush();
- delete fTextureCache;
- delete fFontCache;
- delete fDrawBuffer;
- delete fDrawBufferVBAllocPool;
- delete fDrawBufferIBAllocPool;
- GrSafeUnref(fCustomPathRenderer);
- GrSafeUnref(fAAFillRectIndexBuffer);
- GrSafeUnref(fAAStrokeRectIndexBuffer);
- fGpu->unref();
-}
-
-void GrContext::contextLost() {
- contextDestroyed();
- this->setupDrawBuffer();
-}
-
-void GrContext::contextDestroyed() {
- // abandon first to so destructors
- // don't try to free the resources in the API.
- fGpu->abandonResources();
-
- delete fDrawBuffer;
- fDrawBuffer = NULL;
-
- delete fDrawBufferVBAllocPool;
- fDrawBufferVBAllocPool = NULL;
-
- delete fDrawBufferIBAllocPool;
- fDrawBufferIBAllocPool = NULL;
-
- GrSafeSetNull(fAAFillRectIndexBuffer);
- GrSafeSetNull(fAAStrokeRectIndexBuffer);
-
- fTextureCache->removeAll();
- fFontCache->freeAll();
- fGpu->markContextDirty();
-}
-
-void GrContext::resetContext() {
- fGpu->markContextDirty();
-}
-
-void GrContext::freeGpuResources() {
- this->flush();
- fTextureCache->removeAll();
- fFontCache->freeAll();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-int GrContext::PaintStageVertexLayoutBits(
- const GrPaint& paint,
- const bool hasTexCoords[GrPaint::kTotalStages]) {
- int stageMask = paint.getActiveStageMask();
- int layout = 0;
- for (int i = 0; i < GrPaint::kTotalStages; ++i) {
- if ((1 << i) & stageMask) {
- if (NULL != hasTexCoords && hasTexCoords[i]) {
- layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
- } else {
- layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
- }
- }
- }
- return layout;
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
-
-enum {
- kNPOTBit = 0x1,
- kFilterBit = 0x2,
- kKeylessBit = 0x4,
-};
-
-bool GrContext::finalizeTextureKey(GrTextureKey* key,
- const GrSamplerState& sampler,
- bool keyless) const {
- uint32_t bits = 0;
- uint16_t width = key->width();
- uint16_t height = key->height();
-
- if (!fGpu->npotTextureTileSupport()) {
- bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
-
- bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
- (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
-
- if (tiled && !isPow2) {
- bits |= kNPOTBit;
- if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
- bits |= kFilterBit;
- }
- }
- }
-
- if (keyless) {
- bits |= kKeylessBit;
- }
- key->finalize(bits);
- return 0 != bits;
-}
-
-GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
- const GrSamplerState& sampler) {
- finalizeTextureKey(key, sampler, false);
- return fTextureCache->findAndLock(*key);
-}
-
-static void stretchImage(void* dst,
- int dstW,
- int dstH,
- void* src,
- int srcW,
- int srcH,
- int bpp) {
- GrFixed dx = (srcW << 16) / dstW;
- GrFixed dy = (srcH << 16) / dstH;
-
- GrFixed y = dy >> 1;
-
- int dstXLimit = dstW*bpp;
- for (int j = 0; j < dstH; ++j) {
- GrFixed x = dx >> 1;
- void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
- void* dstRow = (uint8_t*)dst + j*dstW*bpp;
- for (int i = 0; i < dstXLimit; i += bpp) {
- memcpy((uint8_t*) dstRow + i,
- (uint8_t*) srcRow + (x>>16)*bpp,
- bpp);
- x += dx;
- }
- y += dy;
- }
-}
-
-GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
- const GrSamplerState& sampler,
- const GrTextureDesc& desc,
- void* srcData, size_t rowBytes) {
- GrAssert(key->width() == desc.fWidth);
- GrAssert(key->height() == desc.fHeight);
-
-#if GR_DUMP_TEXTURE_UPLOAD
- GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
-#endif
-
- GrTextureEntry* entry = NULL;
- bool special = finalizeTextureKey(key, sampler, false);
- if (special) {
- GrTextureEntry* clampEntry;
- GrTextureKey clampKey(*key);
- clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
-
- if (NULL == clampEntry) {
- clampEntry = createAndLockTexture(&clampKey,
- GrSamplerState::ClampNoFilter(),
- desc, srcData, rowBytes);
- GrAssert(NULL != clampEntry);
- if (NULL == clampEntry) {
- return NULL;
- }
- }
- GrTextureDesc rtDesc = desc;
- rtDesc.fFlags = rtDesc.fFlags |
- kRenderTarget_GrTextureFlagBit |
- kNoStencil_GrTextureFlagBit;
- rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
- fGpu->minRenderTargetWidth()));
- rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
- fGpu->minRenderTargetHeight()));
-
- GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
-
- if (NULL != texture) {
- GrDrawTarget::AutoStateRestore asr(fGpu);
- fGpu->setRenderTarget(texture->asRenderTarget());
- fGpu->setTexture(0, clampEntry->texture());
- fGpu->disableStencil();
- fGpu->setViewMatrix(GrMatrix::I());
- fGpu->setAlpha(0xff);
- fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
- fGpu->disableState(GrDrawTarget::kDither_StateBit |
- GrDrawTarget::kClip_StateBit |
- GrDrawTarget::kAntialias_StateBit);
- GrSamplerState::Filter filter;
- // if filtering is not desired then we want to ensure all
- // texels in the resampled image are copies of texels from
- // the original.
- if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
- filter = GrSamplerState::kNearest_Filter;
- } else {
- filter = GrSamplerState::kBilinear_Filter;
- }
- GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
- GrSamplerState::kClamp_WrapMode,
- filter);
- fGpu->setSamplerState(0, stretchSampler);
-
- static const GrVertexLayout layout =
- GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
- GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
-
- if (arg.succeeded()) {
- GrPoint* verts = (GrPoint*) arg.vertices();
- verts[0].setIRectFan(0, 0,
- texture->width(),
- texture->height(),
- 2*sizeof(GrPoint));
- verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
- fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
- 0, 4);
- entry = fTextureCache->createAndLock(*key, texture);
- }
- texture->releaseRenderTarget();
- } else {
- // TODO: Our CPU stretch doesn't filter. But we create separate
- // stretched textures when the sampler state is either filtered or
- // not. Either implement filtered stretch blit on CPU or just create
- // one when FBO case fails.
-
- rtDesc.fFlags = kNone_GrTextureFlags;
- // no longer need to clamp at min RT size.
- rtDesc.fWidth = GrNextPow2(desc.fWidth);
- rtDesc.fHeight = GrNextPow2(desc.fHeight);
- int bpp = GrBytesPerPixel(desc.fFormat);
- GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
- rtDesc.fWidth *
- rtDesc.fHeight);
- stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
- srcData, desc.fWidth, desc.fHeight, bpp);
-
- size_t stretchedRowBytes = rtDesc.fWidth * bpp;
-
- GrTexture* texture = fGpu->createTexture(rtDesc,
- stretchedPixels.get(),
- stretchedRowBytes);
- GrAssert(NULL != texture);
- entry = fTextureCache->createAndLock(*key, texture);
- }
- fTextureCache->unlock(clampEntry);
-
- } else {
- GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
- if (NULL != texture) {
- entry = fTextureCache->createAndLock(*key, texture);
- } else {
- entry = NULL;
- }
- }
- return entry;
-}
-
-GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) {
- uint32_t p0 = desc.fFormat;
- uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
- GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
- this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
-
- GrTextureEntry* entry = fTextureCache->findAndLock(key);
- if (NULL == entry) {
- GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
- if (NULL != texture) {
- entry = fTextureCache->createAndLock(key, texture);
- }
- }
- // If the caller gives us the same desc/sampler twice we don't want
- // to return the same texture the second time (unless it was previously
- // released). So we detach the entry from the cache and reattach at release.
- if (NULL != entry) {
- fTextureCache->detach(entry);
- }
- return entry;
-}
-
-void GrContext::unlockTexture(GrTextureEntry* entry) {
- if (kKeylessBit & entry->key().getPrivateBits()) {
- fTextureCache->reattachAndUnlock(entry);
- } else {
- fTextureCache->unlock(entry);
- }
-}
-
-GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
- void* srcData,
- size_t rowBytes) {
- return fGpu->createTexture(desc, srcData, rowBytes);
-}
-
-void GrContext::getTextureCacheLimits(int* maxTextures,
- size_t* maxTextureBytes) const {
- fTextureCache->getLimits(maxTextures, maxTextureBytes);
-}
-
-void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
- fTextureCache->setLimits(maxTextures, maxTextureBytes);
-}
-
-int GrContext::getMaxTextureDimension() {
- return fGpu->maxTextureDimension();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
- // validate flags here so that GrGpu subclasses don't have to check
- if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
- 0 != desc.fRenderTargetFlags) {
- return NULL;
- }
- if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
- (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
- return NULL;
- }
- if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
- (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
- !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
- return NULL;
- }
- return fGpu->createPlatformSurface(desc);
-}
-
-GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
- return fGpu->createRenderTargetFrom3DApiState();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
- int width, int height) {
- if (!fGpu->supports8BitPalette()) {
- return false;
- }
-
-
- bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
-
- if (!isPow2) {
- if (!fGpu->npotTextureSupport()) {
- return false;
- }
-
- bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
- sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
- if (tiled && !fGpu->npotTextureTileSupport()) {
- return false;
- }
- }
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
-
-void GrContext::setClip(const GrClip& clip) {
- fGpu->setClip(clip);
- fGpu->enableState(GrDrawTarget::kClip_StateBit);
-}
-
-void GrContext::setClip(const GrIRect& rect) {
- GrClip clip;
- clip.setFromIRect(rect);
- fGpu->setClip(clip);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-void GrContext::clear(const GrIRect* rect, const GrColor color) {
- this->flush();
- fGpu->clear(rect, color);
-}
-
-void GrContext::drawPaint(const GrPaint& paint) {
- // set rect to be big enough to fill the space, but not super-huge, so we
- // don't overflow fixed-point implementations
- GrRect r;
- r.setLTRB(0, 0,
- GrIntToScalar(getRenderTarget()->width()),
- GrIntToScalar(getRenderTarget()->height()));
- GrMatrix inverse;
- if (fGpu->getViewInverse(&inverse)) {
- inverse.mapRect(&r);
- } else {
- GrPrintf("---- fGpu->getViewInverse failed\n");
- }
- this->drawRect(paint, r);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-bool GrContext::doOffscreenAA(GrDrawTarget* target,
- const GrPaint& paint,
- bool isLines) const {
-#if GR_MAX_OFFSCREEN_AA_DIM==0
- return false;
-#else
- if (!paint.fAntiAlias) {
- return false;
- }
- if (isLines && fGpu->supportsAALines()) {
- return false;
- }
- if (target->getRenderTarget()->isMultisampled()) {
- return false;
- }
- // we have to be sure that the blend equation is expressible
- // as simple src / dst coeffecients when the source
- // is already modulated by the coverage fraction.
- // We could use dual-source blending to get the correct per-pixel
- // dst coeffecient for the remaining cases.
- if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
- kOne_BlendCoeff != paint.fDstBlendCoeff &&
- kISA_BlendCoeff != paint.fDstBlendCoeff) {
- return false;
- }
- return true;
-#endif
-}
-
-bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
- bool requireStencil,
- const GrIRect& boundRect,
- OffscreenRecord* record) {
- GrAssert(GR_MAX_OFFSCREEN_AA_DIM > 0);
-
- GrAssert(NULL == record->fEntry0);
- GrAssert(NULL == record->fEntry1);
-
- int boundW = boundRect.width();
- int boundH = boundRect.height();
- int size = GrMax(64, (int)GrNextPow2(GrMax(boundW, boundH)));
-
- GrTextureDesc desc;
- if (requireStencil) {
- desc.fFlags = kRenderTarget_GrTextureFlagBit;
- } else {
- desc.fFlags = kRenderTarget_GrTextureFlagBit |
- kNoStencil_GrTextureFlagBit;
- }
-
- desc.fFormat = kRGBA_8888_GrPixelConfig;
-
- int scale;
- // Using MSAA seems to be slower for some yet unknown reason.
- if (false && fGpu->supportsFullsceneAA()) {
- record->fDownsample = OffscreenRecord::kFSAA_Downsample;
- scale = GR_Scalar1;
- desc.fAALevel = kMed_GrAALevel;
- } else {
- record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
- OffscreenRecord::k4x4SinglePass_Downsample :
- OffscreenRecord::k4x4TwoPass_Downsample;
- scale = 4;
- desc.fAALevel = kNone_GrAALevel;
- }
-
- desc.fWidth = scale * size;
- desc.fHeight = scale * size;
-
- record->fEntry0 = this->lockKeylessTexture(desc);
-
- if (NULL == record->fEntry0) {
- return false;
- }
-
- if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
- desc.fWidth /= 2;
- desc.fHeight /= 2;
- record->fEntry1 = this->lockKeylessTexture(desc);
- if (NULL == record->fEntry1) {
- this->unlockTexture(record->fEntry0);
- record->fEntry0 = NULL;
- return false;
- }
- }
-
- GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
- GrAssert(NULL != offRT0);
-
- target->saveCurrentDrawState(&record->fSavedState);
-
- GrPaint tempPaint;
- tempPaint.reset();
- SetPaint(tempPaint, target);
- target->setRenderTarget(offRT0);
-
- GrMatrix transM;
- transM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
- target->postConcatViewMatrix(transM);
- GrMatrix scaleM;
- scaleM.setScale(scale * GR_Scalar1, scale * GR_Scalar1);
- target->postConcatViewMatrix(scaleM);
-
- // clip gets applied in second pass
- target->disableState(GrDrawTarget::kClip_StateBit);
-
- GrIRect clear = SkIRect::MakeWH(scale * boundW, scale * boundH);
- target->clear(&clear, 0x0);
-
- return true;
-}
-
-void GrContext::offscreenAAPass2(GrDrawTarget* target,
- const GrPaint& paint,
- const GrIRect& boundRect,
- OffscreenRecord* record) {
-
- GrAssert(NULL != record->fEntry0);
-
- GrSamplerState::Filter filter;
- if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
- filter = GrSamplerState::k4x4Downsample_Filter;
- } else {
- filter = GrSamplerState::kBilinear_Filter;
- }
-
- GrMatrix sampleM;
- GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
- GrSamplerState::kClamp_WrapMode, filter);
-
- GrTexture* src = record->fEntry0->texture();
- int scale;
-
- enum {
- kOffscreenStage = GrPaint::kTotalStages,
- };
-
- if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
- GrAssert(NULL != record->fEntry1);
- scale = 2;
- GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget();
-
- // Do 2x2 downsample from first to second
- target->setTexture(kOffscreenStage, src);
- target->setRenderTarget(dst);
- target->setViewMatrix(GrMatrix::I());
- sampleM.setScale(scale * GR_Scalar1 / src->width(),
- scale * GR_Scalar1 / src->height());
- sampler.setMatrix(sampleM);
- target->setSamplerState(kOffscreenStage, sampler);
- GrRect rect = SkRect::MakeWH(scale * boundRect.width(),
- scale * boundRect.height());
- target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
-
- src = record->fEntry1->texture();
- } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
- scale = 1;
- GrIRect rect = SkIRect::MakeWH(boundRect.width(), boundRect.height());
- src->asRenderTarget()->overrideResolveRect(rect);
- } else {
- GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
- record->fDownsample);
- scale = 4;
- }
-
- // setup for draw back to main RT
- int stageMask = paint.getActiveStageMask();
-
- target->restoreDrawState(record->fSavedState);
-
- if (stageMask) {
- GrMatrix invVM;
- if (target->getViewInverse(&invVM)) {
- target->preConcatSamplerMatrices(stageMask, invVM);
- }
- }
- target->setViewMatrix(GrMatrix::I());
-
- target->setTexture(kOffscreenStage, src);
- sampleM.setScale(scale * GR_Scalar1 / src->width(),
- scale * GR_Scalar1 / src->height());
- sampler.setMatrix(sampleM);
- sampleM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
- sampler.preConcatMatrix(sampleM);
- target->setSamplerState(kOffscreenStage, sampler);
-
- GrRect dstRect;
- int stages = (1 << kOffscreenStage) | stageMask;
- dstRect.set(boundRect);
- target->drawSimpleRect(dstRect, NULL, stages);
-
- this->unlockTexture(record->fEntry0);
- record->fEntry0 = NULL;
- if (NULL != record->fEntry1) {
- this->unlockTexture(record->fEntry1);
- record->fEntry1 = NULL;
- }
- target->restoreDrawState(record->fSavedState);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-/* create a triangle strip that strokes the specified triangle. There are 8
- unique vertices, but we repreat the last 2 to close up. Alternatively we
- could use an indices array, and then only send 8 verts, but not sure that
- would be faster.
- */
-static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
- GrScalar width) {
- const GrScalar rad = GrScalarHalf(width);
- rect.sort();
-
- verts[0].set(rect.fLeft + rad, rect.fTop + rad);
- verts[1].set(rect.fLeft - rad, rect.fTop - rad);
- verts[2].set(rect.fRight - rad, rect.fTop + rad);
- verts[3].set(rect.fRight + rad, rect.fTop - rad);
- verts[4].set(rect.fRight - rad, rect.fBottom - rad);
- verts[5].set(rect.fRight + rad, rect.fBottom + rad);
- verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
- verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
- verts[8] = verts[0];
- verts[9] = verts[1];
-}
-
-static GrColor getColorForMesh(const GrPaint& paint) {
- // FIXME: This was copied from SkGpuDevice, seems like
- // we should have already smeared a in caller if that
- // is what is desired.
- if (paint.hasTexture()) {
- unsigned a = GrColorUnpackA(paint.fColor);
- return GrColorPackRGBA(a, a, a, a);
- } else {
- return paint.fColor;
- }
-}
-
-static void setInsetFan(GrPoint* pts, size_t stride,
- const GrRect& r, GrScalar dx, GrScalar dy) {
- pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
-}
-
-static const uint16_t gFillAARectIdx[] = {
- 0, 1, 5, 5, 4, 0,
- 1, 2, 6, 6, 5, 1,
- 2, 3, 7, 7, 6, 2,
- 3, 0, 4, 4, 7, 3,
- 4, 5, 6, 6, 7, 4,
-};
-
-int GrContext::aaFillRectIndexCount() const {
- return GR_ARRAY_COUNT(gFillAARectIdx);
-}
-
-GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
- if (NULL == fAAFillRectIndexBuffer) {
- fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
- false);
- GrAssert(NULL != fAAFillRectIndexBuffer);
-#if GR_DEBUG
- bool updated =
-#endif
- fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
- sizeof(gFillAARectIdx));
- GR_DEBUGASSERT(updated);
- }
- return fAAFillRectIndexBuffer;
-}
-
-static const uint16_t gStrokeAARectIdx[] = {
- 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
- 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
- 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
- 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
-
- 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
- 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
- 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
- 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
-
- 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
- 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
- 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
- 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
-};
-
-int GrContext::aaStrokeRectIndexCount() const {
- return GR_ARRAY_COUNT(gStrokeAARectIdx);
-}
-
-GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
- if (NULL == fAAStrokeRectIndexBuffer) {
- fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
- false);
- GrAssert(NULL != fAAStrokeRectIndexBuffer);
-#if GR_DEBUG
- bool updated =
-#endif
- fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
- sizeof(gStrokeAARectIdx));
- GR_DEBUGASSERT(updated);
- }
- return fAAStrokeRectIndexBuffer;
-}
-
-void GrContext::fillAARect(GrDrawTarget* target,
- const GrPaint& paint,
- const GrRect& devRect) {
-
- GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
- GrDrawTarget::kColor_VertexLayoutBit;
-
- size_t vsize = GrDrawTarget::VertexSize(layout);
-
- GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
-
- intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
-
- GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
- GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
-
- setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
- setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
-
- verts += sizeof(GrPoint);
- for (int i = 0; i < 4; ++i) {
- *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
- }
-
- GrColor innerColor = getColorForMesh(paint);
- verts += 4 * vsize;
- for (int i = 0; i < 4; ++i) {
- *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
- }
-
- target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
-
- target->drawIndexed(kTriangles_PrimitiveType, 0,
- 0, 8, this->aaFillRectIndexCount());
-}
-
-void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
- const GrRect& devRect, const GrVec& devStrokeSize) {
- const GrScalar& dx = devStrokeSize.fX;
- const GrScalar& dy = devStrokeSize.fY;
- const GrScalar rx = GrMul(dx, GR_ScalarHalf);
- const GrScalar ry = GrMul(dy, GR_ScalarHalf);
-
- GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
- GrDrawTarget::kColor_VertexLayoutBit;
-
- GrScalar spare;
- {
- GrScalar w = devRect.width() - dx;
- GrScalar h = devRect.height() - dy;
- spare = GrMin(w, h);
- }
-
- if (spare <= 0) {
- GrRect r(devRect);
- r.inset(-rx, -ry);
- fillAARect(target, paint, r);
- return;
- }
-
- size_t vsize = GrDrawTarget::VertexSize(layout);
-
- GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
-
- intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
-
- GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
- GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
- GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
- GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
-
- setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
- setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
- setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
- setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
-
- verts += sizeof(GrPoint);
- for (int i = 0; i < 4; ++i) {
- *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
- }
-
- GrColor innerColor = getColorForMesh(paint);
- verts += 4 * vsize;
- for (int i = 0; i < 8; ++i) {
- *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
- }
-
- verts += 8 * vsize;
- for (int i = 0; i < 8; ++i) {
- *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
- }
-
- target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
- target->drawIndexed(kTriangles_PrimitiveType,
- 0, 0, 16, aaStrokeRectIndexCount());
-}
-
-/**
- * Returns true if the rects edges are integer-aligned.
- */
-static bool isIRect(const GrRect& r) {
- return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
- GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
-}
-
-static bool apply_aa_to_rect(GrDrawTarget* target,
- GrGpu* gpu,
- const GrPaint& paint,
- const GrRect& rect,
- GrScalar width,
- const GrMatrix* matrix,
- GrMatrix* combinedMatrix,
- GrRect* devRect) {
- // we use a simple alpha ramp to do aa on axis-aligned rects
- // do AA with alpha ramp if the caller requested AA, the rect
- // will be axis-aligned,the render target is not
- // multisampled, and the rect won't land on integer coords.
-
- if (!paint.fAntiAlias) {
- return false;
- }
-
- if (target->getRenderTarget()->isMultisampled()) {
- return false;
- }
-
- if (0 == width && gpu->supportsAALines()) {
- return false;
- }
-
- if (!target->getViewMatrix().preservesAxisAlignment()) {
- return false;
- }
-
- if (NULL != matrix &&
- !matrix->preservesAxisAlignment()) {
- return false;
- }
-
- *combinedMatrix = target->getViewMatrix();
- if (NULL != matrix) {
- combinedMatrix->preConcat(*matrix);
- GrAssert(combinedMatrix->preservesAxisAlignment());
- }
-
- combinedMatrix->mapRect(devRect, rect);
- devRect->sort();
-
- if (width < 0) {
- return !isIRect(*devRect);
- } else {
- return true;
- }
-}
-
-void GrContext::drawRect(const GrPaint& paint,
- const GrRect& rect,
- GrScalar width,
- const GrMatrix* matrix) {
-
-
- GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
- int stageMask = paint.getActiveStageMask();
-
- GrRect devRect = rect;
- GrMatrix combinedMatrix;
- bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
- &combinedMatrix, &devRect);
-
- if (doAA) {
- GrDrawTarget::AutoViewMatrixRestore avm(target);
- if (stageMask) {
- GrMatrix inv;
- if (combinedMatrix.invert(&inv)) {
- target->preConcatSamplerMatrices(stageMask, inv);
- }
- }
- target->setViewMatrix(GrMatrix::I());
- if (width >= 0) {
- GrVec strokeSize;;
- if (width > 0) {
- strokeSize.set(width, width);
- combinedMatrix.mapVectors(&strokeSize, 1);
- strokeSize.setAbs(strokeSize);
- } else {
- strokeSize.set(GR_Scalar1, GR_Scalar1);
- }
- strokeAARect(target, paint, devRect, strokeSize);
- } else {
- fillAARect(target, paint, devRect);
- }
- return;
- }
-
- if (width >= 0) {
- // TODO: consider making static vertex buffers for these cases.
- // Hairline could be done by just adding closing vertex to
- // unitSquareVertexBuffer()
- GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
-
- static const int worstCaseVertCount = 10;
- GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
-
- if (!geo.succeeded()) {
- return;
- }
-
- GrPrimitiveType primType;
- int vertCount;
- GrPoint* vertex = geo.positions();
-
- if (width > 0) {
- vertCount = 10;
- primType = kTriangleStrip_PrimitiveType;
- setStrokeRectStrip(vertex, rect, width);
- } else {
- // hairline
- vertCount = 5;
- primType = kLineStrip_PrimitiveType;
- vertex[0].set(rect.fLeft, rect.fTop);
- vertex[1].set(rect.fRight, rect.fTop);
- vertex[2].set(rect.fRight, rect.fBottom);
- vertex[3].set(rect.fLeft, rect.fBottom);
- vertex[4].set(rect.fLeft, rect.fTop);
- }
-
- GrDrawTarget::AutoViewMatrixRestore avmr;
- if (NULL != matrix) {
- avmr.set(target);
- target->preConcatViewMatrix(*matrix);
- target->preConcatSamplerMatrices(stageMask, *matrix);
- }
-
- target->drawNonIndexed(primType, 0, vertCount);
- } else {
- #if GR_STATIC_RECT_VB
- GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
-
- target->setVertexSourceToBuffer(layout,
- fGpu->getUnitSquareVertexBuffer());
- GrDrawTarget::AutoViewMatrixRestore avmr(target);
- GrMatrix m;
- m.setAll(rect.width(), 0, rect.fLeft,
- 0, rect.height(), rect.fTop,
- 0, 0, GrMatrix::I()[8]);
-
- if (NULL != matrix) {
- m.postConcat(*matrix);
- }
-
- target->preConcatViewMatrix(m);
- target->preConcatSamplerMatrices(stageMask, m);
-
- target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
- #else
- target->drawSimpleRect(rect, matrix, stageMask);
- #endif
- }
-}
-
-void GrContext::drawRectToRect(const GrPaint& paint,
- const GrRect& dstRect,
- const GrRect& srcRect,
- const GrMatrix* dstMatrix,
- const GrMatrix* srcMatrix) {
-
- // srcRect refers to paint's first texture
- if (NULL == paint.getTexture(0)) {
- drawRect(paint, dstRect, -1, dstMatrix);
- return;
- }
-
- GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
-
-#if GR_STATIC_RECT_VB
- GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
-
- GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
- GrDrawTarget::AutoViewMatrixRestore avmr(target);
-
- GrMatrix m;
-
- m.setAll(dstRect.width(), 0, dstRect.fLeft,
- 0, dstRect.height(), dstRect.fTop,
- 0, 0, GrMatrix::I()[8]);
- if (NULL != dstMatrix) {
- m.postConcat(*dstMatrix);
- }
- target->preConcatViewMatrix(m);
-
- // srcRect refers to first stage
- int otherStageMask = paint.getActiveStageMask() &
- (~(1 << GrPaint::kFirstTextureStage));
- if (otherStageMask) {
- target->preConcatSamplerMatrices(otherStageMask, m);
- }
-
- m.setAll(srcRect.width(), 0, srcRect.fLeft,
- 0, srcRect.height(), srcRect.fTop,
- 0, 0, GrMatrix::I()[8]);
- if (NULL != srcMatrix) {
- m.postConcat(*srcMatrix);
- }
- target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
-
- target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
- target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
-#else
-
- GrDrawTarget* target;
-#if BATCH_RECT_TO_RECT
- target = this->prepareToDraw(paint, kBuffered_DrawCategory);
-#else
- target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
-#endif
-
- const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
- const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
- srcRects[0] = &srcRect;
- srcMatrices[0] = srcMatrix;
-
- target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
-#endif
-}
-
-void GrContext::drawVertices(const GrPaint& paint,
- GrPrimitiveType primitiveType,
- int vertexCount,
- const GrPoint positions[],
- const GrPoint texCoords[],
- const GrColor colors[],
- const uint16_t indices[],
- int indexCount) {
-
- GrDrawTarget::AutoReleaseGeometry geo;
-
- GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
-
- bool hasTexCoords[GrPaint::kTotalStages] = {
- NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
- 0 // remaining stages use positions
- };
-
- GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
-
- if (NULL != colors) {
- layout |= GrDrawTarget::kColor_VertexLayoutBit;
- }
- int vertexSize = GrDrawTarget::VertexSize(layout);
-
- bool doAA = false;
- OffscreenRecord record;
- GrIRect bounds;
-
- if (sizeof(GrPoint) != vertexSize) {
- if (!geo.set(target, layout, vertexCount, 0)) {
- GrPrintf("Failed to get space for vertices!");
- return;
- }
- int texOffsets[GrDrawTarget::kMaxTexCoords];
- int colorOffset;
- GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
- texOffsets,
- &colorOffset);
- void* curVertex = geo.vertices();
-
- for (int i = 0; i < vertexCount; ++i) {
- *((GrPoint*)curVertex) = positions[i];
-
- if (texOffsets[0] > 0) {
- *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
- }
- if (colorOffset > 0) {
- *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
- }
- curVertex = (void*)((intptr_t)curVertex + vertexSize);
- }
- } else {
- // we don't do offscreen AA when we have per-vertex tex coords or colors
- if (this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) {
- GrRect b;
- b.setBounds(positions, vertexCount);
- target->getViewMatrix().mapRect(&b);
- b.roundOut(&bounds);
-
- if (this->setupOffscreenAAPass1(target, false, bounds, &record)) {
- doAA = true;
- }
- }
- target->setVertexSourceToArray(layout, positions, vertexCount);
- }
-
- if (NULL != indices) {
- target->setIndexSourceToArray(indices, indexCount);
- }
-
- if (NULL != indices) {
- target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
- } else {
- target->drawNonIndexed(primitiveType, 0, vertexCount);
- }
-
- if (doAA) {
- this->offscreenAAPass2(target, paint, bounds, &record);
- }
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-
-void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
- GrPathFill fill, const GrPoint* translate) {
-
- GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
- GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
-
- if (!IsFillInverted(fill) && // will be relaxed soon
- !pr->supportsAA(target, path, fill) &&
- this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
-
- OffscreenRecord record;
- bool needsStencil = pr->requiresStencilPass(target, path, fill);
-
- // compute bounds as intersection of rt size, clip, and path
- GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
- target->getRenderTarget()->height());
- if (target->getClip().hasConservativeBounds()) {
- GrIRect clipIBounds;
- target->getClip().getConservativeBounds().roundOut(&clipIBounds);
- if (!bound.intersect(clipIBounds)) {
- return;
- }
- }
-
- GrRect pathBounds = path.getBounds();
- GrIRect pathIBounds;
- if (!pathBounds.isEmpty()) {
- if (NULL != translate) {
- pathBounds.offset(*translate);
- }
- target->getViewMatrix().mapRect(&pathBounds, pathBounds);
- pathBounds.roundOut(&pathIBounds);
- if (!bound.intersect(pathIBounds)) {
- return;
- }
- }
-
- // for now, abort antialiasing if our bounds are too big, so we don't
- // hit the FBO size limit
- if (pathIBounds.width() > GR_MAX_OFFSCREEN_AA_DIM ||
- pathIBounds.height() > GR_MAX_OFFSCREEN_AA_DIM) {
- goto NO_AA;
- }
-
- if (this->setupOffscreenAAPass1(target, needsStencil, bound, &record)) {
- pr->drawPath(target, 0, path, fill, translate);
- this->offscreenAAPass2(target, paint, bound, &record);
- return;
- }
- }
-
-// we can fall out of the AA section for some reasons, and land here
-NO_AA:
- GrDrawTarget::StageBitfield enabledStages = paint.getActiveStageMask();
-
- pr->drawPath(target, enabledStages, path, fill, translate);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-void GrContext::flush(int flagsBitfield) {
- if (kDiscard_FlushBit & flagsBitfield) {
- fDrawBuffer->reset();
- } else {
- flushDrawBuffer();
- }
-
- if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
- fGpu->forceRenderTargetFlush();
- }
-}
-
-void GrContext::flushText() {
- if (kText_DrawCategory == fLastDrawCategory) {
- flushDrawBuffer();
- }
-}
-
-void GrContext::flushDrawBuffer() {
-#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
- if (fDrawBuffer) {
- fDrawBuffer->playback(fGpu);
- fDrawBuffer->reset();
- }
-#endif
-}
-
-bool GrContext::readTexturePixels(GrTexture* texture,
- int left, int top, int width, int height,
- GrPixelConfig config, void* buffer) {
-
- // TODO: code read pixels for textures that aren't rendertargets
-
- this->flush();
- GrRenderTarget* target = texture->asRenderTarget();
- if (NULL != target) {
- return fGpu->readPixels(target,
- left, top, width, height,
- config, buffer);
- } else {
- return false;
- }
-}
-
-bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
- int left, int top, int width, int height,
- GrPixelConfig config, void* buffer) {
- uint32_t flushFlags = 0;
- if (NULL == target) {
- flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
- }
-
- this->flush(flushFlags);
- return fGpu->readPixels(target,
- left, top, width, height,
- config, buffer);
-}
-
-void GrContext::writePixels(int left, int top, int width, int height,
- GrPixelConfig config, const void* buffer,
- size_t stride) {
-
- // TODO: when underlying api has a direct way to do this we should use it
- // (e.g. glDrawPixels on desktop GL).
-
- const GrTextureDesc desc = {
- kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
- };
- GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
- if (NULL == texture) {
- return;
- }
-
- this->flush(true);
-
- GrAutoUnref aur(texture);
- GrDrawTarget::AutoStateRestore asr(fGpu);
-
- GrMatrix matrix;
- matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
- fGpu->setViewMatrix(matrix);
-
- fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
- fGpu->disableState(GrDrawTarget::kClip_StateBit);
- fGpu->setAlpha(0xFF);
- fGpu->setBlendFunc(kOne_BlendCoeff,
- kZero_BlendCoeff);
- fGpu->setTexture(0, texture);
-
- GrSamplerState sampler;
- sampler.setClampNoFilter();
- matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
- sampler.setMatrix(matrix);
- fGpu->setSamplerState(0, sampler);
-
- GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
- static const int VCOUNT = 4;
-
- GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
- if (!geo.succeeded()) {
- return;
- }
- ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
- fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
-}
-////////////////////////////////////////////////////////////////////////////////
-
-void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
-
- for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
- int s = i + GrPaint::kFirstTextureStage;
- target->setTexture(s, paint.getTexture(i));
- target->setSamplerState(s, *paint.getTextureSampler(i));
- }
-
- target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
-
- for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
- int s = i + GrPaint::kFirstMaskStage;
- target->setTexture(s, paint.getMask(i));
- target->setSamplerState(s, *paint.getMaskSampler(i));
- }
-
- target->setColor(paint.fColor);
-
- if (paint.fDither) {
- target->enableState(GrDrawTarget::kDither_StateBit);
- } else {
- target->disableState(GrDrawTarget::kDither_StateBit);
- }
- if (paint.fAntiAlias) {
- target->enableState(GrDrawTarget::kAntialias_StateBit);
- } else {
- target->disableState(GrDrawTarget::kAntialias_StateBit);
- }
- target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
- target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
-}
-
-GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
- DrawCategory category) {
- if (category != fLastDrawCategory) {
- flushDrawBuffer();
- fLastDrawCategory = category;
- }
- SetPaint(paint, fGpu);
- GrDrawTarget* target = fGpu;
- switch (category) {
- case kText_DrawCategory:
-#if DEFER_TEXT_RENDERING
- target = fDrawBuffer;
- fDrawBuffer->initializeDrawStateAndClip(*fGpu);
-#else
- target = fGpu;
-#endif
- break;
- case kUnbuffered_DrawCategory:
- target = fGpu;
- break;
- case kBuffered_DrawCategory:
- target = fDrawBuffer;
- fDrawBuffer->initializeDrawStateAndClip(*fGpu);
- break;
- }
- return target;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-void GrContext::setRenderTarget(GrRenderTarget* target) {
- this->flush(false);
- fGpu->setRenderTarget(target);
-}
-
-GrRenderTarget* GrContext::getRenderTarget() {
- return fGpu->getRenderTarget();
-}
-
-const GrRenderTarget* GrContext::getRenderTarget() const {
- return fGpu->getRenderTarget();
-}
-
-const GrMatrix& GrContext::getMatrix() const {
- return fGpu->getViewMatrix();
-}
-
-void GrContext::setMatrix(const GrMatrix& m) {
- fGpu->setViewMatrix(m);
-}
-
-void GrContext::concatMatrix(const GrMatrix& m) const {
- fGpu->preConcatViewMatrix(m);
-}
-
-static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
- intptr_t mask = 1 << shift;
- if (pred) {
- bits |= mask;
- } else {
- bits &= ~mask;
- }
- return bits;
-}
-
-void GrContext::resetStats() {
- fGpu->resetStats();
-}
-
-const GrGpuStats& GrContext::getStats() const {
- return fGpu->getStats();
-}
-
-void GrContext::printStats() const {
- fGpu->printStats();
-}
-
-GrContext::GrContext(GrGpu* gpu) :
- fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
- gpu->supportsStencilWrapOps()) {
-
- fGpu = gpu;
- fGpu->ref();
- fGpu->setContext(this);
-
- fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
- fGpu->setClipPathRenderer(fCustomPathRenderer);
-
- fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
- MAX_TEXTURE_CACHE_BYTES);
- fFontCache = new GrFontCache(fGpu);
-
- fLastDrawCategory = kUnbuffered_DrawCategory;
-
- fDrawBuffer = NULL;
- fDrawBufferVBAllocPool = NULL;
- fDrawBufferIBAllocPool = NULL;
-
- fAAFillRectIndexBuffer = NULL;
- fAAStrokeRectIndexBuffer = NULL;
-
- this->setupDrawBuffer();
-}
-
-void GrContext::setupDrawBuffer() {
-
- GrAssert(NULL == fDrawBuffer);
- GrAssert(NULL == fDrawBufferVBAllocPool);
- GrAssert(NULL == fDrawBufferIBAllocPool);
-
-#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
- fDrawBufferVBAllocPool =
- new GrVertexBufferAllocPool(fGpu, false,
- DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
- DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
- fDrawBufferIBAllocPool =
- new GrIndexBufferAllocPool(fGpu, false,
- DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
- DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
-
- fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
- fDrawBufferIBAllocPool);
-#endif
-
-#if BATCH_RECT_TO_RECT
- fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
-#endif
-}
-
-GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
- GrDrawTarget* target;
-#if DEFER_TEXT_RENDERING
- target = prepareToDraw(paint, kText_DrawCategory);
-#else
- target = prepareToDraw(paint, kUnbuffered_DrawCategory);
-#endif
- SetPaint(paint, target);
- return target;
-}
-
-const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
- return fGpu->getQuadIndexBuffer();
-}
-
-GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
- const GrPath& path,
- GrPathFill fill) {
- if (NULL != fCustomPathRenderer &&
- fCustomPathRenderer->canDrawPath(target, path, fill)) {
- return fCustomPathRenderer;
- } else {
- GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
- return &fDefaultPathRenderer;
- }
-}
-
diff --git a/gpu/src/GrCreatePathRenderer_none.cpp b/gpu/src/GrCreatePathRenderer_none.cpp
deleted file mode 100644
index fafecff..0000000
--- a/gpu/src/GrCreatePathRenderer_none.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "GrPathRenderer.h"
-
-
-GrPathRenderer* GrPathRenderer::CreatePathRenderer() { return NULL; }
diff --git a/gpu/src/GrCreatePathRenderer_tesselated.cpp b/gpu/src/GrCreatePathRenderer_tesselated.cpp
deleted file mode 100644
index b00cf35..0000000
--- a/gpu/src/GrCreatePathRenderer_tesselated.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "GrTesselatedPathRenderer.h"
-
-
-GrPathRenderer* GrPathRenderer::CreatePathRenderer() { return new GrTesselatedPathRenderer(); }
diff --git a/gpu/src/GrDrawMesh.cpp b/gpu/src/GrDrawMesh.cpp
deleted file mode 100644
index bd79005..0000000
--- a/gpu/src/GrDrawMesh.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
-#include "GrMesh.h"
-#include "SkCanvas.h"
-
-GrMesh::GrMesh() : fPts(NULL), fCount(0), fIndices(NULL), fIndexCount(0) {}
-
-GrMesh::~GrMesh() {
- delete[] fPts;
- delete[] fIndices;
-}
-
-GrMesh& GrMesh::operator=(const GrMesh& src) {
- delete[] fPts;
- delete[] fIndices;
-
- fBounds = src.fBounds;
- fRows = src.fRows;
- fCols = src.fCols;
-
- fCount = src.fCount;
- fPts = new SkPoint[fCount * 2];
- fTex = fPts + fCount;
- memcpy(fPts, src.fPts, fCount * 2 * sizeof(SkPoint));
-
- delete[] fIndices;
- fIndexCount = src.fIndexCount;
- fIndices = new uint16_t[fIndexCount];
- memcpy(fIndices, src.fIndices, fIndexCount * sizeof(uint16_t));
-
- return *this;
-}
-
-void GrMesh::init(const SkRect& bounds, int rows, int cols,
- const SkRect& texture) {
- SkASSERT(rows > 0 && cols > 0);
-
- fBounds = bounds;
- fRows = rows;
- fCols = cols;
-
- delete[] fPts;
- fCount = (rows + 1) * (cols + 1);
- fPts = new SkPoint[fCount * 2];
- fTex = fPts + fCount;
-
- delete[] fIndices;
- fIndexCount = rows * cols * 6;
- fIndices = new uint16_t[fIndexCount];
-
- SkPoint* pts = fPts;
- const SkScalar dx = bounds.width() / rows;
- const SkScalar dy = bounds.height() / cols;
- SkPoint* tex = fTex;
- const SkScalar dtx = texture.width() / rows;
- const SkScalar dty = texture.height() / cols;
- uint16_t* idx = fIndices;
- int index = 0;
- for (int y = 0; y <= cols; y++) {
- for (int x = 0; x <= rows; x++) {
- pts->set(bounds.fLeft + x*dx, bounds.fTop + y*dy);
- pts += 1;
- tex->set(texture.fLeft + x*dtx, texture.fTop + y*dty);
- tex += 1;
-
- if (y < cols && x < rows) {
- *idx++ = index;
- *idx++ = index + rows + 1;
- *idx++ = index + 1;
-
- *idx++ = index + 1;
- *idx++ = index + rows + 1;
- *idx++ = index + rows + 2;
-
- index += 1;
- }
- }
- index += 1;
- }
-}
-
-void GrMesh::draw(SkCanvas* canvas, const SkPaint& paint) {
- canvas->drawVertices(SkCanvas::kTriangles_VertexMode, fCount,
- fPts, fTex, NULL, NULL, fIndices, fIndexCount,
- paint);
-}
-
-/////////////////////////////////////////////
-
-#include "SkBoundaryPatch.h"
-#include "SkMeshUtils.h"
-
-static SkPoint SkPointInterp(const SkPoint& a, const SkPoint& b, SkScalar t) {
- return SkPoint::Make(SkScalarInterp(a.fX, b.fX, t),
- SkScalarInterp(a.fY, b.fY, t));
-}
-
-static void set_cubic(SkPoint pts[4], SkScalar x0, SkScalar y0,
- SkScalar x3, SkScalar y3, SkScalar scale = 1) {
- SkPoint tmp, tmp2;
-
- pts[0].set(x0, y0);
- pts[3].set(x3, y3);
-
- tmp = SkPointInterp(pts[0], pts[3], SK_Scalar1/3);
- tmp2 = pts[0] - tmp;
- tmp2.rotateCW();
- tmp2.scale(scale);
- pts[1] = tmp + tmp2;
-
- tmp = SkPointInterp(pts[0], pts[3], 2*SK_Scalar1/3);
- tmp2 = pts[3] - tmp;
- tmp2.rotateCW();
- tmp2.scale(scale);
- pts[2] = tmp + tmp2;
-}
-
-void test_patch(SkCanvas* canvas, const SkBitmap& bm, SkScalar scale) {
- const float w = bm.width();
- const float h = bm.height();
- SkCubicBoundary cubic;
- set_cubic(cubic.fPts + 0, 0, 0, w, 0, scale);
- set_cubic(cubic.fPts + 3, w, 0, w, h, scale);
- set_cubic(cubic.fPts + 6, w, h, 0, h, -scale);
- set_cubic(cubic.fPts + 9, 0, h, 0, 0, scale);
-
- SkBoundaryPatch patch;
- patch.setBoundary(&cubic);
-
- const int Rows = 16;
- const int Cols = 16;
- SkPoint pts[Rows * Cols];
- patch.evalPatch(pts, Rows, Cols);
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setFilterBitmap(true);
-
- SkMeshUtils::Draw(canvas, bm, Rows, Cols, pts, NULL, paint);
-}
-
-
diff --git a/gpu/src/GrDrawTarget.cpp b/gpu/src/GrDrawTarget.cpp
deleted file mode 100644
index 2848999..0000000
--- a/gpu/src/GrDrawTarget.cpp
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#include "GrDrawTarget.h"
-#include "GrGpuVertex.h"
-#include "GrTexture.h"
-
-namespace {
-
-// recursive helper for creating mask with all the tex coord bits set for
-// one stage
-template <int N>
-int stage_mask_recur(int stage) {
- return GrDrawTarget::StageTexCoordVertexLayoutBit(stage, N) |
- stage_mask_recur<N+1>(stage);
-}
-template<>
-int stage_mask_recur<GrDrawTarget::kNumStages>(int) { return 0; }
-
-// mask of all tex coord indices for one stage
-int stage_tex_coord_mask(int stage) {
- return stage_mask_recur<0>(stage);
-}
-
-// mask of all bits relevant to one stage
-int stage_mask(int stage) {
- return stage_tex_coord_mask(stage) |
- GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(stage);
-}
-
-// recursive helper for creating mask of with all bits set relevant to one
-// texture coordinate index
-template <int N>
-int tex_coord_mask_recur(int texCoordIdx) {
- return GrDrawTarget::StageTexCoordVertexLayoutBit(N, texCoordIdx) |
- tex_coord_mask_recur<N+1>(texCoordIdx);
-}
-template<>
-int tex_coord_mask_recur<GrDrawTarget::kMaxTexCoords>(int) { return 0; }
-
-// mask of all bits relevant to one texture coordinate index
-int tex_coord_idx_mask(int texCoordIdx) {
- return tex_coord_mask_recur<0>(texCoordIdx);
-}
-
-bool check_layout(GrVertexLayout layout) {
- // can only have 1 or 0 bits set for each stage.
- for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
- int stageBits = layout & stage_mask(s);
- if (stageBits && !GrIsPow2(stageBits)) {
- return false;
- }
- }
- return true;
-}
-
-} //unnamed namespace
-
-size_t GrDrawTarget::VertexSize(GrVertexLayout vertexLayout) {
- GrAssert(check_layout(vertexLayout));
-
- size_t vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
- sizeof(GrGpuTextVertex) :
- sizeof(GrPoint);
-
- size_t size = vecSize; // position
- for (int t = 0; t < kMaxTexCoords; ++t) {
- if (tex_coord_idx_mask(t) & vertexLayout) {
- size += vecSize;
- }
- }
- if (vertexLayout & kColor_VertexLayoutBit) {
- size += sizeof(GrColor);
- }
- return size;
-}
-
-int GrDrawTarget::VertexStageCoordOffset(int stage, GrVertexLayout vertexLayout) {
- GrAssert(check_layout(vertexLayout));
- if (StagePosAsTexCoordVertexLayoutBit(stage) & vertexLayout) {
- return 0;
- }
- int tcIdx = VertexTexCoordsForStage(stage, vertexLayout);
- if (tcIdx >= 0) {
-
- int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
- sizeof(GrGpuTextVertex) :
- sizeof(GrPoint);
- int offset = vecSize; // position
- // figure out how many tex coordinates are present and precede this one.
- for (int t = 0; t < tcIdx; ++t) {
- if (tex_coord_idx_mask(t) & vertexLayout) {
- offset += vecSize;
- }
- }
- return offset;
- }
-
- return -1;
-}
-
-int GrDrawTarget::VertexColorOffset(GrVertexLayout vertexLayout) {
- GrAssert(check_layout(vertexLayout));
-
- if (vertexLayout & kColor_VertexLayoutBit) {
- int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
- sizeof(GrGpuTextVertex) :
- sizeof(GrPoint);
- int offset = vecSize; // position
- // figure out how many tex coordinates are present and precede this one.
- for (int t = 0; t < kMaxTexCoords; ++t) {
- if (tex_coord_idx_mask(t) & vertexLayout) {
- offset += vecSize;
- }
- }
- return offset;
- }
- return -1;
-}
-
-int GrDrawTarget::VertexSizeAndOffsetsByIdx(GrVertexLayout vertexLayout,
- int texCoordOffsetsByIdx[kMaxTexCoords],
- int* colorOffset) {
- GrAssert(check_layout(vertexLayout));
-
- GrAssert(NULL != texCoordOffsetsByIdx);
- GrAssert(NULL != colorOffset);
-
- int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
- sizeof(GrGpuTextVertex) :
- sizeof(GrPoint);
- int size = vecSize; // position
-
- for (int t = 0; t < kMaxTexCoords; ++t) {
- if (tex_coord_idx_mask(t) & vertexLayout) {
- texCoordOffsetsByIdx[t] = size;
- size += vecSize;
- } else {
- texCoordOffsetsByIdx[t] = -1;
- }
- }
- if (kColor_VertexLayoutBit & vertexLayout) {
- *colorOffset = size;
- size += sizeof(GrColor);
- } else {
- *colorOffset = -1;
- }
- return size;
-}
-
-int GrDrawTarget::VertexSizeAndOffsetsByStage(GrVertexLayout vertexLayout,
- int texCoordOffsetsByStage[kNumStages],
- int* colorOffset) {
- GrAssert(check_layout(vertexLayout));
-
- GrAssert(NULL != texCoordOffsetsByStage);
- GrAssert(NULL != colorOffset);
-
- int texCoordOffsetsByIdx[kMaxTexCoords];
- int size = VertexSizeAndOffsetsByIdx(vertexLayout,
- texCoordOffsetsByIdx,
- colorOffset);
- for (int s = 0; s < kNumStages; ++s) {
- int tcIdx;
- if (StagePosAsTexCoordVertexLayoutBit(s) & vertexLayout) {
- texCoordOffsetsByStage[s] = 0;
- } else if ((tcIdx = VertexTexCoordsForStage(s, vertexLayout)) >= 0) {
- texCoordOffsetsByStage[s] = texCoordOffsetsByIdx[tcIdx];
- } else {
- texCoordOffsetsByStage[s] = -1;
- }
- }
- return size;
-}
-
-bool GrDrawTarget::VertexUsesStage(int stage, GrVertexLayout vertexLayout) {
- GrAssert(stage < kNumStages);
- GrAssert(check_layout(vertexLayout));
- return !!(stage_mask(stage) & vertexLayout);
-}
-
-bool GrDrawTarget::VertexUsesTexCoordIdx(int coordIndex,
- GrVertexLayout vertexLayout) {
- GrAssert(coordIndex < kMaxTexCoords);
- GrAssert(check_layout(vertexLayout));
- return !!(tex_coord_idx_mask(coordIndex) & vertexLayout);
-}
-
-int GrDrawTarget::VertexTexCoordsForStage(int stage, GrVertexLayout vertexLayout) {
- GrAssert(stage < kNumStages);
- GrAssert(check_layout(vertexLayout));
- int bit = vertexLayout & stage_tex_coord_mask(stage);
- if (bit) {
- // figure out which set of texture coordates is used
- // bits are ordered T0S0, T0S1, T0S2, ..., T1S0, T1S1, ...
- // and start at bit 0.
- GR_STATIC_ASSERT(sizeof(GrVertexLayout) <= sizeof(uint32_t));
- return (32 - Gr_clz(bit) - 1) / kNumStages;
- }
- return -1;
-}
-
-void GrDrawTarget::VertexLayoutUnitTest() {
- // not necessarily exhaustive
- static bool run;
- if (!run) {
- run = true;
- for (int s = 0; s < kNumStages; ++s) {
-
- GrAssert(!VertexUsesStage(s, 0));
- GrAssert(-1 == VertexStageCoordOffset(s, 0));
- GrVertexLayout stageMask = 0;
- for (int t = 0; t < kMaxTexCoords; ++t) {
- stageMask |= StageTexCoordVertexLayoutBit(s,t);
- }
- GrAssert(1 == kMaxTexCoords || !check_layout(stageMask));
- GrAssert(stage_tex_coord_mask(s) == stageMask);
- stageMask |= StagePosAsTexCoordVertexLayoutBit(s);
- GrAssert(stage_mask(s) == stageMask);
- GrAssert(!check_layout(stageMask));
- }
- for (int t = 0; t < kMaxTexCoords; ++t) {
- GrVertexLayout tcMask = 0;
- GrAssert(!VertexUsesTexCoordIdx(t, 0));
- for (int s = 0; s < kNumStages; ++s) {
- tcMask |= StageTexCoordVertexLayoutBit(s,t);
- GrAssert(VertexUsesStage(s, tcMask));
- GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask));
- GrAssert(VertexUsesTexCoordIdx(t, tcMask));
- GrAssert(2*sizeof(GrPoint) == VertexSize(tcMask));
- GrAssert(t == VertexTexCoordsForStage(s, tcMask));
- for (int s2 = s + 1; s2 < kNumStages; ++s2) {
- GrAssert(-1 == VertexStageCoordOffset(s2, tcMask));
- GrAssert(!VertexUsesStage(s2, tcMask));
- GrAssert(-1 == VertexTexCoordsForStage(s2, tcMask));
-
- #if GR_DEBUG
- GrVertexLayout posAsTex = tcMask | StagePosAsTexCoordVertexLayoutBit(s2);
- #endif
- GrAssert(0 == VertexStageCoordOffset(s2, posAsTex));
- GrAssert(VertexUsesStage(s2, posAsTex));
- GrAssert(2*sizeof(GrPoint) == VertexSize(posAsTex));
- GrAssert(-1 == VertexTexCoordsForStage(s2, posAsTex));
- }
- #if GR_DEBUG
- GrVertexLayout withColor = tcMask | kColor_VertexLayoutBit;
- #endif
- GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColor));
- GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColor));
- }
- GrAssert(tex_coord_idx_mask(t) == tcMask);
- GrAssert(check_layout(tcMask));
-
- int stageOffsets[kNumStages];
- int colorOffset;
- int size;
- size = VertexSizeAndOffsetsByStage(tcMask, stageOffsets, &colorOffset);
- GrAssert(2*sizeof(GrPoint) == size);
- GrAssert(-1 == colorOffset);
- for (int s = 0; s < kNumStages; ++s) {
- GrAssert(VertexUsesStage(s, tcMask));
- GrAssert(sizeof(GrPoint) == stageOffsets[s]);
- GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask));
- }
- }
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-GrDrawTarget::GrDrawTarget() {
-#if GR_DEBUG
- VertexLayoutUnitTest();
-#endif
- fReservedGeometry.fLocked = false;
-#if GR_DEBUG
- fReservedGeometry.fVertexCount = ~0;
- fReservedGeometry.fIndexCount = ~0;
-#endif
- fGeometrySrc.fVertexSrc = kReserved_GeometrySrcType;
- fGeometrySrc.fIndexSrc = kReserved_GeometrySrcType;
-}
-
-void GrDrawTarget::setClip(const GrClip& clip) {
- clipWillBeSet(clip);
- fClip = clip;
-}
-
-const GrClip& GrDrawTarget::getClip() const {
- return fClip;
-}
-
-void GrDrawTarget::setTexture(int stage, GrTexture* tex) {
- GrAssert(stage >= 0 && stage < kNumStages);
- fCurrDrawState.fTextures[stage] = tex;
-}
-
-const GrTexture* GrDrawTarget::getTexture(int stage) const {
- GrAssert(stage >= 0 && stage < kNumStages);
- return fCurrDrawState.fTextures[stage];
-}
-
-GrTexture* GrDrawTarget::getTexture(int stage) {
- GrAssert(stage >= 0 && stage < kNumStages);
- return fCurrDrawState.fTextures[stage];
-}
-
-void GrDrawTarget::setRenderTarget(GrRenderTarget* target) {
- fCurrDrawState.fRenderTarget = target;
-}
-
-const GrRenderTarget* GrDrawTarget::getRenderTarget() const {
- return fCurrDrawState.fRenderTarget;
-}
-
-GrRenderTarget* GrDrawTarget::getRenderTarget() {
- return fCurrDrawState.fRenderTarget;
-}
-
-void GrDrawTarget::setViewMatrix(const GrMatrix& m) {
- fCurrDrawState.fViewMatrix = m;
-}
-
-void GrDrawTarget::preConcatViewMatrix(const GrMatrix& matrix) {
- fCurrDrawState.fViewMatrix.preConcat(matrix);
-}
-
-void GrDrawTarget::postConcatViewMatrix(const GrMatrix& matrix) {
- fCurrDrawState.fViewMatrix.postConcat(matrix);
-}
-
-const GrMatrix& GrDrawTarget::getViewMatrix() const {
- return fCurrDrawState.fViewMatrix;
-}
-
-bool GrDrawTarget::getViewInverse(GrMatrix* matrix) const {
- // Mike: Can we cache this somewhere?
- // Brian: Sure, do we use it often?
-
- GrMatrix inverse;
- if (fCurrDrawState.fViewMatrix.invert(&inverse)) {
- if (matrix) {
- *matrix = inverse;
- }
- return true;
- }
- return false;
-}
-
-void GrDrawTarget::setSamplerState(int stage, const GrSamplerState& state) {
- GrAssert(stage >= 0 && stage < kNumStages);
- fCurrDrawState.fSamplerStates[stage] = state;
-}
-
-void GrDrawTarget::enableState(uint32_t bits) {
- fCurrDrawState.fFlagBits |= bits;
-}
-
-void GrDrawTarget::disableState(uint32_t bits) {
- fCurrDrawState.fFlagBits &= ~(bits);
-}
-
-void GrDrawTarget::setBlendFunc(GrBlendCoeff srcCoeff,
- GrBlendCoeff dstCoeff) {
- fCurrDrawState.fSrcBlend = srcCoeff;
- fCurrDrawState.fDstBlend = dstCoeff;
-#if GR_DEBUG
- switch (dstCoeff) {
- case kDC_BlendCoeff:
- case kIDC_BlendCoeff:
- case kDA_BlendCoeff:
- case kIDA_BlendCoeff:
- GrPrintf("Unexpected dst blend coeff. Won't work correctly with"
- "coverage stages.\n");
- break;
- default:
- break;
- }
- switch (srcCoeff) {
- case kSC_BlendCoeff:
- case kISC_BlendCoeff:
- case kSA_BlendCoeff:
- case kISA_BlendCoeff:
- GrPrintf("Unexpected src blend coeff. Won't work correctly with"
- "coverage stages.\n");
- break;
- default:
- break;
- }
-#endif
-}
-
-void GrDrawTarget::setColor(GrColor c) {
- fCurrDrawState.fColor = c;
-}
-
-void GrDrawTarget::setColorFilter(GrColor c, SkXfermode::Mode mode) {
- fCurrDrawState.fColorFilterColor = c;
- fCurrDrawState.fColorFilterXfermode = mode;
-}
-
-void GrDrawTarget::setAlpha(uint8_t a) {
- this->setColor((a << 24) | (a << 16) | (a << 8) | a);
-}
-
-void GrDrawTarget::saveCurrentDrawState(SavedDrawState* state) const {
- state->fState = fCurrDrawState;
-}
-
-void GrDrawTarget::restoreDrawState(const SavedDrawState& state) {
- fCurrDrawState = state.fState;
-}
-
-void GrDrawTarget::copyDrawState(const GrDrawTarget& srcTarget) {
- fCurrDrawState = srcTarget.fCurrDrawState;
-}
-
-
-bool GrDrawTarget::reserveAndLockGeometry(GrVertexLayout vertexLayout,
- uint32_t vertexCount,
- uint32_t indexCount,
- void** vertices,
- void** indices) {
- GrAssert(!fReservedGeometry.fLocked);
- fReservedGeometry.fVertexCount = vertexCount;
- fReservedGeometry.fIndexCount = indexCount;
-
- fReservedGeometry.fLocked = this->onAcquireGeometry(vertexLayout,
- vertices,
- indices);
- if (fReservedGeometry.fLocked) {
- if (vertexCount) {
- fGeometrySrc.fVertexSrc = kReserved_GeometrySrcType;
- fGeometrySrc.fVertexLayout = vertexLayout;
- } else if (NULL != vertices) {
- *vertices = NULL;
- }
- if (indexCount) {
- fGeometrySrc.fIndexSrc = kReserved_GeometrySrcType;
- } else if (NULL != indices) {
- *indices = NULL;
- }
- }
- return fReservedGeometry.fLocked;
-}
-
-bool GrDrawTarget::geometryHints(GrVertexLayout vertexLayout,
- int32_t* vertexCount,
- int32_t* indexCount) const {
- GrAssert(!fReservedGeometry.fLocked);
- if (NULL != vertexCount) {
- *vertexCount = -1;
- }
- if (NULL != indexCount) {
- *indexCount = -1;
- }
- return false;
-}
-
-void GrDrawTarget::releaseReservedGeometry() {
- GrAssert(fReservedGeometry.fLocked);
- this->onReleaseGeometry();
- fReservedGeometry.fLocked = false;
-}
-
-void GrDrawTarget::setVertexSourceToArray(GrVertexLayout vertexLayout,
- const void* vertexArray,
- int vertexCount) {
- fGeometrySrc.fVertexSrc = kArray_GeometrySrcType;
- fGeometrySrc.fVertexLayout = vertexLayout;
- this->onSetVertexSourceToArray(vertexArray, vertexCount);
-}
-
-void GrDrawTarget::setIndexSourceToArray(const void* indexArray,
- int indexCount) {
- fGeometrySrc.fIndexSrc = kArray_GeometrySrcType;
- this->onSetIndexSourceToArray(indexArray, indexCount);
-}
-
-void GrDrawTarget::setVertexSourceToBuffer(GrVertexLayout vertexLayout,
- const GrVertexBuffer* buffer) {
- fGeometrySrc.fVertexSrc = kBuffer_GeometrySrcType;
- fGeometrySrc.fVertexBuffer = buffer;
- fGeometrySrc.fVertexLayout = vertexLayout;
-}
-
-void GrDrawTarget::setIndexSourceToBuffer(const GrIndexBuffer* buffer) {
- fGeometrySrc.fIndexSrc = kBuffer_GeometrySrcType;
- fGeometrySrc.fIndexBuffer = buffer;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-bool GrDrawTarget::canDisableBlend() const {
- // If we compute a coverage value (using edge AA or a coverage stage) then
- // we can't force blending off.
- if (fCurrDrawState.fEdgeAANumEdges > 0) {
- return false;
- }
- for (int s = fCurrDrawState.fFirstCoverageStage; s < kNumStages; ++s) {
- if (this->isStageEnabled(s)) {
- return false;
- }
- }
-
- if ((kOne_BlendCoeff == fCurrDrawState.fSrcBlend) &&
- (kZero_BlendCoeff == fCurrDrawState.fDstBlend)) {
- return true;
- }
-
- // If we have vertex color without alpha then we can't force blend off
- if ((fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) ||
- 0xff != GrColorUnpackA(fCurrDrawState.fColor)) {
- return false;
- }
-
- // If the src coef will always be 1...
- if (kSA_BlendCoeff != fCurrDrawState.fSrcBlend &&
- kOne_BlendCoeff != fCurrDrawState.fSrcBlend) {
- return false;
- }
-
- // ...and the dst coef is always 0...
- if (kISA_BlendCoeff != fCurrDrawState.fDstBlend &&
- kZero_BlendCoeff != fCurrDrawState.fDstBlend) {
- return false;
- }
-
- // ...and there isn't a texture stage with an alpha channel...
- for (int s = 0; s < fCurrDrawState.fFirstCoverageStage; ++s) {
- if (this->isStageEnabled(s)) {
- GrAssert(NULL != fCurrDrawState.fTextures[s]);
-
- GrPixelConfig config = fCurrDrawState.fTextures[s]->config();
-
- if (!GrPixelConfigIsOpaque(config)) {
- return false;
- }
- }
- }
-
- // ...and there isn't an interesting color filter...
- // TODO: Consider being more aggressive with regards to disabling
- // blending when a color filter is used.
- if (SkXfermode::kDst_Mode != fCurrDrawState.fColorFilterXfermode) {
- return false;
- }
-
- // ...then we disable blend.
- return true;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-void GrDrawTarget::setEdgeAAData(const Edge* edges, int numEdges) {
- GrAssert(numEdges <= kMaxEdges);
- memcpy(fCurrDrawState.fEdgeAAEdges, edges, numEdges * sizeof(Edge));
- fCurrDrawState.fEdgeAANumEdges = numEdges;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-void GrDrawTarget::drawRect(const GrRect& rect,
- const GrMatrix* matrix,
- StageBitfield stageEnableBitfield,
- const GrRect* srcRects[],
- const GrMatrix* srcMatrices[]) {
- GrVertexLayout layout = GetRectVertexLayout(stageEnableBitfield, srcRects);
-
- AutoReleaseGeometry geo(this, layout, 4, 0);
-
- SetRectVertices(rect, matrix, srcRects,
- srcMatrices, layout, geo.vertices());
-
- drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
-}
-
-GrVertexLayout GrDrawTarget::GetRectVertexLayout(StageBitfield stageEnableBitfield,
- const GrRect* srcRects[]) {
- GrVertexLayout layout = 0;
-
- for (int i = 0; i < kNumStages; ++i) {
- int numTC = 0;
- if (stageEnableBitfield & (1 << i)) {
- if (NULL != srcRects && NULL != srcRects[i]) {
- layout |= StageTexCoordVertexLayoutBit(i, numTC);
- ++numTC;
- } else {
- layout |= StagePosAsTexCoordVertexLayoutBit(i);
- }
- }
- }
- return layout;
-}
-void GrDrawTarget::SetRectVertices(const GrRect& rect,
- const GrMatrix* matrix,
- const GrRect* srcRects[],
- const GrMatrix* srcMatrices[],
- GrVertexLayout layout,
- void* vertices) {
-#if GR_DEBUG
- // check that the layout and srcRects agree
- for (int i = 0; i < kNumStages; ++i) {
- if (VertexTexCoordsForStage(i, layout) >= 0) {
- GR_DEBUGASSERT(NULL != srcRects && NULL != srcRects[i]);
- } else {
- GR_DEBUGASSERT(NULL == srcRects || NULL == srcRects[i]);
- }
- }
-#endif
-
- int stageOffsets[kNumStages];
- int colorOffset;
- int vsize = VertexSizeAndOffsetsByStage(layout, stageOffsets, &colorOffset);
- GrAssert(-1 == colorOffset);
-
- GrTCast<GrPoint*>(vertices)->setRectFan(rect.fLeft, rect.fTop,
- rect.fRight, rect.fBottom,
- vsize);
- if (NULL != matrix) {
- matrix->mapPointsWithStride(GrTCast<GrPoint*>(vertices), vsize, 4);
- }
-
- for (int i = 0; i < kNumStages; ++i) {
- if (stageOffsets[i] > 0) {
- GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(vertices) +
- stageOffsets[i]);
- coords->setRectFan(srcRects[i]->fLeft, srcRects[i]->fTop,
- srcRects[i]->fRight, srcRects[i]->fBottom,
- vsize);
- if (NULL != srcMatrices && NULL != srcMatrices[i]) {
- srcMatrices[i]->mapPointsWithStride(coords, vsize, 4);
- }
- }
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-GrDrawTarget::AutoStateRestore::AutoStateRestore() {
- fDrawTarget = NULL;
-}
-
-GrDrawTarget::AutoStateRestore::AutoStateRestore(GrDrawTarget* target) {
- fDrawTarget = target;
- if (NULL != fDrawTarget) {
- fDrawTarget->saveCurrentDrawState(&fDrawState);
- }
-}
-
-GrDrawTarget::AutoStateRestore::~AutoStateRestore() {
- if (NULL != fDrawTarget) {
- fDrawTarget->restoreDrawState(fDrawState);
- }
-}
-
-void GrDrawTarget::AutoStateRestore::set(GrDrawTarget* target) {
- if (target != fDrawTarget) {
- if (NULL != fDrawTarget) {
- fDrawTarget->restoreDrawState(fDrawState);
- }
- if (NULL != target) {
- fDrawTarget->saveCurrentDrawState(&fDrawState);
- }
- fDrawTarget = target;
- }
-}
diff --git a/gpu/src/GrGLDefaultInterface_none.cpp b/gpu/src/GrGLDefaultInterface_none.cpp
deleted file mode 100644
index d355589..0000000
--- a/gpu/src/GrGLDefaultInterface_none.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-void GrGLSetDefaultGLInterface() {
-}
diff --git a/gpu/src/GrGLIndexBuffer.cpp b/gpu/src/GrGLIndexBuffer.cpp
deleted file mode 100644
index 4fb1e99..0000000
--- a/gpu/src/GrGLIndexBuffer.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#include "GrGLIndexBuffer.h"
-#include "GrGpuGL.h"
-
-#define GPUGL static_cast<GrGpuGL*>(getGpu())
-
-GrGLIndexBuffer::GrGLIndexBuffer(GrGpuGL* gpu,
- GrGLuint id,
- size_t sizeInBytes,
- bool dynamic)
- : INHERITED(gpu, sizeInBytes, dynamic)
- , fBufferID(id)
- , fLockPtr(NULL) {
-
-}
-
-void GrGLIndexBuffer::onRelease() {
- // make sure we've not been abandoned
- if (fBufferID) {
- GPUGL->notifyIndexBufferDelete(this);
- GR_GL(DeleteBuffers(1, &fBufferID));
- fBufferID = 0;
- }
-}
-
-void GrGLIndexBuffer::onAbandon() {
- fBufferID = 0;
- fLockPtr = NULL;
-}
-
-void GrGLIndexBuffer::bind() const {
- GR_GL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, fBufferID));
- GPUGL->notifyIndexBufferBind(this);
-}
-
-GrGLuint GrGLIndexBuffer::bufferID() const {
- return fBufferID;
-}
-
-void* GrGLIndexBuffer::lock() {
- GrAssert(fBufferID);
- GrAssert(!isLocked());
- if (GPUGL->supportsBufferLocking()) {
- this->bind();
- // Let driver know it can discard the old data
- GR_GL(BufferData(GR_GL_ELEMENT_ARRAY_BUFFER, size(), NULL,
- dynamic() ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW));
- fLockPtr = GR_GL(MapBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, GR_GL_WRITE_ONLY));
-
- return fLockPtr;
- }
- return NULL;
-}
-
-void* GrGLIndexBuffer::lockPtr() const {
- return fLockPtr;
-}
-
-void GrGLIndexBuffer::unlock() {
- GrAssert(fBufferID);
- GrAssert(isLocked());
- GrAssert(GPUGL->supportsBufferLocking());
-
- this->bind();
- GR_GL(UnmapBuffer(GR_GL_ELEMENT_ARRAY_BUFFER));
- fLockPtr = NULL;
-}
-
-bool GrGLIndexBuffer::isLocked() const {
-#if GR_DEBUG
- if (this->isValid() && GPUGL->supportsBufferLocking()) {
- this->bind();
- GrGLint mapped;
- GR_GL(GetBufferParameteriv(GR_GL_ELEMENT_ARRAY_BUFFER,
- GR_GL_BUFFER_MAPPED, &mapped));
- GrAssert(!!mapped == !!fLockPtr);
- }
-#endif
- return NULL != fLockPtr;
-}
-
-bool GrGLIndexBuffer::updateData(const void* src, size_t srcSizeInBytes) {
- GrAssert(fBufferID);
- GrAssert(!isLocked());
- if (srcSizeInBytes > size()) {
- return false;
- }
- this->bind();
- GrGLenum usage = dynamic() ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW;
- if (size() == srcSizeInBytes) {
- GR_GL(BufferData(GR_GL_ELEMENT_ARRAY_BUFFER, srcSizeInBytes, src, usage));
- } else {
- GR_GL(BufferData(GR_GL_ELEMENT_ARRAY_BUFFER, size(), NULL, usage));
- GR_GL(BufferSubData(GR_GL_ELEMENT_ARRAY_BUFFER, 0, srcSizeInBytes, src));
- }
- return true;
-}
-
-bool GrGLIndexBuffer::updateSubData(const void* src,
- size_t srcSizeInBytes,
- size_t offset) {
- GrAssert(fBufferID);
- GrAssert(!isLocked());
- if (srcSizeInBytes + offset > size()) {
- return false;
- }
- this->bind();
- GR_GL(BufferSubData(GR_GL_ELEMENT_ARRAY_BUFFER, offset, srcSizeInBytes, src));
- return true;
-}
-
diff --git a/gpu/src/GrGLInterface.cpp b/gpu/src/GrGLInterface.cpp
deleted file mode 100644
index 5ecf8eb..0000000
--- a/gpu/src/GrGLInterface.cpp
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#include "GrTypes.h"
-#include "GrGLInterface.h"
-#include "GrGLDefines.h"
-
-#include <stdio.h>
-
-GrGLInterface* gGLInterface = NULL;
-
-void gl_version_from_string(int* major, int* minor,
- const char* versionString) {
- if (NULL == versionString) {
- GrAssert(0);
- *major = 0;
- *minor = 0;
- return;
- }
-
- int n = sscanf(versionString, "%d.%d", major, minor);
- if (2 == n) {
- return;
- }
-
- char profile[2];
- n = sscanf(versionString, "OpenGL ES-%c%c %d.%d", profile, profile+1,
- major, minor);
- bool ok = 4 == n;
- if (!ok) {
- n = sscanf(versionString, "OpenGL ES %d.%d", major, minor);
- ok = 2 == n;
- }
-
- if (!ok) {
- GrAssert(0);
- *major = 0;
- *minor = 0;
- return;
- }
-}
-
-bool has_gl_extension_from_string(const char* ext,
- const char* extensionString) {
- int extLength = strlen(ext);
-
- while (true) {
- int n = strcspn(extensionString, " ");
- if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
- return true;
- }
- if (0 == extensionString[n]) {
- return false;
- }
- extensionString += n+1;
- }
-
- return false;
-}
-
-
-GR_API void GrGLSetGLInterface(GrGLInterface* gl_interface) {
- gGLInterface = gl_interface;
-}
-
-GR_API GrGLInterface* GrGLGetGLInterface() {
- return gGLInterface;
-}
-
-bool has_gl_extension(const char* ext) {
- const char* glstr = reinterpret_cast<const char*>(
- GrGLGetGLInterface()->fGetString(GR_GL_EXTENSIONS));
-
- return has_gl_extension_from_string(ext, glstr);
-}
-
-void gl_version(int* major, int* minor) {
- const char* v = reinterpret_cast<const char*>(
- GrGLGetGLInterface()->fGetString(GR_GL_VERSION));
- gl_version_from_string(major, minor, v);
-}
-
-bool GrGLInterface::validateShaderFunctions() const {
- // required for GrGpuGLShaders
- if (NULL == fAttachShader ||
- NULL == fBindAttribLocation ||
- NULL == fCompileShader ||
- NULL == fCreateProgram ||
- NULL == fCreateShader ||
- NULL == fDeleteProgram ||
- NULL == fDeleteShader ||
- NULL == fDisableVertexAttribArray ||
- NULL == fEnableVertexAttribArray ||
- NULL == fGetProgramInfoLog ||
- NULL == fGetProgramiv ||
- NULL == fGetShaderInfoLog ||
- NULL == fGetShaderiv ||
- NULL == fGetUniformLocation ||
- NULL == fLinkProgram ||
- NULL == fShaderSource ||
- NULL == fUniform1f ||
- NULL == fUniform1i ||
- NULL == fUniform1fv ||
- NULL == fUniform1iv ||
- NULL == fUniform2f ||
- NULL == fUniform2i ||
- NULL == fUniform2fv ||
- NULL == fUniform2iv ||
- NULL == fUniform3f ||
- NULL == fUniform3i ||
- NULL == fUniform3fv ||
- NULL == fUniform3iv ||
- NULL == fUniform4f ||
- NULL == fUniform4i ||
- NULL == fUniform4fv ||
- NULL == fUniform4iv ||
- NULL == fUniformMatrix2fv ||
- NULL == fUniformMatrix3fv ||
- NULL == fUniformMatrix4fv ||
- NULL == fUseProgram ||
- NULL == fVertexAttrib4fv ||
- NULL == fVertexAttribPointer) {
- return false;
- }
- return true;
-}
-
-bool GrGLInterface::validateFixedFunctions() const {
- if (NULL == fClientActiveTexture ||
- NULL == fColor4ub ||
- NULL == fColorPointer ||
- NULL == fDisableClientState ||
- NULL == fEnableClientState ||
- NULL == fLoadMatrixf ||
- NULL == fMatrixMode ||
- NULL == fPointSize ||
- NULL == fShadeModel ||
- NULL == fTexCoordPointer ||
- NULL == fTexEnvi ||
- NULL == fVertexPointer) {
- return false;
- }
- return true;
-}
-
-bool GrGLInterface::validate(GrEngine engine) const {
-
- bool isDesktop = kDesktop_GrGLBinding == fBindingsExported;
-
- // ES1 and 2 can be supported in the same interface
- bool isES = ((kES1_GrGLBinding | kES2_GrGLBinding) & fBindingsExported &&
- !(~(kES1_GrGLBinding | kES2_GrGLBinding) & fBindingsExported));
-
- if (!isDesktop && !isES) {
- return false;
- }
-
- // functions that are always required
- if (NULL == fActiveTexture ||
- NULL == fBindBuffer ||
- NULL == fBindTexture ||
- NULL == fBlendFunc ||
- NULL == fBufferData ||
- NULL == fBufferSubData ||
- NULL == fClear ||
- NULL == fClearColor ||
- NULL == fClearStencil ||
- NULL == fColorMask ||
- NULL == fCullFace ||
- NULL == fDeleteBuffers ||
- NULL == fDeleteTextures ||
- NULL == fDepthMask ||
- NULL == fDisable ||
- NULL == fDrawArrays ||
- NULL == fDrawElements ||
- NULL == fEnable ||
- NULL == fFrontFace ||
- NULL == fGenBuffers ||
- NULL == fGenTextures ||
- NULL == fGetBufferParameteriv ||
- NULL == fGetError ||
- NULL == fGetIntegerv ||
- NULL == fGetString ||
- NULL == fPixelStorei ||
- NULL == fReadPixels ||
- NULL == fScissor ||
- NULL == fStencilFunc ||
- NULL == fStencilMask ||
- NULL == fStencilOp ||
- NULL == fTexImage2D ||
- NULL == fTexParameteri ||
- NULL == fTexSubImage2D ||
- NULL == fViewport ||
- NULL == fBindFramebuffer ||
- NULL == fBindRenderbuffer ||
- NULL == fCheckFramebufferStatus ||
- NULL == fDeleteFramebuffers ||
- NULL == fDeleteRenderbuffers ||
- NULL == fFramebufferRenderbuffer ||
- NULL == fFramebufferTexture2D ||
- NULL == fGenFramebuffers ||
- NULL == fGenRenderbuffers ||
- NULL == fRenderbufferStorage) {
- return false;
- }
-
- switch (engine) {
- case kOpenGL_Shaders_GrEngine:
- if (kES1_GrGLBinding == fBindingsExported) {
- return false;
- }
- if (!this->validateShaderFunctions()) {
- return false;
- }
- break;
- case kOpenGL_Fixed_GrEngine:
- if (kES1_GrGLBinding == fBindingsExported) {
- return false;
- }
- if (!this->validateFixedFunctions()) {
- return false;
- }
- break;
- default:
- return false;
- }
-
- int major, minor;
- const char* ext;
-
- gl_version(&major, &minor);
- ext = (const char*)fGetString(GR_GL_EXTENSIONS);
-
- // Now check that baseline ES/Desktop fns not covered above are present
- // and that we have fn pointers for any advertised extensions that we will
- // try to use.
-
- // these functions are part of ES2, we assume they are available
- // On the desktop we assume they are available if the extension
- // is present or GL version is high enough.
- if ((kES2_GrGLBinding & fBindingsExported)) {
- if (NULL == fBlendColor ||
- NULL == fStencilFuncSeparate ||
- NULL == fStencilMaskSeparate ||
- NULL == fStencilOpSeparate) {
- return false;
- }
- } else if (kDesktop_GrGLBinding == fBindingsExported) {
- if (major >= 2) {
- if (NULL == fStencilFuncSeparate ||
- NULL == fStencilMaskSeparate ||
- NULL == fStencilOpSeparate) {
- return false;
- }
- }
- if (1 < major || (1 == major && 4 <= minor) ||
- has_gl_extension_from_string("GL_EXT_blend_color", ext)) {
- if (NULL == fBlendColor) {
- return false;
- }
- }
- }
-
- // optional function on desktop before 1.3
- if (kDesktop_GrGLBinding != fBindingsExported ||
- (1 < major || (1 == major && 3 <= minor)) ||
- has_gl_extension_from_string("GL_ARB_texture_compression", ext)) {
- if (NULL == fCompressedTexImage2D) {
- return false;
- }
- }
-
- // part of desktop GL
- if (kDesktop_GrGLBinding == fBindingsExported &&
- NULL == fLineWidth) {
- return false;
- }
- // FBO MSAA
- if (kDesktop_GrGLBinding == fBindingsExported) {
- // GL 3.0 and the ARB extension have multisample + blit
- if ((major >= 3) || has_gl_extension_from_string("GL_ARB_framebuffer_object", ext)) {
- if (NULL == fRenderbufferStorageMultisample ||
- NULL == fBlitFramebuffer) {
- return false;
- }
- } else {
- if (has_gl_extension_from_string("GL_EXT_framebuffer_blit", ext) &&
- NULL == fBlitFramebuffer) {
- return false;
- }
- if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample", ext) &&
- NULL == fRenderbufferStorageMultisample) {
- return false;
- }
- }
- } else {
- if (has_gl_extension_from_string("GL_CHROMIUM_framebuffer_multisample", ext)) {
- if (NULL == fRenderbufferStorageMultisample ||
- NULL == fBlitFramebuffer) {
- return false;
- }
- }
- if (has_gl_extension_from_string("GL_APPLE_framebuffer_multisample", ext)) {
- if (NULL == fRenderbufferStorageMultisample ||
- NULL == fResolveMultisampleFramebuffer) {
- return false;
- }
- }
- }
-
- // On ES buffer mapping is an extension. On Desktop
- // buffer mapping was part of original VBO extension
- // which we require.
- if (kDesktop_GrGLBinding == fBindingsExported ||
- has_gl_extension_from_string("GL_OES_mapbuffer", ext)) {
- if (NULL == fMapBuffer ||
- NULL == fUnmapBuffer) {
- return false;
- }
- }
-
- // Dual source blending
- if (kDesktop_GrGLBinding == fBindingsExported &&
- (has_gl_extension_from_string("GL_ARB_blend_func_extended", ext) ||
- (3 < major) || (3 == major && 3 <= minor))) {
- if (NULL == fBindFragDataLocationIndexed) {
- return false;
- }
- }
-
- return true;
-}
-
diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp
deleted file mode 100644
index ecb4753..0000000
--- a/gpu/src/GrGLProgram.cpp
+++ /dev/null
@@ -1,1176 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "GrGLProgram.h"
-
-#include "GrBinHashKey.h"
-#include "GrGLConfig.h"
-#include "GrMemory.h"
-
-#include "SkXfermode.h"
-
-namespace {
-
-const char* GrPrecision() {
- if (GR_GL_SUPPORT_ES2) {
- return "mediump";
- } else {
- return " ";
- }
-}
-
-const char* GrShaderPrecision() {
- if (GR_GL_SUPPORT_ES2) {
- return "precision mediump float;\n";
- } else {
- return "";
- }
-}
-
-} // namespace
-
-#define PRINT_SHADERS 0
-
-#if GR_GL_ATTRIBUTE_MATRICES
- #define VIEW_MATRIX_NAME "aViewM"
-#else
- #define VIEW_MATRIX_NAME "uViewM"
-#endif
-
-#define POS_ATTR_NAME "aPosition"
-#define COL_ATTR_NAME "aColor"
-#define COL_UNI_NAME "uColor"
-#define EDGES_UNI_NAME "uEdges"
-#define COL_FILTER_UNI_NAME "uColorFilter"
-
-static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
- *s = "aTexCoord";
- s->appendS32(coordIdx);
-}
-
-static inline const char* float_vector_type(int count) {
- static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
- GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(FLOAT_VECS));
- return FLOAT_VECS[count];
-}
-
-static inline const char* vector_homog_coord(int count) {
- static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
- GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS));
- return HOMOGS[count];
-}
-
-static inline const char* vector_nonhomog_coords(int count) {
- static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
- GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS));
- return NONHOMOGS[count];
-}
-
-static inline const char* vector_all_coords(int count) {
- static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
- GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL));
- return ALL[count];
-}
-
-static inline const char* all_ones_vec(int count) {
- static const char* ONESVEC[] = {"ERROR", "1.0", "vec2(1,1)",
- "vec3(1,1,1)", "vec4(1,1,1,1)"};
- GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ONESVEC));
- return ONESVEC[count];
-}
-
-static inline const char* all_zeros_vec(int count) {
- static const char* ZEROSVEC[] = {"ERROR", "0.0", "vec2(0,0)",
- "vec3(0,0,0)", "vec4(0,0,0,0)"};
- GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ZEROSVEC));
- return ZEROSVEC[count];
-}
-
-static inline const char* declared_color_output_name() { return "fsColorOut"; }
-static inline const char* dual_source_output_name() { return "dualSourceOut"; }
-
-static void tex_matrix_name(int stage, GrStringBuilder* s) {
-#if GR_GL_ATTRIBUTE_MATRICES
- *s = "aTexM";
-#else
- *s = "uTexM";
-#endif
- s->appendS32(stage);
-}
-
-static void normalized_texel_size_name(int stage, GrStringBuilder* s) {
- *s = "uTexelSize";
- s->appendS32(stage);
-}
-
-static void sampler_name(int stage, GrStringBuilder* s) {
- *s = "uSampler";
- s->appendS32(stage);
-}
-
-static void stage_varying_name(int stage, GrStringBuilder* s) {
- *s = "vStage";
- s->appendS32(stage);
-}
-
-static void radial2_param_name(int stage, GrStringBuilder* s) {
- *s = "uRadial2Params";
- s->appendS32(stage);
-}
-
-static void radial2_varying_name(int stage, GrStringBuilder* s) {
- *s = "vB";
- s->appendS32(stage);
-}
-
-static void tex_domain_name(int stage, GrStringBuilder* s) {
- *s = "uTexDom";
- s->appendS32(stage);
-}
-
-GrGLProgram::GrGLProgram() {
-}
-
-GrGLProgram::~GrGLProgram() {
-}
-
-void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff,
- GrBlendCoeff* dstCoeff) const {
- switch (fProgramDesc.fDualSrcOutput) {
- case ProgramDesc::kNone_DualSrcOutput:
- break;
- // the prog will write a coverage value to the secondary
- // output and the dst is blended by one minus that value.
- case ProgramDesc::kCoverage_DualSrcOutput:
- case ProgramDesc::kCoverageISA_DualSrcOutput:
- case ProgramDesc::kCoverageISC_DualSrcOutput:
- *dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_BlendCoeff;
- break;
- default:
- GrCrash("Unexpected dual source blend output");
- break;
- }
-}
-
-void GrGLProgram::buildKey(GrBinHashKeyBuilder& key) const {
- // Add stage configuration to the key
- key.keyData(reinterpret_cast<const uint32_t*>(&fProgramDesc), sizeof(ProgramDesc));
-}
-
-// assigns modulation of two vars to an output var
-// vars can be vec4s or floats (or one of each)
-// result is always vec4
-// if either var is "" then assign to the other var
-// if both are "" then assign all ones
-static inline void modulate_helper(const char* outputVar,
- const char* var0,
- const char* var1,
- GrStringBuilder* code) {
- GrAssert(NULL != outputVar);
- GrAssert(NULL != var0);
- GrAssert(NULL != var1);
- GrAssert(NULL != code);
-
- bool has0 = '\0' != *var0;
- bool has1 = '\0' != *var1;
-
- if (!has0 && !has1) {
- code->appendf("\t%s = %s;\n", outputVar, all_ones_vec(4));
- } else if (!has0) {
- code->appendf("\t%s = vec4(%s);\n", outputVar, var1);
- } else if (!has1) {
- code->appendf("\t%s = vec4(%s);\n", outputVar, var0);
- } else {
- code->appendf("\t%s = vec4(%s * %s);\n", outputVar, var0, var1);
- }
-}
-
-// assigns addition of two vars to an output var
-// vars can be vec4s or floats (or one of each)
-// result is always vec4
-// if either var is "" then assign to the other var
-// if both are "" then assign all zeros
-static inline void add_helper(const char* outputVar,
- const char* var0,
- const char* var1,
- GrStringBuilder* code) {
- GrAssert(NULL != outputVar);
- GrAssert(NULL != var0);
- GrAssert(NULL != var1);
- GrAssert(NULL != code);
-
- bool has0 = '\0' != *var0;
- bool has1 = '\0' != *var1;
-
- if (!has0 && !has1) {
- code->appendf("\t%s = %s;\n", outputVar, all_zeros_vec(4));
- } else if (!has0) {
- code->appendf("\t%s = vec4(%s);\n", outputVar, var1);
- } else if (!has1) {
- code->appendf("\t%s = vec4(%s);\n", outputVar, var0);
- } else {
- code->appendf("\t%s = vec4(%s + %s);\n", outputVar, var0, var1);
- }
-}
-
-// given two blend coeffecients determine whether the src
-// and/or dst computation can be omitted.
-static inline void needBlendInputs(SkXfermode::Coeff srcCoeff,
- SkXfermode::Coeff dstCoeff,
- bool* needSrcValue,
- bool* needDstValue) {
- if (SkXfermode::kZero_Coeff == srcCoeff) {
- switch (dstCoeff) {
- // these all read the src
- case SkXfermode::kSC_Coeff:
- case SkXfermode::kISC_Coeff:
- case SkXfermode::kSA_Coeff:
- case SkXfermode::kISA_Coeff:
- *needSrcValue = true;
- break;
- default:
- *needSrcValue = false;
- break;
- }
- } else {
- *needSrcValue = true;
- }
- if (SkXfermode::kZero_Coeff == dstCoeff) {
- switch (srcCoeff) {
- // these all read the dst
- case SkXfermode::kDC_Coeff:
- case SkXfermode::kIDC_Coeff:
- case SkXfermode::kDA_Coeff:
- case SkXfermode::kIDA_Coeff:
- *needDstValue = true;
- break;
- default:
- *needDstValue = false;
- break;
- }
- } else {
- *needDstValue = true;
- }
-}
-
-/**
- * Create a blend_coeff * value string to be used in shader code. Sets empty
- * string if result is trivially zero.
- */
-static void blendTermString(GrStringBuilder* str, SkXfermode::Coeff coeff,
- const char* src, const char* dst,
- const char* value) {
- switch (coeff) {
- case SkXfermode::kZero_Coeff: /** 0 */
- *str = "";
- break;
- case SkXfermode::kOne_Coeff: /** 1 */
- *str = value;
- break;
- case SkXfermode::kSC_Coeff:
- str->printf("(%s * %s)", src, value);
- break;
- case SkXfermode::kISC_Coeff:
- str->printf("((%s - %s) * %s)", all_ones_vec(4), src, value);
- break;
- case SkXfermode::kDC_Coeff:
- str->printf("(%s * %s)", dst, value);
- break;
- case SkXfermode::kIDC_Coeff:
- str->printf("((%s - %s) * %s)", all_ones_vec(4), dst, value);
- break;
- case SkXfermode::kSA_Coeff: /** src alpha */
- str->printf("(%s.a * %s)", src, value);
- break;
- case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
- str->printf("((1.0 - %s.a) * %s)", src, value);
- break;
- case SkXfermode::kDA_Coeff: /** dst alpha */
- str->printf("(%s.a * %s)", dst, value);
- break;
- case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
- str->printf("((1.0 - %s.a) * %s)", dst, value);
- break;
- default:
- GrCrash("Unexpected xfer coeff.");
- break;
- }
-}
-/**
- * Adds a line to the fragment shader code which modifies the color by
- * the specified color filter.
- */
-static void addColorFilter(GrStringBuilder* fsCode, const char * outputVar,
- SkXfermode::Coeff uniformCoeff,
- SkXfermode::Coeff colorCoeff,
- const char* inColor) {
- GrStringBuilder colorStr, constStr;
- blendTermString(&colorStr, colorCoeff, COL_FILTER_UNI_NAME,
- inColor, inColor);
- blendTermString(&constStr, uniformCoeff, COL_FILTER_UNI_NAME,
- inColor, COL_FILTER_UNI_NAME);
-
- add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode);
-}
-
-bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
-
- ShaderCodeSegments segments;
- const uint32_t& layout = fProgramDesc.fVertexLayout;
-
- programData->fUniLocations.reset();
-
- SkXfermode::Coeff colorCoeff, uniformCoeff;
- // The rest of transfer mode color filters have not been implemented
- if (fProgramDesc.fColorFilterXfermode < SkXfermode::kCoeffModesCnt) {
- GR_DEBUGCODE(bool success =)
- SkXfermode::ModeAsCoeff(static_cast<SkXfermode::Mode>
- (fProgramDesc.fColorFilterXfermode),
- &uniformCoeff, &colorCoeff);
- GR_DEBUGASSERT(success);
- } else {
- colorCoeff = SkXfermode::kOne_Coeff;
- uniformCoeff = SkXfermode::kZero_Coeff;
- }
-
- bool needColorFilterUniform;
- bool needComputedColor;
- needBlendInputs(uniformCoeff, colorCoeff,
- &needColorFilterUniform, &needComputedColor);
-
- // the dual source output has no canonical var name, have to
- // declare an output, which is incompatible with gl_FragColor/gl_FragData.
- const char* fsColorOutput;
- bool dualSourceOutputWritten = false;
- bool usingDeclaredOutputs = ProgramDesc::kNone_DualSrcOutput !=
- fProgramDesc.fDualSrcOutput;
- if (usingDeclaredOutputs) {
- GrAssert(0 == segments.fHeader.size());
- segments.fHeader.printf("#version 150\n");
- fsColorOutput = declared_color_output_name();
- segments.fFSOutputs.appendf("out vec4 %s;\n", fsColorOutput);
- } else {
- fsColorOutput = "gl_FragColor";
- }
-
-#if GR_GL_ATTRIBUTE_MATRICES
- segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n";
- programData->fUniLocations.fViewMatrixUni = kSetAsAttribute;
-#else
- segments.fVSUnis += "uniform mat3 " VIEW_MATRIX_NAME ";\n";
- programData->fUniLocations.fViewMatrixUni = kUseUniform;
-#endif
- segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
-
- segments.fVSCode.append(
- "void main() {\n"
- "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3("POS_ATTR_NAME", 1);\n"
- "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n");
-
- // incoming color to current stage being processed.
- GrStringBuilder inColor;
-
- if (needComputedColor) {
- switch (fProgramDesc.fColorType) {
- case ProgramDesc::kAttribute_ColorType:
- segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n");
- segments.fVaryings.append("varying vec4 vColor;\n");
- segments.fVSCode.append( "\tvColor = " COL_ATTR_NAME ";\n");
- inColor = "vColor";
- break;
- case ProgramDesc::kUniform_ColorType:
- segments.fFSUnis.append( "uniform vec4 " COL_UNI_NAME ";\n");
- programData->fUniLocations.fColorUni = kUseUniform;
- inColor = COL_UNI_NAME;
- break;
- default:
- GrAssert(ProgramDesc::kNone_ColorType == fProgramDesc.fColorType);
- break;
- }
- }
-
- if (fProgramDesc.fEmitsPointSize){
- segments.fVSCode.append("\tgl_PointSize = 1.0;\n");
- }
-
- segments.fFSCode.append("void main() {\n");
-
- // add texture coordinates that are used to the list of vertex attr decls
- GrStringBuilder texCoordAttrs[GrDrawTarget::kMaxTexCoords];
- for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
- if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
- tex_attr_name(t, texCoordAttrs + t);
- segments.fVSAttrs.appendf("attribute vec2 %s;\n", texCoordAttrs[t].c_str());
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // compute the final color
-
- // if we have color stages string them together, feeding the output color
- // of each to the next and generating code for each stage.
- if (needComputedColor) {
- GrStringBuilder outColor;
- for (int s = 0; s < fProgramDesc.fFirstCoverageStage; ++s) {
- if (fProgramDesc.fStages[s].isEnabled()) {
- // create var to hold stage result
- outColor = "color";
- outColor.appendS32(s);
- segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
-
- const char* inCoords;
- // figure out what our input coords are
- if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) &
- layout) {
- inCoords = POS_ATTR_NAME;
- } else {
- int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
- // we better have input tex coordinates if stage is enabled.
- GrAssert(tcIdx >= 0);
- GrAssert(texCoordAttrs[tcIdx].size());
- inCoords = texCoordAttrs[tcIdx].c_str();
- }
-
- genStageCode(s,
- fProgramDesc.fStages[s],
- inColor.size() ? inColor.c_str() : NULL,
- outColor.c_str(),
- inCoords,
- &segments,
- &programData->fUniLocations.fStages[s]);
- inColor = outColor;
- }
- }
- }
-
- // if have all ones for the "dst" input to the color filter then we can make
- // additional optimizations.
- if (needColorFilterUniform && !inColor.size() &&
- (SkXfermode::kIDC_Coeff == uniformCoeff ||
- SkXfermode::kIDA_Coeff == uniformCoeff)) {
- uniformCoeff = SkXfermode::kZero_Coeff;
- bool bogus;
- needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff,
- &needColorFilterUniform, &bogus);
- }
- if (needColorFilterUniform) {
- segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n");
- programData->fUniLocations.fColorFilterUni = kUseUniform;
- }
-
- bool wroteFragColorZero = false;
- if (SkXfermode::kZero_Coeff == uniformCoeff &&
- SkXfermode::kZero_Coeff == colorCoeff) {
- segments.fFSCode.appendf("\t%s = %s;\n",
- fsColorOutput,
- all_zeros_vec(4));
- wroteFragColorZero = true;
- } else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) {
- segments.fFSCode.appendf("\tvec4 filteredColor;\n");
- const char* color = inColor.size() ? inColor.c_str() : all_ones_vec(4);
- addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff,
- colorCoeff, color);
- inColor = "filteredColor";
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // compute the partial coverage (coverage stages and edge aa)
-
- GrStringBuilder inCoverage;
-
- // we don't need to compute coverage at all if we know the final shader
- // output will be zero and we don't have a dual src blend output.
- if (!wroteFragColorZero ||
- ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) {
- if (fProgramDesc.fEdgeAANumEdges > 0) {
- segments.fFSUnis.append("uniform vec3 " EDGES_UNI_NAME "[");
- segments.fFSUnis.appendS32(fProgramDesc.fEdgeAANumEdges);
- segments.fFSUnis.append("];\n");
- programData->fUniLocations.fEdgesUni = kUseUniform;
- int count = fProgramDesc.fEdgeAANumEdges;
- segments.fFSCode.append(
- "\tvec3 pos = vec3(gl_FragCoord.xy, 1);\n");
- for (int i = 0; i < count; i++) {
- segments.fFSCode.append("\tfloat a");
- segments.fFSCode.appendS32(i);
- segments.fFSCode.append(" = clamp(dot(" EDGES_UNI_NAME "[");
- segments.fFSCode.appendS32(i);
- segments.fFSCode.append("], pos), 0.0, 1.0);\n");
- }
- segments.fFSCode.append("\tfloat edgeAlpha = ");
- for (int i = 0; i < count - 1; i++) {
- segments.fFSCode.append("min(a");
- segments.fFSCode.appendS32(i);
- segments.fFSCode.append(" * a");
- segments.fFSCode.appendS32(i + 1);
- segments.fFSCode.append(", ");
- }
- segments.fFSCode.append("a");
- segments.fFSCode.appendS32(count - 1);
- segments.fFSCode.append(" * a0");
- for (int i = 0; i < count - 1; i++) {
- segments.fFSCode.append(")");
- }
- segments.fFSCode.append(";\n");
- inCoverage = "edgeAlpha";
- }
-
- GrStringBuilder outCoverage;
- const int& startStage = fProgramDesc.fFirstCoverageStage;
- for (int s = startStage; s < GrDrawTarget::kNumStages; ++s) {
- if (fProgramDesc.fStages[s].isEnabled()) {
- // create var to hold stage output
- outCoverage = "coverage";
- outCoverage.appendS32(s);
- segments.fFSCode.appendf("\tvec4 %s;\n", outCoverage.c_str());
-
- const char* inCoords;
- // figure out what our input coords are
- if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
- inCoords = POS_ATTR_NAME;
- } else {
- int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
- // we better have input tex coordinates if stage is enabled.
- GrAssert(tcIdx >= 0);
- GrAssert(texCoordAttrs[tcIdx].size());
- inCoords = texCoordAttrs[tcIdx].c_str();
- }
-
- genStageCode(s,
- fProgramDesc.fStages[s],
- inCoverage.size() ? inCoverage.c_str() : NULL,
- outCoverage.c_str(),
- inCoords,
- &segments,
- &programData->fUniLocations.fStages[s]);
- inCoverage = outCoverage;
- }
- }
- if (ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) {
- segments.fFSOutputs.appendf("out vec4 %s;\n",
- dual_source_output_name());
- bool outputIsZero = false;
- GrStringBuilder coeff;
- if (ProgramDesc::kCoverage_DualSrcOutput !=
- fProgramDesc.fDualSrcOutput && !wroteFragColorZero) {
- if (!inColor.size()) {
- outputIsZero = true;
- } else {
- if (fProgramDesc.fDualSrcOutput ==
- ProgramDesc::kCoverageISA_DualSrcOutput) {
- coeff.printf("(1 - %s.a)", inColor.c_str());
- } else {
- coeff.printf("(vec4(1,1,1,1) - %s)", inColor.c_str());
- }
- }
- }
- if (outputIsZero) {
- segments.fFSCode.appendf("\t%s = %s;\n",
- dual_source_output_name(),
- all_zeros_vec(4));
- } else {
- modulate_helper(dual_source_output_name(),
- coeff.c_str(),
- inCoverage.c_str(),
- &segments.fFSCode);
- }
- dualSourceOutputWritten = true;
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // combine color and coverage as frag color
-
- if (!wroteFragColorZero) {
- modulate_helper(fsColorOutput,
- inColor.c_str(),
- inCoverage.c_str(),
- &segments.fFSCode);
- }
-
- segments.fVSCode.append("}\n");
- segments.fFSCode.append("}\n");
-
- ///////////////////////////////////////////////////////////////////////////
- // compile and setup attribs and unis
-
- if (!CompileFSAndVS(segments, programData)) {
- return false;
- }
-
- if (!this->bindOutputsAttribsAndLinkProgram(texCoordAttrs,
- usingDeclaredOutputs,
- dualSourceOutputWritten,
- programData)) {
- return false;
- }
-
- this->getUniformLocationsAndInitCache(programData);
-
- return true;
-}
-
-bool GrGLProgram::CompileFSAndVS(const ShaderCodeSegments& segments,
- CachedData* programData) {
-
- static const int MAX_STRINGS = 6;
- const char* strings[MAX_STRINGS];
- int lengths[MAX_STRINGS];
- int stringCnt = 0;
-
- if (segments.fHeader.size()) {
- strings[stringCnt] = segments.fHeader.c_str();
- lengths[stringCnt] = segments.fHeader.size();
- ++stringCnt;
- }
- if (segments.fVSUnis.size()) {
- strings[stringCnt] = segments.fVSUnis.c_str();
- lengths[stringCnt] = segments.fVSUnis.size();
- ++stringCnt;
- }
- if (segments.fVSAttrs.size()) {
- strings[stringCnt] = segments.fVSAttrs.c_str();
- lengths[stringCnt] = segments.fVSAttrs.size();
- ++stringCnt;
- }
- if (segments.fVaryings.size()) {
- strings[stringCnt] = segments.fVaryings.c_str();
- lengths[stringCnt] = segments.fVaryings.size();
- ++stringCnt;
- }
-
- GrAssert(segments.fVSCode.size());
- strings[stringCnt] = segments.fVSCode.c_str();
- lengths[stringCnt] = segments.fVSCode.size();
- ++stringCnt;
-
-#if PRINT_SHADERS
- GrPrintf(segments.fHeader.c_str());
- GrPrintf(segments.fVSUnis.c_str());
- GrPrintf(segments.fVSAttrs.c_str());
- GrPrintf(segments.fVaryings.c_str());
- GrPrintf(segments.fVSCode.c_str());
- GrPrintf("\n");
-#endif
- GrAssert(stringCnt <= MAX_STRINGS);
- programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
- stringCnt,
- strings,
- lengths);
-
- if (!programData->fVShaderID) {
- return false;
- }
-
- stringCnt = 0;
-
- if (segments.fHeader.size()) {
- strings[stringCnt] = segments.fHeader.c_str();
- lengths[stringCnt] = segments.fHeader.size();
- ++stringCnt;
- }
- if (strlen(GrShaderPrecision()) > 1) {
- strings[stringCnt] = GrShaderPrecision();
- lengths[stringCnt] = strlen(GrShaderPrecision());
- ++stringCnt;
- }
- if (segments.fFSUnis.size()) {
- strings[stringCnt] = segments.fFSUnis.c_str();
- lengths[stringCnt] = segments.fFSUnis.size();
- ++stringCnt;
- }
- if (segments.fVaryings.size()) {
- strings[stringCnt] = segments.fVaryings.c_str();
- lengths[stringCnt] = segments.fVaryings.size();
- ++stringCnt;
- }
- if (segments.fFSOutputs.size()) {
- strings[stringCnt] = segments.fFSOutputs.c_str();
- lengths[stringCnt] = segments.fFSOutputs.size();
- ++stringCnt;
- }
-
- GrAssert(segments.fFSCode.size());
- strings[stringCnt] = segments.fFSCode.c_str();
- lengths[stringCnt] = segments.fFSCode.size();
- ++stringCnt;
-
-#if PRINT_SHADERS
- GrPrintf(segments.fHeader.c_str());
- GrPrintf(GrShaderPrecision());
- GrPrintf(segments.fFSUnis.c_str());
- GrPrintf(segments.fVaryings.c_str());
- GrPrintf(segments.fFSOutputs.c_str());
- GrPrintf(segments.fFSCode.c_str());
- GrPrintf("\n");
-#endif
- GrAssert(stringCnt <= MAX_STRINGS);
- programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
- stringCnt,
- strings,
- lengths);
-
- if (!programData->fFShaderID) {
- return false;
- }
-
- return true;
-}
-
-GrGLuint GrGLProgram::CompileShader(GrGLenum type,
- int stringCnt,
- const char** strings,
- int* stringLengths) {
- GrGLuint shader = GR_GL(CreateShader(type));
- if (0 == shader) {
- return 0;
- }
-
- GrGLint compiled = GR_GL_INIT_ZERO;
- GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
- GR_GL(CompileShader(shader));
- GR_GL(GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
-
- if (!compiled) {
- GrGLint infoLen = GR_GL_INIT_ZERO;
- GR_GL(GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
- GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
- if (infoLen > 0) {
- GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
- for (int i = 0; i < stringCnt; ++i) {
- if (NULL == stringLengths || stringLengths[i] < 0) {
- GrPrintf(strings[i]);
- } else {
- GrPrintf("%.*s", stringLengths[i], strings[i]);
- }
- }
- GrPrintf("\n%s", log.get());
- }
- GrAssert(!"Shader compilation failed!");
- GR_GL(DeleteShader(shader));
- return 0;
- }
- return shader;
-}
-
-bool GrGLProgram::bindOutputsAttribsAndLinkProgram(
- GrStringBuilder texCoordAttrNames[],
- bool bindColorOut,
- bool bindDualSrcOut,
- CachedData* programData) const {
- programData->fProgramID = GR_GL(CreateProgram());
- if (!programData->fProgramID) {
- return false;
- }
- const GrGLint& progID = programData->fProgramID;
-
- GR_GL(AttachShader(progID, programData->fVShaderID));
- GR_GL(AttachShader(progID, programData->fFShaderID));
-
- if (bindColorOut) {
- GR_GL(BindFragDataLocationIndexed(programData->fProgramID,
- 0, 0, declared_color_output_name()));
- }
- if (bindDualSrcOut) {
- GR_GL(BindFragDataLocationIndexed(programData->fProgramID,
- 0, 1, dual_source_output_name()));
- }
-
- // Bind the attrib locations to same values for all shaders
- GR_GL(BindAttribLocation(progID, PositionAttributeIdx(), POS_ATTR_NAME));
- for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
- if (texCoordAttrNames[t].size()) {
- GR_GL(BindAttribLocation(progID,
- TexCoordAttributeIdx(t),
- texCoordAttrNames[t].c_str()));
- }
- }
-
- if (kSetAsAttribute == programData->fUniLocations.fViewMatrixUni) {
- GR_GL(BindAttribLocation(progID,
- ViewMatrixAttributeIdx(),
- VIEW_MATRIX_NAME));
- }
-
- for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
- const StageUniLocations& unis = programData->fUniLocations.fStages[s];
- if (kSetAsAttribute == unis.fTextureMatrixUni) {
- GrStringBuilder matName;
- tex_matrix_name(s, &matName);
- GR_GL(BindAttribLocation(progID,
- TextureMatrixAttributeIdx(s),
- matName.c_str()));
- }
- }
-
- GR_GL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME));
-
- GR_GL(LinkProgram(progID));
-
- GrGLint linked = GR_GL_INIT_ZERO;
- GR_GL(GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
- if (!linked) {
- GrGLint infoLen = GR_GL_INIT_ZERO;
- GR_GL(GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
- GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
- if (infoLen > 0) {
- GR_GL(GetProgramInfoLog(progID,
- infoLen+1,
- NULL,
- (char*)log.get()));
- GrPrintf((char*)log.get());
- }
- GrAssert(!"Error linking program");
- GR_GL(DeleteProgram(progID));
- programData->fProgramID = 0;
- return false;
- }
- return true;
-}
-
-void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const {
- const GrGLint& progID = programData->fProgramID;
-
- if (kUseUniform == programData->fUniLocations.fViewMatrixUni) {
- programData->fUniLocations.fViewMatrixUni =
- GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
- GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni);
- }
- if (kUseUniform == programData->fUniLocations.fColorUni) {
- programData->fUniLocations.fColorUni =
- GR_GL(GetUniformLocation(progID, COL_UNI_NAME));
- GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni);
- }
- if (kUseUniform == programData->fUniLocations.fColorFilterUni) {
- programData->fUniLocations.fColorFilterUni =
- GR_GL(GetUniformLocation(progID, COL_FILTER_UNI_NAME));
- GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
- }
-
- if (kUseUniform == programData->fUniLocations.fEdgesUni) {
- programData->fUniLocations.fEdgesUni =
- GR_GL(GetUniformLocation(progID, EDGES_UNI_NAME));
- GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni);
- } else {
- programData->fUniLocations.fEdgesUni = kUnusedUniform;
- }
-
- for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
- StageUniLocations& locations = programData->fUniLocations.fStages[s];
- if (fProgramDesc.fStages[s].isEnabled()) {
- if (kUseUniform == locations.fTextureMatrixUni) {
- GrStringBuilder texMName;
- tex_matrix_name(s, &texMName);
- locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
- progID,
- texMName.c_str()));
- GrAssert(kUnusedUniform != locations.fTextureMatrixUni);
- }
-
- if (kUseUniform == locations.fSamplerUni) {
- GrStringBuilder samplerName;
- sampler_name(s, &samplerName);
- locations.fSamplerUni = GR_GL(GetUniformLocation(
- progID,
- samplerName.c_str()));
- GrAssert(kUnusedUniform != locations.fSamplerUni);
- }
-
- if (kUseUniform == locations.fNormalizedTexelSizeUni) {
- GrStringBuilder texelSizeName;
- normalized_texel_size_name(s, &texelSizeName);
- locations.fNormalizedTexelSizeUni =
- GR_GL(GetUniformLocation(progID, texelSizeName.c_str()));
- GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni);
- }
-
- if (kUseUniform == locations.fRadial2Uni) {
- GrStringBuilder radial2ParamName;
- radial2_param_name(s, &radial2ParamName);
- locations.fRadial2Uni = GR_GL(GetUniformLocation(
- progID,
- radial2ParamName.c_str()));
- GrAssert(kUnusedUniform != locations.fRadial2Uni);
- }
-
- if (kUseUniform == locations.fTexDomUni) {
- GrStringBuilder texDomName;
- tex_domain_name(s, &texDomName);
- locations.fTexDomUni = GR_GL(GetUniformLocation(
- progID,
- texDomName.c_str()));
- GrAssert(kUnusedUniform != locations.fTexDomUni);
- }
- }
- }
- GR_GL(UseProgram(progID));
-
- // init sampler unis and set bogus values for state tracking
- for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
- if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) {
- GR_GL(Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
- }
- programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
- programData->fRadial2CenterX1[s] = GR_ScalarMax;
- programData->fRadial2Radius0[s] = -GR_ScalarMax;
- programData->fTextureWidth[s] = -1;
- programData->fTextureHeight[s] = -1;
- }
- programData->fViewMatrix = GrMatrix::InvalidMatrix();
- programData->fColor = GrColor_ILLEGAL;
- programData->fColorFilterColor = GrColor_ILLEGAL;
-}
-
-//============================================================================
-// Stage code generation
-//============================================================================
-
-void GrGLProgram::genStageCode(int stageNum,
- const GrGLProgram::ProgramDesc::StageDesc& desc,
- const char* fsInColor, // NULL means no incoming color
- const char* fsOutColor,
- const char* vsInCoord,
- ShaderCodeSegments* segments,
- StageUniLocations* locations) const {
-
- GrAssert(stageNum >= 0 && stageNum <= 9);
-
- GrStringBuilder varyingName;
- stage_varying_name(stageNum, &varyingName);
-
- // First decide how many coords are needed to access the texture
- // Right now it's always 2 but we could start using 1D textures for
- // gradients.
- static const int coordDims = 2;
- int varyingDims;
- /// Vertex Shader Stuff
-
- // decide whether we need a matrix to transform texture coords
- // and whether the varying needs a perspective coord.
- GrStringBuilder texMName;
- tex_matrix_name(stageNum, &texMName);
- if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
- varyingDims = coordDims;
- } else {
- #if GR_GL_ATTRIBUTE_MATRICES
- segments->fVSAttrs.appendf("attribute mat3 %s;\n", texMName.c_str());
- locations->fTextureMatrixUni = kSetAsAttribute;
- #else
- segments->fVSUnis.appendf("uniform mat3 %s;\n", texMName.c_str());
- locations->fTextureMatrixUni = kUseUniform;
- #endif
- if (desc.fOptFlags & ProgramDesc::StageDesc::kNoPerspective_OptFlagBit) {
- varyingDims = coordDims;
- } else {
- varyingDims = coordDims + 1;
- }
- }
-
- GrStringBuilder samplerName;
- sampler_name(stageNum, &samplerName);
- segments->fFSUnis.appendf("uniform sampler2D %s;\n", samplerName.c_str());
- locations->fSamplerUni = kUseUniform;
-
- GrStringBuilder texelSizeName;
- if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
- normalized_texel_size_name(stageNum, &texelSizeName);
- segments->fFSUnis.appendf("uniform vec2 %s;\n", texelSizeName.c_str());
- }
-
- segments->fVaryings.appendf("varying %s %s;\n",
- float_vector_type(varyingDims), varyingName.c_str());
-
- if (desc.fOptFlags & ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit) {
- GrAssert(varyingDims == coordDims);
- segments->fVSCode.appendf("\t%s = %s;\n", varyingName.c_str(), vsInCoord);
- } else {
- // varying = texMatrix * texCoord
- segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
- varyingName.c_str(), texMName.c_str(),
- vsInCoord, vector_all_coords(varyingDims));
- }
-
- GrStringBuilder radial2ParamsName;
- radial2_param_name(stageNum, &radial2ParamsName);
- // for radial grads without perspective we can pass the linear
- // part of the quadratic as a varying.
- GrStringBuilder radial2VaryingName;
- radial2_varying_name(stageNum, &radial2VaryingName);
-
- if (ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
-
- segments->fVSUnis.appendf("uniform %s float %s[6];\n",
- GrPrecision(), radial2ParamsName.c_str());
- segments->fFSUnis.appendf("uniform float %s[6];\n",
- radial2ParamsName.c_str());
- locations->fRadial2Uni = kUseUniform;
-
- // if there is perspective we don't interpolate this
- if (varyingDims == coordDims) {
- GrAssert(2 == coordDims);
- segments->fVaryings.appendf("varying float %s;\n", radial2VaryingName.c_str());
-
- // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
- segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n",
- radial2VaryingName.c_str(), radial2ParamsName.c_str(),
- varyingName.c_str(), radial2ParamsName.c_str());
- }
- }
-
- /// Fragment Shader Stuff
- GrStringBuilder fsCoordName;
- // function used to access the shader, may be made projective
- GrStringBuilder texFunc("texture2D");
- if (desc.fOptFlags & (ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit |
- ProgramDesc::StageDesc::kNoPerspective_OptFlagBit)) {
- GrAssert(varyingDims == coordDims);
- fsCoordName = varyingName;
- } else {
- // if we have to do some special op on the varyings to get
- // our final tex coords then when in perspective we have to
- // do an explicit divide. Otherwise, we can use a Proj func.
- if (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
- ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) {
- texFunc.append("Proj");
- fsCoordName = varyingName;
- } else {
- fsCoordName = "inCoord";
- fsCoordName.appendS32(stageNum);
- segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
- float_vector_type(coordDims),
- fsCoordName.c_str(),
- varyingName.c_str(),
- vector_nonhomog_coords(varyingDims),
- varyingName.c_str(),
- vector_homog_coord(varyingDims));
- }
- }
-
- GrStringBuilder sampleCoords;
- bool complexCoord = false;
- switch (desc.fCoordMapping) {
- case ProgramDesc::StageDesc::kIdentity_CoordMapping:
- sampleCoords = fsCoordName;
- break;
- case ProgramDesc::StageDesc::kSweepGradient_CoordMapping:
- sampleCoords.printf("vec2(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5, 0.5)", fsCoordName.c_str(), fsCoordName.c_str());
- complexCoord = true;
- break;
- case ProgramDesc::StageDesc::kRadialGradient_CoordMapping:
- sampleCoords.printf("vec2(length(%s.xy), 0.5)", fsCoordName.c_str());
- complexCoord = true;
- break;
- case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: {
- GrStringBuilder cName("c");
- GrStringBuilder ac4Name("ac4");
- GrStringBuilder rootName("root");
-
- cName.appendS32(stageNum);
- ac4Name.appendS32(stageNum);
- rootName.appendS32(stageNum);
-
- // if we were able to interpolate the linear component bVar is the varying
- // otherwise compute it
- GrStringBuilder bVar;
- if (coordDims == varyingDims) {
- bVar = radial2VaryingName;
- GrAssert(2 == varyingDims);
- } else {
- GrAssert(3 == varyingDims);
- bVar = "b";
- bVar.appendS32(stageNum);
- segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n",
- bVar.c_str(), radial2ParamsName.c_str(),
- fsCoordName.c_str(), radial2ParamsName.c_str());
- }
-
- // c = (x^2)+(y^2) - params[4]
- segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n",
- cName.c_str(), fsCoordName.c_str(),
- fsCoordName.c_str(),
- radial2ParamsName.c_str());
- // ac4 = 4.0 * params[0] * c
- segments->fFSCode.appendf("\tfloat %s = %s[0] * 4.0 * %s;\n",
- ac4Name.c_str(), radial2ParamsName.c_str(),
- cName.c_str());
-
- // root = sqrt(b^2-4ac)
- // (abs to avoid exception due to fp precision)
- segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
- rootName.c_str(), bVar.c_str(), bVar.c_str(),
- ac4Name.c_str());
-
- // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
- // y coord is 0.5 (texture is effectively 1D)
- sampleCoords.printf("vec2((-%s + %s[5] * %s) * %s[1], 0.5)",
- bVar.c_str(), radial2ParamsName.c_str(),
- rootName.c_str(), radial2ParamsName.c_str());
- complexCoord = true;
- break;}
- };
-
- const char* smear;
- if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
- smear = ".aaaa";
- } else {
- smear = "";
- }
- GrStringBuilder modulate;
- if (NULL != fsInColor) {
- modulate.printf(" * %s", fsInColor);
- }
-
- if (desc.fOptFlags &
- ProgramDesc::StageDesc::kCustomTextureDomain_OptFlagBit) {
- GrStringBuilder texDomainName;
- tex_domain_name(stageNum, &texDomainName);
- segments->fFSUnis.appendf("uniform %s %s;\n",
- float_vector_type(4),
- texDomainName.c_str());
- GrStringBuilder coordVar("clampCoord");
- segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n",
- float_vector_type(coordDims),
- coordVar.c_str(),
- sampleCoords.c_str(),
- texDomainName.c_str(),
- texDomainName.c_str());
- sampleCoords = coordVar;
- locations->fTexDomUni = kUseUniform;
- }
-
- if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
- locations->fNormalizedTexelSizeUni = kUseUniform;
- if (complexCoord) {
- // assign the coord to a var rather than compute 4x.
- GrStringBuilder coordVar("tCoord");
- coordVar.appendS32(stageNum);
- segments->fFSCode.appendf("\t%s %s = %s;\n",
- float_vector_type(coordDims),
- coordVar.c_str(), sampleCoords.c_str());
- sampleCoords = coordVar;
- }
- GrAssert(2 == coordDims);
- GrStringBuilder accumVar("accum");
- accumVar.appendS32(stageNum);
- segments->fFSCode.appendf("\tvec4 %s = %s(%s, %s + vec2(-%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
- segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
- segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(-%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
- segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
- segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
- } else {
- segments->fFSCode.appendf("\t%s = %s(%s, %s)%s%s;\n", fsOutColor, texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), smear, modulate.c_str());
- }
-}
diff --git a/gpu/src/GrGLProgram.h b/gpu/src/GrGLProgram.h
deleted file mode 100644
index 473bcb6..0000000
--- a/gpu/src/GrGLProgram.h
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#ifndef GrGLProgram_DEFINED
-#define GrGLProgram_DEFINED
-
-#include "GrGLInterface.h"
-#include "GrStringBuilder.h"
-#include "GrGpu.h"
-
-#include "SkXfermode.h"
-
-class GrBinHashKeyBuilder;
-
-struct ShaderCodeSegments {
- GrStringBuilder fHeader; // VS+FS, GLSL version, etc
- GrStringBuilder fVSUnis;
- GrStringBuilder fVSAttrs;
- GrStringBuilder fVaryings;
- GrStringBuilder fFSUnis;
- GrStringBuilder fFSOutputs;
- GrStringBuilder fVSCode;
- GrStringBuilder fFSCode;
-};
-
-/**
- * This class manages a GPU program and records per-program information.
- * We can specify the attribute locations so that they are constant
- * across our shaders. But the driver determines the uniform locations
- * at link time. We don't need to remember the sampler uniform location
- * because we will bind a texture slot to it and never change it
- * Uniforms are program-local so we can't rely on fHWState to hold the
- * previous uniform state after a program change.
- */
-class GrGLProgram {
-public:
- class CachedData;
-
- GrGLProgram();
- ~GrGLProgram();
-
- /**
- * Streams data that can uniquely identifies the generated
- * gpu program into a key, for cache indexing purposes.
- *
- * @param key The key object to receive the key data
- */
- void buildKey(GrBinHashKeyBuilder& key) const;
-
- /**
- * This is the heavy initilization routine for building a GLProgram.
- * The result of heavy init is not stored in datamembers of GrGLProgam,
- * but in a separate cacheable container.
- */
- bool genProgram(CachedData* programData) const;
-
- /**
- * The shader may modify the blend coeffecients. Params are in/out
- */
- void overrideBlend(GrBlendCoeff* srcCoeff, GrBlendCoeff* dstCoeff) const;
-
- /**
- * Attribute indices
- */
- static int PositionAttributeIdx() { return 0; }
- static int TexCoordAttributeIdx(int tcIdx) { return 1 + tcIdx; }
- static int ColorAttributeIdx() { return 1 + GrDrawTarget::kMaxTexCoords; }
- static int ViewMatrixAttributeIdx() {
- return 2 + GrDrawTarget::kMaxTexCoords;
- }
- static int TextureMatrixAttributeIdx(int stage) {
- return 5 + GrDrawTarget::kMaxTexCoords + 3 * stage;
- }
-
-private:
-
- // Parameters that affect code generation
- // These structs should be kept compact; they are the input to an
- // expensive hash key generator.
- struct ProgramDesc {
- ProgramDesc() {
- // since we use this as part of a key we can't have any unitialized
- // padding
- memset(this, 0, sizeof(ProgramDesc));
- }
-
- struct StageDesc {
- enum OptFlagBits {
- kNoPerspective_OptFlagBit = 1 << 0,
- kIdentityMatrix_OptFlagBit = 1 << 1,
- kCustomTextureDomain_OptFlagBit = 1 << 2,
- kIsEnabled_OptFlagBit = 1 << 7
- };
- enum Modulation {
- kColor_Modulation,
- kAlpha_Modulation
- };
- enum FetchMode {
- kSingle_FetchMode,
- k2x2_FetchMode
- };
- enum CoordMapping {
- kIdentity_CoordMapping,
- kRadialGradient_CoordMapping,
- kSweepGradient_CoordMapping,
- kRadial2Gradient_CoordMapping
- };
-
- uint8_t fOptFlags;
- uint8_t fModulation; // casts to enum Modulation
- uint8_t fFetchMode; // casts to enum FetchMode
- uint8_t fCoordMapping; // casts to enum CoordMapping
-
- inline bool isEnabled() const {
- return fOptFlags & kIsEnabled_OptFlagBit;
- }
- inline void setEnabled(bool newValue) {
- if (newValue) {
- fOptFlags |= kIsEnabled_OptFlagBit;
- } else {
- fOptFlags &= ~kIsEnabled_OptFlagBit;
- }
- }
- };
-
- enum ColorType {
- kNone_ColorType = 0,
- kAttribute_ColorType = 1,
- kUniform_ColorType = 2,
- };
- // Dual-src blending makes use of a secondary output color that can be
- // used as a per-pixel blend coeffecient. This controls whether a
- // secondary source is output and what value it holds.
- enum DualSrcOutput {
- kNone_DualSrcOutput,
- kCoverage_DualSrcOutput,
- kCoverageISA_DualSrcOutput,
- kCoverageISC_DualSrcOutput,
- kDualSrcOutputCnt
- };
-
- // stripped of bits that don't affect prog generation
- GrVertexLayout fVertexLayout;
-
- StageDesc fStages[GrDrawTarget::kNumStages];
-
- uint8_t fColorType; // casts to enum ColorType
- uint8_t fDualSrcOutput; // casts to enum DualSrcOutput
- int8_t fFirstCoverageStage;
- SkBool8 fEmitsPointSize;
-
- int8_t fEdgeAANumEdges;
- uint8_t fColorFilterXfermode; // casts to enum SkXfermode::Mode
-
- uint8_t fPadTo32bLengthMultiple [2];
-
- } fProgramDesc;
-
- const ProgramDesc& getDesc() { return fProgramDesc; }
-
-public:
- enum {
- kUnusedUniform = -1,
- kSetAsAttribute = 1000,
- };
-
- struct StageUniLocations {
- GrGLint fTextureMatrixUni;
- GrGLint fNormalizedTexelSizeUni;
- GrGLint fSamplerUni;
- GrGLint fRadial2Uni;
- GrGLint fTexDomUni;
- void reset() {
- fTextureMatrixUni = kUnusedUniform;
- fNormalizedTexelSizeUni = kUnusedUniform;
- fSamplerUni = kUnusedUniform;
- fRadial2Uni = kUnusedUniform;
- fTexDomUni = kUnusedUniform;
- }
- };
-
- struct UniLocations {
- GrGLint fViewMatrixUni;
- GrGLint fColorUni;
- GrGLint fEdgesUni;
- GrGLint fColorFilterUni;
- StageUniLocations fStages[GrDrawTarget::kNumStages];
- void reset() {
- fViewMatrixUni = kUnusedUniform;
- fColorUni = kUnusedUniform;
- fEdgesUni = kUnusedUniform;
- fColorFilterUni = kUnusedUniform;
- for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
- fStages[s].reset();
- }
- }
- };
-
- class CachedData : public ::GrNoncopyable {
- public:
- CachedData() {
- }
-
- ~CachedData() {
- }
-
- void copyAndTakeOwnership(CachedData& other) {
- memcpy(this, &other, sizeof(*this));
- }
-
- public:
-
- // IDs
- GrGLuint fVShaderID;
- GrGLuint fFShaderID;
- GrGLuint fProgramID;
- // shader uniform locations (-1 if shader doesn't use them)
- UniLocations fUniLocations;
-
- GrMatrix fViewMatrix;
-
- // these reflect the current values of uniforms
- // (GL uniform values travel with program)
- GrColor fColor;
- GrColor fColorFilterColor;
- GrMatrix fTextureMatrices[GrDrawTarget::kNumStages];
- // width and height used for normalized texel size
- int fTextureWidth[GrDrawTarget::kNumStages];
- int fTextureHeight[GrDrawTarget::kNumStages];
- GrScalar fRadial2CenterX1[GrDrawTarget::kNumStages];
- GrScalar fRadial2Radius0[GrDrawTarget::kNumStages];
- bool fRadial2PosRoot[GrDrawTarget::kNumStages];
- GrRect fTextureDomain[GrDrawTarget::kNumStages];
-
- private:
- enum Constants {
- kUniLocationPreAllocSize = 8
- };
-
- }; // CachedData
-
-private:
- enum {
- kUseUniform = 2000
- };
-
- // should set all fields in locations var to kUseUniform if the
- // corresponding uniform is required for the program.
- void genStageCode(int stageNum,
- const ProgramDesc::StageDesc& desc,
- const char* fsInColor, // NULL means no incoming color
- const char* fsOutColor,
- const char* vsInCoord,
- ShaderCodeSegments* segments,
- StageUniLocations* locations) const;
-
- static bool CompileFSAndVS(const ShaderCodeSegments& segments,
- CachedData* programData);
-
- // Compiles a GL shader, returns shader ID or 0 if failed
- // params have same meaning as glShaderSource
- static GrGLuint CompileShader(GrGLenum type, int stringCnt,
- const char** strings,
- int* stringLengths);
-
- // Creates a GL program ID, binds shader attributes to GL vertex attrs, and
- // links the program
- bool bindOutputsAttribsAndLinkProgram(
- GrStringBuilder texCoordAttrNames[GrDrawTarget::kMaxTexCoords],
- bool bindColorOut,
- bool bindDualSrcOut,
- CachedData* programData) const;
-
- // Gets locations for all uniforms set to kUseUniform and initializes cache
- // to invalid values.
- void getUniformLocationsAndInitCache(CachedData* programData) const;
-
- friend class GrGpuGLShaders;
-};
-
-#endif
diff --git a/gpu/src/GrGLTexture.cpp b/gpu/src/GrGLTexture.cpp
deleted file mode 100644
index d3ccfa6..0000000
--- a/gpu/src/GrGLTexture.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#include "GrGLTexture.h"
-#include "GrGpuGL.h"
-
-#define GPUGL static_cast<GrGpuGL*>(getGpu())
-
-GrGLRenderTarget::GrGLRenderTarget(GrGpuGL* gpu,
- const GLRenderTargetIDs& ids,
- GrGLTexID* texID,
- GrGLuint stencilBits,
- bool isMultisampled,
- const GrGLIRect& viewport,
- GrGLTexture* texture)
- : INHERITED(gpu, texture, viewport.fWidth,
- viewport.fHeight, stencilBits, isMultisampled) {
- fRTFBOID = ids.fRTFBOID;
- fTexFBOID = ids.fTexFBOID;
- fStencilRenderbufferID = ids.fStencilRenderbufferID;
- fMSColorRenderbufferID = ids.fMSColorRenderbufferID;
- fViewport = viewport;
- fOwnIDs = ids.fOwnIDs;
- fTexIDObj = texID;
- GrSafeRef(fTexIDObj);
-}
-
-void GrGLRenderTarget::onRelease() {
- if (fOwnIDs) {
- if (fTexFBOID) {
- GPUGL->notifyRenderTargetDelete(this);
- GR_GL(DeleteFramebuffers(1, &fTexFBOID));
- }
- if (fRTFBOID && fRTFBOID != fTexFBOID) {
- GR_GL(DeleteFramebuffers(1, &fRTFBOID));
- }
- if (fStencilRenderbufferID) {
- GR_GL(DeleteRenderbuffers(1, &fStencilRenderbufferID));
- }
- if (fMSColorRenderbufferID) {
- GR_GL(DeleteRenderbuffers(1, &fMSColorRenderbufferID));
- }
- }
- fRTFBOID = 0;
- fTexFBOID = 0;
- fStencilRenderbufferID = 0;
- fMSColorRenderbufferID = 0;
- GrSafeUnref(fTexIDObj);
- fTexIDObj = NULL;
-}
-
-void GrGLRenderTarget::onAbandon() {
- fRTFBOID = 0;
- fTexFBOID = 0;
- fStencilRenderbufferID = 0;
- fMSColorRenderbufferID = 0;
- if (NULL != fTexIDObj) {
- fTexIDObj->abandon();
- fTexIDObj = NULL;
- }
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
-
-const GrGLenum* GrGLTexture::WrapMode2GLWrap() {
- static const GrGLenum mirrorRepeatModes[] = {
- GR_GL_CLAMP_TO_EDGE,
- GR_GL_REPEAT,
- GR_GL_MIRRORED_REPEAT
- };
-
- static const GrGLenum repeatModes[] = {
- GR_GL_CLAMP_TO_EDGE,
- GR_GL_REPEAT,
- GR_GL_REPEAT
- };
-
- if (GR_GL_SUPPORT_ES1 && !GR_GL_SUPPORT_ES2) {
- return repeatModes; // GL_MIRRORED_REPEAT not supported.
- } else {
- return mirrorRepeatModes;
- }
-};
-
-GrGLTexture::GrGLTexture(GrGpuGL* gpu,
- const GLTextureDesc& textureDesc,
- const GLRenderTargetIDs& rtIDs,
- const TexParams& initialTexParams)
- : INHERITED(gpu,
- textureDesc.fContentWidth,
- textureDesc.fContentHeight,
- textureDesc.fFormat) {
-
- fTexParams = initialTexParams;
- fTexIDObj = new GrGLTexID(textureDesc.fTextureID,
- textureDesc.fOwnsID);
- fUploadFormat = textureDesc.fUploadFormat;
- fUploadByteCount = textureDesc.fUploadByteCount;
- fUploadType = textureDesc.fUploadType;
- fOrientation = textureDesc.fOrientation;
- fAllocWidth = textureDesc.fAllocWidth;
- fAllocHeight = textureDesc.fAllocHeight;
- fScaleX = GrIntToScalar(textureDesc.fContentWidth) /
- textureDesc.fAllocWidth;
- fScaleY = GrIntToScalar(textureDesc.fContentHeight) /
- textureDesc.fAllocHeight;
-
- GrAssert(0 != textureDesc.fTextureID);
-
- if (rtIDs.fTexFBOID) {
- // we render to the top left
- GrGLIRect vp;
- vp.fLeft = 0;
- vp.fWidth = textureDesc.fContentWidth;
- vp.fHeight = textureDesc.fContentHeight;
- vp.fBottom = textureDesc.fAllocHeight - textureDesc.fContentHeight;
-
- fRenderTarget = new GrGLRenderTarget(gpu, rtIDs, fTexIDObj,
- textureDesc.fStencilBits,
- rtIDs.fRTFBOID != rtIDs.fTexFBOID,
- vp, this);
- }
-}
-
-void GrGLTexture::onRelease() {
- INHERITED::onRelease();
- if (NULL != fTexIDObj) {
- GPUGL->notifyTextureDelete(this);
- fTexIDObj->unref();
- fTexIDObj = NULL;
- }
-}
-
-void GrGLTexture::onAbandon() {
- INHERITED::onAbandon();
- if (NULL != fTexIDObj) {
- fTexIDObj->abandon();
- }
-}
-
-void GrGLTexture::uploadTextureData(uint32_t x,
- uint32_t y,
- uint32_t width,
- uint32_t height,
- const void* srcData) {
-
- GPUGL->setSpareTextureUnit();
-
- // glCompressedTexSubImage2D doesn't support any formats
- // (at least without extensions)
- GrAssert(fUploadFormat != GR_GL_PALETTE8_RGBA8);
-
- // If we need to update textures that are created upside down
- // then we have to modify this code to flip the srcData
- GrAssert(kTopDown_Orientation == fOrientation);
- GR_GL(BindTexture(GR_GL_TEXTURE_2D, fTexIDObj->id()));
- GR_GL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, fUploadByteCount));
- GR_GL(TexSubImage2D(GR_GL_TEXTURE_2D, 0, x, y, width, height,
- fUploadFormat, fUploadType, srcData));
-
-}
-
-intptr_t GrGLTexture::getTextureHandle() {
- return fTexIDObj->id();
-}
-
diff --git a/gpu/src/GrGLUtil.cpp b/gpu/src/GrGLUtil.cpp
deleted file mode 100644
index 04e25fd..0000000
--- a/gpu/src/GrGLUtil.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "GrGLConfig.h"
-#include "GrGLInterface.h"
-
-void GrGLClearErr() {
- while (GR_GL_NO_ERROR != GrGLGetGLInterface()->fGetError()) {}
-}
-
-void GrGLCheckErr(const char* location, const char* call) {
- uint32_t err = GrGLGetGLInterface()->fGetError();
- if (GR_GL_NO_ERROR != err) {
- GrPrintf("---- glGetError %x", err);
- if (NULL != location) {
- GrPrintf(" at\n\t%s", location);
- }
- if (NULL != call) {
- GrPrintf("\n\t\t%s", call);
- }
- GrPrintf("\n");
- }
-}
-
-void GrGLRestoreResetRowLength() {
- if (GR_GL_SUPPORT_DESKTOP) {
- GR_GL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-#if GR_GL_LOG_CALLS
- bool gLogCallsGL = !!(GR_GL_LOG_CALLS_START);
-#endif
-
-#if GR_GL_CHECK_ERROR
- bool gCheckErrorGL = !!(GR_GL_CHECK_ERROR_START);
-#endif
-
diff --git a/gpu/src/GrGLVertexBuffer.cpp b/gpu/src/GrGLVertexBuffer.cpp
deleted file mode 100644
index 3fa1425..0000000
--- a/gpu/src/GrGLVertexBuffer.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#include "GrGLVertexBuffer.h"
-#include "GrGpuGL.h"
-
-#define GPUGL static_cast<GrGpuGL*>(getGpu())
-
-GrGLVertexBuffer::GrGLVertexBuffer(GrGpuGL* gpu,
- GrGLuint id,
- size_t sizeInBytes,
- bool dynamic)
- : INHERITED(gpu, sizeInBytes, dynamic)
- , fBufferID(id)
- , fLockPtr(NULL) {
-}
-
-void GrGLVertexBuffer::onRelease() {
- // make sure we've not been abandoned
- if (fBufferID) {
- GPUGL->notifyVertexBufferDelete(this);
- GR_GL(DeleteBuffers(1, &fBufferID));
- fBufferID = 0;
- }
-}
-
-void GrGLVertexBuffer::onAbandon() {
- fBufferID = 0;
- fLockPtr = NULL;
-}
-
-void GrGLVertexBuffer::bind() const {
- GR_GL(BindBuffer(GR_GL_ARRAY_BUFFER, fBufferID));
- GPUGL->notifyVertexBufferBind(this);
-}
-
-GrGLuint GrGLVertexBuffer::bufferID() const {
- return fBufferID;
-}
-
-void* GrGLVertexBuffer::lock() {
- GrAssert(fBufferID);
- GrAssert(!isLocked());
- if (GPUGL->supportsBufferLocking()) {
- this->bind();
- // Let driver know it can discard the old data
- GR_GL(BufferData(GR_GL_ARRAY_BUFFER, size(), NULL,
- dynamic() ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW));
- fLockPtr = GR_GL(MapBuffer(GR_GL_ARRAY_BUFFER, GR_GL_WRITE_ONLY));
- return fLockPtr;
- }
- return NULL;
-}
-
-void* GrGLVertexBuffer::lockPtr() const {
- return fLockPtr;
-}
-
-void GrGLVertexBuffer::unlock() {
-
- GrAssert(fBufferID);
- GrAssert(isLocked());
- GrAssert(GPUGL->supportsBufferLocking());
-
- this->bind();
- GR_GL(UnmapBuffer(GR_GL_ARRAY_BUFFER));
- fLockPtr = NULL;
-}
-
-bool GrGLVertexBuffer::isLocked() const {
- GrAssert(!this->isValid() || fBufferID);
-#if GR_DEBUG
- if (this->isValid() && GPUGL->supportsBufferLocking()) {
- GrGLint mapped;
- this->bind();
- GR_GL(GetBufferParameteriv(GR_GL_ARRAY_BUFFER, GR_GL_BUFFER_MAPPED, &mapped));
- GrAssert(!!mapped == !!fLockPtr);
- }
-#endif
- return NULL != fLockPtr;
-}
-
-bool GrGLVertexBuffer::updateData(const void* src, size_t srcSizeInBytes) {
- GrAssert(fBufferID);
- GrAssert(!isLocked());
- if (srcSizeInBytes > size()) {
- return false;
- }
- this->bind();
- GrGLenum usage = dynamic() ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW;
- if (size() == srcSizeInBytes) {
- GR_GL(BufferData(GR_GL_ARRAY_BUFFER, srcSizeInBytes, src, usage));
- } else {
- GR_GL(BufferData(GR_GL_ARRAY_BUFFER, size(), NULL, usage));
- GR_GL(BufferSubData(GR_GL_ARRAY_BUFFER, 0, srcSizeInBytes, src));
- }
- return true;
-}
-
-bool GrGLVertexBuffer::updateSubData(const void* src,
- size_t srcSizeInBytes,
- size_t offset) {
- GrAssert(fBufferID);
- GrAssert(!isLocked());
- if (srcSizeInBytes + offset > size()) {
- return false;
- }
- this->bind();
- GR_GL(BufferSubData(GR_GL_ARRAY_BUFFER, offset, srcSizeInBytes, src));
- return true;
-}
-
diff --git a/gpu/src/GrGpuFactory.cpp b/gpu/src/GrGpuFactory.cpp
deleted file mode 100644
index 38c07b7..0000000
--- a/gpu/src/GrGpuFactory.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "GrTypes.h"
-
-// must be before GrGLConfig.h
-#if GR_WIN32_BUILD
-// #include "GrGpuD3D9.h"
-#endif
-
-#include "GrGLConfig.h"
-
-#include "GrGpu.h"
-#include "GrGpuGLFixed.h"
-#include "GrGpuGLShaders.h"
-
-GrGpu* GrGpu::Create(GrEngine engine, GrPlatform3DContext context3D) {
-
- if (kOpenGL_Shaders_GrEngine == engine ||
- kOpenGL_Fixed_GrEngine == engine) {
- // If no GL bindings have been installed, fall-back to calling the
- // GL functions that have been linked with the executable.
- if (!GrGLGetGLInterface()) {
- GrGLSetDefaultGLInterface();
- // If there is no platform-default then just fail.
- if (!GrGLGetGLInterface()) {
- return NULL;
- }
- }
- if (!GrGLGetGLInterface()->validate(engine)) {
-#if GR_DEBUG
- GrPrintf("Failed GL interface validation!");
-#endif
- return NULL;
- }
- }
-
- GrGpu* gpu = NULL;
-
- switch (engine) {
- case kOpenGL_Shaders_GrEngine:
- GrAssert(NULL == (void*)context3D);
- {
-#if 0 // old code path, will be removed soon
- gpu = new GrGpuGLShaders2;
-#else
- gpu = new GrGpuGLShaders;
-#endif
- }
- break;
- case kOpenGL_Fixed_GrEngine:
- GrAssert(NULL == (void*)context3D);
- gpu = new GrGpuGLFixed;
- break;
- case kDirect3D9_GrEngine:
- GrAssert(NULL != (void*)context3D);
-#if GR_WIN32_BUILD
-// gpu = new GrGpuD3D9((IDirect3DDevice9*)context3D);
-#endif
- break;
- default:
- GrAssert(!"unknown engine");
- break;
- }
-
- return gpu;
-}
diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp
deleted file mode 100644
index ff2d406..0000000
--- a/gpu/src/GrGpuGL.cpp
+++ /dev/null
@@ -1,2076 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "GrGpuGL.h"
-#include "GrMemory.h"
-#include "GrTypes.h"
-
-static const GrGLuint GR_MAX_GLUINT = ~0;
-static const GrGLint GR_INVAL_GLINT = ~0;
-
-// we use a spare texture unit to avoid
-// mucking with the state of any of the stages.
-static const int SPARE_TEX_UNIT = GrGpuGL::kNumStages;
-
-#define SKIP_CACHE_CHECK true
-
-static const GrGLenum gXfermodeCoeff2Blend[] = {
- GR_GL_ZERO,
- GR_GL_ONE,
- GR_GL_SRC_COLOR,
- GR_GL_ONE_MINUS_SRC_COLOR,
- GR_GL_DST_COLOR,
- GR_GL_ONE_MINUS_DST_COLOR,
- GR_GL_SRC_ALPHA,
- GR_GL_ONE_MINUS_SRC_ALPHA,
- GR_GL_DST_ALPHA,
- GR_GL_ONE_MINUS_DST_ALPHA,
- GR_GL_CONSTANT_COLOR,
- GR_GL_ONE_MINUS_CONSTANT_COLOR,
- GR_GL_CONSTANT_ALPHA,
- GR_GL_ONE_MINUS_CONSTANT_ALPHA,
-
- // extended blend coeffs
- GR_GL_SRC1_COLOR,
- GR_GL_ONE_MINUS_SRC1_COLOR,
- GR_GL_SRC1_ALPHA,
- GR_GL_ONE_MINUS_SRC1_ALPHA,
-};
-
-bool GrGpuGL::BlendCoeffReferencesConstant(GrBlendCoeff coeff) {
- static const bool gCoeffReferencesBlendConst[] = {
- false,
- false,
- false,
- false,
- false,
- false,
- false,
- false,
- false,
- false,
- true,
- true,
- true,
- true,
-
- // extended blend coeffs
- false,
- false,
- false,
- false,
- };
- return gCoeffReferencesBlendConst[coeff];
- GR_STATIC_ASSERT(kTotalBlendCoeffCount == GR_ARRAY_COUNT(gCoeffReferencesBlendConst));
-
- GR_STATIC_ASSERT(0 == kZero_BlendCoeff);
- GR_STATIC_ASSERT(1 == kOne_BlendCoeff);
- GR_STATIC_ASSERT(2 == kSC_BlendCoeff);
- GR_STATIC_ASSERT(3 == kISC_BlendCoeff);
- GR_STATIC_ASSERT(4 == kDC_BlendCoeff);
- GR_STATIC_ASSERT(5 == kIDC_BlendCoeff);
- GR_STATIC_ASSERT(6 == kSA_BlendCoeff);
- GR_STATIC_ASSERT(7 == kISA_BlendCoeff);
- GR_STATIC_ASSERT(8 == kDA_BlendCoeff);
- GR_STATIC_ASSERT(9 == kIDA_BlendCoeff);
- GR_STATIC_ASSERT(10 == kConstC_BlendCoeff);
- GR_STATIC_ASSERT(11 == kIConstC_BlendCoeff);
- GR_STATIC_ASSERT(12 == kConstA_BlendCoeff);
- GR_STATIC_ASSERT(13 == kIConstA_BlendCoeff);
-
- GR_STATIC_ASSERT(14 == kS2C_BlendCoeff);
- GR_STATIC_ASSERT(15 == kIS2C_BlendCoeff);
- GR_STATIC_ASSERT(16 == kS2A_BlendCoeff);
- GR_STATIC_ASSERT(17 == kIS2A_BlendCoeff);
-
- // assertion for gXfermodeCoeff2Blend have to be in GrGpu scope
- GR_STATIC_ASSERT(kTotalBlendCoeffCount == GR_ARRAY_COUNT(gXfermodeCoeff2Blend));
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-void GrGpuGL::AdjustTextureMatrix(const GrGLTexture* texture,
- GrSamplerState::SampleMode mode,
- GrMatrix* matrix) {
- GrAssert(NULL != texture);
- GrAssert(NULL != matrix);
- if (GR_Scalar1 != texture->contentScaleX() ||
- GR_Scalar1 != texture->contentScaleY()) {
- if (GrSamplerState::kRadial_SampleMode == mode) {
- GrMatrix scale;
- scale.setScale(texture->contentScaleX(), texture->contentScaleX());
- matrix->postConcat(scale);
- } else if (GrSamplerState::kNormal_SampleMode == mode) {
- GrMatrix scale;
- scale.setScale(texture->contentScaleX(), texture->contentScaleY());
- matrix->postConcat(scale);
- } else {
- GrPrintf("We haven't handled NPOT adjustment for other sample modes!");
- }
- }
- GrGLTexture::Orientation orientation = texture->orientation();
- if (GrGLTexture::kBottomUp_Orientation == orientation) {
- GrMatrix invY;
- invY.setAll(GR_Scalar1, 0, 0,
- 0, -GR_Scalar1, GR_Scalar1,
- 0, 0, GrMatrix::I()[8]);
- matrix->postConcat(invY);
- } else {
- GrAssert(GrGLTexture::kTopDown_Orientation == orientation);
- }
-}
-
-bool GrGpuGL::TextureMatrixIsIdentity(const GrGLTexture* texture,
- const GrSamplerState& sampler) {
- GrAssert(NULL != texture);
- if (!sampler.getMatrix().isIdentity()) {
- return false;
- }
- if (GR_Scalar1 != texture->contentScaleX() ||
- GR_Scalar1 != texture->contentScaleY()) {
- return false;
- }
- GrGLTexture::Orientation orientation = texture->orientation();
- if (GrGLTexture::kBottomUp_Orientation == orientation) {
- return false;
- } else {
- GrAssert(GrGLTexture::kTopDown_Orientation == orientation);
- }
- return true;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static bool gPrintStartupSpew;
-
-static bool fbo_test(int w, int h) {
-
- GrGLint savedFBO;
- GrGLint savedTexUnit;
- GR_GL_GetIntegerv(GR_GL_ACTIVE_TEXTURE, &savedTexUnit);
- GR_GL_GetIntegerv(GR_GL_FRAMEBUFFER_BINDING, &savedFBO);
-
- GR_GL(ActiveTexture(GR_GL_TEXTURE0 + SPARE_TEX_UNIT));
-
- GrGLuint testFBO;
- GR_GL(GenFramebuffers(1, &testFBO));
- GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, testFBO));
- GrGLuint testRTTex;
- GR_GL(GenTextures(1, &testRTTex));
- GR_GL(BindTexture(GR_GL_TEXTURE_2D, testRTTex));
- // some implementations require texture to be mip-map complete before
- // FBO with level 0 bound as color attachment will be framebuffer complete.
- GR_GL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER, GR_GL_NEAREST));
- GR_GL(TexImage2D(GR_GL_TEXTURE_2D, 0, GR_GL_RGBA, w, h,
- 0, GR_GL_RGBA, GR_GL_UNSIGNED_BYTE, NULL));
- GR_GL(BindTexture(GR_GL_TEXTURE_2D, 0));
- GR_GL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0,
- GR_GL_TEXTURE_2D, testRTTex, 0));
- GrGLenum status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
- GR_GL(DeleteFramebuffers(1, &testFBO));
- GR_GL(DeleteTextures(1, &testRTTex));
-
- GR_GL(ActiveTexture(savedTexUnit));
- GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, savedFBO));
-
- return status == GR_GL_FRAMEBUFFER_COMPLETE;
-}
-
-GrGpuGL::GrGpuGL() {
-
- if (gPrintStartupSpew) {
- GrPrintf("------------------------- create GrGpuGL %p --------------\n",
- this);
- GrPrintf("------ VENDOR %s\n",
- GrGLGetGLInterface()->fGetString(GR_GL_VENDOR));
- GrPrintf("------ RENDERER %s\n",
- GrGLGetGLInterface()->fGetString(GR_GL_RENDERER));
- GrPrintf("------ VERSION %s\n",
- GrGLGetGLInterface()->fGetString(GR_GL_VERSION));
- GrPrintf("------ EXTENSIONS\n %s \n",
- GrGLGetGLInterface()->fGetString(GR_GL_EXTENSIONS));
- }
-
- GrGLClearErr();
-
- resetDirtyFlags();
-
- GrGLint maxTextureUnits;
- // check FS and fixed-function texture unit limits
- // we only use textures in the fragment stage currently.
- // checks are > to make sure we have a spare unit.
- if (GR_GL_SUPPORT_DESKTOP || GR_GL_SUPPORT_ES2) {
- GR_GL_GetIntegerv(GR_GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
- GrAssert(maxTextureUnits > kNumStages);
- }
- if (GR_GL_SUPPORT_DESKTOP || GR_GL_SUPPORT_ES1) {
- GR_GL_GetIntegerv(GR_GL_MAX_TEXTURE_UNITS, &maxTextureUnits);
- GrAssert(maxTextureUnits > kNumStages);
- }
- if (GR_GL_SUPPORT_ES2) {
- GR_GL_GetIntegerv(GR_GL_MAX_FRAGMENT_UNIFORM_VECTORS,
- &fMaxFragmentUniformVectors);
- } else if (GR_GL_SUPPORT_DESKTOP) {
- GrGLint max;
- GR_GL_GetIntegerv(GR_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &max);
- fMaxFragmentUniformVectors = max / 4;
- } else {
- fMaxFragmentUniformVectors = 16;
- }
-
- ////////////////////////////////////////////////////////////////////////////
- // Check for supported features.
-
- int major, minor;
- gl_version(&major, &minor);
-
- GrGLint numFormats;
- GR_GL_GetIntegerv(GR_GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats);
- GrAutoSTMalloc<10, GrGLint> formats(numFormats);
- GR_GL_GetIntegerv(GR_GL_COMPRESSED_TEXTURE_FORMATS, formats);
- for (int i = 0; i < numFormats; ++i) {
- if (formats[i] == GR_GL_PALETTE8_RGBA8) {
- f8bitPaletteSupport = true;
- break;
- }
- }
-
- if (gPrintStartupSpew) {
- GrPrintf("Palette8 support: %s\n", (f8bitPaletteSupport ? "YES" : "NO"));
- }
-
- GR_STATIC_ASSERT(0 == kNone_GrAALevel);
- GR_STATIC_ASSERT(1 == kLow_GrAALevel);
- GR_STATIC_ASSERT(2 == kMed_GrAALevel);
- GR_STATIC_ASSERT(3 == kHigh_GrAALevel);
-
- memset(fAASamples, 0, sizeof(fAASamples));
- fMSFBOType = kNone_MSFBO;
- if (GR_GL_SUPPORT_ES) {
- if (has_gl_extension("GL_CHROMIUM_framebuffer_multisample")) {
- // chrome's extension is equivalent to the EXT msaa
- // and fbo_blit extensions.
- fMSFBOType = kDesktopEXT_MSFBO;
- } else if (has_gl_extension("GL_APPLE_framebuffer_multisample")) {
- fMSFBOType = kAppleES_MSFBO;
- }
- } else {
- GrAssert(GR_GL_SUPPORT_DESKTOP);
- if ((major >= 3) || has_gl_extension("GL_ARB_framebuffer_object")) {
- fMSFBOType = kDesktopARB_MSFBO;
- } else if (has_gl_extension("GL_EXT_framebuffer_multisample") &&
- has_gl_extension("GL_EXT_framebuffer_blit")) {
- fMSFBOType = kDesktopEXT_MSFBO;
- }
- }
- if (gPrintStartupSpew) {
- switch (fMSFBOType) {
- case kNone_MSFBO:
- GrPrintf("MSAA Support: NONE\n");
- break;
- case kDesktopARB_MSFBO:
- GrPrintf("MSAA Support: DESKTOP ARB.\n");
- break;
- case kDesktopEXT_MSFBO:
- GrPrintf("MSAA Support: DESKTOP EXT.\n");
- break;
- case kAppleES_MSFBO:
- GrPrintf("MSAA Support: APPLE ES.\n");
- break;
- }
- }
-
- if (kNone_MSFBO != fMSFBOType) {
- GrGLint maxSamples;
- GR_GL_GetIntegerv(GR_GL_MAX_SAMPLES, &maxSamples);
- if (maxSamples > 1 ) {
- fAASamples[kNone_GrAALevel] = 0;
- fAASamples[kLow_GrAALevel] = GrMax(2,
- GrFixedFloorToInt((GR_FixedHalf) *
- maxSamples));
- fAASamples[kMed_GrAALevel] = GrMax(2,
- GrFixedFloorToInt(((GR_Fixed1*3)/4) *
- maxSamples));
- fAASamples[kHigh_GrAALevel] = maxSamples;
- }
- if (gPrintStartupSpew) {
- GrPrintf("\tMax Samples: %d\n", maxSamples);
- }
- }
- fFSAASupport = fAASamples[kHigh_GrAALevel] > 0;
-
- if (GR_GL_SUPPORT_DESKTOP) {
- fHasStencilWrap = (major >= 2 || (major == 1 && minor >= 4)) ||
- has_gl_extension("GL_EXT_stencil_wrap");
- } else {
- fHasStencilWrap = (major >= 2) || has_gl_extension("GL_OES_stencil_wrap");
- }
- if (gPrintStartupSpew) {
- GrPrintf("Stencil Wrap: %s\n", (fHasStencilWrap ? "YES" : "NO"));
- }
-
- if (GR_GL_SUPPORT_DESKTOP) {
- // we could also look for GL_ATI_separate_stencil extension or
- // GL_EXT_stencil_two_side but they use different function signatures
- // than GL2.0+ (and than each other).
- fTwoSidedStencilSupport = (major >= 2);
- // supported on GL 1.4 and higher or by extension
- fStencilWrapOpsSupport = (major > 1) ||
- ((1 == major) && (minor >= 4)) ||
- has_gl_extension("GL_EXT_stencil_wrap");
- } else {
- // ES 2 has two sided stencil but 1.1 doesn't. There doesn't seem to be
- // an ES1 extension.
- fTwoSidedStencilSupport = (major >= 2);
- // stencil wrap support is in ES2, ES1 requires extension.
- fStencilWrapOpsSupport = (major > 1) ||
- has_gl_extension("GL_OES_stencil_wrap");
- }
- if (gPrintStartupSpew) {
- GrPrintf("Stencil Caps: TwoSide: %s, Wrap: %s\n",
- (fTwoSidedStencilSupport ? "YES" : "NO"),
- (fStencilWrapOpsSupport ? "YES" : "NO"));
- }
-
- if (GR_GL_SUPPORT_DESKTOP) {
- fRGBA8Renderbuffer = true;
- } else {
- fRGBA8Renderbuffer = has_gl_extension("GL_OES_rgb8_rgba8");
- }
- if (gPrintStartupSpew) {
- GrPrintf("RGBA Renderbuffer: %s\n", (fRGBA8Renderbuffer ? "YES" : "NO"));
- }
-
-
- if (GR_GL_SUPPORT_ES) {
- if (GR_GL_32BPP_COLOR_FORMAT == GR_GL_BGRA) {
- GrAssert(has_gl_extension("GL_EXT_texture_format_BGRA8888"));
- }
- }
-
- if (GR_GL_SUPPORT_DESKTOP) {
- fBufferLockSupport = true; // we require VBO support and the desktop VBO
- // extension includes glMapBuffer.
- } else {
- fBufferLockSupport = has_gl_extension("GL_OES_mapbuffer");
- }
-
- if (gPrintStartupSpew) {
- GrPrintf("Map Buffer: %s\n", (fBufferLockSupport ? "YES" : "NO"));
- }
-
- if (GR_GL_SUPPORT_DESKTOP) {
- if (major >= 2 || has_gl_extension("GL_ARB_texture_non_power_of_two")) {
- fNPOTTextureTileSupport = true;
- fNPOTTextureSupport = true;
- } else {
- fNPOTTextureTileSupport = false;
- fNPOTTextureSupport = false;
- }
- } else {
- if (major >= 2) {
- fNPOTTextureSupport = true;
- fNPOTTextureTileSupport = has_gl_extension("GL_OES_texture_npot");
- } else {
- fNPOTTextureSupport =
- has_gl_extension("GL_APPLE_texture_2D_limited_npot");
- fNPOTTextureTileSupport = false;
- }
- }
-
- fAALineSupport = GR_GL_SUPPORT_DESKTOP;
-
- ////////////////////////////////////////////////////////////////////////////
- // Experiments to determine limitations that can't be queried. TODO: Make
- // these a preprocess that generate some compile time constants.
-
- // sanity check to make sure we can at least create an FBO from a POT texture
-
- bool simpleFBOSuccess = fbo_test(128, 128);
- if (gPrintStartupSpew) {
- if (!simpleFBOSuccess) {
- GrPrintf("FBO Sanity Test: FAILED\n");
- } else {
- GrPrintf("FBO Sanity Test: PASSED\n");
- }
- }
- GrAssert(simpleFBOSuccess);
-
- /* Experimentation has found that some GLs that support NPOT textures
- do not support FBOs with a NPOT texture. They report "unsupported" FBO
- status. I don't know how to explicitly query for this. Do an
- experiment. Note they may support NPOT with a renderbuffer but not a
- texture. Presumably, the implementation bloats the renderbuffer
- internally to the next POT.
- */
- bool fNPOTRenderTargetSupport = false;
- if (fNPOTTextureSupport) {
- fNPOTRenderTargetSupport = fbo_test(200, 200);
- }
-
- if (gPrintStartupSpew) {
- if (fNPOTTextureSupport) {
- GrPrintf("NPOT textures supported\n");
- if (fNPOTTextureTileSupport) {
- GrPrintf("NPOT texture tiling supported\n");
- } else {
- GrPrintf("NPOT texture tiling NOT supported\n");
- }
- if (fNPOTRenderTargetSupport) {
- GrPrintf("NPOT render targets supported\n");
- } else {
- GrPrintf("NPOT render targets NOT supported\n");
- }
- } else {
- GrPrintf("NPOT textures NOT supported\n");
- }
- }
-
- GR_GL_GetIntegerv(GR_GL_MAX_TEXTURE_SIZE, &fMaxTextureDimension);
-
- /* The iPhone 4 has a restriction that for an FBO with texture color
- attachment with height <= 8 then the width must be <= height. Here
- we look for such a limitation.
- */
- fMinRenderTargetHeight = GR_INVAL_GLINT;
- GrGLint maxRenderSize;
- GR_GL_GetIntegerv(GR_GL_MAX_RENDERBUFFER_SIZE, &maxRenderSize);
- // fbo_test creates FBOs with texture bound to the color attachment
- maxRenderSize = GrMin(maxRenderSize, fMaxTextureDimension);
-
- if (gPrintStartupSpew) {
- GrPrintf("Small height FBO texture experiments\n");
- }
-
- for (GrGLuint i = 1; i <= 256; fNPOTRenderTargetSupport ? ++i : i *= 2) {
- GrGLuint w = maxRenderSize;
- GrGLuint h = i;
- if (fbo_test(w, h)) {
- if (gPrintStartupSpew) {
- GrPrintf("\t[%d, %d]: PASSED\n", w, h);
- }
- fMinRenderTargetHeight = i;
- break;
- } else {
- if (gPrintStartupSpew) {
- GrPrintf("\t[%d, %d]: FAILED\n", w, h);
- }
- }
- }
- GrAssert(GR_INVAL_GLINT != fMinRenderTargetHeight);
-
- if (gPrintStartupSpew) {
- GrPrintf("Small width FBO texture experiments\n");
- }
- fMinRenderTargetWidth = GR_MAX_GLUINT;
- for (GrGLuint i = 1; i <= 256; fNPOTRenderTargetSupport ? i *= 2 : ++i) {
- GrGLuint w = i;
- GrGLuint h = maxRenderSize;
- if (fbo_test(w, h)) {
- if (gPrintStartupSpew) {
- GrPrintf("\t[%d, %d]: PASSED\n", w, h);
- }
- fMinRenderTargetWidth = i;
- break;
- } else {
- if (gPrintStartupSpew) {
- GrPrintf("\t[%d, %d]: FAILED\n", w, h);
- }
- }
- }
- GrAssert(GR_INVAL_GLINT != fMinRenderTargetWidth);
-}
-
-GrGpuGL::~GrGpuGL() {
-}
-
-void GrGpuGL::resetContext() {
- // We detect cases when blending is effectively off
- fHWBlendDisabled = false;
- GR_GL(Enable(GR_GL_BLEND));
-
- // we don't use the zb at all
- GR_GL(Disable(GR_GL_DEPTH_TEST));
- GR_GL(DepthMask(GR_GL_FALSE));
-
- GR_GL(Disable(GR_GL_CULL_FACE));
- GR_GL(FrontFace(GR_GL_CCW));
- fHWDrawState.fDrawFace = kBoth_DrawFace;
-
- GR_GL(Disable(GR_GL_DITHER));
- if (GR_GL_SUPPORT_DESKTOP) {
- GR_GL(Disable(GR_GL_LINE_SMOOTH));
- GR_GL(Disable(GR_GL_POINT_SMOOTH));
- GR_GL(Disable(GR_GL_MULTISAMPLE));
- fHWAAState.fMSAAEnabled = false;
- fHWAAState.fSmoothLineEnabled = false;
- }
-
- GR_GL(ColorMask(GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE));
- fHWDrawState.fFlagBits = 0;
-
- // we only ever use lines in hairline mode
- GR_GL(LineWidth(1));
-
- // invalid
- fActiveTextureUnitIdx = -1;
-
- // illegal values
- fHWDrawState.fSrcBlend = (GrBlendCoeff)-1;
- fHWDrawState.fDstBlend = (GrBlendCoeff)-1;
-
- fHWDrawState.fBlendConstant = 0x00000000;
- GR_GL(BlendColor(0,0,0,0));
-
- fHWDrawState.fColor = GrColor_ILLEGAL;
-
- fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
-
- for (int s = 0; s < kNumStages; ++s) {
- fHWDrawState.fTextures[s] = NULL;
- fHWDrawState.fSamplerStates[s].setRadial2Params(-GR_ScalarMax,
- -GR_ScalarMax,
- true);
-
- fHWDrawState.fSamplerStates[s].setMatrix(GrMatrix::InvalidMatrix());
- }
-
- fHWBounds.fScissorRect.invalidate();
- fHWBounds.fScissorEnabled = false;
- GR_GL(Disable(GR_GL_SCISSOR_TEST));
- fHWBounds.fViewportRect.invalidate();
-
- fHWDrawState.fStencilSettings.invalidate();
- fHWStencilClip = false;
- fClipState.fClipIsDirty = true;
-
- fHWGeometryState.fIndexBuffer = NULL;
- fHWGeometryState.fVertexBuffer = NULL;
-
- fHWGeometryState.fArrayPtrsDirty = true;
-
- GR_GL(ColorMask(GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE));
- fHWDrawState.fRenderTarget = NULL;
-}
-
-GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc) {
-
- bool isTexture = kTexture_GrPlatformSurfaceType == desc.fSurfaceType ||
- kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType;
- bool isRenderTarget = kRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType ||
- kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType;
-
- GrGLRenderTarget::GLRenderTargetIDs rtIDs;
- if (isRenderTarget) {
- rtIDs.fRTFBOID = desc.fPlatformRenderTarget;
- if (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) {
- if (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) {
- rtIDs.fTexFBOID = desc.fPlatformResolveDestination;
- } else {
- GrAssert(!isTexture); // this should have been filtered by GrContext
- rtIDs.fTexFBOID = GrGLRenderTarget::kUnresolvableFBOID;
- }
- } else {
- rtIDs.fTexFBOID = desc.fPlatformRenderTarget;
- }
- // we don't know what the RB ids are without glGets and we don't care
- // since we aren't responsible for deleting them.
- rtIDs.fStencilRenderbufferID = 0;
- rtIDs.fMSColorRenderbufferID = 0;
-
- rtIDs.fOwnIDs = false;
- } else {
- rtIDs.reset();
- }
-
- if (isTexture) {
- GrGLTexture::GLTextureDesc texDesc;
- GrGLenum dontCare;
- if (!canBeTexture(desc.fConfig, &dontCare,
- &texDesc.fUploadFormat,
- &texDesc.fUploadType)) {
- return NULL;
- }
-
- GrGLTexture::TexParams params;
-
- texDesc.fAllocWidth = texDesc.fContentWidth = desc.fWidth;
- texDesc.fAllocHeight = texDesc.fContentHeight = desc.fHeight;
-
- texDesc.fFormat = texDesc.fFormat;
- texDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
- texDesc.fStencilBits = desc.fStencilBits;
- texDesc.fTextureID = desc.fPlatformTexture;
- texDesc.fUploadByteCount = GrBytesPerPixel(desc.fConfig);
- texDesc.fOwnsID = false;
-
- params.invalidate(); // rather than do glGets.
-
- return new GrGLTexture(this, texDesc, rtIDs, params);
- } else {
- GrGLIRect viewport;
- viewport.fLeft = 0;
- viewport.fBottom = 0;
- viewport.fWidth = desc.fWidth;
- viewport.fHeight = desc.fHeight;
-
- return new GrGLRenderTarget(this, rtIDs, NULL, desc.fStencilBits,
- kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags,
- viewport, NULL);
- }
-}
-
-GrRenderTarget* GrGpuGL::onCreateRenderTargetFrom3DApiState() {
-
- GrGLRenderTarget::GLRenderTargetIDs rtIDs;
-
- GR_GL_GetIntegerv(GR_GL_FRAMEBUFFER_BINDING, (GrGLint*)&rtIDs.fRTFBOID);
- rtIDs.fTexFBOID = rtIDs.fRTFBOID;
- rtIDs.fMSColorRenderbufferID = 0;
- rtIDs.fStencilRenderbufferID = 0;
-
- GrGLIRect viewport;
- viewport.setFromGLViewport();
- GrGLuint stencilBits;
- GR_GL_GetIntegerv(GR_GL_STENCIL_BITS, (GrGLint*)&stencilBits);
-
- GrGLint samples;
- GR_GL_GetIntegerv(GR_GL_SAMPLES, &samples);
-
- rtIDs.fOwnIDs = false;
-
- return new GrGLRenderTarget(this, rtIDs, NULL, stencilBits,
- (samples > 0), viewport, NULL);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static const GrGLuint UNKNOWN_BITS = ~0;
-
-struct StencilFormat {
- GrGLenum fEnum;
- GrGLuint fBits;
- bool fPacked;
-};
-
-const StencilFormat* GrGLStencilFormats() {
- // defines stencil formats from more to less preferred
- static const StencilFormat desktopStencilFormats[] = {
- {GR_GL_STENCIL_INDEX8, 8, false},
- {GR_GL_STENCIL_INDEX16, 16, false},
- {GR_GL_DEPTH24_STENCIL8, 8, true },
- {GR_GL_STENCIL_INDEX4, 4, false},
- {GR_GL_STENCIL_INDEX, UNKNOWN_BITS, false},
- {GR_GL_DEPTH_STENCIL, UNKNOWN_BITS, true },
- {0, 0, false}
- };
-
- static const StencilFormat esStencilFormats[] = {
- {GR_GL_STENCIL_INDEX8, 8, false},
- {GR_GL_DEPTH24_STENCIL8, 8, true },
- {GR_GL_STENCIL_INDEX4, 4, false},
- {0, 0, false}
- };
-
- if (GR_GL_SUPPORT_DESKTOP) {
- return desktopStencilFormats;
- } else {
- return esStencilFormats;
- }
-}
-
-// good to set a break-point here to know when createTexture fails
-static GrTexture* return_null_texture() {
-// GrAssert(!"null texture");
- return NULL;
-}
-
-#if GR_DEBUG
-static size_t as_size_t(int x) {
- return x;
-}
-#endif
-
-GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc,
- const void* srcData,
- size_t rowBytes) {
-
-#if GR_COLLECT_STATS
- ++fStats.fTextureCreateCnt;
-#endif
-
- this->setSpareTextureUnit();
-
- static const GrGLTexture::TexParams DEFAULT_PARAMS = {
- GR_GL_NEAREST,
- GR_GL_CLAMP_TO_EDGE,
- GR_GL_CLAMP_TO_EDGE
- };
-
- GrGLTexture::GLTextureDesc glDesc;
- GrGLenum internalFormat;
-
- glDesc.fContentWidth = desc.fWidth;
- glDesc.fContentHeight = desc.fHeight;
- glDesc.fAllocWidth = desc.fWidth;
- glDesc.fAllocHeight = desc.fHeight;
- glDesc.fStencilBits = 0;
- glDesc.fFormat = desc.fFormat;
- glDesc.fOwnsID = true;
-
- bool renderTarget = 0 != (desc.fFlags & kRenderTarget_GrTextureFlagBit);
- if (!canBeTexture(desc.fFormat,
- &internalFormat,
- &glDesc.fUploadFormat,
- &glDesc.fUploadType)) {
- return return_null_texture();
- }
-
- GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples));
- GrGLint samples = fAASamples[desc.fAALevel];
- if (kNone_MSFBO == fMSFBOType && desc.fAALevel != kNone_GrAALevel) {
- GrPrintf("AA RT requested but not supported on this platform.");
- }
-
- GR_GL(GenTextures(1, &glDesc.fTextureID));
- if (!glDesc.fTextureID) {
- return return_null_texture();
- }
-
- glDesc.fUploadByteCount = GrBytesPerPixel(desc.fFormat);
-
- // in case we need a temporary, trimmed copy of the src pixels
- GrAutoSMalloc<128 * 128> trimStorage;
-
- /*
- * check if our srcData has extra bytes past each row. If so, we need
- * to trim those off here, since GL doesn't let us pass the rowBytes as
- * a parameter to glTexImage2D
- */
- if (GR_GL_SUPPORT_DESKTOP) {
- if (srcData) {
- GR_GL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH,
- rowBytes / glDesc.fUploadByteCount));
- }
- } else {
- size_t trimRowBytes = desc.fWidth * glDesc.fUploadByteCount;
- if (srcData && (trimRowBytes < rowBytes)) {
- // copy the data into our new storage, skipping the trailing bytes
- size_t trimSize = desc.fHeight * trimRowBytes;
- const char* src = (const char*)srcData;
- char* dst = (char*)trimStorage.realloc(trimSize);
- for (uint32_t y = 0; y < desc.fHeight; y++) {
- memcpy(dst, src, trimRowBytes);
- src += rowBytes;
- dst += trimRowBytes;
- }
- // now point srcData to our trimmed version
- srcData = trimStorage.get();
- }
- }
-
- if (renderTarget) {
- if (!this->npotRenderTargetSupport()) {
- glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
- glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
- }
-
- glDesc.fAllocWidth = GrMax<int>(fMinRenderTargetWidth,
- glDesc.fAllocWidth);
- glDesc.fAllocHeight = GrMax<int>(fMinRenderTargetHeight,
- glDesc.fAllocHeight);
- } else if (!this->npotTextureSupport()) {
- glDesc.fAllocWidth = GrNextPow2(desc.fWidth);
- glDesc.fAllocHeight = GrNextPow2(desc.fHeight);
- }
-
- GR_GL(BindTexture(GR_GL_TEXTURE_2D, glDesc.fTextureID));
- GR_GL(TexParameteri(GR_GL_TEXTURE_2D,
- GR_GL_TEXTURE_MAG_FILTER,
- DEFAULT_PARAMS.fFilter));
- GR_GL(TexParameteri(GR_GL_TEXTURE_2D,
- GR_GL_TEXTURE_MIN_FILTER,
- DEFAULT_PARAMS.fFilter));
- GR_GL(TexParameteri(GR_GL_TEXTURE_2D,
- GR_GL_TEXTURE_WRAP_S,
- DEFAULT_PARAMS.fWrapS));
- GR_GL(TexParameteri(GR_GL_TEXTURE_2D,
- GR_GL_TEXTURE_WRAP_T,
- DEFAULT_PARAMS.fWrapT));
-
- GR_GL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
- if (kIndex_8_GrPixelConfig == desc.fFormat &&
- supports8BitPalette()) {
- // ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
- GrAssert(desc.fWidth == glDesc.fAllocWidth);
- GrAssert(desc.fHeight == glDesc.fAllocHeight);
- GrGLsizei imageSize = glDesc.fAllocWidth * glDesc.fAllocHeight +
- kGrColorTableSize;
- GR_GL(CompressedTexImage2D(GR_GL_TEXTURE_2D, 0, glDesc.fUploadFormat,
- glDesc.fAllocWidth, glDesc.fAllocHeight,
- 0, imageSize, srcData));
- GrGLRestoreResetRowLength();
- } else {
- if (NULL != srcData && (glDesc.fAllocWidth != desc.fWidth ||
- glDesc.fAllocHeight != desc.fHeight)) {
- GR_GL(TexImage2D(GR_GL_TEXTURE_2D, 0, internalFormat,
- glDesc.fAllocWidth, glDesc.fAllocHeight,
- 0, glDesc.fUploadFormat, glDesc.fUploadType, NULL));
- GR_GL(TexSubImage2D(GR_GL_TEXTURE_2D, 0, 0, 0, desc.fWidth,
- desc.fHeight, glDesc.fUploadFormat,
- glDesc.fUploadType, srcData));
- GrGLRestoreResetRowLength();
-
- uint32_t extraW = glDesc.fAllocWidth - desc.fWidth;
- uint32_t extraH = glDesc.fAllocHeight - desc.fHeight;
- uint32_t maxTexels = extraW * extraH;
- maxTexels = GrMax(extraW * desc.fHeight, maxTexels);
- maxTexels = GrMax(desc.fWidth * extraH, maxTexels);
-
- GrAutoSMalloc<128*128> texels(glDesc.fUploadByteCount * maxTexels);
-
- uint32_t rowSize = desc.fWidth * glDesc.fUploadByteCount;
- if (extraH) {
- uint8_t* lastRowStart = (uint8_t*) srcData +
- (desc.fHeight - 1) * rowSize;
- uint8_t* extraRowStart = (uint8_t*)texels.get();
-
- for (uint32_t i = 0; i < extraH; ++i) {
- memcpy(extraRowStart, lastRowStart, rowSize);
- extraRowStart += rowSize;
- }
- GR_GL(TexSubImage2D(GR_GL_TEXTURE_2D, 0, 0, desc.fHeight, desc.fWidth,
- extraH, glDesc.fUploadFormat, glDesc.fUploadType,
- texels.get()));
- }
- if (extraW) {
- uint8_t* edgeTexel = (uint8_t*)srcData + rowSize - glDesc.fUploadByteCount;
- uint8_t* extraTexel = (uint8_t*)texels.get();
- for (uint32_t j = 0; j < desc.fHeight; ++j) {
- for (uint32_t i = 0; i < extraW; ++i) {
- memcpy(extraTexel, edgeTexel, glDesc.fUploadByteCount);
- extraTexel += glDesc.fUploadByteCount;
- }
- edgeTexel += rowSize;
- }
- GR_GL(TexSubImage2D(GR_GL_TEXTURE_2D, 0, desc.fWidth, 0, extraW,
- desc.fHeight, glDesc.fUploadFormat,
- glDesc.fUploadType, texels.get()));
- }
- if (extraW && extraH) {
- uint8_t* cornerTexel = (uint8_t*)srcData + desc.fHeight * rowSize
- - glDesc.fUploadByteCount;
- uint8_t* extraTexel = (uint8_t*)texels.get();
- for (uint32_t i = 0; i < extraW*extraH; ++i) {
- memcpy(extraTexel, cornerTexel, glDesc.fUploadByteCount);
- extraTexel += glDesc.fUploadByteCount;
- }
- GR_GL(TexSubImage2D(GR_GL_TEXTURE_2D, 0, desc.fWidth, desc.fHeight,
- extraW, extraH, glDesc.fUploadFormat,
- glDesc.fUploadType, texels.get()));
- }
-
- } else {
- GR_GL(TexImage2D(GR_GL_TEXTURE_2D, 0, internalFormat, glDesc.fAllocWidth,
- glDesc.fAllocHeight, 0, glDesc.fUploadFormat,
- glDesc.fUploadType, srcData));
- GrGLRestoreResetRowLength();
- }
- }
-
- glDesc.fOrientation = GrGLTexture::kTopDown_Orientation;
-
- GrGLRenderTarget::GLRenderTargetIDs rtIDs;
- rtIDs.fStencilRenderbufferID = 0;
- rtIDs.fMSColorRenderbufferID = 0;
- rtIDs.fRTFBOID = 0;
- rtIDs.fTexFBOID = 0;
- rtIDs.fOwnIDs = true;
- GrGLenum msColorRenderbufferFormat = -1;
-
- if (renderTarget) {
-#if GR_COLLECT_STATS
- ++fStats.fRenderTargetCreateCnt;
-#endif
- bool failed = true;
- GrGLenum status;
- GrGLint err;
-
- // If need have both RT flag and srcData we have
- // to invert the data before uploading because FBO
- // will be rendered bottom up
- GrAssert(NULL == srcData);
- glDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
-
- GR_GL(GenFramebuffers(1, &rtIDs.fTexFBOID));
- GrAssert(rtIDs.fTexFBOID);
-
- // If we are using multisampling and we will create two FBOS We render
- // to one and then resolve to the texture bound to the other.
- if (samples > 1 && kNone_MSFBO != fMSFBOType) {
- GR_GL(GenFramebuffers(1, &rtIDs.fRTFBOID));
- GrAssert(0 != rtIDs.fRTFBOID);
- GR_GL(GenRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
- GrAssert(0 != rtIDs.fMSColorRenderbufferID);
- if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
- GR_GL(DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
- GR_GL(DeleteTextures(1, &glDesc.fTextureID));
- GR_GL(DeleteFramebuffers(1, &rtIDs.fTexFBOID));
- GR_GL(DeleteFramebuffers(1, &rtIDs.fRTFBOID));
- return return_null_texture();
- }
- } else {
- rtIDs.fRTFBOID = rtIDs.fTexFBOID;
- }
- if (!(kNoStencil_GrTextureFlagBit & desc.fFlags)) {
- GR_GL(GenRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
- GrAssert(0 != rtIDs.fStencilRenderbufferID);
- }
-
- // someone suggested that some systems might require
- // unbinding the texture before we call FramebufferTexture2D
- // (seems unlikely)
- GR_GL(BindTexture(GR_GL_TEXTURE_2D, 0));
-
- err = ~GR_GL_NO_ERROR;
-
- const StencilFormat* stencilFormats = GrGLStencilFormats();
- for (int i = 0; 0 != stencilFormats[i].fEnum; ++i) {
- if (rtIDs.fStencilRenderbufferID) {
- GR_GL(BindRenderbuffer(GR_GL_RENDERBUFFER,
- rtIDs.fStencilRenderbufferID));
- if (samples > 1) {
- GR_GL_NO_ERR(RenderbufferStorageMultisample(
- GR_GL_RENDERBUFFER,
- samples,
- stencilFormats[i].fEnum,
- glDesc.fAllocWidth,
- glDesc.fAllocHeight));
- } else {
- GR_GL_NO_ERR(RenderbufferStorage(GR_GL_RENDERBUFFER,
- stencilFormats[i].fEnum,
- glDesc.fAllocWidth,
- glDesc.fAllocHeight));
- }
- err = GrGLGetGLInterface()->fGetError();
- if (err != GR_GL_NO_ERROR) {
- continue;
- }
- }
- if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
- GrAssert(samples > 1);
- GR_GL(BindRenderbuffer(GR_GL_RENDERBUFFER,
- rtIDs.fMSColorRenderbufferID));
- GR_GL_NO_ERR(RenderbufferStorageMultisample(
- GR_GL_RENDERBUFFER,
- samples,
- msColorRenderbufferFormat,
- glDesc.fAllocWidth,
- glDesc.fAllocHeight));
- err = GrGLGetGLInterface()->fGetError();
- if (err != GR_GL_NO_ERROR) {
- continue;
- }
- }
- GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, rtIDs.fTexFBOID));
-
-#if GR_COLLECT_STATS
- ++fStats.fRenderTargetChngCnt;
-#endif
- GR_GL(FramebufferTexture2D(GR_GL_FRAMEBUFFER,
- GR_GL_COLOR_ATTACHMENT0,
- GR_GL_TEXTURE_2D,
- glDesc.fTextureID, 0));
- if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
- GrGLenum status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
- if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
- GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
- status, desc.fWidth, desc.fHeight);
- continue;
- }
- GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, rtIDs.fRTFBOID));
- #if GR_COLLECT_STATS
- ++fStats.fRenderTargetChngCnt;
- #endif
- GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
- GR_GL_COLOR_ATTACHMENT0,
- GR_GL_RENDERBUFFER,
- rtIDs.fMSColorRenderbufferID));
-
- }
- if (rtIDs.fStencilRenderbufferID) {
- // bind the stencil to rt fbo if present, othewise the tex fbo
- GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
- GR_GL_STENCIL_ATTACHMENT,
- GR_GL_RENDERBUFFER,
- rtIDs.fStencilRenderbufferID));
- // if it is a packed format bind to depth also, otherwise
- // we may get an unsupported fbo completeness result
- if (stencilFormats[i].fPacked) {
- GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
- GR_GL_DEPTH_ATTACHMENT,
- GR_GL_RENDERBUFFER,
- rtIDs.fStencilRenderbufferID));
- }
- }
- status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
-
- if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
- GrPrintf("-- glCheckFramebufferStatus %x %d %d\n",
- status, desc.fWidth, desc.fHeight);
- // undo the depth bind
- if (rtIDs.fStencilRenderbufferID &&
- stencilFormats[i].fPacked) {
- GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
- GR_GL_DEPTH_ATTACHMENT,
- GR_GL_RENDERBUFFER,
- 0));
- }
- continue;
- }
- // we're successful!
- failed = false;
- if (rtIDs.fStencilRenderbufferID) {
- if (UNKNOWN_BITS == stencilFormats[i].fBits) {
- GR_GL_GetIntegerv(GR_GL_STENCIL_BITS, (GrGLint*)&glDesc.fStencilBits);
- } else {
- glDesc.fStencilBits = stencilFormats[i].fBits;
- }
- }
- break;
- }
- if (failed) {
- if (rtIDs.fStencilRenderbufferID) {
- GR_GL(DeleteRenderbuffers(1, &rtIDs.fStencilRenderbufferID));
- }
- if (rtIDs.fMSColorRenderbufferID) {
- GR_GL(DeleteRenderbuffers(1, &rtIDs.fMSColorRenderbufferID));
- }
- if (rtIDs.fRTFBOID != rtIDs.fTexFBOID) {
- GR_GL(DeleteFramebuffers(1, &rtIDs.fRTFBOID));
- }
- if (rtIDs.fTexFBOID) {
- GR_GL(DeleteFramebuffers(1, &rtIDs.fTexFBOID));
- }
- GR_GL(DeleteTextures(1, &glDesc.fTextureID));
- return return_null_texture();
- }
- }
-#ifdef TRACE_TEXTURE_CREATION
- GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
- tex->fTextureID, width, height, tex->fUploadByteCount);
-#endif
- GrGLTexture* tex = new GrGLTexture(this, glDesc, rtIDs, DEFAULT_PARAMS);
-
- if (0 != rtIDs.fTexFBOID) {
- GrRenderTarget* rt = tex->asRenderTarget();
- // We've messed with FBO state but may not have set the correct viewport
- // so just dirty the rendertarget state to force a resend.
- fHWDrawState.fRenderTarget = NULL;
-
- // clear the new stencil buffer if we have one
- if (!(desc.fFlags & kNoStencil_GrTextureFlagBit)) {
- GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget;
- fCurrDrawState.fRenderTarget = rt;
- this->clearStencil(0, ~0);
- fCurrDrawState.fRenderTarget = rtSave;
- }
- }
- return tex;
-}
-
-GrVertexBuffer* GrGpuGL::onCreateVertexBuffer(uint32_t size, bool dynamic) {
- GrGLuint id;
- GR_GL(GenBuffers(1, &id));
- if (id) {
- GR_GL(BindBuffer(GR_GL_ARRAY_BUFFER, id));
- fHWGeometryState.fArrayPtrsDirty = true;
- GrGLClearErr();
- // make sure driver can allocate memory for this buffer
- GR_GL_NO_ERR(BufferData(GR_GL_ARRAY_BUFFER, size, NULL,
- dynamic ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW));
- if (GrGLGetGLInterface()->fGetError() != GR_GL_NO_ERROR) {
- GR_GL(DeleteBuffers(1, &id));
- // deleting bound buffer does implicit bind to 0
- fHWGeometryState.fVertexBuffer = NULL;
- return NULL;
- }
- GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(this, id,
- size, dynamic);
- fHWGeometryState.fVertexBuffer = vertexBuffer;
- return vertexBuffer;
- }
- return NULL;
-}
-
-GrIndexBuffer* GrGpuGL::onCreateIndexBuffer(uint32_t size, bool dynamic) {
- GrGLuint id;
- GR_GL(GenBuffers(1, &id));
- if (id) {
- GR_GL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, id));
- GrGLClearErr();
- // make sure driver can allocate memory for this buffer
- GR_GL_NO_ERR(BufferData(GR_GL_ELEMENT_ARRAY_BUFFER, size, NULL,
- dynamic ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW));
- if (GrGLGetGLInterface()->fGetError() != GR_GL_NO_ERROR) {
- GR_GL(DeleteBuffers(1, &id));
- // deleting bound buffer does implicit bind to 0
- fHWGeometryState.fIndexBuffer = NULL;
- return NULL;
- }
- GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(this, id,
- size, dynamic);
- fHWGeometryState.fIndexBuffer = indexBuffer;
- return indexBuffer;
- }
- return NULL;
-}
-
-void GrGpuGL::flushScissor(const GrIRect* rect) {
- GrAssert(NULL != fCurrDrawState.fRenderTarget);
- const GrGLIRect& vp =
- ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getViewport();
-
- GrGLIRect scissor;
- if (NULL != rect) {
- scissor.setRelativeTo(vp, rect->fLeft, rect->fTop,
- rect->width(), rect->height());
- if (scissor.contains(vp)) {
- rect = NULL;
- }
- }
-
- if (NULL != rect) {
- if (fHWBounds.fScissorRect != scissor) {
- scissor.pushToGLScissor();
- fHWBounds.fScissorRect = scissor;
- }
- if (!fHWBounds.fScissorEnabled) {
- GR_GL(Enable(GR_GL_SCISSOR_TEST));
- fHWBounds.fScissorEnabled = true;
- }
- } else {
- if (fHWBounds.fScissorEnabled) {
- GR_GL(Disable(GR_GL_SCISSOR_TEST));
- fHWBounds.fScissorEnabled = false;
- }
- }
-}
-
-void GrGpuGL::onClear(const GrIRect* rect, GrColor color) {
- if (NULL == fCurrDrawState.fRenderTarget) {
- return;
- }
- GrIRect r;
- if (NULL != rect) {
- // flushScissor expects rect to be clipped to the target.
- r = *rect;
- GrIRect rtRect = SkIRect::MakeWH(fCurrDrawState.fRenderTarget->width(),
- fCurrDrawState.fRenderTarget->height());
- if (r.intersect(rtRect)) {
- rect = &r;
- } else {
- return;
- }
- }
- this->flushRenderTarget(rect);
- this->flushScissor(rect);
- GR_GL(ColorMask(GR_GL_TRUE,GR_GL_TRUE,GR_GL_TRUE,GR_GL_TRUE));
- fHWDrawState.fFlagBits &= ~kNoColorWrites_StateBit;
- GR_GL(ClearColor(GrColorUnpackR(color)/255.f,
- GrColorUnpackG(color)/255.f,
- GrColorUnpackB(color)/255.f,
- GrColorUnpackA(color)/255.f));
- GR_GL(Clear(GR_GL_COLOR_BUFFER_BIT));
-}
-
-void GrGpuGL::clearStencil(uint32_t value, uint32_t mask) {
- if (NULL == fCurrDrawState.fRenderTarget) {
- return;
- }
-
- this->flushRenderTarget(&GrIRect::EmptyIRect());
-
- if (fHWBounds.fScissorEnabled) {
- GR_GL(Disable(GR_GL_SCISSOR_TEST));
- fHWBounds.fScissorEnabled = false;
- }
- GR_GL(StencilMask(mask));
- GR_GL(ClearStencil(value));
- GR_GL(Clear(GR_GL_STENCIL_BUFFER_BIT));
- fHWDrawState.fStencilSettings.invalidate();
-}
-
-void GrGpuGL::clearStencilClip(const GrIRect& rect) {
- GrAssert(NULL != fCurrDrawState.fRenderTarget);
-#if 0
- GrGLint stencilBitCount = fCurrDrawState.fRenderTarget->stencilBits();
- GrAssert(stencilBitCount > 0);
- GrGLint clipStencilMask = (1 << (stencilBitCount - 1));
-#else
- // we could just clear the clip bit but when we go through
- // angle a partial stencil mask will cause clears to be
- // turned into draws. Our contract on GrDrawTarget says that
- // changing the clip between stencil passes may or may not
- // zero the client's clip bits. So we just clear the whole thing.
- static const GrGLint clipStencilMask = ~0;
-#endif
- this->flushRenderTarget(&GrIRect::EmptyIRect());
- flushScissor(&rect);
- GR_GL(StencilMask(clipStencilMask));
- GR_GL(ClearStencil(0));
- GR_GL(Clear(GR_GL_STENCIL_BUFFER_BIT));
- fHWDrawState.fStencilSettings.invalidate();
-}
-
-void GrGpuGL::onForceRenderTargetFlush() {
- this->flushRenderTarget(&GrIRect::EmptyIRect());
-}
-
-bool GrGpuGL::onReadPixels(GrRenderTarget* target,
- int left, int top, int width, int height,
- GrPixelConfig config, void* buffer) {
- GrGLenum internalFormat; // we don't use this for glReadPixels
- GrGLenum format;
- GrGLenum type;
- if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
- return false;
- }
- GrGLRenderTarget* tgt = static_cast<GrGLRenderTarget*>(target);
- GrAutoTPtrValueRestore<GrRenderTarget*> autoTargetRestore;
- switch (tgt->getResolveType()) {
- case GrGLRenderTarget::kCantResolve_ResolveType:
- return false;
- case GrGLRenderTarget::kAutoResolves_ResolveType:
- autoTargetRestore.save(&fCurrDrawState.fRenderTarget);
- fCurrDrawState.fRenderTarget = target;
- this->flushRenderTarget(&GrIRect::EmptyIRect());
- break;
- case GrGLRenderTarget::kCanResolve_ResolveType:
- this->resolveRenderTarget(tgt);
- // we don't track the state of the READ FBO ID.
- GR_GL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, tgt->textureFBOID()));
- break;
- default:
- GrCrash("Unknown resolve type");
- }
-
- const GrGLIRect& glvp = tgt->getViewport();
-
- // the read rect is viewport-relative
- GrGLIRect readRect;
- readRect.setRelativeTo(glvp, left, top, width, height);
- GR_GL(ReadPixels(readRect.fLeft, readRect.fBottom,
- readRect.fWidth, readRect.fHeight,
- format, type, buffer));
-
- // now reverse the order of the rows, since GL's are bottom-to-top, but our
- // API presents top-to-bottom
- {
- size_t stride = width * GrBytesPerPixel(config);
- GrAutoMalloc rowStorage(stride);
- void* tmp = rowStorage.get();
-
- const int halfY = height >> 1;
- char* top = reinterpret_cast<char*>(buffer);
- char* bottom = top + (height - 1) * stride;
- for (int y = 0; y < halfY; y++) {
- memcpy(tmp, top, stride);
- memcpy(top, bottom, stride);
- memcpy(bottom, tmp, stride);
- top += stride;
- bottom -= stride;
- }
- }
- return true;
-}
-
-void GrGpuGL::flushRenderTarget(const GrIRect* bound) {
-
- GrAssert(NULL != fCurrDrawState.fRenderTarget);
-
- GrGLRenderTarget* rt = (GrGLRenderTarget*)fCurrDrawState.fRenderTarget;
- if (fHWDrawState.fRenderTarget != fCurrDrawState.fRenderTarget) {
- GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, rt->renderFBOID()));
- #if GR_COLLECT_STATS
- ++fStats.fRenderTargetChngCnt;
- #endif
- #if GR_DEBUG
- GrGLenum status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
- if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
- GrPrintf("-- glCheckFramebufferStatus %x\n", status);
- }
- #endif
- fDirtyFlags.fRenderTargetChanged = true;
- fHWDrawState.fRenderTarget = fCurrDrawState.fRenderTarget;
- const GrGLIRect& vp = rt->getViewport();
- if (fHWBounds.fViewportRect != vp) {
- vp.pushToGLViewport();
- fHWBounds.fViewportRect = vp;
- }
- }
- if (NULL == bound || !bound->isEmpty()) {
- rt->flagAsNeedingResolve(bound);
- }
-}
-
-GrGLenum gPrimitiveType2GLMode[] = {
- GR_GL_TRIANGLES,
- GR_GL_TRIANGLE_STRIP,
- GR_GL_TRIANGLE_FAN,
- GR_GL_POINTS,
- GR_GL_LINES,
- GR_GL_LINE_STRIP
-};
-
-#define SWAP_PER_DRAW 0
-
-#if SWAP_PER_DRAW
- #if GR_MAC_BUILD
- #include <AGL/agl.h>
- #elif GR_WIN32_BUILD
- void SwapBuf() {
- DWORD procID = GetCurrentProcessId();
- HWND hwnd = GetTopWindow(GetDesktopWindow());
- while(hwnd) {
- DWORD wndProcID = 0;
- GetWindowThreadProcessId(hwnd, &wndProcID);
- if(wndProcID == procID) {
- SwapBuffers(GetDC(hwnd));
- }
- hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
- }
- }
- #endif
-#endif
-
-void GrGpuGL::onDrawIndexed(GrPrimitiveType type,
- uint32_t startVertex,
- uint32_t startIndex,
- uint32_t vertexCount,
- uint32_t indexCount) {
- GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
-
- GrGLvoid* indices = (GrGLvoid*)(sizeof(uint16_t) * startIndex);
-
- GrAssert(NULL != fHWGeometryState.fIndexBuffer);
- GrAssert(NULL != fHWGeometryState.fVertexBuffer);
-
- // our setupGeometry better have adjusted this to zero since
- // DrawElements always draws from the begining of the arrays for idx 0.
- GrAssert(0 == startVertex);
-
- GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
- GR_GL_UNSIGNED_SHORT, indices));
-#if SWAP_PER_DRAW
- glFlush();
- #if GR_MAC_BUILD
- aglSwapBuffers(aglGetCurrentContext());
- int set_a_break_pt_here = 9;
- aglSwapBuffers(aglGetCurrentContext());
- #elif GR_WIN32_BUILD
- SwapBuf();
- int set_a_break_pt_here = 9;
- SwapBuf();
- #endif
-#endif
-}
-
-void GrGpuGL::onDrawNonIndexed(GrPrimitiveType type,
- uint32_t startVertex,
- uint32_t vertexCount) {
- GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
-
- GrAssert(NULL != fHWGeometryState.fVertexBuffer);
-
- // our setupGeometry better have adjusted this to zero.
- // DrawElements doesn't take an offset so we always adjus the startVertex.
- GrAssert(0 == startVertex);
-
- // pass 0 for parameter first. We have to adjust gl*Pointer() to
- // account for startVertex in the DrawElements case. So we always
- // rely on setupGeometry to have accounted for startVertex.
- GR_GL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
-#if SWAP_PER_DRAW
- glFlush();
- #if GR_MAC_BUILD
- aglSwapBuffers(aglGetCurrentContext());
- int set_a_break_pt_here = 9;
- aglSwapBuffers(aglGetCurrentContext());
- #elif GR_WIN32_BUILD
- SwapBuf();
- int set_a_break_pt_here = 9;
- SwapBuf();
- #endif
-#endif
-}
-
-void GrGpuGL::resolveRenderTarget(GrGLRenderTarget* rt) {
-
- if (rt->needsResolve()) {
- GrAssert(kNone_MSFBO != fMSFBOType);
- GrAssert(rt->textureFBOID() != rt->renderFBOID());
- GR_GL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER,
- rt->renderFBOID()));
- GR_GL(BindFramebuffer(GR_GL_DRAW_FRAMEBUFFER,
- rt->textureFBOID()));
- #if GR_COLLECT_STATS
- ++fStats.fRenderTargetChngCnt;
- #endif
- // make sure we go through flushRenderTarget() since we've modified
- // the bound DRAW FBO ID.
- fHWDrawState.fRenderTarget = NULL;
- const GrGLIRect& vp = rt->getViewport();
- const GrIRect dirtyRect = rt->getResolveRect();
- GrGLIRect r;
- r.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop,
- dirtyRect.width(), dirtyRect.height());
-
- if (kAppleES_MSFBO == fMSFBOType) {
- // Apple's extension uses the scissor as the blit bounds.
- GR_GL(Enable(GR_GL_SCISSOR_TEST));
- GR_GL(Scissor(r.fLeft, r.fBottom,
- r.fWidth, r.fHeight));
- GR_GL(ResolveMultisampleFramebuffer());
- fHWBounds.fScissorRect.invalidate();
- fHWBounds.fScissorEnabled = true;
- } else {
- if (kDesktopARB_MSFBO != fMSFBOType) {
- // this respects the scissor during the blit, so disable it.
- GrAssert(kDesktopEXT_MSFBO == fMSFBOType);
- flushScissor(NULL);
- }
- int right = r.fLeft + r.fWidth;
- int top = r.fBottom + r.fHeight;
- GR_GL(BlitFramebuffer(r.fLeft, r.fBottom, right, top,
- r.fLeft, r.fBottom, right, top,
- GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
- }
- rt->flagAsResolved();
- }
-}
-
-static const GrGLenum grToGLStencilFunc[] = {
- GR_GL_ALWAYS, // kAlways_StencilFunc
- GR_GL_NEVER, // kNever_StencilFunc
- GR_GL_GREATER, // kGreater_StencilFunc
- GR_GL_GEQUAL, // kGEqual_StencilFunc
- GR_GL_LESS, // kLess_StencilFunc
- GR_GL_LEQUAL, // kLEqual_StencilFunc,
- GR_GL_EQUAL, // kEqual_StencilFunc,
- GR_GL_NOTEQUAL, // kNotEqual_StencilFunc,
-};
-GR_STATIC_ASSERT(GR_ARRAY_COUNT(grToGLStencilFunc) == kBasicStencilFuncCount);
-GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
-GR_STATIC_ASSERT(1 == kNever_StencilFunc);
-GR_STATIC_ASSERT(2 == kGreater_StencilFunc);
-GR_STATIC_ASSERT(3 == kGEqual_StencilFunc);
-GR_STATIC_ASSERT(4 == kLess_StencilFunc);
-GR_STATIC_ASSERT(5 == kLEqual_StencilFunc);
-GR_STATIC_ASSERT(6 == kEqual_StencilFunc);
-GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc);
-
-static const GrGLenum grToGLStencilOp[] = {
- GR_GL_KEEP, // kKeep_StencilOp
- GR_GL_REPLACE, // kReplace_StencilOp
- GR_GL_INCR_WRAP, // kIncWrap_StencilOp
- GR_GL_INCR, // kIncClamp_StencilOp
- GR_GL_DECR_WRAP, // kDecWrap_StencilOp
- GR_GL_DECR, // kDecClamp_StencilOp
- GR_GL_ZERO, // kZero_StencilOp
- GR_GL_INVERT, // kInvert_StencilOp
-};
-GR_STATIC_ASSERT(GR_ARRAY_COUNT(grToGLStencilOp) == kStencilOpCount);
-GR_STATIC_ASSERT(0 == kKeep_StencilOp);
-GR_STATIC_ASSERT(1 == kReplace_StencilOp);
-GR_STATIC_ASSERT(2 == kIncWrap_StencilOp);
-GR_STATIC_ASSERT(3 == kIncClamp_StencilOp);
-GR_STATIC_ASSERT(4 == kDecWrap_StencilOp);
-GR_STATIC_ASSERT(5 == kDecClamp_StencilOp);
-GR_STATIC_ASSERT(6 == kZero_StencilOp);
-GR_STATIC_ASSERT(7 == kInvert_StencilOp);
-
-void GrGpuGL::flushStencil() {
- const GrStencilSettings* settings = &fCurrDrawState.fStencilSettings;
-
- // use stencil for clipping if clipping is enabled and the clip
- // has been written into the stencil.
- bool stencilClip = fClipState.fClipInStencil &&
- (kClip_StateBit & fCurrDrawState.fFlagBits);
- bool stencilChange = fHWStencilClip != stencilClip ||
- fHWDrawState.fStencilSettings != *settings ||
- ((fHWDrawState.fFlagBits & kModifyStencilClip_StateBit) !=
- (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit));
-
- if (stencilChange) {
-
- // we can't simultaneously perform stencil-clipping and modify the stencil clip
- GrAssert(!stencilClip || !(fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit));
-
- if (settings->isDisabled()) {
- if (stencilClip) {
- settings = &gClipStencilSettings;
- }
- }
-
- if (settings->isDisabled()) {
- GR_GL(Disable(GR_GL_STENCIL_TEST));
- } else {
- GR_GL(Enable(GR_GL_STENCIL_TEST));
- #if GR_DEBUG
- if (!fStencilWrapOpsSupport) {
- GrAssert(settings->fFrontPassOp != kIncWrap_StencilOp);
- GrAssert(settings->fFrontPassOp != kDecWrap_StencilOp);
- GrAssert(settings->fFrontFailOp != kIncWrap_StencilOp);
- GrAssert(settings->fBackFailOp != kDecWrap_StencilOp);
- GrAssert(settings->fBackPassOp != kIncWrap_StencilOp);
- GrAssert(settings->fBackPassOp != kDecWrap_StencilOp);
- GrAssert(settings->fBackFailOp != kIncWrap_StencilOp);
- GrAssert(settings->fFrontFailOp != kDecWrap_StencilOp);
- }
- #endif
- int stencilBits = fCurrDrawState.fRenderTarget->stencilBits();
- GrAssert(stencilBits ||
- (GrStencilSettings::gDisabled ==
- fCurrDrawState.fStencilSettings));
- GrGLuint clipStencilMask = 1 << (stencilBits - 1);
- GrGLuint userStencilMask = clipStencilMask - 1;
-
- unsigned int frontRef = settings->fFrontFuncRef;
- unsigned int frontMask = settings->fFrontFuncMask;
- unsigned int frontWriteMask = settings->fFrontWriteMask;
- GrGLenum frontFunc;
-
- if (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit) {
-
- GrAssert(settings->fFrontFunc < kBasicStencilFuncCount);
- frontFunc = grToGLStencilFunc[settings->fFrontFunc];
- } else {
- frontFunc = grToGLStencilFunc[ConvertStencilFunc(stencilClip, settings->fFrontFunc)];
-
- ConvertStencilFuncAndMask(settings->fFrontFunc,
- stencilClip,
- clipStencilMask,
- userStencilMask,
- &frontRef,
- &frontMask);
- frontWriteMask &= userStencilMask;
- }
- GrAssert(settings->fFrontFailOp >= 0 &&
- (unsigned) settings->fFrontFailOp < GR_ARRAY_COUNT(grToGLStencilOp));
- GrAssert(settings->fFrontPassOp >= 0 &&
- (unsigned) settings->fFrontPassOp < GR_ARRAY_COUNT(grToGLStencilOp));
- GrAssert(settings->fBackFailOp >= 0 &&
- (unsigned) settings->fBackFailOp < GR_ARRAY_COUNT(grToGLStencilOp));
- GrAssert(settings->fBackPassOp >= 0 &&
- (unsigned) settings->fBackPassOp < GR_ARRAY_COUNT(grToGLStencilOp));
- if (fTwoSidedStencilSupport) {
- GrGLenum backFunc;
-
- unsigned int backRef = settings->fBackFuncRef;
- unsigned int backMask = settings->fBackFuncMask;
- unsigned int backWriteMask = settings->fBackWriteMask;
-
-
- if (fCurrDrawState.fFlagBits & kModifyStencilClip_StateBit) {
- GrAssert(settings->fBackFunc < kBasicStencilFuncCount);
- backFunc = grToGLStencilFunc[settings->fBackFunc];
- } else {
- backFunc = grToGLStencilFunc[ConvertStencilFunc(stencilClip, settings->fBackFunc)];
- ConvertStencilFuncAndMask(settings->fBackFunc,
- stencilClip,
- clipStencilMask,
- userStencilMask,
- &backRef,
- &backMask);
- backWriteMask &= userStencilMask;
- }
-
- GR_GL(StencilFuncSeparate(GR_GL_FRONT, frontFunc, frontRef, frontMask));
- GR_GL(StencilMaskSeparate(GR_GL_FRONT, frontWriteMask));
- GR_GL(StencilFuncSeparate(GR_GL_BACK, backFunc, backRef, backMask));
- GR_GL(StencilMaskSeparate(GR_GL_BACK, backWriteMask));
- GR_GL(StencilOpSeparate(GR_GL_FRONT, grToGLStencilOp[settings->fFrontFailOp],
- grToGLStencilOp[settings->fFrontPassOp],
- grToGLStencilOp[settings->fFrontPassOp]));
-
- GR_GL(StencilOpSeparate(GR_GL_BACK, grToGLStencilOp[settings->fBackFailOp],
- grToGLStencilOp[settings->fBackPassOp],
- grToGLStencilOp[settings->fBackPassOp]));
- } else {
- GR_GL(StencilFunc(frontFunc, frontRef, frontMask));
- GR_GL(StencilMask(frontWriteMask));
- GR_GL(StencilOp(grToGLStencilOp[settings->fFrontFailOp],
- grToGLStencilOp[settings->fFrontPassOp],
- grToGLStencilOp[settings->fFrontPassOp]));
- }
- }
- fHWDrawState.fStencilSettings = fCurrDrawState.fStencilSettings;
- fHWStencilClip = stencilClip;
- }
-}
-
-bool GrGpuGL::useSmoothLines() {
- // there is a conflict between using smooth lines and our use of
- // premultiplied alpha. Smooth lines tweak the incoming alpha value
- // but not in a premul-alpha way. So we only use them when our alpha
- // is 0xff.
-
- // TODO: write a smarter line frag shader.
-
- return (kAntialias_StateBit & fCurrDrawState.fFlagBits) &&
- canDisableBlend();
-}
-
-void GrGpuGL::flushAAState(GrPrimitiveType type) {
- if (GR_GL_SUPPORT_DESKTOP) {
- // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
- // smooth lines.
-
- // we prefer smooth lines over multisampled lines
- // msaa should be disabled if drawing smooth lines.
- if (GrIsPrimTypeLines(type)) {
- bool smooth = useSmoothLines();
- if (!fHWAAState.fSmoothLineEnabled && smooth) {
- GR_GL(Enable(GR_GL_LINE_SMOOTH));
- fHWAAState.fSmoothLineEnabled = true;
- } else if (fHWAAState.fSmoothLineEnabled && !smooth) {
- GR_GL(Disable(GR_GL_LINE_SMOOTH));
- fHWAAState.fSmoothLineEnabled = false;
- }
- if (fCurrDrawState.fRenderTarget->isMultisampled() &&
- fHWAAState.fMSAAEnabled) {
- GR_GL(Disable(GR_GL_MULTISAMPLE));
- fHWAAState.fMSAAEnabled = false;
- }
- } else if (fCurrDrawState.fRenderTarget->isMultisampled() &&
- !!(kAntialias_StateBit & fCurrDrawState.fFlagBits) !=
- fHWAAState.fMSAAEnabled) {
- if (fHWAAState.fMSAAEnabled) {
- GR_GL(Disable(GR_GL_MULTISAMPLE));
- fHWAAState.fMSAAEnabled = false;
- } else {
- GR_GL(Enable(GR_GL_MULTISAMPLE));
- fHWAAState.fMSAAEnabled = true;
- }
- }
- }
-}
-
-void GrGpuGL::flushBlend(GrPrimitiveType type,
- GrBlendCoeff srcCoeff,
- GrBlendCoeff dstCoeff) {
- if (GrIsPrimTypeLines(type) && useSmoothLines()) {
- if (fHWBlendDisabled) {
- GR_GL(Enable(GR_GL_BLEND));
- fHWBlendDisabled = false;
- }
- if (kSA_BlendCoeff != fHWDrawState.fSrcBlend ||
- kISA_BlendCoeff != fHWDrawState.fDstBlend) {
- GR_GL(BlendFunc(gXfermodeCoeff2Blend[kSA_BlendCoeff],
- gXfermodeCoeff2Blend[kISA_BlendCoeff]));
- fHWDrawState.fSrcBlend = kSA_BlendCoeff;
- fHWDrawState.fDstBlend = kISA_BlendCoeff;
- }
- } else {
- bool blendOff = canDisableBlend();
- if (fHWBlendDisabled != blendOff) {
- if (blendOff) {
- GR_GL(Disable(GR_GL_BLEND));
- } else {
- GR_GL(Enable(GR_GL_BLEND));
- }
- fHWBlendDisabled = blendOff;
- }
- if (!blendOff) {
- if (fHWDrawState.fSrcBlend != srcCoeff ||
- fHWDrawState.fDstBlend != dstCoeff) {
- GR_GL(BlendFunc(gXfermodeCoeff2Blend[srcCoeff],
- gXfermodeCoeff2Blend[dstCoeff]));
- fHWDrawState.fSrcBlend = srcCoeff;
- fHWDrawState.fDstBlend = dstCoeff;
- }
- if ((BlendCoeffReferencesConstant(srcCoeff) ||
- BlendCoeffReferencesConstant(dstCoeff)) &&
- fHWDrawState.fBlendConstant != fCurrDrawState.fBlendConstant) {
-
- float c[] = {
- GrColorUnpackR(fCurrDrawState.fBlendConstant) / 255.f,
- GrColorUnpackG(fCurrDrawState.fBlendConstant) / 255.f,
- GrColorUnpackB(fCurrDrawState.fBlendConstant) / 255.f,
- GrColorUnpackA(fCurrDrawState.fBlendConstant) / 255.f
- };
- GR_GL(BlendColor(c[0], c[1], c[2], c[3]));
- fHWDrawState.fBlendConstant = fCurrDrawState.fBlendConstant;
- }
- }
- }
-}
-
-bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) {
-
- // GrGpu::setupClipAndFlushState should have already checked this
- // and bailed if not true.
- GrAssert(NULL != fCurrDrawState.fRenderTarget);
-
- for (int s = 0; s < kNumStages; ++s) {
- // bind texture and set sampler state
- if (this->isStageEnabled(s)) {
- GrGLTexture* nextTexture = (GrGLTexture*)fCurrDrawState.fTextures[s];
-
- // true for now, but maybe not with GrEffect.
- GrAssert(NULL != nextTexture);
- // if we created a rt/tex and rendered to it without using a
- // texture and now we're texuring from the rt it will still be
- // the last bound texture, but it needs resolving. So keep this
- // out of the "last != next" check.
- GrGLRenderTarget* texRT =
- static_cast<GrGLRenderTarget*>(nextTexture->asRenderTarget());
- if (NULL != texRT) {
- resolveRenderTarget(texRT);
- }
-
- if (fHWDrawState.fTextures[s] != nextTexture) {
- setTextureUnit(s);
- GR_GL(BindTexture(GR_GL_TEXTURE_2D, nextTexture->textureID()));
- #if GR_COLLECT_STATS
- ++fStats.fTextureChngCnt;
- #endif
- //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
- fHWDrawState.fTextures[s] = nextTexture;
- }
-
- const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
- const GrGLTexture::TexParams& oldTexParams =
- nextTexture->getTexParams();
- GrGLTexture::TexParams newTexParams;
-
- if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
- newTexParams.fFilter = GR_GL_NEAREST;
- } else {
- newTexParams.fFilter = GR_GL_LINEAR;
- }
-
- newTexParams.fWrapS =
- GrGLTexture::WrapMode2GLWrap()[sampler.getWrapX()];
- newTexParams.fWrapT =
- GrGLTexture::WrapMode2GLWrap()[sampler.getWrapY()];
-
- if (newTexParams.fFilter != oldTexParams.fFilter) {
- setTextureUnit(s);
- GR_GL(TexParameteri(GR_GL_TEXTURE_2D,
- GR_GL_TEXTURE_MAG_FILTER,
- newTexParams.fFilter));
- GR_GL(TexParameteri(GR_GL_TEXTURE_2D,
- GR_GL_TEXTURE_MIN_FILTER,
- newTexParams.fFilter));
- }
- if (newTexParams.fWrapS != oldTexParams.fWrapS) {
- setTextureUnit(s);
- GR_GL(TexParameteri(GR_GL_TEXTURE_2D,
- GR_GL_TEXTURE_WRAP_S,
- newTexParams.fWrapS));
- }
- if (newTexParams.fWrapT != oldTexParams.fWrapT) {
- setTextureUnit(s);
- GR_GL(TexParameteri(GR_GL_TEXTURE_2D,
- GR_GL_TEXTURE_WRAP_T,
- newTexParams.fWrapT));
- }
- nextTexture->setTexParams(newTexParams);
-
- // The texture matrix has to compensate for texture width/height
- // and NPOT-embedded-in-POT
- fDirtyFlags.fTextureChangedMask |= (1 << s);
- }
- }
-
- GrIRect* rect = NULL;
- GrIRect clipBounds;
- if ((fCurrDrawState.fFlagBits & kClip_StateBit) &&
- fClip.hasConservativeBounds()) {
- fClip.getConservativeBounds().roundOut(&clipBounds);
- rect = &clipBounds;
- }
- this->flushRenderTarget(rect);
- this->flushAAState(type);
-
- if ((fCurrDrawState.fFlagBits & kDither_StateBit) !=
- (fHWDrawState.fFlagBits & kDither_StateBit)) {
- if (fCurrDrawState.fFlagBits & kDither_StateBit) {
- GR_GL(Enable(GR_GL_DITHER));
- } else {
- GR_GL(Disable(GR_GL_DITHER));
- }
- }
-
- if ((fCurrDrawState.fFlagBits & kNoColorWrites_StateBit) !=
- (fHWDrawState.fFlagBits & kNoColorWrites_StateBit)) {
- GrGLenum mask;
- if (fCurrDrawState.fFlagBits & kNoColorWrites_StateBit) {
- mask = GR_GL_FALSE;
- } else {
- mask = GR_GL_TRUE;
- }
- GR_GL(ColorMask(mask, mask, mask, mask));
- }
-
- if (fHWDrawState.fDrawFace != fCurrDrawState.fDrawFace) {
- switch (fCurrDrawState.fDrawFace) {
- case kCCW_DrawFace:
- GR_GL(Enable(GR_GL_CULL_FACE));
- GR_GL(CullFace(GR_GL_BACK));
- break;
- case kCW_DrawFace:
- GR_GL(Enable(GR_GL_CULL_FACE));
- GR_GL(CullFace(GR_GL_FRONT));
- break;
- case kBoth_DrawFace:
- GR_GL(Disable(GR_GL_CULL_FACE));
- break;
- default:
- GrCrash("Unknown draw face.");
- }
- fHWDrawState.fDrawFace = fCurrDrawState.fDrawFace;
- }
-
-#if GR_DEBUG
- // check for circular rendering
- for (int s = 0; s < kNumStages; ++s) {
- GrAssert(!this->isStageEnabled(s) ||
- NULL == fCurrDrawState.fRenderTarget ||
- NULL == fCurrDrawState.fTextures[s] ||
- fCurrDrawState.fTextures[s]->asRenderTarget() !=
- fCurrDrawState.fRenderTarget);
- }
-#endif
-
- flushStencil();
-
- // flushStencil may look at the private state bits, so keep it before this.
- fHWDrawState.fFlagBits = fCurrDrawState.fFlagBits;
- return true;
-}
-
-void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
- if (fHWGeometryState.fVertexBuffer != buffer) {
- fHWGeometryState.fArrayPtrsDirty = true;
- fHWGeometryState.fVertexBuffer = buffer;
- }
-}
-
-void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
- if (fHWGeometryState.fVertexBuffer == buffer) {
- // deleting bound buffer does implied bind to 0
- fHWGeometryState.fVertexBuffer = NULL;
- fHWGeometryState.fArrayPtrsDirty = true;
- }
-}
-
-void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
- fGeometrySrc.fIndexBuffer = buffer;
-}
-
-void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
- if (fHWGeometryState.fIndexBuffer == buffer) {
- // deleting bound buffer does implied bind to 0
- fHWGeometryState.fIndexBuffer = NULL;
- }
-}
-
-void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
- GrAssert(NULL != renderTarget);
- if (fCurrDrawState.fRenderTarget == renderTarget) {
- fCurrDrawState.fRenderTarget = NULL;
- }
- if (fHWDrawState.fRenderTarget == renderTarget) {
- fHWDrawState.fRenderTarget = NULL;
- }
-}
-
-void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
- for (int s = 0; s < kNumStages; ++s) {
- if (fCurrDrawState.fTextures[s] == texture) {
- fCurrDrawState.fTextures[s] = NULL;
- }
- if (fHWDrawState.fTextures[s] == texture) {
- // deleting bound texture does implied bind to 0
- fHWDrawState.fTextures[s] = NULL;
- }
- }
-}
-
-bool GrGpuGL::canBeTexture(GrPixelConfig config,
- GrGLenum* internalFormat,
- GrGLenum* format,
- GrGLenum* type) {
- switch (config) {
- case kRGBA_8888_GrPixelConfig:
- case kRGBX_8888_GrPixelConfig: // todo: can we tell it our X?
- *format = GR_GL_32BPP_COLOR_FORMAT;
- if (GR_GL_SUPPORT_ES) {
- // according to GL_EXT_texture_format_BGRA8888 the *internal*
- // format for a BGRA is BGRA not RGBA (as on desktop)
- *internalFormat = GR_GL_32BPP_COLOR_FORMAT;
- } else {
- *internalFormat = GR_GL_RGBA;
- }
- *type = GR_GL_UNSIGNED_BYTE;
- break;
- case kRGB_565_GrPixelConfig:
- *format = GR_GL_RGB;
- *internalFormat = GR_GL_RGB;
- *type = GR_GL_UNSIGNED_SHORT_5_6_5;
- break;
- case kRGBA_4444_GrPixelConfig:
- *format = GR_GL_RGBA;
- *internalFormat = GR_GL_RGBA;
- *type = GR_GL_UNSIGNED_SHORT_4_4_4_4;
- break;
- case kIndex_8_GrPixelConfig:
- if (this->supports8BitPalette()) {
- *format = GR_GL_PALETTE8_RGBA8;
- *internalFormat = GR_GL_PALETTE8_RGBA8;
- *type = GR_GL_UNSIGNED_BYTE; // unused I think
- } else {
- return false;
- }
- break;
- case kAlpha_8_GrPixelConfig:
- *format = GR_GL_ALPHA;
- *internalFormat = GR_GL_ALPHA;
- *type = GR_GL_UNSIGNED_BYTE;
- break;
- default:
- return false;
- }
- return true;
-}
-
-void GrGpuGL::setTextureUnit(int unit) {
- GrAssert(unit >= 0 && unit < kNumStages);
- if (fActiveTextureUnitIdx != unit) {
- GR_GL(ActiveTexture(GR_GL_TEXTURE0 + unit));
- fActiveTextureUnitIdx = unit;
- }
-}
-
-void GrGpuGL::setSpareTextureUnit() {
- if (fActiveTextureUnitIdx != (GR_GL_TEXTURE0 + SPARE_TEX_UNIT)) {
- GR_GL(ActiveTexture(GR_GL_TEXTURE0 + SPARE_TEX_UNIT));
- fActiveTextureUnitIdx = SPARE_TEX_UNIT;
- }
-}
-
-/* On ES the internalFormat and format must match for TexImage and we use
- GL_RGB, GL_RGBA for color formats. We also generally like having the driver
- decide the internalFormat. However, on ES internalFormat for
- RenderBufferStorage* has to be a specific format (not a base format like
- GL_RGBA).
- */
-bool GrGpuGL::fboInternalFormat(GrPixelConfig config, GrGLenum* format) {
- switch (config) {
- case kRGBA_8888_GrPixelConfig:
- case kRGBX_8888_GrPixelConfig:
- if (fRGBA8Renderbuffer) {
- *format = GR_GL_RGBA8;
- return true;
- } else {
- return false;
- }
- case kRGB_565_GrPixelConfig:
- GrAssert(GR_GL_SUPPORT_ES); // ES2 supports 565. ES1 supports it
- // with FBO extension desktop GL has
- // no such internal format
- *format = GR_GL_RGB565;
- return true;
- case kRGBA_4444_GrPixelConfig:
- *format = GR_GL_RGBA4;
- return true;
- default:
- return false;
- }
-}
-
-void GrGpuGL::resetDirtyFlags() {
- Gr_bzero(&fDirtyFlags, sizeof(fDirtyFlags));
-}
-
-void GrGpuGL::setBuffers(bool indexed,
- int* extraVertexOffset,
- int* extraIndexOffset) {
-
- GrAssert(NULL != extraVertexOffset);
-
- GrGLVertexBuffer* vbuf;
- switch (fGeometrySrc.fVertexSrc) {
- case kBuffer_GeometrySrcType:
- *extraVertexOffset = 0;
- vbuf = (GrGLVertexBuffer*) fGeometrySrc.fVertexBuffer;
- break;
- case kArray_GeometrySrcType:
- case kReserved_GeometrySrcType:
- finalizeReservedVertices();
- *extraVertexOffset = fCurrPoolStartVertex;
- vbuf = (GrGLVertexBuffer*) fCurrPoolVertexBuffer;
- break;
- default:
- vbuf = NULL; // suppress warning
- GrCrash("Unknown geometry src type!");
- }
-
- GrAssert(NULL != vbuf);
- GrAssert(!vbuf->isLocked());
- if (fHWGeometryState.fVertexBuffer != vbuf) {
- GR_GL(BindBuffer(GR_GL_ARRAY_BUFFER, vbuf->bufferID()));
- fHWGeometryState.fArrayPtrsDirty = true;
- fHWGeometryState.fVertexBuffer = vbuf;
- }
-
- if (indexed) {
- GrAssert(NULL != extraIndexOffset);
-
- GrGLIndexBuffer* ibuf;
- switch (fGeometrySrc.fIndexSrc) {
- case kBuffer_GeometrySrcType:
- *extraIndexOffset = 0;
- ibuf = (GrGLIndexBuffer*)fGeometrySrc.fIndexBuffer;
- break;
- case kArray_GeometrySrcType:
- case kReserved_GeometrySrcType:
- finalizeReservedIndices();
- *extraIndexOffset = fCurrPoolStartIndex;
- ibuf = (GrGLIndexBuffer*) fCurrPoolIndexBuffer;
- break;
- default:
- ibuf = NULL; // suppress warning
- GrCrash("Unknown geometry src type!");
- }
-
- GrAssert(NULL != ibuf);
- GrAssert(!ibuf->isLocked());
- if (fHWGeometryState.fIndexBuffer != ibuf) {
- GR_GL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, ibuf->bufferID()));
- fHWGeometryState.fIndexBuffer = ibuf;
- }
- }
-}
-
-int GrGpuGL::getMaxEdges() const {
- // FIXME: This is a pessimistic estimate based on how many other things
- // want to add uniforms. This should be centralized somewhere.
- return GR_CT_MIN(fMaxFragmentUniformVectors - 8, kMaxEdges);
-}
diff --git a/gpu/src/GrGpuGL.h b/gpu/src/GrGpuGL.h
deleted file mode 100644
index 696b72f..0000000
--- a/gpu/src/GrGpuGL.h
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrGpuGL_DEFINED
-#define GrGpuGL_DEFINED
-
-#include "GrGpu.h"
-#include "GrGLIRect.h"
-#include "GrGLTexture.h"
-
-#include "GrGLVertexBuffer.h"
-#include "GrGLIndexBuffer.h"
-
-class GrGpuGL : public GrGpu {
-public:
- virtual ~GrGpuGL();
-
-protected:
- GrGpuGL();
-
- struct {
- size_t fVertexOffset;
- GrVertexLayout fVertexLayout;
- const GrVertexBuffer* fVertexBuffer;
- const GrIndexBuffer* fIndexBuffer;
- bool fArrayPtrsDirty;
- } fHWGeometryState;
-
- struct AAState {
- bool fMSAAEnabled;
- bool fSmoothLineEnabled;
- } fHWAAState;
-
- DrState fHWDrawState;
- bool fHWStencilClip;
-
- // As flush of GL state proceeds it updates fHDrawState
- // to reflect the new state. Later parts of the state flush
- // may perform cascaded changes but cannot refer to fHWDrawState.
- // These code paths can refer to the dirty flags. Subclass should
- // call resetDirtyFlags after its flush is complete
- struct {
- bool fRenderTargetChanged : 1;
- int fTextureChangedMask;
- } fDirtyFlags;
- GR_STATIC_ASSERT(8 * sizeof(int) >= kNumStages);
-
- // clears the dirty flags
- void resetDirtyFlags();
-
- // last scissor / viewport scissor state seen by the GL.
- struct {
- bool fScissorEnabled;
- GrGLIRect fScissorRect;
- GrGLIRect fViewportRect;
- } fHWBounds;
-
- // GrGpu overrides
- // overrides from GrGpu
- virtual void resetContext();
-
- virtual GrTexture* onCreateTexture(const GrTextureDesc& desc,
- const void* srcData,
- size_t rowBytes);
- virtual GrVertexBuffer* onCreateVertexBuffer(uint32_t size,
- bool dynamic);
- virtual GrIndexBuffer* onCreateIndexBuffer(uint32_t size,
- bool dynamic);
- virtual GrResource* onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc);
- virtual GrRenderTarget* onCreateRenderTargetFrom3DApiState();
-
- virtual void onClear(const GrIRect* rect, GrColor color);
-
- virtual void onForceRenderTargetFlush();
-
- virtual bool onReadPixels(GrRenderTarget* target,
- int left, int top, int width, int height,
- GrPixelConfig, void* buffer);
-
- virtual void onDrawIndexed(GrPrimitiveType type,
- uint32_t startVertex,
- uint32_t startIndex,
- uint32_t vertexCount,
- uint32_t indexCount);
- virtual void onDrawNonIndexed(GrPrimitiveType type,
- uint32_t vertexCount,
- uint32_t numVertices);
- virtual void flushScissor(const GrIRect* rect);
- void clearStencil(uint32_t value, uint32_t mask);
- virtual void clearStencilClip(const GrIRect& rect);
- virtual int getMaxEdges() const;
-
- // binds texture unit in GL
- void setTextureUnit(int unitIdx);
-
- // binds appropriate vertex and index buffers, also returns any extra
- // extra verts or indices to offset by.
- void setBuffers(bool indexed,
- int* extraVertexOffset,
- int* extraIndexOffset);
-
- // flushes state that is common to fixed and programmable GL
- // dither
- // line smoothing
- // texture binding
- // sampler state (filtering, tiling)
- // FBO binding
- // line width
- bool flushGLStateCommon(GrPrimitiveType type);
-
- // subclass should call this to flush the blend state
- void flushBlend(GrPrimitiveType type,
- GrBlendCoeff srcCoeff,
- GrBlendCoeff dstCoeff);
-
- // adjusts texture matrix to account for orientation, size, and npotness
- static void AdjustTextureMatrix(const GrGLTexture* texture,
- GrSamplerState::SampleMode mode,
- GrMatrix* matrix);
-
- // subclass may try to take advantage of identity tex matrices.
- // This helper determines if matrix will be identity after all
- // adjustments are applied.
- static bool TextureMatrixIsIdentity(const GrGLTexture* texture,
- const GrSamplerState& sampler);
-
- static bool BlendCoeffReferencesConstant(GrBlendCoeff coeff);
-
-private:
-
- // notify callbacks to update state tracking when related
- // objects are bound to GL or deleted outside of the class
- void notifyVertexBufferBind(const GrGLVertexBuffer* buffer);
- void notifyVertexBufferDelete(const GrGLVertexBuffer* buffer);
- void notifyIndexBufferBind(const GrGLIndexBuffer* buffer);
- void notifyIndexBufferDelete(const GrGLIndexBuffer* buffer);
- void notifyTextureDelete(GrGLTexture* texture);
- void notifyRenderTargetDelete(GrRenderTarget* renderTarget);
-
- void setSpareTextureUnit();
-
- bool useSmoothLines();
-
- // bound is region that may be modified and therefore has to be resolved.
- // NULL means whole target. Can be an empty rect.
- void flushRenderTarget(const GrIRect* bound);
- void flushStencil();
- void flushAAState(GrPrimitiveType type);
-
- void resolveRenderTarget(GrGLRenderTarget* texture);
-
- bool canBeTexture(GrPixelConfig config,
- GrGLenum* internalFormat,
- GrGLenum* format,
- GrGLenum* type);
-
- bool fboInternalFormat(GrPixelConfig config, GrGLenum* format);
-
- friend class GrGLVertexBuffer;
- friend class GrGLIndexBuffer;
- friend class GrGLTexture;
- friend class GrGLRenderTarget;
-
- bool fHWBlendDisabled;
-
- GrGLuint fAASamples[4];
- enum {
- kNone_MSFBO = 0, //<! no support for MSAA FBOs
- kDesktopARB_MSFBO,//<! GL3.0-style MSAA FBO (GL_ARB_framebuffer_object)
- kDesktopEXT_MSFBO,//<! earlier GL_EXT_framebuffer* extensions
- kAppleES_MSFBO, //<! GL_APPLE_framebuffer_multisample ES extension
- } fMSFBOType;
-
- // Do we have stencil wrap ops.
- bool fHasStencilWrap;
-
- // The maximum number of fragment uniform vectors (GLES has min. 16).
- int fMaxFragmentUniformVectors;
-
- // ES requires an extension to support RGBA8 in RenderBufferStorage
- bool fRGBA8Renderbuffer;
-
- int fActiveTextureUnitIdx;
-
- typedef GrGpu INHERITED;
-};
-
-#endif
diff --git a/gpu/src/GrGpuGLFixed.cpp b/gpu/src/GrGpuGLFixed.cpp
deleted file mode 100644
index 65229dc..0000000
--- a/gpu/src/GrGpuGLFixed.cpp
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#include "GrGLConfig.h"
-
-#include "GrGpuGLFixed.h"
-#include "GrGpuVertex.h"
-
-#define SKIP_CACHE_CHECK true
-
-struct GrGpuMatrix {
- GrGLfloat fMat[16];
-
- void reset() {
- Gr_bzero(fMat, sizeof(fMat));
- fMat[0] = fMat[5] = fMat[10] = fMat[15] = GR_Scalar1;
- }
-
- void set(const GrMatrix& m) {
- Gr_bzero(fMat, sizeof(fMat));
- fMat[0] = GrScalarToFloat(m[GrMatrix::kMScaleX]);
- fMat[4] = GrScalarToFloat(m[GrMatrix::kMSkewX]);
- fMat[12] = GrScalarToFloat(m[GrMatrix::kMTransX]);
-
- fMat[1] = GrScalarToFloat(m[GrMatrix::kMSkewY]);
- fMat[5] = GrScalarToFloat(m[GrMatrix::kMScaleY]);
- fMat[13] = GrScalarToFloat(m[GrMatrix::kMTransY]);
-
- fMat[3] = GrScalarToFloat(m[GrMatrix::kMPersp0]);
- fMat[7] = GrScalarToFloat(m[GrMatrix::kMPersp1]);
- fMat[15] = GrScalarToFloat(m[GrMatrix::kMPersp2]);
-
- fMat[10] = 1.f; // z-scale
- }
-};
-
-// these must match the order in the corresponding enum in GrGpu.h
-static const GrGLenum gMatrixMode2Enum[] = {
- GR_GL_MODELVIEW, GR_GL_TEXTURE
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-GrGpuGLFixed::GrGpuGLFixed() {
- f4X4DownsampleFilterSupport = false;
- fDualSourceBlendingSupport = false;
-}
-
-GrGpuGLFixed::~GrGpuGLFixed() {
-}
-
-void GrGpuGLFixed::resetContext() {
- INHERITED::resetContext();
-
- GR_GL(Disable(GR_GL_TEXTURE_2D));
-
- for (int s = 0; s < kNumStages; ++s) {
- setTextureUnit(s);
- GR_GL(EnableClientState(GR_GL_VERTEX_ARRAY));
- GR_GL(TexEnvi(GR_GL_TEXTURE_ENV, GR_GL_TEXTURE_ENV_MODE, GR_GL_COMBINE));
- GR_GL(TexEnvi(GR_GL_TEXTURE_ENV, GR_GL_COMBINE_RGB, GR_GL_MODULATE));
- GR_GL(TexEnvi(GR_GL_TEXTURE_ENV, GR_GL_SRC0_RGB, GR_GL_TEXTURE0+s));
- GR_GL(TexEnvi(GR_GL_TEXTURE_ENV, GR_GL_SRC1_RGB, GR_GL_PREVIOUS));
- GR_GL(TexEnvi(GR_GL_TEXTURE_ENV, GR_GL_OPERAND1_RGB, GR_GL_SRC_COLOR));
-
- GR_GL(TexEnvi(GR_GL_TEXTURE_ENV, GR_GL_COMBINE_ALPHA, GR_GL_MODULATE));
- GR_GL(TexEnvi(GR_GL_TEXTURE_ENV, GR_GL_SRC0_ALPHA, GR_GL_TEXTURE0+s));
- GR_GL(TexEnvi(GR_GL_TEXTURE_ENV, GR_GL_OPERAND0_ALPHA, GR_GL_SRC_ALPHA));
- GR_GL(TexEnvi(GR_GL_TEXTURE_ENV, GR_GL_SRC1_ALPHA, GR_GL_PREVIOUS));
- GR_GL(TexEnvi(GR_GL_TEXTURE_ENV, GR_GL_OPERAND1_ALPHA, GR_GL_SRC_ALPHA));
-
- // color oprand0 changes between GL_SRC_COLR and GL_SRC_ALPHA depending
- // upon whether we have a (premultiplied) RGBA texture or just an ALPHA
- // texture, e.g.:
- //glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
- fHWRGBOperand0[s] = (TextureEnvRGBOperands) -1;
- }
-
- fHWGeometryState.fVertexLayout = 0;
- fHWGeometryState.fVertexOffset = ~0;
- GR_GL(EnableClientState(GR_GL_VERTEX_ARRAY));
- GR_GL(DisableClientState(GR_GL_TEXTURE_COORD_ARRAY));
- GR_GL(ShadeModel(GR_GL_FLAT));
- GR_GL(DisableClientState(GR_GL_COLOR_ARRAY));
-
- GR_GL(PointSize(1.f));
-
- GrGLClearErr();
- fTextVerts = false;
-
- fBaseVertex = 0xffffffff;
-}
-
-
-void GrGpuGLFixed::flushProjectionMatrix() {
- float mat[16];
- Gr_bzero(mat, sizeof(mat));
-
- GrAssert(NULL != fCurrDrawState.fRenderTarget);
-
- mat[0] = 2.f / fCurrDrawState.fRenderTarget->width();
- mat[5] = -2.f / fCurrDrawState.fRenderTarget->height();
- mat[10] = -1.f;
- mat[15] = 1;
-
- mat[12] = -1.f;
- mat[13] = 1.f;
-
- GR_GL(MatrixMode(GR_GL_PROJECTION));
- GR_GL(LoadMatrixf(mat));
-}
-
-bool GrGpuGLFixed::flushGraphicsState(GrPrimitiveType type) {
-
- bool usingTextures[kNumStages];
-
- for (int s = 0; s < kNumStages; ++s) {
- usingTextures[s] = this->isStageEnabled(s);
- if (usingTextures[s] && fCurrDrawState.fSamplerStates[s].isGradient()) {
- unimpl("Fixed pipe doesn't support radial/sweep gradients");
- return false;
- }
- }
-
- if (GR_GL_SUPPORT_ES1) {
- if (BlendCoeffReferencesConstant(fCurrDrawState.fSrcBlend) ||
- BlendCoeffReferencesConstant(fCurrDrawState.fDstBlend)) {
- unimpl("ES1 doesn't support blend constant");
- return false;
- }
- }
-
- if (!flushGLStateCommon(type)) {
- return false;
- }
-
- this->flushBlend(type, fCurrDrawState.fSrcBlend, fCurrDrawState.fDstBlend);
-
- if (fDirtyFlags.fRenderTargetChanged) {
- flushProjectionMatrix();
- }
-
- for (int s = 0; s < kNumStages; ++s) {
- bool wasUsingTexture = StageWillBeUsed(s, fHWGeometryState.fVertexLayout, fHWDrawState);
- if (usingTextures[s] != wasUsingTexture) {
- setTextureUnit(s);
- if (usingTextures[s]) {
- GR_GL(Enable(GR_GL_TEXTURE_2D));
- } else {
- GR_GL(Disable(GR_GL_TEXTURE_2D));
- }
- }
- }
-
- uint32_t vertColor = (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit);
- uint32_t prevVertColor = (fHWGeometryState.fVertexLayout &
- kColor_VertexLayoutBit);
-
- if (vertColor != prevVertColor) {
- if (vertColor) {
- GR_GL(ShadeModel(GR_GL_SMOOTH));
- // invalidate the immediate mode color
- fHWDrawState.fColor = GrColor_ILLEGAL;
- } else {
- GR_GL(ShadeModel(GR_GL_FLAT));
- }
- }
-
-
- if (!vertColor && fHWDrawState.fColor != fCurrDrawState.fColor) {
- GR_GL(Color4ub(GrColorUnpackR(fCurrDrawState.fColor),
- GrColorUnpackG(fCurrDrawState.fColor),
- GrColorUnpackB(fCurrDrawState.fColor),
- GrColorUnpackA(fCurrDrawState.fColor)));
- fHWDrawState.fColor = fCurrDrawState.fColor;
- }
-
- // set texture environment, decide whether we are modulating by RGB or A.
- for (int s = 0; s < kNumStages; ++s) {
- if (usingTextures[s]) {
- GrGLTexture* texture = (GrGLTexture*)fCurrDrawState.fTextures[s];
- if (NULL != texture) {
- TextureEnvRGBOperands nextRGBOperand0 =
- (GrPixelConfigIsAlphaOnly(texture->config())) ?
- kAlpha_TextureEnvRGBOperand :
- kColor_TextureEnvRGBOperand;
- if (fHWRGBOperand0[s] != nextRGBOperand0) {
- setTextureUnit(s);
- GR_GL(TexEnvi(GR_GL_TEXTURE_ENV,
- GR_GL_OPERAND0_RGB,
- (nextRGBOperand0==kAlpha_TextureEnvRGBOperand) ?
- GR_GL_SRC_ALPHA :
- GR_GL_SRC_COLOR));
- fHWRGBOperand0[s] = nextRGBOperand0;
- }
-
- if (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
- (fHWDrawState.fSamplerStates[s].getMatrix() !=
- getSamplerMatrix(s))) {
-
- GrMatrix texMat = getSamplerMatrix(s);
- AdjustTextureMatrix(texture,
- GrSamplerState::kNormal_SampleMode,
- &texMat);
- GrGpuMatrix glm;
- glm.set(texMat);
- setTextureUnit(s);
- GR_GL(MatrixMode(GR_GL_TEXTURE));
- GR_GL(LoadMatrixf(glm.fMat));
- recordHWSamplerMatrix(s, getSamplerMatrix(s));
- }
- } else {
- GrAssert(!"Rendering with texture vert flag set but no bound texture");
- return false;
- }
- }
- }
-
- if (fHWDrawState.fViewMatrix != fCurrDrawState.fViewMatrix) {
- GrGpuMatrix glm;
- glm.set(fCurrDrawState.fViewMatrix);
- GR_GL(MatrixMode(GR_GL_MODELVIEW));
- GR_GL(LoadMatrixf(glm.fMat));
- fHWDrawState.fViewMatrix =
- fCurrDrawState.fViewMatrix;
- }
- resetDirtyFlags();
- return true;
-}
-
-void GrGpuGLFixed::setupGeometry(int* startVertex,
- int* startIndex,
- int vertexCount,
- int indexCount) {
-
- int newColorOffset;
- int newTexCoordOffsets[kNumStages];
-
- GrGLsizei newStride = VertexSizeAndOffsetsByStage(fGeometrySrc.fVertexLayout,
- newTexCoordOffsets,
- &newColorOffset);
- int oldColorOffset;
- int oldTexCoordOffsets[kNumStages];
- GrGLsizei oldStride = VertexSizeAndOffsetsByStage(fHWGeometryState.fVertexLayout,
- oldTexCoordOffsets,
- &oldColorOffset);
-
- bool indexed = NULL != startIndex;
-
- int extraVertexOffset;
- int extraIndexOffset;
- setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
-
- GrGLenum scalarType;
- if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
- scalarType = GrGLTextType;
- } else {
- scalarType = GrGLType;
- }
-
- size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
- *startVertex = 0;
- if (indexed) {
- *startIndex += extraIndexOffset;
- }
-
- // all the Pointers must be set if any of these are true
- bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
- vertexOffset != fHWGeometryState.fVertexOffset ||
- newStride != oldStride;
-
- // position and tex coord offsets change if above conditions are true
- // or the type changed based on text vs nontext type coords.
- bool posAndTexChange = allOffsetsChange ||
- ((GrGLTextType != GrGLType) &&
- (kTextFormat_VertexLayoutBit &
- (fHWGeometryState.fVertexLayout ^
- fGeometrySrc.fVertexLayout)));
-
- if (posAndTexChange) {
- GR_GL(VertexPointer(2, scalarType, newStride, (GrGLvoid*)vertexOffset));
- fHWGeometryState.fVertexOffset = vertexOffset;
- }
-
- for (int s = 0; s < kNumStages; ++s) {
- // need to enable array if tex coord offset is 0
- // (using positions as coords)
- if (newTexCoordOffsets[s] >= 0) {
- GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[s]);
- if (oldTexCoordOffsets[s] < 0) {
- GR_GL(ClientActiveTexture(GR_GL_TEXTURE0+s));
- GR_GL(EnableClientState(GR_GL_TEXTURE_COORD_ARRAY));
- GR_GL(TexCoordPointer(2, scalarType, newStride, texCoordOffset));
- } else if (posAndTexChange ||
- newTexCoordOffsets[s] != oldTexCoordOffsets[s]) {
- GR_GL(ClientActiveTexture(GR_GL_TEXTURE0+s));
- GR_GL(TexCoordPointer(2, scalarType, newStride, texCoordOffset));
- }
- } else if (oldTexCoordOffsets[s] >= 0) {
- GR_GL(ClientActiveTexture(GR_GL_TEXTURE0+s));
- GR_GL(DisableClientState(GR_GL_TEXTURE_COORD_ARRAY));
- }
- }
-
- if (newColorOffset > 0) {
- GrGLvoid* colorOffset = (GrGLvoid*)(vertexOffset + newColorOffset);
- if (oldColorOffset <= 0) {
- GR_GL(EnableClientState(GR_GL_COLOR_ARRAY));
- GR_GL(ColorPointer(4, GR_GL_UNSIGNED_BYTE, newStride, colorOffset));
- } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
- GR_GL(ColorPointer(4, GR_GL_UNSIGNED_BYTE, newStride, colorOffset));
- }
- } else if (oldColorOffset > 0) {
- GR_GL(DisableClientState(GR_GL_COLOR_ARRAY));
- }
-
- fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
- fHWGeometryState.fArrayPtrsDirty = false;
-}
diff --git a/gpu/src/GrGpuGLFixed.h b/gpu/src/GrGpuGLFixed.h
deleted file mode 100644
index 487c09f..0000000
--- a/gpu/src/GrGpuGLFixed.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#ifndef GrGpuGLFixed_DEFINED
-#define GrGpuGLFixed_DEFINED
-
-#include "GrGpuGL.h"
-
-// Fixed Pipeline OpenGL or OpenGL ES 1.x
-class GrGpuGLFixed : public GrGpuGL {
-public:
- GrGpuGLFixed();
- virtual ~GrGpuGLFixed();
-
-protected:
- // overrides from GrGpu
- virtual bool flushGraphicsState(GrPrimitiveType type);
- virtual void setupGeometry(int* startVertex,
- int* startIndex,
- int vertexCount,
- int indexCount);
-
-private:
- virtual void resetContext();
-
- // Helpers to make code more readable
- const GrMatrix& getHWSamplerMatrix(int stage) const {
- return fHWDrawState.fSamplerStates[stage].getMatrix();
- }
- void recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
- fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
- }
-
- // when the texture is GL_RGBA we set the GL_COMBINE texture
- // environment rgb operand 0 to be GL_COLOR to modulate each incoming
- // R,G, & B by the texture's R, G, & B. When the texture is alpha-only we
- // set the operand to GL_ALPHA so that the incoming frag's R, G, &B are all
- // modulated by the texture's A.
- enum TextureEnvRGBOperands {
- kAlpha_TextureEnvRGBOperand,
- kColor_TextureEnvRGBOperand,
- };
- TextureEnvRGBOperands fHWRGBOperand0[kNumStages];
-
- void flushProjectionMatrix();
-
- // are the currently bound vertex buffers/arrays laid
- // out for text or other drawing.
- bool fTextVerts;
-
- // On GL we have to build the base vertex offset into the
- // glVertexPointer/glTexCoordPointer/etc
- int fBaseVertex;
-
- typedef GrGpuGL INHERITED;
-};
-
-#endif
diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
deleted file mode 100644
index 0a933b5..0000000
--- a/gpu/src/GrGpuGLShaders.cpp
+++ /dev/null
@@ -1,845 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "GrBinHashKey.h"
-#include "GrGLProgram.h"
-#include "GrGpuGLShaders.h"
-#include "GrGpuVertex.h"
-#include "GrMemory.h"
-#include "GrNoncopyable.h"
-#include "GrStringBuilder.h"
-#include "GrRandom.h"
-
-#define SKIP_CACHE_CHECK true
-#define GR_UINT32_MAX static_cast<uint32_t>(-1)
-
-#include "GrTHashCache.h"
-
-class GrGpuGLShaders::ProgramCache : public ::GrNoncopyable {
-private:
- class Entry;
-
-#if GR_DEBUG
- typedef GrBinHashKey<Entry, 4> ProgramHashKey; // Flex the dynamic allocation muscle in debug
-#else
- typedef GrBinHashKey<Entry, 64> ProgramHashKey;
-#endif
-
- class Entry : public ::GrNoncopyable {
- public:
- Entry() {}
- void copyAndTakeOwnership(Entry& entry) {
- fProgramData.copyAndTakeOwnership(entry.fProgramData);
- fKey.copyAndTakeOwnership(entry.fKey); // ownership transfer
- fLRUStamp = entry.fLRUStamp;
- }
-
- public:
- int compare(const ProgramHashKey& key) const { return fKey.compare(key); }
-
- public:
- GrGLProgram::CachedData fProgramData;
- ProgramHashKey fKey;
- unsigned int fLRUStamp;
- };
-
- GrTHashTable<Entry, ProgramHashKey, 8> fHashCache;
-
- // We may have kMaxEntries+1 shaders in the GL context because
- // we create a new shader before evicting from the cache.
- enum {
- kMaxEntries = 32
- };
- Entry fEntries[kMaxEntries];
- int fCount;
- unsigned int fCurrLRUStamp;
-
-public:
- ProgramCache()
- : fCount(0)
- , fCurrLRUStamp(0) {
- }
-
- ~ProgramCache() {
- for (int i = 0; i < fCount; ++i) {
- GrGpuGLShaders::DeleteProgram(&fEntries[i].fProgramData);
- }
- }
-
- void abandon() {
- fCount = 0;
- }
-
- void invalidateViewMatrices() {
- for (int i = 0; i < fCount; ++i) {
- // set to illegal matrix
- fEntries[i].fProgramData.fViewMatrix = GrMatrix::InvalidMatrix();
- }
- }
-
- GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc) {
- Entry newEntry;
- while (newEntry.fKey.doPass()) {
- desc.buildKey(newEntry.fKey);
- }
- Entry* entry = fHashCache.find(newEntry.fKey);
- if (NULL == entry) {
- if (!desc.genProgram(&newEntry.fProgramData)) {
- return NULL;
- }
- if (fCount < kMaxEntries) {
- entry = fEntries + fCount;
- ++fCount;
- } else {
- GrAssert(kMaxEntries == fCount);
- entry = fEntries;
- for (int i = 1; i < kMaxEntries; ++i) {
- if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
- entry = fEntries + i;
- }
- }
- fHashCache.remove(entry->fKey, entry);
- GrGpuGLShaders::DeleteProgram(&entry->fProgramData);
- }
- entry->copyAndTakeOwnership(newEntry);
- fHashCache.insert(entry->fKey, entry);
- }
-
- entry->fLRUStamp = fCurrLRUStamp;
- if (GR_UINT32_MAX == fCurrLRUStamp) {
- // wrap around! just trash our LRU, one time hit.
- for (int i = 0; i < fCount; ++i) {
- fEntries[i].fLRUStamp = 0;
- }
- }
- ++fCurrLRUStamp;
- return &entry->fProgramData;
- }
-};
-
-void GrGpuGLShaders::abandonResources(){
- INHERITED::abandonResources();
- fProgramCache->abandon();
-}
-
-void GrGpuGLShaders::DeleteProgram(GrGLProgram::CachedData* programData) {
- GR_GL(DeleteShader(programData->fVShaderID));
- GR_GL(DeleteShader(programData->fFShaderID));
- GR_GL(DeleteProgram(programData->fProgramID));
- GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));)
-}
-
-void GrGpuGLShaders::ProgramUnitTest() {
-
- static const int STAGE_OPTS[] = {
- 0,
- GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit,
- GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping
- };
- static const GrGLProgram::ProgramDesc::StageDesc::Modulation STAGE_MODULATES[] = {
- GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation,
- GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation
- };
- static const GrGLProgram::ProgramDesc::StageDesc::CoordMapping STAGE_COORD_MAPPINGS[] = {
- GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping,
- GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping,
- GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping,
- GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping
- };
- static const GrGLProgram::ProgramDesc::StageDesc::FetchMode FETCH_MODES[] = {
- GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode,
- GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode,
- };
- GrGLProgram program;
- GrGLProgram::ProgramDesc& pdesc = program.fProgramDesc;
-
- static const int NUM_TESTS = 512;
-
- // GrRandoms nextU() values have patterns in the low bits
- // So using nextU() % array_count might never take some values.
- GrRandom random;
- for (int t = 0; t < NUM_TESTS; ++t) {
-
-#if 0
- GrPrintf("\nTest Program %d\n-------------\n", t);
- static const int stop = -1;
- if (t == stop) {
- int breakpointhere = 9;
- }
-#endif
-
- pdesc.fVertexLayout = 0;
- pdesc.fEmitsPointSize = random.nextF() > .5f;
- float colorType = random.nextF();
- if (colorType < 1.f / 3.f) {
- pdesc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
- } else if (colorType < 2.f / 3.f) {
- pdesc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
- } else {
- pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
- }
-
- int idx = (int)(random.nextF() * (SkXfermode::kCoeffModesCnt));
- pdesc.fColorFilterXfermode = (SkXfermode::Mode)idx;
-
- idx = (int)(random.nextF() * (kNumStages+1));
- pdesc.fFirstCoverageStage = idx;
-
- pdesc.fEdgeAANumEdges = (random.nextF() * (getMaxEdges() + 1));
-
- if (fDualSourceBlendingSupport) {
- pdesc.fDualSrcOutput =
- (GrGLProgram::ProgramDesc::DualSrcOutput)
- (int)(random.nextF() * GrGLProgram::ProgramDesc::kDualSrcOutputCnt);
- } else {
- pdesc.fDualSrcOutput =
- GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
- }
-
- for (int s = 0; s < kNumStages; ++s) {
- // enable the stage?
- if (random.nextF() > .5f) {
- // use separate tex coords?
- if (random.nextF() > .5f) {
- int t = (int)(random.nextF() * kMaxTexCoords);
- pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
- } else {
- pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
- }
- }
- // use text-formatted verts?
- if (random.nextF() > .5f) {
- pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
- }
- idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
- pdesc.fStages[s].fOptFlags = STAGE_OPTS[idx];
- idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
- pdesc.fStages[s].fModulation = STAGE_MODULATES[idx];
- idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
- pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[idx];
- idx = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES));
- pdesc.fStages[s].fFetchMode = FETCH_MODES[idx];
- pdesc.fStages[s].setEnabled(VertexUsesStage(s, pdesc.fVertexLayout));
- }
- GrGLProgram::CachedData cachedData;
- program.genProgram(&cachedData);
- DeleteProgram(&cachedData);
- bool again = false;
- if (again) {
- program.genProgram(&cachedData);
- DeleteProgram(&cachedData);
- }
- }
-}
-
-GrGpuGLShaders::GrGpuGLShaders() {
-
- resetContext();
- int major, minor;
- gl_version(&major, &minor);
-
- f4X4DownsampleFilterSupport = true;
- if (GR_GL_SUPPORT_DESKTOP) {
- fDualSourceBlendingSupport =
- major > 3 ||(3 == major && 3 <= minor) ||
- has_gl_extension("GL_ARB_blend_func_extended");
- } else {
- fDualSourceBlendingSupport = false;
- }
-
- fProgramData = NULL;
- fProgramCache = new ProgramCache();
-
-#if 0
- ProgramUnitTest();
-#endif
-}
-
-GrGpuGLShaders::~GrGpuGLShaders() {
- delete fProgramCache;
-}
-
-const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
- GrAssert(fProgramData);
-
- if (GrGLProgram::kSetAsAttribute ==
- fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
- return fHWDrawState.fSamplerStates[stage].getMatrix();
- } else {
- return fProgramData->fTextureMatrices[stage];
- }
-}
-
-void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
- GrAssert(fProgramData);
- if (GrGLProgram::kSetAsAttribute ==
- fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
- fHWDrawState.fSamplerStates[stage].setMatrix(matrix);
- } else {
- fProgramData->fTextureMatrices[stage] = matrix;
- }
-}
-
-void GrGpuGLShaders::resetContext() {
- INHERITED::resetContext();
-
- fHWGeometryState.fVertexLayout = 0;
- fHWGeometryState.fVertexOffset = ~0;
- GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
- for (int t = 0; t < kMaxTexCoords; ++t) {
- GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
- }
- GR_GL(EnableVertexAttribArray(GrGLProgram::PositionAttributeIdx()));
-
- fHWProgramID = 0;
-}
-
-void GrGpuGLShaders::flushViewMatrix() {
- GrAssert(NULL != fCurrDrawState.fRenderTarget);
- GrMatrix m;
- m.setAll(
- GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
- 0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
- 0, 0, GrMatrix::I()[8]);
- m.setConcat(m, fCurrDrawState.fViewMatrix);
-
- // ES doesn't allow you to pass true to the transpose param,
- // so do our own transpose
- GrGLfloat mt[] = {
- GrScalarToFloat(m[GrMatrix::kMScaleX]),
- GrScalarToFloat(m[GrMatrix::kMSkewY]),
- GrScalarToFloat(m[GrMatrix::kMPersp0]),
- GrScalarToFloat(m[GrMatrix::kMSkewX]),
- GrScalarToFloat(m[GrMatrix::kMScaleY]),
- GrScalarToFloat(m[GrMatrix::kMPersp1]),
- GrScalarToFloat(m[GrMatrix::kMTransX]),
- GrScalarToFloat(m[GrMatrix::kMTransY]),
- GrScalarToFloat(m[GrMatrix::kMPersp2])
- };
-
- if (GrGLProgram::kSetAsAttribute ==
- fProgramData->fUniLocations.fViewMatrixUni) {
- int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
- GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
- GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
- GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
- } else {
- GrAssert(GrGLProgram::kUnusedUniform !=
- fProgramData->fUniLocations.fViewMatrixUni);
- GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
- 1, false, mt));
- }
-}
-
-void GrGpuGLShaders::flushTextureDomain(int s) {
- const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni;
- if (GrGLProgram::kUnusedUniform != uni) {
- const GrRect &texDom =
- fCurrDrawState.fSamplerStates[s].getTextureDomain();
-
- if (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
- fProgramData->fTextureDomain[s] != texDom) {
-
- fProgramData->fTextureDomain[s] = texDom;
-
- float values[4] = {
- GrScalarToFloat(texDom.left()),
- GrScalarToFloat(texDom.top()),
- GrScalarToFloat(texDom.right()),
- GrScalarToFloat(texDom.bottom())
- };
-
- GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
- GrGLTexture::Orientation orientation = texture->orientation();
-
- // vertical flip if necessary
- if (GrGLTexture::kBottomUp_Orientation == orientation) {
- values[1] = 1.0f - values[1];
- values[3] = 1.0f - values[3];
- // The top and bottom were just flipped, so correct the ordering
- // of elements so that values = (l, t, r, b).
- SkTSwap(values[1], values[3]);
- }
-
- values[0] *= SkScalarToFloat(texture->contentScaleX());
- values[2] *= SkScalarToFloat(texture->contentScaleX());
- values[1] *= SkScalarToFloat(texture->contentScaleY());
- values[3] *= SkScalarToFloat(texture->contentScaleY());
-
- GR_GL(Uniform4fv(uni, 1, values));
- }
- }
-}
-
-void GrGpuGLShaders::flushTextureMatrix(int s) {
- const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
- GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
- if (NULL != texture) {
- if (GrGLProgram::kUnusedUniform != uni &&
- (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
- getHWSamplerMatrix(s) != getSamplerMatrix(s))) {
-
- GrAssert(NULL != fCurrDrawState.fTextures[s]);
-
- GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
-
- GrMatrix m = getSamplerMatrix(s);
- GrSamplerState::SampleMode mode =
- fCurrDrawState.fSamplerStates[s].getSampleMode();
- AdjustTextureMatrix(texture, mode, &m);
-
- // ES doesn't allow you to pass true to the transpose param,
- // so do our own transpose
- GrGLfloat mt[] = {
- GrScalarToFloat(m[GrMatrix::kMScaleX]),
- GrScalarToFloat(m[GrMatrix::kMSkewY]),
- GrScalarToFloat(m[GrMatrix::kMPersp0]),
- GrScalarToFloat(m[GrMatrix::kMSkewX]),
- GrScalarToFloat(m[GrMatrix::kMScaleY]),
- GrScalarToFloat(m[GrMatrix::kMPersp1]),
- GrScalarToFloat(m[GrMatrix::kMTransX]),
- GrScalarToFloat(m[GrMatrix::kMTransY]),
- GrScalarToFloat(m[GrMatrix::kMPersp2])
- };
-
- if (GrGLProgram::kSetAsAttribute ==
- fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
- int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
- GR_GL(VertexAttrib4fv(baseIdx + 0, mt+0));
- GR_GL(VertexAttrib4fv(baseIdx + 1, mt+3));
- GR_GL(VertexAttrib4fv(baseIdx + 2, mt+6));
- } else {
- GR_GL(UniformMatrix3fv(uni, 1, false, mt));
- }
- recordHWSamplerMatrix(s, getSamplerMatrix(s));
- }
- }
-}
-
-void GrGpuGLShaders::flushRadial2(int s) {
-
- const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
- const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[s];
- if (GrGLProgram::kUnusedUniform != uni &&
- (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
- fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
- fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
-
- GrScalar centerX1 = sampler.getRadial2CenterX1();
- GrScalar radius0 = sampler.getRadial2Radius0();
-
- GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
-
- float values[6] = {
- GrScalarToFloat(a),
- 1 / (2.f * values[0]),
- GrScalarToFloat(centerX1),
- GrScalarToFloat(radius0),
- GrScalarToFloat(GrMul(radius0, radius0)),
- sampler.isRadial2PosRoot() ? 1.f : -1.f
- };
- GR_GL(Uniform1fv(uni, 6, values));
- fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
- fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
- fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
- }
-}
-
-void GrGpuGLShaders::flushTexelSize(int s) {
- const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
- if (GrGLProgram::kUnusedUniform != uni) {
- GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
- if (texture->allocWidth() != fProgramData->fTextureWidth[s] ||
- texture->allocHeight() != fProgramData->fTextureWidth[s]) {
-
- float texelSize[] = {1.f / texture->allocWidth(),
- 1.f / texture->allocHeight()};
- GR_GL(Uniform2fv(uni, 1, texelSize));
- }
- }
-}
-
-void GrGpuGLShaders::flushEdgeAAData() {
- const int& uni = fProgramData->fUniLocations.fEdgesUni;
- if (GrGLProgram::kUnusedUniform != uni) {
- int count = fCurrDrawState.fEdgeAANumEdges;
- Edge edges[kMaxEdges];
- // Flip the edges in Y
- float height = fCurrDrawState.fRenderTarget->height();
- for (int i = 0; i < count; ++i) {
- edges[i] = fCurrDrawState.fEdgeAAEdges[i];
- float b = edges[i].fY;
- edges[i].fY = -b;
- edges[i].fZ += b * height;
- }
- GR_GL(Uniform3fv(uni, count, &edges[0].fX));
- }
-}
-
-static const float ONE_OVER_255 = 1.f / 255.f;
-
-#define GR_COLOR_TO_VEC4(color) {\
- GrColorUnpackR(color) * ONE_OVER_255,\
- GrColorUnpackG(color) * ONE_OVER_255,\
- GrColorUnpackB(color) * ONE_OVER_255,\
- GrColorUnpackA(color) * ONE_OVER_255 \
-}
-
-void GrGpuGLShaders::flushColor() {
- const GrGLProgram::ProgramDesc& desc = fCurrentProgram.getDesc();
- if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
- // color will be specified per-vertex as an attribute
- // invalidate the const vertex attrib color
- fHWDrawState.fColor = GrColor_ILLEGAL;
- } else {
- switch (desc.fColorType) {
- case GrGLProgram::ProgramDesc::kAttribute_ColorType:
- if (fHWDrawState.fColor != fCurrDrawState.fColor) {
- // OpenGL ES only supports the float varities of glVertexAttrib
- float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
- GR_GL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(), c));
- fHWDrawState.fColor = fCurrDrawState.fColor;
- }
- break;
- case GrGLProgram::ProgramDesc::kUniform_ColorType:
- if (fProgramData->fColor != fCurrDrawState.fColor) {
- // OpenGL ES only supports the float varities of glVertexAttrib
- float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
- GrAssert(GrGLProgram::kUnusedUniform !=
- fProgramData->fUniLocations.fColorUni);
- GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorUni, 1, c));
- fProgramData->fColor = fCurrDrawState.fColor;
- }
- break;
- case GrGLProgram::ProgramDesc::kNone_ColorType:
- GrAssert(0xffffffff == fCurrDrawState.fColor);
- break;
- default:
- GrCrash("Unknown color type.");
- }
- }
- if (fProgramData->fUniLocations.fColorFilterUni
- != GrGLProgram::kUnusedUniform
- && fProgramData->fColorFilterColor
- != fCurrDrawState.fColorFilterColor) {
- float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColorFilterColor);
- GR_GL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
- fProgramData->fColorFilterColor = fCurrDrawState.fColorFilterColor;
- }
-}
-
-
-bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
- if (!flushGLStateCommon(type)) {
- return false;
- }
-
- if (fDirtyFlags.fRenderTargetChanged) {
- // our coords are in pixel space and the GL matrices map to NDC
- // so if the viewport changed, our matrix is now wrong.
- fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
- // we assume all shader matrices may be wrong after viewport changes
- fProgramCache->invalidateViewMatrices();
- }
-
- buildProgram(type);
- fProgramData = fProgramCache->getProgramData(fCurrentProgram);
- if (NULL == fProgramData) {
- GrAssert(!"Failed to create program!");
- return false;
- }
-
- if (fHWProgramID != fProgramData->fProgramID) {
- GR_GL(UseProgram(fProgramData->fProgramID));
- fHWProgramID = fProgramData->fProgramID;
- }
- GrBlendCoeff srcCoeff = fCurrDrawState.fSrcBlend;
- GrBlendCoeff dstCoeff = fCurrDrawState.fDstBlend;
-
- fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
- this->flushBlend(type, srcCoeff, dstCoeff);
-
- this->flushColor();
-
- GrMatrix* currViewMatrix;
- if (GrGLProgram::kSetAsAttribute ==
- fProgramData->fUniLocations.fViewMatrixUni) {
- currViewMatrix = &fHWDrawState.fViewMatrix;
- } else {
- currViewMatrix = &fProgramData->fViewMatrix;
- }
-
- if (*currViewMatrix != fCurrDrawState.fViewMatrix) {
- flushViewMatrix();
- *currViewMatrix = fCurrDrawState.fViewMatrix;
- }
-
- for (int s = 0; s < kNumStages; ++s) {
- this->flushTextureMatrix(s);
-
- this->flushRadial2(s);
-
- this->flushTexelSize(s);
-
- this->flushTextureDomain(s);
- }
- this->flushEdgeAAData();
- resetDirtyFlags();
- return true;
-}
-
-void GrGpuGLShaders::postDraw() {
-}
-
-void GrGpuGLShaders::setupGeometry(int* startVertex,
- int* startIndex,
- int vertexCount,
- int indexCount) {
-
- int newColorOffset;
- int newTexCoordOffsets[kMaxTexCoords];
-
- GrGLsizei newStride = VertexSizeAndOffsetsByIdx(fGeometrySrc.fVertexLayout,
- newTexCoordOffsets,
- &newColorOffset);
- int oldColorOffset;
- int oldTexCoordOffsets[kMaxTexCoords];
- GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(fHWGeometryState.fVertexLayout,
- oldTexCoordOffsets,
- &oldColorOffset);
- bool indexed = NULL != startIndex;
-
- int extraVertexOffset;
- int extraIndexOffset;
- setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
-
- GrGLenum scalarType;
- bool texCoordNorm;
- if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
- scalarType = GrGLTextType;
- texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
- } else {
- scalarType = GrGLType;
- texCoordNorm = false;
- }
-
- size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
- *startVertex = 0;
- if (indexed) {
- *startIndex += extraIndexOffset;
- }
-
- // all the Pointers must be set if any of these are true
- bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
- vertexOffset != fHWGeometryState.fVertexOffset ||
- newStride != oldStride;
-
- // position and tex coord offsets change if above conditions are true
- // or the type/normalization changed based on text vs nontext type coords.
- bool posAndTexChange = allOffsetsChange ||
- (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
- (kTextFormat_VertexLayoutBit &
- (fHWGeometryState.fVertexLayout ^
- fGeometrySrc.fVertexLayout)));
-
- if (posAndTexChange) {
- int idx = GrGLProgram::PositionAttributeIdx();
- GR_GL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
- (GrGLvoid*)vertexOffset));
- fHWGeometryState.fVertexOffset = vertexOffset;
- }
-
- for (int t = 0; t < kMaxTexCoords; ++t) {
- if (newTexCoordOffsets[t] > 0) {
- GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
- int idx = GrGLProgram::TexCoordAttributeIdx(t);
- if (oldTexCoordOffsets[t] <= 0) {
- GR_GL(EnableVertexAttribArray(idx));
- GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
- newStride, texCoordOffset));
- } else if (posAndTexChange ||
- newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
- GR_GL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
- newStride, texCoordOffset));
- }
- } else if (oldTexCoordOffsets[t] > 0) {
- GR_GL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
- }
- }
-
- if (newColorOffset > 0) {
- GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
- int idx = GrGLProgram::ColorAttributeIdx();
- if (oldColorOffset <= 0) {
- GR_GL(EnableVertexAttribArray(idx));
- GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
- true, newStride, colorOffset));
- } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
- GR_GL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
- true, newStride, colorOffset));
- }
- } else if (oldColorOffset > 0) {
- GR_GL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
- }
-
- fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
- fHWGeometryState.fArrayPtrsDirty = false;
-}
-
-void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
- GrGLProgram::ProgramDesc& desc = fCurrentProgram.fProgramDesc;
-
- // Must initialize all fields or cache will have false negatives!
- desc.fVertexLayout = fGeometrySrc.fVertexLayout;
-
- desc.fEmitsPointSize = kPoints_PrimitiveType == type;
-
- bool requiresAttributeColors = desc.fVertexLayout & kColor_VertexLayoutBit;
- // fColorType records how colors are specified for the program. Strip
- // the bit from the layout to avoid false negatives when searching for an
- // existing program in the cache.
- desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
-
- desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
-
-#if GR_AGGRESSIVE_SHADER_OPTS
- if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
- desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType;
- } else
-#endif
-#if GR_GL_NO_CONSTANT_ATTRIBUTES
- if (!requiresAttributeColors) {
- desc.fColorType = GrGLProgram::ProgramDesc::kUniform_ColorType;
- } else
-#endif
- {
- if (requiresAttributeColors) {} // suppress unused var warning
- desc.fColorType = GrGLProgram::ProgramDesc::kAttribute_ColorType;
- }
-
- desc.fEdgeAANumEdges = fCurrDrawState.fEdgeAANumEdges;
-
- int lastEnabledStage = -1;
-
- for (int s = 0; s < kNumStages; ++s) {
- GrGLProgram::ProgramDesc::StageDesc& stage = desc.fStages[s];
-
- stage.fOptFlags = 0;
- stage.setEnabled(this->isStageEnabled(s));
-
- if (stage.isEnabled()) {
- lastEnabledStage = s;
- GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
- GrAssert(NULL != texture);
- // we matrix to invert when orientation is TopDown, so make sure
- // we aren't in that case before flagging as identity.
- if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) {
- stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit;
- } else if (!getSamplerMatrix(s).hasPerspective()) {
- stage.fOptFlags |= GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit;
- }
- switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) {
- case GrSamplerState::kNormal_SampleMode:
- stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping;
- break;
- case GrSamplerState::kRadial_SampleMode:
- stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping;
- break;
- case GrSamplerState::kRadial2_SampleMode:
- stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping;
- break;
- case GrSamplerState::kSweep_SampleMode:
- stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping;
- break;
- default:
- GrCrash("Unexpected sample mode!");
- break;
- }
-
- switch (fCurrDrawState.fSamplerStates[s].getFilter()) {
- // these both can use a regular texture2D()
- case GrSamplerState::kNearest_Filter:
- case GrSamplerState::kBilinear_Filter:
- stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::kSingle_FetchMode;
- break;
- // performs 4 texture2D()s
- case GrSamplerState::k4x4Downsample_Filter:
- stage.fFetchMode = GrGLProgram::ProgramDesc::StageDesc::k2x2_FetchMode;
- break;
- default:
- GrCrash("Unexpected filter!");
- break;
- }
-
- if (fCurrDrawState.fSamplerStates[s].hasTextureDomain()) {
- GrAssert(GrSamplerState::kClamp_WrapMode ==
- fCurrDrawState.fSamplerStates[s].getWrapX() &&
- GrSamplerState::kClamp_WrapMode ==
- fCurrDrawState.fSamplerStates[s].getWrapY());
- stage.fOptFlags |=
- GrGLProgram::ProgramDesc::StageDesc::
- kCustomTextureDomain_OptFlagBit;
- }
-
- if (GrPixelConfigIsAlphaOnly(texture->config())) {
- stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
- } else {
- stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
- }
- } else {
- stage.fOptFlags = 0;
- stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0;
- stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0;
- }
- }
-
- desc.fDualSrcOutput = GrGLProgram::ProgramDesc::kNone_DualSrcOutput;
- // use canonical value when coverage/color distinction won't affect
- // generated code to prevent duplicate programs.
- desc.fFirstCoverageStage = kNumStages;
- if (fCurrDrawState.fFirstCoverageStage <= lastEnabledStage) {
- // color filter is applied between color/coverage computation
- if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
- desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
- }
-
- // We could consider cases where the final color is solid (0xff alpha)
- // and the dst coeff can correctly be set to a non-dualsrc gl value.
- // (e.g. solid draw, and dst coeff is kZero. It's correct to make
- // the dst coeff be kISA. Or solid draw with kSA can be tweaked to be
- // kOne).
- if (fDualSourceBlendingSupport) {
- if (kZero_BlendCoeff == fCurrDrawState.fDstBlend) {
- // write the coverage value to second color
- desc.fDualSrcOutput =
- GrGLProgram::ProgramDesc::kCoverage_DualSrcOutput;
- desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
- } else if (kSA_BlendCoeff == fCurrDrawState.fDstBlend) {
- // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
- // cover
- desc.fDualSrcOutput =
- GrGLProgram::ProgramDesc::kCoverageISA_DualSrcOutput;
- desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
- } else if (kSC_BlendCoeff == fCurrDrawState.fDstBlend) {
- // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
- // cover
- desc.fDualSrcOutput =
- GrGLProgram::ProgramDesc::kCoverageISC_DualSrcOutput;
- desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage;
- }
- }
- }
-}
diff --git a/gpu/src/GrMemory.cpp b/gpu/src/GrMemory.cpp
deleted file mode 100644
index 3da924a..0000000
--- a/gpu/src/GrMemory.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#include "GrMemory.h"
-
-#include <stdlib.h>
-
-void* GrMalloc(size_t bytes) {
- void* ptr = ::malloc(bytes);
- if (NULL == ptr) {
- ::exit(-1);
- }
- return ptr;
-}
-
-void GrFree(void* ptr) {
- if (ptr) {
- ::free(ptr);
- }
-}
-
-
diff --git a/gpu/src/GrPathRenderer.cpp b/gpu/src/GrPathRenderer.cpp
deleted file mode 100644
index 58bb12e..0000000
--- a/gpu/src/GrPathRenderer.cpp
+++ /dev/null
@@ -1,447 +0,0 @@
-#include "GrPathRenderer.h"
-
-#include "GrPoint.h"
-#include "GrDrawTarget.h"
-#include "GrPathUtils.h"
-#include "GrMemory.h"
-#include "GrTexture.h"
-
-GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
- bool stencilWrapOpsSupport)
- : fSeparateStencil(separateStencilSupport),
- fStencilWrapOps(stencilWrapOpsSupport) {
-
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Stencil rules for paths
-
-////// Even/Odd
-
-static const GrStencilSettings gEOStencilPass = {
- kInvert_StencilOp, kInvert_StencilOp,
- kKeep_StencilOp, kKeep_StencilOp,
- kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0xffffffff, 0xffffffff,
- 0xffffffff, 0xffffffff
-};
-
-// ok not to check clip b/c stencil pass only wrote inside clip
-static const GrStencilSettings gEOColorPass = {
- kZero_StencilOp, kZero_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kNotEqual_StencilFunc, kNotEqual_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x0, 0x0,
- 0xffffffff, 0xffffffff
-};
-
-// have to check clip b/c outside clip will always be zero.
-static const GrStencilSettings gInvEOColorPass = {
- kZero_StencilOp, kZero_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x0, 0x0,
- 0xffffffff, 0xffffffff
-};
-
-////// Winding
-
-// when we have separate stencil we increment front faces / decrement back faces
-// when we don't have wrap incr and decr we use the stencil test to simulate
-// them.
-
-static const GrStencilSettings gWindStencilSeparateWithWrap = {
- kIncWrap_StencilOp, kDecWrap_StencilOp,
- kKeep_StencilOp, kKeep_StencilOp,
- kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0xffffffff, 0xffffffff,
- 0xffffffff, 0xffffffff
-};
-
-// if inc'ing the max value, invert to make 0
-// if dec'ing zero invert to make all ones.
-// we can't avoid touching the stencil on both passing and
-// failing, so we can't resctrict ourselves to the clip.
-static const GrStencilSettings gWindStencilSeparateNoWrap = {
- kInvert_StencilOp, kInvert_StencilOp,
- kIncClamp_StencilOp, kDecClamp_StencilOp,
- kEqual_StencilFunc, kEqual_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0xffffffff, 0x0,
- 0xffffffff, 0xffffffff
-};
-
-// When there are no separate faces we do two passes to setup the winding rule
-// stencil. First we draw the front faces and inc, then we draw the back faces
-// and dec. These are same as the above two split into the incrementing and
-// decrementing passes.
-static const GrStencilSettings gWindSingleStencilWithWrapInc = {
- kIncWrap_StencilOp, kIncWrap_StencilOp,
- kKeep_StencilOp, kKeep_StencilOp,
- kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0xffffffff, 0xffffffff,
- 0xffffffff, 0xffffffff
-};
-static const GrStencilSettings gWindSingleStencilWithWrapDec = {
- kDecWrap_StencilOp, kDecWrap_StencilOp,
- kKeep_StencilOp, kKeep_StencilOp,
- kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0xffffffff, 0xffffffff,
- 0xffffffff, 0xffffffff
-};
-static const GrStencilSettings gWindSingleStencilNoWrapInc = {
- kInvert_StencilOp, kInvert_StencilOp,
- kIncClamp_StencilOp, kIncClamp_StencilOp,
- kEqual_StencilFunc, kEqual_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0xffffffff, 0xffffffff,
- 0xffffffff, 0xffffffff
-};
-static const GrStencilSettings gWindSingleStencilNoWrapDec = {
- kInvert_StencilOp, kInvert_StencilOp,
- kDecClamp_StencilOp, kDecClamp_StencilOp,
- kEqual_StencilFunc, kEqual_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x0, 0x0,
- 0xffffffff, 0xffffffff
-};
-
-static const GrStencilSettings gWindColorPass = {
- kZero_StencilOp, kZero_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kNonZeroIfInClip_StencilFunc, kNonZeroIfInClip_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x0, 0x0,
- 0xffffffff, 0xffffffff
-};
-
-static const GrStencilSettings gInvWindColorPass = {
- kZero_StencilOp, kZero_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x0, 0x0,
- 0xffffffff, 0xffffffff
-};
-
-////// Normal render to stencil
-
-// Sometimes the default path renderer can draw a path directly to the stencil
-// buffer without having to first resolve the interior / exterior.
-static const GrStencilSettings gDirectToStencil = {
- kZero_StencilOp, kZero_StencilOp,
- kIncClamp_StencilOp, kIncClamp_StencilOp,
- kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x0, 0x0,
- 0xffffffff, 0xffffffff
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Helpers for drawPath
-
-static GrConvexHint getConvexHint(const SkPath& path) {
- return path.isConvex() ? kConvex_ConvexHint : kConcave_ConvexHint;
-}
-
-#define STENCIL_OFF 0 // Always disable stencil (even when needed)
-
-static inline bool single_pass_path(const GrDrawTarget& target,
- const GrPath& path,
- GrPathFill fill) {
-#if STENCIL_OFF
- return true;
-#else
- if (kEvenOdd_PathFill == fill) {
- GrConvexHint hint = getConvexHint(path);
- return hint == kConvex_ConvexHint ||
- hint == kNonOverlappingConvexPieces_ConvexHint;
- } else if (kWinding_PathFill == fill) {
- GrConvexHint hint = getConvexHint(path);
- return hint == kConvex_ConvexHint ||
- hint == kNonOverlappingConvexPieces_ConvexHint ||
- (hint == kSameWindingConvexPieces_ConvexHint &&
- target.canDisableBlend() && !target.isDitherState());
-
- }
- return false;
-#endif
-}
-
-bool GrDefaultPathRenderer::requiresStencilPass(const GrDrawTarget* target,
- const GrPath& path,
- GrPathFill fill) const {
- return !single_pass_path(*target, path, fill);
-}
-
-void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
- GrDrawTarget::StageBitfield stages,
- const GrPath& path,
- GrPathFill fill,
- const GrPoint* translate,
- bool stencilOnly) {
-
- GrDrawTarget::AutoStateRestore asr(target);
- bool colorWritesWereDisabled = target->isColorWriteDisabled();
- // face culling doesn't make sense here
- GrAssert(GrDrawTarget::kBoth_DrawFace == target->getDrawFace());
-
- GrMatrix viewM = target->getViewMatrix();
- // In order to tesselate the path we get a bound on how much the matrix can
- // stretch when mapping to screen coordinates.
- GrScalar stretch = viewM.getMaxStretch();
- bool useStretch = stretch > 0;
- GrScalar tol = GrPathUtils::gTolerance;
-
- if (!useStretch) {
- // TODO: deal with perspective in some better way.
- tol /= 10;
- } else {
- tol = GrScalarDiv(tol, stretch);
- }
- GrScalar tolSqd = GrMul(tol, tol);
-
- int subpathCnt;
- int maxPts = GrPathUtils::worstCasePointCount(path, &subpathCnt, tol);
-
- GrVertexLayout layout = 0;
- for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
- if ((1 << s) & stages) {
- layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
- }
- }
-
- // add 4 to hold the bounding rect
- GrDrawTarget::AutoReleaseGeometry arg(target, layout, maxPts + 4, 0);
-
- GrPoint* base = (GrPoint*) arg.vertices();
- GrPoint* vert = base;
- GrPoint* subpathBase = base;
-
- GrAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
-
- // TODO: use primitve restart if available rather than multiple draws
- GrPrimitiveType type;
- int passCount = 0;
- const GrStencilSettings* passes[3];
- GrDrawTarget::DrawFace drawFace[3];
- bool reverse = false;
- bool lastPassIsBounds;
-
- if (kHairLine_PathFill == fill) {
- type = kLineStrip_PrimitiveType;
- passCount = 1;
- if (stencilOnly) {
- passes[0] = &gDirectToStencil;
- } else {
- passes[0] = NULL;
- }
- lastPassIsBounds = false;
- drawFace[0] = GrDrawTarget::kBoth_DrawFace;
- } else {
- type = kTriangleFan_PrimitiveType;
- if (single_pass_path(*target, path, fill)) {
- passCount = 1;
- if (stencilOnly) {
- passes[0] = &gDirectToStencil;
- } else {
- passes[0] = NULL;
- }
- drawFace[0] = GrDrawTarget::kBoth_DrawFace;
- lastPassIsBounds = false;
- } else {
- switch (fill) {
- case kInverseEvenOdd_PathFill:
- reverse = true;
- // fallthrough
- case kEvenOdd_PathFill:
- passes[0] = &gEOStencilPass;
- if (stencilOnly) {
- passCount = 1;
- lastPassIsBounds = false;
- } else {
- passCount = 2;
- lastPassIsBounds = true;
- if (reverse) {
- passes[1] = &gInvEOColorPass;
- } else {
- passes[1] = &gEOColorPass;
- }
- }
- drawFace[0] = drawFace[1] = GrDrawTarget::kBoth_DrawFace;
- break;
-
- case kInverseWinding_PathFill:
- reverse = true;
- // fallthrough
- case kWinding_PathFill:
- if (fSeparateStencil) {
- if (fStencilWrapOps) {
- passes[0] = &gWindStencilSeparateWithWrap;
- } else {
- passes[0] = &gWindStencilSeparateNoWrap;
- }
- passCount = 2;
- drawFace[0] = GrDrawTarget::kBoth_DrawFace;
- } else {
- if (fStencilWrapOps) {
- passes[0] = &gWindSingleStencilWithWrapInc;
- passes[1] = &gWindSingleStencilWithWrapDec;
- } else {
- passes[0] = &gWindSingleStencilNoWrapInc;
- passes[1] = &gWindSingleStencilNoWrapDec;
- }
- // which is cw and which is ccw is arbitrary.
- drawFace[0] = GrDrawTarget::kCW_DrawFace;
- drawFace[1] = GrDrawTarget::kCCW_DrawFace;
- passCount = 3;
- }
- if (stencilOnly) {
- lastPassIsBounds = false;
- --passCount;
- } else {
- lastPassIsBounds = true;
- drawFace[passCount-1] = GrDrawTarget::kBoth_DrawFace;
- if (reverse) {
- passes[passCount-1] = &gInvWindColorPass;
- } else {
- passes[passCount-1] = &gWindColorPass;
- }
- }
- break;
- default:
- GrAssert(!"Unknown path fill!");
- return;
- }
- }
- }
-
- GrPoint pts[4];
-
- bool first = true;
- int subpath = 0;
-
- SkPath::Iter iter(path, false);
-
- for (;;) {
- GrPathCmd cmd = (GrPathCmd)iter.next(pts);
- switch (cmd) {
- case kMove_PathCmd:
- if (!first) {
- subpathVertCount[subpath] = vert-subpathBase;
- subpathBase = vert;
- ++subpath;
- }
- *vert = pts[0];
- vert++;
- break;
- case kLine_PathCmd:
- *vert = pts[1];
- vert++;
- break;
- case kQuadratic_PathCmd: {
- GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
- tolSqd, &vert,
- GrPathUtils::quadraticPointCount(pts, tol));
- break;
- }
- case kCubic_PathCmd: {
- GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
- tolSqd, &vert,
- GrPathUtils::cubicPointCount(pts, tol));
- break;
- }
- case kClose_PathCmd:
- break;
- case kEnd_PathCmd:
- subpathVertCount[subpath] = vert-subpathBase;
- ++subpath; // this could be only in debug
- goto FINISHED;
- }
- first = false;
- }
-FINISHED:
- GrAssert(subpath == subpathCnt);
- GrAssert((vert - base) <= maxPts);
-
- if (translate) {
- int count = vert - base;
- for (int i = 0; i < count; i++) {
- base[i].offset(translate->fX, translate->fY);
- }
- }
-
- // if we're stenciling we will follow with a pass that draws
- // a bounding rect to set the color. We're stenciling when
- // passCount > 1.
- const int& boundVertexStart = maxPts;
- GrPoint* boundsVerts = base + boundVertexStart;
- if (lastPassIsBounds) {
- GrRect bounds;
- if (reverse) {
- GrAssert(NULL != target->getRenderTarget());
- // draw over the whole world.
- bounds.setLTRB(0, 0,
- GrIntToScalar(target->getRenderTarget()->width()),
- GrIntToScalar(target->getRenderTarget()->height()));
- GrMatrix vmi;
- if (target->getViewInverse(&vmi)) {
- vmi.mapRect(&bounds);
- }
- } else {
- bounds.setBounds((GrPoint*)base, vert - base);
- }
- boundsVerts[0].setRectFan(bounds.fLeft, bounds.fTop, bounds.fRight,
- bounds.fBottom);
- }
-
- for (int p = 0; p < passCount; ++p) {
- target->setDrawFace(drawFace[p]);
- if (NULL != passes[p]) {
- target->setStencil(*passes[p]);
- }
-
- if (lastPassIsBounds && (p == passCount-1)) {
- if (!colorWritesWereDisabled) {
- target->disableState(GrDrawTarget::kNoColorWrites_StateBit);
- }
- target->drawNonIndexed(kTriangleFan_PrimitiveType,
- boundVertexStart, 4);
-
- } else {
- if (passCount > 1) {
- target->enableState(GrDrawTarget::kNoColorWrites_StateBit);
- }
- int baseVertex = 0;
- for (int sp = 0; sp < subpathCnt; ++sp) {
- target->drawNonIndexed(type,
- baseVertex,
- subpathVertCount[sp]);
- baseVertex += subpathVertCount[sp];
- }
- }
- }
-}
-
-void GrDefaultPathRenderer::drawPath(GrDrawTarget* target,
- GrDrawTarget::StageBitfield stages,
- const GrPath& path,
- GrPathFill fill,
- const GrPoint* translate) {
- this->onDrawPath(target, stages, path, fill, translate, false);
-}
-
-void GrDefaultPathRenderer::drawPathToStencil(GrDrawTarget* target,
- const GrPath& path,
- GrPathFill fill,
- const GrPoint* translate) {
- GrAssert(kInverseEvenOdd_PathFill != fill);
- GrAssert(kInverseWinding_PathFill != fill);
- this->onDrawPath(target, 0, path, fill, translate, true);
-}
diff --git a/gpu/src/GrPathUtils.h b/gpu/src/GrPathUtils.h
deleted file mode 100644
index 2cd00cb..0000000
--- a/gpu/src/GrPathUtils.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#ifndef GrPathUtils_DEFINED
-#define GrPathUtils_DEFINED
-
-#include "GrNoncopyable.h"
-#include "GrPoint.h"
-#include "GrPath.h"
-
-/**
- * Utilities for evaluating paths.
- */
-class GrPathUtils : public GrNoncopyable {
-public:
- static int worstCasePointCount(const GrPath&,
- int* subpaths,
- GrScalar tol);
- static uint32_t quadraticPointCount(const GrPoint points[], GrScalar tol);
- static uint32_t generateQuadraticPoints(const GrPoint& p0,
- const GrPoint& p1,
- const GrPoint& p2,
- GrScalar tolSqd,
- GrPoint** points,
- uint32_t pointsLeft);
- static uint32_t cubicPointCount(const GrPoint points[], GrScalar tol);
- static uint32_t generateCubicPoints(const GrPoint& p0,
- const GrPoint& p1,
- const GrPoint& p2,
- const GrPoint& p3,
- GrScalar tolSqd,
- GrPoint** points,
- uint32_t pointsLeft);
-
- static const GrScalar gTolerance;
-};
-#endif
diff --git a/gpu/src/GrPrintf_printf.cpp b/gpu/src/GrPrintf_printf.cpp
deleted file mode 100644
index ad239ec..0000000
--- a/gpu/src/GrPrintf_printf.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#include "GrTypes.h"
-
-#include <stdarg.h>
-#include <stdio.h>
-
-void GrPrintf(const char format[], ...) {
- const size_t MAX_BUFFER_SIZE = 2048;
-
- char buffer[MAX_BUFFER_SIZE + 1];
- va_list args;
-
- va_start(args, format);
- vsnprintf(buffer, MAX_BUFFER_SIZE, format, args);
- va_end(args);
-
- printf("%s", buffer);
-}
-
-
diff --git a/gpu/src/GrResource.cpp b/gpu/src/GrResource.cpp
deleted file mode 100644
index 70e87d5..0000000
--- a/gpu/src/GrResource.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "GrResource.h"
-#include "GrGpu.h"
-
-GrResource::GrResource(GrGpu* gpu) {
- fGpu = gpu;
- fNext = NULL;
- fPrevious = NULL;
- fGpu->insertResource(this);
-}
-
-void GrResource::release() {
- if (NULL != fGpu) {
- this->onRelease();
- fGpu->removeResource(this);
- fGpu = NULL;
- }
-}
-
-void GrResource::abandon() {
- if (NULL != fGpu) {
- this->onAbandon();
- fGpu->removeResource(this);
- fGpu = NULL;
- }
-}
diff --git a/gpu/src/GrStencil.cpp b/gpu/src/GrStencil.cpp
deleted file mode 100644
index edf83fe..0000000
--- a/gpu/src/GrStencil.cpp
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "GrStencil.h"
-
-const GrStencilSettings GrStencilSettings::gDisabled = {
- kKeep_StencilOp, kKeep_StencilOp,
- kKeep_StencilOp, kKeep_StencilOp,
- kAlways_StencilFunc, kAlways_StencilFunc,
- 0x0, 0x0,
- 0x0, 0x0,
- 0x0, 0x0
-};
-GR_STATIC_ASSERT(0 == kKeep_StencilOp);
-GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
-
-////////////////////////////////////////////////////////////////////////////////
-// Stencil Rules for Merging user stencil space into clip
-
-// We can't include the clip bit in the ref or mask values because the division
-// between user and clip bits in the stencil depends on the number of stencil
-// bits in the runtime. Comments below indicate what the code should do to
-// incorporate the clip bit into these settings.
-
-///////
-// Replace
-
-// set the ref to be the clip bit, but mask it out for the test
-static const GrStencilSettings gUserToClipReplace = {
- kReplace_StencilOp, kReplace_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kLess_StencilFunc, kLess_StencilFunc,
- 0xffffffff, 0xffffffff, // unset clip bit
- 0x0, 0x0, // set clip bit
- 0xffffffff, 0xffffffff
-};
-static const GrStencilSettings gInvUserToClipReplace = {
- kReplace_StencilOp, kReplace_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kEqual_StencilFunc, kEqual_StencilFunc,
- 0xffffffff, 0xffffffff, // unset clip bit
- 0x0, 0x0, // set clip bit
- 0xffffffff, 0xffffffff
-};
-
-///////
-// Intersect
-static const GrStencilSettings gUserToClipIsect = {
- kReplace_StencilOp, kReplace_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kLess_StencilFunc, kLess_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x0, 0x0, // set clip bit
- 0xffffffff, 0xffffffff
-};
-static const GrStencilSettings gInvUserToClipIsect = {
- kReplace_StencilOp, kReplace_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kEqual_StencilFunc, kEqual_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x0, 0x0, // set clip bit
- 0xffffffff, 0xffffffff
-};
-
-///////
-// Difference
-static const GrStencilSettings gUserToClipDiff = {
- kReplace_StencilOp, kReplace_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kEqual_StencilFunc, kEqual_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x0, 0x0, // set clip bit
- 0xffffffff, 0xffffffff
-};
-static const GrStencilSettings gInvUserToClipDiff = {
- kReplace_StencilOp, kReplace_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kLess_StencilFunc, kLess_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x0, 0x0, // set clip bit
- 0xffffffff, 0xffffffff
-};
-
-///////
-// Union
-
-// first pass makes all the passing cases >= just clip bit set.
-static const GrStencilSettings gUserToClipUnionPass0 = {
- kReplace_StencilOp, kReplace_StencilOp,
- kKeep_StencilOp, kKeep_StencilOp,
- kLEqual_StencilFunc, kLEqual_StencilFunc,
- 0xffffffff, 0xffffffff, // unset clip bit
- 0x00000001, 0x00000001, // set clip bit
- 0xffffffff, 0xffffffff
-};
-
-// second pass allows anything greater than just clip bit set to pass
-static const GrStencilSettings gUserToClipUnionPass1 = {
- kReplace_StencilOp, kReplace_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kLEqual_StencilFunc, kLEqual_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x00000000, 0x00000000, // set clip bit
- 0xffffffff, 0xffffffff
-};
-
-// for inverse first pass finds non-zerp user with clip bit set
-// and converts it to just clip bit set
-static const GrStencilSettings gInvUserToClipUnionPass0 = {
- kReplace_StencilOp, kReplace_StencilOp,
- kKeep_StencilOp, kKeep_StencilOp,
- kLess_StencilFunc, kLess_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x00000000, 0x00000000, // set clip bit
- 0xffffffff, 0xffffffff
-};
-
-// second pass lets anything through with a nonzero user portion
-// and writes a ref value with just the clip bit set to it.
-static const GrStencilSettings gInvUserToClipUnionPass1 = {
- kReplace_StencilOp, kReplace_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kLess_StencilFunc, kLess_StencilFunc,
- 0xffffffff, 0xffffffff, // unset clip bit
- 0x00000000, 0x00000000, // set clip bit
- 0xffffffff, 0xffffffff
-};
-
-///////
-// Xor
-static const GrStencilSettings gUserToClipXorPass0 = {
- kInvert_StencilOp, kInvert_StencilOp,
- kKeep_StencilOp, kKeep_StencilOp,
- kEqual_StencilFunc, kEqual_StencilFunc,
- 0xffffffff, 0xffffffff, // unset clip bit
- 0x00000000, 0x00000000,
- 0xffffffff, 0xffffffff
-};
-
-static const GrStencilSettings gUserToClipXorPass1 = {
- kReplace_StencilOp, kReplace_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kGreater_StencilFunc, kGreater_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x00000000, 0x00000000, // set clip bit
- 0xffffffff, 0xffffffff
-};
-
-static const GrStencilSettings gInvUserToClipXorPass0 = {
- kInvert_StencilOp, kInvert_StencilOp,
- kKeep_StencilOp, kKeep_StencilOp,
- kEqual_StencilFunc, kEqual_StencilFunc,
- 0xffffffff, 0xffffffff, // unset clip bit
- 0x00000000, 0x00000000,
- 0xffffffff, 0xffffffff
-};
-
-static const GrStencilSettings gInvUserToClipXorPass1 = {
- kReplace_StencilOp, kReplace_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kLess_StencilFunc, kLess_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x00000000, 0x00000000, // set clip bit
- 0xffffffff, 0xffffffff
-};
-
-///////
-// Reverse Diff
-static const GrStencilSettings gUserToClipRDiffPass0 = {
- kInvert_StencilOp, kInvert_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kLess_StencilFunc, kLess_StencilFunc,
- 0xffffffff, 0xffffffff, // unset clip bit
- 0x00000000, 0x00000000, // set clip bit
- 0xffffffff, 0xffffffff
-};
-
-static const GrStencilSettings gUserToClipRDiffPass1 = {
- kReplace_StencilOp, kReplace_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kEqual_StencilFunc, kEqual_StencilFunc,
- 0x00000000, 0x00000000, // set clip bit
- 0x00000000, 0x00000000, // set clip bit
- 0xffffffff, 0xffffffff
-};
-
-static const GrStencilSettings gInvUserToClipRDiff = {
- kInvert_StencilOp, kInvert_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kEqual_StencilFunc, kEqual_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x00000000, 0x00000000,
- 0x00000000, 0x00000000 // set clip bit
-};
-///////
-// Direct to Stencil
-
-// We can render a clip element directly without first writing to the client
-// portion of the clip when the fill is not inverse and the set operation will
-// only modify the in/out status of samples covered by the clip element.
-
-// this one only works if used right after stencil clip was cleared.
-// Our GrClip doesn't allow midstream replace ops.
-static const GrStencilSettings gReplaceClip = {
- kReplace_StencilOp, kReplace_StencilOp,
- kReplace_StencilOp, kReplace_StencilOp,
- kAlways_StencilFunc, kAlways_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x00000000, 0x00000000, // set clip bit
- 0x00000000, 0x00000000 // set clipBit
-};
-
-static const GrStencilSettings gUnionClip = {
- kReplace_StencilOp, kReplace_StencilOp,
- kReplace_StencilOp, kReplace_StencilOp,
- kAlways_StencilFunc, kAlways_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x00000000, 0x00000000, // set clip bit
- 0x00000000, 0x00000000 // set clip bit
-};
-
-static const GrStencilSettings gXorClip = {
- kInvert_StencilOp, kInvert_StencilOp,
- kInvert_StencilOp, kInvert_StencilOp,
- kAlways_StencilFunc, kAlways_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x00000000, 0x00000000,
- 0x00000000, 0x00000000 // set clip bit
-};
-
-static const GrStencilSettings gDiffClip = {
- kZero_StencilOp, kZero_StencilOp,
- kZero_StencilOp, kZero_StencilOp,
- kAlways_StencilFunc, kAlways_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x00000000, 0x00000000,
- 0x00000000, 0x00000000 // set clip bit
-};
-
-bool GrStencilSettings::GetClipPasses(GrSetOp op,
- bool canBeDirect,
- unsigned int stencilClipMask,
- bool invertedFill,
- int* numPasses,
- GrStencilSettings settings[kMaxStencilClipPasses]) {
- if (canBeDirect && !invertedFill) {
- *numPasses = 0;
- switch (op) {
- case kReplace_SetOp:
- *numPasses = 1;
- settings[0] = gReplaceClip;
- break;
- case kUnion_SetOp:
- *numPasses = 1;
- settings[0] = gUnionClip;
- break;
- case kXor_SetOp:
- *numPasses = 1;
- settings[0] = gXorClip;
- break;
- case kDifference_SetOp:
- *numPasses = 1;
- settings[0] = gDiffClip;
- break;
- default: // suppress warning
- break;
- }
- if (1 == *numPasses) {
- settings[0].fFrontFuncRef |= stencilClipMask;
- settings[0].fFrontWriteMask |= stencilClipMask;
- settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
- settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
- return true;
- }
- }
- switch (op) {
- // if we make the path renderer go to stencil we always give it a
- // non-inverted fill and we use the stencil rules on the client->clipbit
- // pass to select either the zeros or nonzeros.
- case kReplace_SetOp:
- *numPasses= 1;
- settings[0] = invertedFill ? gInvUserToClipReplace : gUserToClipReplace;
- settings[0].fFrontFuncMask &= ~stencilClipMask;
- settings[0].fFrontFuncRef |= stencilClipMask;
- settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
- settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
- break;
- case kIntersect_SetOp:
- *numPasses = 1;
- settings[0] = invertedFill ? gInvUserToClipIsect : gUserToClipIsect;
- settings[0].fFrontFuncRef = stencilClipMask;
- settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
- break;
- case kUnion_SetOp:
- *numPasses = 2;
- if (invertedFill) {
- settings[0] = gInvUserToClipUnionPass0;
- settings[0].fFrontFuncRef |= stencilClipMask;
- settings[0].fBackFuncRef = settings[0].fFrontFuncMask;
-
- settings[1] = gInvUserToClipUnionPass1;
- settings[1].fFrontFuncMask &= ~stencilClipMask;
- settings[1].fFrontFuncRef |= stencilClipMask;
- settings[1].fBackFuncMask = settings[1].fFrontFuncMask;
- settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
-
- } else {
- settings[0] = gUserToClipUnionPass0;
- settings[0].fFrontFuncMask &= ~stencilClipMask;
- settings[0].fFrontFuncRef |= stencilClipMask;
- settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
- settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
-
- settings[1] = gUserToClipUnionPass1;
- settings[1].fFrontFuncRef |= stencilClipMask;
- settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
- }
- break;
- case kXor_SetOp:
- *numPasses = 2;
- if (invertedFill) {
- settings[0] = gInvUserToClipXorPass0;
- settings[0].fFrontFuncMask &= ~stencilClipMask;
- settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
-
- settings[1] = gInvUserToClipXorPass1;
- settings[1].fFrontFuncRef |= stencilClipMask;
- settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
- } else {
- settings[0] = gUserToClipXorPass0;
- settings[0].fFrontFuncMask &= ~stencilClipMask;
- settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
-
- settings[1] = gUserToClipXorPass1;
- settings[1].fFrontFuncRef |= stencilClipMask;
- settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
- }
- break;
- case kDifference_SetOp:
- *numPasses = 1;
- settings[0] = invertedFill ? gInvUserToClipDiff : gUserToClipDiff;
- settings[0].fFrontFuncRef |= stencilClipMask;
- settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
- break;
- case kReverseDifference_SetOp:
- if (invertedFill) {
- *numPasses = 1;
- settings[0] = gInvUserToClipRDiff;
- settings[0].fFrontWriteMask |= stencilClipMask;
- settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
- } else {
- *numPasses = 2;
- settings[0] = gUserToClipRDiffPass0;
- settings[0].fFrontFuncMask &= ~stencilClipMask;
- settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
- settings[0].fFrontFuncRef |= stencilClipMask;
- settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
-
- settings[1] = gUserToClipRDiffPass1;
- settings[1].fFrontFuncMask |= stencilClipMask;
- settings[1].fFrontFuncRef |= stencilClipMask;
- settings[1].fBackFuncMask = settings[1].fFrontFuncMask;
- settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
- }
- break;
- default:
- GrCrash("Unknown set op");
- }
- return false;
-}
diff --git a/gpu/src/GrTesselatedPathRenderer.cpp b/gpu/src/GrTesselatedPathRenderer.cpp
deleted file mode 100644
index 0e3389c..0000000
--- a/gpu/src/GrTesselatedPathRenderer.cpp
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "GrTesselatedPathRenderer.h"
-
-#include "GrMemory.h"
-#include "GrPathUtils.h"
-#include "GrPoint.h"
-#include "GrTDArray.h"
-
-#include <sk_glu.h>
-
-struct PolygonData {
- PolygonData(GrTDArray<GrPoint>* vertices, GrTDArray<short>* indices)
- : fVertices(vertices)
- , fIndices(indices)
- {
- }
- GrTDArray<GrPoint>* fVertices;
- GrTDArray<short>* fIndices;
-};
-
-static void beginData(GLenum type, void* data)
-{
- GR_DEBUGASSERT(type == GL_TRIANGLES);
-}
-
-static void edgeFlagData(GLboolean flag, void* data)
-{
-}
-
-static void vertexData(void* vertexData, void* data)
-{
- short* end = static_cast<PolygonData*>(data)->fIndices->append();
- *end = reinterpret_cast<long>(vertexData);
-}
-
-static void endData(void* data)
-{
-}
-
-static void combineData(GLdouble coords[3], void* vertexData[4],
- GLfloat weight[4], void **outData, void* data)
-{
- PolygonData* polygonData = static_cast<PolygonData*>(data);
- int index = polygonData->fVertices->count();
- *polygonData->fVertices->append() = GrPoint::Make(static_cast<float>(coords[0]),
- static_cast<float>(coords[1]));
- *outData = reinterpret_cast<void*>(index);
-}
-
-typedef void (*TESSCB)();
-
-static unsigned fill_type_to_glu_winding_rule(GrPathFill fill) {
- switch (fill) {
- case kWinding_PathFill:
- return GLU_TESS_WINDING_NONZERO;
- case kEvenOdd_PathFill:
- return GLU_TESS_WINDING_ODD;
- case kInverseWinding_PathFill:
- return GLU_TESS_WINDING_POSITIVE;
- case kInverseEvenOdd_PathFill:
- return GLU_TESS_WINDING_ODD;
- case kHairLine_PathFill:
- return GLU_TESS_WINDING_NONZERO; // FIXME: handle this
- default:
- GrAssert(!"Unknown path fill!");
- return 0;
- }
-}
-
-GrTesselatedPathRenderer::GrTesselatedPathRenderer() {
-}
-
-typedef GrTDArray<GrDrawTarget::Edge> EdgeArray;
-
-bool isCCW(const GrPoint* pts)
-{
- GrVec v1 = pts[1] - pts[0];
- GrVec v2 = pts[2] - pts[1];
- return v1.cross(v2) < 0;
-}
-
-static size_t computeEdgesAndOffsetVertices(const GrMatrix& matrix,
- const GrMatrix& inverse,
- GrPoint* vertices,
- size_t numVertices,
- EdgeArray* edges)
-{
- matrix.mapPoints(vertices, numVertices);
- GrPoint p = vertices[numVertices - 1];
- float sign = isCCW(vertices) ? -1.0f : 1.0f;
- for (size_t i = 0; i < numVertices; ++i) {
- GrPoint q = vertices[i];
- if (p == q) continue;
- GrVec tangent = GrVec::Make(p.fY - q.fY, q.fX - p.fX);
- float scale = sign / tangent.length();
- float cross2 = p.fX * q.fY - q.fX * p.fY;
- GrDrawTarget::Edge edge(tangent.fX * scale,
- tangent.fY * scale,
- cross2 * scale + 0.5f);
- *edges->append() = edge;
- p = q;
- }
- GrDrawTarget::Edge prev_edge = *edges->back();
- for (int i = 0; i < edges->count(); ++i) {
- GrDrawTarget::Edge edge = edges->at(i);
- vertices[i] = prev_edge.intersect(edge);
- inverse.mapPoints(&vertices[i], 1);
- prev_edge = edge;
- }
- return edges->count();
-}
-
-void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target,
- GrDrawTarget::StageBitfield stages,
- const GrPath& path,
- GrPathFill fill,
- const GrPoint* translate) {
- GrDrawTarget::AutoStateRestore asr(target);
- // face culling doesn't make sense here
- GrAssert(GrDrawTarget::kBoth_DrawFace == target->getDrawFace());
-
- GrMatrix viewM = target->getViewMatrix();
- // In order to tesselate the path we get a bound on how much the matrix can
- // stretch when mapping to screen coordinates.
- GrScalar stretch = viewM.getMaxStretch();
- bool useStretch = stretch > 0;
- GrScalar tol = GrPathUtils::gTolerance;
-
- if (!useStretch) {
- // TODO: deal with perspective in some better way.
- tol /= 10;
- } else {
- tol = GrScalarDiv(tol, stretch);
- }
- GrScalar tolSqd = GrMul(tol, tol);
-
- int subpathCnt;
- int maxPts = GrPathUtils::worstCasePointCount(path, &subpathCnt, tol);
-
- GrVertexLayout layout = 0;
- for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
- if ((1 << s) & stages) {
- layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
- }
- }
-
- bool inverted = IsFillInverted(fill);
- if (inverted) {
- maxPts += 4;
- subpathCnt++;
- }
- GrPoint* base = new GrPoint[maxPts];
- GrPoint* vert = base;
- GrPoint* subpathBase = base;
-
- GrAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
-
- GrPoint pts[4];
- SkPath::Iter iter(path, true);
-
- bool first = true;
- int subpath = 0;
-
- for (;;) {
- switch (iter.next(pts)) {
- case kMove_PathCmd:
- if (!first) {
- subpathVertCount[subpath] = vert-subpathBase;
- subpathBase = vert;
- ++subpath;
- }
- *vert = pts[0];
- vert++;
- break;
- case kLine_PathCmd:
- *vert = pts[1];
- vert++;
- break;
- case kQuadratic_PathCmd: {
- GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
- tolSqd, &vert,
- GrPathUtils::quadraticPointCount(pts, tol));
- break;
- }
- case kCubic_PathCmd: {
- GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
- tolSqd, &vert,
- GrPathUtils::cubicPointCount(pts, tol));
- break;
- }
- case kClose_PathCmd:
- break;
- case kEnd_PathCmd:
- subpathVertCount[subpath] = vert-subpathBase;
- ++subpath; // this could be only in debug
- goto FINISHED;
- }
- first = false;
- }
-FINISHED:
- if (translate) {
- for (int i = 0; i < vert - base; i++) {
- base[i].offset(translate->fX, translate->fY);
- }
- }
-
- if (inverted) {
- GrRect bounds;
- GrAssert(NULL != target->getRenderTarget());
- bounds.setLTRB(0, 0,
- GrIntToScalar(target->getRenderTarget()->width()),
- GrIntToScalar(target->getRenderTarget()->height()));
- GrMatrix vmi;
- if (target->getViewInverse(&vmi)) {
- vmi.mapRect(&bounds);
- }
- *vert++ = GrPoint::Make(bounds.fLeft, bounds.fTop);
- *vert++ = GrPoint::Make(bounds.fLeft, bounds.fBottom);
- *vert++ = GrPoint::Make(bounds.fRight, bounds.fBottom);
- *vert++ = GrPoint::Make(bounds.fRight, bounds.fTop);
- subpathVertCount[subpath++] = 4;
- }
-
- GrAssert(subpath == subpathCnt);
- GrAssert((vert - base) <= maxPts);
-
- size_t count = vert - base;
-
- if (count < 3) {
- delete[] base;
- return;
- }
-
- if (subpathCnt == 1 && !inverted && path.isConvex()) {
- if (target->isAntialiasState()) {
- EdgeArray edges;
- GrMatrix inverse, matrix = target->getViewMatrix();
- target->getViewInverse(&inverse);
-
- count = computeEdgesAndOffsetVertices(matrix, inverse, base, count, &edges);
- size_t maxEdges = target->getMaxEdges();
- if (count <= maxEdges) {
- // All edges fit; upload all edges and draw all verts as a fan
- target->setVertexSourceToArray(layout, base, count);
- target->setEdgeAAData(&edges[0], count);
- target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
- } else {
- // Upload "maxEdges" edges and verts at a time, and draw as
- // separate fans
- for (size_t i = 0; i < count - 2; i += maxEdges - 2) {
- edges[i] = edges[0];
- base[i] = base[0];
- int size = GR_CT_MIN(count - i, maxEdges);
- target->setVertexSourceToArray(layout, &base[i], size);
- target->setEdgeAAData(&edges[i], size);
- target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, size);
- }
- }
- target->setEdgeAAData(NULL, 0);
- } else {
- target->setVertexSourceToArray(layout, base, count);
- target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
- }
- delete[] base;
- return;
- }
-
- // FIXME: This copy could be removed if we had (templated?) versions of
- // generate_*_point above that wrote directly into doubles.
- double* inVertices = new double[count * 3];
- for (size_t i = 0; i < count; ++i) {
- inVertices[i * 3] = base[i].fX;
- inVertices[i * 3 + 1] = base[i].fY;
- inVertices[i * 3 + 2] = 1.0;
- }
-
- GLUtesselator* tess = Sk_gluNewTess();
- unsigned windingRule = fill_type_to_glu_winding_rule(fill);
- Sk_gluTessProperty(tess, GLU_TESS_WINDING_RULE, windingRule);
- Sk_gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (TESSCB) &beginData);
- Sk_gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (TESSCB) &vertexData);
- Sk_gluTessCallback(tess, GLU_TESS_END_DATA, (TESSCB) &endData);
- Sk_gluTessCallback(tess, GLU_TESS_EDGE_FLAG_DATA, (TESSCB) &edgeFlagData);
- Sk_gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (TESSCB) &combineData);
- GrTDArray<short> indices;
- GrTDArray<GrPoint> vertices;
- PolygonData data(&vertices, &indices);
-
- Sk_gluTessBeginPolygon(tess, &data);
- size_t i = 0;
- for (int sp = 0; sp < subpathCnt; ++sp) {
- Sk_gluTessBeginContour(tess);
- int start = i;
- size_t end = start + subpathVertCount[sp];
- for (; i < end; ++i) {
- double* inVertex = &inVertices[i * 3];
- *vertices.append() = GrPoint::Make(inVertex[0], inVertex[1]);
- Sk_gluTessVertex(tess, inVertex, reinterpret_cast<void*>(i));
- }
- Sk_gluTessEndContour(tess);
- }
-
- Sk_gluTessEndPolygon(tess);
- Sk_gluDeleteTess(tess);
-
- if (indices.count() > 0) {
- target->setVertexSourceToArray(layout, vertices.begin(), vertices.count());
- target->setIndexSourceToArray(indices.begin(), indices.count());
- target->drawIndexed(kTriangles_PrimitiveType,
- 0,
- 0,
- vertices.count(),
- indices.count());
- }
- delete[] inVertices;
- delete[] base;
-}
-
-bool GrTesselatedPathRenderer::canDrawPath(const GrDrawTarget* target,
- const SkPath& path,
- GrPathFill fill) const {
- return kHairLine_PathFill != fill;
-}
-
-void GrTesselatedPathRenderer::drawPathToStencil(GrDrawTarget* target,
- const SkPath& path,
- GrPathFill fill,
- const GrPoint* translate) {
- GrAlwaysAssert(!"multipass stencil should not be needed");
-}
-
-bool GrTesselatedPathRenderer::supportsAA(GrDrawTarget* target,
- const SkPath& path,
- GrPathFill fill) {
- int subpathCnt = 0;
- int tol = GrPathUtils::gTolerance;
- GrPathUtils::worstCasePointCount(path, &subpathCnt, tol);
- return (subpathCnt == 1 &&
- !IsFillInverted(fill) &&
- path.isConvex());
-}
diff --git a/gpu/src/GrTexture.cpp b/gpu/src/GrTexture.cpp
deleted file mode 100644
index 8df9c9e..0000000
--- a/gpu/src/GrTexture.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "GrTexture.h"
-#include "GrContext.h"
-#include "GrGpu.h"
-
-bool GrRenderTarget::readPixels(int left, int top, int width, int height,
- GrPixelConfig config, void* buffer) {
- // go through context so that all necessary flushing occurs
- GrContext* context = this->getGpu()->getContext();
- GrAssert(NULL != context);
- return context->readRenderTargetPixels(this,
- left, top,
- width, height,
- config, buffer);
-}
-
-void GrRenderTarget::flagAsNeedingResolve(const GrIRect* rect) {
- if (kCanResolve_ResolveType == getResolveType()) {
- if (NULL != rect) {
- fResolveRect.join(*rect);
- if (!fResolveRect.intersect(0, 0, this->width(), this->height())) {
- fResolveRect.setEmpty();
- }
- } else {
- fResolveRect.setLTRB(0, 0, this->width(), this->height());
- }
- }
-}
-
-void GrRenderTarget::overrideResolveRect(const GrIRect rect) {
- fResolveRect = rect;
- if (fResolveRect.isEmpty()) {
- fResolveRect.setLargestInverted();
- } else {
- if (!fResolveRect.intersect(0, 0, this->width(), this->height())) {
- fResolveRect.setLargestInverted();
- }
- }
-}
-
-bool GrTexture::readPixels(int left, int top, int width, int height,
- GrPixelConfig config, void* buffer) {
- // go through context so that all necessary flushing occurs
- GrContext* context = this->getGpu()->getContext();
- GrAssert(NULL != context);
- return context->readTexturePixels(this,
- left, top,
- width, height,
- config, buffer);
-}
diff --git a/gpu/src/GrTextureCache.cpp b/gpu/src/GrTextureCache.cpp
deleted file mode 100644
index c3a61ac..0000000
--- a/gpu/src/GrTextureCache.cpp
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-
-#include "GrTextureCache.h"
-#include "GrTexture.h"
-
-GrTextureEntry::GrTextureEntry(const GrTextureKey& key, GrTexture* texture)
- : fKey(key), fTexture(texture) {
- fLockCount = 0;
- fPrev = fNext = NULL;
-
- // we assume ownership of the texture, and will unref it when we die
- GrAssert(texture);
-}
-
-GrTextureEntry::~GrTextureEntry() {
- fTexture->unref();
-}
-
-#if GR_DEBUG
-void GrTextureEntry::validate() const {
- GrAssert(fLockCount >= 0);
- GrAssert(fTexture);
- fTexture->validate();
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-
-GrTextureCache::GrTextureCache(int maxCount, size_t maxBytes) :
- fMaxCount(maxCount),
- fMaxBytes(maxBytes) {
- fEntryCount = 0;
- fEntryBytes = 0;
- fClientDetachedCount = 0;
- fClientDetachedBytes = 0;
-
- fHead = fTail = NULL;
-}
-
-GrTextureCache::~GrTextureCache() {
- GrAutoTextureCacheValidate atcv(this);
-
- this->removeAll();
-}
-
-void GrTextureCache::getLimits(int* maxTextures, size_t* maxTextureBytes) const{
- if (maxTextures) {
- *maxTextures = fMaxCount;
- }
- if (maxTextureBytes) {
- *maxTextureBytes = fMaxBytes;
- }
-}
-
-void GrTextureCache::setLimits(int maxTextures, size_t maxTextureBytes) {
- bool smaller = (maxTextures < fMaxCount) || (maxTextureBytes < fMaxBytes);
-
- fMaxCount = maxTextures;
- fMaxBytes = maxTextureBytes;
-
- if (smaller) {
- this->purgeAsNeeded();
- }
-}
-
-void GrTextureCache::internalDetach(GrTextureEntry* entry,
- bool clientDetach) {
- GrTextureEntry* prev = entry->fPrev;
- GrTextureEntry* next = entry->fNext;
-
- if (prev) {
- prev->fNext = next;
- } else {
- fHead = next;
- }
- if (next) {
- next->fPrev = prev;
- } else {
- fTail = prev;
- }
-
- // update our stats
- if (clientDetach) {
- fClientDetachedCount += 1;
- fClientDetachedBytes += entry->texture()->sizeInBytes();
- } else {
- fEntryCount -= 1;
- fEntryBytes -= entry->texture()->sizeInBytes();
- }
-}
-
-void GrTextureCache::attachToHead(GrTextureEntry* entry,
- bool clientReattach) {
- entry->fPrev = NULL;
- entry->fNext = fHead;
- if (fHead) {
- fHead->fPrev = entry;
- }
- fHead = entry;
- if (NULL == fTail) {
- fTail = entry;
- }
-
- // update our stats
- if (clientReattach) {
- fClientDetachedCount -= 1;
- fClientDetachedBytes -= entry->texture()->sizeInBytes();
- } else {
- fEntryCount += 1;
- fEntryBytes += entry->texture()->sizeInBytes();
- }
-}
-
-class GrTextureCache::Key {
- typedef GrTextureEntry T;
-
- const GrTextureKey& fKey;
-public:
- Key(const GrTextureKey& key) : fKey(key) {}
-
- uint32_t getHash() const { return fKey.hashIndex(); }
-
- static bool LT(const T& entry, const Key& key) {
- return entry.key() < key.fKey;
- }
- static bool EQ(const T& entry, const Key& key) {
- return entry.key() == key.fKey;
- }
-#if GR_DEBUG
- static uint32_t GetHash(const T& entry) {
- return entry.key().hashIndex();
- }
- static bool LT(const T& a, const T& b) {
- return a.key() < b.key();
- }
- static bool EQ(const T& a, const T& b) {
- return a.key() == b.key();
- }
-#endif
-};
-
-GrTextureEntry* GrTextureCache::findAndLock(const GrTextureKey& key) {
- GrAutoTextureCacheValidate atcv(this);
-
- GrTextureEntry* entry = fCache.find(key);
- if (entry) {
- this->internalDetach(entry, false);
- this->attachToHead(entry, false);
- // mark the entry as "busy" so it doesn't get purged
- entry->lock();
- }
- return entry;
-}
-
-GrTextureEntry* GrTextureCache::createAndLock(const GrTextureKey& key,
- GrTexture* texture) {
- GrAutoTextureCacheValidate atcv(this);
-
- GrTextureEntry* entry = new GrTextureEntry(key, texture);
-
- this->attachToHead(entry, false);
- fCache.insert(key, entry);
-
-#if GR_DUMP_TEXTURE_UPLOAD
- GrPrintf("--- add texture to cache %p, count=%d bytes= %d %d\n",
- entry, fEntryCount, texture->sizeInBytes(), fEntryBytes);
-#endif
-
- // mark the entry as "busy" so it doesn't get purged
- entry->lock();
- this->purgeAsNeeded();
- return entry;
-}
-
-void GrTextureCache::detach(GrTextureEntry* entry) {
- internalDetach(entry, true);
- fCache.remove(entry->fKey, entry);
-}
-
-void GrTextureCache::reattachAndUnlock(GrTextureEntry* entry) {
- attachToHead(entry, true);
- fCache.insert(entry->key(), entry);
- unlock(entry);
-}
-
-void GrTextureCache::unlock(GrTextureEntry* entry) {
- GrAutoTextureCacheValidate atcv(this);
-
- GrAssert(entry);
- GrAssert(entry->isLocked());
- GrAssert(fCache.find(entry->key()));
-
- entry->unlock();
- this->purgeAsNeeded();
-}
-
-void GrTextureCache::purgeAsNeeded() {
- GrAutoTextureCacheValidate atcv(this);
-
- GrTextureEntry* entry = fTail;
- while (entry) {
- if (fEntryCount <= fMaxCount && fEntryBytes <= fMaxBytes) {
- break;
- }
-
- GrTextureEntry* prev = entry->fPrev;
- if (!entry->isLocked()) {
- // remove from our cache
- fCache.remove(entry->fKey, entry);
-
- // remove from our llist
- this->internalDetach(entry, false);
-
-#if GR_DUMP_TEXTURE_UPLOAD
- GrPrintf("--- ~texture from cache %p [%d %d]\n", entry->texture(),
- entry->texture()->width(),
- entry->texture()->height());
-#endif
- delete entry;
- }
- entry = prev;
- }
-}
-
-void GrTextureCache::removeAll() {
- GrAssert(!fClientDetachedCount);
- GrAssert(!fClientDetachedBytes);
-
- GrTextureEntry* entry = fHead;
- while (entry) {
- GrAssert(!entry->isLocked());
-
- GrTextureEntry* next = entry->fNext;
- delete entry;
- entry = next;
- }
-
- fCache.removeAll();
- fHead = fTail = NULL;
- fEntryCount = 0;
- fEntryBytes = 0;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-#if GR_DEBUG
-static int countMatches(const GrTextureEntry* head, const GrTextureEntry* target) {
- const GrTextureEntry* entry = head;
- int count = 0;
- while (entry) {
- if (target == entry) {
- count += 1;
- }
- entry = entry->next();
- }
- return count;
-}
-
-#if GR_DEBUG
-static bool both_zero_or_nonzero(int count, size_t bytes) {
- return (count == 0 && bytes == 0) || (count > 0 && bytes > 0);
-}
-#endif
-
-void GrTextureCache::validate() const {
- GrAssert(!fHead == !fTail);
- GrAssert(both_zero_or_nonzero(fEntryCount, fEntryBytes));
- GrAssert(both_zero_or_nonzero(fClientDetachedCount, fClientDetachedBytes));
- GrAssert(fClientDetachedBytes <= fEntryBytes);
- GrAssert(fClientDetachedCount <= fEntryCount);
- GrAssert((fEntryCount - fClientDetachedCount) == fCache.count());
-
- fCache.validate();
-
- GrTextureEntry* entry = fHead;
- int count = 0;
- size_t bytes = 0;
- while (entry) {
- entry->validate();
- GrAssert(fCache.find(entry->key()));
- count += 1;
- bytes += entry->texture()->sizeInBytes();
- entry = entry->fNext;
- }
- GrAssert(count == fEntryCount - fClientDetachedCount);
- GrAssert(bytes == fEntryBytes - fClientDetachedBytes);
-
- count = 0;
- for (entry = fTail; entry; entry = entry->fPrev) {
- count += 1;
- }
- GrAssert(count == fEntryCount - fClientDetachedCount);
-
- for (int i = 0; i < count; i++) {
- int matches = countMatches(fHead, fCache.getArray()[i]);
- GrAssert(1 == matches);
- }
-}
-#endif
-
-
diff --git a/gpu/src/GrTouchGesture.cpp b/gpu/src/GrTouchGesture.cpp
deleted file mode 100644
index 0eaedc7..0000000
--- a/gpu/src/GrTouchGesture.cpp
+++ /dev/null
@@ -1,243 +0,0 @@
-#include "GrTouchGesture.h"
-#include "SkMatrix.h"
-#include "SkTime.h"
-
-#include <math.h>
-
-static const SkMSec MAX_DBL_TAP_INTERVAL = 300;
-static const float MAX_DBL_TAP_DISTANCE = 100;
-static const float MAX_JITTER_RADIUS = 2;
-
-// if true, then ignore the touch-move, 'cause its probably just jitter
-static bool close_enough_for_jitter(float x0, float y0, float x1, float y1) {
- return sk_float_abs(x0 - x1) <= MAX_JITTER_RADIUS &&
- sk_float_abs(y0 - y1) <= MAX_JITTER_RADIUS;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-GrTouchGesture::GrTouchGesture() {
- this->reset();
-}
-
-GrTouchGesture::~GrTouchGesture() {
-}
-
-void GrTouchGesture::reset() {
- fTouches.reset();
- fState = kEmpty_State;
- fLocalM.reset();
- fGlobalM.reset();
-
- fLastUpT = SkTime::GetMSecs() - 2*MAX_DBL_TAP_INTERVAL;
- fLastUpP.set(0, 0);
-}
-
-void GrTouchGesture::flushLocalM() {
- fGlobalM.postConcat(fLocalM);
- fLocalM.reset();
-}
-
-const SkMatrix& GrTouchGesture::localM() {
- if (fFlinger.isActive()) {
- if (!fFlinger.evaluateMatrix(&fLocalM)) {
- this->flushLocalM();
- }
- }
- return fLocalM;
-}
-
-void GrTouchGesture::appendNewRec(void* owner, float x, float y) {
- Rec* rec = fTouches.append();
- rec->fOwner = owner;
- rec->fStartX = rec->fPrevX = rec->fLastX = x;
- rec->fStartY = rec->fPrevY = rec->fLastY = y;
- rec->fLastT = rec->fPrevT = SkTime::GetMSecs();
-}
-
-void GrTouchGesture::touchBegin(void* owner, float x, float y) {
-// GrPrintf("--- %d touchBegin %p %g %g\n", fTouches.count(), owner, x, y);
-
- int index = this->findRec(owner);
- if (index >= 0) {
- this->flushLocalM();
- fTouches.removeShuffle(index);
- GrPrintf("---- already exists, removing\n");
- }
-
- if (fTouches.count() == 2) {
- return;
- }
-
- this->flushLocalM();
- fFlinger.stop();
-
- this->appendNewRec(owner, x, y);
-
- switch (fTouches.count()) {
- case 1:
- fState = kTranslate_State;
- break;
- case 2:
- fState = kZoom_State;
- break;
- default:
- break;
- }
-}
-
-int GrTouchGesture::findRec(void* owner) const {
- for (int i = 0; i < fTouches.count(); i++) {
- if (owner == fTouches[i].fOwner) {
- return i;
- }
- }
- return -1;
-}
-
-static float center(float pos0, float pos1) {
- return (pos0 + pos1) * 0.5f;
-}
-
-static const float MAX_ZOOM_SCALE = 4;
-static const float MIN_ZOOM_SCALE = 0.25f;
-
-float GrTouchGesture::limitTotalZoom(float scale) const {
- // this query works 'cause we know that we're square-scale w/ no skew/rotation
- const float curr = fGlobalM[0];
-
- if (scale > 1 && curr * scale > MAX_ZOOM_SCALE) {
- scale = MAX_ZOOM_SCALE / curr;
- } else if (scale < 1 && curr * scale < MIN_ZOOM_SCALE) {
- scale = MIN_ZOOM_SCALE / curr;
- }
- return scale;
-}
-
-void GrTouchGesture::touchMoved(void* owner, float x, float y) {
-// GrPrintf("--- %d touchMoved %p %g %g\n", fTouches.count(), owner, x, y);
-
- GrAssert(kEmpty_State != fState);
-
- int index = this->findRec(owner);
- if (index < 0) {
- // not found, so I guess we should add it...
- GrPrintf("---- add missing begin\n");
- this->appendNewRec(owner, x, y);
- index = fTouches.count() - 1;
- }
-
- Rec& rec = fTouches[index];
-
- // not sure how valuable this is
- if (fTouches.count() == 2) {
- if (close_enough_for_jitter(rec.fLastX, rec.fLastY, x, y)) {
-// GrPrintf("--- drop touchMove, withing jitter tolerance %g %g\n", rec.fLastX - x, rec.fLastY - y);
- return;
- }
- }
-
- rec.fPrevX = rec.fLastX; rec.fLastX = x;
- rec.fPrevY = rec.fLastY; rec.fLastY = y;
- rec.fPrevT = rec.fLastT; rec.fLastT = SkTime::GetMSecs();
-
- switch (fTouches.count()) {
- case 1: {
- float dx = rec.fLastX - rec.fStartX;
- float dy = rec.fLastY - rec.fStartY;
- dx = (float)sk_float_round2int(dx);
- dy = (float)sk_float_round2int(dy);
- fLocalM.setTranslate(dx, dy);
- } break;
- case 2: {
- GrAssert(kZoom_State == fState);
- const Rec& rec0 = fTouches[0];
- const Rec& rec1 = fTouches[1];
-
- float scale = this->computePinch(rec0, rec1);
- scale = this->limitTotalZoom(scale);
-
- fLocalM.setTranslate(-center(rec0.fStartX, rec1.fStartX),
- -center(rec0.fStartY, rec1.fStartY));
- fLocalM.postScale(scale, scale);
- fLocalM.postTranslate(center(rec0.fLastX, rec1.fLastX),
- center(rec0.fLastY, rec1.fLastY));
- } break;
- default:
- break;
- }
-}
-
-void GrTouchGesture::touchEnd(void* owner) {
-// GrPrintf("--- %d touchEnd %p\n", fTouches.count(), owner);
-
- int index = this->findRec(owner);
- if (index < 0) {
- GrPrintf("--- not found\n");
- return;
- }
-
- const Rec& rec = fTouches[index];
- if (this->handleDblTap(rec.fLastX, rec.fLastY)) {
- return;
- }
-
- // count() reflects the number before we removed the owner
- switch (fTouches.count()) {
- case 1: {
- this->flushLocalM();
- float dx = rec.fLastX - rec.fPrevX;
- float dy = rec.fLastY - rec.fPrevY;
- float dur = (rec.fLastT - rec.fPrevT) * 0.001f;
- if (dur > 0) {
- fFlinger.reset(dx / dur, dy / dur);
- }
- fState = kEmpty_State;
- } break;
- case 2:
- this->flushLocalM();
- GrAssert(kZoom_State == fState);
- fState = kEmpty_State;
- break;
- default:
- GrAssert(kZoom_State == fState);
- break;
- }
-
- fTouches.removeShuffle(index);
-}
-
-float GrTouchGesture::computePinch(const Rec& rec0, const Rec& rec1) {
- double dx = rec0.fStartX - rec1.fStartX;
- double dy = rec0.fStartY - rec1.fStartY;
- double dist0 = sqrt(dx*dx + dy*dy);
-
- dx = rec0.fLastX - rec1.fLastX;
- dy = rec0.fLastY - rec1.fLastY;
- double dist1 = sqrt(dx*dx + dy*dy);
-
- double scale = dist1 / dist0;
- return (float)scale;
-}
-
-bool GrTouchGesture::handleDblTap(float x, float y) {
- bool found = false;
- SkMSec now = SkTime::GetMSecs();
- if (now - fLastUpT <= MAX_DBL_TAP_INTERVAL) {
- if (SkPoint::Length(fLastUpP.fX - x,
- fLastUpP.fY - y) <= MAX_DBL_TAP_DISTANCE) {
- fFlinger.stop();
- fLocalM.reset();
- fGlobalM.reset();
- fTouches.reset();
- fState = kEmpty_State;
- found = true;
- }
- }
-
- fLastUpT = now;
- fLastUpP.set(x, y);
- return found;
-}
-
-
diff --git a/gpu/src/android/GrGLDefaultInterface_android.cpp b/gpu/src/android/GrGLDefaultInterface_android.cpp
deleted file mode 100644
index e52277e..0000000
--- a/gpu/src/android/GrGLDefaultInterface_android.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-// Modified from chromium/src/webkit/glue/gl_bindings_skia_cmd_buffer.cc
-
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "GrGLInterface.h"
-
-#ifndef GL_GLEXT_PROTOTYPES
-#define GL_GLEXT_PROTOTYPES
-#endif
-
-#include "gl2.h"
-#include "gl2ext.h"
-/*
-#include "gpu/GLES2/gl2.h"
-#include "gpu/GLES2/gl2ext.h"
-*/
-void GrGLSetDefaultGLInterface() {
- static GrGLInterface cmd_buffer_interface = {
- kES2_GrGLBinding,
-
- glActiveTexture,
- glAttachShader,
- glBindAttribLocation,
- glBindBuffer,
- glBindTexture,
- glBlendColor,
- glBlendFunc,
- glBufferData,
- glBufferSubData,
- glClear,
- glClearColor,
- glClearStencil,
- NULL, // glClientActiveTexture
- NULL, // glColor4ub
- glColorMask,
- NULL, // glColorPointer
- glCompileShader,
- glCompressedTexImage2D,
- glCreateProgram,
- glCreateShader,
- glCullFace,
- glDeleteBuffers,
- glDeleteProgram,
- glDeleteShader,
- glDeleteTextures,
- glDepthMask,
- glDisable,
- NULL, // glDisableClientState
- glDisableVertexAttribArray,
- glDrawArrays,
- glDrawElements,
- glEnable,
- NULL, // glEnableClientState
- glEnableVertexAttribArray,
- glFrontFace,
- glGenBuffers,
- glGenTextures,
- glGetBufferParameteriv,
- glGetError,
- glGetIntegerv,
- glGetProgramInfoLog,
- glGetProgramiv,
- glGetShaderInfoLog,
- glGetShaderiv,
- glGetString,
- glGetUniformLocation,
- glLineWidth,
- glLinkProgram,
- NULL, // glLoadMatrixf
- NULL, // glMatrixMode
- glPixelStorei,
- NULL, // glPointSize
- glReadPixels,
- glScissor,
- NULL, // glShadeModel
- glShaderSource,
- glStencilFunc,
- glStencilFuncSeparate,
- glStencilMask,
- glStencilMaskSeparate,
- glStencilOp,
- glStencilOpSeparate,
- NULL, // glTexCoordPointer
- NULL, // glTexEnvi
- glTexImage2D,
- glTexParameteri,
- glTexSubImage2D,
- glUniform1f,
- glUniform1i,
- glUniform1fv,
- glUniform1iv,
- glUniform2f,
- glUniform2i,
- glUniform2fv,
- glUniform2iv,
- glUniform3f,
- glUniform3i,
- glUniform3fv,
- glUniform3iv,
- glUniform4f,
- glUniform4i,
- glUniform4fv,
- glUniform4iv,
- glUniformMatrix2fv,
- glUniformMatrix3fv,
- glUniformMatrix4fv,
- glUseProgram,
- glVertexAttrib4fv,
- glVertexAttribPointer,
- NULL, // glVertexPointer
- glViewport,
- glBindFramebuffer,
- glBindRenderbuffer,
- glCheckFramebufferStatus,
- glDeleteFramebuffers,
- glDeleteRenderbuffers,
- glFramebufferRenderbuffer,
- glFramebufferTexture2D,
- glGenFramebuffers,
- glGenRenderbuffers,
- glRenderbufferStorage,
- NULL, // glRenderbufferStorageMultisampleEXT,
- NULL, // glBlitFramebufferEXT,
- NULL, // glResolveMultisampleFramebuffer
- glMapBufferOES,
- glUnmapBufferOES,
- NULL,
- GrGLInterface::kStaticInitEndGuard
- };
- static bool host_StubGL_initialized = false;
- if (!host_StubGL_initialized) {
- GrGLSetGLInterface(&cmd_buffer_interface);
- host_StubGL_initialized = true;
- }
-}
-
diff --git a/gpu/src/gr_files.mk b/gpu/src/gr_files.mk
deleted file mode 100644
index bd6f061..0000000
--- a/gpu/src/gr_files.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-SOURCE := \
- GrAllocPool.cpp \
- GrAtlas.cpp \
- GrClip.cpp \
- GrContext.cpp \
- GrCreatePathRenderer_none.cpp \
- GrDrawTarget.cpp \
- GrGLIndexBuffer.cpp \
- GrGLInterface.cpp \
- GrGLProgram.cpp \
- GrGLTexture.cpp \
- GrGLVertexBuffer.cpp \
- GrGpu.cpp \
- GrGpuGLFixed.cpp \
- GrGpuFactory.cpp \
- GrGLUtil.cpp \
- GrGpuGL.cpp \
- GrGpuGLShaders.cpp \
- GrInOrderDrawBuffer.cpp \
- GrMatrix.cpp \
- GrMemory.cpp \
- GrPathUtils.cpp \
- GrRectanizer_fifo.cpp \
- GrResource.cpp \
- GrTesselatedPathRenderer.cpp \
- GrTexture.cpp \
- GrTextureCache.cpp \
- GrTextContext.cpp \
- GrTextStrike.cpp \
- GrBufferAllocPool.cpp\
- GrPathRenderer.cpp \
- GrStencil.cpp
diff --git a/gpu/src/mac/GrGLDefaultInterface_mac.cpp b/gpu/src/mac/GrGLDefaultInterface_mac.cpp
deleted file mode 100644
index fb5b182..0000000
--- a/gpu/src/mac/GrGLDefaultInterface_mac.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "GrGLInterface.h"
-
-#include <OpenGL/gl.h>
-#include <OpenGL/glext.h>
-
-void GrGLSetDefaultGLInterface() {
- static GrGLInterface gDefaultInterface;
- static bool gDefaultInterfaceInit;
- if (!gDefaultInterfaceInit) {
- gDefaultInterface.fActiveTexture = glActiveTexture;
- gDefaultInterface.fAttachShader = glAttachShader;
- gDefaultInterface.fBindAttribLocation = glBindAttribLocation;
- gDefaultInterface.fBindBuffer = glBindBuffer;
- gDefaultInterface.fBindTexture = glBindTexture;
- gDefaultInterface.fBlendColor = glBlendColor;
- gDefaultInterface.fBlendFunc = glBlendFunc;
- gDefaultInterface.fBufferData = glBufferData;
- gDefaultInterface.fBufferSubData = glBufferSubData;
- gDefaultInterface.fClear = glClear;
- gDefaultInterface.fClearColor = glClearColor;
- gDefaultInterface.fClearStencil = glClearStencil;
- gDefaultInterface.fClientActiveTexture = glClientActiveTexture;
- gDefaultInterface.fColorMask = glColorMask;
- gDefaultInterface.fColorPointer = glColorPointer;
- gDefaultInterface.fColor4ub = glColor4ub;
- gDefaultInterface.fCompileShader = glCompileShader;
- gDefaultInterface.fCompressedTexImage2D = glCompressedTexImage2D;
- gDefaultInterface.fCreateProgram = glCreateProgram;
- gDefaultInterface.fCreateShader = glCreateShader;
- gDefaultInterface.fCullFace = glCullFace;
- gDefaultInterface.fDeleteBuffers = glDeleteBuffers;
- gDefaultInterface.fDeleteProgram = glDeleteProgram;
- gDefaultInterface.fDeleteShader = glDeleteShader;
- gDefaultInterface.fDeleteTextures = glDeleteTextures;
- gDefaultInterface.fDepthMask = glDepthMask;
- gDefaultInterface.fDisable = glDisable;
- gDefaultInterface.fDisableClientState = glDisableClientState;
- gDefaultInterface.fDisableVertexAttribArray =
- glDisableVertexAttribArray;
- gDefaultInterface.fDrawArrays = glDrawArrays;
- gDefaultInterface.fDrawElements = glDrawElements;
- gDefaultInterface.fEnable = glEnable;
- gDefaultInterface.fEnableClientState = glEnableClientState;
- gDefaultInterface.fEnableVertexAttribArray = glEnableVertexAttribArray;
- gDefaultInterface.fFrontFace = glFrontFace;
- gDefaultInterface.fGenBuffers = glGenBuffers;
- gDefaultInterface.fGetBufferParameteriv = glGetBufferParameteriv;
- gDefaultInterface.fGetError = glGetError;
- gDefaultInterface.fGetIntegerv = glGetIntegerv;
- gDefaultInterface.fGetProgramInfoLog = glGetProgramInfoLog;
- gDefaultInterface.fGetProgramiv = glGetProgramiv;
- gDefaultInterface.fGetShaderInfoLog = glGetShaderInfoLog;
- gDefaultInterface.fGetShaderiv = glGetShaderiv;
- gDefaultInterface.fGetString = glGetString;
- gDefaultInterface.fGenTextures = glGenTextures;
- gDefaultInterface.fGetUniformLocation = glGetUniformLocation;
- gDefaultInterface.fLineWidth = glLineWidth;
- gDefaultInterface.fLinkProgram = glLinkProgram;
- gDefaultInterface.fLoadMatrixf = glLoadMatrixf;
- gDefaultInterface.fMapBuffer = glMapBuffer;
- gDefaultInterface.fMatrixMode = glMatrixMode;
- gDefaultInterface.fPointSize = glPointSize;
- gDefaultInterface.fPixelStorei = glPixelStorei;
- gDefaultInterface.fReadPixels = glReadPixels;
- gDefaultInterface.fScissor = glScissor;
- gDefaultInterface.fShadeModel = glShadeModel;
- gDefaultInterface.fShaderSource = glShaderSource;
- gDefaultInterface.fStencilFunc = glStencilFunc;
- gDefaultInterface.fStencilFuncSeparate = glStencilFuncSeparate;
- gDefaultInterface.fStencilMask = glStencilMask;
- gDefaultInterface.fStencilMaskSeparate = glStencilMaskSeparate;
- gDefaultInterface.fStencilOp = glStencilOp;
- gDefaultInterface.fStencilOpSeparate = glStencilOpSeparate;
- gDefaultInterface.fTexCoordPointer = glTexCoordPointer;
- gDefaultInterface.fTexEnvi = glTexEnvi;
- // mac uses GLenum for internalFormat param (non-standard)
- // amounts to int vs. uint.
- gDefaultInterface.fTexImage2D = (GrGLTexImage2DProc)glTexImage2D;
- gDefaultInterface.fTexParameteri = glTexParameteri;
- gDefaultInterface.fTexSubImage2D = glTexSubImage2D;
- gDefaultInterface.fUniform1f = glUniform1f;
- gDefaultInterface.fUniform1i = glUniform1i;
- gDefaultInterface.fUniform1fv = glUniform1fv;
- gDefaultInterface.fUniform1iv = glUniform1iv;
- gDefaultInterface.fUniform2f = glUniform2f;
- gDefaultInterface.fUniform2i = glUniform2i;
- gDefaultInterface.fUniform2fv = glUniform2fv;
- gDefaultInterface.fUniform2iv = glUniform2iv;
- gDefaultInterface.fUniform3f = glUniform3f;
- gDefaultInterface.fUniform3i = glUniform3i;
- gDefaultInterface.fUniform3fv = glUniform3fv;
- gDefaultInterface.fUniform3iv = glUniform3iv;
- gDefaultInterface.fUniform4f = glUniform4f;
- gDefaultInterface.fUniform4i = glUniform4i;
- gDefaultInterface.fUniform4fv = glUniform4fv;
- gDefaultInterface.fUniform4iv = glUniform4iv;
- gDefaultInterface.fUniform4fv = glUniform4fv;
- gDefaultInterface.fUniformMatrix2fv = glUniformMatrix2fv;
- gDefaultInterface.fUniformMatrix3fv = glUniformMatrix3fv;
- gDefaultInterface.fUniformMatrix4fv = glUniformMatrix4fv;
- gDefaultInterface.fUnmapBuffer = glUnmapBuffer;
- gDefaultInterface.fUseProgram = glUseProgram;
- gDefaultInterface.fVertexAttrib4fv = glVertexAttrib4fv;
- gDefaultInterface.fVertexAttribPointer = glVertexAttribPointer;
- gDefaultInterface.fVertexPointer = glVertexPointer;
- gDefaultInterface.fViewport = glViewport;
-
-#if GL_ARB_framebuffer_object
- gDefaultInterface.fGenFramebuffers = glGenFramebuffers;
- gDefaultInterface.fBindFramebuffer = glBindFramebuffer;
- gDefaultInterface.fFramebufferTexture2D = glFramebufferTexture2D;
- gDefaultInterface.fCheckFramebufferStatus = glCheckFramebufferStatus;
- gDefaultInterface.fDeleteFramebuffers = glDeleteFramebuffers;
- gDefaultInterface.fRenderbufferStorage = glRenderbufferStorage;
- gDefaultInterface.fGenRenderbuffers = glGenRenderbuffers;
- gDefaultInterface.fDeleteRenderbuffers = glDeleteRenderbuffers;
- gDefaultInterface.fFramebufferRenderbuffer = glFramebufferRenderbuffer;
- gDefaultInterface.fBindRenderbuffer = glBindRenderbuffer;
- gDefaultInterface.fRenderbufferStorageMultisample =
- glRenderbufferStorageMultisample;
- gDefaultInterface.fBlitFramebuffer = glBlitFramebuffer;
-#elif GL_EXT_framebuffer_object
- gDefaultInterface.fGenFramebuffers = glGenFramebuffersEXT;
- gDefaultInterface.fBindFramebuffer = glBindFramebufferEXT;
- gDefaultInterface.fFramebufferTexture2D = glFramebufferTexture2DEXT;
- gDefaultInterface.fCheckFramebufferStatus = glCheckFramebufferStatusEXT;
- gDefaultInterface.fDeleteFramebuffers = glDeleteFramebuffersEXT;
- gDefaultInterface.fRenderbufferStorage = glRenderbufferStorageEXT;
- gDefaultInterface.fGenRenderbuffers = glGenRenderbuffersEXT;
- gDefaultInterface.fDeleteRenderbuffers = glDeleteRenderbuffers;
- gDefaultInterface.fFramebufferRenderbuffer =
- glFramebufferRenderbufferEXT;
- gDefaultInterface.fBindRenderbuffer = glBindRenderbufferEXT;
- #if GL_EXT_framebuffer_multisample
- gDefaultInterface.fRenderbufferStorageMultisample =
- glRenderbufferStorageMultisampleEXT;
- #endif
- #if GL_EXT_framebuffer_blit
- gDefaultInterface.fBlitFramebuffer = glBlitFramebufferEXT;
- #endif
-#endif
- gDefaultInterface.fBindFragDataLocationIndexed = NULL;
-
- gDefaultInterface.fBindingsExported = kDesktop_GrGLBinding;
-
- gDefaultInterfaceInit = true;
- }
- GrGLSetGLInterface(&gDefaultInterface);
-}
diff --git a/gpu/src/mesa/GrGLDefaultInterface_mesa.cpp b/gpu/src/mesa/GrGLDefaultInterface_mesa.cpp
deleted file mode 100644
index 0350c30..0000000
--- a/gpu/src/mesa/GrGLDefaultInterface_mesa.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "GrGLInterface.h"
-
-#include "GL/osmesa.h"
-#include <GL/glext.h>
-#include <GL/glu.h>
-
-#define GR_GL_GET_PROC(F) gDefaultInterface.f ## F = (GrGL ## F ## Proc) \
- OSMesaGetProcAddress("gl" #F);
-#define GR_GL_GET_PROC_SUFFIX(F, S) gDefaultInterface.f ## F = (GrGL ## F ## Proc) \
- OSMesaGetProcAddress("gl" #F #S);
-
-void GrGLSetDefaultGLInterface() {
- static GrGLInterface gDefaultInterface;
- static bool gDefaultInterfaceInit;
- if (!gDefaultInterfaceInit && NULL != OSMesaGetCurrentContext()) {
- int major, minor;
- const char* versionString = (const char*) glGetString(GL_VERSION);
- const char* extString = (const char*) glGetString(GL_EXTENSIONS);
- gl_version_from_string(&major, &minor, versionString);
-
- if (major == 1 && minor < 5) {
- // We must have array and element_array buffer objects.
- return;
- }
-
- gDefaultInterface.fActiveTexture = glActiveTexture;
- GR_GL_GET_PROC(AttachShader);
- GR_GL_GET_PROC(BindAttribLocation);
- GR_GL_GET_PROC(BindBuffer);
- gDefaultInterface.fBindTexture = glBindTexture;
- gDefaultInterface.fBlendColor = glBlendColor;
- gDefaultInterface.fBlendFunc = glBlendFunc;
- GR_GL_GET_PROC(BufferData);
- GR_GL_GET_PROC(BufferSubData);
- gDefaultInterface.fClear = glClear;
- gDefaultInterface.fClearColor = glClearColor;
- gDefaultInterface.fClearStencil = glClearStencil;
- gDefaultInterface.fClientActiveTexture = glClientActiveTexture;
- gDefaultInterface.fColorMask = glColorMask;
- gDefaultInterface.fColorPointer = glColorPointer;
- gDefaultInterface.fColor4ub = glColor4ub;
- GR_GL_GET_PROC(CompileShader);
- gDefaultInterface.fCompressedTexImage2D = glCompressedTexImage2D;
- GR_GL_GET_PROC(CreateProgram);
- GR_GL_GET_PROC(CreateShader);
- gDefaultInterface.fCullFace = glCullFace;
- GR_GL_GET_PROC(DeleteBuffers);
- GR_GL_GET_PROC(DeleteProgram);
- GR_GL_GET_PROC(DeleteShader);
- gDefaultInterface.fDeleteTextures = glDeleteTextures;
- gDefaultInterface.fDepthMask = glDepthMask;
- gDefaultInterface.fDisable = glDisable;
- gDefaultInterface.fDisableClientState = glDisableClientState;
- GR_GL_GET_PROC(DisableVertexAttribArray);
- gDefaultInterface.fDrawArrays = glDrawArrays;
- gDefaultInterface.fDrawElements = glDrawElements;
- gDefaultInterface.fEnable = glEnable;
- gDefaultInterface.fEnableClientState = glEnableClientState;
- GR_GL_GET_PROC(EnableVertexAttribArray);
- gDefaultInterface.fFrontFace = glFrontFace;
- GR_GL_GET_PROC(GenBuffers);
- GR_GL_GET_PROC(GetBufferParameteriv);
- gDefaultInterface.fGetError = glGetError;
- gDefaultInterface.fGetIntegerv = glGetIntegerv;
- GR_GL_GET_PROC(GetProgramInfoLog);
- GR_GL_GET_PROC(GetProgramiv);
- GR_GL_GET_PROC(GetShaderInfoLog);
- GR_GL_GET_PROC(GetShaderiv);
- gDefaultInterface.fGetString = glGetString;
- gDefaultInterface.fGenTextures = glGenTextures;
- GR_GL_GET_PROC(GetUniformLocation);
- gDefaultInterface.fLineWidth = glLineWidth;
- GR_GL_GET_PROC(LinkProgram);
- gDefaultInterface.fLoadMatrixf = glLoadMatrixf;
- GR_GL_GET_PROC(MapBuffer);
- gDefaultInterface.fMatrixMode = glMatrixMode;
- gDefaultInterface.fPointSize = glPointSize;
- gDefaultInterface.fPixelStorei = glPixelStorei;
- gDefaultInterface.fReadPixels = glReadPixels;
- gDefaultInterface.fScissor = glScissor;
- gDefaultInterface.fShadeModel = glShadeModel;
- GR_GL_GET_PROC(ShaderSource);
- gDefaultInterface.fStencilFunc = glStencilFunc;
- GR_GL_GET_PROC(StencilFuncSeparate);
- gDefaultInterface.fStencilMask = glStencilMask;
- GR_GL_GET_PROC(StencilMaskSeparate);
- gDefaultInterface.fStencilOp = glStencilOp;
- GR_GL_GET_PROC(StencilOpSeparate);
- gDefaultInterface.fTexCoordPointer = glTexCoordPointer;
- gDefaultInterface.fTexEnvi = glTexEnvi;
- //OSMesa on Mac's glTexImage2D takes a GLenum for internalFormat rather than a GLint.
- gDefaultInterface.fTexImage2D = reinterpret_cast<GrGLTexImage2DProc>(glTexImage2D);
- gDefaultInterface.fTexParameteri = glTexParameteri;
- gDefaultInterface.fTexSubImage2D = glTexSubImage2D;
- GR_GL_GET_PROC(Uniform1f);
- GR_GL_GET_PROC(Uniform1i);
- GR_GL_GET_PROC(Uniform1fv);
- GR_GL_GET_PROC(Uniform1iv);
- GR_GL_GET_PROC(Uniform2f);
- GR_GL_GET_PROC(Uniform2i);
- GR_GL_GET_PROC(Uniform2fv);
- GR_GL_GET_PROC(Uniform2iv);
- GR_GL_GET_PROC(Uniform3f);
- GR_GL_GET_PROC(Uniform3i);
- GR_GL_GET_PROC(Uniform3fv);
- GR_GL_GET_PROC(Uniform3iv);
- GR_GL_GET_PROC(Uniform4f);
- GR_GL_GET_PROC(Uniform4i);
- GR_GL_GET_PROC(Uniform4fv);
- GR_GL_GET_PROC(Uniform4iv);
- GR_GL_GET_PROC(UniformMatrix2fv);
- GR_GL_GET_PROC(UniformMatrix3fv);
- GR_GL_GET_PROC(UniformMatrix4fv);
- GR_GL_GET_PROC(UnmapBuffer);
- GR_GL_GET_PROC(UseProgram);
- GR_GL_GET_PROC(VertexAttrib4fv);
- GR_GL_GET_PROC(VertexAttribPointer);
- gDefaultInterface.fVertexPointer = glVertexPointer;
- gDefaultInterface.fViewport = glViewport;
-
- // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since
- // GL_ARB_framebuffer_object doesn't use ARB suffix.)
- if (major >= 3 || has_gl_extension_from_string(
- "GL_ARB_framebuffer_object", extString)) {
- GR_GL_GET_PROC(GenFramebuffers);
- GR_GL_GET_PROC(BindFramebuffer);
- GR_GL_GET_PROC(FramebufferTexture2D);
- GR_GL_GET_PROC(CheckFramebufferStatus);
- GR_GL_GET_PROC(DeleteFramebuffers);
- GR_GL_GET_PROC(RenderbufferStorage);
- GR_GL_GET_PROC(GenRenderbuffers);
- GR_GL_GET_PROC(DeleteRenderbuffers);
- GR_GL_GET_PROC(FramebufferRenderbuffer);
- GR_GL_GET_PROC(BindRenderbuffer);
- GR_GL_GET_PROC(RenderbufferStorageMultisample);
- GR_GL_GET_PROC(BlitFramebuffer);
- } else if (has_gl_extension_from_string("GL_EXT_framebuffer_object",
- extString)) {
- GR_GL_GET_PROC_SUFFIX(GenFramebuffers, EXT);
- GR_GL_GET_PROC_SUFFIX(BindFramebuffer, EXT);
- GR_GL_GET_PROC_SUFFIX(FramebufferTexture2D, EXT);
- GR_GL_GET_PROC_SUFFIX(CheckFramebufferStatus, EXT);
- GR_GL_GET_PROC_SUFFIX(DeleteFramebuffers, EXT);
- GR_GL_GET_PROC_SUFFIX(RenderbufferStorage, EXT);
- GR_GL_GET_PROC_SUFFIX(GenRenderbuffers, EXT);
- GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
- GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
- GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, EXT);
- if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample",
- extString)) {
- GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
- }
- if (has_gl_extension_from_string("GL_EXT_framebuffer_blit",
- extString)) {
- GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT);
- }
- } else {
- // we must have FBOs
- return;
- }
- GR_GL_GET_PROC(BindFragDataLocationIndexed);
- gDefaultInterface.fBindingsExported = kDesktop_GrGLBinding;
-
- gDefaultInterfaceInit = true;
- }
- if (gDefaultInterfaceInit)
- GrGLSetGLInterface(&gDefaultInterface);
-}
diff --git a/gpu/src/skia/SkUIView.mm b/gpu/src/skia/SkUIView.mm
deleted file mode 100644
index 8cd6c77..0000000
--- a/gpu/src/skia/SkUIView.mm
+++ /dev/null
@@ -1,858 +0,0 @@
-#import "SkUIView.h"
-#include <QuartzCore/QuartzCore.h>
-
-#include "SkGpuCanvas.h"
-#include "SkCGUtils.h"
-#include "GrContext.h"
-
-#define SKWIND_CONFIG SkBitmap::kRGB_565_Config
-//#define SKWIND_CONFIG SkBitmap::kARGB_8888_Config
-#define SKGL_CONFIG kEAGLColorFormatRGB565
-//#define SKGL_CONFIG kEAGLColorFormatRGBA8
-
-#define SHOW_FPS
-#define FORCE_REDRAW
-//#define DUMP_FPS_TO_PRINTF
-
-//#define USE_ACCEL_TO_ROTATE
-
-//#define SHOULD_COUNTER_INIT 334
-static int gShouldCounter;
-static bool should_draw() {
- if (--gShouldCounter == 0) {
- // printf("\n");
- }
- return true;
- return gShouldCounter >= 0;
-}
-#ifdef SHOULD_COUNTER_INIT
- bool (*gShouldDrawProc)() = should_draw;
-#else
- bool (*gShouldDrawProc)() = NULL;
-#endif
-
-//#define USE_GL_1
-#define USE_GL_2
-
-#if defined(USE_GL_1) || defined(USE_GL_2)
- #define USE_GL
-#endif
-
-@implementation SkUIView
-
-
-@synthesize fWind;
-@synthesize fTitleLabel;
-@synthesize fBackend;
-@synthesize fComplexClip;
-@synthesize fUseWarp;
-
-#include "SkWindow.h"
-#include "SkEvent.h"
-
-static float gScreenScale = 1;
-
-extern SkOSWindow* create_sk_window(void* hwnd);
-
-#define kREDRAW_UIVIEW_GL "sk_redraw_uiview_gl_iOS"
-
-#define TITLE_HEIGHT 44
-
-static const float SCALE_FOR_ZOOM_LENS = 4.0;
-#define Y_OFFSET_FOR_ZOOM_LENS 200
-#define SIZE_FOR_ZOOM_LENS 250
-
-static const float MAX_ZOOM_SCALE = 4.0;
-static const float MIN_ZOOM_SCALE = 2.0 / MAX_ZOOM_SCALE;
-
-extern bool gDoTraceDraw;
-#define DO_TRACE_DRAW_MAX 100
-
-#ifdef SHOW_FPS
-struct FPSState {
- static const int FRAME_COUNT = 60;
-
- CFTimeInterval fNow0, fNow1;
- CFTimeInterval fTime0, fTime1, fTotalTime;
- int fFrameCounter;
- int fDrawCounter;
-
- FPSState() {
- fTime0 = fTime1 = fTotalTime = 0;
- fFrameCounter = 0;
- }
-
- void startDraw() {
- fNow0 = CACurrentMediaTime();
-
- if (0 == fDrawCounter && false) {
- gDoTraceDraw = true;
- SkDebugf("\n");
- }
- }
-
- void endDraw() {
- fNow1 = CACurrentMediaTime();
-
- if (0 == fDrawCounter) {
- gDoTraceDraw = true;
- }
- if (DO_TRACE_DRAW_MAX == ++fDrawCounter) {
- fDrawCounter = 0;
- }
- }
-
- void flush(SkOSWindow* wind) {
- CFTimeInterval now2 = CACurrentMediaTime();
-
- fTime0 += fNow1 - fNow0;
- fTime1 += now2 - fNow1;
-
- if (++fFrameCounter == FRAME_COUNT) {
- CFTimeInterval totalNow = CACurrentMediaTime();
- fTotalTime = totalNow - fTotalTime;
-
- SkMSec ms0 = (int)(1000 * fTime0 / FRAME_COUNT);
- SkMSec msTotal = (int)(1000 * fTotalTime / FRAME_COUNT);
-
- SkString str;
- str.printf("ms: %d [%d], fps: %3.1f", msTotal, ms0,
- FRAME_COUNT / fTotalTime);
-#ifdef DUMP_FPS_TO_PRINTF
- SkDebugf("%s\n", str.c_str());
-#else
- wind->setTitle(str.c_str());
-#endif
-
- fTotalTime = totalNow;
- fTime0 = fTime1 = 0;
- fFrameCounter = 0;
- }
- }
-};
-
-static FPSState gFPS;
-
- #define FPS_StartDraw() gFPS.startDraw()
- #define FPS_EndDraw() gFPS.endDraw()
- #define FPS_Flush(wind) gFPS.flush(wind)
-#else
- #define FPS_StartDraw()
- #define FPS_EndDraw()
- #define FPS_Flush(wind)
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-
-#ifdef USE_GL
-+ (Class) layerClass
-{
- return [CAEAGLLayer class];
-}
-#endif
-
-- (id)initWithMyDefaults {
- fBackend = kGL_Backend;
- fUseWarp = false;
- fRedrawRequestPending = false;
- fWind = create_sk_window(self);
- fWind->setConfig(SKWIND_CONFIG);
- fMatrix.reset();
- fLocalMatrix.reset();
- fNeedGestureEnded = false;
- fNeedFirstPinch = true;
- fZoomAround = false;
- fComplexClip = false;
-
- [self initGestures];
-
-#ifdef USE_GL
- CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
- eaglLayer.opaque = TRUE;
- eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithBool:NO],
- kEAGLDrawablePropertyRetainedBacking,
- SKGL_CONFIG,
- kEAGLDrawablePropertyColorFormat,
- nil];
-
-#ifdef USE_GL_1
- fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
-#else
- fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
-#endif
-
- if (!fGL.fContext || ![EAGLContext setCurrentContext:fGL.fContext])
- {
- [self release];
- return nil;
- }
-
- // Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer
- glGenFramebuffersOES(1, &fGL.fFramebuffer);
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, fGL.fFramebuffer);
-
- glGenRenderbuffersOES(1, &fGL.fRenderbuffer);
- glGenRenderbuffersOES(1, &fGL.fStencilbuffer);
-
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, fGL.fRenderbuffer);
- glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, fGL.fRenderbuffer);
-
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, fGL.fStencilbuffer);
- glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, fGL.fStencilbuffer);
-#endif
-
-#ifdef USE_ACCEL_TO_ROTATE
- fRotateMatrix.reset();
- [UIAccelerometer sharedAccelerometer].delegate = self;
- [UIAccelerometer sharedAccelerometer].updateInterval = 1 / 30.0;
-#endif
- return self;
-}
-
-- (id)initWithCoder:(NSCoder*)coder {
- if ((self = [super initWithCoder:coder])) {
- self = [self initWithMyDefaults];
- }
- return self;
-}
-
-- (id)initWithFrame:(CGRect)frame {
- if (self = [super initWithFrame:frame]) {
- self = [self initWithMyDefaults];
- }
- return self;
-}
-
-#include "SkImageDecoder.h"
-#include "SkStream_NSData.h"
-
-static void zoom_around(SkCanvas* canvas, float cx, float cy, float zoom) {
- float clipW = SIZE_FOR_ZOOM_LENS;
- float clipH = SIZE_FOR_ZOOM_LENS;
-
- SkRect r;
- r.set(0, 0, clipW, clipH);
- r.offset(cx - clipW/2, cy - clipH/2);
-
- SkPaint paint;
- paint.setColor(0xFF66AAEE);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setStrokeWidth(10);
-
- // draw our "frame" around the zoom lens
- canvas->drawRect(r, paint);
-
- // now clip and scale the lens
- canvas->clipRect(r);
- canvas->translate(cx, cy);
- canvas->scale(zoom, zoom);
- canvas->translate(-cx, -cy);
-}
-
-- (void)drawWithCanvas:(SkCanvas*)canvas {
- if (fComplexClip) {
- canvas->drawColor(SK_ColorBLUE);
-
- SkPath path;
- static const SkRect r[] = {
- { 50, 50, 250, 250 },
- { 150, 150, 500, 600 }
- };
- for (size_t i = 0; i < GR_ARRAY_COUNT(r); i++) {
- path.addRect(r[i]);
- }
- canvas->clipPath(path);
- }
-
- // This is to consolidate multiple inval requests
- fRedrawRequestPending = false;
-
- if (fFlingState.isActive()) {
- if (!fFlingState.evaluateMatrix(&fLocalMatrix)) {
- [self flushLocalMatrix];
- }
- }
-
- SkMatrix localMatrix = fLocalMatrix;
-#ifdef USE_ACCEL_TO_ROTATE
- localMatrix.preConcat(fRotateMatrix);
-#endif
-
- SkMatrix matrix;
- matrix.setConcat(localMatrix, fMatrix);
-
- const SkMatrix* localM = NULL;
- if (localMatrix.getType() & SkMatrix::kScale_Mask) {
- localM = &localMatrix;
- }
-#ifdef USE_ACCEL_TO_ROTATE
- localM = &localMatrix;
-#endif
- canvas->setExternalMatrix(localM);
-
-#ifdef SHOULD_COUNTER_INIT
- gShouldCounter = SHOULD_COUNTER_INIT;
-#endif
-
- {
- int saveCount = canvas->save();
- canvas->concat(matrix);
-// SkRect r = { 10, 10, 500, 600 }; canvas->clipRect(r);
- fWind->draw(canvas);
- canvas->restoreToCount(saveCount);
- }
-
- if (fZoomAround) {
- zoom_around(canvas, fZoomAroundX, fZoomAroundY, SCALE_FOR_ZOOM_LENS);
- canvas->concat(matrix);
- fWind->draw(canvas);
- }
-
-#ifdef FORCE_REDRAW
- fWind->inval(NULL);
-#endif
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-- (void)layoutSubviews {
- int W, H;
-
- gScreenScale = [UIScreen mainScreen].scale;
-
-#ifdef USE_GL
-
- CAEAGLLayer* eaglLayer = (CAEAGLLayer*)self.layer;
- if ([self respondsToSelector:@selector(setContentScaleFactor:)]) {
- self.contentScaleFactor = gScreenScale;
- }
- // Allocate color buffer backing based on the current layer size
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, fGL.fRenderbuffer);
- [fGL.fContext renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:eaglLayer];
-
- glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &fGL.fWidth);
- glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &fGL.fHeight);
-
- if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
- {
- NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
- }
-
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, fGL.fStencilbuffer);
- glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_STENCIL_INDEX8_OES, fGL.fWidth, fGL.fHeight);
-
- W = fGL.fWidth;
- H = fGL.fHeight;
-#else
- CGRect rect = [self bounds];
- W = (int)CGRectGetWidth(rect);
- H = (int)CGRectGetHeight(rect) - TITLE_HEIGHT;
-#endif
-
- printf("---- layoutSubviews %d %d\n", W, H);
- fWind->resize(W, H);
- fWind->inval(NULL);
-}
-
-#ifdef USE_GL
-
-static GrContext* gCtx;
-static GrContext* get_global_grctx() {
- // should be pthread-local at least
- if (NULL == gCtx) {
-#ifdef USE_GL_1
- gCtx = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, 0);
-#else
- gCtx = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, 0);
-#endif
- }
- return gCtx;
-}
-
-#include "SkDevice.h"
-#include "SkShader.h"
-#include "SkGrTexturePixelRef.h"
-#include "GrMesh.h"
-#include "SkRandom.h"
-
-#include "GrAtlas.h"
-#include "GrTextStrike.h"
-
-static void show_fontcache(GrContext* ctx, SkCanvas* canvas) {
-#if 0
- SkPaint paint;
- const int SIZE = 64;
- GrAtlas* plot[64][64];
-
- paint.setAntiAlias(true);
- paint.setTextSize(24);
- paint.setTextAlign(SkPaint::kCenter_Align);
-
- Gr_bzero(plot, sizeof(plot));
-
- GrFontCache* cache = ctx->getFontCache();
- GrTextStrike* strike = cache->getHeadStrike();
- int count = 0;
- while (strike) {
- GrAtlas* atlas = strike->getAtlas();
- while (atlas) {
- int x = atlas->getPlotX();
- int y = atlas->getPlotY();
-
- SkRandom rand((intptr_t)strike);
- SkColor c = rand.nextU() | 0x80808080;
- paint.setColor(c);
- paint.setAlpha(0x80);
-
- SkRect r;
- r.set(x * SIZE, y * SIZE, (x + 1)*SIZE, (y+1)*SIZE);
- r.inset(1, 1);
- canvas->drawRect(r, paint);
-
- paint.setColor(0xFF660000);
- SkString label;
- label.printf("%d", count);
- canvas->drawText(label.c_str(), label.size(), r.centerX(),
- r.fTop + r.height() * 2 / 3, paint);
-
- atlas = atlas->nextAtlas();
- }
- strike = strike->fNext;
- count += 1;
- }
-#endif
-}
-
-void test_patch(SkCanvas* canvas, const SkBitmap& bm, SkScalar scale);
-
-static void draw_mesh(SkCanvas* canvas, const SkBitmap& bm) {
- GrMesh fMesh;
-
- SkRect r;
- r.set(0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()));
-
- // fMesh.init(bounds, fBitmap.width() / 40, fBitmap.height() / 40, texture);
- fMesh.init(r, bm.width()/16, bm.height()/16, r);
-
- SkPaint paint;
- SkShader* s = SkShader::CreateBitmapShader(bm, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
- paint.setShader(s)->unref();
- fMesh.draw(canvas, paint);
-}
-
-static void scale_about(SkCanvas* canvas, float sx, float sy, float px, float py) {
- canvas->translate(px, py);
- canvas->scale(sx, sy);
- canvas->translate(-px, -py);
-}
-
-static float grInterp(float v0, float v1, float percent) {
- return v0 + percent * (v1 - v0);
-}
-
-static void draw_device(SkCanvas* canvas, SkDevice* dev, float w, float h, float warp) {
- canvas->save();
- float s = grInterp(1, 0.8, warp);
- scale_about(canvas, s, s, w/2, h/2);
- test_patch(canvas, dev->accessBitmap(false), warp);
- canvas->restore();
-}
-
-- (void)drawInGL {
-// printf("------ drawInGL\n");
- // This application only creates a single context which is already set current at this point.
- // This call is redundant, but needed if dealing with multiple contexts.
- [EAGLContext setCurrentContext:fGL.fContext];
-
- // This application only creates a single default framebuffer which is already bound at this point.
- // This call is redundant, but needed if dealing with multiple framebuffers.
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, fGL.fFramebuffer);
-
- GLint scissorEnable;
- glGetIntegerv(GL_SCISSOR_TEST, &scissorEnable);
- glDisable(GL_SCISSOR_TEST);
- glClearColor(0,0,0,0);
- glClear(GL_COLOR_BUFFER_BIT);
- if (scissorEnable) {
- glEnable(GL_SCISSOR_TEST);
- }
-
- GrContext* ctx = get_global_grctx();
- SkGpuCanvas origCanvas(ctx);
- origCanvas.setBitmapDevice(fWind->getBitmap());
-
- // gl->reset();
- SkGpuCanvas glCanvas(ctx);
- SkCanvas rasterCanvas;
-
- SkCanvas* canvas;
- SkDevice* dev = NULL;
-
- switch (fBackend) {
- case kRaster_Backend:
- canvas = &rasterCanvas;
- break;
- case kGL_Backend:
- canvas = &glCanvas;
- break;
- }
-
- if (fUseWarp || fWarpState.isActive()) {
- if (kGL_Backend == fBackend) {
- dev = origCanvas.createDevice(fWind->getBitmap(), true);
- canvas->setDevice(dev)->unref();
- } else {
- canvas->setBitmapDevice(fWind->getBitmap());
- dev = canvas->getDevice();
- }
- } else {
- canvas->setBitmapDevice(fWind->getBitmap());
- dev = NULL;
- }
-
- canvas->translate(0, TITLE_HEIGHT);
-
- // if we're not "retained", then we have to always redraw everything.
- // This call forces us to ignore the fDirtyRgn, and draw everywhere.
- // If we are "retained", we can skip this call (as the raster case does)
- fWind->forceInvalAll();
-
- FPS_StartDraw();
- [self drawWithCanvas:canvas];
- FPS_EndDraw();
-
- if (dev) {
- draw_device(&origCanvas, dev, fWind->width(), fWind->height(),
- fWarpState.evaluate());
- } else {
- if (kRaster_Backend == fBackend) {
- origCanvas.drawBitmap(fWind->getBitmap(), 0, 0, NULL);
- }
- // else GL - we're already on screen
- }
-
- show_fontcache(ctx, canvas);
- ctx->flush(false);
-
- // This application only creates a single color renderbuffer which is already bound at this point.
- // This call is redundant, but needed if dealing with multiple renderbuffers.
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, fGL.fRenderbuffer);
- [fGL.fContext presentRenderbuffer:GL_RENDERBUFFER_OES];
-
-#if GR_COLLECT_STATS
- static int frame = 0;
- if (!(frame % 100)) {
- get_global_grctx()->printStats();
- }
- get_global_grctx()->resetStats();
- ++frame;
-#endif
-
- FPS_Flush(fWind);
-
-#if 0
- gCtx->deleteAllTextures(GrTextureCache::kAbandonTexture_DeleteMode);
- gCtx->unref();
- gCtx = NULL;
-#endif
-}
-
-#else // raster case
-
-- (void)drawRect:(CGRect)rect {
- CGContextRef cg = UIGraphicsGetCurrentContext();
- SkCanvas* canvas = NULL;
-
- FPS_StartDraw();
- [self drawWithCanvas:canvas];
-
- FPS_EndDraw();
- SkCGDrawBitmap(cg, fWind->getBitmap(), 0, TITLE_HEIGHT);
-
- FPS_Flush(fWind);
-
-}
-#endif
-
-- (void)setWarpState:(bool)useWarp {
- fWarpState.stop(); // we should reverse from where we are if active...
-
- const float duration = 0.5;
- fUseWarp = useWarp;
- if (useWarp) {
- fWarpState.start(0, 1, duration);
- } else {
- fWarpState.start(1, 0, duration);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-- (void)flushLocalMatrix {
- fMatrix.postConcat(fLocalMatrix);
- fLocalMatrix.reset();
- fFlingState.stop();
- fNeedGestureEnded = false;
- fNeedFirstPinch = true;
-}
-
-- (void)localMatrixWithGesture:(UIGestureRecognizer*)gesture {
- fNeedGestureEnded = true;
-
- switch (gesture.state) {
- case UIGestureRecognizerStateCancelled:
- case UIGestureRecognizerStateEnded:
- [self flushLocalMatrix];
- break;
- case UIGestureRecognizerStateChanged: {
- SkMatrix matrix;
- matrix.setConcat(fLocalMatrix, fMatrix);
- } break;
- default:
- break;
- }
-}
-
-- (void)commonHandleGesture:(UIGestureRecognizer*)sender {
- if (fFlingState.isActive()) {
- [self flushLocalMatrix];
- }
-
- switch (sender.state) {
- case UIGestureRecognizerStateBegan:
- [self flushLocalMatrix];
- break;
- default:
- break;
- }
-}
-
-- (void)handleDTapGesture:(UIGestureRecognizer*)sender {
- [self flushLocalMatrix];
- fMatrix.reset();
-}
-
-static float discretize(float x) {
- return (int)x;
-}
-
-- (void)handlePanGesture:(UIPanGestureRecognizer*)sender {
- [self commonHandleGesture:sender];
-
- CGPoint delta = [sender translationInView:self];
- delta.x *= gScreenScale;
- delta.y *= gScreenScale;
- // avoid flickering where the drawing might toggle in and out of a pixel
- // center if translated by a fractional value
- delta.x = discretize(delta.x);
- delta.y = discretize(delta.y);
- fLocalMatrix.setTranslate(delta.x, delta.y);
- [self localMatrixWithGesture:sender];
-
- if (UIGestureRecognizerStateEnded == sender.state) {
- CGPoint velocity = [sender velocityInView:self];
- fFlingState.reset(velocity.x, velocity.y);
- fNeedGestureEnded = true;
- }
-}
-
-- (float)limitTotalZoom:(float)scale {
- // this query works 'cause we know that we're square-scale w/ no skew/rotation
- const float curr = fMatrix[0];
-
- if (scale > 1 && curr * scale > MAX_ZOOM_SCALE) {
- scale = MAX_ZOOM_SCALE / curr;
- } else if (scale < 1 && curr * scale < MIN_ZOOM_SCALE) {
- scale = MIN_ZOOM_SCALE / curr;
- }
- return scale;
-}
-
-- (void)handleScaleGesture:(UIPinchGestureRecognizer*)sender {
- [self commonHandleGesture:sender];
-
- if ([sender numberOfTouches] == 2) {
- float scale = sender.scale;
- CGPoint p0 = [sender locationOfTouch:0 inView:self];
- CGPoint p1 = [sender locationOfTouch:0 inView:self];
- float cx = (p0.x + p1.x) * 0.5;
- float cy = (p0.y + p1.y) * 0.5;
-
- if (fNeedFirstPinch) {
- fFirstPinchX = cx;
- fFirstPinchY = cy;
- fNeedFirstPinch = false;
- }
-
- scale = [self limitTotalZoom:scale];
-
- fLocalMatrix.setTranslate(-fFirstPinchX, -fFirstPinchY);
- fLocalMatrix.postScale(scale, scale);
- fLocalMatrix.postTranslate(cx, cy);
- [self localMatrixWithGesture:sender];
- } else {
- [self flushLocalMatrix];
- }
-}
-
-- (void)handleLongPressGesture:(UILongPressGestureRecognizer*)sender {
- [self commonHandleGesture:sender];
-
- if ([sender numberOfTouches] == 0) {
- fZoomAround = false;
- return;
- }
-
- CGPoint pt = [sender locationOfTouch:0 inView:self];
- switch (sender.state) {
- case UIGestureRecognizerStateBegan:
- case UIGestureRecognizerStateChanged:
- fZoomAround = true;
- fZoomAroundX = pt.x;
- fZoomAroundY = pt.y - Y_OFFSET_FOR_ZOOM_LENS;
- break;
- case UIGestureRecognizerStateEnded:
- case UIGestureRecognizerStateCancelled:
- fZoomAround = false;
- break;
- default:
- break;
- }
-}
-
-- (void)addAndReleaseGesture:(UIGestureRecognizer*)gesture {
- [self addGestureRecognizer:gesture];
- [gesture release];
-}
-
-- (void)initGestures {
- UITapGestureRecognizer* tapG = [UITapGestureRecognizer alloc];
- [tapG initWithTarget:self action:@selector(handleDTapGesture:)];
- tapG.numberOfTapsRequired = 2;
- [self addAndReleaseGesture:tapG];
-
- UIPanGestureRecognizer* panG = [UIPanGestureRecognizer alloc];
- [panG initWithTarget:self action:@selector(handlePanGesture:)];
- [self addAndReleaseGesture:panG];
-
- UIPinchGestureRecognizer* pinchG = [UIPinchGestureRecognizer alloc];
- [pinchG initWithTarget:self action:@selector(handleScaleGesture:)];
- [self addAndReleaseGesture:pinchG];
-
- UILongPressGestureRecognizer* longG = [UILongPressGestureRecognizer alloc];
- [longG initWithTarget:self action:@selector(handleLongPressGesture:)];
- [self addAndReleaseGesture:longG];
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static float abs(float x) { return x < 0 ? -x : x; }
-
-static bool normalize(UIAcceleration* acc, float xy[]) {
- float mag2 = acc.x*acc.x + acc.y*acc.y + acc.z*acc.z;
- if (mag2 < 0.000001) {
- return false;
- }
- if (abs((float)acc.z) > 0.9 * sqrt(mag2)) {
- return false;
- }
-
- mag2 = acc.x*acc.x + acc.y*acc.y;
- if (mag2 < 0.000001) {
- return false;
- }
- float scale = 1 / sqrt(mag2);
- xy[0] = acc.x * scale;
- xy[1] = acc.y * scale;
- return true;
-}
-
-static void normalize(float xy[]) {
- float scale = 1 / sqrt(xy[0]*xy[0] + xy[1]*xy[1]);
- xy[0] *= scale;
- xy[1] *= scale;
-}
-
-static float weighted_average(float newv, float oldv) {
- return newv * 0.25 + oldv * 0.75;
-}
-
-- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acc {
-
- float norm[2];
- if (normalize(acc, norm)) {
- float sinv = -norm[0];
- float cosv = -norm[1];
- // smooth
- norm[0] = weighted_average(sinv, -fRotateMatrix[1]);
- norm[1] = weighted_average(cosv, fRotateMatrix[0]);
- normalize(norm);
- fRotateMatrix.setSinCos(norm[0], norm[1], 400, 400);
- }
-#if 0
- NSDate *now = [NSDate date];
- NSTimeInterval intervalDate = [now timeIntervalSinceDate:now_prev];
-
- velX += (acceleration.x * intervalDate);
- distX += (velX * intervalDate);
- //do other axis here too
-
- // setup for next UIAccelerometer event
- now_prev = now;
-#endif
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-- (void)setSkTitle:(const char *)title {
- if (fTitleLabel) {
- fTitleLabel.text = [NSString stringWithUTF8String:title];
- [fTitleLabel setNeedsDisplay];
- }
-}
-
-- (BOOL)onHandleEvent:(const SkEvent&)evt {
- if (evt.isType(kREDRAW_UIVIEW_GL)) {
- [self drawInGL];
- return true;
- }
- return false;
-}
-
-- (void)postInvalWithRect:(const SkIRect*)r {
-#ifdef USE_GL
-
-#if 1
- if (!fRedrawRequestPending) {
- fRedrawRequestPending = true;
- /*
- performSelectorOnMainThread seems to starve updating other views
- (e.g. our FPS view in the titlebar), so we use the afterDelay
- version
- */
- if (0) {
- [self performSelectorOnMainThread:@selector(drawInGL) withObject:nil waitUntilDone:NO];
- } else {
- [self performSelector:@selector(drawInGL) withObject:nil afterDelay:0];
- }
- }
-#else
- if (!fRedrawRequestPending) {
- SkEvent* evt = new SkEvent(kREDRAW_UIVIEW_GL);
- evt->post(fWind->getSinkID());
- fRedrawRequestPending = true;
- }
-#endif
-
-#else
- if (r) {
- [self setNeedsDisplayInRect:CGRectMake(r->fLeft, r->fTop,
- r->width(), r->height())];
- } else {
- [self setNeedsDisplay];
- }
-#endif
-}
-
-@end
diff --git a/gpu/src/unix/GrGLDefaultInterface_unix.cpp b/gpu/src/unix/GrGLDefaultInterface_unix.cpp
deleted file mode 100644
index 3e9b975..0000000
--- a/gpu/src/unix/GrGLDefaultInterface_unix.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "GrGLInterface.h"
-
-#include <GL/glx.h>
-#include <GL/gl.h>
-#include <GL/glext.h>
-#include <GL/glu.h>
-
-#define GR_GL_GET_PROC(F) gDefaultInterface.f ## F = (GrGL ## F ## Proc) \
- glXGetProcAddress(reinterpret_cast<const GLubyte*>("gl" #F));
-#define GR_GL_GET_PROC_SUFFIX(F, S) gDefaultInterface.f ## F = (GrGL ## F ## Proc) \
- glXGetProcAddress(reinterpret_cast<const GLubyte*>("gl" #F #S));
-
-void GrGLSetDefaultGLInterface() {
- static GrGLInterface gDefaultInterface;
- static bool gDefaultInterfaceInit;
- if (!gDefaultInterfaceInit && NULL != glXGetCurrentContext()) {
- int major, minor;
- const char* versionString = (const char*) glGetString(GL_VERSION);
- const char* extString = (const char*) glGetString(GL_EXTENSIONS);
- gl_version_from_string(&major, &minor, versionString);
-
- if (major == 1 && minor < 5) {
- // We must have array and element_array buffer objects.
- return;
- }
-
- gDefaultInterface.fActiveTexture = glActiveTexture;
- GR_GL_GET_PROC(AttachShader);
- GR_GL_GET_PROC(BindAttribLocation);
- GR_GL_GET_PROC(BindBuffer);
- gDefaultInterface.fBindTexture = glBindTexture;
- gDefaultInterface.fBlendColor = glBlendColor;
- gDefaultInterface.fBlendFunc = glBlendFunc;
- GR_GL_GET_PROC(BufferData);
- GR_GL_GET_PROC(BufferSubData);
- gDefaultInterface.fClear = glClear;
- gDefaultInterface.fClearColor = glClearColor;
- gDefaultInterface.fClearStencil = glClearStencil;
- gDefaultInterface.fClientActiveTexture = glClientActiveTexture;
- gDefaultInterface.fColorMask = glColorMask;
- gDefaultInterface.fColorPointer = glColorPointer;
- gDefaultInterface.fColor4ub = glColor4ub;
- GR_GL_GET_PROC(CompileShader);
- gDefaultInterface.fCompressedTexImage2D = glCompressedTexImage2D;
- GR_GL_GET_PROC(CreateProgram);
- GR_GL_GET_PROC(CreateShader);
- gDefaultInterface.fCullFace = glCullFace;
- GR_GL_GET_PROC(DeleteBuffers);
- GR_GL_GET_PROC(DeleteProgram);
- GR_GL_GET_PROC(DeleteShader);
- gDefaultInterface.fDeleteTextures = glDeleteTextures;
- gDefaultInterface.fDepthMask = glDepthMask;
- gDefaultInterface.fDisable = glDisable;
- gDefaultInterface.fDisableClientState = glDisableClientState;
- GR_GL_GET_PROC(DisableVertexAttribArray);
- gDefaultInterface.fDrawArrays = glDrawArrays;
- gDefaultInterface.fDrawElements = glDrawElements;
- gDefaultInterface.fEnable = glEnable;
- gDefaultInterface.fEnableClientState = glEnableClientState;
- GR_GL_GET_PROC(EnableVertexAttribArray);
- gDefaultInterface.fFrontFace = glFrontFace;
- GR_GL_GET_PROC(GenBuffers);
- GR_GL_GET_PROC(GetBufferParameteriv);
- gDefaultInterface.fGetError = glGetError;
- gDefaultInterface.fGetIntegerv = glGetIntegerv;
- GR_GL_GET_PROC(GetProgramInfoLog);
- GR_GL_GET_PROC(GetProgramiv);
- GR_GL_GET_PROC(GetShaderInfoLog);
- GR_GL_GET_PROC(GetShaderiv);
- gDefaultInterface.fGetString = glGetString;
- gDefaultInterface.fGenTextures = glGenTextures;
- GR_GL_GET_PROC(GetUniformLocation);
- gDefaultInterface.fLineWidth = glLineWidth;
- GR_GL_GET_PROC(LinkProgram);
- gDefaultInterface.fLoadMatrixf = glLoadMatrixf;
- GR_GL_GET_PROC(MapBuffer);
- gDefaultInterface.fMatrixMode = glMatrixMode;
- gDefaultInterface.fPointSize = glPointSize;
- gDefaultInterface.fPixelStorei = glPixelStorei;
- gDefaultInterface.fReadPixels = glReadPixels;
- gDefaultInterface.fScissor = glScissor;
- gDefaultInterface.fShadeModel = glShadeModel;
- GR_GL_GET_PROC(ShaderSource);
- gDefaultInterface.fStencilFunc = glStencilFunc;
- GR_GL_GET_PROC(StencilFuncSeparate);
- gDefaultInterface.fStencilMask = glStencilMask;
- GR_GL_GET_PROC(StencilMaskSeparate);
- gDefaultInterface.fStencilOp = glStencilOp;
- GR_GL_GET_PROC(StencilOpSeparate);
- gDefaultInterface.fTexCoordPointer = glTexCoordPointer;
- gDefaultInterface.fTexEnvi = glTexEnvi;
- gDefaultInterface.fTexImage2D = glTexImage2D;
- gDefaultInterface.fTexParameteri = glTexParameteri;
- gDefaultInterface.fTexSubImage2D = glTexSubImage2D;
- GR_GL_GET_PROC(Uniform1f);
- GR_GL_GET_PROC(Uniform1i);
- GR_GL_GET_PROC(Uniform1fv);
- GR_GL_GET_PROC(Uniform1iv);
- GR_GL_GET_PROC(Uniform2f);
- GR_GL_GET_PROC(Uniform2i);
- GR_GL_GET_PROC(Uniform2fv);
- GR_GL_GET_PROC(Uniform2iv);
- GR_GL_GET_PROC(Uniform3f);
- GR_GL_GET_PROC(Uniform3i);
- GR_GL_GET_PROC(Uniform3fv);
- GR_GL_GET_PROC(Uniform3iv);
- GR_GL_GET_PROC(Uniform4f);
- GR_GL_GET_PROC(Uniform4i);
- GR_GL_GET_PROC(Uniform4fv);
- GR_GL_GET_PROC(Uniform4iv);
- GR_GL_GET_PROC(UniformMatrix2fv);
- GR_GL_GET_PROC(UniformMatrix3fv);
- GR_GL_GET_PROC(UniformMatrix4fv);
- GR_GL_GET_PROC(UnmapBuffer);
- GR_GL_GET_PROC(UseProgram);
- GR_GL_GET_PROC(VertexAttrib4fv);
- GR_GL_GET_PROC(VertexAttribPointer);
- gDefaultInterface.fVertexPointer = glVertexPointer;
- gDefaultInterface.fViewport = glViewport;
- GR_GL_GET_PROC(BindFragDataLocationIndexed);
-
- // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since
- // GL_ARB_framebuffer_object doesn't use ARB suffix.)
- if (major >= 3 || has_gl_extension_from_string(
- "GL_ARB_framebuffer_object", extString)) {
- GR_GL_GET_PROC(GenFramebuffers);
- GR_GL_GET_PROC(BindFramebuffer);
- GR_GL_GET_PROC(FramebufferTexture2D);
- GR_GL_GET_PROC(CheckFramebufferStatus);
- GR_GL_GET_PROC(DeleteFramebuffers);
- GR_GL_GET_PROC(RenderbufferStorage);
- GR_GL_GET_PROC(GenRenderbuffers);
- GR_GL_GET_PROC(DeleteRenderbuffers);
- GR_GL_GET_PROC(FramebufferRenderbuffer);
- GR_GL_GET_PROC(BindRenderbuffer);
- GR_GL_GET_PROC(RenderbufferStorageMultisample);
- GR_GL_GET_PROC(BlitFramebuffer);
- } else if (has_gl_extension_from_string("GL_EXT_framebuffer_object",
- extString)) {
- GR_GL_GET_PROC_SUFFIX(GenFramebuffers, EXT);
- GR_GL_GET_PROC_SUFFIX(BindFramebuffer, EXT);
- GR_GL_GET_PROC_SUFFIX(FramebufferTexture2D, EXT);
- GR_GL_GET_PROC_SUFFIX(CheckFramebufferStatus, EXT);
- GR_GL_GET_PROC_SUFFIX(DeleteFramebuffers, EXT);
- GR_GL_GET_PROC_SUFFIX(RenderbufferStorage, EXT);
- GR_GL_GET_PROC_SUFFIX(GenRenderbuffers, EXT);
- GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
- GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
- GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, EXT);
- if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample",
- extString)) {
- GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
- }
- if (has_gl_extension_from_string("GL_EXT_framebuffer_blit",
- extString)) {
- GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT);
- }
- } else {
- // we must have FBOs
- return;
- }
- gDefaultInterface.fBindingsExported = kDesktop_GrGLBinding;
-
- gDefaultInterfaceInit = true;
- }
- if (gDefaultInterfaceInit)
- GrGLSetGLInterface(&gDefaultInterface);
-}
diff --git a/gpu/src/win/GrGLDefaultInterface_win.cpp b/gpu/src/win/GrGLDefaultInterface_win.cpp
deleted file mode 100644
index 428abb1..0000000
--- a/gpu/src/win/GrGLDefaultInterface_win.cpp
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "GrGLInterface.h"
-
-#include <Windows.h>
-#include <GL/GL.h>
-
-/*
- * Windows makes the GL funcs all be __stdcall instead of __cdecl :(
- * This implementation will only work if GR_GL_FUNCTION_TYPE is __stdcall.
- * Otherwise, a springboard would be needed that hides the calling convention.
- */
-
-#define GR_GL_GET_PROC(F) gDefaultInterface.f ## F = (GrGL ## F ## Proc) wglGetProcAddress("gl" #F);
-#define GR_GL_GET_PROC_SUFFIX(F, S) gDefaultInterface.f ## F = (GrGL ## F ## Proc) wglGetProcAddress("gl" #F #S);
-
-void GrGLSetDefaultGLInterface() {
- static GrGLInterface gDefaultInterface;
- static bool gDefaultInterfaceInit;
- if (!gDefaultInterfaceInit) {
-
- // wglGetProcAddress requires a context.
- if (NULL != wglGetCurrentContext()) {
- int major, minor;
- const char* versionString = (const char*) glGetString(GL_VERSION);
- const char* extString = (const char*) glGetString(GL_EXTENSIONS);
- gl_version_from_string(&major, &minor, versionString);
-
- if (major == 1 && minor < 5) {
- // We must have array and element_array buffer objects.
- return;
- }
-
- // Functions that are part of GL 1.1 will return NULL in
- // wglGetProcAddress
- gDefaultInterface.fBlendFunc = glBlendFunc;
- gDefaultInterface.fClear = glClear;
- gDefaultInterface.fClearColor = glClearColor;
- gDefaultInterface.fClearStencil = glClearStencil;
- gDefaultInterface.fColor4ub = glColor4ub;
- gDefaultInterface.fColorMask = glColorMask;
- gDefaultInterface.fColorPointer = glColorPointer;
- gDefaultInterface.fCullFace = glCullFace;
- gDefaultInterface.fDeleteTextures = glDeleteTextures;
- gDefaultInterface.fDepthMask = glDepthMask;
- gDefaultInterface.fDisable = glDisable;
- gDefaultInterface.fDisableClientState = glDisableClientState;
- gDefaultInterface.fDrawArrays = glDrawArrays;
- gDefaultInterface.fDrawElements = glDrawElements;
- gDefaultInterface.fEnable = glEnable;
- gDefaultInterface.fEnableClientState = glEnableClientState;
- gDefaultInterface.fFrontFace = glFrontFace;
- gDefaultInterface.fGenTextures = glGenTextures;
- gDefaultInterface.fGetError = glGetError;
- gDefaultInterface.fGetIntegerv = glGetIntegerv;
- gDefaultInterface.fGetString = glGetString;
- gDefaultInterface.fLineWidth = glLineWidth;
- gDefaultInterface.fLoadMatrixf = glLoadMatrixf;
- gDefaultInterface.fMatrixMode = glMatrixMode;
- gDefaultInterface.fPixelStorei = glPixelStorei;
- gDefaultInterface.fPointSize = glPointSize;
- gDefaultInterface.fReadPixels = glReadPixels;
- gDefaultInterface.fScissor = glScissor;
- gDefaultInterface.fShadeModel = glShadeModel;
- gDefaultInterface.fStencilFunc = glStencilFunc;
- gDefaultInterface.fStencilMask = glStencilMask;
- gDefaultInterface.fStencilOp = glStencilOp;
- gDefaultInterface.fTexImage2D = glTexImage2D;
- gDefaultInterface.fTexParameteri = glTexParameteri;
- gDefaultInterface.fTexCoordPointer = glTexCoordPointer;
- gDefaultInterface.fTexEnvi = glTexEnvi;
- gDefaultInterface.fTexSubImage2D = glTexSubImage2D;
- gDefaultInterface.fViewport = glViewport;
- gDefaultInterface.fVertexPointer = glVertexPointer;
-
- GR_GL_GET_PROC(ActiveTexture);
- GR_GL_GET_PROC(AttachShader);
- GR_GL_GET_PROC(BindAttribLocation);
- GR_GL_GET_PROC(BindBuffer);
- GR_GL_GET_PROC(BindTexture);
- GR_GL_GET_PROC(BlendColor);
- GR_GL_GET_PROC(BufferData);
- GR_GL_GET_PROC(BufferSubData);
- GR_GL_GET_PROC(ClientActiveTexture);
- GR_GL_GET_PROC(CompileShader);
- GR_GL_GET_PROC(CompressedTexImage2D);
- GR_GL_GET_PROC(CreateProgram);
- GR_GL_GET_PROC(CreateShader);
- GR_GL_GET_PROC(DeleteBuffers);
- GR_GL_GET_PROC(DeleteProgram);
- GR_GL_GET_PROC(DeleteShader);
- GR_GL_GET_PROC(DisableVertexAttribArray);
- GR_GL_GET_PROC(EnableVertexAttribArray);
- GR_GL_GET_PROC(GenBuffers);
- GR_GL_GET_PROC(GetBufferParameteriv);
- GR_GL_GET_PROC(GetProgramInfoLog);
- GR_GL_GET_PROC(GetProgramiv);
- GR_GL_GET_PROC(GetShaderInfoLog);
- GR_GL_GET_PROC(GetShaderiv);
- GR_GL_GET_PROC(GetUniformLocation);
- GR_GL_GET_PROC(LinkProgram);
- GR_GL_GET_PROC(ShaderSource);
- GR_GL_GET_PROC(StencilFuncSeparate);
- GR_GL_GET_PROC(StencilMaskSeparate);
- GR_GL_GET_PROC(StencilOpSeparate);
- GR_GL_GET_PROC(Uniform1f);
- GR_GL_GET_PROC(Uniform1i);
- GR_GL_GET_PROC(Uniform1fv);
- GR_GL_GET_PROC(Uniform1iv);
- GR_GL_GET_PROC(Uniform2f);
- GR_GL_GET_PROC(Uniform2i);
- GR_GL_GET_PROC(Uniform2fv);
- GR_GL_GET_PROC(Uniform2iv);
- GR_GL_GET_PROC(Uniform3f);
- GR_GL_GET_PROC(Uniform3i);
- GR_GL_GET_PROC(Uniform3fv);
- GR_GL_GET_PROC(Uniform3iv);
- GR_GL_GET_PROC(Uniform4f);
- GR_GL_GET_PROC(Uniform4i);
- GR_GL_GET_PROC(Uniform4fv);
- GR_GL_GET_PROC(Uniform4iv);
- GR_GL_GET_PROC(UniformMatrix2fv);
- GR_GL_GET_PROC(UniformMatrix3fv);
- GR_GL_GET_PROC(UniformMatrix4fv);
- GR_GL_GET_PROC(UseProgram);
- GR_GL_GET_PROC(VertexAttrib4fv);
- GR_GL_GET_PROC(VertexAttribPointer);
- GR_GL_GET_PROC(BindFragDataLocationIndexed);
-
- // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since
- // GL_ARB_framebuffer_object doesn't use ARB suffix.)
- if (major >= 3 || has_gl_extension_from_string("GL_ARB_framebuffer_object", extString)) {
- GR_GL_GET_PROC(GenFramebuffers);
- GR_GL_GET_PROC(BindFramebuffer);
- GR_GL_GET_PROC(FramebufferTexture2D);
- GR_GL_GET_PROC(CheckFramebufferStatus);
- GR_GL_GET_PROC(DeleteFramebuffers);
- GR_GL_GET_PROC(RenderbufferStorage);
- GR_GL_GET_PROC(GenRenderbuffers);
- GR_GL_GET_PROC(DeleteRenderbuffers);
- GR_GL_GET_PROC(FramebufferRenderbuffer);
- GR_GL_GET_PROC(BindRenderbuffer);
- GR_GL_GET_PROC(RenderbufferStorageMultisample);
- GR_GL_GET_PROC(BlitFramebuffer);
- } else if (has_gl_extension_from_string("GL_EXT_framebuffer_object", extString)) {
- GR_GL_GET_PROC_SUFFIX(GenFramebuffers, EXT);
- GR_GL_GET_PROC_SUFFIX(BindFramebuffer, EXT);
- GR_GL_GET_PROC_SUFFIX(FramebufferTexture2D, EXT);
- GR_GL_GET_PROC_SUFFIX(CheckFramebufferStatus, EXT);
- GR_GL_GET_PROC_SUFFIX(DeleteFramebuffers, EXT);
- GR_GL_GET_PROC_SUFFIX(RenderbufferStorage, EXT);
- GR_GL_GET_PROC_SUFFIX(GenRenderbuffers, EXT);
- GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
- GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
- GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, EXT);
- if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample", extString)) {
- GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
- }
- if (has_gl_extension_from_string("GL_EXT_framebuffer_blit", extString)) {
- GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT);
- }
- } else {
- // we must have FBOs
- return;
- }
- GR_GL_GET_PROC(MapBuffer);
- GR_GL_GET_PROC(UnmapBuffer);
-
- gDefaultInterface.fBindingsExported = kDesktop_GrGLBinding;
-
- gDefaultInterfaceInit = true;
- }
- }
- if (gDefaultInterfaceInit) {
- GrGLSetGLInterface(&gDefaultInterface);
- }
-}
diff --git a/gyp/FileReaderApp.gyp b/gyp/FileReaderApp.gyp
new file mode 100644
index 0000000..c5651c7
--- /dev/null
+++ b/gyp/FileReaderApp.gyp
@@ -0,0 +1,78 @@
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'FileReaderApp',
+ 'type': 'executable',
+ 'mac_bundle' : 1,
+
+ 'include_dirs' : [
+ '../include/pipe',
+ '../experimental/FileReaderApp',
+ '../experimental/SimpleCocoaApp',
+ ],
+ 'sources': [
+ '../experimental/FileReaderApp/ReaderView.cpp',
+ '../src/pipe/SkGPipeRead.cpp',
+ ],
+ 'sources!': [
+ '../src/utils/mac/SkOSWindow_Mac.cpp',
+ ],
+ 'dependencies': [
+ 'core.gyp:core',
+ 'effects.gyp:effects',
+ 'opts.gyp:opts',
+ 'ports.gyp:ports',
+ 'utils.gyp:utils',
+ 'views.gyp:views',
+ 'xml.gyp:xml',
+ ],
+ 'conditions' : [
+ # Only supports Mac currently
+ ['skia_os == "mac"', {
+ 'sources': [
+ '../experimental/SimpleCocoaApp/SkNSWindow.mm',
+ '../experimental/SimpleCocoaApp/SkNSView.mm',
+ '../experimental/FileReaderApp/FileReaderApp-Info.plist',
+ '../experimental/FileReaderApp/FileReaderAppDelegate.mm',
+ '../experimental/FileReaderApp/FileReaderApp_Prefix.pch',
+ '../experimental/FileReaderApp/FileReaderWindow.mm',
+ '../experimental/FileReaderApp/main.m',
+ '../include/utils/mac/SkCGUtils.h',
+ '../src/utils/mac/SkCreateCGImageRef.cpp',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Cocoa.framework',
+ '$(SDKROOT)/System/Library/Frameworks/AppKit.framework',
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/OpenGL.framework',
+ ],
+ 'libraries!': [
+ # Currently skia mac apps rely on Carbon and AGL for UI. Future
+ # apps should use Cocoa instead and dependencies on Carbon and AGL
+ # should eventually be removed
+ '$(SDKROOT)/System/Library/Frameworks/Carbon.framework',
+ '$(SDKROOT)/System/Library/Frameworks/AGL.framework',
+ ],
+ },
+ 'xcode_settings' : {
+ 'INFOPLIST_FILE' : '../experimental/FileReaderApp/FileReaderApp-Info.plist',
+ },
+ 'mac_bundle_resources' : [
+ '../experimental/FileReaderApp/English.lproj/InfoPlist.strings',
+ '../experimental/FileReaderApp/English.lproj/MainMenu.xib',
+ ],
+ }],
+ ],
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/SampleApp.gyp b/gyp/SampleApp.gyp
new file mode 100644
index 0000000..fed4bf4
--- /dev/null
+++ b/gyp/SampleApp.gyp
@@ -0,0 +1,281 @@
+
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'SampleApp',
+ 'type': 'executable',
+ 'mac_bundle' : 1,
+ 'include_dirs' : [
+ '../src/core', # needed to get SkConcaveToTriangle, maybe this should be moved to include dir?
+ '../gm', # needed to pull gm.h
+ '../include/pipe', # To pull in SkGPipe.h for pipe reader/writer
+ '../samplecode', # To pull SampleApp.h and SampleCode.h
+ ],
+ 'includes': [
+ 'gmslides.gypi',
+ ],
+ 'sources': [
+ '../gm/gm.cpp',
+ '../gm/gm.h',
+
+ '../samplecode/GMSampleView.h',
+ '../samplecode/ClockFaceView.cpp',
+ '../samplecode/OverView.cpp',
+ '../samplecode/Sample2PtRadial.cpp',
+ '../samplecode/SampleAAClip.cpp',
+ '../samplecode/SampleAAClip2.cpp',
+ '../samplecode/SampleAARects.cpp',
+ '../samplecode/SampleAARectModes.cpp',
+ '../samplecode/SampleAll.cpp',
+ '../samplecode/SampleAnimator.cpp',
+ '../samplecode/SampleApp.cpp',
+ '../samplecode/SampleArc.cpp',
+ '../samplecode/SampleAvoid.cpp',
+ '../samplecode/SampleBigBlur.cpp',
+ '../samplecode/SampleBigGradient.cpp',
+ '../samplecode/SampleBitmapRect.cpp',
+ '../samplecode/SampleBlur.cpp',
+ '../samplecode/SampleCamera.cpp',
+ '../samplecode/SampleCircle.cpp',
+ '../samplecode/SampleClip.cpp',
+ '../samplecode/SampleCode.h',
+ '../samplecode/SampleColorFilter.cpp',
+ '../samplecode/SampleComplexClip.cpp',
+ '../samplecode/SampleConcavePaths.cpp',
+ '../samplecode/SampleCull.cpp',
+ '../samplecode/SampleDecode.cpp',
+ '../samplecode/SampleDegenerateTwoPtRadials.cpp',
+ '../samplecode/SampleDither.cpp',
+ '../samplecode/SampleDitherBitmap.cpp',
+ '../samplecode/SampleDrawBitmap.cpp',
+ '../samplecode/SampleDrawLooper.cpp',
+ '../samplecode/SampleEffects.cpp',
+ '../samplecode/SampleEmboss.cpp',
+ '../samplecode/SampleEmptyPath.cpp',
+ '../samplecode/SampleEncode.cpp',
+ '../samplecode/SampleFillType.cpp',
+ '../samplecode/SampleFilter.cpp',
+ '../samplecode/SampleFilter2.cpp',
+ '../samplecode/SampleFontCache.cpp',
+ '../samplecode/SampleFontScalerTest.cpp',
+ '../samplecode/SampleFuzz.cpp',
+ '../samplecode/SampleGradients.cpp',
+ '../samplecode/SampleHairCurves.cpp',
+ '../samplecode/SampleHairline.cpp',
+ '../samplecode/SampleHairModes.cpp',
+ '../samplecode/SampleImage.cpp',
+ '../samplecode/SampleImageDir.cpp',
+ '../samplecode/SampleLayerMask.cpp',
+ '../samplecode/SampleLayers.cpp',
+ '../samplecode/SampleLCD.cpp',
+ '../samplecode/SampleLineClipper.cpp',
+ '../samplecode/SampleLines.cpp',
+ '../samplecode/SampleMeasure.cpp',
+ '../samplecode/SampleMipMap.cpp',
+ '../samplecode/SampleMovie.cpp',
+ '../samplecode/SampleNinePatch.cpp',
+ '../samplecode/SampleOvalTest.cpp',
+ '../samplecode/SampleOverflow.cpp',
+ '../samplecode/SamplePageFlip.cpp',
+ '../samplecode/SamplePatch.cpp',
+ '../samplecode/SamplePath.cpp',
+ '../samplecode/SamplePathClip.cpp',
+ '../samplecode/SamplePathEffects.cpp',
+ '../samplecode/SamplePicture.cpp',
+ '../samplecode/SamplePoints.cpp',
+ '../samplecode/SamplePolyToPoly.cpp',
+ '../samplecode/SampleRegion.cpp',
+ '../samplecode/SampleRepeatTile.cpp',
+ '../samplecode/SampleShaders.cpp',
+ '../samplecode/SampleShaderText.cpp',
+ '../samplecode/SampleShapes.cpp',
+ '../samplecode/SampleSkLayer.cpp',
+ '../samplecode/SampleSlides.cpp',
+ '../samplecode/SampleStrokePath.cpp',
+ '../samplecode/SampleStrokeText.cpp',
+ '../samplecode/SampleTests.cpp',
+ '../samplecode/SampleText.cpp',
+ '../samplecode/SampleTextAlpha.cpp',
+ '../samplecode/SampleTextBox.cpp',
+ '../samplecode/SampleTextEffects.cpp',
+ '../samplecode/SampleTextOnPath.cpp',
+ '../samplecode/SampleTextureDomain.cpp',
+ '../samplecode/SampleTiling.cpp',
+ '../samplecode/SampleTinyBitmap.cpp',
+ '../samplecode/SampleTriangles.cpp',
+ '../samplecode/SampleTypeface.cpp',
+ '../samplecode/SampleUnitMapper.cpp',
+ '../samplecode/SampleVertices.cpp',
+ '../samplecode/SampleXfermodes.cpp',
+ '../samplecode/SampleXfermodesBlur.cpp',
+ '../samplecode/TransitionView.cpp',
+
+ # Dependencies for the pipe code in SampleApp
+ '../src/pipe/SkGPipeRead.cpp',
+ '../src/pipe/SkGPipeWrite.cpp',
+
+ # DrawingBoard
+ #'../experimental/DrawingBoard/SkColorPalette.h',
+ #'../experimental/DrawingBoard/SkColorPalette.cpp',
+ #'../experimental/DrawingBoard/SkNetPipeController.h',
+ #'../experimental/DrawingBoard/SkNetPipeController.cpp',
+ #'../experimental/DrawingBoard/SampleDrawingClient.cpp',
+ #'../experimental/DrawingBoard/SampleDrawingServer.cpp',
+
+ # Networking
+ #'../experimental/Networking/SampleNetPipeReader.cpp',
+ #'../experimental/Networking/SkSockets.cpp',
+ #'../experimental/Networking/SkSockets.h',
+
+ # Debugger
+ '../experimental/Debugger/DebuggerViews.h',
+ '../experimental/Debugger/DebuggerContentView.cpp',
+ '../experimental/Debugger/DebuggerCommandsView.cpp',
+ '../experimental/Debugger/DebuggerStateView.cpp',
+ '../experimental/Debugger/SkDebugDumper.cpp',
+ '../experimental/Debugger/SkDebugDumper.h',
+ ],
+ 'sources!': [
+ '../samplecode/SampleSkLayer.cpp', #relies on SkMatrix44 which doesn't compile
+ '../samplecode/SampleTests.cpp', #includes unknown file SkShaderExtras.h
+ '../samplecode/SampleWarp.cpp',
+ '../samplecode/SampleFontCache.cpp',
+ ],
+ 'dependencies': [
+ 'core.gyp:core',
+ 'effects.gyp:effects',
+ 'images.gyp:images',
+ 'ports.gyp:ports',
+ 'views.gyp:views',
+ 'utils.gyp:utils',
+ 'animator.gyp:animator',
+ 'xml.gyp:xml',
+ 'svg.gyp:svg',
+ 'experimental.gyp:experimental',
+ 'gpu.gyp:gr',
+ 'gpu.gyp:skgr',
+ 'pdf.gyp:pdf',
+ ],
+ 'conditions' : [
+ [ 'skia_os in ["linux", "freebsd", "openbsd", "solaris"]', {
+ 'sources!': [
+ '../samplecode/SampleDecode.cpp',
+ ],
+ }],
+ [ 'skia_os == "win"', {
+ 'sources!': [
+ # require UNIX functions
+ '../samplecode/SampleEncode.cpp',
+ '../samplecode/SamplePageFlip.cpp',
+ ],
+ }],
+ [ 'skia_os == "mac"', {
+ 'sources!': [
+ '../samplecode/SampleDecode.cpp',
+ ],
+ 'sources': [
+ # Sample App specific files
+ '../src/utils/mac/SampleApp-Info.plist',
+ '../src/utils/mac/SampleAppDelegate.h',
+ '../src/utils/mac/SampleAppDelegate.mm',
+ '../src/utils/mac/SkSampleNSView.h',
+ '../src/utils/mac/SkSampleNSView.mm',
+
+ # Mac files
+ '../src/utils/mac/SkEventNotifier.h',
+ '../src/utils/mac/SkEventNotifier.mm',
+ '../src/utils/mac/skia_mac.mm',
+ '../src/utils/mac/SkNSView.h',
+ '../src/utils/mac/SkNSView.mm',
+ '../src/utils/mac/SkOptionsTableView.h',
+ '../src/utils/mac/SkOptionsTableView.mm',
+ '../src/utils/mac/SkOSWindow_Mac.mm',
+ '../src/utils/mac/SkTextFieldCell.h',
+ '../src/utils/mac/SkTextFieldCell.m',
+ ],
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework',
+ '$(SDKROOT)/System/Library/Frameworks/OpenGL.framework',
+ ],
+ 'xcode_settings' : {
+ 'INFOPLIST_FILE' : '../src/utils/mac/SampleApp-Info.plist',
+ },
+ 'mac_bundle_resources' : [
+ '../src/utils/mac/SampleApp.xib',
+ ],
+ }],
+ [ 'skia_os == "ios"', {
+ # TODO: This doesn't build properly yet, but it's getting there.
+ 'sources!': [
+ '../samplecode/SampleDecode.cpp',
+ ],
+ 'sources': [
+ '../experimental/iOSSampleApp/SkIOSNotifier.mm',
+ '../experimental/iOSSampleApp/SkTime_iOS.mm',
+ '../experimental/iOSSampleApp/SkUIDetailViewController.mm',
+ '../experimental/iOSSampleApp/SkUIRootViewController.mm',
+ '../experimental/iOSSampleApp/SkUIView_shell.mm',
+
+ '../experimental/iOSSampleApp/iOSSampleApp_Prefix.pch',
+ '../experimental/iOSSampleApp/Shared/main.m',
+ '../experimental/iOSSampleApp/iPad/AppDelegate_iPad.mm',
+ '../experimental/iOSSampleApp/iPad/SkUISplitViewController.mm',
+ '../experimental/iOSSampleApp/iPhone/AppDelegate_iPhone.mm',
+ '../experimental/iOSSampleApp/iPhone/SkUINavigationController.mm',
+
+ '../src/utils/ios/SkOSWindow_iOS.mm',
+ '../src/utils/ios/SkImageDecoder_iOS.mm',
+ '../src/utils/ios/SkStream_NSData.mm',
+ '../src/utils/ios/SkOSFile_iOS.mm',
+
+ '../src/utils/mac/SkCreateCGImageRef.cpp',
+ '../experimental/iOSSampleApp/SkiOSSampleApp-Debug.xcconfig',
+ '../experimental/iOSSampleApp/SkiOSSampleApp-Release.xcconfig',
+ ],
+ 'include_dirs' : [
+ '../experimental/iOSSampleApp',
+ '../experimental/iOSSampleApp/iPad',
+ '../experimental/iOSSampleApp/iPhone',
+ '../include/utils/ios',
+ '../../include/gpu',
+ ],
+ 'xcode_config_file': '../experimental/iOSSampleApp/SkiOSSampleApp-Base.xcconfig',
+ 'mac_bundle_resources' : [
+ '../experimental/iOSSampleApp/iPad/MainWindow_iPad.xib',
+ '../experimental/iOSSampleApp/iPhone/MainWindow_iPhone.xib',
+ ],
+ }],
+ [ 'skia_os == "android"', {
+ 'sources!': [
+ '../samplecode/SampleAnimator.cpp',
+ '../samplecode/SampleUnitMapper.cpp',
+ ],
+ 'dependencies!': [
+ 'animator.gyp:animator',
+ 'experimental.gyp:experimental',
+ ],
+ 'dependencies': [
+ 'android_system.gyp:sampleApp',
+ ],
+ }],
+ ],
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'SubSystem': '2',
+ 'AdditionalDependencies': [
+ 'd3d9.lib',
+ ],
+ },
+ },
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/SimpleCocoaApp.gyp b/gyp/SimpleCocoaApp.gyp
new file mode 100644
index 0000000..ed35d54
--- /dev/null
+++ b/gyp/SimpleCocoaApp.gyp
@@ -0,0 +1,65 @@
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'SimpleCocoaApp',
+ 'type': 'executable',
+ 'mac_bundle' : 1,
+ 'include_dirs' : [
+ '../experimental/SimpleCocoaApp/',
+ ],
+ 'sources': [
+ '../src/utils/mac/SkEventNotifier.h',
+ '../src/utils/mac/SkEventNotifier.mm',
+ '../src/utils/mac/skia_mac.mm',
+ '../src/utils/mac/SkNSView.h',
+ '../src/utils/mac/SkNSView.mm',
+ '../src/utils/mac/SkOptionsTableView.h',
+ '../src/utils/mac/SkOptionsTableView.mm',
+ '../src/utils/mac/SkOSWindow_Mac.mm',
+ '../src/utils/mac/SkTextFieldCell.h',
+ '../src/utils/mac/SkTextFieldCell.m',
+
+ '../experimental/SimpleCocoaApp/SimpleApp-Info.plist',
+ '../experimental/SimpleCocoaApp/SimpleApp.h',
+ '../experimental/SimpleCocoaApp/SimpleApp.mm',
+
+ ],
+ 'dependencies': [
+ 'core.gyp:core',
+ 'opts.gyp:opts',
+ 'utils.gyp:utils',
+ 'views.gyp:views',
+ 'xml.gyp:xml',
+ ],
+ 'conditions' : [
+ # Only supports Mac currently
+ [ 'skia_os == "mac"', {
+ 'sources': [
+ '../include/utils/mac/SkCGUtils.h',
+ '../src/utils/mac/SkCreateCGImageRef.cpp',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/OpenGL.framework',
+ ],
+ },
+ 'xcode_settings' : {
+ 'INFOPLIST_FILE' : '../experimental/SimpleCocoaApp/SimpleApp-Info.plist',
+ },
+ 'mac_bundle_resources' : [
+ '../experimental/SimpleCocoaApp/SimpleApp.xib',
+ ],
+ }],
+ ],
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/all.gyp b/gyp/all.gyp
new file mode 100644
index 0000000..37844bb
--- /dev/null
+++ b/gyp/all.gyp
@@ -0,0 +1,41 @@
+# Creates a Makefile that is capable of building all executable targets.
+#
+# To build on Linux:
+# ./gyp_skia && make all
+#
+# Building on other platforms not tested yet.
+#
+
+#
+#
+#
+#
+#
+# THIS IS DEPRECATED IN FAVOR OF trunk/skia.gyp !!!
+# Questions? Contact epoger@google.com
+#
+#
+#
+#
+
+{
+ 'targets': [
+ {
+ 'target_name': 'all',
+ 'type': 'none',
+ 'dependencies': [
+ 'bench.gyp:bench',
+ 'gm.gyp:gm',
+ 'SampleApp.gyp:SampleApp',
+ 'tests.gyp:tests',
+ 'tools.gyp:tools',
+ ],
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/android_system.gyp b/gyp/android_system.gyp
new file mode 100644
index 0000000..27a82f3
--- /dev/null
+++ b/gyp/android_system.gyp
@@ -0,0 +1,21 @@
+# This GYP file stores the dependencies necessary to build Skia on the Android
+# platform. The OS doesn't provide many stable libraries as part of the
+# distribution so we have to build a few of them ourselves.
+#
+# We tried adding this gyp file to the android directory at the root of
+# the Skia repo, but that resulted in the generated makefiles being created
+# outside of the intended output directory. So to avoid this we created a simple
+# shim here that includes the android_system.gypi file. The actual dependencies
+# are defined and maintained in that gypi file.
+#
+# Also this assumes that the android directory is a sibling to the directory
+# that contains your primary Skia checkout. If it is not then you must manually
+# edit the includes below to specify the actual location of the android.gypi.
+# This is due to the fact that we cannot use variables in an includes as the
+# variable expansion step for gyp happens after the includes are processed.
+{
+ 'includes': [
+ 'common.gypi',
+ '../../android/gyp/android.gypi',
+ ],
+} \ No newline at end of file
diff --git a/gyp/animator.gyp b/gyp/animator.gyp
new file mode 100644
index 0000000..fc61e71
--- /dev/null
+++ b/gyp/animator.gyp
@@ -0,0 +1,193 @@
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'animator',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../include/config',
+ '../include/core',
+ '../include/effects',
+ '../include/animator',
+ '../include/views',
+ '../include/xml',
+ '../include/utils',
+ '../include/images',
+ ],
+ 'sources': [
+ '../include/animator/SkAnimator.h',
+ '../include/animator/SkAnimatorView.h',
+
+ '../src/animator/SkAnimate.h',
+ '../src/animator/SkAnimateActive.cpp',
+ '../src/animator/SkAnimateActive.h',
+ '../src/animator/SkAnimateBase.cpp',
+ '../src/animator/SkAnimateBase.h',
+ '../src/animator/SkAnimateField.cpp',
+ '../src/animator/SkAnimateMaker.cpp',
+ '../src/animator/SkAnimateMaker.h',
+ '../src/animator/SkAnimateProperties.h',
+ '../src/animator/SkAnimateSet.cpp',
+ '../src/animator/SkAnimateSet.h',
+ '../src/animator/SkAnimator.cpp',
+ '../src/animator/SkAnimatorScript.cpp',
+ '../src/animator/SkAnimatorScript.h',
+ #'../src/animator/SkAnimatorScript2.cpp', fails on windows
+ #'../src/animator/SkAnimatorScript2.h',
+ '../src/animator/SkBase64.cpp',
+ '../src/animator/SkBase64.h',
+ '../src/animator/SkBoundable.cpp',
+ '../src/animator/SkBoundable.h',
+ '../src/animator/SkBuildCondensedInfo.cpp',
+ #'../src/animator/SkCondensedDebug.cpp', fails on windows
+ #'../src/animator/SkCondensedRelease.cpp',
+ '../src/animator/SkDisplayable.cpp',
+ '../src/animator/SkDisplayable.h',
+ '../src/animator/SkDisplayAdd.cpp',
+ '../src/animator/SkDisplayAdd.h',
+ '../src/animator/SkDisplayApply.cpp',
+ '../src/animator/SkDisplayApply.h',
+ '../src/animator/SkDisplayBounds.cpp',
+ '../src/animator/SkDisplayBounds.h',
+ '../src/animator/SkDisplayEvent.cpp',
+ '../src/animator/SkDisplayEvent.h',
+ '../src/animator/SkDisplayEvents.cpp',
+ '../src/animator/SkDisplayEvents.h',
+ '../src/animator/SkDisplayInclude.cpp',
+ '../src/animator/SkDisplayInclude.h',
+ '../src/animator/SkDisplayInput.cpp',
+ '../src/animator/SkDisplayInput.h',
+ '../src/animator/SkDisplayList.cpp',
+ '../src/animator/SkDisplayList.h',
+ '../src/animator/SkDisplayMath.cpp',
+ '../src/animator/SkDisplayMath.h',
+ '../src/animator/SkDisplayMovie.cpp',
+ '../src/animator/SkDisplayMovie.h',
+ '../src/animator/SkDisplayNumber.cpp',
+ '../src/animator/SkDisplayNumber.h',
+ '../src/animator/SkDisplayPost.cpp',
+ '../src/animator/SkDisplayPost.h',
+ '../src/animator/SkDisplayRandom.cpp',
+ '../src/animator/SkDisplayRandom.h',
+ '../src/animator/SkDisplayScreenplay.cpp',
+ '../src/animator/SkDisplayScreenplay.h',
+ '../src/animator/SkDisplayType.cpp',
+ '../src/animator/SkDisplayType.h',
+ '../src/animator/SkDisplayTypes.cpp',
+ '../src/animator/SkDisplayTypes.h',
+ '../src/animator/SkDisplayXMLParser.cpp',
+ '../src/animator/SkDisplayXMLParser.h',
+ '../src/animator/SkDraw3D.cpp',
+ '../src/animator/SkDraw3D.h',
+ '../src/animator/SkDrawable.cpp',
+ '../src/animator/SkDrawable.h',
+ '../src/animator/SkDrawBitmap.cpp',
+ '../src/animator/SkDrawBitmap.h',
+ '../src/animator/SkDrawBlur.cpp',
+ '../src/animator/SkDrawBlur.h',
+ '../src/animator/SkDrawClip.cpp',
+ '../src/animator/SkDrawClip.h',
+ '../src/animator/SkDrawColor.cpp',
+ '../src/animator/SkDrawColor.h',
+ '../src/animator/SkDrawDash.cpp',
+ '../src/animator/SkDrawDash.h',
+ '../src/animator/SkDrawDiscrete.cpp',
+ '../src/animator/SkDrawDiscrete.h',
+ '../src/animator/SkDrawEmboss.cpp',
+ '../src/animator/SkDrawEmboss.h',
+ '../src/animator/SkDrawExtraPathEffect.cpp',
+ '../src/animator/SkDrawFull.cpp',
+ '../src/animator/SkDrawFull.h',
+ '../src/animator/SkDrawGradient.cpp',
+ '../src/animator/SkDrawGradient.h',
+ '../src/animator/SkDrawGroup.cpp',
+ '../src/animator/SkDrawGroup.h',
+ '../src/animator/SkDrawLine.cpp',
+ '../src/animator/SkDrawLine.h',
+ '../src/animator/SkDrawMatrix.cpp',
+ '../src/animator/SkDrawMatrix.h',
+ '../src/animator/SkDrawOval.cpp',
+ '../src/animator/SkDrawOval.h',
+ '../src/animator/SkDrawPaint.cpp',
+ '../src/animator/SkDrawPaint.h',
+ '../src/animator/SkDrawPath.cpp',
+ '../src/animator/SkDrawPath.h',
+ '../src/animator/SkDrawPoint.cpp',
+ '../src/animator/SkDrawPoint.h',
+ '../src/animator/SkDrawRectangle.cpp',
+ '../src/animator/SkDrawRectangle.h',
+ '../src/animator/SkDrawSaveLayer.cpp',
+ '../src/animator/SkDrawSaveLayer.h',
+ '../src/animator/SkDrawShader.cpp',
+ '../src/animator/SkDrawShader.h',
+ '../src/animator/SkDrawText.cpp',
+ '../src/animator/SkDrawText.h',
+ '../src/animator/SkDrawTextBox.cpp',
+ '../src/animator/SkDrawTextBox.h',
+ '../src/animator/SkDrawTo.cpp',
+ '../src/animator/SkDrawTo.h',
+ '../src/animator/SkDrawTransparentShader.cpp',
+ '../src/animator/SkDrawTransparentShader.h',
+ '../src/animator/SkDump.cpp',
+ '../src/animator/SkDump.h',
+ '../src/animator/SkExtras.h',
+ '../src/animator/SkGetCondensedInfo.cpp',
+ '../src/animator/SkHitClear.cpp',
+ '../src/animator/SkHitClear.h',
+ '../src/animator/SkHitTest.cpp',
+ '../src/animator/SkHitTest.h',
+ '../src/animator/SkIntArray.h',
+ '../src/animator/SkMatrixParts.cpp',
+ '../src/animator/SkMatrixParts.h',
+ '../src/animator/SkMemberInfo.cpp',
+ '../src/animator/SkMemberInfo.h',
+ '../src/animator/SkOpArray.cpp',
+ '../src/animator/SkOpArray.h',
+ '../src/animator/SkOperand.h',
+ '../src/animator/SkOperand2.h',
+ '../src/animator/SkOperandInterpolator.h',
+ '../src/animator/SkOperandIterpolator.cpp',
+ '../src/animator/SkPaintParts.cpp',
+ '../src/animator/SkPaintParts.h',
+ '../src/animator/SkParseSVGPath.cpp',
+ '../src/animator/SkPathParts.cpp',
+ '../src/animator/SkPathParts.h',
+ '../src/animator/SkPostParts.cpp',
+ '../src/animator/SkPostParts.h',
+ '../src/animator/SkScript.cpp',
+ '../src/animator/SkScript.h',
+ '../src/animator/SkScript2.h',
+ '../src/animator/SkScriptCallBack.h',
+ '../src/animator/SkScriptDecompile.cpp',
+ '../src/animator/SkScriptRuntime.cpp',
+ '../src/animator/SkScriptRuntime.h',
+ '../src/animator/SkScriptTokenizer.cpp',
+ '../src/animator/SkSnapshot.cpp',
+ '../src/animator/SkSnapshot.h',
+ '../src/animator/SkTDArray_Experimental.h',
+ '../src/animator/SkTextOnPath.cpp',
+ '../src/animator/SkTextOnPath.h',
+ '../src/animator/SkTextToPath.cpp',
+ '../src/animator/SkTextToPath.h',
+ '../src/animator/SkTime.cpp',
+ '../src/animator/SkTypedArray.cpp',
+ '../src/animator/SkTypedArray.h',
+ '../src/animator/SkXMLAnimatorWriter.cpp',
+ '../src/animator/SkXMLAnimatorWriter.h',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../include/animator',
+ ],
+ },
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/apptype_console.gypi b/gyp/apptype_console.gypi
new file mode 100644
index 0000000..f2f6e1c
--- /dev/null
+++ b/gyp/apptype_console.gypi
@@ -0,0 +1,21 @@
+# target_defaults used for executable targets that generate a console app
+{
+ 'target_defaults': {
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ #Allows for creation / output to console.
+ #Console (/SUBSYSTEM:CONSOLE)
+ 'SubSystem': '1',
+
+ #Console app, use main/wmain
+ 'EntryPointSymbol': 'mainCRTStartup',
+ },
+ },
+ },
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/bench.gyp b/gyp/bench.gyp
new file mode 100644
index 0000000..0c5e2ea
--- /dev/null
+++ b/gyp/bench.gyp
@@ -0,0 +1,36 @@
+# GYP file to build performance testbench.
+#
+{
+ 'includes': [
+ 'apptype_console.gypi',
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'bench',
+ 'type': 'executable',
+ 'include_dirs' : [
+ '../src/core',
+ '../src/gpu',
+ ],
+ 'includes': [
+ 'bench.gypi'
+ ],
+ 'dependencies': [
+ 'core.gyp:core',
+ 'effects.gyp:effects',
+ 'gpu.gyp:gr',
+ 'gpu.gyp:skgr',
+ 'images.gyp:images',
+ 'ports.gyp:ports',
+ 'utils.gyp:utils',
+ ],
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/bench.gypi b/gyp/bench.gypi
new file mode 100644
index 0000000..5fbfef7
--- /dev/null
+++ b/gyp/bench.gypi
@@ -0,0 +1,71 @@
+# sources and conditions used in skia's bench.gyp and chromium's skia.gyp
+#
+{
+ 'sources': [
+ '../bench/benchmain.cpp',
+ '../bench/BenchTimer.h',
+ '../bench/BenchTimer.cpp',
+ '../bench/BenchSysTimer_mach.h',
+ '../bench/BenchSysTimer_mach.cpp',
+ '../bench/BenchSysTimer_posix.h',
+ '../bench/BenchSysTimer_posix.cpp',
+ '../bench/BenchSysTimer_windows.h',
+ '../bench/BenchSysTimer_windows.cpp',
+ '../bench/BenchGpuTimer_gl.h',
+ '../bench/BenchGpuTimer_gl.cpp',
+
+ '../bench/SkBenchmark.h',
+ '../bench/SkBenchmark.cpp',
+
+ '../bench/AAClipBench.cpp',
+ '../bench/BitmapBench.cpp',
+ '../bench/BlurBench.cpp',
+ '../bench/ChromeBench.cpp',
+ '../bench/DecodeBench.cpp',
+ '../bench/FontScalerBench.cpp',
+ '../bench/GradientBench.cpp',
+ '../bench/MathBench.cpp',
+ '../bench/MatrixBench.cpp',
+ '../bench/MutexBench.cpp',
+ '../bench/PathBench.cpp',
+ '../bench/RectBench.cpp',
+ '../bench/RepeatTileBench.cpp',
+ '../bench/ScalarBench.cpp',
+ '../bench/ShaderMaskBench.cpp',
+ '../bench/TextBench.cpp',
+ '../bench/VertBench.cpp',
+ ],
+ 'conditions': [
+ [ 'skia_os != "mac"', {
+ 'sources!': [
+ '../bench/BenchSysTimer_mach.h',
+ '../bench/BenchSysTimer_mach.cpp',
+ ],
+ }],
+ [ 'skia_os not in ["linux", "freebsd", "openbsd", "solaris", "android"]', {
+ 'sources!': [
+ '../bench/BenchSysTimer_posix.h',
+ '../bench/BenchSysTimer_posix.cpp',
+ ],
+ }],
+ [ 'skia_os in ["linux", "freebsd", "openbsd", "solaris"]', {
+ 'link_settings': {
+ 'libraries': [
+ '-lrt',
+ ],
+ },
+ }],
+ [ 'skia_os != "win"', {
+ 'sources!': [
+ '../bench/BenchSysTimer_windows.h',
+ '../bench/BenchSysTimer_windows.cpp',
+ ],
+ }],
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/common.gypi b/gyp/common.gypi
new file mode 100644
index 0000000..30424de
--- /dev/null
+++ b/gyp/common.gypi
@@ -0,0 +1,70 @@
+# Copyright 2011 The Android Open Source Project
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+ 'includes': [
+ 'common_variables.gypi',
+ ],
+ 'target_defaults': {
+
+ # Validate the 'skia_os' setting against 'OS', because only certain
+ # combinations work. You should only override 'skia_os' for certain
+ # situations, like building for iOS on a Mac.
+ 'variables': {
+ 'conditions': [
+ ['skia_os != OS and not (skia_os == "ios" and OS == "mac")',
+ {'error': '<!(Cannot build with skia_os=<(skia_os) on OS=<(OS))'}],
+ ['skia_mesa and skia_os not in ["mac", "linux"]',
+ {'error': '<!(skia_mesa=1 only supported with skia_os="mac" or "linux".)'}],
+ ],
+ },
+ 'includes': [
+ 'common_conditions.gypi'
+ ],
+ 'conditions': [
+ [ 'skia_scalar == "float"',
+ {
+ 'defines': [
+ 'SK_SCALAR_IS_FLOAT',
+ 'SK_CAN_USE_FLOAT',
+ ],
+ }, { # else, skia_scalar != "float"
+ 'defines': [
+ 'SK_SCALAR_IS_FIXED',
+ 'SK_CAN_USE_FLOAT', # we can still use floats along the way
+ ],
+ }
+ ],
+ [ 'skia_mesa', {
+ 'defines': [
+ 'SK_MESA',
+ ],
+ 'direct_dependent_settings': {
+ 'defines': [
+ 'SK_MESA',
+ ],
+ },
+ }],
+ ],
+ 'configurations': {
+ 'Debug': {
+ 'defines': [
+ 'SK_DEBUG',
+ 'GR_DEBUG=1',
+ ],
+ },
+ 'Release': {
+ 'defines': [
+ 'SK_RELEASE',
+ 'GR_RELEASE=1',
+ ],
+ },
+ },
+ }, # end 'target_defaults'
+}
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/common_conditions.gypi b/gyp/common_conditions.gypi
new file mode 100644
index 0000000..e18cbc1
--- /dev/null
+++ b/gyp/common_conditions.gypi
@@ -0,0 +1,212 @@
+# conditions used in both common.gypi and skia.gyp in chromium
+#
+{
+ 'conditions' : [
+
+ ['skia_os == "win"',
+ {
+ 'defines': [
+ 'SK_BUILD_FOR_WIN32',
+ 'SK_IGNORE_STDINT_DOT_H',
+ '_CRT_SECURE_NO_WARNINGS',
+ ],
+ 'msvs_cygwin_shell': 0,
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'WarningLevel': '1',
+ 'WarnAsError': 'false',
+ 'DebugInformationFormat': '3',
+ 'AdditionalOptions': [ '/MP' ],
+ },
+ 'VCLinkerTool': {
+ 'AdditionalDependencies': [
+ 'OpenGL32.lib',
+ 'usp10.lib',
+ ],
+ },
+ },
+ 'configurations': {
+ 'Debug': {
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'DebugInformationFormat': '4', # editAndContiue (/ZI)
+ 'ProgramDataBaseFileName': '$(OutDir)\\$(ProjectName).pdb',
+ 'Optimization': '0', # optimizeDisabled (/Od)
+ 'PreprocessorDefinitions': ['_DEBUG'],
+ 'RuntimeLibrary': '3', # rtMultiThreadedDebugDLL (/MDd)
+ 'ExceptionHandling': '0',
+ 'RuntimeTypeInfo': 'false', # /GR-
+ 'WarningLevel': '3', # level3 (/W3)
+ },
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true', # /DEBUG
+ 'LinkIncremental': '2', # /INCREMENTAL
+ },
+ },
+ },
+ 'Release': {
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'DebugInformationFormat': '3', # programDatabase (/Zi)
+ 'ProgramDataBaseFileName': '$(OutDir)\\$(ProjectName).pdb',
+ 'Optimization': '3', # full (/Ox)
+ 'WholeProgramOptimization': 'true', #/GL
+ # Changing the floating point model requires rebaseling gm images
+ #'FloatingPointModel': '2', # fast (/fp:fast)
+ 'FavorSizeOrSpeed': '1', # speed (/Ot)
+ 'PreprocessorDefinitions': ['NDEBUG'],
+ 'RuntimeLibrary': '2', # rtMultiThreadedDLL (/MD)
+ 'ExceptionHandling': '0',
+ 'RuntimeTypeInfo': 'false', # /GR-
+ 'WarningLevel': '3', # level3 (/W3)
+ },
+ 'VCLinkerTool': {
+ 'GenerateDebugInformation': 'true', # /DEBUG
+ 'LinkTimeCodeGeneration': '1', # useLinkTimeCodeGeneration /LTCG
+ },
+ 'VCLibrarianTool': {
+ 'LinkTimeCodeGeneration': 'true', # useLinkTimeCodeGeneration /LTCG
+ },
+ },
+ },
+ },
+ },
+ ],
+
+ ['skia_os in ["linux", "freebsd", "openbsd", "solaris"]',
+ {
+ 'defines': [
+ 'SK_SAMPLES_FOR_X',
+ 'SK_BUILD_FOR_UNIX',
+ ],
+ 'configurations': {
+ 'Debug': {
+ 'cflags': ['-g']
+ },
+ 'Release': {
+ 'cflags': ['-O2']
+ },
+ },
+ 'cflags': [
+ # TODO(tony): Enable -Werror once all the strict-aliasing problems
+ # are fixed.
+ #'-Werror',
+ '-Wall',
+ '-Wextra',
+ '-Wno-unused',
+ # suppressions below here were added for clang
+ '-Wno-unused-parameter',
+ '-Wno-c++11-extensions'
+ ],
+ 'include_dirs' : [
+ '/usr/include/freetype2',
+ ],
+ },
+ ],
+
+ ['skia_os == "mac"',
+ {
+ 'defines': [
+ 'SK_BUILD_FOR_MAC',
+ ],
+ 'configurations': {
+ 'Debug': {
+ 'xcode_settings': {
+ 'GCC_OPTIMIZATION_LEVEL': '0',
+ },
+ },
+ 'Release': {
+ 'xcode_settings': {
+ 'GCC_OPTIMIZATION_LEVEL': '3',
+ },
+ },
+ },
+ 'xcode_settings': {
+ 'SYMROOT': '<(DEPTH)/xcodebuild',
+ 'SDKROOT': 'macosx10.6',
+# trying to get this to work, but it needs clang I think...
+# 'WARNING_CFLAGS': '-Wexit-time-destructors',
+ 'CLANG_WARN_CXX0X_EXTENSIONS': 'NO',
+ },
+ },
+ ],
+
+ ['skia_os == "ios"',
+ {
+ 'defines': [
+ 'SK_BUILD_FOR_IOS',
+ ],
+ 'configurations': {
+ 'Debug': {
+ 'xcode_settings': {
+ 'GCC_OPTIMIZATION_LEVEL': '0',
+ },
+ },
+ },
+ 'xcode_settings': {
+ 'SYMROOT': '<(DEPTH)/xcodebuild',
+ },
+ },
+ ],
+
+ ['skia_os == "android"',
+ {
+ 'defines': [
+ 'SK_BUILD_FOR_ANDROID',
+ 'SK_BUILD_FOR_ANDROID_NDK',
+ 'SK_ALLOW_STATIC_GLOBAL_INITIALIZERS=0',
+ ],
+ 'configurations': {
+ 'Debug': {
+ 'cflags': ['-g']
+ },
+ 'Release': {
+ 'cflags': ['-O2']
+ },
+ },
+ 'libraries': [
+ '-lstdc++',
+ '-lm',
+ '-llog',
+ ],
+ 'cflags': [
+ '-fno-exceptions',
+ '-fno-rtti',
+ ],
+ 'conditions': [
+ [ 'skia_target_arch == "arm" and arm_thumb == 1', {
+ 'cflags': [
+ '-mthumb',
+ ],
+ }],
+ [ 'skia_target_arch == "arm" and armv7 == 1', {
+ 'defines': [
+ '__ARM_ARCH__=7',
+ ],
+ 'cflags': [
+ '-march=armv7-a',
+ ],
+ 'conditions': [
+ [ 'arm_neon == 1', {
+ 'defines': [
+ '__ARM_HAVE_NEON',
+ ],
+ 'cflags': [
+ '-mfloat-abi=softfp',
+ '-mfpu=neon',
+ ],
+ }],
+ ],
+ }],
+ ],
+ },
+ ],
+
+ ], # end 'conditions'
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/common_variables.gypi b/gyp/common_variables.gypi
new file mode 100644
index 0000000..94e2b9b
--- /dev/null
+++ b/gyp/common_variables.gypi
@@ -0,0 +1,25 @@
+# variables used in both common.gypi and skia.gyp in chromium
+#
+{
+ # Define all variables, allowing for override in GYP_DEFINES.
+ #
+ # One such variable is 'skia_os', which we use instead of 'OS' throughout
+ # our gyp files. We set it automatically based on 'OS', but allow the
+ # user to override it via GYP_DEFINES if they like.
+ 'variables': {
+ 'skia_scalar%': 'float',
+ 'skia_os%': '<(OS)',
+ 'skia_mesa%': 0,
+ 'skia_target_arch%': '',
+ },
+ 'skia_scalar%': '<(skia_scalar)',
+ 'skia_os': '<(skia_os)',
+ 'skia_mesa': '<(skia_mesa)',
+ 'skia_target_arch': '<(skia_target_arch)',
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/core.gyp b/gyp/core.gyp
new file mode 100644
index 0000000..f83f482
--- /dev/null
+++ b/gyp/core.gyp
@@ -0,0 +1,327 @@
+# Core Skia library code.
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'core',
+ 'type': 'static_library',
+ 'msvs_guid': 'B7760B5E-BFA8-486B-ACFD-49E3A6DE8E76',
+ 'sources': [
+ '../src/core/ARGB32_Clamp_Bilinear_BitmapShader.h',
+ '../src/core/Sk64.cpp',
+ '../src/core/SkAAClip.cpp',
+ '../src/core/SkAdvancedTypefaceMetrics.cpp',
+ '../src/core/SkAlphaRuns.cpp',
+ '../src/core/SkAntiRun.h',
+ '../src/core/SkBitmap.cpp',
+ '../src/core/SkBitmapProcShader.cpp',
+ '../src/core/SkBitmapProcShader.h',
+ '../src/core/SkBitmapProcState.cpp',
+ '../src/core/SkBitmapProcState.h',
+ '../src/core/SkBitmapProcState_matrix.h',
+ '../src/core/SkBitmapProcState_matrixProcs.cpp',
+ '../src/core/SkBitmapProcState_sample.h',
+ '../src/core/SkBitmapSampler.cpp',
+ '../src/core/SkBitmapSampler.h',
+ '../src/core/SkBitmapSamplerTemplate.h',
+ '../src/core/SkBitmapShader16BilerpTemplate.h',
+ '../src/core/SkBitmapShaderTemplate.h',
+ '../src/core/SkBitmap_scroll.cpp',
+ '../src/core/SkBlitBWMaskTemplate.h',
+ '../src/core/SkBlitMask_D32.cpp',
+ '../src/core/SkBlitRow_D16.cpp',
+ '../src/core/SkBlitRow_D32.cpp',
+ '../src/core/SkBlitRow_D4444.cpp',
+ '../src/core/SkBlitter.cpp',
+ '../src/core/SkBlitter_4444.cpp',
+ '../src/core/SkBlitter_A1.cpp',
+ '../src/core/SkBlitter_A8.cpp',
+ '../src/core/SkBlitter_ARGB32.cpp',
+ '../src/core/SkBlitter_RGB16.cpp',
+ '../src/core/SkBlitter_Sprite.cpp',
+ '../src/core/SkBuffer.cpp',
+ '../src/core/SkCanvas.cpp',
+ '../src/core/SkChunkAlloc.cpp',
+ '../src/core/SkClampRange.cpp',
+ '../src/core/SkClipStack.cpp',
+ '../src/core/SkColor.cpp',
+ '../src/core/SkColorFilter.cpp',
+ '../src/core/SkColorTable.cpp',
+ '../src/core/SkComposeShader.cpp',
+ '../src/core/SkConcaveToTriangles.cpp',
+ '../src/core/SkConcaveToTriangles.h',
+ '../src/core/SkConfig8888.h',
+ '../src/core/SkCordic.cpp',
+ '../src/core/SkCordic.h',
+ '../src/core/SkCoreBlitters.h',
+ '../src/core/SkCubicClipper.cpp',
+ '../src/core/SkCubicClipper.h',
+ '../src/core/SkData.cpp',
+ '../src/core/SkDebug.cpp',
+ '../src/core/SkDeque.cpp',
+ '../src/core/SkDevice.cpp',
+ '../src/core/SkDither.cpp',
+ '../src/core/SkDraw.cpp',
+ '../src/core/SkDrawProcs.h',
+ '../src/core/SkEdgeBuilder.cpp',
+ '../src/core/SkEdgeClipper.cpp',
+ '../src/core/SkEdge.cpp',
+ '../src/core/SkEdge.h',
+ '../src/core/SkFP.h',
+ '../src/core/SkFilterProc.cpp',
+ '../src/core/SkFilterProc.h',
+ '../src/core/SkFlattenable.cpp',
+ '../src/core/SkFloat.cpp',
+ '../src/core/SkFloat.h',
+ '../src/core/SkFloatBits.cpp',
+ '../src/core/SkFontHost.cpp',
+ '../src/core/SkGeometry.cpp',
+ '../src/core/SkGlyphCache.cpp',
+ '../src/core/SkGlyphCache.h',
+ '../src/core/SkGraphics.cpp',
+ '../src/core/SkLineClipper.cpp',
+ '../src/core/SkMallocPixelRef.cpp',
+ '../src/core/SkMask.cpp',
+ '../src/core/SkMaskFilter.cpp',
+ '../src/core/SkMath.cpp',
+ '../src/core/SkMatrix.cpp',
+ '../src/core/SkMetaData.cpp',
+ '../src/core/SkMMapStream.cpp',
+ '../src/core/SkPackBits.cpp',
+ '../src/core/SkPaint.cpp',
+ '../src/core/SkPath.cpp',
+ '../src/core/SkPathEffect.cpp',
+ '../src/core/SkPathHeap.cpp',
+ '../src/core/SkPathHeap.h',
+ '../src/core/SkPathMeasure.cpp',
+ '../src/core/SkPicture.cpp',
+ '../src/core/SkPictureFlat.cpp',
+ '../src/core/SkPictureFlat.h',
+ '../src/core/SkPicturePlayback.cpp',
+ '../src/core/SkPicturePlayback.h',
+ '../src/core/SkPictureRecord.cpp',
+ '../src/core/SkPictureRecord.h',
+ '../src/core/SkPixelRef.cpp',
+ '../src/core/SkPoint.cpp',
+ '../src/core/SkProcSpriteBlitter.cpp',
+ '../src/core/SkPtrRecorder.cpp',
+ '../src/core/SkQuadClipper.cpp',
+ '../src/core/SkQuadClipper.h',
+ '../src/core/SkRasterClip.cpp',
+ '../src/core/SkRasterizer.cpp',
+ '../src/core/SkRect.cpp',
+ '../src/core/SkRefDict.cpp',
+ '../src/core/SkRegion.cpp',
+ '../src/core/SkRegionPriv.h',
+ '../src/core/SkRegion_path.cpp',
+ '../src/core/SkScalar.cpp',
+ '../src/core/SkScalerContext.cpp',
+ '../src/core/SkScan.cpp',
+ '../src/core/SkScanPriv.h',
+ '../src/core/SkScan_AntiPath.cpp',
+ '../src/core/SkScan_Antihair.cpp',
+ '../src/core/SkScan_Hairline.cpp',
+ '../src/core/SkScan_Path.cpp',
+ '../src/core/SkShader.cpp',
+ '../src/core/SkShape.cpp',
+ '../src/core/SkSpriteBlitter_ARGB32.cpp',
+ '../src/core/SkSpriteBlitter_RGB16.cpp',
+ '../src/core/SkSinTable.h',
+ '../src/core/SkSpriteBlitter.h',
+ '../src/core/SkSpriteBlitterTemplate.h',
+ '../src/core/SkStream.cpp',
+ '../src/core/SkString.cpp',
+ '../src/core/SkStroke.cpp',
+ '../src/core/SkStrokerPriv.cpp',
+ '../src/core/SkStrokerPriv.h',
+ '../src/core/SkTextFormatParams.h',
+ '../src/core/SkTSearch.cpp',
+ '../src/core/SkTSort.h',
+ '../src/core/SkTemplatesPriv.h',
+ '../src/core/SkTypeface.cpp',
+ '../src/core/SkTypefaceCache.cpp',
+ '../src/core/SkTypefaceCache.h',
+ '../src/core/SkUnPreMultiply.cpp',
+ '../src/core/SkUtils.cpp',
+ '../src/core/SkWriter32.cpp',
+ '../src/core/SkXfermode.cpp',
+
+ '../include/core/Sk64.h',
+ '../include/core/SkAdvancedTypefaceMetrics.h',
+ '../include/core/SkAutoKern.h',
+ '../include/core/SkBitmap.h',
+ '../include/core/SkBlitRow.h',
+ '../include/core/SkBlitter.h',
+ '../include/core/SkBounder.h',
+ '../include/core/SkBuffer.h',
+ '../include/core/SkCanvas.h',
+ '../include/core/SkChunkAlloc.h',
+ '../include/core/SkClampRange.h',
+ '../include/core/SkClipStack.h',
+ '../include/core/SkColor.h',
+ '../include/core/SkColorFilter.h',
+ '../include/core/SkColorPriv.h',
+ '../include/core/SkColorShader.h',
+ '../include/core/SkComposeShader.h',
+ '../include/core/SkData.h',
+ '../include/core/SkDeque.h',
+ '../include/core/SkDescriptor.h',
+ '../include/core/SkDevice.h',
+ '../include/core/SkDither.h',
+ '../include/core/SkDraw.h',
+ '../include/core/SkDrawFilter.h',
+ '../include/core/SkDrawLooper.h',
+ '../include/core/SkEndian.h',
+ '../include/core/SkFDot6.h',
+ '../include/core/SkFixed.h',
+ '../include/core/SkFlattenable.h',
+ '../include/core/SkFloatBits.h',
+ '../include/core/SkFloatingPoint.h',
+ '../include/core/SkFontHost.h',
+ '../include/core/SkGeometry.h',
+ '../include/core/SkGraphics.h',
+ '../include/core/SkMallocPixelRef.h',
+ '../include/core/SkMask.h',
+ '../include/core/SkMaskFilter.h',
+ '../include/core/SkMath.h',
+ '../include/core/SkMatrix.h',
+ '../include/core/SkMetaData.h',
+ '../include/core/SkMMapStream.h',
+ '../include/core/SkOSFile.h',
+ '../include/core/SkPackBits.h',
+ '../include/core/SkPaint.h',
+ '../include/core/SkPath.h',
+ '../include/core/SkPathEffect.h',
+ '../include/core/SkPathMeasure.h',
+ '../include/core/SkPerspIter.h',
+ '../include/core/SkPicture.h',
+ '../include/core/SkPixelRef.h',
+ '../include/core/SkPoint.h',
+ '../include/core/SkPtrRecorder.h',
+ '../include/core/SkRandom.h',
+ '../include/core/SkRasterizer.h',
+ '../include/core/SkReader32.h',
+ '../include/core/SkRect.h',
+ '../include/core/SkRefCnt.h',
+ '../include/core/SkRefDict.h',
+ '../include/core/SkRegion.h',
+ '../include/core/SkScalar.h',
+ '../include/core/SkScalarCompare.h',
+ '../include/core/SkScalerContext.h',
+ '../include/core/SkScan.h',
+ '../include/core/SkShader.h',
+ '../include/core/SkStream.h',
+ '../include/core/SkString.h',
+ '../include/core/SkStroke.h',
+ '../include/core/SkTArray.h',
+ '../include/core/SkTDArray.h',
+ '../include/core/SkTDStack.h',
+ '../include/core/SkTDict.h',
+ '../include/core/SkTRegistry.h',
+ '../include/core/SkTScopedPtr.h',
+ '../include/core/SkTSearch.h',
+ '../include/core/SkTemplates.h',
+ '../include/core/SkThread.h',
+ '../include/core/SkThread_platform.h',
+ '../include/core/SkTime.h',
+ '../include/core/SkTLazy.h',
+ '../include/core/SkTrace.h',
+ '../include/core/SkTypeface.h',
+ '../include/core/SkTypes.h',
+ '../include/core/SkUnPreMultiply.h',
+ '../include/core/SkUnitMapper.h',
+ '../include/core/SkUtils.h',
+ '../include/core/SkWriter32.h',
+ '../include/core/SkXfermode.h',
+ ],
+ 'include_dirs': [
+ '../include/config',
+ '../include/core',
+ '../include/ports',
+ '../include/xml',
+ '../src/core',
+ ],
+ 'msvs_disabled_warnings': [4244, 4267,4345, 4390, 4554, 4800],
+ 'conditions': [
+ [ 'skia_os in ["linux", "freebsd", "openbsd", "solaris"]', {
+ 'cflags': [
+ '-Wno-unused',
+ '-Wno-unused-function',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-lfreetype',
+ '-lpthread',
+ ],
+ },
+ }],
+ [ 'skia_os == "mac"', {
+ 'include_dirs': [
+ '../include/utils/mac',
+ '../third_party/freetype/include/**',
+ ],
+ 'sources': [
+ '../include/utils/mac/SkCGUtils.h',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/ApplicationServices.framework',
+ ],
+ },
+ }],
+ [ 'skia_os == "ios"', {
+ 'include_dirs': [
+ '../include/utils/ios',
+ ],
+ 'sources': [
+ '../include/utils/mac/SkCGUtils.h',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/CoreFoundation.framework',
+ '/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/CoreGraphics.framework',
+ '/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/CoreText.framework',
+ '/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/UIKit.framework',
+ '/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/Foundation.framework',
+ '/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/QuartzCore.framework',
+ '/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/OpenGLES.framework',
+ ],
+ },
+ }],
+ [ 'skia_os == "win"', {
+ 'include_dirs': [
+ 'config/win',
+ ],
+ 'sources!': [
+ '../include/core/SkMMapStream.h',
+ '../src/core/SkMMapStream.cpp',
+ ],
+ }],
+ [ 'skia_os == "android"', {
+ 'dependencies': [
+ 'android_system.gyp:ft2',
+ ],
+ }],
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ 'config',
+ '../include/config',
+ '../include/core',
+ 'ext',
+ ],
+ },
+ 'dependencies': [
+ 'opts.gyp:opts'
+ ],
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/effects.gyp b/gyp/effects.gyp
new file mode 100644
index 0000000..28f0017
--- /dev/null
+++ b/gyp/effects.gyp
@@ -0,0 +1,92 @@
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'effects',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../include/config',
+ '../include/core',
+ '../include/effects',
+ ],
+ 'sources': [
+ '../include/effects/Sk1DPathEffect.h',
+ '../include/effects/Sk2DPathEffect.h',
+ '../include/effects/SkAvoidXfermode.h',
+ '../include/effects/SkArithmeticMode.h',
+ '../include/effects/SkBlurDrawLooper.h',
+ '../include/effects/SkBlurImageFilter.h',
+ '../include/effects/SkBlurMaskFilter.h',
+ '../include/effects/SkColorMatrix.h',
+ '../include/effects/SkColorMatrixFilter.h',
+ '../include/effects/SkCornerPathEffect.h',
+ '../include/effects/SkDashPathEffect.h',
+ '../include/effects/SkDiscretePathEffect.h',
+ '../include/effects/SkDrawExtraPathEffect.h',
+ '../include/effects/SkEffects.h',
+ '../include/effects/SkEmbossMaskFilter.h',
+ '../include/effects/SkGradientShader.h',
+ '../include/effects/SkGroupShape.h',
+ '../include/effects/SkKernel33MaskFilter.h',
+ '../include/effects/SkLayerDrawLooper.h',
+ '../include/effects/SkLayerRasterizer.h',
+ '../include/effects/SkPaintFlagsDrawFilter.h',
+ '../include/effects/SkPixelXorXfermode.h',
+ '../include/effects/SkPorterDuff.h',
+ '../include/effects/SkRectShape.h',
+ '../include/effects/SkTableColorFilter.h',
+ '../include/effects/SkTableMaskFilter.h',
+ '../include/effects/SkTransparentShader.h',
+
+ '../src/effects/Sk1DPathEffect.cpp',
+ '../src/effects/Sk2DPathEffect.cpp',
+ '../src/effects/SkAvoidXfermode.cpp',
+ '../src/effects/SkArithmeticMode.cpp',
+ '../src/effects/SkBitmapCache.cpp',
+ '../src/effects/SkBitmapCache.h',
+ '../src/effects/SkBlurDrawLooper.cpp',
+ '../src/effects/SkBlurMask.cpp',
+ '../src/effects/SkBlurMask.h',
+ '../src/effects/SkBlurImageFilter.cpp',
+ '../src/effects/SkBlurMaskFilter.cpp',
+ '../src/effects/SkColorFilters.cpp',
+ '../src/effects/SkColorMatrixFilter.cpp',
+ '../src/effects/SkCornerPathEffect.cpp',
+ '../src/effects/SkDashPathEffect.cpp',
+ '../src/effects/SkDiscretePathEffect.cpp',
+ '../src/effects/SkEffects.cpp',
+ '../src/effects/SkEmbossMask.cpp',
+ '../src/effects/SkEmbossMask.h',
+ '../src/effects/SkEmbossMask_Table.h',
+ '../src/effects/SkEmbossMaskFilter.cpp',
+ '../src/effects/SkGradientShader.cpp',
+ '../src/effects/SkGroupShape.cpp',
+ '../src/effects/SkKernel33MaskFilter.cpp',
+ '../src/effects/SkLayerDrawLooper.cpp',
+ '../src/effects/SkLayerRasterizer.cpp',
+ '../src/effects/SkPaintFlagsDrawFilter.cpp',
+ '../src/effects/SkPixelXorXfermode.cpp',
+ '../src/effects/SkPorterDuff.cpp',
+ '../src/effects/SkRadialGradient_Table.h',
+ '../src/effects/SkRectShape.cpp',
+ '../src/effects/SkTableColorFilter.cpp',
+ '../src/effects/SkTableMaskFilter.cpp',
+ '../src/effects/SkTestImageFilters.cpp',
+ '../src/effects/SkTransparentShader.cpp',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../include/effects',
+ ],
+ },
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/experimental.gyp b/gyp/experimental.gyp
new file mode 100644
index 0000000..c5b8c5e
--- /dev/null
+++ b/gyp/experimental.gyp
@@ -0,0 +1,31 @@
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'experimental',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../include/config',
+ '../include/core',
+ ],
+ 'sources': [
+ '../experimental/SkSetPoly3To3.cpp',
+ '../experimental/SkSetPoly3To3_A.cpp',
+ '../experimental/SkSetPoly3To3_D.cpp',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../experimental',
+ ],
+ },
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/freetype.gyp b/gyp/freetype.gyp
new file mode 100644
index 0000000..e86a338
--- /dev/null
+++ b/gyp/freetype.gyp
@@ -0,0 +1,69 @@
+{
+# 'includes': [
+# 'common.gypi',
+# ],
+ 'targets': [
+ {
+ 'target_name': 'skfreetype',
+ 'type': 'static_library',
+ 'sources': [
+ '../third_party/freetype/src/base/ftbbox.c',
+ '../third_party/freetype/src/base/ftbitmap.c',
+ '../third_party/freetype/src/base/ftglyph.c',
+ '../third_party/freetype/src/base/ftlcdfil.c',
+ '../third_party/freetype/src/base/ftstroke.c',
+ '../third_party/freetype/src/base/ftxf86.c',
+ '../third_party/freetype/src/base/ftbase.c',
+ '../third_party/freetype/src/base/ftsystem.c',
+ '../third_party/freetype/src/base/ftinit.c',
+ '../third_party/freetype/src/base/ftgasp.c',
+ '../third_party/freetype/src/base/ftfstype.c',
+ '../third_party/freetype/src/raster/raster.c',
+ '../third_party/freetype/src/sfnt/sfnt.c',
+ '../third_party/freetype/src/smooth/smooth.c',
+ '../third_party/freetype/src/autofit/autofit.c',
+ '../third_party/freetype/src/truetype/truetype.c',
+ '../third_party/freetype/src/cff/cff.c',
+ '../third_party/freetype/src/psnames/psnames.c',
+ '../third_party/freetype/src/pshinter/pshinter.c',
+
+# added for linker
+ '../third_party/freetype/src/lzw/ftlzw.c',
+ '../third_party/freetype/src/gzip/ftgzip.c',
+ '../third_party/freetype/src/cid/type1cid.c',
+ '../third_party/freetype/src/bdf/bdf.c',
+ '../third_party/freetype/src/psaux/psaux.c',
+ '../third_party/freetype/src/pcf/pcf.c',
+ '../third_party/freetype/src/pfr/pfr.c',
+ '../third_party/freetype/src/type1/type1.c',
+ '../third_party/freetype/src/type42/type42.c',
+ '../third_party/freetype/src/winfonts/winfnt.c',
+ ],
+ 'include_dirs': [
+ '../third_party/freetype/internal',
+ '../third_party/freetype/builds',
+ '../third_party/freetype/include',
+ '../third_party/freetype',
+ ],
+ 'cflags': [
+ '-W',
+ '-Wall',
+ '-fPIC',
+ '-DPIC',
+ '-DDARWIN_NO_CARBON',
+ '-DFT2_BUILD_LIBRARY',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../third_party/freetype/include', # For ft2build.h
+ ],
+ },
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/gm.gyp b/gyp/gm.gyp
new file mode 100644
index 0000000..43075dc
--- /dev/null
+++ b/gyp/gm.gyp
@@ -0,0 +1,44 @@
+# GYP file to build the "gm" (golden master) executable.
+{
+ 'includes': [
+ 'apptype_console.gypi',
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'gm',
+ 'type': 'executable',
+ 'includes': [
+ 'gmslides.gypi',
+ ],
+ 'sources': [
+ '../gm/gm.cpp',
+ '../gm/gmmain.cpp',
+ ],
+ 'dependencies': [
+ 'core.gyp:core',
+ 'effects.gyp:effects',
+ 'gpu.gyp:gr',
+ 'gpu.gyp:skgr',
+ 'images.gyp:images',
+ 'ports.gyp:ports',
+ 'pdf.gyp:pdf',
+ 'utils.gyp:utils',
+ ],
+ #mac does not like empty dependency.
+ 'conditions': [
+ [ 'skia_os == "win"', {
+ 'dependencies': [
+ 'xps.gyp:xps',
+ ],
+ }],
+ ],
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi
new file mode 100644
index 0000000..66692d1
--- /dev/null
+++ b/gyp/gmslides.gypi
@@ -0,0 +1,55 @@
+# include this gypi to include all the golden master slides.
+{
+ 'sources': [
+ '../gm/aaclip.cpp',
+ '../gm/aarectmodes.cpp',
+ '../gm/arithmode.cpp',
+ '../gm/bitmapcopy.cpp',
+ '../gm/bitmapfilters.cpp',
+ '../gm/bitmapscroll.cpp',
+ '../gm/blurs.cpp',
+ '../gm/colormatrix.cpp',
+ '../gm/complexclip.cpp',
+ '../gm/complexclip2.cpp',
+ '../gm/cubicpaths.cpp',
+ '../gm/degeneratesegments.cpp',
+ '../gm/drawbitmaprect.cpp',
+ '../gm/emptypath.cpp',
+ '../gm/filltypes.cpp',
+ '../gm/filltypespersp.cpp',
+ '../gm/fontscaler.cpp',
+ '../gm/gradients.cpp',
+ '../gm/gradtext.cpp',
+ '../gm/hairmodes.cpp',
+ '../gm/imageblur.cpp',
+ '../gm/lcdtext.cpp',
+ '../gm/linepaths.cpp',
+ '../gm/ninepatchstretch.cpp',
+ '../gm/nocolorbleed.cpp',
+ '../gm/pathfill.cpp',
+ '../gm/pathreverse.cpp',
+ '../gm/points.cpp',
+ '../gm/poly2poly.cpp',
+ '../gm/quadpaths.cpp',
+ '../gm/shadertext.cpp',
+ '../gm/shadows.cpp',
+ '../gm/shapes.cpp',
+ '../gm/strokefill.cpp',
+ '../gm/strokerects.cpp',
+ '../gm/strokes.cpp',
+ '../gm/tablecolorfilter.cpp',
+ '../gm/testimagefilters.cpp',
+ '../gm/texdata.cpp',
+ '../gm/tilemodes.cpp',
+ '../gm/tinybitmap.cpp',
+ '../gm/verttext.cpp',
+ '../gm/verttext2.cpp',
+ '../gm/xfermodes.cpp',
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/gpu.gyp b/gyp/gpu.gyp
new file mode 100644
index 0000000..9fcded1
--- /dev/null
+++ b/gyp/gpu.gyp
@@ -0,0 +1,356 @@
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'target_defaults': {
+ 'conditions': [
+ ['skia_os != "win"', {
+ 'sources/': [ ['exclude', '_win.(h|cpp)$'],
+ ],
+ }],
+ ['skia_os != "mac"', {
+ 'sources/': [ ['exclude', '_mac.(h|cpp)$'],
+ ],
+ }],
+ ['skia_os != "linux"', {
+ 'sources/': [ ['exclude', '_unix.(h|cpp)$'],
+ ],
+ }],
+ ['skia_os != "ios"', {
+ 'sources/': [ ['exclude', '_iOS.(h|cpp)$'],
+ ],
+ }],
+ ['skia_os != "android"', {
+ 'sources/': [ ['exclude', '_android.(h|cpp)$'],
+ ],
+ }],
+ [ 'skia_os == "android"', {
+ 'defines': [
+ 'GR_ANDROID_BUILD=1',
+ ],
+ }],
+ [ 'skia_os == "mac"', {
+ 'defines': [
+ 'GR_MAC_BUILD=1',
+ ],
+ }],
+ [ 'skia_os == "linux"', {
+ 'defines': [
+ 'GR_LINUX_BUILD=1',
+ ],
+ }],
+ [ 'skia_os == "ios"', {
+ 'defines': [
+ 'GR_IOS_BUILD=1',
+ ],
+ }],
+ [ 'skia_os == "win"', {
+ 'defines': [
+ 'GR_WIN32_BUILD=1',
+ 'GR_GL_FUNCTION_TYPE=__stdcall',
+ ],
+ }],
+ ],
+ 'direct_dependent_settings': {
+ 'conditions': [
+ [ 'skia_os == "android"', {
+ 'defines': [
+ 'GR_ANDROID_BUILD=1',
+ ],
+ }],
+ [ 'skia_os == "mac"', {
+ 'defines': [
+ 'GR_MAC_BUILD=1',
+ ],
+ }],
+ [ 'skia_os == "linux"', {
+ 'defines': [
+ 'GR_LINUX_BUILD=1',
+ ],
+ }],
+ [ 'skia_os == "ios"', {
+ 'defines': [
+ 'GR_IOS_BUILD=1',
+ ],
+ }],
+ [ 'skia_os == "win"', {
+ 'defines': [
+ 'GR_WIN32_BUILD=1',
+ 'GR_GL_FUNCTION_TYPE=__stdcall',
+ ],
+ }],
+ ],
+ 'include_dirs': [
+ '../include/gpu',
+ ],
+ },
+ },
+ 'targets': [
+ {
+ 'target_name': 'skgr',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../include/config',
+ '../include/core',
+ '../src/core',
+ '../include/gpu',
+ ],
+ 'sources': [
+ '../include/gpu/SkGLContext.h',
+ '../include/gpu/SkMesaGLContext.h',
+ '../include/gpu/SkNativeGLContext.h',
+ '../include/gpu/SkNullGLContext.h',
+ '../include/gpu/SkGpuCanvas.h',
+ '../include/gpu/SkGpuDevice.h',
+ '../include/gpu/SkGr.h',
+ '../include/gpu/SkGrTexturePixelRef.h',
+
+ '../src/gpu/GrPrintf_skia.cpp',
+ '../src/gpu/SkGLContext.cpp',
+ '../src/gpu/SkGpuCanvas.cpp',
+ '../src/gpu/SkGpuDevice.cpp',
+ '../src/gpu/SkGr.cpp',
+ '../src/gpu/SkGrFontScaler.cpp',
+ '../src/gpu/SkGrTexturePixelRef.cpp',
+ '../src/gpu/SkNullGLContext.cpp',
+
+ '../src/gpu/android/SkNativeGLContext_android.cpp',
+
+ '../src/gpu/mac/SkNativeGLContext_mac.cpp',
+
+ '../src/gpu/win/SkNativeGLContext_win.cpp',
+
+ '../src/gpu/unix/SkNativeGLContext_unix.cpp',
+
+ '../src/gpu/mesa/SkMesaGLContext.cpp',
+ ],
+ 'conditions': [
+ [ 'not skia_mesa', {
+ 'sources!': [
+ '../src/gpu/mesa/SkMesaGLContext.cpp',
+ ],
+ }],
+ [ 'skia_mesa and skia_os == "mac"', {
+ 'include_dirs': [
+ '$(SDKROOT)/usr/X11/include/',
+ ],
+ }],
+ ],
+ },
+ {
+ 'target_name': 'gr',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../include/core',
+ '../include/config',
+ '../include/gpu',
+ ],
+ 'dependencies': [
+ 'libtess.gyp:libtess',
+ ],
+ 'sources': [
+ '../include/gpu/GrClip.h',
+ '../include/gpu/GrClipIterator.h',
+ '../include/gpu/GrColor.h',
+ '../include/gpu/GrConfig.h',
+ '../include/gpu/GrContext.h',
+ '../include/gpu/GrFontScaler.h',
+ '../include/gpu/GrGLConfig.h',
+ '../include/gpu/GrGLConfig_chrome.h',
+ '../include/gpu/GrGLDefines.h',
+ '../include/gpu/GrGLInterface.h',
+ '../include/gpu/GrGlyph.h',
+ '../include/gpu/GrInstanceCounter.h',
+ '../include/gpu/GrKey.h',
+ '../include/gpu/GrMatrix.h',
+ '../include/gpu/GrNoncopyable.h',
+ '../include/gpu/GrPaint.h',
+ '../include/gpu/GrPath.h',
+ '../include/gpu/GrPoint.h',
+ '../include/gpu/GrRect.h',
+ '../include/gpu/GrRefCnt.h',
+ '../include/gpu/GrRenderTarget.h',
+ '../include/gpu/GrResource.h',
+ '../include/gpu/GrSamplerState.h',
+ '../include/gpu/GrScalar.h',
+ '../include/gpu/GrTextContext.h',
+ '../include/gpu/GrTexture.h',
+ '../include/gpu/GrTypes.h',
+ '../include/gpu/GrUserConfig.h',
+
+ '../src/gpu/GrAAHairLinePathRenderer.cpp',
+ '../src/gpu/GrAAHairLinePathRenderer.h',
+ '../src/gpu/GrAddPathRenderers_aahairline.cpp',
+ '../src/gpu/GrAllocator.h',
+ '../src/gpu/GrAllocPool.h',
+ '../src/gpu/GrAllocPool.cpp',
+ '../src/gpu/GrAtlas.cpp',
+ '../src/gpu/GrAtlas.h',
+ '../src/gpu/GrBinHashKey.h',
+ '../src/gpu/GrBufferAllocPool.cpp',
+ '../src/gpu/GrBufferAllocPool.h',
+ '../src/gpu/GrClip.cpp',
+ '../src/gpu/GrContext.cpp',
+ '../src/gpu/GrDefaultPathRenderer.cpp',
+ '../src/gpu/GrDefaultPathRenderer.h',
+ '../src/gpu/GrDrawState.h',
+ '../src/gpu/GrDrawTarget.cpp',
+ '../src/gpu/GrDrawTarget.h',
+ '../src/gpu/GrGeometryBuffer.h',
+ '../src/gpu/GrGLCreateNativeInterface_none.cpp',
+ '../src/gpu/GrGLCreateNullInterface.cpp',
+ '../src/gpu/GrGLDefaultInterface_none.cpp',
+ '../src/gpu/GrGLDefaultInterface_native.cpp',
+ '../src/gpu/GrGLIndexBuffer.cpp',
+ '../src/gpu/GrGLIndexBuffer.h',
+ '../src/gpu/GrGLInterface.cpp',
+ '../src/gpu/GrGLIRect.h',
+ '../src/gpu/GrGLProgram.cpp',
+ '../src/gpu/GrGLProgram.h',
+ '../src/gpu/GrGLRenderTarget.cpp',
+ '../src/gpu/GrGLRenderTarget.h',
+ '../src/gpu/GrGLShaderVar.h',
+ '../src/gpu/GrGLSL.cpp',
+ '../src/gpu/GrGLSL.h',
+ '../src/gpu/GrGLStencilBuffer.cpp',
+ '../src/gpu/GrGLStencilBuffer.h',
+ '../src/gpu/GrGLTexture.cpp',
+ '../src/gpu/GrGLTexture.h',
+ '../src/gpu/GrGLUtil.cpp',
+ '../src/gpu/GrGLVertexBuffer.cpp',
+ '../src/gpu/GrGLVertexBuffer.h',
+ '../src/gpu/GrGpu.cpp',
+ '../src/gpu/GrGpu.h',
+ '../src/gpu/GrGpuFactory.cpp',
+ '../src/gpu/GrGpuGL.cpp',
+ '../src/gpu/GrGpuGL.h',
+ '../src/gpu/GrGpuGLShaders.cpp',
+ '../src/gpu/GrGpuGLShaders.h',
+ '../src/gpu/GrGpuVertex.h',
+ '../src/gpu/GrIndexBuffer.h',
+ '../src/gpu/GrInOrderDrawBuffer.cpp',
+ '../src/gpu/GrInOrderDrawBuffer.h',
+ '../src/gpu/GrMatrix.cpp',
+ '../src/gpu/GrMemory.cpp',
+ '../src/gpu/GrPathRendererChain.cpp',
+ '../src/gpu/GrPathRendererChain.h',
+ '../src/gpu/GrPathRenderer.cpp',
+ '../src/gpu/GrPathRenderer.h',
+ '../src/gpu/GrPathUtils.cpp',
+ '../src/gpu/GrPathUtils.h',
+ '../src/gpu/GrPlotMgr.h',
+ '../src/gpu/GrRandom.h',
+ '../src/gpu/GrRectanizer.cpp',
+ '../src/gpu/GrRectanizer.h',
+ '../src/gpu/GrRedBlackTree.h',
+ '../src/gpu/GrRenderTarget.cpp',
+ '../src/gpu/GrResource.cpp',
+ '../src/gpu/GrResourceCache.cpp',
+ '../src/gpu/GrResourceCache.h',
+ '../src/gpu/GrStencil.cpp',
+ '../src/gpu/GrStencil.h',
+ '../src/gpu/GrStencilBuffer.cpp',
+ '../src/gpu/GrStencilBuffer.h',
+ '../src/gpu/GrStringBuilder.h',
+ '../src/gpu/GrTBSearch.h',
+ '../src/gpu/GrTDArray.h',
+ '../src/gpu/GrTesselatedPathRenderer.cpp',
+ '../src/gpu/GrTesselatedPathRenderer.h',
+ '../src/gpu/GrTextContext.cpp',
+ '../src/gpu/GrTextStrike.cpp',
+ '../src/gpu/GrTextStrike.h',
+ '../src/gpu/GrTextStrike_impl.h',
+ '../src/gpu/GrTexture.cpp',
+ '../src/gpu/GrTHashCache.h',
+ '../src/gpu/GrTLList.h',
+ '../src/gpu/GrVertexBuffer.h',
+ '../src/gpu/gr_unittests.cpp',
+
+
+ '../src/gpu/mac/GrGLCreateNativeInterface_mac.cpp',
+
+ '../src/gpu/win/GrGLCreateNativeInterface_win.cpp',
+
+ '../src/gpu/unix/GrGLCreateNativeInterface_unix.cpp',
+
+ '../src/gpu/android/GrGLCreateNativeInterface_android.cpp',
+
+ '../src/gpu/mesa/GrGLCreateMesaInterface.cpp',
+ ],
+ 'defines': [
+ 'GR_IMPLEMENTATION=1',
+ ],
+ 'conditions': [
+ [ 'skia_os == "linux"', {
+ 'sources!': [
+ '../src/gpu/GrGLDefaultInterface_none.cpp',
+ '../src/gpu/GrGLCreateNativeInterface_none.cpp',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-lGL',
+ '-lX11',
+ ],
+ },
+ }],
+ [ 'skia_mesa and skia_os == "linux"', {
+ 'link_settings': {
+ 'libraries': [
+ '-lOSMesa',
+ ],
+ },
+ }],
+ [ 'skia_os == "mac"', {
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/OpenGL.framework',
+ ],
+ },
+ 'sources!': [
+ '../src/gpu/GrGLDefaultInterface_none.cpp',
+ '../src/gpu/GrGLCreateNativeInterface_none.cpp',
+ ],
+ }],
+ [ 'skia_mesa and skia_os == "mac"', {
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/usr/X11/lib/libOSMesa.dylib',
+ ],
+ },
+ 'include_dirs': [
+ '$(SDKROOT)/usr/X11/include/',
+ ],
+ }],
+ [ 'not skia_mesa', {
+ 'sources!': [
+ '../src/gpu/mesa/GrGLCreateMesaInterface.cpp',
+ ],
+ }],
+ [ 'skia_os == "win"', {
+ 'sources!': [
+ '../src/gpu/GrGLDefaultInterface_none.cpp',
+ '../src/gpu/GrGLCreateNativeInterface_none.cpp',
+ ],
+ }],
+ [ 'skia_os == "android"', {
+ 'sources!': [
+ '../src/gpu/GrGLDefaultInterface_none.cpp',
+ '../src/gpu/GrGLCreateNativeInterface_none.cpp',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-lGLESv2',
+ '-lEGL',
+ ],
+ },
+ }],
+ ],
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/iOSSampleApp.gyp b/gyp/iOSSampleApp.gyp
new file mode 100644
index 0000000..84708bb
--- /dev/null
+++ b/gyp/iOSSampleApp.gyp
@@ -0,0 +1,279 @@
+{
+ 'includes': [
+ 'target_defaults.gypi',
+ ],
+ 'defines!': [
+ 'SK_BUILD_FOR_MAC',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'iOSSampleApp',
+ 'type': 'executable',
+ 'mac_bundle' : 1,
+ 'include_dirs' : [
+ '../src/core', # needed to get SkConcaveToTriangle, maybe this should be moved to include dir?
+ '../gm', # SampleGM.cpp pulls gm.h
+ '../include/pipe', # To pull in SkGPipe.h for pipe reader/writer
+ ],
+ 'sources': [
+ # gm files needed for SampleGM.cpp
+ '../gm/bitmapfilters.cpp',
+ '../gm/blurs.cpp',
+ '../gm/complexclip.cpp',
+ '../gm/filltypes.cpp',
+ '../gm/gm.h',
+ '../gm/gradients.cpp',
+ '../gm/nocolorbleed.cpp',
+ '../gm/points.cpp',
+ '../gm/poly2poly.cpp',
+ '../gm/shadertext.cpp',
+ '../gm/shadows.cpp',
+ '../gm/shapes.cpp',
+ '../gm/tilemodes.cpp',
+ '../gm/xfermodes.cpp',
+
+ '../samplecode/ClockFaceView.cpp',
+ '../samplecode/OverView.cpp',
+ '../samplecode/Sample2PtRadial.cpp',
+ '../samplecode/SampleAll.cpp',
+ '../samplecode/SampleAnimator.cpp',
+ '../samplecode/SampleApp.cpp',
+ '../samplecode/SampleArc.cpp',
+ '../samplecode/SampleAvoid.cpp',
+ '../samplecode/SampleBigBlur.cpp',
+ '../samplecode/SampleBigGradient.cpp',
+ '../samplecode/SampleBitmapRect.cpp',
+ '../samplecode/SampleBlur.cpp',
+ '../samplecode/SampleCamera.cpp',
+ '../samplecode/SampleCircle.cpp',
+ '../samplecode/SampleCode.h',
+ '../samplecode/SampleColorFilter.cpp',
+ '../samplecode/SampleComplexClip.cpp',
+ '../samplecode/SampleConcavePaths.cpp',
+ '../samplecode/SampleCull.cpp',
+ '../samplecode/SampleDecode.cpp',
+ '../samplecode/SampleDegenerateTwoPtRadials.cpp',
+ '../samplecode/SampleDither.cpp',
+ '../samplecode/SampleDitherBitmap.cpp',
+ '../samplecode/SampleDrawBitmap.cpp',
+ '../samplecode/SampleDrawLooper.cpp',
+ '../samplecode/SampleEffects.cpp',
+ '../samplecode/SampleEmboss.cpp',
+ '../samplecode/SampleEncode.cpp',
+ '../samplecode/SampleExtractAlpha.cpp',
+ '../samplecode/SampleFillType.cpp',
+ '../samplecode/SampleFilter.cpp',
+ '../samplecode/SampleFilter2.cpp',
+ '../samplecode/SampleFontCache.cpp',
+ '../samplecode/SampleFontScalerTest.cpp',
+ '../samplecode/SampleFuzz.cpp',
+ '../samplecode/SampleGM.cpp',
+ '../samplecode/SampleGradients.cpp',
+ '../samplecode/SampleHairline.cpp',
+ '../samplecode/SampleImage.cpp',
+ '../samplecode/SampleImageDir.cpp',
+ '../samplecode/SampleLayerMask.cpp',
+ '../samplecode/SampleLayers.cpp',
+ '../samplecode/SampleLCD.cpp',
+ '../samplecode/SampleLineClipper.cpp',
+ '../samplecode/SampleLines.cpp',
+ '../samplecode/SampleMeasure.cpp',
+ '../samplecode/SampleMipMap.cpp',
+ '../samplecode/SampleMovie.cpp',
+ '../samplecode/SampleNinePatch.cpp',
+ '../samplecode/SampleOvalTest.cpp',
+ '../samplecode/SampleOverflow.cpp',
+ '../samplecode/SamplePageFlip.cpp',
+ '../samplecode/SamplePatch.cpp',
+ '../samplecode/SamplePath.cpp',
+ '../samplecode/SamplePathClip.cpp',
+ '../samplecode/SamplePathEffects.cpp',
+ '../samplecode/SamplePicture.cpp',
+ '../samplecode/SamplePoints.cpp',
+ '../samplecode/SamplePolyToPoly.cpp',
+ '../samplecode/SampleAARects.cpp',
+ '../samplecode/SampleRegion.cpp',
+ '../samplecode/SampleRepeatTile.cpp',
+ '../samplecode/SampleShaders.cpp',
+ '../samplecode/SampleShaderText.cpp',
+ '../samplecode/SampleShapes.cpp',
+ '../samplecode/SampleSkLayer.cpp',
+ '../samplecode/SampleSlides.cpp',
+ '../samplecode/SampleStrokePath.cpp',
+ '../samplecode/SampleStrokeText.cpp',
+ '../samplecode/SampleTests.cpp',
+ '../samplecode/SampleText.cpp',
+ '../samplecode/SampleTextAlpha.cpp',
+ '../samplecode/SampleTextBox.cpp',
+ '../samplecode/SampleTextEffects.cpp',
+ '../samplecode/SampleTextOnPath.cpp',
+ '../samplecode/SampleTextureDomain.cpp',
+ '../samplecode/SampleTiling.cpp',
+ '../samplecode/SampleTinyBitmap.cpp',
+ '../samplecode/SampleTriangles.cpp',
+ '../samplecode/SampleTypeface.cpp',
+ '../samplecode/SampleUnitMapper.cpp',
+ '../samplecode/SampleVertices.cpp',
+ '../samplecode/SampleXfermodes.cpp',
+ '../samplecode/SampleXfermodesBlur.cpp',
+
+ # Dependencies for the pipe code in SampleApp
+ '../src/pipe/SkGPipeRead.cpp',
+ '../src/pipe/SkGPipeWrite.cpp',
+
+ # DrawingBoard
+ '../experimental/DrawingBoard/SkColorPalette.h',
+ '../experimental/DrawingBoard/SkColorPalette.cpp',
+ '../experimental/DrawingBoard/SkNetPipeController.h',
+ '../experimental/DrawingBoard/SkNetPipeController.cpp',
+ '../experimental/DrawingBoard/SampleDrawingClient.cpp',
+ '../experimental/DrawingBoard/SampleDrawingServer.cpp',
+
+ # Networking
+ '../experimental/Networking/SampleNetPipeReader.cpp',
+ '../experimental/Networking/SkSockets.cpp',
+ '../experimental/Networking/SkSockets.h',
+
+ # Transition
+ '../src/utils/SkInterpolator.cpp',
+ '../include/utils/SkInterpolator.h',
+ '../samplecode/TransitionView.cpp',
+ ],
+ 'sources!': [
+ '../samplecode/SampleSkLayer.cpp', #relies on SkMatrix44 which doesn't compile
+ '../samplecode/SampleTests.cpp', #includes unknown file SkShaderExtras.h
+ '../samplecode/SampleWarp.cpp',
+ '../samplecode/SampleFontCache.cpp',
+ ],
+ 'dependencies': [
+ 'core.gyp:core',
+ 'effects.gyp:effects',
+ 'images.gyp:images',
+ 'ports.gyp:ports',
+ 'views.gyp:views',
+ 'utils.gyp:utils',
+ 'animator.gyp:animator',
+ 'xml.gyp:xml',
+ 'svg.gyp:svg',
+ 'experimental.gyp:experimental',
+ 'gpu.gyp:gr',
+ 'gpu.gyp:skgr',
+ 'pdf.gyp:pdf',
+ ],
+ 'conditions' : [
+ [ 'OS == "linux" or OS == "freebsd" or OS == "openbsd" or OS == "solaris"', {
+ 'sources!': [
+ '../samplecode/SampleDecode.cpp',
+ ],
+ }],
+ [ 'OS == "win"', {
+ 'sources!': [
+ # require UNIX functions
+ '../samplecode/SampleEncode.cpp',
+ '../samplecode/SamplePageFlip.cpp',
+ ],
+ }],
+ [ 'OS == "mac"', {
+ 'sources!': [
+ '../samplecode/SampleDecode.cpp',
+ '../src/gpu/mac/GrGLDefaultInterface_mac.cpp',
+ ],
+ 'sources': [
+ # Shared resources
+ '../experimental/SkEventNotifier.h',
+ '../experimental/SkEventNotifier.mm',
+ '../experimental/iOSSampleApp/SkiOSSampleApp-Base.xcconfig',
+ '../experimental/iOSSampleApp/SkiOSSampleApp-Debug.xcconfig',
+ '../experimental/iOSSampleApp/SkiOSSampleApp-Release.xcconfig',
+ '../experimental/iOSSampleApp/iOSSampleApp-Info.plist',
+ '../experimental/iOSSampleApp/iOSSampleApp_Prefix.pch',
+ '../experimental/iOSSampleApp/Shared/SkOptionListController.h',
+ '../experimental/iOSSampleApp/Shared/SkOptionListController.mm',
+ '../experimental/iOSSampleApp/Shared/SkUIRootViewController.h',
+ '../experimental/iOSSampleApp/Shared/SkUIRootViewController.mm',
+ '../experimental/iOSSampleApp/Shared/SkOptionsTableViewController.h',
+ '../experimental/iOSSampleApp/Shared/SkOptionsTableViewController.mm',
+ '../experimental/iOSSampleApp/Shared/SkUIView.h',
+ '../experimental/iOSSampleApp/Shared/SkUIView.mm',
+ '../experimental/iOSSampleApp/Shared/SkUIDetailViewController.h',
+ '../experimental/iOSSampleApp/Shared/SkUIDetailViewController.mm',
+ '../experimental/iOSSampleApp/Shared/main.m',
+
+ # iPad
+ '../experimental/iOSSampleApp/iPad/AppDelegate_iPad.h',
+ '../experimental/iOSSampleApp/iPad/AppDelegate_iPad.mm',
+ '../experimental/iOSSampleApp/iPad/SkUISplitViewController.h',
+ '../experimental/iOSSampleApp/iPad/SkUISplitViewController.mm',
+ '../experimental/iOSSampleApp/iPad/MainWindow_iPad.xib',
+
+ # iPhone
+ '../experimental/iOSSampleApp/iPhone/AppDelegate_iPhone.h',
+ '../experimental/iOSSampleApp/iPhone/AppDelegate_iPhone.mm',
+ '../experimental/iOSSampleApp/iPhone/SkUINavigationController.h',
+ '../experimental/iOSSampleApp/iPhone/SkUINavigationController.mm',
+ '../experimental/iOSSampleApp/iPhone/MainWindow_iPhone.xib',
+
+ '../src/utils/ios/SkOSWindow_iOS.mm',
+ '../src/utils/ios/SkImageDecoder_iOS.mm',
+ '../src/utils/ios/SkStream_NSData.mm',
+ '../src/utils/ios/SkOSFile_iOS.mm',
+
+ '../include/utils/mac/SkCGUtils.h',
+ '../src/utils/mac/SkCreateCGImageRef.cpp',
+ '../experimental/iOSSampleApp/SkiOSSampleApp-Debug.xcconfig',
+ '../experimental/iOSSampleApp/SkiOSSampleApp-Release.xcconfig',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/CoreFoundation.framework',
+ '/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/CoreGraphics.framework',
+ '/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/CoreText.framework',
+ '/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/UIKit.framework',
+ '/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/Foundation.framework',
+ '/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/QuartzCore.framework',
+ '/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/OpenGLES.framework',
+ ],
+ 'libraries!': [
+ #remove mac dependencies
+ '$(SDKROOT)/System/Library/Frameworks/Cocoa.framework',
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework',
+ '$(SDKROOT)/System/Library/Frameworks/OpenGL.framework',
+ '$(SDKROOT)/System/Library/Frameworks/ApplicationServices.framework',
+ ],
+ },
+ 'include_dirs' : [
+ '../experimental/iOSSampleApp',
+ '../experimental/iOSSampleApp/iPad',
+ '../experimental/iOSSampleApp/iPhone',
+ '../include/utils/ios',
+ '../../include/gpu',
+ ],
+ #'xcode_settings' : {
+ # 'INFOPLIST_FILE' : '../experimental/iOSSampleApp/iOSSampleApp-Info.plist',
+ # 'ARCHS' : 'armv6 armv7',
+ # 'IPHONEOS_DEPLOYMENT_TARGET' : '4.2',
+ # 'SDKROOT' : 'iphoneos',
+ # 'TARGETED_DEVICE_FAMILY' : '1,2',
+ # 'USER_HEADER_SEARCH_PATHS' : '../../gpu/include/** ../../include/**',
+ # 'CODE_SIGN_IDENTITY' : 'iPhone Developer',
+ # 'GCC_PREPROCESSOR_DEFINITIONS' : 'SK_BUILD_FOR_IOS',
+ # 'GCC_OPTIMIZATION_LEVEL' : '0',
+ #},
+ 'xcode_config_file': '../experimental/iOSSampleApp/SkiOSSampleApp-Base.xcconfig',
+ 'mac_bundle_resources' : [
+ '../experimental/iOSSampleApp/iPad/MainWindow_iPad.xib',
+ '../experimental/iOSSampleApp/iPhone/MainWindow_iPhone.xib',
+ ],
+ }],
+
+ ],
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/images.gyp b/gyp/images.gyp
new file mode 100644
index 0000000..0732351
--- /dev/null
+++ b/gyp/images.gyp
@@ -0,0 +1,149 @@
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'images',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'utils.gyp:utils',
+ ],
+ 'include_dirs': [
+ '../include/config',
+ '../include/core',
+ '../include/images',
+ ],
+ 'sources': [
+ '../include/images/SkFlipPixelRef.h',
+ '../include/images/SkImageDecoder.h',
+ '../include/images/SkImageEncoder.h',
+ '../include/images/SkImageRef.h',
+ '../include/images/SkImageRef_GlobalPool.h',
+ '../include/images/SkJpegUtility.h',
+ '../include/images/SkMovie.h',
+ '../include/images/SkPageFlipper.h',
+
+ '../src/images/bmpdecoderhelper.cpp',
+ '../src/images/bmpdecoderhelper.h',
+ '../src/images/SkBitmapRegionDecoder.cpp',
+ '../src/images/SkBitmap_RLEPixels.h',
+ '../src/images/SkCreateRLEPixelRef.cpp',
+ '../src/images/SkFDStream.cpp',
+ '../src/images/SkFlipPixelRef.cpp',
+ '../src/images/SkImageDecoder.cpp',
+ '../src/images/SkImageDecoder_Factory.cpp',
+ '../src/images/SkImageDecoder_libbmp.cpp',
+ '../src/images/SkImageDecoder_libgif.cpp',
+ '../src/images/SkImageDecoder_libico.cpp',
+ '../src/images/SkImageDecoder_libjpeg.cpp',
+ '../src/images/SkImageDecoder_libpng.cpp',
+ '../src/images/SkImageDecoder_wbmp.cpp',
+ '../src/images/SkImageEncoder.cpp',
+ '../src/images/SkImageEncoder_Factory.cpp',
+ '../src/images/SkImageRef.cpp',
+ '../src/images/SkImageRefPool.cpp',
+ '../src/images/SkImageRefPool.h',
+ '../src/images/SkImageRef_GlobalPool.cpp',
+ '../src/images/SkJpegUtility.cpp',
+ '../src/images/SkMovie.cpp',
+ '../src/images/SkMovie_gif.cpp',
+ '../src/images/SkPageFlipper.cpp',
+ '../src/images/SkScaledBitmapSampler.cpp',
+ '../src/images/SkScaledBitmapSampler.h',
+
+ '../src/ports/SkImageDecoder_CG.cpp',
+ '../src/ports/SkImageDecoder_WIC.cpp',
+ ],
+ 'conditions': [
+ [ 'skia_os == "win"', {
+ 'sources!': [
+ '../include/images/SkJpegUtility.h',
+
+ '../src/images/SkFDStream.cpp',
+ '../src/images/SkImageDecoder_Factory.cpp',
+ '../src/images/SkImageDecoder_libgif.cpp',
+ '../src/images/SkImageDecoder_libjpeg.cpp',
+ '../src/images/SkImageDecoder_libpng.cpp',
+ '../src/images/SkImageDecoder_libpvjpeg.c',
+ '../src/images/SkImageEncoder_Factory.cpp',
+ '../src/images/SkJpegUtility.cpp',
+ '../src/images/SkMovie_gif.cpp',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ 'windowscodecs.lib',
+ ],
+ },
+ },{ #else if skia_os != win
+ 'sources!': [
+ '../src/ports/SkImageDecoder_WIC.cpp',
+ ],
+ }],
+ [ 'skia_os == "mac"', {
+ 'sources!': [
+ '../include/images/SkJpegUtility.h',
+
+ '../src/images/SkImageDecoder_Factory.cpp',
+ '../src/images/SkImageDecoder_libpng.cpp',
+ '../src/images/SkImageDecoder_libgif.cpp',
+ '../src/images/SkImageDecoder_libjpeg.cpp',
+ '../src/images/SkImageDecoder_libpvjpeg.c',
+ '../src/images/SkImageEncoder_Factory.cpp',
+ '../src/images/SkJpegUtility.cpp',
+ '../src/images/SkMovie_gif.cpp',
+ ],
+ },{ #else if skia_os != mac
+ 'sources!': [
+ '../src/ports/SkImageDecoder_CG.cpp',
+ ],
+ }],
+ [ 'skia_os in ["linux", "freebsd", "openbsd", "solaris"]', {
+ 'sources!': [
+ '../include/images/SkJpegUtility.h',
+
+ '../src/images/SkImageDecoder_libjpeg.cpp',
+ '../src/images/SkImageDecoder_libgif.cpp',
+ '../src/images/SkImageDecoder_libpvjpeg.c',
+ '../src/images/SkJpegUtility.cpp',
+ '../src/images/SkMovie_gif.cpp',
+ ],
+ # libpng stuff:
+ # Any targets that depend on this target should link in libpng and
+ # our code that calls it.
+ # See http://code.google.com/p/gyp/wiki/InputFormatReference#Dependent_Settings
+ 'link_settings': {
+ 'sources': [
+ '../src/images/SkImageDecoder_libpng.cpp',
+ ],
+ 'libraries': [
+ '-lpng',
+ ],
+ },
+ # end libpng stuff
+ }],
+ [ 'skia_os == "android"', {
+ 'sources!': [
+ '../src/images/SkImageDecoder_libjpeg.cpp',
+ '../src/images/SkJpegUtility.cpp',
+ ],
+ 'dependencies': [
+ 'android_system.gyp:gif',
+ 'android_system.gyp:png',
+ ],
+ }],
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../include/images',
+ ],
+ },
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/libtess.gyp b/gyp/libtess.gyp
new file mode 100644
index 0000000..d74bcc7
--- /dev/null
+++ b/gyp/libtess.gyp
@@ -0,0 +1,59 @@
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'libtess',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../third_party/glu',
+ ],
+ 'sources': [
+ '../third_party/glu/sk_glu.h',
+ '../third_party/glu/gluos.h',
+ '../third_party/glu/libtess/dict-list.h',
+ '../third_party/glu/libtess/dict.c',
+ '../third_party/glu/libtess/dict.h',
+ '../third_party/glu/libtess/geom.c',
+ '../third_party/glu/libtess/geom.h',
+ '../third_party/glu/libtess/memalloc.c',
+ '../third_party/glu/libtess/memalloc.h',
+ '../third_party/glu/libtess/mesh.c',
+ '../third_party/glu/libtess/mesh.h',
+ '../third_party/glu/libtess/normal.c',
+ '../third_party/glu/libtess/normal.h',
+ '../third_party/glu/libtess/priorityq-heap.h',
+ '../third_party/glu/libtess/priorityq-sort.h',
+ '../third_party/glu/libtess/priorityq.c',
+ '../third_party/glu/libtess/priorityq.h',
+ '../third_party/glu/libtess/render.c',
+ '../third_party/glu/libtess/render.h',
+ '../third_party/glu/libtess/sweep.c',
+ '../third_party/glu/libtess/sweep.h',
+ '../third_party/glu/libtess/tess.c',
+ '../third_party/glu/libtess/tess.h',
+ '../third_party/glu/libtess/tessmono.c',
+ '../third_party/glu/libtess/tessmono.h',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../third_party/glu',
+ ],
+ },
+ 'conditions': [
+ [ 'skia_os == "android"', {
+ 'cflags!': [
+ '-fno-rtti', # supresses warnings about invalid option of non-C++ code
+ ],
+ }],
+ ],
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/opts.gyp b/gyp/opts.gyp
new file mode 100644
index 0000000..1f67e00
--- /dev/null
+++ b/gyp/opts.gyp
@@ -0,0 +1,81 @@
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ # Due to an unfortunate intersection of lameness between gcc and gyp,
+ # we have to build the *_SSE2.cpp files in a separate target. The
+ # gcc lameness is that, in order to compile SSE2 intrinsics code, it
+ # must be passed the -msse2 flag. However, with this flag, it may
+ # emit SSE2 instructions even for scalar code, such as the CPUID
+ # test used to test for the presence of SSE2. So that, and all other
+ # code must be compiled *without* -msse2. The gyp lameness is that it
+ # does not allow file-specific CFLAGS, so we must create this extra
+ # target for those files to be compiled with -msse2.
+ #
+ # This is actually only a problem on 32-bit Linux (all Intel Macs have
+ # SSE2, Linux x86_64 has SSE2 by definition, and MSC will happily emit
+ # SSE2 from instrinsics, while generating plain ol' 386 for everything
+ # else). However, to keep the .gyp file simple and avoid platform-specific
+ # build breakage, we do this on all platforms.
+
+ # For about the same reason, we need to compile the ARM opts files
+ # separately as well.
+ {
+ 'target_name': 'opts',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../include/config',
+ '../include/core',
+ '../src/core',
+ '../src/opts',
+ ],
+ 'conditions': [
+ [ 'skia_os in ["linux", "freebsd", "openbsd", "solaris"]', {
+ 'cflags': [
+ '-msse2',
+ ],
+ }],
+ [ 'skia_target_arch != "arm"', {
+ 'sources': [
+ '../src/opts/opts_check_SSE2.cpp',
+ '../src/opts/SkBitmapProcState_opts_SSE2.cpp',
+ '../src/opts/SkBlitRow_opts_SSE2.cpp',
+ '../src/opts/SkUtils_opts_SSE2.cpp',
+ ],
+ }],
+ [ 'skia_target_arch == "arm" and armv7 == 1', {
+ # The assembly uses the frame pointer register (r7 in Thumb/r11 in
+ # ARM), the compiler doesn't like that.
+ 'cflags!': [
+ '-fno-omit-frame-pointer',
+ ],
+ 'cflags': [
+ '-fomit-frame-pointer',
+ ],
+ 'sources': [
+ '../src/opts/opts_check_arm.cpp',
+ '../src/opts/memset.arm.S',
+ '../src/opts/memset16_neon.S',
+ '../src/opts/memset32_neon.S',
+ '../src/opts/SkBitmapProcState_opts_arm.cpp',
+ '../src/opts/SkBlitRow_opts_arm.cpp',
+ ],
+ }],
+ [ 'skia_target_arch == "arm" and armv7 != 1', {
+ 'sources': [
+ '../src/opts/SkBitmapProcState_opts_none.cpp',
+ '../src/opts/SkBlitRow_opts_none.cpp',
+ '../src/opts/SkUtils_opts_none.cpp',
+ ],
+ }],
+ ],
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/pdf.gyp b/gyp/pdf.gyp
new file mode 100644
index 0000000..f0c6b47
--- /dev/null
+++ b/gyp/pdf.gyp
@@ -0,0 +1,66 @@
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'pdf',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../include/config',
+ '../include/core',
+ '../include/pdf',
+ '../src/core', # needed to get SkGlyphCache.h and SkTextFormatParams.h
+ ],
+ 'sources': [
+ '../include/pdf/SkBitSet.h',
+ '../include/pdf/SkPDFCatalog.h',
+ '../include/pdf/SkPDFDevice.h',
+ '../include/pdf/SkPDFDocument.h',
+ '../include/pdf/SkPDFFont.h',
+ '../include/pdf/SkPDFFormXObject.h',
+ '../include/pdf/SkPDFGraphicState.h',
+ '../include/pdf/SkPDFImage.h',
+ '../include/pdf/SkPDFPage.h',
+ '../include/pdf/SkPDFShader.h',
+ '../include/pdf/SkPDFStream.h',
+ '../include/pdf/SkPDFTypes.h',
+ '../include/pdf/SkPDFUtils.h',
+
+ '../src/pdf/SkBitSet.cpp',
+ '../src/pdf/SkPDFCatalog.cpp',
+ '../src/pdf/SkPDFDevice.cpp',
+ '../src/pdf/SkPDFDocument.cpp',
+ '../src/pdf/SkPDFFont.cpp',
+ '../src/pdf/SkPDFFontImpl.h',
+ '../src/pdf/SkPDFFormXObject.cpp',
+ '../src/pdf/SkPDFGraphicState.cpp',
+ '../src/pdf/SkPDFImage.cpp',
+ '../src/pdf/SkPDFPage.cpp',
+ '../src/pdf/SkPDFShader.cpp',
+ '../src/pdf/SkPDFStream.cpp',
+ '../src/pdf/SkPDFTypes.cpp',
+ '../src/pdf/SkPDFUtils.cpp',
+ ],
+ # This section makes all targets that depend on this target
+ # #define SK_SUPPORT_PDF and have access to the pdf header files.
+ 'direct_dependent_settings': {
+ 'defines': [
+ 'SK_SUPPORT_PDF',
+ ],
+ 'include_dirs': [
+ '../include/pdf',
+ ],
+ },
+ 'dependencies': [
+ 'zlib.gyp:zlib',
+ ],
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/ports.gyp b/gyp/ports.gyp
new file mode 100644
index 0000000..c89a06d
--- /dev/null
+++ b/gyp/ports.gyp
@@ -0,0 +1,114 @@
+# Port-specific Skia library code.
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'ports',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../include/config',
+ '../include/core',
+ '../include/images',
+ '../include/effects',
+ '../include/ports',
+ '../include/xml',
+ '../src/core',
+ ],
+ 'sources': [
+ '../src/ports/SkDebug_stdio.cpp',
+ '../src/ports/SkDebug_win.cpp',
+ '../src/ports/SkFontHost_sandbox_none.cpp',
+ '../src/ports/SkFontHost_win.cpp',
+ '../src/ports/SkGlobalInitialization_default.cpp',
+ '../src/ports/SkThread_win.cpp',
+
+ '../src/ports/SkFontHost_tables.cpp',
+ '../src/ports/SkMemory_malloc.cpp',
+ '../src/ports/SkOSFile_stdio.cpp',
+ '../src/ports/SkTime_Unix.cpp',
+ '../src/ports/SkTime_win.cpp',
+ '../src/ports/SkXMLParser_empty.cpp',
+ '../src/ports/sk_predefined_gamma.h',
+ ],
+ 'conditions': [
+ [ 'skia_os in ["linux", "freebsd", "openbsd", "solaris"]', {
+ 'sources': [
+ '../src/ports/SkThread_pthread.cpp',
+ '../src/ports/SkFontHost_FreeType.cpp',
+ '../src/ports/SkFontHost_gamma_none.cpp',
+ '../src/ports/SkFontHost_linux.cpp',
+ ],
+ }],
+ [ 'skia_os == "mac"', {
+ 'include_dirs': [
+ '../include/utils/mac',
+ '../third_party/freetype/include/**',
+ ],
+ 'sources': [
+ '../src/ports/SkFontHost_mac_coretext.cpp',
+# '../src/ports/SkFontHost_FreeType.cpp',
+# '../src/ports/SkFontHost_freetype_mac.cpp',
+# '../src/ports/SkFontHost_gamma_none.cpp',
+ '../src/ports/SkThread_pthread.cpp',
+ ],
+ }],
+ [ 'skia_os == "ios"', {
+ 'include_dirs': [
+ '../include/utils/ios',
+ ],
+ 'sources': [
+ '../src/ports/SkFontHost_mac_coretext.cpp',
+ '../src/ports/SkThread_pthread.cpp',
+ ],
+ }],
+ [ 'skia_os == "win"', {
+ 'include_dirs': [
+ 'config/win',
+ ],
+ 'sources!': [ # these are used everywhere but windows
+ '../src/ports/SkDebug_stdio.cpp',
+ '../src/ports/SkTime_Unix.cpp',
+ ],
+ }, { # else !win
+ 'sources!': [
+ '../src/ports/SkDebug_win.cpp',
+ '../src/ports/SkFontHost_win.cpp',
+ '../src/ports/SkThread_win.cpp',
+ '../src/ports/SkTime_win.cpp',
+ ],
+ }],
+ [ 'skia_os == "android"', {
+ 'sources!': [
+ '../src/ports/SkDebug_stdio.cpp',
+ ],
+ 'sources': [
+ '../src/ports/SkDebug_android.cpp',
+ '../src/ports/SkThread_pthread.cpp',
+ '../src/ports/SkFontHost_android.cpp',
+ '../src/ports/SkFontHost_gamma.cpp',
+ '../src/ports/SkFontHost_FreeType.cpp',
+ '../src/ports/FontHostConfiguration_android.cpp',
+ #TODO: include the ports/SkImageRef_ashmem.cpp for non-NDK builds
+ ],
+ 'dependencies': [
+ 'android_system.gyp:ft2',
+ 'android_system.gyp:expat',
+ ],
+ }],
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../include/ports',
+ ],
+ },
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/svg.gyp b/gyp/svg.gyp
new file mode 100644
index 0000000..c72b99f
--- /dev/null
+++ b/gyp/svg.gyp
@@ -0,0 +1,91 @@
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'svg',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../include/config',
+ '../include/core',
+ '../include/xml',
+ '../include/utils',
+ '../include/svg',
+ ],
+ 'sources': [
+ '../include/svg/SkSVGAttribute.h',
+ '../include/svg/SkSVGBase.h',
+ '../include/svg/SkSVGPaintState.h',
+ '../include/svg/SkSVGParser.h',
+ '../include/svg/SkSVGTypes.h',
+
+ '../src/svg/SkSVGCircle.cpp',
+ '../src/svg/SkSVGCircle.h',
+ '../src/svg/SkSVGClipPath.cpp',
+ '../src/svg/SkSVGClipPath.h',
+ '../src/svg/SkSVGDefs.cpp',
+ '../src/svg/SkSVGDefs.h',
+ '../src/svg/SkSVGElements.cpp',
+ '../src/svg/SkSVGElements.h',
+ '../src/svg/SkSVGEllipse.cpp',
+ '../src/svg/SkSVGEllipse.h',
+ '../src/svg/SkSVGFeColorMatrix.cpp',
+ '../src/svg/SkSVGFeColorMatrix.h',
+ '../src/svg/SkSVGFilter.cpp',
+ '../src/svg/SkSVGFilter.h',
+ '../src/svg/SkSVGG.cpp',
+ '../src/svg/SkSVGG.h',
+ '../src/svg/SkSVGGradient.cpp',
+ '../src/svg/SkSVGGradient.h',
+ '../src/svg/SkSVGGroup.cpp',
+ '../src/svg/SkSVGGroup.h',
+ '../src/svg/SkSVGImage.cpp',
+ '../src/svg/SkSVGImage.h',
+ '../src/svg/SkSVGLine.cpp',
+ '../src/svg/SkSVGLine.h',
+ '../src/svg/SkSVGLinearGradient.cpp',
+ '../src/svg/SkSVGLinearGradient.h',
+ '../src/svg/SkSVGMask.cpp',
+ '../src/svg/SkSVGMask.h',
+ '../src/svg/SkSVGMetadata.cpp',
+ '../src/svg/SkSVGMetadata.h',
+ '../src/svg/SkSVGPaintState.cpp',
+ '../src/svg/SkSVGParser.cpp',
+ '../src/svg/SkSVGPath.cpp',
+ '../src/svg/SkSVGPath.h',
+ '../src/svg/SkSVGPolygon.cpp',
+ '../src/svg/SkSVGPolygon.h',
+ '../src/svg/SkSVGPolyline.cpp',
+ '../src/svg/SkSVGPolyline.h',
+ '../src/svg/SkSVGRadialGradient.cpp',
+ '../src/svg/SkSVGRadialGradient.h',
+ '../src/svg/SkSVGRect.cpp',
+ '../src/svg/SkSVGRect.h',
+ '../src/svg/SkSVGStop.cpp',
+ '../src/svg/SkSVGStop.h',
+ '../src/svg/SkSVGSVG.cpp',
+ '../src/svg/SkSVGSVG.h',
+ '../src/svg/SkSVGSymbol.cpp',
+ '../src/svg/SkSVGSymbol.h',
+ '../src/svg/SkSVGText.cpp',
+ '../src/svg/SkSVGText.h',
+ '../src/svg/SkSVGUse.cpp',
+ ],
+ 'sources!' : [
+ '../src/svg/SkSVG.cpp', # doesn't compile, maybe this is test code?
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../include/svg',
+ ],
+ },
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/tests.gyp b/gyp/tests.gyp
new file mode 100644
index 0000000..27a34a0
--- /dev/null
+++ b/gyp/tests.gyp
@@ -0,0 +1,95 @@
+# GYP file to build unit tests.
+{
+ 'includes': [
+ 'apptype_console.gypi',
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'tests',
+ 'type': 'executable',
+ 'include_dirs' : [
+ '../src/core',
+ '../src/gpu',
+ ],
+ 'sources': [
+ '../tests/AAClipTest.cpp',
+ '../tests/BitmapCopyTest.cpp',
+ '../tests/BitmapGetColorTest.cpp',
+ '../tests/BitSetTest.cpp',
+ '../tests/BlitRowTest.cpp',
+ '../tests/BlurTest.cpp',
+ '../tests/CanvasTest.cpp',
+ '../tests/ClampRangeTest.cpp',
+ '../tests/ClipCubicTest.cpp',
+ '../tests/ClipStackTest.cpp',
+ '../tests/ClipperTest.cpp',
+ '../tests/ColorFilterTest.cpp',
+ '../tests/ColorTest.cpp',
+ '../tests/DataRefTest.cpp',
+ '../tests/DequeTest.cpp',
+ '../tests/DrawBitmapRectTest.cpp',
+ '../tests/EmptyPathTest.cpp',
+ '../tests/FillPathTest.cpp',
+ '../tests/FlateTest.cpp',
+ '../tests/GeometryTest.cpp',
+ '../tests/GLInterfaceValidation.cpp',
+ '../tests/GLProgramsTest.cpp',
+ '../tests/InfRectTest.cpp',
+ '../tests/MathTest.cpp',
+ '../tests/MatrixTest.cpp',
+ '../tests/Matrix44Test.cpp',
+ '../tests/MemsetTest.cpp',
+ '../tests/MetaDataTest.cpp',
+ '../tests/PackBitsTest.cpp',
+ '../tests/PaintTest.cpp',
+ '../tests/ParsePathTest.cpp',
+ '../tests/PathCoverageTest.cpp',
+ '../tests/PathMeasureTest.cpp',
+ '../tests/PathTest.cpp',
+ '../tests/PDFPrimitivesTest.cpp',
+ '../tests/PointTest.cpp',
+ '../tests/QuickRejectTest.cpp',
+ '../tests/Reader32Test.cpp',
+ '../tests/ReadPixelsTest.cpp',
+ '../tests/RefDictTest.cpp',
+ '../tests/RegionTest.cpp',
+ '../tests/ScalarTest.cpp',
+ '../tests/ShaderOpacityTest.cpp',
+ '../tests/Sk64Test.cpp',
+ '../tests/skia_test.cpp',
+ '../tests/SortTest.cpp',
+ '../tests/SrcOverTest.cpp',
+ '../tests/StreamTest.cpp',
+ '../tests/StringTest.cpp',
+ '../tests/Test.cpp',
+ '../tests/Test.h',
+ '../tests/TestSize.cpp',
+ '../tests/ToUnicode.cpp',
+ '../tests/UnicodeTest.cpp',
+ '../tests/UtilsTest.cpp',
+ '../tests/WArrayTest.cpp',
+ '../tests/WritePixelsTest.cpp',
+ '../tests/Writer32Test.cpp',
+ '../tests/XfermodeTest.cpp',
+ ],
+ 'dependencies': [
+ 'core.gyp:core',
+ 'effects.gyp:effects',
+ 'experimental.gyp:experimental',
+ 'gpu.gyp:gr',
+ 'gpu.gyp:skgr',
+ 'images.gyp:images',
+ 'ports.gyp:ports',
+ 'pdf.gyp:pdf',
+ 'utils.gyp:utils',
+ ],
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/tools.gyp b/gyp/tools.gyp
new file mode 100644
index 0000000..1e419cd
--- /dev/null
+++ b/gyp/tools.gyp
@@ -0,0 +1,73 @@
+# GYP file to build various tools.
+#
+# To build on Linux:
+# ./gyp_skia tools.gyp && make tools
+#
+# Building on other platforms not tested yet.
+#
+{
+ 'includes': [
+ 'apptype_console.gypi',
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ # Build all executable targets defined below.
+ 'target_name': 'tools',
+ 'type': 'none',
+ 'dependencies': [
+ 'skdiff',
+ 'skhello',
+ 'skimage',
+ ],
+ },
+ {
+ 'target_name': 'skdiff',
+ 'type': 'executable',
+ 'sources': [
+ '../src/effects/SkEffects_none.cpp',
+ '../tools/skdiff_main.cpp',
+ ],
+ 'dependencies': [
+ 'core.gyp:core',
+ 'images.gyp:images',
+ 'ports.gyp:ports',
+ 'utils.gyp:utils',
+ ],
+ },
+ {
+ 'target_name': 'skhello',
+ 'type': 'executable',
+ 'sources': [
+ '../src/effects/SkEffects_none.cpp',
+ '../tools/skhello.cpp',
+ ],
+ 'dependencies': [
+ 'core.gyp:core',
+ 'images.gyp:images',
+ 'ports.gyp:ports',
+ 'utils.gyp:utils',
+ ],
+ },
+ {
+ 'target_name': 'skimage',
+ 'type': 'executable',
+ 'sources': [
+ '../src/effects/SkEffects_none.cpp',
+ '../tools/skimage_main.cpp',
+ ],
+ 'dependencies': [
+ 'core.gyp:core',
+ 'images.gyp:images',
+ 'ports.gyp:ports',
+ 'utils.gyp:utils',
+ ],
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/utils.gyp b/gyp/utils.gyp
new file mode 100644
index 0000000..b4b2be3
--- /dev/null
+++ b/gyp/utils.gyp
@@ -0,0 +1,161 @@
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'utils',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../include/config',
+ '../include/core',
+ '../include/utils',
+ '../include/utils/mac',
+ '../include/utils/unix',
+ '../include/utils/win',
+ '../include/views',
+ '../include/effects',
+ '../include/xml',
+ ],
+ 'sources': [
+ '../include/utils/SkBoundaryPatch.h',
+ '../include/utils/SkCamera.h',
+ '../include/utils/SkCubicInterval.h',
+ '../include/utils/SkCullPoints.h',
+ '../include/utils/SkDumpCanvas.h',
+ '../include/utils/SkInterpolator.h',
+ '../include/utils/SkLayer.h',
+ '../include/utils/SkMatrix44.h',
+ '../include/utils/SkMeshUtils.h',
+ '../include/utils/SkNinePatch.h',
+ '../include/utils/SkNWayCanvas.h',
+ '../include/utils/SkParse.h',
+ '../include/utils/SkParsePaint.h',
+ '../include/utils/SkParsePath.h',
+ '../include/utils/SkProxyCanvas.h',
+ '../include/utils/SkSfntUtils.h',
+ '../include/utils/SkTextBox.h',
+ '../include/utils/SkUnitMappers.h',
+ '../include/utils/SkWGL.h',
+
+ '../src/utils/SkBoundaryPatch.cpp',
+ '../src/utils/SkCamera.cpp',
+ '../src/utils/SkColorMatrix.cpp',
+ '../src/utils/SkCubicInterval.cpp',
+ '../src/utils/SkCullPoints.cpp',
+ '../src/utils/SkDumpCanvas.cpp',
+ '../src/utils/SkInterpolator.cpp',
+ '../src/utils/SkLayer.cpp',
+ '../src/utils/SkMatrix44.cpp',
+ '../src/utils/SkMeshUtils.cpp',
+ '../src/utils/SkNinePatch.cpp',
+ '../src/utils/SkNWayCanvas.cpp',
+ '../src/utils/SkOSFile.cpp',
+ '../src/utils/SkParse.cpp',
+ '../src/utils/SkParseColor.cpp',
+ '../src/utils/SkParsePath.cpp',
+ '../src/utils/SkProxyCanvas.cpp',
+ '../src/utils/SkSfntUtils.cpp',
+ '../src/utils/SkUnitMappers.cpp',
+
+ #mac
+ '../include/utils/mac/SkCGUtils.h',
+ '../src/utils/mac/SkCreateCGImageRef.cpp',
+
+ #sdl
+ '../src/utils/SDL/SkOSWindow_SDL.cpp',
+
+ #*nix
+ '../src/utils/unix/keysym2ucs.c',
+ '../src/utils/unix/SkOSWindow_Unix.cpp',
+
+ #windows
+ '../include/utils/win/SkAutoCoInitialize.h',
+ '../include/utils/win/SkHRESULT.h',
+ '../include/utils/win/SkIStream.h',
+ '../include/utils/win/SkTScopedComPtr.h',
+ '../src/utils/win/SkAutoCoInitialize.cpp',
+ '../src/utils/win/skia_win.cpp',
+ '../src/utils/win/SkHRESULT.cpp',
+ '../src/utils/win/SkIStream.cpp',
+ '../src/utils/win/SkOSWindow_win.cpp',
+ '../src/utils/win/SkWGL_win.cpp',
+ ],
+ 'sources!': [
+ '../src/utils/SDL/SkOSWindow_SDL.cpp',
+ ],
+ 'conditions': [
+ [ 'skia_os == "mac"', {
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/AGL.framework',
+ ],
+ },
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../include/utils/mac',
+ ],
+ },
+ },{ #else if 'skia_os != "mac"'
+ 'include_dirs!': [
+ '../include/utils/mac',
+ ],
+ 'sources!': [
+ '../include/utils/mac/SkCGUtils.h',
+ '../src/utils/mac/SkCreateCGImageRef.cpp',
+ '../src/utils/mac/skia_mac.mm',
+ '../src/utils/mac/SkOSWindow_Mac.mm',
+ ],
+ }],
+ [ 'skia_os in ["linux", "freebsd", "openbsd", "solaris"]', {
+ 'link_settings': {
+ 'libraries': [
+ '-lGL',
+ '-lGLU',
+ ],
+ },
+ },{ #else if 'skia_os not in ["linux", "freebsd", "openbsd", "solaris"]'
+ 'include_dirs!': [
+ '../include/utils/unix',
+ ],
+ 'sources!': [
+ '../src/utils/unix/keysym2ucs.c',
+ '../src/utils/unix/SkOSWindow_Unix.cpp',
+ ],
+ }],
+ [ 'skia_os == "win"', {
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../include/utils/win',
+ ],
+ },
+ },{ #else if 'skia_os != "win"'
+ 'include_dirs!': [
+ '../include/utils/win',
+ ],
+ 'sources/': [ ['exclude', '_win.(h|cpp)$'],],
+ 'sources!': [
+ '../include/utils/win/SkAutoCoInitialize.h',
+ '../include/utils/win/SkHRESULT.h',
+ '../include/utils/win/SkIStream.h',
+ '../include/utils/win/SkTScopedComPtr.h',
+ '../src/utils/win/SkAutoCoInitialize.cpp',
+ '../src/utils/win/SkHRESULT.cpp',
+ '../src/utils/win/SkIStream.cpp',
+ ],
+ }],
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../include/utils',
+ ],
+ },
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/views.gyp b/gyp/views.gyp
new file mode 100644
index 0000000..e91b28e
--- /dev/null
+++ b/gyp/views.gyp
@@ -0,0 +1,118 @@
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'views',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../include/config',
+ '../include/core',
+ '../include/views',
+ '../include/xml',
+ '../include/utils',
+ '../include/images',
+ '../include/animator',
+ '../include/effects',
+ ],
+ 'sources': [
+ '../include/views/SkApplication.h',
+ '../include/views/SkBGViewArtist.h',
+ '../include/views/SkBorderView.h',
+ '../include/views/SkEvent.h',
+ '../include/views/SkEventSink.h',
+ '../include/views/SkImageView.h',
+ '../include/views/SkKey.h',
+ '../include/views/SkOSMenu.h',
+ '../include/views/SkOSWindow_Mac.h',
+ '../include/views/SkOSWindow_SDL.h',
+ '../include/views/SkOSWindow_Unix.h',
+ '../include/views/SkOSWindow_Win.h',
+ #'../include/views/SkOSWindow_wxwidgets.h',
+ '../include/views/SkProgressBarView.h',
+ '../include/views/SkScrollBarView.h',
+ '../include/views/SkStackViewLayout.h',
+ '../include/views/SkSystemEventTypes.h',
+ '../include/views/SkTouchGesture.h',
+ '../include/views/SkView.h',
+ '../include/views/SkViewInflate.h',
+ '../include/views/SkWidget.h',
+ '../include/views/SkWidgetViews.h',
+ '../include/views/SkWindow.h',
+
+ '../src/views/SkBGViewArtist.cpp',
+ '../src/views/SkBorderView.cpp',
+ '../src/views/SkEvent.cpp',
+ '../src/views/SkEventSink.cpp',
+ '../src/views/SkImageView.cpp',
+ '../src/views/SkListView.cpp',
+ '../src/views/SkListWidget.cpp',
+ '../src/views/SkOSMenu.cpp',
+ '../src/views/SkParsePaint.cpp',
+ '../src/views/SkProgressBarView.cpp',
+ '../src/views/SkProgressView.cpp',
+ '../src/views/SkScrollBarView.cpp',
+ '../src/views/SkStackViewLayout.cpp',
+ '../src/views/SkStaticTextView.cpp',
+ '../src/views/SkTagList.cpp',
+ '../src/views/SkTagList.h',
+ '../src/views/SkTextBox.cpp',
+ '../src/views/SkTouchGesture.cpp',
+ '../src/views/SkView.cpp',
+ '../src/views/SkViewInflate.cpp',
+ '../src/views/SkViewPriv.cpp',
+ '../src/views/SkViewPriv.h',
+ '../src/views/SkWidget.cpp',
+ '../src/views/SkWidgets.cpp',
+ '../src/views/SkWidgetViews.cpp',
+ '../src/views/SkWindow.cpp',
+ ],
+ 'sources!' : [
+ '../src/views/SkListView.cpp', #depends on missing SkListSource implementation
+ '../src/views/SkListWidget.cpp', #depends on missing SkListSource implementation
+ ],
+ 'conditions': [
+ [ 'skia_os == "mac"', {
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/Cocoa.framework',
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ ],
+ },
+ }],
+ [ 'skia_os in ["linux", "freebsd", "openbsd", "solaris"]', {
+ 'sources': [
+ '../unix_test_app/main.cpp',
+ ],
+ }],
+ [ 'skia_os == "android"', {
+ # Android does not support animator so we need to remove all files
+ # that have references to it.
+ 'include_dirs!': [
+ '../include/animator',
+ ],
+ 'sources!': [
+ '../src/views/SkBorderView.cpp',
+ '../src/views/SkImageView.cpp',
+ '../src/views/SkProgressBarView.cpp',
+ '../src/views/SkScrollBarView.cpp',
+ '../src/views/SkStaticTextView.cpp',
+ '../src/views/SkWidgetViews.cpp',
+ ],
+ }],
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../include/views',
+ ],
+ },
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/xml.gyp b/gyp/xml.gyp
new file mode 100644
index 0000000..7da8666
--- /dev/null
+++ b/gyp/xml.gyp
@@ -0,0 +1,58 @@
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'xml',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../include/config',
+ '../include/core',
+ '../include/xml',
+ '../include/utils',
+ ],
+ 'sources': [
+ '../include/xml/SkBML_WXMLParser.h',
+ '../include/xml/SkBML_XMLParser.h',
+ '../include/xml/SkDOM.h',
+ '../include/xml/SkJS.h',
+ '../include/xml/SkXMLParser.h',
+ '../include/xml/SkXMLWriter.h',
+
+ '../src/xml/SkBML_Verbs.h',
+ '../src/xml/SkBML_XMLParser.cpp',
+ '../src/xml/SkDOM.cpp',
+ '../src/xml/SkJS.cpp',
+ '../src/xml/SkJSDisplayable.cpp',
+ '../src/xml/SkXMLParser.cpp',
+ '../src/xml/SkXMLPullParser.cpp',
+ '../src/xml/SkXMLWriter.cpp',
+ ],
+ 'sources!': [
+ '../src/xml/SkXMLPullParser.cpp', #if 0 around class decl in header
+ ],
+ 'conditions': [
+ [ 'skia_os in ["win", "mac", "linux", "freebsd", "openbsd", "solaris", "android"]', {
+ 'sources!': [
+ # no jsapi.h by default on system
+ '../include/xml/SkJS.h',
+ '../src/xml/SkJS.cpp',
+ '../src/xml/SkJSDisplayable.cpp',
+ ],
+ }],
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '../include/xml',
+ ],
+ },
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/xps.gyp b/gyp/xps.gyp
new file mode 100644
index 0000000..ff68d6f
--- /dev/null
+++ b/gyp/xps.gyp
@@ -0,0 +1,67 @@
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'xps',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'core.gyp:core',
+ 'images.gyp:images',
+ 'utils.gyp:utils',
+ 'pdf.gyp:pdf', # needed to get SkBitSet
+ ],
+ 'include_dirs': [
+ '../include/device/xps',
+ '../include/utils/win',
+ '../src/core', # needed to get SkGlyphCache.h
+ ],
+ 'sources': [
+ '../include/device/xps/SkConstexprMath.h',
+ '../include/device/xps/SkXPSDevice.h',
+
+ '../src/device/xps/SkXPSDevice.cpp',
+ ],
+ 'conditions': [
+ [ 'skia_os == "win"', {
+ 'link_settings': {
+ 'libraries': [
+ 'T2Embed.lib',
+ 'FontSub.lib',
+ ],
+ },
+ },{ #else if 'skia_os != "win"'
+ 'include_dirs!': [
+ '../include/utils/win',
+ ],
+ 'sources!': [
+ '../include/device/xps/SkXPSDevice.h',
+
+ '../src/device/xps/SkXPSDevice.cpp',
+ ],
+ }],
+ ],
+ # This section makes all targets that depend on this target
+ # #define SK_SUPPORT_XPS and have access to the xps header files.
+ 'direct_dependent_settings': {
+ 'conditions': [
+ [ 'skia_os == "win"', {
+ 'defines': [
+ 'SK_SUPPORT_XPS',
+ ],
+ }],
+ ],
+ 'include_dirs': [
+ '../include/device/xps',
+ ],
+ },
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/gyp/zlib.gyp b/gyp/zlib.gyp
new file mode 100644
index 0000000..5ed9d14
--- /dev/null
+++ b/gyp/zlib.gyp
@@ -0,0 +1,40 @@
+{
+ 'includes': [
+ 'common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'zlib',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../include/config',
+ '../include/core',
+ ],
+ 'sources': [
+ '../include/core/SkFlate.h',
+
+ '../src/core/SkFlate.cpp',
+ ],
+ 'conditions': [
+ [ 'skia_os == "mac"', {
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/usr/lib/libz.dylib',
+ ],
+ },
+ 'defines': [ 'SK_ZLIB_INCLUDE=<zlib.h>', ],
+ }],
+ [ 'skia_os in ["linux", "freebsd", "openbsd", "solaris", "android"]', {
+ 'link_settings': { 'libraries': [ '-lz', ], },
+ 'defines': [ 'SK_ZLIB_INCLUDE=<zlib.h>', ],
+ }],
+ ],
+ },
+ ],
+}
+
+# Local Variables:
+# tab-width:2
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/include/animator/SkAnimator.h b/include/animator/SkAnimator.h
index 04d342c..e6c5583 100644
--- a/include/animator/SkAnimator.h
+++ b/include/animator/SkAnimator.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkAnimator_DEFINED
#define SkAnimator_DEFINED
diff --git a/include/animator/SkAnimatorView.h b/include/animator/SkAnimatorView.h
index 3c6c8a1..940dd26 100644
--- a/include/animator/SkAnimatorView.h
+++ b/include/animator/SkAnimatorView.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkAnimatorView_DEFINED
#define SkAnimatorView_DEFINED
diff --git a/include/config/SkUserConfig.h b/include/config/SkUserConfig.h
deleted file mode 100644
index c56d8cf..0000000
--- a/include/config/SkUserConfig.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SkUserConfig_DEFINED
-#define SkUserConfig_DEFINED
-
-/* SkTypes.h, the root of the public header files, does the following trick:
-
- #include "SkPreConfig.h"
- #include "SkUserConfig.h"
- #include "SkPostConfig.h"
-
- SkPreConfig.h runs first, and it is responsible for initializing certain
- skia defines.
-
- SkPostConfig.h runs last, and its job is to just check that the final
- defines are consistent (i.e. that we don't have mutually conflicting
- defines).
-
- SkUserConfig.h (this file) runs in the middle. It gets to change or augment
- the list of flags initially set in preconfig, and then postconfig checks
- that everything still makes sense.
-
- Below are optional defines that add, subtract, or change default behavior
- in Skia. Your port can locally edit this file to enable/disable flags as
- you choose, or these can be delared on your command line (i.e. -Dfoo).
-
- By default, this include file will always default to having all of the flags
- commented out, so including it will have no effect.
-*/
-
-///////////////////////////////////////////////////////////////////////////////
-
-/* Scalars (the fractional value type in skia) can be implemented either as
- floats or 16.16 integers (fixed). Exactly one of these two symbols must be
- defined.
-*/
-//#define SK_SCALAR_IS_FLOAT
-//#define SK_SCALAR_IS_FIXED
-
-
-/* Somewhat independent of how SkScalar is implemented, Skia also wants to know
- if it can use floats at all. Naturally, if SK_SCALAR_IS_FLOAT is defined,
- SK_CAN_USE_FLOAT must be too; but if scalars are fixed, SK_CAN_USE_FLOAT
- can go either way.
- */
-//#define SK_CAN_USE_FLOAT
-
-/* For some performance-critical scalar operations, skia will optionally work
- around the standard float operators if it knows that the CPU does not have
- native support for floats. If your environment uses software floating point,
- define this flag.
- */
-//#define SK_SOFTWARE_FLOAT
-
-
-/* Skia has lots of debug-only code. Often this is just null checks or other
- parameter checking, but sometimes it can be quite intrusive (e.g. check that
- each 32bit pixel is in premultiplied form). This code can be very useful
- during development, but will slow things down in a shipping product.
-
- By default, these mutually exclusive flags are defined in SkPreConfig.h,
- based on the presence or absence of NDEBUG, but that decision can be changed
- here.
- */
-//#define SK_DEBUG
-//#define SK_RELEASE
-
-
-/* If, in debugging mode, Skia needs to stop (presumably to invoke a debugger)
- it will call SK_CRASH(). If this is not defined it, it is defined in
- SkPostConfig.h to write to an illegal address
- */
-//#define SK_CRASH() *(int *)(uintptr_t)0 = 0
-
-
-/* preconfig will have attempted to determine the endianness of the system,
- but you can change these mutually exclusive flags here.
- */
-//#define SK_CPU_BENDIAN
-//#define SK_CPU_LENDIAN
-
-
-/* Some compilers don't support long long for 64bit integers. If yours does
- not, define this to the appropriate type.
- */
-//#define SkLONGLONG int64_t
-
-
-/* Some envorinments do not suport writable globals (eek!). If yours does not,
- define this flag.
- */
-//#define SK_USE_RUNTIME_GLOBALS
-
-
-/* To write debug messages to a console, skia will call SkDebugf(...) following
- printf conventions (e.g. const char* format, ...). If you want to redirect
- this to something other than printf, define yours here
- */
-//#define SkDebugf(...) MyFunction(__VA_ARGS__)
-
-/* To enable additional blitters (and fontscaler code) to support separate
- alpha channels for R G B channels, define SK_SUPPORT_LCDTEXT
- */
-//#define SK_SUPPORT_LCDTEXT
-
-/* If zlib is available and you want to support the flate compression
- algorithm (used in PDF generation), define SK_ZLIB_INCLUDE to be the
- include path.
- */
-//#define SK_ZLIB_INCLUDE <zlib.h>
-
-/* Define this to allow PDF scalars above 32k. The PDF/A spec doesn't allow
- them, but modern PDF interpreters should handle them just fine.
- */
-//#define SK_ALLOW_LARGE_PDF_SCALARS
-
-/* Define this to remove dimension checks on bitmaps. Not all blits will be
- correct yet, so this is mostly for debugging the implementation.
- */
-//#define SK_ALLOW_OVER_32K_BITMAPS
-
-/* If SK_DEBUG is defined, then you can optionally define SK_SUPPORT_UNITTEST
- which will run additional self-tests at startup. These can take a long time,
- so this flag is optional.
- */
-#ifdef SK_DEBUG
-//#define SK_SUPPORT_UNITTEST
-#endif
-
-/* Change the ordering to work in X windows.
- */
-#ifdef SK_SAMPLES_FOR_X
- #define SK_R32_SHIFT 16
- #define SK_G32_SHIFT 8
- #define SK_B32_SHIFT 0
- #define SK_A32_SHIFT 24
-#endif
-
-#endif
diff --git a/include/config/sk_stdint.h b/include/config/sk_stdint.h
index 9a5f5ca..360755e 100644
--- a/include/config/sk_stdint.h
+++ b/include/config/sk_stdint.h
@@ -1,13 +1,23 @@
-#ifndef sk_stdint_DEFINED
-#define sk_stdint_DEFINED
-
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef short int16_t;
-typedef unsigned short uint16_t;
-typedef int int32_t;
-typedef unsigned uint32_t;
-typedef long long int64_t;
-typedef unsigned long long uint64_t;
-
-#endif
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef sk_stdint_DEFINED
+#define sk_stdint_DEFINED
+
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef int int32_t;
+typedef unsigned uint32_t;
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+#endif
diff --git a/include/core/Sk64.h b/include/core/Sk64.h
index b40b27f..b86e0be 100644
--- a/include/core/Sk64.h
+++ b/include/core/Sk64.h
@@ -1,24 +1,16 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef Sk64_DEFINED
#define Sk64_DEFINED
#include "SkFixed.h"
-#include "SkMath.h"
/** \class Sk64
diff --git a/include/core/SkAdvancedTypefaceMetrics.h b/include/core/SkAdvancedTypefaceMetrics.h
index 1b81909..09fc9a9 100644..100755
--- a/include/core/SkAdvancedTypefaceMetrics.h
+++ b/include/core/SkAdvancedTypefaceMetrics.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2011 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2011 Google Inc.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkAdvancedTypefaceMetrics_DEFINED
#define SkAdvancedTypefaceMetrics_DEFINED
@@ -139,10 +132,21 @@ void finishRange(
typename SkAdvancedTypefaceMetrics::AdvanceMetric<Data>::MetricType
type);
+/** Retrieve advance data for glyphs. Used by the PDF backend. It calls
+ underlying platform dependent API getAdvance to acquire the data.
+ @param num_glyphs Total number of glyphs in the given font.
+ @param glyphIDs For per-glyph info, specify subset of the font by
+ giving glyph ids. Each integer represents a glyph
+ id. Passing NULL means all glyphs in the font.
+ @param glyphIDsCount Number of elements in subsetGlyphIds. Ignored if
+ glyphIDs is NULL.
+*/
template <typename Data, typename FontHandle>
SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* getAdvanceData(
FontHandle fontHandle,
int num_glyphs,
+ const uint32_t* glyphIDs,
+ uint32_t glyphIDsCount,
bool (*getAdvance)(FontHandle fontHandle, int gId, Data* data));
} // namespace skia_advanced_typeface_metrics_utils
diff --git a/include/core/SkAutoKern.h b/include/core/SkAutoKern.h
index 023cb6b..7a5cdef 100644
--- a/include/core/SkAutoKern.h
+++ b/include/core/SkAutoKern.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkAutoKern.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkAutoKern_DEFINED
#define SkAutoKern_DEFINED
diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h
index 91143c1..57b80e5 100644
--- a/include/core/SkBitmap.h
+++ b/include/core/SkBitmap.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkBitmap_DEFINED
#define SkBitmap_DEFINED
@@ -165,14 +158,41 @@ public:
*/
Sk64 getSafeSize64() const ;
+ /** Returns true if this bitmap is marked as immutable, meaning that the
+ contents of its pixels will not change for the lifetime of the bitmap.
+ */
+ bool isImmutable() const;
+
+ /** Marks this bitmap as immutable, meaning that the contents of its
+ pixels will not change for the lifetime of the bitmap and of the
+ underlying pixelref. This state can be set, but it cannot be
+ cleared once it is set. This state propagates to all other bitmaps
+ that share the same pixelref.
+ */
+ void setImmutable();
+
/** 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);
+ /** Returns true if the bitmap is volatile (i.e. should not be cached by devices.)
+ */
+ bool isVolatile() const;
+
+ /** Specify whether this bitmap is volatile. Bitmaps are not volatile by
+ default. Temporary bitmaps that are discarded after use should be
+ marked as volatile. This provides a hint to the device that the bitmap
+ should not be cached. Providing this hint when appropriate can
+ improve performance by avoiding unnecessary overhead and resource
+ consumption on the device.
+ */
+ void setIsVolatile(bool);
+
/** Reset the bitmap to its initial state (see default constructor). If we are a (shared)
owner of the pixels, that ownership is decremented.
*/
@@ -218,12 +238,11 @@ public:
/** Copies the bitmap's pixels to the location pointed at by dst and returns
true if possible, returns false otherwise.
- In the event that the bitmap's stride is equal to dstRowBytes, and if
- it is greater than strictly required by the bitmap's current config
- (this may happen if the bitmap is an extracted subset of another), then
- this function will copy bytes past the eand of each row, excluding the
- last row. No copies are made outside of the declared size of dst,
- however.
+ In the case when the dstRowBytes matches the bitmap's rowBytes, the copy
+ may be made faster by copying over the dst's per-row padding (for all
+ rows but the last). By setting preserveDstPad to true the caller can
+ disable this optimization and ensure that pixels in the padding are not
+ overwritten.
Always returns false for RLE formats.
@@ -232,27 +251,12 @@ public:
pixels using indicated stride.
@param dstRowBytes Width of each line in the buffer. If -1, uses
bitmap's internal stride.
+ @param preserveDstPad Must we preserve padding in the dst
*/
- bool copyPixelsTo(void* const dst, size_t dstSize, int dstRowBytes = -1)
+ bool copyPixelsTo(void* const dst, size_t dstSize, int dstRowBytes = -1,
+ bool preserveDstPad = false)
const;
- /** Copies the pixels at location src to the bitmap's pixel buffer.
- Returns true if copy if possible (bitmap buffer is large enough),
- false otherwise.
-
- Like copyPixelsTo, this function may write values beyond the end of
- each row, although never outside the defined buffer.
-
- Always returns false for RLE formats.
-
- @param src Location of the source buffer.
- @param srcSize Height of source buffer in pixels.
- @param srcRowBytes Width of each line in the buffer. If -1, uses i
- bitmap's internal stride.
- */
- bool copyPixelsFrom(const void* const src, size_t srcSize,
- int srcRowBytes = -1);
-
/** Use the standard HeapAllocator to create the pixelref that manages the
pixel memory. It will be sized based on the current width/height/config.
If this is called multiple times, a new pixelref object will be created
@@ -316,6 +320,14 @@ public:
*/
void unlockPixels() const;
+ /**
+ * Some bitmaps can return a copy of their pixels for lockPixels(), but
+ * that copy, if modified, will not be pushed back. These bitmaps should
+ * not be used as targets for a raster device/canvas (since all pixels
+ * modifications will be lost when unlockPixels() is called.)
+ */
+ bool lockPixelsAreWritable() const;
+
/** Call this to be sure that the bitmap is valid enough to be drawn (i.e.
it has non-null pixels, and if required by its config, it has a
non-null colortable. Returns true if all of the above are met.
@@ -463,19 +475,29 @@ public:
*/
bool extractSubset(SkBitmap* dst, const SkIRect& subset) const;
- /** Makes a deep copy of this bitmap, respecting the requested config.
- Returns false if either there is an error (i.e. the src does not have
- pixels) or the request cannot be satisfied (e.g. the src has per-pixel
- alpha, and the requested config does not support alpha).
- @param dst The bitmap to be sized and allocated
- @param c The desired config for dst
- @param allocator Allocator used to allocate the pixelref for the dst
- bitmap. If this is null, the standard HeapAllocator
- will be used.
- @return true if the copy could be made.
- */
+ /** Makes a deep copy of this bitmap, respecting the requested config,
+ * and allocating the dst pixels on the cpu.
+ * Returns false if either there is an error (i.e. the src does not have
+ * pixels) or the request cannot be satisfied (e.g. the src has per-pixel
+ * alpha, and the requested config does not support alpha).
+ * @param dst The bitmap to be sized and allocated
+ * @param c The desired config for dst
+ * @param allocator Allocator used to allocate the pixelref for the dst
+ * bitmap. If this is null, the standard HeapAllocator
+ * will be used.
+ * @return true if the copy could be made.
+ */
bool copyTo(SkBitmap* dst, Config c, Allocator* allocator = NULL) const;
+ /** Makes a deep copy of this bitmap, respecting the requested config, and
+ * with custom allocation logic that will keep the copied pixels
+ * in the same domain as the source: If the src pixels are allocated for
+ * the cpu, then so will the dst. If the src pixels are allocated on the
+ * gpu (typically as a texture), the it will do the same for the dst.
+ * If the request cannot be fulfilled, returns false and dst is unmodified.
+ */
+ bool deepCopyTo(SkBitmap* dst, Config c) const;
+
/** Returns true if this bitmap can be deep copied into the requested config
by calling copyTo().
*/
@@ -580,7 +602,9 @@ private:
mutable int fRawPixelGenerationID;
enum Flags {
- kImageIsOpaque_Flag = 0x01
+ kImageIsOpaque_Flag = 0x01,
+ kImageIsVolatile_Flag = 0x02,
+ kImageIsImmutable_Flag = 0x04
};
uint32_t fRowBytes;
@@ -698,17 +722,23 @@ private:
void inval16BitCache();
};
-class SkAutoLockPixels {
+class SkAutoLockPixels : public SkNoncopyable {
public:
- SkAutoLockPixels(const SkBitmap& bitmap) : fBitmap(bitmap) {
- bitmap.lockPixels();
+ SkAutoLockPixels(const SkBitmap& bm, bool doLock = true) : fBitmap(bm) {
+ fDidLock = doLock;
+ if (doLock) {
+ bm.lockPixels();
+ }
}
~SkAutoLockPixels() {
- fBitmap.unlockPixels();
+ if (fDidLock) {
+ fBitmap.unlockPixels();
+ }
}
private:
const SkBitmap& fBitmap;
+ bool fDidLock;
};
/** Helper class that performs the lock/unlockColors calls on a colortable.
diff --git a/include/core/SkBlitRow.h b/include/core/SkBlitRow.h
index bb8cbc2..fb62f5a 100644
--- a/include/core/SkBlitRow.h
+++ b/include/core/SkBlitRow.h
@@ -1,3 +1,10 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkBlitRow_DEFINED
#define SkBlitRow_DEFINED
@@ -25,8 +32,8 @@ public:
@param x The x coordinate of the beginning of the scanline
@param y THe y coordinate of the scanline
*/
- typedef void (*Proc)(uint16_t* SK_RESTRICT dst,
- const SkPMColor* SK_RESTRICT src,
+ typedef void (*Proc)(uint16_t* dst,
+ const SkPMColor* src,
int count, U8CPU alpha, int x, int y);
/** Function pointer that blends a single color with a row of 32-bit colors
@@ -51,8 +58,8 @@ public:
@param count number of colors to blend
@param alpha global alpha to be applied to all src colors
*/
- typedef void (*Proc32)(uint32_t* SK_RESTRICT dst,
- const SkPMColor* SK_RESTRICT src,
+ typedef void (*Proc32)(uint32_t* dst,
+ const SkPMColor* src,
int count, U8CPU alpha);
static Proc32 Factory32(unsigned flags32);
@@ -84,29 +91,4 @@ private:
};
};
-/**
- * Factory for blitmask procs
- */
-class SkBlitMask {
-public:
- /**
- * Function pointer that blits the mask into a device (dst) colorized
- * by color. The number of pixels to blit is specified by width and height,
- * but each scanline is offset by dstRB (rowbytes) and srcRB respectively.
- */
- typedef void (*Proc)(void* dst, size_t dstRB, SkBitmap::Config dstConfig,
- const uint8_t* mask, size_t maskRB, SkColor color,
- int width, int height);
-
- /* Public entry-point to return a blitmask function ptr
- */
- static Proc Factory(SkBitmap::Config dstConfig, SkColor color);
-
- /* return either platform specific optimized blitmask function-ptr,
- * or NULL if no optimized
- */
- static Proc PlatformProcs(SkBitmap::Config dstConfig, SkColor color);
-};
-
-
#endif
diff --git a/include/core/SkBlitter.h b/include/core/SkBlitter.h
index 11b84fd..ce74a28 100644
--- a/include/core/SkBlitter.h
+++ b/include/core/SkBlitter.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkBlitter.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkBlitter_DEFINED
#define SkBlitter_DEFINED
@@ -25,28 +17,49 @@
#include "SkRegion.h"
#include "SkMask.h"
+/** SkBlitter and its subclasses are responsible for actually writing pixels
+ into memory. Besides efficiency, they handle clipping and antialiasing.
+*/
class SkBlitter {
public:
virtual ~SkBlitter();
+ /// Blit a horizontal run of one or more pixels.
virtual void blitH(int x, int y, int width);
- virtual void blitAntiH(int x, int y, const SkAlpha[], const int16_t runs[]);
+ /// Blit a horizontal run of antialiased pixels; runs[] is a *sparse*
+ /// zero-terminated run-length encoding of spans of constant alpha values.
+ virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
+ const int16_t runs[]);
+ /// Blit a vertical run of pixels with a constant alpha value.
virtual void blitV(int x, int y, int height, SkAlpha alpha);
+ /// Blit a solid rectangle one or more pixels wide.
virtual void blitRect(int x, int y, int width, int height);
+ /** Blit a rectangle with one alpha-blended column on the left,
+ width (zero or more) opaque pixels, and one alpha-blended column
+ on the right.
+ The result will always be at least two pixels wide.
+ */
+ virtual void blitAntiRect(int x, int y, int width, int height,
+ SkAlpha leftAlpha, SkAlpha rightAlpha);
+ /// Blit a pattern of pixels defined by a rectangle-clipped mask;
+ /// typically used for text.
virtual void blitMask(const SkMask&, const SkIRect& clip);
- /* If the blitter just sets a single value for each pixel, return the
+ /** If the blitter just sets a single value for each pixel, return the
bitmap it draws into, and assign value. If not, return NULL and ignore
the value parameter.
*/
virtual const SkBitmap* justAnOpaqueColor(uint32_t* value);
- // not virtual, just helpers
+ ///@name non-virtual helpers
void blitMaskRegion(const SkMask& mask, const SkRegion& clip);
void blitRectRegion(const SkIRect& rect, const SkRegion& clip);
void blitRegion(const SkRegion& clip);
+ ///@}
- // factories
+ /** @name Factories
+ Return the correct blitter to use given the specified context.
+ */
static SkBlitter* Choose(const SkBitmap& device,
const SkMatrix& matrix,
const SkPaint& paint) {
@@ -63,6 +76,7 @@ public:
const SkBitmap& src,
int left, int top,
void* storage, size_t storageSize);
+ ///@}
private:
};
@@ -71,12 +85,13 @@ private:
*/
class SkNullBlitter : public SkBlitter {
public:
- virtual void blitH(int x, int y, int width);
- virtual void blitAntiH(int x, int y, const SkAlpha[], const int16_t 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 SkIRect& clip);
- virtual const SkBitmap* justAnOpaqueColor(uint32_t* value);
+ virtual void blitH(int x, int y, int width) SK_OVERRIDE;
+ virtual void blitAntiH(int x, int y, const SkAlpha[],
+ const int16_t runs[]) SK_OVERRIDE;
+ virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE;
+ virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE;
+ virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE;
+ virtual const SkBitmap* justAnOpaqueColor(uint32_t* value) SK_OVERRIDE;
};
/** Wraps another (real) blitter, and ensures that the real blitter is only
@@ -91,13 +106,15 @@ public:
fClipRect = clipRect;
}
- // overrides
- virtual void blitH(int x, int y, int width);
- virtual void blitAntiH(int x, int y, const SkAlpha[], const int16_t 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 SkIRect& clip);
- virtual const SkBitmap* justAnOpaqueColor(uint32_t* value);
+ virtual void blitH(int x, int y, int width) SK_OVERRIDE;
+ virtual void blitAntiH(int x, int y, const SkAlpha[],
+ const int16_t runs[]) SK_OVERRIDE;
+ virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE;
+ virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE;
+ virtual void blitAntiRect(int x, int y, int width, int height,
+ SkAlpha leftAlpha, SkAlpha rightAlpha) SK_OVERRIDE;
+ virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE;
+ virtual const SkBitmap* justAnOpaqueColor(uint32_t* value) SK_OVERRIDE;
private:
SkBlitter* fBlitter;
@@ -105,8 +122,8 @@ private:
};
/** Wraps another (real) blitter, and ensures that the real blitter is only
-called with coordinates that have been clipped by the specified clipRgn.
-This means the caller need not perform the clipping ahead of time.
+ called with coordinates that have been clipped by the specified clipRgn.
+ This means the caller need not perform the clipping ahead of time.
*/
class SkRgnClipBlitter : public SkBlitter {
public:
@@ -116,19 +133,25 @@ public:
fRgn = clipRgn;
}
- // overrides
- virtual void blitH(int x, int y, int width);
- virtual void blitAntiH(int x, int y, const SkAlpha[], const int16_t 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 SkIRect& clip);
- virtual const SkBitmap* justAnOpaqueColor(uint32_t* value);
+ virtual void blitH(int x, int y, int width) SK_OVERRIDE;
+ virtual void blitAntiH(int x, int y, const SkAlpha[],
+ const int16_t runs[]) SK_OVERRIDE;
+ virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE;
+ virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE;
+ virtual void blitAntiRect(int x, int y, int width, int height,
+ SkAlpha leftAlpha, SkAlpha rightAlpha) SK_OVERRIDE;
+ virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE;
+ virtual const SkBitmap* justAnOpaqueColor(uint32_t* value) SK_OVERRIDE;
private:
SkBlitter* fBlitter;
const SkRegion* fRgn;
};
+/** Factory to set up the appropriate most-efficient wrapper blitter
+ to apply a clip. Returns a pointer to a member, so lifetime must
+ be managed carefully.
+*/
class SkBlitterClipper {
public:
SkBlitter* apply(SkBlitter* blitter, const SkRegion* clip,
diff --git a/include/core/SkBounder.h b/include/core/SkBounder.h
index fa4f7fb..5bac358 100644
--- a/include/core/SkBounder.h
+++ b/include/core/SkBounder.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkBounder_DEFINED
#define SkBounder_DEFINED
diff --git a/include/core/SkBuffer.h b/include/core/SkBuffer.h
index 6745650..7a63d3a 100644
--- a/include/core/SkBuffer.h
+++ b/include/core/SkBuffer.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkBuffer_DEFINED
#define SkBuffer_DEFINED
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 273153f..24e4141 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkCanvas_DEFINED
#define SkCanvas_DEFINED
@@ -30,11 +23,9 @@
class SkBounder;
class SkDevice;
-class SkDeviceFactory;
class SkDraw;
class SkDrawFilter;
class SkPicture;
-class SkShape;
/** \class SkCanvas
@@ -53,15 +44,10 @@ class SkShape;
*/
class SK_API SkCanvas : public SkRefCnt {
public:
- /** Construct a canvas with the given device factory.
- @param factory Specify the factory for generating additional devices.
- The factory may be null, in which case
- SkRasterDeviceFactory will be used.
- */
- explicit SkCanvas(SkDeviceFactory* factory = NULL);
+ SkCanvas();
+
+ /** Construct a canvas with the specified device to draw into.
- /** Construct a canvas with the specified device to draw into. The device
- factory will be retrieved from the passed device.
@param device Specifies a device for the canvas to draw into.
*/
explicit SkCanvas(SkDevice* device);
@@ -75,6 +61,13 @@ public:
///////////////////////////////////////////////////////////////////////////
+ /**
+ * Return the width/height of the underlying device. The current drawable
+ * area may be small (due to clipping or saveLayer). For a canvas with
+ * no device, 0,0 will be returned.
+ */
+ SkISize getDeviceSize() const;
+
/** Return the canvas' device object, which may be null. The device holds
the bitmap of the pixels that the canvas draws into. The reference count
of the returned device is not changed by this call.
@@ -96,49 +89,123 @@ public:
*/
SkDevice* getTopDevice() const;
- /** May be overridden by subclasses. This returns a compatible device
- for this canvas, with the specified config/width/height. If the device
- is raster, the pixels will be allocated automatically.
- */
- virtual SkDevice* createDevice(SkBitmap::Config, int width, int height,
- bool isOpaque, bool forLayer = false);
-
/**
* Create a new raster device and make it current. This also returns
* the new device.
*/
- SkDevice* setBitmapDevice(const SkBitmap& bitmap, bool forLayer = false);
+ SkDevice* setBitmapDevice(const SkBitmap& bitmap);
/**
- * Return the current device factory, or NULL. The reference count of
- * the returned factory is not changed.
+ * Shortcut for getDevice()->createCompatibleDevice(...).
+ * If getDevice() == NULL, this method does nothing, and returns NULL.
*/
- SkDeviceFactory* getDeviceFactory() const { return fDeviceFactory; }
+ SkDevice* createCompatibleDevice(SkBitmap::Config config,
+ int width, int height,
+ bool isOpaque);
+
+ ///////////////////////////////////////////////////////////////////////////
/**
- * Replace any existing factory with the specified factory, unrefing the
- * previous (if any), and refing the new one (if any). For convenience,
- * the factory parameter is also returned.
+ * This enum can be used with read/writePixels to perform a pixel ops to or
+ * from an 8888 config other than Skia's native config (SkPMColor). There
+ * are three byte orders supported: native, BGRA, and RGBA. Each has a
+ * premultiplied and unpremultiplied variant.
+ *
+ * Components of a 8888 pixel can be packed/unpacked from a 32bit word using
+ * either byte offsets or shift values. Byte offsets are endian-invariant
+ * while shifts are not. BGRA and RGBA configs are defined by byte
+ * orderings. The native config is defined by shift values (SK_A32_SHIFT,
+ * ..., SK_B32_SHIFT).
*/
- SkDeviceFactory* setDeviceFactory(SkDeviceFactory*);
+ enum Config8888 {
+ /**
+ * Skia's native order specified by:
+ * SK_A32_SHIFT, SK_R32_SHIFT, SK_G32_SHIFT, and SK_B32_SHIFT
+ *
+ * kNative_Premul_Config8888 is equivalent to SkPMColor
+ * kNative_Unpremul_Config8888 has the same component order as SkPMColor
+ * but is not premultiplied.
+ */
+ kNative_Premul_Config8888,
+ kNative_Unpremul_Config8888,
+ /**
+ * low byte to high byte: B, G, R, A.
+ */
+ kBGRA_Premul_Config8888,
+ kBGRA_Unpremul_Config8888,
+ /**
+ * low byte to high byte: R, G, B, A.
+ */
+ kRGBA_Premul_Config8888,
+ kRGBA_Unpremul_Config8888,
+ };
- ///////////////////////////////////////////////////////////////////////////
+ /**
+ * On success (returns true), copy the canvas pixels into the bitmap.
+ * On failure, the bitmap parameter is left unchanged and false is
+ * returned.
+ *
+ * The canvas' pixels are converted to the bitmap's config. The only
+ * supported config is kARGB_8888_Config, though this is likely to be
+ * relaxed in the future. The meaning of config kARGB_8888_Config is
+ * modified by the enum param config8888. The default value interprets
+ * kARGB_8888_Config as SkPMColor
+ *
+ * If the bitmap has pixels already allocated, the canvas pixels will be
+ * written there. If not, bitmap->allocPixels() will be called
+ * automatically. If the bitmap is backed by a texture readPixels will
+ * fail.
+ *
+ * The actual pixels written is the intersection of the canvas' bounds, and
+ * the rectangle formed by the bitmap's width,height and the specified x,y.
+ * If bitmap pixels extend outside of that intersection, they will not be
+ * modified.
+ *
+ * Other failure conditions:
+ * * If the canvas is backed by a non-raster device (e.g. PDF) then
+ * readPixels will fail.
+ * * If bitmap is texture-backed then readPixels will fail. (This may be
+ * relaxed in the future.)
+ *
+ * Example that reads the entire canvas into a bitmap using the native
+ * SkPMColor:
+ * SkISize size = canvas->getDeviceSize();
+ * bitmap->setConfig(SkBitmap::kARGB_8888_Config, size.fWidth,
+ * size.fHeight);
+ * if (canvas->readPixels(bitmap, 0, 0)) {
+ * // use the pixels
+ * }
+ */
+ bool readPixels(SkBitmap* bitmap,
+ int x, int y,
+ Config8888 config8888 = kNative_Premul_Config8888);
/**
- * Copy the pixels from the device into bitmap. Returns true on success.
- * If false is returned, then the bitmap parameter is left unchanged.
- * The bitmap parameter is treated as output-only, and will be completely
- * overwritten (if the method returns true).
+ * DEPRECATED: This will be removed as soon as webkit is no longer relying
+ * on it. The bitmap is resized to the intersection of srcRect and the
+ * canvas bounds. New pixels are always allocated on success. Bitmap is
+ * unmodified on failure.
*/
bool readPixels(const SkIRect& srcRect, SkBitmap* bitmap);
- bool readPixels(SkBitmap* bitmap);
/**
* Similar to draw sprite, this method will copy the pixels in bitmap onto
- * the device, with the top/left corner specified by (x, y). The pixel
- * values in the device are completely replaced: there is no blending.
+ * the canvas, with the top/left corner specified by (x, y). The canvas'
+ * pixel values are completely replaced: there is no blending.
+ *
+ * Currently if bitmap is backed by a texture this is a no-op. This may be
+ * relaxed in the future.
+ *
+ * If the bitmap has config kARGB_8888_Config then the config8888 param
+ * will determines how the pixel valuess are intepreted. If the bitmap is
+ * not kARGB_8888_Config then this parameter is ignored.
+ *
+ * Note: If you are recording drawing commands on this canvas to
+ * SkPicture, writePixels() is ignored!
*/
- void writePixels(const SkBitmap& bitmap, int x, int y);
+ void writePixels(const SkBitmap& bitmap,
+ int x, int y,
+ Config8888 config8888 = kNative_Premul_Config8888);
///////////////////////////////////////////////////////////////////////////
@@ -220,6 +287,11 @@ public:
*/
void restoreToCount(int saveCount);
+ /** Returns true if drawing is currently going to a layer (from saveLayer)
+ * rather than to the root device.
+ */
+ bool isDrawingToLayer() const;
+
/** Preconcat the current matrix with the specified translation
@param dx The distance to translate in X
@param dy The distance to translate in Y
@@ -268,7 +340,8 @@ public:
@return true if the canvas' clip is non-empty
*/
virtual bool clipRect(const SkRect& rect,
- SkRegion::Op op = SkRegion::kIntersect_Op);
+ SkRegion::Op op = SkRegion::kIntersect_Op,
+ bool doAntiAlias = false);
/** Modify the current clip with the specified path.
@param path The path to apply to the current clip
@@ -276,7 +349,8 @@ public:
@return true if the canvas' new clip is non-empty
*/
virtual bool clipPath(const SkPath& path,
- SkRegion::Op op = SkRegion::kIntersect_Op);
+ SkRegion::Op op = SkRegion::kIntersect_Op,
+ bool doAntiAlias = false);
/** Modify the current clip with the specified region. Note that unlike
clipRect() and clipPath() which transform their arguments by the current
@@ -359,6 +433,13 @@ public:
*/
bool getClipBounds(SkRect* bounds, EdgeType et = kAA_EdgeType) const;
+ /** Return the bounds of the current clip, in device coordinates; returns
+ true if non-empty. Maybe faster than getting the clip explicitly and
+ then taking its bounds.
+ */
+ bool getClipDeviceBounds(SkIRect* bounds) const;
+
+
/** Fill the entire canvas' bitmap (restricted to the current clip) with the
specified ARGB color, using the specified mode.
@param a the alpha component (0..255) of the color to fill the canvas
@@ -565,6 +646,23 @@ public:
virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m,
const SkPaint* paint = NULL);
+ /**
+ * Draw the bitmap stretched differentially to fit into dst.
+ * center is a rect within the bitmap, and logically divides the bitmap
+ * into 9 sections (3x3). For example, if the middle pixel of a [5x5]
+ * bitmap is the "center", then the center-rect should be [2, 2, 3, 3].
+ *
+ * If the dst is >= the bitmap size, then...
+ * - The 4 corners are not stretch at all.
+ * - The sides are stretch in only one axis.
+ * - The center is stretch in both axes.
+ * Else, for each axis where dst < bitmap,
+ * - The corners shrink proportionally
+ * - The sides (along the shrink axis) and center are not drawn
+ */
+ virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
+ const SkRect& dst, const SkPaint* paint = NULL);
+
/** Draw the specified bitmap, with its top/left corner at (x,y),
NOT transformed by the current matrix. Note: if the paint
contains a maskfilter that generates a mask which extends beyond the
@@ -643,7 +741,7 @@ public:
const SkPath& path, const SkMatrix* matrix,
const SkPaint& paint);
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
/** Draw the text on path, with each character/glyph origin specified by the pos[]
array. The origin is interpreted by the Align setting in the paint.
@param text The text to be drawn
@@ -669,10 +767,6 @@ public:
*/
virtual void drawPicture(SkPicture& picture);
- /** Draws the specified shape
- */
- virtual void drawShape(SkShape*);
-
enum VertexMode {
kTriangles_VertexMode,
kTriangleStrip_VertexMode,
@@ -753,6 +847,17 @@ public:
*/
const SkMatrix& getTotalMatrix() const;
+ enum ClipType {
+ kEmpty_ClipType = 0,
+ kRect_ClipType,
+ kComplex_ClipType
+ };
+
+ /** Returns a description of the total clip; may be cheaper than
+ getting the clip and querying it directly.
+ */
+ ClipType getClipType() const;
+
/** Return the current device clip (concatenation of all clip calls).
This does not account for the translate in any of the devices.
@return the current device clip (concatenation of all clip calls).
@@ -760,6 +865,14 @@ public:
const SkRegion& getTotalClip() const;
/**
+ * Return true if the current clip is non-empty.
+ *
+ * If bounds is not NULL, set it to the bounds of the current clip
+ * in global coordinates.
+ */
+ bool getTotalClipBounds(SkIRect* bounds) const;
+
+ /**
* Return the current clipstack. This mirrors the result in getTotalClip()
* but is represented as a stack of geometric clips + region-ops.
*/
@@ -824,7 +937,7 @@ private:
SkBounder* fBounder;
SkDevice* fLastDeviceToGainFocus;
- SkDeviceFactory* fDeviceFactory;
+ int fLayerCount; // number of successful saveLayer calls
void prepareForDeviceDraw(SkDevice*, const SkMatrix&, const SkRegion&,
const SkClipStack& clipStack);
@@ -834,13 +947,31 @@ private:
friend class SkDrawIter; // needs setupDrawForLayerDevice()
+ SkDevice* createLayerDevice(SkBitmap::Config, int width, int height,
+ bool isOpaque);
+
SkDevice* init(SkDevice*);
+
+ // internal methods are not virtual, so they can safely be called by other
+ // canvas apis, without confusing subclasses (like SkPictureRecording)
void internalDrawBitmap(const SkBitmap&, const SkIRect*, const SkMatrix& m,
const SkPaint* paint);
+ void internalDrawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
+ const SkRect& dst, const SkPaint* paint);
+ void internalDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
+ const SkRect& dst, const SkPaint* paint);
+ void internalDrawPaint(const SkPaint& paint);
+
+
void drawDevice(SkDevice*, int x, int y, const SkPaint*);
// shared by save() and saveLayer()
int internalSave(SaveFlags flags);
void internalRestore();
+ static void DrawRect(const SkDraw& draw, const SkPaint& paint,
+ const SkRect& r, SkScalar textSize);
+ static void DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
+ const char text[], size_t byteLength,
+ SkScalar x, SkScalar y);
/* These maintain a cache of the clip bounds in local coordinates,
(converted to 2s-compliment if floats are slow).
@@ -918,4 +1049,3 @@ private:
};
#endif
-
diff --git a/include/core/SkChunkAlloc.h b/include/core/SkChunkAlloc.h
index ba9e2c9..28d3c7e 100644
--- a/include/core/SkChunkAlloc.h
+++ b/include/core/SkChunkAlloc.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkChunkAlloc_DEFINED
#define SkChunkAlloc_DEFINED
diff --git a/include/core/SkClampRange.h b/include/core/SkClampRange.h
index 9acf1ad..68a27e9 100644
--- a/include/core/SkClampRange.h
+++ b/include/core/SkClampRange.h
@@ -1,19 +1,12 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkClampRange_DEFINED
#define SkClampRange_DEFINED
diff --git a/include/core/SkClipStack.h b/include/core/SkClipStack.h
index 6e8da76..fc96f03 100644
--- a/include/core/SkClipStack.h
+++ b/include/core/SkClipStack.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkClipStack_DEFINED
#define SkClipStack_DEFINED
@@ -27,10 +34,10 @@ public:
SkRegion::Op op = SkRegion::kIntersect_Op) {
SkRect r;
r.set(ir);
- this->clipDevRect(r, op);
+ this->clipDevRect(r, op, false);
}
- void clipDevRect(const SkRect&, SkRegion::Op = SkRegion::kIntersect_Op);
- void clipDevPath(const SkPath&, SkRegion::Op = SkRegion::kIntersect_Op);
+ void clipDevRect(const SkRect&, SkRegion::Op, bool doAA);
+ void clipDevPath(const SkPath&, SkRegion::Op, bool doAA);
class B2FIter {
public:
@@ -42,11 +49,13 @@ public:
B2FIter(const SkClipStack& stack);
struct Clip {
+ Clip() : fRect(NULL), fPath(NULL), fOp(SkRegion::kIntersect_Op) {}
friend bool operator==(const Clip& a, const Clip& b);
friend bool operator!=(const Clip& a, const Clip& b);
const SkRect* fRect; // if non-null, this is a rect clip
const SkPath* fPath; // if non-null, this is a path clip
SkRegion::Op fOp;
+ bool fDoAA;
};
/**
diff --git a/include/core/SkColor.h b/include/core/SkColor.h
index 1f82aa7..e6d4352 100644
--- a/include/core/SkColor.h
+++ b/include/core/SkColor.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkColor_DEFINED
#define SkColor_DEFINED
diff --git a/include/core/SkColorFilter.h b/include/core/SkColorFilter.h
index 3e9aee8..97db5cc 100644
--- a/include/core/SkColorFilter.h
+++ b/include/core/SkColorFilter.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkColorFilter_DEFINED
#define SkColorFilter_DEFINED
@@ -30,6 +23,31 @@ public:
*/
virtual bool asColorMode(SkColor* color, SkXfermode::Mode* mode);
+ /**
+ * If the filter can be represented by a 5x4 matrix, this
+ * returns true, and sets the matrix appropriately.
+ * If not, this returns false and ignores the parameter.
+ */
+ virtual bool asColorMatrix(SkScalar matrix[20]);
+
+ /**
+ * If the filter can be represented by per-component table, return true,
+ * and if table is not null, copy the bitmap containing the table into it.
+ *
+ * The table bitmap will be in SkBitmap::kA8_Config. Each row corresponding
+ * to each component in ARGB order. e.g. row[0] == alpha, row[1] == red,
+ * etc. To transform a color, you (logically) perform the following:
+ *
+ * a' = *table.getAddr8(a, 0);
+ * r' = *table.getAddr8(r, 1);
+ * g' = *table.getAddr8(g, 2);
+ * b' = *table.getAddr8(b, 3);
+ *
+ * The original component value is the horizontal index for a given row,
+ * and the stored value at that index is the new value for that component.
+ */
+ virtual bool asComponentTable(SkBitmap* table);
+
/** Called with a scanline of colors, as if there was a shader installed.
The implementation writes out its filtered version into result[].
Note: shader and result may be the same buffer.
@@ -99,7 +117,8 @@ public:
are ignored.
*/
static SkColorFilter* CreateLightingFilter(SkColor mul, SkColor add);
-
+
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
protected:
SkColorFilter() {}
SkColorFilter(SkFlattenableReadBuffer& rb) : INHERITED(rb) {}
@@ -126,8 +145,8 @@ public:
protected:
SkFilterShader(SkFlattenableReadBuffer& );
- virtual void flatten(SkFlattenableWriteBuffer& );
- virtual Factory getFactory() { return CreateProc; }
+ virtual void flatten(SkFlattenableWriteBuffer& ) SK_OVERRIDE;
+ virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
private:
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkFilterShader, (buffer)); }
diff --git a/include/core/SkColorPriv.h b/include/core/SkColorPriv.h
index 6fa9df3..714e845 100644
--- a/include/core/SkColorPriv.h
+++ b/include/core/SkColorPriv.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkColorPriv_DEFINED
#define SkColorPriv_DEFINED
@@ -51,6 +44,21 @@ static inline int SkAlphaBlend(int src, int dst, int scale256) {
return dst + SkAlphaMul(src - dst, scale256);
}
+/**
+ * Returns (src * alpha + dst * (255 - alpha)) / 255
+ *
+ * This is more accurate than SkAlphaBlend, but slightly slower
+ */
+static inline int SkAlphaBlend255(S16CPU src, S16CPU dst, U8CPU alpha) {
+ SkASSERT((int16_t)src == src);
+ SkASSERT((int16_t)dst == dst);
+ SkASSERT((uint8_t)alpha == alpha);
+
+ int prod = SkMulS16(src - dst, alpha) + 128;
+ prod = (prod + (prod >> 8)) >> 8;
+ return dst + prod;
+}
+
#define SK_R16_BITS 5
#define SK_G16_BITS 6
#define SK_B16_BITS 5
@@ -216,6 +224,21 @@ static inline SkPMColor SkPackARGB32NoCheck(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
(g << SK_G32_SHIFT) | (b << SK_B32_SHIFT);
}
+static inline
+SkPMColor SkPremultiplyARGBInline(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
+ SkA32Assert(a);
+ SkA32Assert(r);
+ SkA32Assert(g);
+ SkA32Assert(b);
+
+ if (a != 255) {
+ r = SkMulDiv255Round(r, a);
+ g = SkMulDiv255Round(g, a);
+ b = SkMulDiv255Round(b, a);
+ }
+ return SkPackARGB32(a, r, g, b);
+}
+
SK_API extern const uint32_t gMask_00FF00FF;
static inline uint32_t SkAlphaMulQ(uint32_t c, unsigned scale) {
diff --git a/include/core/SkColorShader.h b/include/core/SkColorShader.h
index b7537e1..9b1fed3 100644
--- a/include/core/SkColorShader.h
+++ b/include/core/SkColorShader.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2007 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkColorShader_DEFINED
#define SkColorShader_DEFINED
@@ -39,38 +32,38 @@ public:
virtual ~SkColorShader();
- virtual uint32_t getFlags() { return fFlags; }
- virtual uint8_t getSpan16Alpha() const;
+ virtual uint32_t getFlags() SK_OVERRIDE;
+ virtual uint8_t getSpan16Alpha() const SK_OVERRIDE;
+ virtual bool isOpaque() const SK_OVERRIDE;
virtual bool setContext(const SkBitmap& device, const SkPaint& paint,
- const SkMatrix& matrix);
- virtual void shadeSpan(int x, int y, SkPMColor span[], int count);
- virtual void shadeSpan16(int x, int y, uint16_t span[], int count);
- virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count);
+ const SkMatrix& matrix) SK_OVERRIDE;
+ virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE;
+ virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) SK_OVERRIDE;
+ // we return false for this, use asAGradient
virtual BitmapType asABitmap(SkBitmap* outTexture,
SkMatrix* outMatrix,
TileMode xy[2],
- SkScalar* twoPointRadialParams) const;
+ SkScalar* twoPointRadialParams) const SK_OVERRIDE;
- virtual GradientType asAGradient(GradientInfo* info) const;
+ virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE;
protected:
- SkColorShader(SkFlattenableReadBuffer& );
- virtual void flatten(SkFlattenableWriteBuffer& );
- virtual Factory getFactory() { return CreateProc; }
+ SkColorShader(SkFlattenableReadBuffer&);
+
+ virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+ virtual Factory getFactory() SK_OVERRIDE;
+
private:
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
- return SkNEW_ARGS(SkColorShader, (buffer));
- }
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+
SkColor fColor; // ignored if fInheritColor is true
SkPMColor fPMColor; // cached after setContext()
uint32_t fFlags; // cached after setContext()
uint16_t fColor16; // cached after setContext()
SkBool8 fInheritColor;
- // deferred allocation, used for asABitmap()
- mutable SkPixelRef* fAsABitmapPixelRef;
-
typedef SkShader INHERITED;
};
diff --git a/include/core/SkComposeShader.h b/include/core/SkComposeShader.h
index ea37549..f243954 100644
--- a/include/core/SkComposeShader.h
+++ b/include/core/SkComposeShader.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkComposeShader_DEFINED
#define SkComposeShader_DEFINED
diff --git a/include/core/SkData.h b/include/core/SkData.h
new file mode 100644
index 0000000..a134536
--- /dev/null
+++ b/include/core/SkData.h
@@ -0,0 +1,137 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef SkData_DEFINED
+#define SkData_DEFINED
+
+#include "SkRefCnt.h"
+
+/**
+ * SkData holds an immutable data buffer. Not only is the data immutable,
+ * but the actual ptr that is returned (by data() or bytes()) is guaranteed
+ * to always be the same for the life of this instance.
+ */
+class SkData : public SkRefCnt {
+public:
+ /**
+ * Returns the number of bytes stored.
+ */
+ size_t size() const { return fSize; }
+
+ /**
+ * Returns the ptr to the data.
+ */
+ const void* data() const { return fPtr; }
+
+ /**
+ * Like data(), returns a read-only ptr into the data, but in this case
+ * it is cast to uint8_t*, to make it easy to add an offset to it.
+ */
+ const uint8_t* bytes() const {
+ return reinterpret_cast<const uint8_t*>(fPtr);
+ }
+
+ /**
+ * Helper to copy a range of the data into a caller-provided buffer.
+ * Returns the actual number of bytes copied, after clamping offset and
+ * length to the size of the data. If buffer is NULL, it is ignored, and
+ * only the computed number of bytes is returned.
+ */
+ size_t copyRange(size_t offset, size_t length, void* buffer) const;
+
+ /**
+ * Function that, if provided, will be called when the SkData goes out
+ * of scope, allowing for custom allocation/freeing of the data.
+ */
+ typedef void (*ReleaseProc)(const void* ptr, size_t length, void* context);
+
+ /**
+ * Create a new dataref by copying the specified data
+ */
+ static SkData* NewWithCopy(const void* data, size_t length);
+
+ /**
+ * Create a new dataref, taking the data ptr as is, and using the
+ * releaseproc to free it. The proc may be NULL.
+ */
+ static SkData* NewWithProc(const void* data, size_t length,
+ ReleaseProc proc, void* context);
+
+ /**
+ * Create a new dataref, reference the data ptr as is, and calling
+ * sk_free to delete it.
+ */
+ static SkData* NewFromMalloc(const void* data, size_t length);
+
+ /**
+ * Create a new dataref using a subset of the data in the specified
+ * src dataref.
+ */
+ static SkData* NewSubset(const SkData* src, size_t offset, size_t length);
+
+ /**
+ * Returns a new empty dataref (or a reference to a shared empty dataref).
+ * New or shared, the caller must see that unref() is eventually called.
+ */
+ static SkData* NewEmpty();
+
+private:
+ ReleaseProc fReleaseProc;
+ void* fReleaseProcContext;
+
+ const void* fPtr;
+ size_t fSize;
+
+ SkData(const void* ptr, size_t size, ReleaseProc, void* context);
+ ~SkData();
+};
+
+/**
+ * Specialized version of SkAutoTUnref<SkData> for automatically unref-ing a
+ * SkData. If the SkData is null, data(), bytes() and size() will return 0.
+ */
+class SkAutoDataUnref : SkNoncopyable {
+public:
+ SkAutoDataUnref(SkData* data) : fRef(data) {
+ if (data) {
+ fData = data->data();
+ fSize = data->size();
+ } else {
+ fData = NULL;
+ fSize = 0;
+ }
+ }
+ ~SkAutoDataUnref() {
+ SkSafeUnref(fRef);
+ }
+
+ const void* data() const { return fData; }
+ const uint8_t* bytes() const {
+ return reinterpret_cast<const uint8_t*> (fData);
+ }
+ size_t size() const { return fSize; }
+ SkData* get() const { return fRef; }
+
+ void release() {
+ if (fRef) {
+ fRef->unref();
+ fRef = NULL;
+ fData = NULL;
+ fSize = 0;
+ }
+ }
+
+private:
+ SkData* fRef;
+ const void* fData;
+ size_t fSize;
+};
+
+#endif
diff --git a/include/core/SkDeque.h b/include/core/SkDeque.h
index 8bf8b5b..b4f420d 100644
--- a/include/core/SkDeque.h
+++ b/include/core/SkDeque.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkDeque_DEFINED
#define SkDeque_DEFINED
diff --git a/include/core/SkDescriptor.h b/include/core/SkDescriptor.h
index 09397b7..b97b75f 100644
--- a/include/core/SkDescriptor.h
+++ b/include/core/SkDescriptor.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkDescriptor_DEFINED
#define SkDescriptor_DEFINED
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index d9a4fde..c026a4b 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2010 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkDevice_DEFINED
#define SkDevice_DEFINED
@@ -23,55 +16,57 @@
#include "SkColor.h"
class SkClipStack;
-class SkDevice;
class SkDraw;
struct SkIRect;
class SkMatrix;
class SkMetaData;
class SkRegion;
-/** \class SkDeviceFactory
-
- Devices that extend SkDevice should also provide a SkDeviceFactory class
- to pass into SkCanvas. Doing so will eliminate the need to extend
- SkCanvas as well.
-*/
-class SK_API SkDeviceFactory : public SkRefCnt {
-public:
- SkDeviceFactory();
- virtual ~SkDeviceFactory();
- virtual SkDevice* newDevice(SkCanvas*, SkBitmap::Config, int width,
- int height, bool isOpaque, bool isLayer) = 0;
-};
-
-class SkRasterDeviceFactory : public SkDeviceFactory {
-public:
- virtual SkDevice* newDevice(SkCanvas*, SkBitmap::Config, int width,
- int height, bool isOpaque, bool isLayer);
-};
+// This is an opaque class, not interpreted by skia
+class SkGpuRenderTarget;
class SK_API SkDevice : public SkRefCnt {
public:
- SkDevice(SkCanvas*);
- /** Construct a new device, extracting the width/height/config/isOpaque values from
- the bitmap. If transferPixelOwnership is true, and the bitmap claims to own its
- own pixels (getOwnsPixels() == true), then transfer this responsibility to the
- device, and call setOwnsPixels(false) on the bitmap.
+ /**
+ * Construct a new device with the specified bitmap as its backend. It is
+ * valid for the bitmap to have no pixels associated with it. In that case,
+ * any drawing to this device will have no effect.
+ */
+ SkDevice(const SkBitmap& bitmap);
- Subclasses may override the destructor, which is virtual, even though this class
- doesn't have one. SkRefCnt does.
+ /**
+ * Create a new raster device and have the pixels be automatically
+ * allocated. The rowBytes of the device will be computed automatically
+ * based on the config and the width.
+ *
+ * @param config The desired config for the pixels. If the request cannot
+ * be met, the closest matching support config will be used.
+ * @param width width (in pixels) of the device
+ * @param height height (in pixels) of the device
+ * @param isOpaque Set to true if it is known that all of the pixels will
+ * be drawn to opaquely. Used as an accelerator when drawing
+ * these pixels to another device.
+ */
+ SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque = false);
- @param bitmap A copy of this bitmap is made and stored in the device
- */
- SkDevice(SkCanvas*, const SkBitmap& bitmap, bool forOffscreen);
virtual ~SkDevice();
/**
- * Return the factory that will create this subclass of SkDevice.
- * The returned factory is cached by the device, and so its reference count
- * is not changed by this call.
+ * Creates a device that is of the same type as this device (e.g. SW-raster,
+ * GPU, or PDF). The backing store for this device is created automatically
+ * (e.g. offscreen pixels or FBO or whatever is appropriate).
+ *
+ * @param width width of the device to create
+ * @param height height of the device to create
+ * @param isOpaque performance hint, set to true if you know that you will
+ * draw into this device such that all of the pixels will
+ * be opaque.
*/
- SkDeviceFactory* getDeviceFactory();
+ SkDevice* createCompatibleDevice(SkBitmap::Config config,
+ int width, int height,
+ bool isOpaque);
+
+ SkMetaData& getMetaData();
enum Capabilities {
kGL_Capability = 0x1, //!< mask indicating GL support
@@ -88,28 +83,20 @@ public:
virtual int height() const { return fBitmap.height(); }
/**
- * Return the device's origin: its offset in device coordinates from
- * the default origin in its canvas' matrix/clip
+ * Return the bounds of the device in the coordinate space of the root
+ * canvas. The root device will have its top-left at 0,0, but other devices
+ * such as those associated with saveLayer may have a non-zero origin.
*/
- const SkIPoint& getOrigin() const { return fOrigin; }
+ void getGlobalBounds(SkIRect* bounds) const;
- /** Return the bitmap config of the device's pixels
- */
- SkBitmap::Config config() const { return fBitmap.getConfig(); }
/** Returns true if the device's bitmap's config treats every pixels as
implicitly opaque.
*/
bool isOpaque() const { return fBitmap.isOpaque(); }
- /** Return the bounds of the device
- */
- void getBounds(SkIRect* bounds) const;
-
- /** Return true if the specified rectangle intersects the bounds of the
- device. If sect is not NULL and there is an intersection, sect returns
- the intersection.
+ /** Return the bitmap config of the device's pixels
*/
- bool intersects(const SkIRect& r, SkIRect* sect = NULL) const;
+ SkBitmap::Config config() const { return fBitmap.getConfig(); }
/** Return the bitmap associated with this device. Call this each time you need
to access the bitmap, as it notifies the subclass to perform any flushing
@@ -119,26 +106,56 @@ public:
*/
const SkBitmap& accessBitmap(bool changePixels);
- /** Clears the entire device to the specified color (including alpha).
- * Ignores the clip.
+ /**
+ * DEPRECATED: This will be made protected once WebKit stops using it.
+ * Instead use Canvas' writePixels method.
+ *
+ * Similar to draw sprite, this method will copy the pixels in bitmap onto
+ * the device, with the top/left corner specified by (x, y). The pixel
+ * values in the device are completely replaced: there is no blending.
+ *
+ * Currently if bitmap is backed by a texture this is a no-op. This may be
+ * relaxed in the future.
+ *
+ * If the bitmap has config kARGB_8888_Config then the config8888 param
+ * will determines how the pixel valuess are intepreted. If the bitmap is
+ * not kARGB_8888_Config then this parameter is ignored.
*/
- virtual void clear(SkColor color);
+ virtual void writePixels(const SkBitmap& bitmap, int x, int y,
+ SkCanvas::Config8888 config8888 = SkCanvas::kNative_Premul_Config8888);
/**
- * Deprecated name for clear.
+ * Return the device's associated gpu render target, or NULL.
*/
- void eraseColor(SkColor eraseColor) { this->clear(eraseColor); }
+ virtual SkGpuRenderTarget* accessRenderTarget() { return NULL; }
- /** Called when this device is installed into a Canvas. Balanaced by a call
- to unlockPixels() when the device is removed from a Canvas.
- */
- virtual void lockPixels();
- virtual void unlockPixels();
- /** Return the device's associated texture, or NULL. If returned, it may be
- drawn into another device
+ /**
+ * Return the device's origin: its offset in device coordinates from
+ * the default origin in its canvas' matrix/clip
+ */
+ const SkIPoint& getOrigin() const { return fOrigin; }
+
+protected:
+ enum Usage {
+ kGeneral_Usage,
+ kSaveLayer_Usage, // <! internal use only
+ };
+
+ struct TextFlags {
+ uint32_t fFlags; // SkPaint::getFlags()
+ SkPaint::Hinting fHinting;
+ };
+
+ /**
+ * Device may filter the text flags for drawing text here. If it wants to
+ * make a change to the specified values, it should write them into the
+ * textflags parameter (output) and return true. If the paint is fine as
+ * is, then ignore the textflags parameter and return false.
+ *
+ * The baseclass SkDevice filters based on its depth and blitters.
*/
- virtual SkGpuTexture* accessTexture() { return NULL; }
+ virtual bool filterTextFlags(const SkPaint& paint, TextFlags*);
/**
* Called with the correct matrix and clip before this device is drawn
@@ -161,24 +178,15 @@ public:
virtual void gainFocus(SkCanvas*, const SkMatrix&, const SkRegion&,
const SkClipStack&) {}
- /** Causes any deferred drawing to the device to be completed.
- */
- virtual void flush() {}
-
- /**
- * Copy the pixels from the device into bitmap. Returns true on success.
- * If false is returned, then the bitmap parameter is left unchanged.
- * The bitmap parameter is treated as output-only, and will be completely
- * overwritten (if the method returns true).
+ /** Clears the entire device to the specified color (including alpha).
+ * Ignores the clip.
*/
- virtual bool readPixels(const SkIRect& srcRect, SkBitmap* bitmap);
+ virtual void clear(SkColor color);
/**
- * Similar to draw sprite, this method will copy the pixels in bitmap onto
- * the device, with the top/left corner specified by (x, y). The pixel
- * values in the device are completely replaced: there is no blending.
+ * Deprecated name for clear.
*/
- virtual void writePixels(const SkBitmap& bitmap, int x, int y);
+ void eraseColor(SkColor eraseColor) { this->clear(eraseColor); }
/** These are called inside the per-device-layer loop for each draw call.
When these are called, we have already applied any saveLayer operations,
@@ -210,6 +218,10 @@ public:
const SkMatrix& matrix, const SkPaint& paint);
virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
int x, int y, const SkPaint& paint);
+ /**
+ * Does not handle text decoration.
+ * Decorations (underline and stike-thru) will be handled by SkCanvas.
+ */
virtual void drawText(const SkDraw&, const void* text, size_t len,
SkScalar x, SkScalar y, const SkPaint& paint);
virtual void drawPosText(const SkDraw&, const void* text, size_t len,
@@ -218,7 +230,7 @@ public:
virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len,
const SkPath& path, const SkMatrix* matrix,
const SkPaint& paint);
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
virtual void drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len,
const SkPoint pos[], const SkPaint& paint,
const SkPath& path, const SkMatrix* matrix);
@@ -228,35 +240,44 @@ public:
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
const SkPaint& paint);
+ /** The SkDevice passed will be an SkDevice which was returned by a call to
+ onCreateCompatibleDevice on this device with kSaveLayer_Usage.
+ */
virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
const SkPaint&);
- ///////////////////////////////////////////////////////////////////////////
-
- SkMetaData& getMetaData();
-
- struct TextFlags {
- uint32_t fFlags; // SkPaint::getFlags()
- SkPaint::Hinting fHinting;
- };
-
/**
- * Device may filter the text flags for drawing text here. If it wants to
- * make a change to the specified values, it should write them into the
- * textflags parameter (output) and return true. If the paint is fine as
- * is, then ignore the textflags parameter and return false.
+ * On success (returns true), copy the device pixels into the bitmap.
+ * On failure, the bitmap parameter is left unchanged and false is
+ * returned.
*
- * The baseclass SkDevice filters based on its depth and blitters.
+ * The device's pixels are converted to the bitmap's config. The only
+ * supported config is kARGB_8888_Config, though this is likely to be
+ * relaxed in the future. The meaning of config kARGB_8888_Config is
+ * modified by the enum param config8888. The default value interprets
+ * kARGB_8888_Config as SkPMColor
+ *
+ * If the bitmap has pixels already allocated, the device pixels will be
+ * written there. If not, bitmap->allocPixels() will be called
+ * automatically. If the bitmap is backed by a texture readPixels will
+ * fail.
+ *
+ * The actual pixels written is the intersection of the device's bounds,
+ * and the rectangle formed by the bitmap's width,height and the specified
+ * x,y. If bitmap pixels extend outside of that intersection, they will not
+ * be modified.
+ *
+ * Other failure conditions:
+ * * If the device is not a raster device (e.g. PDF) then readPixels will
+ * fail.
+ * * If bitmap is texture-backed then readPixels will fail. (This may be
+ * relaxed in the future.)
*/
- virtual bool filterTextFlags(const SkPaint& paint, TextFlags*);
+ bool readPixels(SkBitmap* bitmap,
+ int x, int y,
+ SkCanvas::Config8888 config8888);
-protected:
- /**
- * subclasses must override this to return a new (or ref'd) instance of
- * a device factory that will create this subclass of device. This value
- * is cached, so it should get called at most once for a given instance.
- */
- virtual SkDeviceFactory* onNewDeviceFactory();
+ ///////////////////////////////////////////////////////////////////////////
/** Update as needed the pixel value in the bitmap, so that the caller can access
the pixels directly. Note: only the pixels field should be altered. The config/width/height/rowbytes
@@ -270,18 +291,76 @@ protected:
fBitmap.setPixelRef(pr, offset);
return pr;
}
+
+ /**
+ * Implements readPixels API. The caller will ensure that:
+ * 1. bitmap has pixel config kARGB_8888_Config.
+ * 2. bitmap has pixels.
+ * 3. The rectangle (x, y, x + bitmap->width(), y + bitmap->height()) is
+ * contained in the device bounds.
+ */
+ virtual bool onReadPixels(const SkBitmap& bitmap,
+ int x, int y,
+ SkCanvas::Config8888 config8888);
+
+ /** Called when this device is installed into a Canvas. Balanaced by a call
+ to unlockPixels() when the device is removed from a Canvas.
+ */
+ virtual void lockPixels();
+ virtual void unlockPixels();
+
+ /**
+ * Returns true if the device allows processing of this imagefilter. If
+ * false is returned, then the filter is ignored. This may happen for
+ * some subclasses that do not support pixel manipulations after drawing
+ * has occurred (e.g. printing). The default implementation returns true.
+ */
+ virtual bool allowImageFilter(SkImageFilter*);
+
+ /**
+ * Override and return true for filters that the device handles
+ * intrinsically. Returning false means call the filter.
+ * Default impl returns false. This will only be called if allowImageFilter()
+ * returned true.
+ */
+ virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
+ const SkMatrix& ctm,
+ SkBitmap* result, SkIPoint* offset);
+
+ // This is equal kBGRA_Premul_Config8888 or kRGBA_Premul_Config8888 if
+ // either is identical to kNative_Premul_Config8888. Otherwise, -1.
+ static const SkCanvas::Config8888 kPMColorAlias;
private:
friend class SkCanvas;
+ friend struct DeviceCM; //for setMatrixClip
+ friend class SkDraw;
+ friend class SkDrawIter;
+ friend class SkDeviceFilteredPaint;
+ friend class DeviceImageFilterProxy;
+
// just called by SkCanvas when built as a layer
void setOrigin(int x, int y) { fOrigin.set(x, y); }
+ // just called by SkCanvas for saveLayer
+ SkDevice* createCompatibleDeviceForSaveLayer(SkBitmap::Config config,
+ int width, int height,
+ bool isOpaque);
+
+ /**
+ * Subclasses should override this to implement createCompatibleDevice.
+ */
+ virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config,
+ int width, int height,
+ bool isOpaque,
+ Usage usage);
+
+ /** Causes any deferred drawing to the device to be completed.
+ */
+ virtual void flush() {}
- SkCanvas* fCanvas;
SkBitmap fBitmap;
SkIPoint fOrigin;
SkMetaData* fMetaData;
-
- SkDeviceFactory* fCachedDeviceFactory;
};
#endif
diff --git a/include/core/SkDither.h b/include/core/SkDither.h
index 5b2552d..692c7e4 100644
--- a/include/core/SkDither.h
+++ b/include/core/SkDither.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkDither_DEFINED
#define SkDither_DEFINED
diff --git a/include/core/SkDraw.h b/include/core/SkDraw.h
index b751be0..8c659c2 100644
--- a/include/core/SkDraw.h
+++ b/include/core/SkDraw.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkDraw_DEFINED
#define SkDraw_DEFINED
@@ -30,6 +23,7 @@ class SkClipStack;
class SkDevice;
class SkPath;
class SkRegion;
+class SkRasterClip;
struct SkDrawProcs;
class SkDraw {
@@ -61,7 +55,7 @@ public:
int scalarsPerPosition, const SkPaint& paint) const;
void drawTextOnPath(const char text[], size_t byteLength,
const SkPath&, const SkMatrix*, const SkPaint&) const;
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
void drawPosTextOnPath(const char text[], size_t byteLength,
const SkPoint pos[], const SkPaint& paint,
const SkPath& path, const SkMatrix* matrix) const;
@@ -112,7 +106,8 @@ private:
public:
const SkBitmap* fBitmap; // required
const SkMatrix* fMatrix; // required
- const SkRegion* fClip; // required
+ const SkRegion* fClip; // DEPRECATED
+ const SkRasterClip* fRC; // required
const SkClipStack* fClipStack; // optional
SkDevice* fDevice; // optional
@@ -154,6 +149,7 @@ private:
const SkPath* fPath; // returned in next
SkScalar fXPos; // accumulated xpos, returned in next
SkAutoKern fAutoKern;
+ int fXYIndex; // cache for horizontal -vs- vertical text
};
#endif
diff --git a/include/core/SkDrawFilter.h b/include/core/SkDrawFilter.h
index c8af187..303b80e 100644
--- a/include/core/SkDrawFilter.h
+++ b/include/core/SkDrawFilter.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2011 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkDrawFilter_DEFINED
#define SkDrawFilter_DEFINED
diff --git a/include/core/SkDrawLooper.h b/include/core/SkDrawLooper.h
index 3830b4a..e8265db 100644
--- a/include/core/SkDrawLooper.h
+++ b/include/core/SkDrawLooper.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2011 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkDrawLooper_DEFINED
#define SkDrawLooper_DEFINED
diff --git a/include/core/SkEdgeClipper.h b/include/core/SkEdgeClipper.h
index 6720b9c..a7eedd5 100644
--- a/include/core/SkEdgeClipper.h
+++ b/include/core/SkEdgeClipper.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2009 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkEdgeClipper_DEFINED
#define SkEdgeClipper_DEFINED
diff --git a/include/core/SkEmptyShader.h b/include/core/SkEmptyShader.h
new file mode 100644
index 0000000..bf270bf
--- /dev/null
+++ b/include/core/SkEmptyShader.h
@@ -0,0 +1,43 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef SkEmptyShader_DEFINED
+#define SkEmptyShader_DEFINED
+
+#include "SkShader.h"
+
+/**
+ * \class SkEmptyShader
+ * A Shader that always draws nothing. Its setContext always returns false,
+ * so it never expects that its shadeSpan() methods will get called.
+ */
+class SK_API SkEmptyShader : public SkShader {
+public:
+ SkEmptyShader() {}
+
+ virtual uint32_t getFlags() SK_OVERRIDE;
+ virtual uint8_t getSpan16Alpha() const SK_OVERRIDE;
+ virtual bool setContext(const SkBitmap&, const SkPaint&,
+ const SkMatrix&) SK_OVERRIDE;
+ virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE;
+ virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) SK_OVERRIDE;
+
+protected:
+ SkEmptyShader(SkFlattenableReadBuffer&);
+
+ virtual Factory getFactory() SK_OVERRIDE;
+ virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+
+private:
+ typedef SkShader INHERITED;
+};
+
+#endif
diff --git a/include/core/SkEndian.h b/include/core/SkEndian.h
index a72dfe3..3eb67da 100644
--- a/include/core/SkEndian.h
+++ b/include/core/SkEndian.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkEndian_DEFINED
#define SkEndian_DEFINED
@@ -87,6 +80,19 @@ static inline void SkEndianSwap32s(uint32_t array[], int count) {
#define SkEndian_SwapLE32(n) SkEndianSwap32(n)
#endif
+// When a bytestream is embedded in a 32-bit word, how far we need to
+// shift the word to extract each byte from the low 8 bits by anding with 0xff.
+#ifdef SK_CPU_LENDIAN
+ #define SkEndian_Byte0Shift 0
+ #define SkEndian_Byte1Shift 8
+ #define SkEndian_Byte2Shift 16
+ #define SkEndian_Byte3Shift 24
+#else // SK_CPU_BENDIAN
+ #define SkEndian_Byte0Shift 24
+ #define SkEndian_Byte1Shift 16
+ #define SkEndian_Byte2Shift 8
+ #define SkEndian_Byte3Shift 0
+#endif
#endif
diff --git a/include/core/SkFDot6.h b/include/core/SkFDot6.h
index 9d56116..aa58857 100644
--- a/include/core/SkFDot6.h
+++ b/include/core/SkFDot6.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkFDot6_DEFINED
#define SkFDot6_DEFINED
diff --git a/include/core/SkFixed.h b/include/core/SkFixed.h
index 8b56c50..0af5d9d 100644
--- a/include/core/SkFixed.h
+++ b/include/core/SkFixed.h
@@ -1,23 +1,16 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkFixed_DEFINED
#define SkFixed_DEFINED
-#include "SkMath.h"
+#include "SkTypes.h"
/** \file SkFixed.h
@@ -103,17 +96,23 @@ inline SkFixed SkFixedFraction(SkFixed x)
/** 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 SkFixedRoundToInt(x) (((x) + SK_FixedHalf) >> 16)
+#define SkFixedCeilToInt(x) (((x) + SK_Fixed1 - 1) >> 16)
+#define SkFixedFloorToInt(x) ((x) >> 16)
+
+#define SkFixedRoundToFixed(x) (((x) + SK_FixedHalf) & 0xFFFF0000)
+#define SkFixedCeilToFixed(x) (((x) + SK_Fixed1 - 1) & 0xFFFF0000)
+#define SkFixedFloorToFixed(x) ((x) & 0xFFFF0000)
+
+// DEPRECATED
+#define SkFixedFloor(x) SkFixedFloorToInt(x)
+#define SkFixedCeil(x) SkFixedCeilToInt(x)
+#define SkFixedRound(x) SkFixedRoundToInt(x)
+
#define SkFixedAbs(x) SkAbs32(x)
#define SkFixedAve(a, b) (((a) + (b)) >> 1)
-// The same as SkIntToFixed(SkFixedFloor(x))
-#define SkFixedFloorToFixed(x) ((x) & ~0xFFFF)
-
SkFixed SkFixedMul_portable(SkFixed, SkFixed);
SkFract SkFractMul_portable(SkFract, SkFract);
inline SkFixed SkFixedSquare_portable(SkFixed value)
diff --git a/include/core/SkFlate.h b/include/core/SkFlate.h
index b606742..c111de0 100644
--- a/include/core/SkFlate.h
+++ b/include/core/SkFlate.h
@@ -1,25 +1,19 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2010 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkFlate_DEFINED
#define SkFlate_DEFINED
#include "SkTypes.h"
-class SkDynamicMemoryWStream;
+class SkData;
+class SkWStream;
class SkStream;
/** \class SkFlate
@@ -31,15 +25,28 @@ public:
*/
static bool HaveFlate();
- /** Use the flate compression algorithm to compress the data in src,
- putting the result into dst. Returns false if an error occurs.
+ /**
+ * Use the flate compression algorithm to compress the data in src,
+ * putting the result into dst. Returns false if an error occurs.
*/
- static bool Deflate(SkStream* src, SkDynamicMemoryWStream* dst);
-
+ static bool Deflate(SkStream* src, SkWStream* dst);
+
+ /**
+ * Use the flate compression algorithm to compress the data in src,
+ * putting the result into dst. Returns false if an error occurs.
+ */
+ static bool Deflate(const void* src, size_t len, SkWStream* dst);
+
+ /**
+ * Use the flate compression algorithm to compress the data,
+ * putting the result into dst. Returns false if an error occurs.
+ */
+ static bool Deflate(const SkData*, SkWStream* dst);
+
/** Use the flate compression algorithm to decompress the data in src,
putting the result into dst. Returns false if an error occurs.
*/
- static bool Inflate(SkStream* src, SkDynamicMemoryWStream* dst);
+ static bool Inflate(SkStream* src, SkWStream* dst);
};
#endif
diff --git a/include/core/SkFlattenable.h b/include/core/SkFlattenable.h
index 03bcab8..a66638e 100644
--- a/include/core/SkFlattenable.h
+++ b/include/core/SkFlattenable.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkFlattenable_DEFINED
#define SkFlattenable_DEFINED
@@ -27,6 +20,40 @@ class SkFlattenableReadBuffer;
class SkFlattenableWriteBuffer;
class SkString;
+#if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+
+#define SK_DECLARE_FLATTENABLE_REGISTRAR()
+
+#define SK_DEFINE_FLATTENABLE_REGISTRAR(flattenable) \
+ static SkFlattenable::Registrar g##flattenable##Reg(#flattenable, \
+ flattenable::CreateProc);
+
+#define SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(flattenable)
+#define SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(flattenable) \
+ static SkFlattenable::Registrar g##flattenable##Reg(#flattenable, \
+ flattenable::CreateProc);
+#define SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
+
+#else
+
+#define SK_DECLARE_FLATTENABLE_REGISTRAR() static void Init();
+
+#define SK_DEFINE_FLATTENABLE_REGISTRAR(flattenable) \
+ void flattenable::Init() { \
+ SkFlattenable::Registrar(#flattenable, CreateProc); \
+ }
+
+#define SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(flattenable) \
+ void flattenable::Init() {
+
+#define SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(flattenable) \
+ SkFlattenable::Registrar(#flattenable, flattenable::CreateProc);
+
+#define SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END \
+ }
+
+#endif
+
/** \class SkFlattenable
SkFlattenable is the base class for objects that need to be flattened
@@ -68,6 +95,13 @@ public:
protected:
SkFlattenable(SkFlattenableReadBuffer&) {}
+
+private:
+#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+ static void InitializeFlattenables();
+#endif
+
+ friend class SkGraphics;
};
// helpers for matrix and region
@@ -100,11 +134,27 @@ public:
fTFArray = array;
fTFCount = count;
}
-
+
+ /**
+ * Call this with a pre-loaded array of Factories, in the same order as
+ * were created/written by the writer. SkPicture uses this.
+ */
void setFactoryPlayback(SkFlattenable::Factory array[], int count) {
+ fFactoryTDArray = NULL;
fFactoryArray = array;
fFactoryCount = count;
}
+
+ /**
+ * Call this with an initially empty array, so the reader can cache each
+ * factory it sees by name. Used by the pipe code in conjunction with
+ * the writer's kInlineFactoryNames_Flag.
+ */
+ void setFactoryArray(SkTDArray<SkFlattenable::Factory>* array) {
+ fFactoryTDArray = array;
+ fFactoryArray = NULL;
+ fFactoryCount = 0;
+ }
SkTypeface* readTypeface();
SkRefCnt* readRefCnt();
@@ -118,6 +168,7 @@ private:
SkTypeface** fTFArray;
int fTFCount;
+ SkTDArray<SkFlattenable::Factory>* fFactoryTDArray;
SkFlattenable::Factory* fFactoryArray;
int fFactoryCount;
@@ -165,12 +216,22 @@ public:
SkFactorySet* setFactoryRecorder(SkFactorySet*);
enum Flags {
- kCrossProcess_Flag = 0x01
+ kCrossProcess_Flag = 0x01,
+ /**
+ * Instructs the writer to inline Factory names as there are seen the
+ * first time (after that we store an index). The pipe code uses this.
+ */
+ kInlineFactoryNames_Flag = 0x02,
};
- Flags getFlags() const { return fFlags; }
+ Flags getFlags() const { return (Flags)fFlags; }
void setFlags(Flags flags) { fFlags = flags; }
- bool isCrossProcess() const { return (fFlags & kCrossProcess_Flag) != 0; }
+ bool isCrossProcess() const {
+ return SkToBool(fFlags & kCrossProcess_Flag);
+ }
+ bool inlineFactoryNames() const {
+ return SkToBool(fFlags & kInlineFactoryNames_Flag);
+ }
bool persistBitmapPixels() const {
return (fFlags & kCrossProcess_Flag) != 0;
@@ -179,10 +240,10 @@ public:
bool persistTypeface() const { return (fFlags & kCrossProcess_Flag) != 0; }
private:
- Flags fFlags;
- SkRefCntSet* fTFSet;
- SkRefCntSet* fRCSet;
- SkFactorySet* fFactorySet;
+ uint32_t fFlags;
+ SkRefCntSet* fTFSet;
+ SkRefCntSet* fRCSet;
+ SkFactorySet* fFactorySet;
typedef SkWriter32 INHERITED;
};
diff --git a/include/core/SkFloatBits.h b/include/core/SkFloatBits.h
index 288f2d8..e6fc5b5 100644
--- a/include/core/SkFloatBits.h
+++ b/include/core/SkFloatBits.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkFloatBits_DEFINED
#define SkFloatBits_DEFINED
diff --git a/include/core/SkFloatingPoint.h b/include/core/SkFloatingPoint.h
index 8c3bb83..ee91cd9 100644
--- a/include/core/SkFloatingPoint.h
+++ b/include/core/SkFloatingPoint.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkFloatingPoint_DEFINED
#define SkFloatingPoint_DEFINED
@@ -65,12 +58,24 @@ static inline float sk_float_copysign(float x, float y) {
#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_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
+
+#ifdef SK_BUILD_FOR_WIN
+ #define sk_float_isfinite(x) _finite(x)
+ #define sk_float_isnan(x) _isnan(x)
+ static inline int sk_float_isinf(float x) {
+ int32_t bits = SkFloat2Bits(x);
+ return (bits << 1) == (0xFF << 24);
+ }
+#else
+ #define sk_float_isfinite(x) isfinite(x)
+ #define sk_float_isnan(x) isnan(x)
+ #define sk_float_isinf(x) isinf(x)
#endif
#ifdef SK_USE_FLOATBITS
diff --git a/include/core/SkFontHost.h b/include/core/SkFontHost.h
index e20ea05..c549519 100644
--- a/include/core/SkFontHost.h
+++ b/include/core/SkFontHost.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkFontHost_DEFINED
#define SkFontHost_DEFINED
@@ -31,7 +24,7 @@ typedef uint32_t SkFontTableTag;
This class is ported to each environment. It is responsible for bridging
the gap between the (sort of) abstract class SkTypeface and the
platform-specific implementation that provides access to font files.
-
+
One basic task is for each create (subclass of) SkTypeface, the FontHost is
resonsible for assigning a uniqueID. The ID should be unique for the
underlying font file/data, not unique per typeface instance. Thus it is
@@ -43,7 +36,7 @@ typedef uint32_t SkFontTableTag;
returned). Either way, the fontID for those instance(s) will be the same.
In addition, the fontID should never be set to 0. That value is used as a
sentinel to indicate no-font-id.
-
+
The major aspects are:
1) Given either a name/style, return a subclass of SkTypeface that
references the closest matching font available on the host system.
@@ -72,17 +65,17 @@ public:
/** Return a new typeface given the data buffer. If the data does not
represent a valid font, returns null.
-
+
If a typeface instance is returned, the caller is responsible for
calling unref() on the typeface when they are finished with it.
-
+
The returned typeface may or may not have called ref() on the stream
parameter. If the typeface has not called ref(), then it may have made
a copy of the releveant data. In either case, the caller is still
- responsible for its refcnt ownership of the stream.
+ responsible for its refcnt ownership of the stream.
*/
static SkTypeface* CreateTypefaceFromStream(SkStream*);
-
+
/** Return a new typeface from the specified file path. If the file does not
represent a valid font, this returns null. If a typeface is returned,
the caller is responsible for calling unref() when it is no longer used.
@@ -90,13 +83,13 @@ public:
static SkTypeface* CreateTypefaceFromFile(const char path[]);
///////////////////////////////////////////////////////////////////////////
-
+
/** Returns true if the specified unique ID matches an existing font.
Returning false is similar to calling OpenStream with an invalid ID,
which will return NULL in that case.
*/
static bool ValidFontID(SkFontID uniqueID);
-
+
/** Return a new stream to read the font data, or null if the uniqueID does
not match an existing typeface. .The caller must call stream->unref()
when it is finished reading the data.
@@ -145,7 +138,7 @@ public:
static SkTypeface* Deserialize(SkStream*);
///////////////////////////////////////////////////////////////////////////
-
+
/** Return a subclass of SkScalarContext
*/
static SkScalerContext* CreateScalerContext(const SkDescriptor* desc);
@@ -188,10 +181,17 @@ public:
names, etc.) should be populated.
@return The returned object has already been referenced. NULL is
returned if the font is not found.
+ @param glyphIDs For per-glyph info, specify subset of the font by
+ giving glyph ids. Each integer represents a glyph
+ id. Passing NULL means all glyphs in the font.
+ @param glyphIDsCount Number of elements in subsetGlyphIds. Ignored if
+ glyphIDs is NULL.
*/
static SkAdvancedTypefaceMetrics* GetAdvancedTypefaceMetrics(
SkFontID fontID,
- SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo);
+ SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
+ const uint32_t* glyphIDs,
+ uint32_t glyphIDsCount);
/** Return the number of tables in the font
*/
@@ -206,7 +206,7 @@ public:
/** Given a table tag, return the size of its contents, or 0 if not present
*/
static size_t GetTableSize(SkFontID, SkFontTableTag);
-
+
/** Copy the contents of a table into data (allocated by the caller). Note
that the contents of the table will be in their native endian order
(which for most truetype tables is big endian). If the table tag is
@@ -232,20 +232,9 @@ public:
///////////////////////////////////////////////////////////////////////////
- /** Return the number of bytes (approx) that should be purged from the font
- cache. The input parameter is the cache's estimate of how much as been
- allocated by the cache so far.
- To purge (basically) everything, return the input parameter.
- To purge nothing, return 0
- */
- static size_t ShouldPurgeFontCache(size_t sizeAllocatedSoFar);
+ /** DEPRECATED -- only called by SkFontHost_FreeType internally
- /** Return SkScalerContext gamma flag, or 0, based on the paint that will be
- used to draw something with antialiasing.
- */
- static int ComputeGammaFlag(const SkPaint& paint);
-
- /** Return NULL or a pointer to 256 bytes for the black (table[0]) and
+ Return NULL or a pointer to 256 bytes for the black (table[0]) and
white (table[1]) gamma tables.
*/
static void GetGammaTables(const uint8_t* tables[2]);
@@ -286,7 +275,7 @@ public:
static void SetSubpixelOrder(LCDOrder order);
static LCDOrder GetSubpixelOrder();
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
///////////////////////////////////////////////////////////////////////////
/**
@@ -297,7 +286,14 @@ public:
*/
static uint32_t GetUnitsPerEm(SkFontID fontID);
#endif
+
+ /** If Skia is running in a constrained environment and the typeface
+ implementation is handle based, the typeface data may become
+ unavailable asynchronously. If a font host or scaler context method is
+ unable to access font data, it may call this function as a request to
+ make the handle contained in the typeface useable.
+ */
+ static void EnsureTypefaceAccessible(const SkTypeface& typeface);
};
#endif
-
diff --git a/include/core/SkGeometry.h b/include/core/SkGeometry.h
index 000ca73..26f27ba 100644
--- a/include/core/SkGeometry.h
+++ b/include/core/SkGeometry.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkGeometry.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkGeometry_DEFINED
#define SkGeometry_DEFINED
@@ -113,7 +105,11 @@ void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint* locOrNull,
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[],
+/** Given a src cubic bezier, chop it at the specified t values,
+ where 0 < t < 1, and return the new cubics in dst:
+ dst[0..3],dst[3..6],...,dst[3*t_count..3*(t_count+1)]
+*/
+void SkChopCubicAt(const SkPoint src[4], SkPoint dst[], const SkScalar t[],
int t_count);
/** Given a src cubic bezier, chop it at the specified t == 1/2,
@@ -149,8 +145,9 @@ int SkChopCubicAtXExtrema(const SkPoint src[4], SkPoint dst[10]);
*/
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.
+/** Return 1 for no chop, 2 for having chopped the cubic at a single
+ inflection point, 3 for having chopped at 2 inflection points.
+ dst will hold the resulting 1, 2, or 3 cubics.
*/
int SkChopCubicAtInflections(const SkPoint src[4], SkPoint dst[10]);
diff --git a/include/core/SkGlobals.h b/include/core/SkGlobals.h
deleted file mode 100644
index 8e28290..0000000
--- a/include/core/SkGlobals.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SkGlobals_DEFINED
-#define SkGlobals_DEFINED
-
-#include "SkThread.h"
-
-class SkGlobals {
-public:
- class Rec {
- public:
- virtual ~Rec();
- private:
- Rec* fNext;
- uint32_t 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 null, return null, 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(uint32_t tag, Rec* (*create_proc)());
- /** Helper for Find, when you want to assert that the Rec is already in the list
- */
- static Rec* Get(uint32_t tag)
- {
- Rec* rec = SkGlobals::Find(tag, NULL);
- 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/core/SkGraphics.h b/include/core/SkGraphics.h
index 25c926f..c89758b 100644
--- a/include/core/SkGraphics.h
+++ b/include/core/SkGraphics.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkGraphics_DEFINED
#define SkGraphics_DEFINED
@@ -21,24 +14,57 @@
class SkGraphics {
public:
+ /**
+ * Call this at process initialization time if your environment does not
+ * permit static global initializers that execute code. Note that
+ * Init() is not thread-safe.
+ */
static void Init();
- static void Term();
- /** Return the (approximate) number of bytes used by the font cache.
- */
- static size_t GetFontCacheUsed();
-
- /** Attempt to purge the font cache until <= the specified amount remains
- in the cache. Specifying 0 will attempt to purge the entire cache.
- Returns true if some amount was purged from the font cache.
- */
- static bool SetFontCacheUsed(size_t usageInBytes);
+ /**
+ * Call this to release any memory held privately, such as the font cache.
+ */
+ static void Term();
- /** Return the version numbers for the library. If the parameter is not
- null, it is set to the version number.
+ /**
+ * Return the version numbers for the library. If the parameter is not
+ * null, it is set to the version number.
*/
static void GetVersion(int32_t* major, int32_t* minor, int32_t* patch);
+ /**
+ * Return the max number of bytes that should be used by the font cache.
+ * If the cache needs to allocate more, it will purge previous entries.
+ * This max can be changed by calling SetFontCacheLimit().
+ */
+ static size_t GetFontCacheLimit();
+
+ /**
+ * Specify the max number of bytes that should be used by the font cache.
+ * If the cache needs to allocate more, it will purge previous entries.
+ *
+ * This function returns the previous setting, as if GetFontCacheLimit()
+ * had be called before the new limit was set.
+ */
+ static size_t SetFontCacheLimit(size_t bytes);
+
+ /**
+ * For debugging purposes, this will attempt to purge the font cache. It
+ * does not change the limit, but will cause subsequent font measures and
+ * draws to be recreated, since they will no longer be in the cache.
+ */
+ static void PurgeFontCache();
+
+ /**
+ * Applications with command line options may pass optional state, such
+ * as cache sizes, here, for instance:
+ * font-cache-limit=12345678
+ *
+ * The flags format is name=value[;name=value...] with no spaces.
+ * This format is subject to change.
+ */
+ static void SetFlags(const char* flags);
+
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
diff --git a/include/core/SkImageFilter.h b/include/core/SkImageFilter.h
new file mode 100644
index 0000000..22b9569
--- /dev/null
+++ b/include/core/SkImageFilter.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkImageFilter_DEFINED
+#define SkImageFilter_DEFINED
+
+#include "SkFlattenable.h"
+
+class SkBitmap;
+class SkDevice;
+class SkMatrix;
+struct SkPoint;
+
+/**
+ * Experimental.
+ *
+ * Base class for image filters. If one is installed in the paint, then
+ * all drawing occurs as usual, but it is as if the drawing happened into an
+ * offscreen (before the xfermode is applied). This offscreen bitmap will
+ * then be handed to the imagefilter, who in turn creates a new bitmap which
+ * is what will finally be drawn to the device (using the original xfermode).
+ *
+ * THIS SIGNATURE IS TEMPORARY
+ *
+ * There are several weaknesses in this function signature:
+ * 1. Does not expose the destination/target device, so filters that can draw
+ * directly to it are unable to take advantage of that optimization.
+ * 2. Does not expose a way to create a "compabitible" image (i.e. gpu -> gpu)
+ * 3. As with #1, the filter is unable to "read" the dest (which would be slow)
+ *
+ * Therefore, we should not create any real dependencies on this API yet -- it
+ * is being checked in as a check-point so we can explore these and other
+ * considerations.
+ */
+class SK_API SkImageFilter : public SkFlattenable {
+public:
+ class Proxy {
+ public:
+ virtual SkDevice* createDevice(int width, int height) = 0;
+
+ // returns true if the proxy handled the filter itself. if this returns
+ // false then the filter's code will be called.
+ virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
+ const SkMatrix& ctm,
+ SkBitmap* result, SkIPoint* offset) = 0;
+ virtual ~Proxy() {};
+ };
+
+ /**
+ * Request a new (result) image to be created from the src image.
+ * If the src has no pixels (isNull()) then the request just wants to
+ * receive the config and width/height of the result.
+ *
+ * The matrix is the current matrix on the canvas.
+ *
+ * Offset is the amount to translate the resulting image relative to the
+ * src when it is drawn.
+ *
+ * If the result image cannot be created, return false, in which case both
+ * the result and offset parameters will be ignored by the caller.
+ */
+ bool filterImage(Proxy*, const SkBitmap& src, const SkMatrix& ctm,
+ SkBitmap* result, SkIPoint* offset);
+
+ /**
+ * Given the src bounds of an image, this returns the bounds of the result
+ * image after the filter has been applied.
+ */
+ bool filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst);
+
+ /**
+ * Experimental.
+ *
+ * If the filter can be expressed as a gaussian-blur, return true and
+ * set the sigma to the values for horizontal and vertical.
+ */
+ virtual bool asABlur(SkSize* sigma) const;
+
+protected:
+ SkImageFilter() {}
+ explicit SkImageFilter(SkFlattenableReadBuffer& rb) : INHERITED(rb) {}
+
+ // Default impl returns false
+ virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
+ SkBitmap* result, SkIPoint* offset);
+ // Default impl copies src into dst and returns true
+ virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*);
+
+private:
+ typedef SkFlattenable INHERITED;
+};
+
+#endif
diff --git a/include/core/SkLineClipper.h b/include/core/SkLineClipper.h
index 4c23781..1958395 100644
--- a/include/core/SkLineClipper.h
+++ b/include/core/SkLineClipper.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkLineClipper_DEFINED
#define SkLineClipper_DEFINED
diff --git a/include/core/SkMMapStream.h b/include/core/SkMMapStream.h
index be063bd..19ba634 100644
--- a/include/core/SkMMapStream.h
+++ b/include/core/SkMMapStream.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkMMapStream_DEFINED
#define SkMMapStream_DEFINED
@@ -26,7 +19,6 @@ public:
virtual void setMemory(const void* data, size_t length, bool);
private:
- int fFildes;
void* fAddr;
size_t fSize;
diff --git a/include/core/SkMallocPixelRef.h b/include/core/SkMallocPixelRef.h
index edaab94..2ceb826 100644
--- a/include/core/SkMallocPixelRef.h
+++ b/include/core/SkMallocPixelRef.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkMallocPixelRef_DEFINED
#define SkMallocPixelRef_DEFINED
@@ -44,6 +37,7 @@ public:
return SkNEW_ARGS(SkMallocPixelRef, (buffer));
}
+ SK_DECLARE_PIXEL_REF_REGISTRAR()
protected:
// overrides from SkPixelRef
virtual void* onLockPixels(SkColorTable**);
diff --git a/include/core/SkMask.h b/include/core/SkMask.h
index f437622..3f9a114 100644
--- a/include/core/SkMask.h
+++ b/include/core/SkMask.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkMask_DEFINED
#define SkMask_DEFINED
@@ -28,30 +21,13 @@ struct SkMask {
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
-
- /* The LCD formats look like this in memory:
-
- First, there's an A8 plane which contains the average alpha value for
- each pixel. Because of this, the LCD formats can be passed directly
- to functions which expect an A8 and everything will just work.
-
- After that in memory, there's a bitmap of 32-bit values which have
- been RGB order corrected for the current screen (based on the
- settings in SkFontHost at the time of renderering). The alpha value
- for each pixel is the maximum of the three alpha values.
-
- kHorizontalLCD_Format has an extra column of pixels on the left and right
- edges. kVerticalLCD_Format has an extra row at the top and bottom.
- */
-
- kHorizontalLCD_Format, //!< 4 bytes/pixel: a/r/g/b
- kVerticalLCD_Format, //!< 4 bytes/pixel: a/r/g/b
kARGB32_Format, //!< SkPMColor
- kLCD16_Format //!< 565 alpha for r/g/b
+ kLCD16_Format, //!< 565 alpha for r/g/b
+ kLCD32_Format //!< 888 alpha for r/g/b
};
enum {
- kCountMaskFormats = kVerticalLCD_Format + 1
+ kCountMaskFormats = kLCD32_Format + 1
};
uint8_t* fImage;
@@ -80,7 +56,7 @@ struct SkMask {
x,y are in the same coordiate space as fBounds.
*/
uint8_t* getAddr1(int x, int y) const {
- SkASSERT(fFormat == kBW_Format);
+ SkASSERT(kBW_Format == fFormat);
SkASSERT(fBounds.contains(x, y));
SkASSERT(fImage != NULL);
return fImage + ((x - fBounds.fLeft) >> 3) + (y - fBounds.fTop) * fRowBytes;
@@ -90,8 +66,8 @@ struct SkMask {
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);
+ uint8_t* getAddr8(int x, int y) const {
+ SkASSERT(kA8_Format == fFormat);
SkASSERT(fBounds.contains(x, y));
SkASSERT(fImage != NULL);
return fImage + x - fBounds.fLeft + (y - fBounds.fTop) * fRowBytes;
@@ -110,28 +86,32 @@ struct SkMask {
return row + (x - fBounds.fLeft);
}
- /** Return an address into the 32-bit plane of an LCD or VerticalLCD mask
- for the given position.
- */
- const uint32_t* getAddrLCD(int x, int y) const {
- SkASSERT(fFormat == kHorizontalLCD_Format || fFormat == kVerticalLCD_Format);
+ /**
+ * Return the address of the specified 32bit mask. In the debug build,
+ * this asserts that the mask's format is kLCD32_Format, and that (x,y)
+ * are contained in the mask's fBounds.
+ */
+ uint32_t* getAddrLCD32(int x, int y) const {
+ SkASSERT(kLCD32_Format == fFormat);
+ SkASSERT(fBounds.contains(x, y));
SkASSERT(fImage != NULL);
-
- return reinterpret_cast<const uint32_t*>(fImage + SkAlign4(fRowBytes * fBounds.height())) +
- x - fBounds.fLeft + (y - fBounds.fTop) * rowWordsLCD();
+ uint32_t* row = (uint32_t*)(fImage + (y - fBounds.fTop) * fRowBytes);
+ return row + (x - fBounds.fLeft);
}
- /** Return the number of 32-bit words in a row of the 32-bit plane of an
- LCD or VerticalLCD mask.
- */
- unsigned rowWordsLCD() const {
- SkASSERT(fFormat == kHorizontalLCD_Format || fFormat == kVerticalLCD_Format);
- if (fFormat == kHorizontalLCD_Format) {
- return fBounds.width() + 2;
- } else {
- return fBounds.width();
- }
- }
+ /**
+ * Returns the address of the specified pixel, computing the pixel-size
+ * at runtime based on the mask format. This will be slightly slower than
+ * using one of the routines where the format is implied by the name
+ * e.g. getAddr8 or getAddrLCD32.
+ *
+ * x,y must be contained by the mask's bounds (this is asserted in the
+ * debug build, but not checked in the release build.)
+ *
+ * This should not be called with kBW_Format, as it will give unspecified
+ * results (and assert in the debug build).
+ */
+ void* getAddr(int x, int y) const;
static uint8_t* AllocImage(size_t bytes);
static void FreeImage(void* image);
@@ -141,10 +121,28 @@ struct SkMask {
kJustRenderImage_CreateMode, //!< render into preallocate mask
kComputeBoundsAndRenderImage_CreateMode //!< compute bounds, alloc image and render into it
};
+};
+
+///////////////////////////////////////////////////////////////////////////////
- static bool FormatIsLCD(Format fm) {
- return kHorizontalLCD_Format == fm || kVerticalLCD_Format == fm;
+/**
+ * \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 SkAutoMaskFreeImage {
+public:
+ SkAutoMaskFreeImage(uint8_t* maskImage) {
+ fImage = maskImage;
+ }
+
+ ~SkAutoMaskFreeImage() {
+ SkMask::FreeImage(fImage);
}
+
+private:
+ uint8_t* fImage;
};
#endif
diff --git a/include/core/SkMaskFilter.h b/include/core/SkMaskFilter.h
index 60dade9..2808de7 100644
--- a/include/core/SkMaskFilter.h
+++ b/include/core/SkMaskFilter.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkMaskFilter_DEFINED
#define SkMaskFilter_DEFINED
@@ -24,7 +17,7 @@ class SkBlitter;
class SkBounder;
class SkMatrix;
class SkPath;
-class SkRegion;
+class SkRasterClip;
/** \class SkMaskFilter
@@ -62,16 +55,30 @@ public:
virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
SkIPoint* 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);
-
virtual void flatten(SkFlattenableWriteBuffer& ) {}
+ enum BlurType {
+ kNone_BlurType, //!< this maskfilter is not a blur
+ kNormal_BlurType, //!< fuzzy inside and outside
+ kSolid_BlurType, //!< solid inside, fuzzy outside
+ kOuter_BlurType, //!< nothing inside, fuzzy outside
+ kInner_BlurType, //!< fuzzy inside, nothing outside
+ };
+
+ struct BlurInfo {
+ SkScalar fRadius;
+ bool fIgnoreTransform;
+ bool fHighQuality;
+ };
+
+ /**
+ * Optional method for maskfilters that can be described as a blur. If so,
+ * they return the corresponding BlurType and set the fields in BlurInfo
+ * (if not null). If they cannot be described as a blur, they return
+ * kNone_BlurType and ignore the info parameter.
+ */
+ virtual BlurType asABlur(BlurInfo*) const;
+
/**
* The fast bounds function is used to enable the paint to be culled early
* in the drawing pipeline. This function accepts the current bounds of the
@@ -88,27 +95,17 @@ public:
protected:
// empty for now, but lets get our subclass to remember to init us for the future
SkMaskFilter(SkFlattenableReadBuffer&) {}
-};
-/** \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;
+ friend class SkDraw;
+
+ /** 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 SkRasterClip&, SkBounder*, SkBlitter* blitter);
};
#endif
diff --git a/include/core/SkMath.h b/include/core/SkMath.h
index efe378a..5889103 100644
--- a/include/core/SkMath.h
+++ b/include/core/SkMath.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkMath_DEFINED
#define SkMath_DEFINED
diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h
index 480e077..8fdb818 100644
--- a/include/core/SkMatrix.h
+++ b/include/core/SkMatrix.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkMatrix_DEFINED
#define SkMatrix_DEFINED
@@ -21,6 +14,16 @@
class SkString;
+#ifdef SK_SCALAR_IS_FLOAT
+ typedef SkScalar SkPersp;
+ #define SkScalarToPersp(x) (x)
+ #define SkPerspToScalar(x) (x)
+#else
+ typedef SkFract SkPersp;
+ #define SkScalarToPersp(x) SkFixedToFract(x)
+ #define SkPerspToScalar(x) SkFractToFixed(x)
+#endif
+
/** \class SkMatrix
The SkMatrix class holds a 3x3 matrix for transforming coordinates.
@@ -74,10 +77,11 @@ public:
bool preservesAxisAlignment() const { return this->rectStaysRect(); }
/**
- * Returns true if the perspective contains perspective elements.
+ * Returns true if the matrix contains perspective elements.
*/
bool hasPerspective() const {
- return SkToBool(this->getType() & kPerspective_Mask);
+ return SkToBool(this->getPerspectiveTypeMaskOnly() &
+ kPerspective_Mask);
}
enum {
@@ -92,6 +96,18 @@ public:
kMPersp2
};
+ /** Affine arrays are in column major order
+ because that's how PDF and XPS like it.
+ */
+ enum {
+ kAScaleX,
+ kASkewY,
+ kASkewX,
+ kAScaleY,
+ kATransX,
+ kATransY
+ };
+
SkScalar operator[](int index) const {
SkASSERT((unsigned)index < 9);
return fMat[index];
@@ -108,8 +124,8 @@ public:
SkScalar getSkewX() const { return fMat[kMSkewX]; }
SkScalar getTranslateX() const { return fMat[kMTransX]; }
SkScalar getTranslateY() const { return fMat[kMTransY]; }
- SkScalar getPerspX() const { return fMat[kMPersp0]; }
- SkScalar getPerspY() const { return fMat[kMPersp1]; }
+ SkPersp getPerspX() const { return fMat[kMPersp0]; }
+ SkPersp getPerspY() const { return fMat[kMPersp1]; }
SkScalar& operator[](int index) {
SkASSERT((unsigned)index < 9);
@@ -129,12 +145,12 @@ public:
void setSkewX(SkScalar v) { this->set(kMSkewX, v); }
void setTranslateX(SkScalar v) { this->set(kMTransX, v); }
void setTranslateY(SkScalar v) { this->set(kMTransY, v); }
- void setPerspX(SkScalar v) { this->set(kMPersp0, v); }
- void setPerspY(SkScalar v) { this->set(kMPersp1, v); }
+ void setPerspX(SkPersp v) { this->set(kMPersp0, v); }
+ void setPerspY(SkPersp v) { this->set(kMPersp1, v); }
void setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX,
SkScalar skewY, SkScalar scaleY, SkScalar transY,
- SkScalar persp0, SkScalar persp1, SkScalar persp2) {
+ SkPersp persp0, SkPersp persp1, SkPersp persp2) {
fMat[kMScaleX] = scaleX;
fMat[kMSkewX] = skewX;
fMat[kMTransX] = transX;
@@ -164,6 +180,10 @@ public:
/** Set the matrix to scale by sx and sy.
*/
void setScale(SkScalar sx, SkScalar sy);
+ /** Set the matrix to scale by 1/divx and 1/divy. Returns false and doesn't
+ touch the matrix if either divx or divy is zero.
+ */
+ bool setIDiv(int divx, int divy);
/** 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.
@@ -318,12 +338,19 @@ public:
*/
bool invert(SkMatrix* inverse) const;
- /** Fills the passed array with the tranform values in the right order
- for PDFs. If the matrix is a perspective transform, returns false
- and fills the array with an identity transform.
- @param transform The array to fill in.
+ /** Fills the passed array with affine identity values
+ in column major order.
+ @param affine The array to fill with affine identity values.
+ Must not be NULL.
*/
- bool pdfTransform(SkScalar transform[6]) const;
+ static void SetAffineIdentity(SkScalar affine[6]);
+
+ /** Fills the passed array with the affine values in column major order.
+ If the matrix is a perspective transform, returns false
+ and does not change the passed array.
+ @param affine The array to fill with affine values. Ignored if NULL.
+ */
+ bool asAffine(SkScalar affine[6]) 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.
@@ -348,6 +375,31 @@ public:
this->mapPoints(pts, pts, count);
}
+ /** Like mapPoints but with custom byte stride between the points. Stride
+ * should be a multiple of sizeof(SkScalar).
+ */
+ void mapPointsWithStride(SkPoint pts[], size_t stride, int count) const {
+ SkASSERT(stride >= sizeof(SkPoint));
+ SkASSERT(0 == stride % sizeof(SkScalar));
+ for (int i = 0; i < count; ++i) {
+ this->mapPoints(pts, pts, 1);
+ pts = (SkPoint*)((intptr_t)pts + stride);
+ }
+ }
+
+ /** Like mapPoints but with custom byte stride between the points.
+ */
+ void mapPointsWithStride(SkPoint dst[], SkPoint src[],
+ size_t stride, int count) const {
+ SkASSERT(stride >= sizeof(SkPoint));
+ SkASSERT(0 == stride % sizeof(SkScalar));
+ for (int i = 0; i < count; ++i) {
+ this->mapPoints(dst, src, 1);
+ src = (SkPoint*)((intptr_t)src + stride);
+ dst = (SkPoint*)((intptr_t)dst + stride);
+ }
+ }
+
void mapXY(SkScalar x, SkScalar y, SkPoint* result) const {
SkASSERT(result);
this->getMapXYProc()(*this, x, y, result);
@@ -395,13 +447,6 @@ public:
return this->mapRect(rect, *rect);
}
- void mapPointsWithStride(SkPoint pts[], size_t stride, int count) const {
- for (int i = 0; i < count; ++i) {
- this->mapPoints(pts, pts, 1);
- pts = (SkPoint*)((intptr_t)pts + stride);
- }
- }
-
/** 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.
@@ -466,10 +511,10 @@ public:
void toDumpString(SkString*) const;
/**
- * Calculates the maximum stretching factor of the matrix. Only defined if
- * the matrix does not have perspective.
+ * Calculates the maximum stretching factor of the matrix. If the matrix has
+ * perspective -1 is returned.
*
- * @return maximum strecthing factor or negative if matrix has perspective.
+ * @return maximum strecthing factor
*/
SkScalar getMaxStretch() const;
@@ -484,6 +529,14 @@ public:
*/
static const SkMatrix& InvalidMatrix();
+ /**
+ * Testing routine; the matrix's type cache should never need to be
+ * manually invalidated during normal use.
+ */
+ void dirtyMatrixTypeCache() {
+ this->setTypeMask(kUnknown_Mask);
+ }
+
private:
enum {
/** Set if the matrix will map a rectangle to another rectangle. This
@@ -494,6 +547,11 @@ private:
*/
kRectStaysRect_Mask = 0x10,
+ /** Set if the perspective bit is valid even though the rest of
+ the matrix is Unknown.
+ */
+ kOnlyPerspectiveValid_Mask = 0x40,
+
kUnknown_Mask = 0x80,
kORableMasks = kTranslate_Mask |
@@ -512,10 +570,13 @@ private:
mutable uint8_t fTypeMask;
uint8_t computeTypeMask() const;
+ uint8_t computePerspectiveTypeMask() const;
void setTypeMask(int mask) {
// allow kUnknown or a valid mask
- SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask);
+ SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask ||
+ ((kUnknown_Mask | kOnlyPerspectiveValid_Mask | kPerspective_Mask) & mask)
+ == mask);
fTypeMask = SkToU8(mask);
}
@@ -529,6 +590,24 @@ private:
SkASSERT((mask & kAllMasks) == mask);
fTypeMask &= ~mask;
}
+
+ TypeMask getPerspectiveTypeMaskOnly() const {
+ if ((fTypeMask & kUnknown_Mask) &&
+ !(fTypeMask & kOnlyPerspectiveValid_Mask)) {
+ fTypeMask = this->computePerspectiveTypeMask();
+ }
+ return (TypeMask)(fTypeMask & 0xF);
+ }
+
+ /** Returns true if we already know that the matrix is identity;
+ false otherwise.
+ */
+ bool isTriviallyIdentity() const {
+ if (fTypeMask & kUnknown_Mask) {
+ return false;
+ }
+ return ((fTypeMask & 0xF) == 0);
+ }
static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
@@ -560,4 +639,3 @@ private:
};
#endif
-
diff --git a/include/core/SkMetaData.h b/include/core/SkMetaData.h
index 1c34fd5..86f186f 100644
--- a/include/core/SkMetaData.h
+++ b/include/core/SkMetaData.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkMetaData_DEFINED
#define SkMetaData_DEFINED
diff --git a/include/core/SkOSFile.h b/include/core/SkOSFile.h
index de8090c..9f01ead 100644
--- a/include/core/SkOSFile.h
+++ b/include/core/SkOSFile.h
@@ -1,26 +1,19 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
//
#ifndef SkOSFile_DEFINED
#define SkOSFile_DEFINED
#include "SkString.h"
-#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
+#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
#include <dirent.h>
#endif
@@ -55,13 +48,17 @@ public:
~Iter();
void reset(const char path[], const char suffix[] = NULL);
+ /** If getDir is true, only returns directories.
+ Results are undefined if true and false calls are
+ interleaved on a single iterator.
+ */
bool next(SkString* name, bool getDir = false);
private:
#ifdef SK_BUILD_FOR_WIN
HANDLE fHandle;
uint16_t* fPath16;
-#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
+#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
DIR* fDIR;
SkString fPath, fSuffix;
#endif
diff --git a/include/core/SkPackBits.h b/include/core/SkPackBits.h
index c11231b..f0614a0 100644
--- a/include/core/SkPackBits.h
+++ b/include/core/SkPackBits.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPackBits_DEFINED
#define SkPackBits_DEFINED
diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h
index 9b547a4..445f7eb 100644
--- a/include/core/SkPaint.h
+++ b/include/core/SkPaint.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPaint_DEFINED
#define SkPaint_DEFINED
@@ -29,6 +22,7 @@ class SkFlattenableWriteBuffer;
struct SkGlyph;
struct SkRect;
class SkGlyphCache;
+class SkImageFilter;
class SkMaskFilter;
class SkMatrix;
class SkPath;
@@ -55,8 +49,8 @@ public:
SkPaint& operator=(const SkPaint&);
- SK_API friend int operator==(const SkPaint& a, const SkPaint& b);
- friend int operator!=(const SkPaint& a, const SkPaint& b) {
+ SK_API friend bool operator==(const SkPaint& a, const SkPaint& b);
+ friend bool operator!=(const SkPaint& a, const SkPaint& b) {
return !(a == b);
}
@@ -105,10 +99,12 @@ public:
kLCDRenderText_Flag = 0x200, //!< mask to enable subpixel glyph renderering
kEmbeddedBitmapText_Flag = 0x400, //!< mask to enable embedded bitmap strikes
kAutoHinting_Flag = 0x800, //!< mask to force Freetype's autohinter
+ kVerticalText_Flag = 0x1000,
+
// when adding extra flags, note that the fFlags member is specified
// with a bit-width and you'll have to expand it.
- kAllFlags = 0xFFF
+ kAllFlags = 0x1FFF
};
/** Return the paint's flags. Use the Flag enum to test flag values.
@@ -165,21 +161,24 @@ public:
return SkToBool(this->getFlags() & kSubpixelText_Flag);
}
- /** Helper for setFlags(), setting or clearing the kSubpixelText_Flag
- bit @param subpixelText true to set the subpixelText bit in the paint's flags,
- false to clear it.
- */
+ /**
+ * Helper for setFlags(), setting or clearing the kSubpixelText_Flag.
+ * @param subpixelText true to set the subpixelText bit in the paint's
+ * flags, false to clear it.
+ */
void setSubpixelText(bool subpixelText);
bool isLCDRenderText() const {
return SkToBool(this->getFlags() & kLCDRenderText_Flag);
}
- /** Helper for setFlags(), setting or clearing the kLCDRenderText_Flag bit
- @param subpixelRender true to set the subpixelRenderText bit in the paint's flags,
- false to clear it.
- */
- void setLCDRenderText(bool subpixelRender);
+ /**
+ * Helper for setFlags(), setting or clearing the kLCDRenderText_Flag.
+ * Note: antialiasing must also be on for lcd rendering
+ * @param lcdText true to set the LCDRenderText bit in the paint's flags,
+ * false to clear it.
+ */
+ void setLCDRenderText(bool lcdText);
bool isEmbeddedBitmapText() const {
return SkToBool(this->getFlags() & kEmbeddedBitmapText_Flag);
@@ -202,6 +201,20 @@ public:
*/
void setAutohinted(bool useAutohinter);
+ bool isVerticalText() const {
+ return SkToBool(this->getFlags() & kVerticalText_Flag);
+ }
+
+ /**
+ * Helper for setting or clearing the kVerticalText_Flag bit in
+ * setFlags(...).
+ *
+ * If this bit is set, then advances are treated as Y values rather than
+ * X values, and drawText will places its glyphs vertically rather than
+ * horizontally.
+ */
+ void setVerticalText(bool);
+
/** Helper for getFlags(), returning true if kUnderlineText_Flag bit is set
@return true if the underlineText bit is set in the paint's flags.
*/
@@ -600,6 +613,9 @@ public:
*/
SkRasterizer* setRasterizer(SkRasterizer* rasterizer);
+ SkImageFilter* getImageFilter() const { return fImageFilter; }
+ SkImageFilter* setImageFilter(SkImageFilter*);
+
/**
* Return the paint's SkDrawLooper (if any). Does not affect the looper's
* reference count.
@@ -748,23 +764,29 @@ public:
return this->textToGlyphs(text, byteLength, NULL);
}
- /** Return the width of the text.
- @param text The text to be measured
- @param length Number of bytes of text to measure
- @param bounds If not NULL, returns the bounds of the text,
- relative to (0, 0).
- @param scale If not 0, return width as if the canvas were scaled
- by this value
- @return The advance width of the text
- */
+ /** Return the width of the text. This will return the vertical measure
+ * if isVerticalText() is true, in which case the returned value should
+ * be treated has a height instead of a width.
+ *
+ * @param text The text to be measured
+ * @param length Number of bytes of text to measure
+ * @param bounds If not NULL, returns the bounds of the text,
+ * relative to (0, 0).
+ * @param scale If not 0, return width as if the canvas were scaled
+ * by this value
+ * @return The advance width of the text
+ */
SkScalar measureText(const void* text, size_t length,
SkRect* bounds, SkScalar scale = 0) const;
- /** Return the width of the text.
- @param text Address of the text
- @param length Number of bytes of text to measure
- @return The width of the text
- */
+ /** Return the width of the text. This will return the vertical measure
+ * if isVerticalText() is true, in which case the returned value should
+ * be treated has a height instead of a width.
+ *
+ * @param text Address of the text
+ * @param length Number of bytes of text to measure
+ * @return The width of the text
+ */
SkScalar measureText(const void* text, size_t length) const {
return this->measureText(text, length, NULL, 0);
}
@@ -782,33 +804,38 @@ public:
kBackward_TextBufferDirection
};
- /** Return the width of the text.
- @param text The text to be measured
- @param length Number of bytes of text to measure
- @param maxWidth Maximum width. Only the subset of text whose accumulated
- widths are <= maxWidth are measured.
- @param measuredWidth Optional. If non-null, this returns the actual
- width of the measured text.
- @param tbd Optional. The direction the text buffer should be
- traversed during measuring.
- @return The number of bytes of text that were measured. Will be
- <= length.
- */
+ /** Return the number of bytes of text that were measured. If
+ * isVerticalText() is true, then the vertical advances are used for
+ * the measurement.
+ *
+ * @param text The text to be measured
+ * @param length Number of bytes of text to measure
+ * @param maxWidth Maximum width. Only the subset of text whose accumulated
+ * widths are <= maxWidth are measured.
+ * @param measuredWidth Optional. If non-null, this returns the actual
+ * width of the measured text.
+ * @param tbd Optional. The direction the text buffer should be
+ * traversed during measuring.
+ * @return The number of bytes of text that were measured. Will be
+ * <= length.
+ */
size_t breakText(const void* text, size_t length, SkScalar maxWidth,
SkScalar* measuredWidth = NULL,
TextBufferDirection tbd = kForward_TextBufferDirection)
const;
- /** Return the advance widths for the characters in the string.
- @param text the text
- @param byteLength number of bytes to of text
- @param widths If not null, returns the array of advance widths of
- the glyphs. If not NULL, must be at least a large
- as the number of unichars in the specified text.
- @param bounds If not null, returns the bounds for each of
- character, relative to (0, 0)
- @return the number of unichars in the specified text.
- */
+ /** Return the advances for the text. These will be vertical advances if
+ * isVerticalText() returns true.
+ *
+ * @param text the text
+ * @param byteLength number of bytes to of text
+ * @param widths If not null, returns the array of advances for
+ * the glyphs. If not NULL, must be at least a large
+ * as the number of unichars in the specified text.
+ * @param bounds If not null, returns the bounds for each of
+ * character, relative to (0, 0)
+ * @return the number of unichars in the specified text.
+ */
int getTextWidths(const void* text, size_t byteLength, SkScalar widths[],
SkRect bounds[] = NULL) const;
@@ -819,14 +846,22 @@ public:
void getTextPath(const void* text, size_t length, SkScalar x, SkScalar y,
SkPath* path) const;
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
const SkGlyph& getUnicharMetrics(SkUnichar);
const SkGlyph& getGlyphMetrics(uint16_t);
const void* findImage(const SkGlyph&);
uint32_t getGenerationID() const;
+
+ /** Returns the base glyph count for the strike associated with this paint
+ */
+ unsigned getBaseGlyphCount(SkUnichar text) const;
#endif
+ // returns true if the paint's settings (e.g. xfermode + alpha) resolve to
+ // mean that we need not draw at all (e.g. SrcOver + 0-alpha)
+ bool nothingToDraw() const;
+
private:
SkTypeface* fTypeface;
SkScalar fTextSize;
@@ -840,20 +875,18 @@ private:
SkColorFilter* fColorFilter;
SkRasterizer* fRasterizer;
SkDrawLooper* fLooper;
+ SkImageFilter* fImageFilter;
SkColor fColor;
SkScalar fWidth;
SkScalar fMiterLimit;
- unsigned fFlags : 12;
+ unsigned fFlags : 14;
unsigned fTextAlign : 2;
unsigned fCapType : 2;
unsigned fJoinType : 2;
unsigned fStyle : 2;
unsigned fTextEncoding : 2; // 3 values
unsigned fHinting : 2;
-#ifdef ANDROID
- uint32_t fGenerationID;
-#endif
SkDrawCacheProc getDrawCacheProc() const;
SkMeasureCacheProc getMeasureCacheProc(TextBufferDirection dir,
@@ -878,9 +911,15 @@ private:
friend class SkDraw;
friend class SkPDFDevice;
friend class SkTextToPathIter;
+
+#ifdef SK_BUILD_FOR_ANDROID
+ // In order for the == operator to work properly this must be the last field
+ // in the struct so that we can do a memcmp to this field's offset.
+ uint32_t fGenerationID;
+#endif
};
-//////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
#include "SkPathEffect.h"
@@ -898,20 +937,18 @@ public:
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(SkFlattenableWriteBuffer&);
- // This method is not exported to java.
virtual Factory getFactory();
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+
private:
SkScalar fWidth, fMiter;
uint8_t fStyle, fJoin, fCap;
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
SkStrokePathEffect(SkFlattenableReadBuffer&);
typedef SkPathEffect INHERITED;
diff --git a/include/core/SkPath.h b/include/core/SkPath.h
index 7120d3f..859486c 100644
--- a/include/core/SkPath.h
+++ b/include/core/SkPath.h
@@ -1,26 +1,19 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPath_DEFINED
#define SkPath_DEFINED
#include "SkMatrix.h"
#include "SkTDArray.h"
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
#define GEN_ID_INC fGenerationID++
#define GEN_ID_PTR_INC(ptr) ptr->fGenerationID++
#else
@@ -45,7 +38,7 @@ public:
~SkPath();
SkPath& operator=(const SkPath&);
-
+
friend bool operator==(const SkPath&, const SkPath&);
friend bool operator!=(const SkPath& a, const SkPath& b) {
return !(a == b);
@@ -77,7 +70,7 @@ public:
/** 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) {
@@ -187,6 +180,35 @@ public:
*/
bool isEmpty() const;
+ /** Test a line for zero length
+
+ @return true if the line is of zero length; otherwise false.
+ */
+ static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2) {
+ return p1.equalsWithinTolerance(p2, SK_ScalarNearlyZero);
+ }
+
+ /** Test a quad for zero length
+
+ @return true if the quad is of zero length; otherwise false.
+ */
+ static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
+ const SkPoint& p3) {
+ return p1.equalsWithinTolerance(p2, SK_ScalarNearlyZero) &&
+ p2.equalsWithinTolerance(p3, SK_ScalarNearlyZero);
+ }
+
+ /** Test a cubic curve for zero length
+
+ @return true if the cubic is of zero length; otherwise false.
+ */
+ static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
+ const SkPoint& p3, const SkPoint& p4) {
+ return p1.equalsWithinTolerance(p2, SK_ScalarNearlyZero) &&
+ p2.equalsWithinTolerance(p3, SK_ScalarNearlyZero) &&
+ p3.equalsWithinTolerance(p4, SK_ScalarNearlyZero);
+ }
+
/** Returns true if the path specifies a rectangle. If so, and if rect is
not null, set rect to the bounds of the path. If the path does not
specify a rectangle, return false and ignore rect.
@@ -431,6 +453,24 @@ public:
kCCW_Direction
};
+ /**
+ * Tries to quickly compute the direction of the first non-degenerate
+ * contour. If it can be computed, return true and set dir to that
+ * direction. If it cannot be (quickly) determined, return false and ignore
+ * the dir parameter.
+ */
+ bool cheapComputeDirection(Direction* dir) const;
+
+ /**
+ * Returns true if the path's direction can be computed via
+ * cheapComputDirection() and if that computed direction matches the
+ * specified direction.
+ */
+ bool cheapIsDirection(Direction dir) const {
+ Direction computedDir;
+ return this->cheapComputeDirection(&computedDir) && computedDir == dir;
+ }
+
/** 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
@@ -504,7 +544,7 @@ public:
@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);
+ void addPath(const SkPath& src, SkScalar dx, SkScalar dy);
/** Add a copy of src to the path
*/
@@ -519,6 +559,11 @@ public:
*/
void addPath(const SkPath& src, const SkMatrix& matrix);
+ /**
+ * Same as addPath(), but reverses the src input
+ */
+ void reverseAddPath(const SkPath& src);
+
/** Offset the path by (dx,dy), returning true on success
@param dx The amount in the X direction to offset the entire path
@@ -553,11 +598,12 @@ public:
}
/** Return the last point on the path. If no points have been added, (0,0)
- is returned.
+ is returned. If there are no points, this returns false, otherwise it
+ returns true.
@param lastPt The last point on the path is returned here
*/
- void getLastPt(SkPoint* lastPt) const;
+ bool getLastPt(SkPoint* lastPt) const;
/** Set the last point on the path. If no points have been added,
moveTo(x,y) is automatically called.
@@ -576,28 +622,47 @@ public:
this->setLastPt(p.fX, p.fY);
}
+ enum SegmentMask {
+ kLine_SegmentMask = 1 << 0,
+ kQuad_SegmentMask = 1 << 1,
+ kCubic_SegmentMask = 1 << 2
+ };
+
+ /**
+ * Returns a mask, where each bit corresponding to a SegmentMask is
+ * set if the path contains 1 or more segments of that type.
+ * Returns 0 for an empty path (no segments).
+ */
+ uint32_t getSegmentMasks() const { return fSegmentMask; }
+
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)
+ kClose_Verb, //!< iter.next returns 1 point (contour's moveTo pt)
kDone_Verb //!< iter.next returns 0 points
};
/** Iterate through all of the segments (lines, quadratics, cubics) of
each contours in a path.
+
+ The iterator cleans up the segments along the way, removing degenerate
+ segments and adding close verbs where necessary. When the forceClose
+ argument is provided, each contour (as defined by a new starting
+ move command) will be completed with a close verb regardless of the
+ contour's contents.
*/
class SK_API Iter {
public:
- Iter();
- Iter(const SkPath&, bool forceClose);
+ 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 points representing the current verb and/or segment
@return The verb for the current segment
*/
@@ -607,12 +672,12 @@ public:
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 (has a kClose_Verb)
@return true if the current contour is closed (has a kClose_Verb)
*/
@@ -626,11 +691,37 @@ public:
SkPoint fLastPt;
SkBool8 fForceClose;
SkBool8 fNeedClose;
- SkBool8 fNeedMoveTo;
SkBool8 fCloseLine;
+ SkBool8 fSegmentState;
bool cons_moveTo(SkPoint pts[1]);
Verb autoClose(SkPoint pts[2]);
+ void consumeDegenerateSegments();
+ };
+
+ /** Iterate through the verbs in the path, providing the associated points.
+ */
+ class SK_API RawIter {
+ public:
+ RawIter();
+ RawIter(const SkPath&);
+
+ void setPath(const SkPath&);
+
+ /** Return the next verb in this iteration of the path. When all
+ segments have been visited, return kDone_Verb.
+
+ @param pts The points representing the current verb and/or segment
+ @return The verb for the current segment
+ */
+ Verb next(SkPoint pts[4]);
+
+ private:
+ const SkPoint* fPts;
+ const uint8_t* fVerbs;
+ const uint8_t* fVerbStop;
+ SkPoint fMoveTo;
+ SkPoint fLastPt;
};
void dump(bool forceClose, const char title[] = NULL) const;
@@ -639,13 +730,7 @@ public:
void flatten(SkWriter32&) const;
void unflatten(SkReader32&);
- /** Subdivide the path so that no segment is longer that dist.
- If bendLines is true, then turn all line segments into curves.
- If dst == null, then the original path itself is modified (not const!)
- */
- void subdivide(SkScalar dist, bool bendLines, SkPath* dst = NULL) const;
-
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
uint32_t getGenerationID() const;
#endif
@@ -655,10 +740,11 @@ private:
SkTDArray<SkPoint> fPts;
SkTDArray<uint8_t> fVerbs;
mutable SkRect fBounds;
- mutable uint8_t fBoundsIsDirty;
uint8_t fFillType;
+ uint8_t fSegmentMask;
+ mutable uint8_t fBoundsIsDirty;
mutable uint8_t fConvexity;
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
uint32_t fGenerationID;
#endif
@@ -686,4 +772,3 @@ private:
};
#endif
-
diff --git a/include/core/SkPathEffect.h b/include/core/SkPathEffect.h
index eb1cc23..1b4cd5f 100644
--- a/include/core/SkPathEffect.h
+++ b/include/core/SkPathEffect.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPathEffect_DEFINED
#define SkPathEffect_DEFINED
@@ -31,7 +24,6 @@ class SkPath;
*/
class SK_API SkPathEffect : public SkFlattenable {
public:
- // This method is not exported to java.
SkPathEffect() {}
/** Given a src path and a width value, return true if the patheffect
@@ -42,6 +34,7 @@ public:
*/
virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width) = 0;
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
private:
// illegal
SkPathEffect(const SkPathEffect&);
@@ -61,7 +54,7 @@ public:
protected:
SkPairPathEffect(SkFlattenableReadBuffer&);
- virtual void flatten(SkFlattenableWriteBuffer&);
+ virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
// these are visible to our subclasses
SkPathEffect* fPE0, *fPE1;
@@ -86,16 +79,16 @@ public:
// overrides
- // This method is not exported to java.
virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
-protected:
- virtual Factory getFactory() { return CreateProc; }
-
-private:
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkComposePathEffect, (buffer));
}
+
+protected:
+ virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
+
+private:
SkComposePathEffect(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
// illegal
@@ -121,16 +114,16 @@ public:
: INHERITED(first, second) {}
// overrides
- // This method is not exported to java.
virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
-protected:
- virtual Factory getFactory() { return CreateProc; }
-
-private:
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkSumPathEffect, (buffer));
}
+
+protected:
+ virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
+
+private:
SkSumPathEffect(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
// illegal
diff --git a/include/core/SkPathMeasure.h b/include/core/SkPathMeasure.h
index 2d94ae2..ec43834 100644
--- a/include/core/SkPathMeasure.h
+++ b/include/core/SkPathMeasure.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPathMeasure_DEFINED
#define SkPathMeasure_DEFINED
diff --git a/include/core/SkPerspIter.h b/include/core/SkPerspIter.h
index 81ce7c8..7f6add2 100644
--- a/include/core/SkPerspIter.h
+++ b/include/core/SkPerspIter.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPerspIter_DEFINED
#define SkPerspIter_DEFINED
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index ac21bc9..47a2b95 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2007 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPicture_DEFINED
#define SkPicture_DEFINED
diff --git a/include/core/SkPixelRef.h b/include/core/SkPixelRef.h
index 8fb368a..e247479 100644
--- a/include/core/SkPixelRef.h
+++ b/include/core/SkPixelRef.h
@@ -1,26 +1,19 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2008 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPixelRef_DEFINED
#define SkPixelRef_DEFINED
+#include "SkBitmap.h"
#include "SkRefCnt.h"
#include "SkString.h"
-class SkBitmap;
class SkColorTable;
struct SkIRect;
class SkMutex;
@@ -30,6 +23,25 @@ class SkFlattenableWriteBuffer;
// this is an opaque class, not interpreted by skia
class SkGpuTexture;
+#if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+
+#define SK_DECLARE_PIXEL_REF_REGISTRAR()
+
+#define SK_DEFINE_PIXEL_REF_REGISTRAR(pixelRef) \
+ static SkPixelRef::Registrar g##pixelRef##Reg(#pixelRef, \
+ pixelRef::Create);
+
+#else
+
+#define SK_DECLARE_PIXEL_REF_REGISTRAR() static void Init();
+
+#define SK_DEFINE_PIXEL_REF_REGISTRAR(pixelRef) \
+ void pixelRef::Init() { \
+ SkPixelRef::Registrar(#pixelRef, Create); \
+ }
+
+#endif
+
/** \class SkPixelRef
This class is the smart container for pixel memory, and is used with
@@ -66,6 +78,14 @@ public:
*/
void unlockPixels();
+ /**
+ * Some bitmaps can return a copy of their pixels for lockPixels(), but
+ * that copy, if modified, will not be pushed back. These bitmaps should
+ * not be used as targets for a raster device/canvas (since all pixels
+ * modifications will be lost when unlockPixels() is called.)
+ */
+ bool lockPixelsAreWritable() const;
+
/** Returns a non-zero, unique value corresponding to the pixels in this
pixelref. Each time the pixels are changed (and notifyPixelsChanged is
called), a different generation ID will be returned.
@@ -116,6 +136,12 @@ public:
bool readPixels(SkBitmap* dst, const SkIRect* subset = NULL);
+ /** Makes a deep copy of this PixelRef, respecting the requested config.
+ Returns NULL if either there is an error (e.g. the destination could
+ not be created with the given config), or this PixelRef does not
+ support deep copies. */
+ virtual SkPixelRef* deepCopy(SkBitmap::Config config) { return NULL; }
+
// serialization
typedef SkPixelRef* (*Factory)(SkFlattenableReadBuffer&);
@@ -123,7 +149,7 @@ public:
virtual Factory getFactory() const { return NULL; }
virtual void flatten(SkFlattenableWriteBuffer&) const;
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
/**
* Acquire a "global" ref on this object.
* The default implementation just calls ref(), but subclasses can override
@@ -161,6 +187,9 @@ protected:
*/
virtual void onUnlockPixels() = 0;
+ /** Default impl returns true */
+ virtual bool onLockPixelsAreWritable() const;
+
/**
* For pixelrefs that don't have access to their raw pixels, they may be
* able to make a copy of them (e.g. if the pixels are on the GPU).
@@ -177,6 +206,10 @@ protected:
SkPixelRef(SkFlattenableReadBuffer&, SkMutex*);
private:
+#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+ static void InitializeFlattenables();
+#endif
+
SkMutex* fMutex; // must remain in scope for the life of this object
void* fPixels;
SkColorTable* fColorTable; // we do not track ownership, subclass does
@@ -188,6 +221,8 @@ private:
// can go from false to true, but never from true to false
bool fIsImmutable;
+
+ friend class SkGraphics;
};
#endif
diff --git a/include/core/SkPoint.h b/include/core/SkPoint.h
index d74435e..de7c0ef 100644
--- a/include/core/SkPoint.h
+++ b/include/core/SkPoint.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPoint_DEFINED
#define SkPoint_DEFINED
@@ -196,6 +189,16 @@ struct SK_API SkPoint {
}
void setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b, size_t stride);
+ static void Offset(SkPoint points[], int count, const SkPoint& offset) {
+ Offset(points, count, offset.fX, offset.fY);
+ }
+
+ static void Offset(SkPoint points[], int count, SkScalar dx, SkScalar dy) {
+ for (int i = 0; i < count; ++i) {
+ points[i].offset(dx, dy);
+ }
+ }
+
void offset(SkScalar dx, SkScalar dy) {
fX += dx;
fY += dy;
@@ -206,10 +209,19 @@ struct SK_API SkPoint {
SkScalar length() const { return SkPoint::Length(fX, fY); }
SkScalar distanceToOrigin() const { return this->length(); }
+ /**
+ * Return true if the computed length of the vector is >= the internal
+ * tolerance (used to avoid dividing by tiny values).
+ */
+ static bool CanNormalize(SkScalar dx, SkScalar dy);
+
+ bool canNormalize() const {
+ return CanNormalize(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 false, otherwise
- return true.
+ already points. If the point has a degenerate length (i.e. nearly 0)
+ then return false and do nothing; otherwise return true.
*/
bool normalize();
@@ -303,6 +315,13 @@ struct SK_API SkPoint {
return a.fX != b.fX || a.fY != b.fY;
}
+ /** Return true if this and the given point are componentwise within tol.
+ */
+ bool equalsWithinTolerance(const SkPoint& v, SkScalar tol) const {
+ return SkScalarNearlyZero(fX - v.fX, tol)
+ && SkScalarNearlyZero(fY - v.fY, tol);
+ }
+
/** Returns a new point whose coordinates are the difference between
a's and b's (a - b)
*/
@@ -325,7 +344,13 @@ struct SK_API SkPoint {
static SkScalar Length(SkScalar x, SkScalar y);
/** Normalize pt, returning its previous length. If the prev length is too
- small (degenerate), return 0 and leave pt unchanged.
+ small (degenerate), return 0 and leave pt unchanged. This uses the same
+ tolerance as CanNormalize.
+
+ Note that this method may be significantly more expensive than
+ the non-static normalize(), because it has to return the previous length
+ of the point. If you don't need the previous length, call the
+ non-static normalize() method instead.
*/
static SkScalar Normalize(SkPoint* pt);
@@ -364,17 +389,70 @@ struct SK_API SkPoint {
SkScalar dy = fY - pt.fY;
return SkScalarMul(dx, dx) + SkScalarMul(dy, dy);
}
-
- SkScalar distanceToLineSegmentBetweenSqd(const SkPoint& a,
+
+ /**
+ * The side of a point relative to a line. If the line is from a to b then
+ * the values are consistent with the sign of (b-a) cross (pt-a)
+ */
+ enum Side {
+ kLeft_Side = -1,
+ kOn_Side = 0,
+ kRight_Side = 1
+ };
+
+ /**
+ * Returns the squared distance to the infinite line between two pts. Also
+ * optionally returns the side of the line that the pt falls on (looking
+ * along line from a to b)
+ */
+ SkScalar distanceToLineBetweenSqd(const SkPoint& a,
+ const SkPoint& b,
+ Side* side = NULL) const;
+
+ /**
+ * Returns the distance to the infinite line between two pts. Also
+ * optionally returns the side of the line that the pt falls on (looking
+ * along the line from a to b)
+ */
+ SkScalar distanceToLineBetween(const SkPoint& a,
+ const SkPoint& b,
+ Side* side = NULL) const {
+ return SkScalarSqrt(this->distanceToLineBetweenSqd(a, b, side));
+ }
+
+ /**
+ * Returns the squared distance to the line segment between pts a and b
+ */
+ SkScalar distanceToLineSegmentBetweenSqd(const SkPoint& a,
const SkPoint& b) const;
-
- SkScalar distanceToLineSegmentBetween(const SkPoint& a,
+
+ /**
+ * Returns the distance to the line segment between pts a and b.
+ */
+ SkScalar distanceToLineSegmentBetween(const SkPoint& a,
const SkPoint& b) const {
return SkScalarSqrt(this->distanceToLineSegmentBetweenSqd(a, b));
}
+
+ /**
+ * Make this vector be orthogonal to vec. Looking down vec the
+ * new vector will point in direction indicated by side (which
+ * must be kLeft_Side or kRight_Side).
+ */
+ void setOrthog(const SkPoint& vec, Side side = kLeft_Side) {
+ // vec could be this
+ SkScalar tmp = vec.fX;
+ if (kLeft_Side == side) {
+ fX = -vec.fY;
+ fY = tmp;
+ } else {
+ SkASSERT(kRight_Side == side);
+ fX = vec.fY;
+ fY = -tmp;
+ }
+ }
};
typedef SkPoint SkVector;
#endif
-
diff --git a/include/core/SkPostConfig.h b/include/core/SkPostConfig.h
index 23ce02b..edce334 100644
--- a/include/core/SkPostConfig.h
+++ b/include/core/SkPostConfig.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPostConfig_DEFINED
#define SkPostConfig_DEFINED
@@ -63,6 +56,32 @@
#endif
#endif
+#if !defined(SK_HAS_COMPILER_FEATURE)
+ #if defined(__has_feature)
+ #define SK_HAS_COMPILER_FEATURE(x) __has_feature(x)
+ #else
+ #define SK_HAS_COMPILER_FEATURE(x) 0
+ #endif
+#endif
+
+/**
+ * The clang static analyzer likes to know that when the program is not
+ * expected to continue (crash, assertion failure, etc). It will notice that
+ * some combination of parameters lead to a function call that does not return.
+ * It can then make appropriate assumptions about the parameters in code
+ * executed only if the non-returning function was *not* called.
+ */
+#if !defined(SkNO_RETURN_HINT)
+ #if SK_HAS_COMPILER_FEATURE(attribute_analyzer_noreturn)
+ namespace {
+ inline void SkNO_RETURN_HINT() __attribute__((analyzer_noreturn));
+ void SkNO_RETURN_HINT() {}
+ }
+ #else
+ #define SkNO_RETURN_HINT() do {} while (false)
+ #endif
+#endif
+
///////////////////////////////////////////////////////////////////////////////
#ifndef SkNEW
@@ -75,9 +94,9 @@
#ifndef SK_CRASH
#if 1 // set to 0 for infinite loop, which can help connecting gdb
- #define SK_CRASH() *(int *)(uintptr_t)0xbbadbeef = 0
+ #define SK_CRASH() do { SkNO_RETURN_HINT(); *(int *)(uintptr_t)0xbbadbeef = 0; } while (false)
#else
- #define SK_CRASH() do {} while (true)
+ #define SK_CRASH() do { SkNO_RETURN_HINT(); } while (true)
#endif
#endif
@@ -107,7 +126,7 @@
#endif
#ifndef SK_DEBUGBREAK
- #define SK_DEBUGBREAK(cond) do { if (!(cond)) __debugbreak(); } while (false)
+ #define SK_DEBUGBREAK(cond) do { if (!(cond)) { SkNO_RETURN_HINT(); __debugbreak(); }} while (false)
#endif
#ifndef SK_A32_SHIFT
@@ -252,7 +271,28 @@
#define DEBUG_CLIENTBLOCK
#endif // _DEBUG
+
#endif
#endif
+//////////////////////////////////////////////////////////////////////
+
+#ifndef SK_OVERRIDE
+#if defined(_MSC_VER)
+#define SK_OVERRIDE override
+#elif defined(__clang__)
+// Some documentation suggests we should be using __attribute__((override)),
+// but it doesn't work.
+#define SK_OVERRIDE override
+#else
+// Linux GCC ignores "__attribute__((override))" and rejects "override".
+#define SK_OVERRIDE
+#endif
+#endif
+
+//////////////////////////////////////////////////////////////////////
+
+#ifndef SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+#define SK_ALLOW_STATIC_GLOBAL_INITIALIZERS 1
+#endif
diff --git a/include/core/SkPreConfig.h b/include/core/SkPreConfig.h
index 6ec73ce..4485f1d 100644
--- a/include/core/SkPreConfig.h
+++ b/include/core/SkPreConfig.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPreConfig_DEFINED
#define SkPreConfig_DEFINED
@@ -23,7 +16,7 @@
//////////////////////////////////////////////////////////////////////
-#if !defined(SK_BUILD_FOR_ANDROID_NDK) && !defined(SK_BUILD_FOR_IOS) && !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) && !defined(SK_BUILD_FOR_SDL) && !defined(SK_BUILD_FOR_BREW)
+#if !defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_ANDROID_NDK) && !defined(SK_BUILD_FOR_IOS) && !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) && !defined(SK_BUILD_FOR_SDL) && !defined(SK_BUILD_FOR_BREW)
#ifdef __APPLE__
#include "TargetConditionals.h"
@@ -37,7 +30,12 @@
#define SK_BUILD_FOR_WIN32
#elif defined(__SYMBIAN32__)
#define SK_BUILD_FOR_WIN32
- #elif defined(linux)
+ #elif defined(ANDROID_NDK)
+ #define SK_BUILD_FOR_ANDROID_NDK
+ #elif defined(ANDROID)
+ #define SK_BUILD_FOR_ANDROID
+ #elif defined(linux) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
+ defined(__sun) || defined(__NetBSD__) || defined(__DragonFly__)
#define SK_BUILD_FOR_UNIX
#elif TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
#define SK_BUILD_FOR_IOS
@@ -45,12 +43,15 @@
#define SK_BUILD_FOR_MAC
#endif
- #if defined(ANDROID)
- #define SK_BUILD_FOR_ANDROID
- #endif
- #if defined(ANDROID_NDK)
- #define SK_BUILD_FOR_ANDROID_NDK
- #endif
+#endif
+
+/* Even if the user only defined the NDK variant we still need to build
+ * the default Android code. Therefore, when attempting to include/exclude
+ * something from the NDK variant check first that we are building for
+ * Android then check the status of the NDK define.
+ */
+#if defined(SK_BUILD_FOR_ANDROID_NDK) && !defined(SK_BUILD_FOR_ANDROID)
+ #define SK_BUILD_FOR_ANDROID
#endif
//////////////////////////////////////////////////////////////////////
@@ -64,7 +65,9 @@
#endif
#ifdef SK_BUILD_FOR_WIN32
- #define SK_RESTRICT
+ #if !defined(SK_RESTRICT)
+ #define SK_RESTRICT __restrict
+ #endif
#include "sk_stdint.h"
#endif
diff --git a/include/core/SkPtrRecorder.h b/include/core/SkPtrRecorder.h
index db6c64d..11fd170 100644
--- a/include/core/SkPtrRecorder.h
+++ b/include/core/SkPtrRecorder.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPtrSet_DEFINED
#define SkPtrSet_DEFINED
@@ -89,10 +82,13 @@ private:
*/
template <typename T> class SkTPtrSet : public SkPtrSet {
public:
+ uint32_t find(T ptr) {
+ return this->INHERITED::find((void*)ptr);
+ }
uint32_t add(T ptr) {
return this->INHERITED::add((void*)ptr);
}
-
+
void copyToArray(T* array) const {
this->INHERITED::copyToArray((void**)array);
}
diff --git a/include/core/SkRandom.h b/include/core/SkRandom.h
index 33b563a..b850df3 100644
--- a/include/core/SkRandom.h
+++ b/include/core/SkRandom.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkRandom_DEFINED
#define SkRandom_DEFINED
diff --git a/include/core/SkRasterizer.h b/include/core/SkRasterizer.h
index d81e613..d249898 100644
--- a/include/core/SkRasterizer.h
+++ b/include/core/SkRasterizer.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkRasterizer_DEFINED
#define SkRasterizer_DEFINED
@@ -35,7 +28,7 @@ public:
const SkIRect* clipBounds, SkMaskFilter* filter,
SkMask* mask, SkMask::CreateMode mode);
- virtual void flatten(SkFlattenableWriteBuffer& ) {}
+ virtual void flatten(SkFlattenableWriteBuffer& ) SK_OVERRIDE {}
protected:
SkRasterizer(SkFlattenableReadBuffer&);
diff --git a/include/core/SkReader32.h b/include/core/SkReader32.h
index 654ebd5..37ace5c 100644
--- a/include/core/SkReader32.h
+++ b/include/core/SkReader32.h
@@ -1,27 +1,18 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkReader32_DEFINED
#define SkReader32_DEFINED
-#include "SkTypes.h"
-
#include "SkScalar.h"
-#include "SkPoint.h"
-#include "SkRect.h"
+
+class SkString;
class SkReader32 : SkNoncopyable {
public:
@@ -73,14 +64,6 @@ public:
return value;
}
- const SkPoint* skipPoint() {
- return (const SkPoint*)this->skip(sizeof(SkPoint));
- }
-
- const SkRect* skipRect() {
- return (const SkRect*)this->skip(sizeof(SkRect));
- }
-
const void* skip(size_t size) {
SkASSERT(ptr_align_4(fCurr));
const void* addr = fCurr;
@@ -89,6 +72,11 @@ public:
return addr;
}
+ template <typename T> const T& skipT() {
+ SkASSERT(SkAlign4(sizeof(T)) == sizeof(T));
+ return *(const T*)this->skip(sizeof(T));
+ }
+
void read(void* dst, size_t size) {
SkASSERT(0 == size || dst != NULL);
SkASSERT(ptr_align_4(fCurr));
@@ -103,12 +91,18 @@ public:
uint32_t readU32() { return this->readInt(); }
/**
- * Read the length of a string written by SkWriter32::writeString()
- * (if len is not NULL) and return the null-ternimated address of the
- * string.
+ * Read the length of a string (written by SkWriter32::writeString) into
+ * len (if len is not NULL) and return the null-ternimated address of the
+ * string within the reader's buffer.
*/
const char* readString(size_t* len = NULL);
+ /**
+ * Read the string (written by SkWriter32::writeString) and return it in
+ * copy (if copy is not null). Return the length of the string.
+ */
+ size_t readIntoString(SkString* copy);
+
private:
// these are always 4-byte aligned
const char* fCurr; // current position within buffer
@@ -116,8 +110,7 @@ private:
const char* fBase; // beginning of buffer
#ifdef SK_DEBUG
- static bool ptr_align_4(const void* ptr)
- {
+ static bool ptr_align_4(const void* ptr) {
return (((const char*)ptr - (const char*)NULL) & 3) == 0;
}
#endif
diff --git a/include/core/SkRect.h b/include/core/SkRect.h
index 19ee12a..65e7611 100644
--- a/include/core/SkRect.h
+++ b/include/core/SkRect.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkRect_DEFINED
#define SkRect_DEFINED
@@ -56,27 +49,39 @@ struct SK_API SkIRect {
r.set(x, y, x + w, y + h);
return r;
}
-
- /** Return true if the rectangle's width or height are <= 0
- */
- 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 left() const { return fLeft; }
+ int top() const { return fTop; }
+ int right() const { return fRight; }
+ int bottom() const { return fBottom; }
+
+ /** return the left edge of the rect */
+ int x() const { return fLeft; }
+ /** return the top edge of the rect */
+ int y() const { return fTop; }
+ /**
+ * Returns the rectangle's width. This does not check for a valid rect
+ * (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.
- */
+
+ /**
+ * Returns the rectangle's height. This does not check for a valid rect
+ * (i.e. top <= bottom) so the result may be negative.
+ */
int height() const { return fBottom - fTop; }
+
+ /**
+ * Return true if the rectangle's width or height are <= 0
+ */
+ bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
- friend int operator==(const SkIRect& a, const SkIRect& b) {
+ friend bool operator==(const SkIRect& a, const SkIRect& b) {
return !memcmp(&a, &b, sizeof(a));
}
- friend int operator!=(const SkIRect& a, const SkIRect& b) {
- return memcmp(&a, &b, sizeof(a));
+ friend bool operator!=(const SkIRect& a, const SkIRect& b) {
+ return !(a == b);
}
bool is16Bit() const {
@@ -330,10 +335,34 @@ struct SK_API SkRect {
return r;
}
- /** Return true if the rectangle's width or height are <= 0
- */
- bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
- bool hasValidCoordinates() const;
+ /**
+ * Return true if the rectangle's width or height are <= 0
+ */
+ bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
+
+ /**
+ * Returns true iff all values in the rect are finite. If any are
+ * infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this
+ * returns false.
+ */
+ bool isFinite() const {
+#ifdef SK_SCALAR_IS_FLOAT
+ // x * 0 will be NaN iff x is infinity or NaN.
+ // a + b will be NaN iff either a or b is NaN.
+ float value = fLeft * 0 + fTop * 0 + fRight * 0 + fBottom * 0;
+
+ // value is either NaN or it is finite (zero).
+ // value==value will be true iff value is not NaN
+ return value == value;
+#else
+ // use bit-or for speed, since we don't care about short-circuting the
+ // tests, and we expect the common case will be that we need to check all.
+ int isNaN = (SK_FixedNaN == fLeft) | (SK_FixedNaN == fTop) |
+ (SK_FixedNaN == fRight) | (SK_FixedNaN == fBottom);
+ return !isNaN;
+#endif
+ }
+
SkScalar left() const { return fLeft; }
SkScalar top() const { return fTop; }
SkScalar right() const { return fRight; }
@@ -343,12 +372,12 @@ struct SK_API SkRect {
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 bool operator==(const SkRect& a, const SkRect& b) {
+ return 0 == memcmp(&a, &b, sizeof(a));
}
- friend int operator!=(const SkRect& a, const SkRect& b) {
- return memcmp(&a, &b, sizeof(a));
+ friend bool operator!=(const SkRect& a, const SkRect& b) {
+ return 0 != memcmp(&a, &b, sizeof(a));
}
/** return the 4 points that enclose the rectangle
@@ -436,9 +465,10 @@ struct SK_API SkRect {
this->offset(delta.fX, delta.fY);
}
- /** 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.
+ /** 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 holds
+ true for dy and the top and bottom.
*/
void inset(SkScalar dx, SkScalar dy) {
fLeft += dx;
@@ -447,6 +477,13 @@ struct SK_API SkRect {
fBottom -= dy;
}
+ /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are
+ moved outwards, making the rectangle wider. If dx is negative, then the
+ sides are moved inwards, making the rectangle narrower. The same hods
+ true for dy and the top and bottom.
+ */
+ void outset(SkScalar dx, SkScalar dy) { this->inset(-dx, -dy); }
+
/** If this rectangle intersects r, return true and set this rectangle to that
intersection, otherwise return false and do not change this rectangle.
If either rectangle is empty, do nothing and return false.
@@ -472,6 +509,12 @@ struct SK_API SkRect {
fLeft < right && left < fRight &&
fTop < bottom && top < fBottom;
}
+
+ /** If rectangles a and b intersect, return true and set this rectangle to
+ * that intersection, otherwise return false and do not change this
+ * rectangle. If either rectangle is empty, do nothing and return false.
+ */
+ bool intersect(const SkRect& a, const SkRect& b);
/**
* Return true if rectangles a and b are not empty and intersect.
@@ -574,6 +617,18 @@ struct SK_API SkRect {
}
/**
+ * Expand this rectangle by rounding its coordinates "out", choosing the
+ * floor of top and left, and the ceil of right and bottom. If this rect
+ * is already on integer coordinates, then it will be unchanged.
+ */
+ void roundOut() {
+ this->set(SkScalarFloorToScalar(fLeft),
+ SkScalarFloorToScalar(fTop),
+ SkScalarCeilToScalar(fRight),
+ SkScalarCeilToScalar(fBottom));
+ }
+
+ /**
* Swap top/bottom or left/right if there are flipped (i.e. if width()
* or height() would have returned a negative value.) This should be called
* if the edges are computed separately, and may have crossed over each
diff --git a/include/core/SkRefCnt.h b/include/core/SkRefCnt.h
index 36f4249..7af0017 100644
--- a/include/core/SkRefCnt.h
+++ b/include/core/SkRefCnt.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkRefCnt_DEFINED
#define SkRefCnt_DEFINED
@@ -37,7 +30,12 @@ public:
/** Destruct, asserting that the reference count is 1.
*/
- virtual ~SkRefCnt() { SkASSERT(fRefCnt == 1); }
+ virtual ~SkRefCnt() {
+#ifdef SK_DEBUG
+ SkASSERT(fRefCnt == 1);
+ fRefCnt = 0; // illegal value, to catch us if we reuse after delete
+#endif
+ }
/** Return the reference count.
*/
@@ -63,20 +61,61 @@ public:
}
}
+ void validate() const {
+ SkASSERT(fRefCnt > 0);
+ }
+
private:
mutable int32_t fRefCnt;
};
+///////////////////////////////////////////////////////////////////////////////
+
+/** Helper macro to safely assign one SkRefCnt[TS]* to another, checking for
+ null 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)
+
+
+/** Check if the argument is non-null, and if so, call obj->ref()
+ */
+template <typename T> static inline void SkSafeRef(T* obj) {
+ if (obj) {
+ obj->ref();
+ }
+}
+
+/** Check if the argument is non-null, and if so, call obj->unref()
+ */
+template <typename T> static inline void SkSafeUnref(T* obj) {
+ if (obj) {
+ obj->unref();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
/**
* Utility class that simply unref's its argument in the destructor.
*/
template <typename T> class SkAutoTUnref : SkNoncopyable {
public:
- SkAutoTUnref(T* obj) : fObj(obj) {}
+ explicit SkAutoTUnref(T* obj = NULL) : fObj(obj) {}
~SkAutoTUnref() { SkSafeUnref(fObj); }
T* get() const { return fObj; }
+ void reset(T* obj) {
+ SkSafeUnref(fObj);
+ fObj = obj;
+ }
+
/**
* Return the hosted object (which may be null), transferring ownership.
* The reference count is not modified, and the internal ptr is set to NULL
@@ -98,35 +137,13 @@ public:
SkAutoUnref(SkRefCnt* obj) : SkAutoTUnref<SkRefCnt>(obj) {}
};
-///////////////////////////////////////////////////////////////////////////////
-
-/** Helper macro to safely assign one SkRefCnt[TS]* to another, checking for
- null 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)
-
-
-/** Check if the argument is non-null, and if so, call obj->ref()
- */
-template <typename T> static inline void SkSafeRef(T* obj) {
- if (obj) {
- obj->ref();
- }
-}
-
-/** Check if the argument is non-null, and if so, call obj->unref()
- */
-template <typename T> static inline void SkSafeUnref(T* obj) {
- if (obj) {
- obj->unref();
- }
-}
+class SkAutoRef : SkNoncopyable {
+public:
+ SkAutoRef(SkRefCnt* obj) : fObj(obj) { SkSafeRef(obj); }
+ ~SkAutoRef() { SkSafeUnref(fObj); }
+private:
+ SkRefCnt* fObj;
+};
/** Wrapper class for SkRefCnt pointers. This manages ref/unref of a pointer to
a SkRefCnt (or subclass) object.
diff --git a/include/core/SkRefDict.h b/include/core/SkRefDict.h
index 0c4b025..6751121 100644
--- a/include/core/SkRefDict.h
+++ b/include/core/SkRefDict.h
@@ -1,19 +1,12 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkRefDict_DEFINED
#define SkRefDict_DEFINED
diff --git a/include/core/SkRegion.h b/include/core/SkRegion.h
index 1dace59..9d89d94 100644
--- a/include/core/SkRegion.h
+++ b/include/core/SkRegion.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2005 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkRegion_DEFINED
#define SkRegion_DEFINED
@@ -93,9 +86,9 @@ public:
const SkIRect& 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. If the region is empty, then
- * this returns false, and path is left unmodified.
+ * Returns true if the region is non-empty, and if so, appends the
+ * boundary(s) of the region to the specified path.
+ * If the region is empty, returns false, and path is left unmodified.
*/
bool getBoundaryPath(SkPath* path) const;
@@ -290,7 +283,7 @@ public:
*/
bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op);
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
/** Returns a new char* containing the list of rectangles in this region
*/
char* toString();
diff --git a/include/core/SkRelay.h b/include/core/SkRelay.h
index 9361482..ef09ce4 100644
--- a/include/core/SkRelay.h
+++ b/include/core/SkRelay.h
@@ -1,19 +1,12 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTRelay_DEFINED
#define SkTRelay_DEFINED
diff --git a/include/core/SkScalar.h b/include/core/SkScalar.h
index ba113f4..71aad98 100644
--- a/include/core/SkScalar.h
+++ b/include/core/SkScalar.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkScalar_DEFINED
#define SkScalar_DEFINED
@@ -99,7 +92,7 @@
*
* Either way, it's not good.
*/
- SkASSERT(!"looks like you passed an SkScalar into SkIntToScalar");
+ SkDEBUGFAIL("looks like you passed an SkScalar into SkIntToScalar");
return (float)0;
}
#else // not SK_DEBUG
@@ -123,15 +116,15 @@
/** 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
- */
- #define SkScalarRound(x) sk_float_round2int(x)
- /** Returns the smallest integer that is >= the specified SkScalar
- */
- #define SkScalarCeil(x) sk_float_ceil2int(x)
- /** Returns the largest integer that is <= the specified SkScalar
- */
- #define SkScalarFloor(x) sk_float_floor2int(x)
+
+ #define SkScalarFloorToScalar(x) sk_float_floor(x)
+ #define SkScalarCeilToScalar(x) sk_float_ceil(x)
+ #define SkScalarRoundToScalar(x) sk_float_floor((x) + 0.5f)
+
+ #define SkScalarFloorToInt(x) sk_float_floor2int(x)
+ #define SkScalarCeilToInt(x) sk_float_ceil2int(x)
+ #define SkScalarRoundToInt(x) sk_float_round2int(x)
+
/** Returns the absolute value of the specified SkScalar
*/
#define SkScalarAbs(x) sk_float_abs(x)
@@ -237,9 +230,15 @@
#define SkDoubleToScalar(n) SkDoubleToFixed(n)
#endif
#define SkScalarFraction(x) SkFixedFraction(x)
- #define SkScalarRound(x) SkFixedRound(x)
- #define SkScalarCeil(x) SkFixedCeil(x)
- #define SkScalarFloor(x) SkFixedFloor(x)
+
+ #define SkScalarFloorToScalar(x) SkFixedFloorToFixed(x)
+ #define SkScalarCeilToScalar(x) SkFixedCeilToFixed(x)
+ #define SkScalarRoundToScalar(x) SkFixedRoundToFixed(x)
+
+ #define SkScalarFloorToInt(x) SkFixedFloorToInt(x)
+ #define SkScalarCeilToInt(x) SkFixedCeilToInt(x)
+ #define SkScalarRoundToInt(x) SkFixedRoundToInt(x)
+
#define SkScalarAbs(x) SkFixedAbs(x)
#define SkScalarCopySign(x, y) SkCopySign32(x, y)
#define SkScalarClampMax(x, max) SkClampMax(x, max)
@@ -284,17 +283,43 @@
}
#endif
+// DEPRECATED : use ToInt or ToScalar variant
+#define SkScalarFloor(x) SkScalarFloorToInt(x)
+#define SkScalarCeil(x) SkScalarCeilToInt(x)
+#define SkScalarRound(x) SkScalarRoundToInt(x)
+
+/**
+ * Returns -1 || 0 || 1 depending on the sign of value:
+ * -1 if x < 0
+ * 0 if x == 0
+ * 1 if x > 0
+ */
+static inline int SkScalarSignAsInt(SkScalar x) {
+ return x < 0 ? -1 : (x > 0);
+}
+
+// Scalar result version of above
+static inline SkScalar SkScalarSignAsScalar(SkScalar x) {
+ return x < 0 ? -SK_Scalar1 : ((x > 0) ? SK_Scalar1 : 0);
+}
+
#define SK_ScalarNearlyZero (SK_Scalar1 / (1 << 12))
/* <= is slower than < for floats, so we use < for our tolerance test
*/
static inline bool SkScalarNearlyZero(SkScalar x,
- SkScalar tolerance = SK_ScalarNearlyZero) {
+ SkScalar tolerance = SK_ScalarNearlyZero) {
SkASSERT(tolerance > 0);
return SkScalarAbs(x) < tolerance;
}
+static inline bool SkScalarNearlyEqual(SkScalar x, SkScalar y,
+ SkScalar tolerance = SK_ScalarNearlyZero) {
+ SkASSERT(tolerance > 0);
+ return SkScalarAbs(x-y) < tolerance;
+}
+
/** Linearly interpolate between A and B, based on t.
If t is 0, return A
If t is 1, return B
diff --git a/include/core/SkScalarCompare.h b/include/core/SkScalarCompare.h
index 7f0b176..0842fdd 100644
--- a/include/core/SkScalarCompare.h
+++ b/include/core/SkScalarCompare.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkScalarCompare_DEFINED
#define SkScalarCompare_DEFINED
diff --git a/include/core/SkScalerContext.h b/include/core/SkScalerContext.h
index cbbbdf0..e7dd7d4 100644
--- a/include/core/SkScalerContext.h
+++ b/include/core/SkScalerContext.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkScalerContext_DEFINED
#define SkScalerContext_DEFINED
@@ -60,7 +53,9 @@ struct SkGlyph {
unsigned rb = width;
if (SkMask::kBW_Format == format) {
rb = (rb + 7) >> 3;
- } else if (SkMask::kARGB32_Format == format) {
+ } else if (SkMask::kARGB32_Format == format ||
+ SkMask::kLCD32_Format == format)
+ {
rb <<= 2;
} else if (SkMask::kLCD16_Format == format) {
rb = SkAlign4(rb << 1);
@@ -157,37 +152,41 @@ struct SkGlyph {
}
void toMask(SkMask* mask) const;
-
- /** Given a glyph which is has a mask format of LCD or VerticalLCD, take
- the A8 plane in fImage and produce a valid LCD plane from it.
- */
- void expandA8ToLCD() const;
};
class SkScalerContext {
public:
enum Flags {
- kFrameAndFill_Flag = 0x01,
- kDevKernText_Flag = 0x02,
- kGammaForBlack_Flag = 0x04, // illegal to set both Gamma flags
- kGammaForWhite_Flag = 0x08, // illegal to set both Gamma flags
+ kFrameAndFill_Flag = 0x0001,
+ kDevKernText_Flag = 0x0002,
+ kEmbeddedBitmapText_Flag = 0x0004,
+ kEmbolden_Flag = 0x0008,
+ kSubpixelPositioning_Flag = 0x0010,
+ kAutohinting_Flag = 0x0020,
+ kVertical_Flag = 0x0040,
+
// together, these two flags resulting in a two bit value which matches
// up with the SkPaint::Hinting enum.
- kHintingBit1_Flag = 0x10,
- kHintingBit2_Flag = 0x20,
- kEmbeddedBitmapText_Flag = 0x40,
- kEmbolden_Flag = 0x80,
- kSubpixelPositioning_Flag = 0x100,
- kAutohinting_Flag = 0x200,
- // these should only ever be set if fMaskFormat is LCD
- kLCD_Vertical_Flag = 0x400, // else Horizontal
- kLCD_BGROrder_Flag = 0x800, // else RGB order
+ kHinting_Shift = 7, // to shift into the other flags above
+ kHintingBit1_Flag = 0x0080,
+ kHintingBit2_Flag = 0x0100,
+
+ // these should only ever be set if fMaskFormat is LCD16 or LCD32
+ kLCD_Vertical_Flag = 0x0200, // else Horizontal
+ kLCD_BGROrder_Flag = 0x0400, // else RGB order
+
+ // luminance : 0 for black text, kLuminance_Max for white text
+ kLuminance_Shift = 11, // to shift into the other flags above
+ kLuminance_Bits = 3, // ensure Flags doesn't exceed 16bits
};
-private:
+
+ // computed values
enum {
- kHintingMask = kHintingBit1_Flag | kHintingBit2_Flag
+ kHinting_Mask = kHintingBit1_Flag | kHintingBit2_Flag,
+ kLuminance_Max = (1 << kLuminance_Bits) - 1,
+ kLuminance_Mask = kLuminance_Max << kLuminance_Shift,
};
-public:
+
struct Rec {
uint32_t fOrigFontID;
uint32_t fFontID;
@@ -207,19 +206,33 @@ public:
void getSingleMatrix(SkMatrix*) const;
SkPaint::Hinting getHinting() const {
- return static_cast<SkPaint::Hinting>((fFlags & kHintingMask) >> 4);
+ unsigned hint = (fFlags & kHinting_Mask) >> kHinting_Shift;
+ return static_cast<SkPaint::Hinting>(hint);
}
void setHinting(SkPaint::Hinting hinting) {
- fFlags = (fFlags & ~kHintingMask) | (hinting << 4);
+ fFlags = (fFlags & ~kHinting_Mask) | (hinting << kHinting_Shift);
}
- SkMask::Format getFormat() const {
- return static_cast<SkMask::Format>(fMaskFormat);
+ unsigned getLuminanceBits() const {
+ return (fFlags & kLuminance_Mask) >> kLuminance_Shift;
+ }
+
+ void setLuminanceBits(unsigned lum) {
+ SkASSERT(lum <= kLuminance_Max);
+ fFlags = (fFlags & ~kLuminance_Mask) | (lum << kLuminance_Shift);
}
- bool isLCD() const {
- return SkMask::FormatIsLCD(this->getFormat());
+ U8CPU getLuminanceByte() const {
+ SkASSERT(3 == kLuminance_Bits);
+ unsigned lum = this->getLuminanceBits();
+ lum |= (lum << kLuminance_Bits);
+ lum |= (lum << kLuminance_Bits*2);
+ return lum >> (4*kLuminance_Bits - 8);
+ }
+
+ SkMask::Format getFormat() const {
+ return static_cast<SkMask::Format>(fMaskFormat);
}
};
@@ -230,6 +243,10 @@ public:
return (SkMask::Format)fRec.fMaskFormat;
}
+ bool isSubpixel() const {
+ return SkToBool(fRec.fFlags & kSubpixelPositioning_Flag);
+ }
+
// remember our glyph offset/base
void setBaseGlyphCount(unsigned baseGlyphCount) {
fBaseGlyphCount = baseGlyphCount;
@@ -240,7 +257,7 @@ public:
fact correspond to a different font/context. In that case, we use the
base-glyph-count to know how to translate back into local glyph space.
*/
- uint16_t charToGlyphID(SkUnichar uni);
+ uint16_t charToGlyphID(SkUnichar uni);
/** Map the glyphID to its glyph index, and then to its char code. Unmapped
glyphs return zero.
@@ -255,6 +272,10 @@ public:
void getFontMetrics(SkPaint::FontMetrics* mX,
SkPaint::FontMetrics* mY);
+#ifdef SK_BUILD_FOR_ANDROID
+ unsigned getBaseGlyphCount(SkUnichar charCode);
+#endif
+
static inline void MakeRec(const SkPaint&, const SkMatrix*, Rec* rec);
static SkScalerContext* Create(const SkDescriptor*);
@@ -273,12 +294,18 @@ protected:
// default impl returns 0, indicating failure.
virtual SkUnichar generateGlyphToChar(uint16_t);
+ void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
+
private:
SkPathEffect* fPathEffect;
SkMaskFilter* fMaskFilter;
SkRasterizer* fRasterizer;
SkScalar fDevFrameWidth;
+ // if this is set, we draw the image from a path, rather than
+ // calling generateImage.
+ bool fGenerateImageFromPath;
+
void internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
SkPath* devPath, SkMatrix* fillToDevMatrix);
@@ -298,5 +325,21 @@ private:
#define kMaskFilter_SkDescriptorTag SkSetFourByteTag('m', 's', 'k', 'f')
#define kRasterizer_SkDescriptorTag SkSetFourByteTag('r', 'a', 's', 't')
+///////////////////////////////////////////////////////////////////////////////
+
+enum SkAxisAlignment {
+ kNone_SkAxisAlignment,
+ kX_SkAxisAlignment,
+ kY_SkAxisAlignment
+};
+
+/**
+ * Return the axis (if any) that the baseline for horizontal text will land on
+ * after running through the specified matrix.
+ *
+ * As an example, the identity matrix will return kX_SkAxisAlignment
+ */
+SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix);
+
#endif
diff --git a/include/core/SkScan.h b/include/core/SkScan.h
index 31d4845..61ba1b0 100644
--- a/include/core/SkScan.h
+++ b/include/core/SkScan.h
@@ -1,25 +1,18 @@
-/* libs/graphics/sgl/SkScan.h
-**
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkScan_DEFINED
#define SkScan_DEFINED
#include "SkRect.h"
+class SkRasterClip;
class SkRegion;
class SkBlitter;
class SkPath;
@@ -31,57 +24,74 @@ typedef SkIRect SkXRect;
class SkScan {
public:
- static void FillIRect(const SkIRect&, const SkRegion* clip, SkBlitter*);
- static void FillXRect(const SkXRect&, const SkRegion* clip, SkBlitter*);
+ static void FillPath(const SkPath&, const SkIRect&, SkBlitter*);
+ ///////////////////////////////////////////////////////////////////////////
+ // rasterclip
+
+ static void FillIRect(const SkIRect&, const SkRasterClip&, SkBlitter*);
+ static void FillXRect(const SkXRect&, const SkRasterClip&, SkBlitter*);
#ifdef SK_SCALAR_IS_FIXED
- static void FillRect(const SkRect& rect, const SkRegion* clip,
+ static void FillRect(const SkRect& rect, const SkRasterClip& clip,
SkBlitter* blitter) {
SkScan::FillXRect(*(const SkXRect*)&rect, clip, blitter);
}
-#else
- static void FillRect(const SkRect&, const SkRegion* clip, SkBlitter*);
-#endif
- static void FillPath(const SkPath&, const SkRegion& clip, SkBlitter*);
-
- static void FillTriangle(const SkPoint pts[], const SkRegion*, SkBlitter*);
- static void FillTriangle(const SkPoint& a, const SkPoint& b,
- const SkPoint& c, const SkRegion* clip,
+ static void AntiFillRect(const SkRect& rect, const SkRasterClip& clip,
SkBlitter* blitter) {
- SkPoint pts[3];
- pts[0] = a;
- pts[1] = b;
- pts[2] = c;
- FillTriangle(pts, clip, blitter);
+ SkScan::AntiFillXRect(*(const SkXRect*)&rect, clip, blitter);
}
-
- static void HairLine(const SkPoint&, const SkPoint&, const SkRegion*,
+#else
+ static void FillRect(const SkRect&, const SkRasterClip&, SkBlitter*);
+ static void AntiFillRect(const SkRect&, const SkRasterClip&, SkBlitter*);
+#endif
+ static void AntiFillXRect(const SkXRect&, const SkRasterClip&, SkBlitter*);
+ static void FillPath(const SkPath&, const SkRasterClip&, SkBlitter*);
+ static void AntiFillPath(const SkPath&, const SkRasterClip&, SkBlitter*);
+ static void FrameRect(const SkRect&, const SkPoint& strokeSize,
+ const SkRasterClip&, SkBlitter*);
+ static void AntiFrameRect(const SkRect&, const SkPoint& strokeSize,
+ const SkRasterClip&, SkBlitter*);
+ static void FillTriangle(const SkPoint pts[], const SkRasterClip&, SkBlitter*);
+ static void HairLine(const SkPoint&, const SkPoint&, const SkRasterClip&,
SkBlitter*);
- static void HairRect(const SkRect&, const SkRegion* clip, SkBlitter*);
- static void HairPath(const SkPath&, const SkRegion* clip, SkBlitter*);
+ static void AntiHairLine(const SkPoint&, const SkPoint&, const SkRasterClip&,
+ SkBlitter*);
+ static void HairRect(const SkRect&, const SkRasterClip&, SkBlitter*);
+ static void AntiHairRect(const SkRect&, const SkRasterClip&, SkBlitter*);
+ static void HairPath(const SkPath&, const SkRasterClip&, SkBlitter*);
+ static void AntiHairPath(const SkPath&, const SkRasterClip&, SkBlitter*);
+
+private:
+ friend class SkAAClip;
+ friend class SkRegion;
- static void AntiFillXRect(const SkXRect&, const SkRegion* clip, SkBlitter*);
+ static void FillIRect(const SkIRect&, const SkRegion* clip, SkBlitter*);
+ static void FillXRect(const SkXRect&, const SkRegion* clip, SkBlitter*);
#ifdef SK_SCALAR_IS_FIXED
- static void AntiFillRect(const SkRect& rect, const SkRegion* clip,
+ static void FillRect(const SkRect& rect, const SkRegion* clip,
SkBlitter* blitter) {
+ SkScan::FillXRect(*(const SkXRect*)&rect, clip, blitter);
+ }
+ static void AntiFillRect(const SkRect& rect, const SkRegion* clip,
+ SkBlitter* blitter) {
SkScan::AntiFillXRect(*(const SkXRect*)&rect, clip, blitter);
}
#else
+ static void FillRect(const SkRect&, const SkRegion* clip, SkBlitter*);
static void AntiFillRect(const SkRect&, const SkRegion* clip, SkBlitter*);
#endif
+ static void AntiFillXRect(const SkXRect&, const SkRegion*, SkBlitter*);
+ static void FillPath(const SkPath&, const SkRegion& clip, SkBlitter*);
+ static void AntiFillPath(const SkPath&, const SkRegion& clip, SkBlitter*,
+ bool forceRLE = false);
+ static void FillTriangle(const SkPoint pts[], const SkRegion*, SkBlitter*);
- static void AntiFillPath(const SkPath&, const SkRegion& clip, SkBlitter*);
-
- static void AntiHairLine(const SkPoint&, const SkPoint&, const SkRegion*,
- SkBlitter*);
- static void AntiHairRect(const SkRect&, const SkRegion* clip, SkBlitter*);
- static void AntiHairPath(const SkPath&, const SkRegion* clip, SkBlitter*);
-
- // draws with a miter-join
- static void FrameRect(const SkRect&, const SkPoint& strokeSize,
- const SkRegion*, SkBlitter*);
static void AntiFrameRect(const SkRect&, const SkPoint& strokeSize,
const SkRegion*, SkBlitter*);
+ static void HairLineRgn(const SkPoint&, const SkPoint&, const SkRegion*,
+ SkBlitter*);
+ static void AntiHairLineRgn(const SkPoint&, const SkPoint&, const SkRegion*,
+ SkBlitter*);
};
/** Assign an SkXRect from a SkIRect, by promoting the src rect's coordinates
diff --git a/include/core/SkShader.h b/include/core/SkShader.h
index cf1d4e9..7c5be06 100644
--- a/include/core/SkShader.h
+++ b/include/core/SkShader.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkShader_DEFINED
#define SkShader_DEFINED
@@ -104,6 +97,15 @@ public:
virtual uint32_t getFlags() { return 0; }
/**
+ * Returns true if the shader is guaranteed to produce only opaque
+ * colors, subject to the SkPaint using the shader to apply an opaque
+ * alpha value. Subclasses should override this to allow some
+ * optimizations. isOpaque() can be called at any time, unlike getFlags,
+ * which only works properly when the context is set.
+ */
+ virtual bool isOpaque() const { return false; }
+
+ /**
* Return the alpha associated with the data returned by shadeSpan16(). If
* kHasSpan16_Flag is not set, this value is meaningless.
*/
@@ -277,7 +279,7 @@ public:
static SkShader* CreateBitmapShader(const SkBitmap& src,
TileMode tmx, TileMode tmy);
- virtual void flatten(SkFlattenableWriteBuffer& );
+ virtual void flatten(SkFlattenableWriteBuffer& ) SK_OVERRIDE;
protected:
enum MatrixClass {
kLinear_MatrixClass, // no perspective
diff --git a/include/core/SkShape.h b/include/core/SkShape.h
index 6cee70e..c7cf9ec 100644
--- a/include/core/SkShape.h
+++ b/include/core/SkShape.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkShape_DEFINED
#define SkShape_DEFINED
@@ -31,6 +38,8 @@ public:
// public for Registrar
static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
+
protected:
virtual void onDraw(SkCanvas*);
diff --git a/include/core/SkSize.h b/include/core/SkSize.h
index 8371c9b..12dbeae 100644
--- a/include/core/SkSize.h
+++ b/include/core/SkSize.h
@@ -1,4 +1,11 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSize_DEFINED
#define SkSize_DEFINED
diff --git a/include/core/SkStream.h b/include/core/SkStream.h
index c3d8185..90d2357 100644
--- a/include/core/SkStream.h
+++ b/include/core/SkStream.h
@@ -1,25 +1,20 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkStream_DEFINED
#define SkStream_DEFINED
#include "SkRefCnt.h"
#include "SkScalar.h"
+class SkData;
+
class SK_API SkStream : public SkRefCnt {
public:
virtual ~SkStream();
@@ -100,6 +95,8 @@ public:
bool writePackedUInt(size_t);
bool writeStream(SkStream* input, size_t length);
+
+ bool writeData(const SkData*);
};
////////////////////////////////////////////////////////////////////////////////////////
@@ -127,9 +124,9 @@ public:
*/
void setPath(const char path[]);
- virtual bool rewind();
- virtual size_t read(void* buffer, size_t size);
- virtual const char* getFileName();
+ virtual bool rewind() SK_OVERRIDE;
+ virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
+ virtual const char* getFileName() SK_OVERRIDE;
private:
SkFILE* fFILE;
@@ -151,9 +148,9 @@ public:
*/
bool isValid() const { return fFD >= 0; }
- virtual bool rewind();
- virtual size_t read(void* buffer, size_t size);
- virtual const char* getFileName() { return NULL; }
+ virtual bool rewind() SK_OVERRIDE;
+ virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
+ virtual const char* getFileName() SK_OVERRIDE { return NULL; }
private:
int fFD;
@@ -182,18 +179,31 @@ public:
will be freed with sk_free.
*/
void setMemoryOwned(const void* data, size_t length);
+
+ /**
+ * Return the stream's data in a SkData. The caller must call unref() when
+ * it is finished using the data.
+ */
+ SkData* copyToData() const;
+
+ /**
+ * Use the specified data as the memory for this stream. The stream will
+ * call ref() on the data (assuming it is not null). The function returns
+ * the data parameter as a convenience.
+ */
+ SkData* setData(SkData*);
+
void skipToAlign4();
- virtual bool rewind();
- virtual size_t read(void* buffer, size_t size);
- virtual const void* getMemoryBase();
+ virtual bool rewind() SK_OVERRIDE;
+ virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
+ virtual const void* getMemoryBase() SK_OVERRIDE;
const void* getAtPos();
size_t seek(size_t offset);
size_t peek() const { return fOffset; }
private:
- const void* fSrc;
- size_t fSize, fOffset;
- SkBool8 fWeOwnTheData;
+ SkData* fData;
+ size_t fOffset;
};
/** \class SkBufferStream
@@ -220,10 +230,10 @@ public:
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);
- virtual const void* getMemoryBase();
+ virtual bool rewind() SK_OVERRIDE;
+ virtual const char* getFileName() SK_OVERRIDE;
+ virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
+ virtual const void* getMemoryBase() SK_OVERRIDE;
private:
enum {
@@ -252,8 +262,8 @@ public:
*/
bool isValid() const { return fFILE != NULL; }
- virtual bool write(const void* buffer, size_t size);
- virtual void flush();
+ virtual bool write(const void* buffer, size_t size) SK_OVERRIDE;
+ virtual void flush() SK_OVERRIDE;
private:
SkFILE* fFILE;
};
@@ -261,7 +271,7 @@ private:
class SkMemoryWStream : public SkWStream {
public:
SkMemoryWStream(void* buffer, size_t size);
- virtual bool write(const void* buffer, size_t size);
+ virtual bool write(const void* buffer, size_t size) SK_OVERRIDE;
private:
char* fBuffer;
@@ -273,24 +283,24 @@ class SK_API SkDynamicMemoryWStream : public SkWStream {
public:
SkDynamicMemoryWStream();
virtual ~SkDynamicMemoryWStream();
- virtual bool write(const void* buffer, size_t size);
+
+ virtual bool write(const void* buffer, size_t size) SK_OVERRIDE;
// 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);
bool read(void* buffer, size_t offset, size_t size);
size_t getOffset() const { return fBytesWritten; }
+ size_t bytesWritten() const { 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;
+ void copyTo(void* dst) const;
+
+ /**
+ * Return a copy of the data written so far. This call is responsible for
+ * calling unref() when they are finished with the data.
+ */
+ SkData* copyToData() const;
- // same as getStream, but additionally detach the flattened datat
- const char* detach();
-
// reset the stream to its original state
void reset();
void padToAlign4();
@@ -299,15 +309,17 @@ private:
Block* fHead;
Block* fTail;
size_t fBytesWritten;
- mutable char* fCopyToCache;
+ mutable SkData* fCopy; // is invalidated if we write after it is created
+
+ void invalidateCopy();
};
class SkDebugWStream : public SkWStream {
public:
// overrides
- virtual bool write(const void* buffer, size_t size);
- virtual void newline();
+ virtual bool write(const void* buffer, size_t size) SK_OVERRIDE;
+ virtual void newline() SK_OVERRIDE;
};
// for now
diff --git a/include/core/SkString.h b/include/core/SkString.h
index 0295b75..3fa367b 100644
--- a/include/core/SkString.h
+++ b/include/core/SkString.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkString_DEFINED
#define SkString_DEFINED
@@ -73,7 +66,7 @@ public:
SkString(const SkString&);
~SkString();
- bool isEmpty() const { return fRec->fLength == 0; }
+ bool isEmpty() const { return 0 == fRec->fLength; }
size_t size() const { return (size_t) fRec->fLength; }
const char* c_str() const { return fRec->data(); }
char operator[](size_t n) const { return this->c_str()[n]; }
@@ -89,19 +82,19 @@ public:
return SkStrEndsWith(fRec->data(), suffix);
}
- friend int operator==(const SkString& a, const SkString& b) {
+ friend bool operator==(const SkString& a, const SkString& b) {
return a.equals(b);
}
- friend int operator!=(const SkString& a, const SkString& b) {
+ friend bool operator!=(const SkString& a, const SkString& b) {
return !a.equals(b);
}
// these methods edit the string
- SkString& operator=(const SkString&);
- SkString& operator=(const char text[]);
+ SkString& operator=(const SkString&);
+ SkString& operator=(const char text[]);
- char* writable_str();
+ char* writable_str();
char& operator[](size_t n) { return this->writable_str()[n]; }
void reset();
@@ -158,8 +151,8 @@ public:
private:
struct Rec {
public:
- uint16_t fLength;
- uint16_t fRefCnt;
+ size_t fLength;
+ int32_t fRefCnt;
char fBeginningOfData;
char* data() { return &fBeginningOfData; }
@@ -175,7 +168,7 @@ private:
#endif
static const Rec gEmptyRec;
- static Rec* AllocRec(const char text[], U16CPU len);
+ static Rec* AllocRec(const char text[], size_t len);
static Rec* RefRec(Rec*);
};
@@ -197,4 +190,7 @@ private:
uint16_t* fUCS2;
};
+/// Creates a new string and writes into it using a printf()-style format.
+SkString SkStringPrintf(const char* format, ...);
+
#endif
diff --git a/include/core/SkStroke.h b/include/core/SkStroke.h
index b593b69..d055b83 100644
--- a/include/core/SkStroke.h
+++ b/include/core/SkStroke.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkStroke_DEFINED
#define SkStroke_DEFINED
diff --git a/include/core/SkTArray.h b/include/core/SkTArray.h
new file mode 100644
index 0000000..577e860
--- /dev/null
+++ b/include/core/SkTArray.h
@@ -0,0 +1,415 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkTArray_DEFINED
+#define SkTArray_DEFINED
+
+#include <new>
+#include "SkTypes.h"
+#include "SkTemplates.h"
+
+template <typename T, bool MEM_COPY = false> class SkTArray;
+
+namespace SkTArrayExt {
+
+template<typename T>
+inline void copy(SkTArray<T, true>* self, const T* array) {
+ memcpy(self->fMemArray, array, self->fCount * sizeof(T));
+}
+template<typename T>
+inline void copyAndDelete(SkTArray<T, true>* self, char* newMemArray) {
+ memcpy(newMemArray, self->fMemArray, self->fCount * sizeof(T));
+}
+
+template<typename T>
+inline void copy(SkTArray<T, false>* self, const T* array) {
+ for (int i = 0; i < self->fCount; ++i) {
+ new (self->fItemArray + i) T(array[i]);
+ }
+}
+template<typename T>
+inline void copyAndDelete(SkTArray<T, false>* self, char* newMemArray) {
+ for (int i = 0; i < self->fCount; ++i) {
+ new (newMemArray + sizeof(T) * i) T(self->fItemArray[i]);
+ self->fItemArray[i].~T();
+ }
+}
+
+}
+
+/** When MEM_COPY is true T will be bit copied when moved.
+ When MEM_COPY is false, T will be copy constructed / destructed.
+ In all cases T's constructor will be called on allocation,
+ and its destructor will be called from this object's destructor.
+*/
+template <typename T, bool MEM_COPY> class SkTArray {
+public:
+ /**
+ * Creates an empty array with no initial storage
+ */
+ SkTArray() {
+ fCount = 0;
+ fReserveCount = gMIN_ALLOC_COUNT;
+ fAllocCount = 0;
+ fMemArray = NULL;
+ fPreAllocMemArray = NULL;
+ }
+
+ /**
+ * Creates an empty array that will preallocate space for reserveCount
+ * elements.
+ */
+ explicit SkTArray(int reserveCount) {
+ this->init(NULL, 0, NULL, reserveCount);
+ }
+
+ /**
+ * Copies one array to another. The new array will be heap allocated.
+ */
+ explicit SkTArray(const SkTArray& array) {
+ this->init(array.fItemArray, array.fCount, NULL, 0);
+ }
+
+ /**
+ * Creates a SkTArray by copying contents of a standard C array. The new
+ * array will be heap allocated. Be careful not to use this constructor
+ * when you really want the (void*, int) version.
+ */
+ SkTArray(const T* array, int count) {
+ this->init(array, count, NULL, 0);
+ }
+
+ /**
+ * assign copy of array to this
+ */
+ SkTArray& operator =(const SkTArray& array) {
+ for (int i = 0; i < fCount; ++i) {
+ fItemArray[i].~T();
+ }
+ fCount = 0;
+ checkRealloc((int)array.count());
+ fCount = array.count();
+ SkTArrayExt::copy(this, static_cast<const T*>(array.fMemArray));
+ return *this;
+ }
+
+ virtual ~SkTArray() {
+ for (int i = 0; i < fCount; ++i) {
+ fItemArray[i].~T();
+ }
+ if (fMemArray != fPreAllocMemArray) {
+ sk_free(fMemArray);
+ }
+ }
+
+ /**
+ * Resets to count() == 0
+ */
+ void reset() { this->pop_back_n(fCount); }
+
+ /**
+ * Number of elements in the array.
+ */
+ int count() const { return fCount; }
+
+ /**
+ * Is the array empty.
+ */
+ bool empty() const { return !fCount; }
+
+ /**
+ * Adds 1 new default-constructed T value and returns in by reference. Note
+ * the reference only remains valid until the next call that adds or removes
+ * elements.
+ */
+ T& push_back() {
+ checkRealloc(1);
+ new ((char*)fMemArray+sizeof(T)*fCount) T;
+ ++fCount;
+ return fItemArray[fCount-1];
+ }
+
+ /**
+ * Version of above that uses a copy constructor to initialize the new item
+ */
+ T& push_back(const T& t) {
+ checkRealloc(1);
+ new ((char*)fMemArray+sizeof(T)*fCount) T(t);
+ ++fCount;
+ return fItemArray[fCount-1];
+ }
+
+ /**
+ * Allocates n more default T values, and returns the address of the start
+ * of that new range. Note: this address is only valid until the next API
+ * call made on the array that might add or remove elements.
+ */
+ T* push_back_n(int n) {
+ SkASSERT(n >= 0);
+ checkRealloc(n);
+ for (int i = 0; i < n; ++i) {
+ new (fItemArray + fCount + i) T;
+ }
+ fCount += n;
+ return fItemArray + fCount - n;
+ }
+
+ /**
+ * Version of above that uses a copy constructor to initialize all n items
+ * to the same T.
+ */
+ T* push_back_n(int n, const T& t) {
+ SkASSERT(n >= 0);
+ checkRealloc(n);
+ for (int i = 0; i < n; ++i) {
+ new (fItemArray + fCount + i) T(t);
+ }
+ fCount += n;
+ return fItemArray + fCount - n;
+ }
+
+ /**
+ * Version of above that uses a copy constructor to initialize the n items
+ * to separate T values.
+ */
+ T* push_back_n(int n, const T t[]) {
+ SkASSERT(n >= 0);
+ checkRealloc(n);
+ for (int i = 0; i < n; ++i) {
+ new (fItemArray + fCount + i) T(t[i]);
+ }
+ fCount += n;
+ return fItemArray + fCount - n;
+ }
+
+ /**
+ * Removes the last element. Not safe to call when count() == 0.
+ */
+ void pop_back() {
+ SkASSERT(fCount > 0);
+ --fCount;
+ fItemArray[fCount].~T();
+ checkRealloc(0);
+ }
+
+ /**
+ * Removes the last n elements. Not safe to call when count() < n.
+ */
+ void pop_back_n(int n) {
+ SkASSERT(n >= 0);
+ SkASSERT(fCount >= n);
+ fCount -= n;
+ for (int i = 0; i < n; ++i) {
+ fItemArray[i].~T();
+ }
+ checkRealloc(0);
+ }
+
+ /**
+ * Pushes or pops from the back to resize. Pushes will be default
+ * initialized.
+ */
+ void resize_back(int newCount) {
+ SkASSERT(newCount >= 0);
+
+ if (newCount > fCount) {
+ push_back_n(newCount - fCount);
+ } else if (newCount < fCount) {
+ pop_back_n(fCount - newCount);
+ }
+ }
+
+ /**
+ * Get the i^th element.
+ */
+ T& operator[] (int i) {
+ SkASSERT(i < fCount);
+ SkASSERT(i >= 0);
+ return fItemArray[i];
+ }
+
+ const T& operator[] (int i) const {
+ SkASSERT(i < fCount);
+ SkASSERT(i >= 0);
+ return fItemArray[i];
+ }
+
+ /**
+ * equivalent to operator[](0)
+ */
+ T& front() { SkASSERT(fCount > 0); return fItemArray[0];}
+
+ const T& front() const { SkASSERT(fCount > 0); return fItemArray[0];}
+
+ /**
+ * equivalent to operator[](count() - 1)
+ */
+ T& back() { SkASSERT(fCount); return fItemArray[fCount - 1];}
+
+ const T& back() const { SkASSERT(fCount > 0); return fItemArray[fCount - 1];}
+
+ /**
+ * equivalent to operator[](count()-1-i)
+ */
+ T& fromBack(int i) {
+ SkASSERT(i >= 0);
+ SkASSERT(i < fCount);
+ return fItemArray[fCount - i - 1];
+ }
+
+ const T& fromBack(int i) const {
+ SkASSERT(i >= 0);
+ SkASSERT(i < fCount);
+ return fItemArray[fCount - i - 1];
+ }
+
+protected:
+ /**
+ * Creates an empty array that will use the passed storage block until it
+ * is insufficiently large to hold the entire array.
+ */
+ template <int N>
+ SkTArray(SkAlignedSTStorage<N,T>* storage) {
+ this->init(NULL, 0, storage->get(), N);
+ }
+
+ /**
+ * Copy another array, using preallocated storage if preAllocCount >=
+ * array.count(). Otherwise storage will only be used when array shrinks
+ * to fit.
+ */
+ template <int N>
+ SkTArray(const SkTArray& array, SkAlignedSTStorage<N,T>* storage) {
+ this->init(array.fItemArray, array.fCount, storage->get(), N);
+ }
+
+ /**
+ * Copy a C array, using preallocated storage if preAllocCount >=
+ * count. Otherwise storage will only be used when array shrinks
+ * to fit.
+ */
+ template <int N>
+ SkTArray(const T* array, int count, SkAlignedSTStorage<N,T>* storage) {
+ this->init(array, count, storage->get(), N);
+ }
+
+ void init(const T* array, int count,
+ void* preAllocStorage, int preAllocOrReserveCount) {
+ SkASSERT(count >= 0);
+ SkASSERT(preAllocOrReserveCount >= 0);
+ fCount = count;
+ fReserveCount = (preAllocOrReserveCount > 0) ?
+ preAllocOrReserveCount :
+ gMIN_ALLOC_COUNT;
+ fPreAllocMemArray = preAllocStorage;
+ if (fReserveCount >= fCount &&
+ NULL != preAllocStorage) {
+ fAllocCount = fReserveCount;
+ fMemArray = preAllocStorage;
+ } else {
+ fAllocCount = SkMax32(fCount, fReserveCount);
+ fMemArray = sk_malloc_throw(fAllocCount * sizeof(T));
+ }
+
+ SkTArrayExt::copy(this, array);
+ }
+
+private:
+
+ static const int gMIN_ALLOC_COUNT = 8;
+
+ inline void checkRealloc(int delta) {
+ SkASSERT(fCount >= 0);
+ SkASSERT(fAllocCount >= 0);
+
+ SkASSERT(-delta <= fCount);
+
+ int newCount = fCount + delta;
+ int newAllocCount = fAllocCount;
+
+ if (newCount > fAllocCount) {
+ newAllocCount = SkMax32(newCount + ((newCount + 1) >> 1),
+ fReserveCount);
+ } else if (newCount < fAllocCount / 3) {
+ newAllocCount = SkMax32(fAllocCount / 2, fReserveCount);
+ }
+
+ if (newAllocCount != fAllocCount) {
+
+ fAllocCount = newAllocCount;
+ char* newMemArray;
+
+ if (fAllocCount == fReserveCount && NULL != fPreAllocMemArray) {
+ newMemArray = (char*) fPreAllocMemArray;
+ } else {
+ newMemArray = (char*) sk_malloc_throw(fAllocCount*sizeof(T));
+ }
+
+ SkTArrayExt::copyAndDelete<T>(this, newMemArray);
+
+ if (fMemArray != fPreAllocMemArray) {
+ sk_free(fMemArray);
+ }
+ fMemArray = newMemArray;
+ }
+ }
+
+ template<typename X> friend void SkTArrayExt::copy(SkTArray<X, true>* that, const X*);
+ template<typename X> friend void SkTArrayExt::copyAndDelete(SkTArray<X, true>* that, char*);
+
+ template<typename X> friend void SkTArrayExt::copy(SkTArray<X, false>* that, const X*);
+ template<typename X> friend void SkTArrayExt::copyAndDelete(SkTArray<X, false>* that, char*);
+
+ int fReserveCount;
+ int fCount;
+ int fAllocCount;
+ void* fPreAllocMemArray;
+ union {
+ T* fItemArray;
+ void* fMemArray;
+ };
+};
+
+/**
+ * Subclass of SkTArray that contains a preallocated memory block for the array.
+ */
+template <int N, typename T, bool DATA_TYPE = false>
+class SkSTArray : public SkTArray<T, DATA_TYPE> {
+private:
+ typedef SkTArray<T, DATA_TYPE> INHERITED;
+
+public:
+ SkSTArray() : INHERITED(&fStorage) {
+ }
+
+ SkSTArray(const SkSTArray& array)
+ : INHERITED(array, &fStorage) {
+ }
+
+ explicit SkSTArray(const INHERITED& array)
+ : INHERITED(array, &fStorage) {
+ }
+
+ SkSTArray(const T* array, int count)
+ : INHERITED(array, count, &fStorage) {
+ }
+
+ SkSTArray& operator= (const SkSTArray& array) {
+ return *this = *(const INHERITED*)&array;
+ }
+
+ SkSTArray& operator= (const INHERITED& array) {
+ INHERITED::operator=(array);
+ return *this;
+ }
+
+private:
+ SkAlignedSTStorage<N,T> fStorage;
+};
+
+#endif
+
diff --git a/include/core/SkTDArray.h b/include/core/SkTDArray.h
index c64d773..5f62203 100644
--- a/include/core/SkTDArray.h
+++ b/include/core/SkTDArray.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTDArray_DEFINED
#define SkTDArray_DEFINED
@@ -71,7 +64,7 @@ public:
return *this;
}
- friend int operator==(const SkTDArray<T>& a, const SkTDArray<T>& b) {
+ friend bool 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)));
@@ -98,7 +91,17 @@ public:
}
bool isEmpty() const { return fCount == 0; }
+
+ /**
+ * Return the number of elements in the array
+ */
int count() const { return fCount; }
+
+ /**
+ * return the number of bytes in the array: count * sizeof(T)
+ */
+ size_t bytes() const { return fCount * sizeof(T); }
+
T* begin() const { return fArray; }
T* end() const { return fArray ? fArray + fCount : NULL; }
T& operator[](int index) const {
diff --git a/include/core/SkTDStack.h b/include/core/SkTDStack.h
index 321c138..be34e01 100644
--- a/include/core/SkTDStack.h
+++ b/include/core/SkTDStack.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTDStack_DEFINED
#define SkTDStack_DEFINED
@@ -21,18 +14,16 @@
template <typename T> class SkTDStack : SkNoncopyable {
public:
- SkTDStack() : fCount(0), fTotalCount(0)
- {
+ SkTDStack() : fCount(0), fTotalCount(0) {
fInitialRec.fNext = NULL;
fRec = &fInitialRec;
// fCount = kSlotCount;
}
- ~SkTDStack()
- {
+
+ ~SkTDStack() {
Rec* rec = fRec;
- while (rec != &fInitialRec)
- {
+ while (rec != &fInitialRec) {
Rec* next = rec->fNext;
sk_free(rec);
rec = next;
@@ -43,11 +34,9 @@ public:
int depth() const { return fTotalCount; }
bool empty() const { return fTotalCount == 0; }
- T* push()
- {
+ T* push() {
SkASSERT(fCount <= kSlotCount);
- if (fCount == kSlotCount)
- {
+ if (fCount == kSlotCount) {
Rec* rec = (Rec*)sk_malloc_throw(sizeof(Rec));
rec->fNext = fRec;
fRec = rec;
@@ -56,48 +45,48 @@ public:
++fTotalCount;
return &fRec->fSlots[fCount++];
}
+
void push(const T& elem) { *this->push() = elem; }
- const T& index(int idx) const
- {
+
+ const T& index(int idx) const {
SkASSERT(fRec && fCount > idx);
return fRec->fSlots[fCount - idx - 1];
- }
- T& index(int idx)
- {
+ }
+
+ T& index(int idx) {
SkASSERT(fRec && fCount > idx);
return fRec->fSlots[fCount - idx - 1];
- }
- const T& top() const
- {
+ }
+
+ const T& top() const {
SkASSERT(fRec && fCount > 0);
return fRec->fSlots[fCount - 1];
}
- T& top()
- {
+
+ T& top() {
SkASSERT(fRec && fCount > 0);
return fRec->fSlots[fCount - 1];
}
- void pop(T* elem)
- {
- if (elem)
+
+ void pop(T* elem) {
+ if (elem) {
*elem = fRec->fSlots[fCount - 1];
+ }
this->pop();
}
- void pop()
- {
+
+ void pop() {
SkASSERT(fCount > 0 && fRec);
--fTotalCount;
- if (--fCount == 0)
- {
- if (fRec != &fInitialRec)
- {
+ if (--fCount == 0) {
+ if (fRec != &fInitialRec) {
Rec* rec = fRec->fNext;
sk_free(fRec);
fCount = kSlotCount;
fRec = rec;
- }
- else
+ } else {
SkASSERT(fTotalCount == 0);
+ }
}
}
diff --git a/include/core/SkTDict.h b/include/core/SkTDict.h
index 0b92779..3620899 100644
--- a/include/core/SkTDict.h
+++ b/include/core/SkTDict.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTDict_DEFINED
#define SkTDict_DEFINED
diff --git a/include/core/SkTLazy.h b/include/core/SkTLazy.h
index fecc975..9cfaccb 100644
--- a/include/core/SkTLazy.h
+++ b/include/core/SkTLazy.h
@@ -1,24 +1,18 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTLazy_DEFINED
#define SkTLazy_DEFINED
#include "SkTypes.h"
+#include <new>
/**
* Efficient way to defer allocating/initializing a class until it is needed
@@ -35,14 +29,15 @@ public:
}
SkTLazy(const SkTLazy<T>& src) : fPtr(NULL) {
- const T* ptr = src.get();
- if (ptr) {
- fPtr = new (fStorage) T(*ptr);
+ if (src.isValid()) {
+ fPtr = new (fStorage) T(*src->get());
+ } else {
+ fPtr = NULL;
}
}
~SkTLazy() {
- if (fPtr) {
+ if (this->isValid()) {
fPtr->~T();
}
}
@@ -54,13 +49,13 @@ public:
* always returned.
*/
T* init() {
- if (fPtr) {
+ if (this->isValid()) {
fPtr->~T();
}
- fPtr = new (fStorage) T;
+ fPtr = new (SkTCast<T*>(fStorage)) T;
return fPtr;
}
-
+
/**
* Copy src into this, and return a pointer to a copy of it. Note this
* will always return the same pointer, so if it is called on a lazy that
@@ -68,19 +63,25 @@ public:
* contents.
*/
T* set(const T& src) {
- if (fPtr) {
+ if (this->isValid()) {
*fPtr = src;
} else {
- fPtr = new (fStorage) T(src);
+ fPtr = new (SkTCast<T*>(fStorage)) T(src);
}
return fPtr;
}
+
+ /**
+ * Returns true if a valid object has been initialized in the SkTLazy,
+ * false otherwise.
+ */
+ bool isValid() const { return NULL != fPtr; }
/**
* Returns either NULL, or a copy of the object that was passed to
* set() or the constructor.
*/
- T* get() const { return fPtr; }
+ T* get() const { SkASSERT(this->isValid()); return fPtr; }
private:
T* fPtr; // NULL or fStorage
diff --git a/include/core/SkTRegistry.h b/include/core/SkTRegistry.h
index 78c5a07..34fcffd 100644
--- a/include/core/SkTRegistry.h
+++ b/include/core/SkTRegistry.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright 2009, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2009 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTRegistry_DEFINED
#define SkTRegistry_DEFINED
@@ -28,7 +21,7 @@ public:
typedef T (*Factory)(P);
SkTRegistry(Factory fact) {
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
// work-around for double-initialization bug
{
SkTRegistry* reg = gHead;
diff --git a/include/core/SkTScopedPtr.h b/include/core/SkTScopedPtr.h
index 1e5d4c4..580d72f 100644
--- a/include/core/SkTScopedPtr.h
+++ b/include/core/SkTScopedPtr.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2011 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2011 Google Inc.
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTScopedPtr_DEFINED
#define SkTScopedPtr_DEFINED
diff --git a/include/core/SkTSearch.h b/include/core/SkTSearch.h
index e208071..d5ab18c 100644
--- a/include/core/SkTSearch.h
+++ b/include/core/SkTSearch.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTSearch_DEFINED
#define SkTSearch_DEFINED
diff --git a/include/core/SkTemplates.h b/include/core/SkTemplates.h
index 55109bf..03f0892 100644
--- a/include/core/SkTemplates.h
+++ b/include/core/SkTemplates.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTemplates_DEFINED
#define SkTemplates_DEFINED
@@ -179,36 +172,88 @@ private:
*/
template <typename T> class SkAutoTMalloc : SkNoncopyable {
public:
- SkAutoTMalloc(size_t count)
- {
+ SkAutoTMalloc(size_t count) {
fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
}
- ~SkAutoTMalloc()
- {
+
+ ~SkAutoTMalloc() {
sk_free(fPtr);
}
+
+ // doesn't preserve contents
+ void reset (size_t count) {
+ sk_free(fPtr);
+ fPtr = fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
+ }
+
T* get() const { return fPtr; }
+ operator T*() {
+ return fPtr;
+ }
+
+ operator const T*() const {
+ return fPtr;
+ }
+
+ T& operator[](int index) {
+ return fPtr[index];
+ }
+
+ const T& operator[](int index) const {
+ return fPtr[index];
+ }
+
private:
T* fPtr;
};
-template <size_t N, typename T> class SkAutoSTMalloc : SkNoncopyable {
+template <size_t N, typename T> class SK_API SkAutoSTMalloc : SkNoncopyable {
public:
- SkAutoSTMalloc(size_t count)
- {
- if (count <= N)
+ SkAutoSTMalloc(size_t count) {
+ if (count <= N) {
fPtr = fTStorage;
- else
+ } else {
fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
+ }
}
- ~SkAutoSTMalloc()
- {
- if (fPtr != fTStorage)
+
+ ~SkAutoSTMalloc() {
+ if (fPtr != fTStorage) {
sk_free(fPtr);
+ }
}
+
+ // doesn't preserve contents
+ void reset(size_t count) {
+ if (fPtr != fTStorage) {
+ sk_free(fPtr);
+ }
+ if (count <= N) {
+ fPtr = fTStorage;
+ } else {
+ fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
+ }
+ }
+
T* get() const { return fPtr; }
+ operator T*() {
+ return fPtr;
+ }
+
+ operator const T*() const {
+ return fPtr;
+ }
+
+ T& operator[](int index) {
+ return fPtr[index];
+ }
+
+ const T& operator[](int index) const {
+ return fPtr[index];
+ }
+
private:
T* fPtr;
union {
@@ -217,5 +262,37 @@ private:
};
};
+/**
+ * Reserves memory that is aligned on double and pointer boundaries.
+ * Hopefully this is sufficient for all practical purposes.
+ */
+template <size_t N> class SkAlignedSStorage : SkNoncopyable {
+public:
+ void* get() { return fData; }
+private:
+ union {
+ void* fPtr;
+ double fDouble;
+ char fData[N];
+ };
+};
+
+/**
+ * Reserves memory that is aligned on double and pointer boundaries.
+ * Hopefully this is sufficient for all practical purposes. Otherwise,
+ * we have to do some arcane trickery to determine alignment of non-POD
+ * types. Lifetime of the memory is the lifetime of the object.
+ */
+template <int N, typename T> class SkAlignedSTStorage : SkNoncopyable {
+public:
+ /**
+ * Returns void* because this object does not initialize the
+ * memory. Use placement new for types that require a cons.
+ */
+ void* get() { return fStorage.get(); }
+private:
+ SkAlignedSStorage<sizeof(T)*N> fStorage;
+};
+
#endif
diff --git a/include/core/SkThread.h b/include/core/SkThread.h
index 637492d..5f2da4a 100644
--- a/include/core/SkThread.h
+++ b/include/core/SkThread.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkThread_DEFINED
#define SkThread_DEFINED
diff --git a/include/core/SkThread_platform.h b/include/core/SkThread_platform.h
index f33f5dc..d83f3ed 100644
--- a/include/core/SkThread_platform.h
+++ b/include/core/SkThread_platform.h
@@ -1,30 +1,62 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkThread_platform_DEFINED
#define SkThread_platform_DEFINED
-#if defined(ANDROID) && !defined(SK_BUILD_FOR_ANDROID_NDK)
+#if defined(SK_BUILD_FOR_ANDROID)
-#include <utils/threads.h>
+#if defined(SK_BUILD_FOR_ANDROID_NDK)
+
+#include <stdint.h>
+
+/* Just use the GCC atomic intrinsics. They're supported by the NDK toolchain,
+ * have reasonable performance, and provide full memory barriers
+ */
+static __attribute__((always_inline)) int32_t sk_atomic_inc(int32_t *addr) {
+ return __sync_fetch_and_add(addr, 1);
+}
+
+static __attribute__((always_inline)) int32_t sk_atomic_dec(int32_t *addr) {
+ return __sync_fetch_and_add(addr, -1);
+}
+
+#else // !SK_BUILD_FOR_ANDROID_NDK
+
+/* The platform atomics operations are slightly more efficient than the
+ * GCC built-ins, so use them.
+ */
#include <utils/Atomic.h>
#define sk_atomic_inc(addr) android_atomic_inc(addr)
#define sk_atomic_dec(addr) android_atomic_dec(addr)
+#endif // !SK_BUILD_FOR_ANDROID_NDK
+
+#else // !SK_BUILD_FOR_ANDROID
+
+/** Implemented by the porting layer, this function adds 1 to the int specified
+ by the address (in a thread-safe manner), and returns the previous value.
+*/
+SK_API int32_t sk_atomic_inc(int32_t* addr);
+/** Implemented by the porting layer, this function subtracts 1 to the int
+ specified by the address (in a thread-safe manner), and returns the previous
+ value.
+*/
+SK_API int32_t sk_atomic_dec(int32_t* addr);
+
+#endif // !SK_BUILD_FOR_ANDROID
+
+#if defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_ANDROID_NDK)
+
+#include <utils/threads.h>
+
class SkMutex : android::Mutex {
public:
// if isGlobal is true, then ignore any errors in the platform-specific
diff --git a/include/core/SkTime.h b/include/core/SkTime.h
index 9ee7110..ede1fd9 100644
--- a/include/core/SkTime.h
+++ b/include/core/SkTime.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTime_DEFINED
#define SkTime_DEFINED
diff --git a/include/core/SkTrace.h b/include/core/SkTrace.h
new file mode 100644
index 0000000..2d48799
--- /dev/null
+++ b/include/core/SkTrace.h
@@ -0,0 +1,47 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkTrace_DEFINED
+#define SkTrace_DEFINED
+
+#ifdef SK_USER_TRACE_INCLUDE_FILE
+
+/* If your system embeds skia and has complex event logging, in
+ src/config/SkUserConfig.h:
+ - define the three SK_TRACE_EVENT macros to map to your system's
+ equivalents,
+ - define the name of the include file in SK_USER_TRACE_INCLUDE_FILE
+ A trivial example is given in src/utils/SkDebugTrace.h.
+
+ All arguments are const char*. Skia typically passes the name of
+ the object and function (and sometimes region of interest within
+ the function) separated by double colons for 'event'.
+
+ SK_TRACE_EVENT1 and SK_TRACE_EVENT2 take one or two arbitrary
+ name-value pairs that you also want to log. SkStringPrintf() is useful
+ for formatting these values.
+
+ For example:
+ SK_TRACE_EVENT0("GrContext::createAndLockTexture");
+ SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath::renderPasses",
+ "verts", SkStringPrintf("%i", vert - base).c_str());
+*/
+
+ #include SK_USER_TRACE_INCLUDE_FILE
+
+#else
+
+ #define SK_TRACE_EVENT0(event)
+ #define SK_TRACE_EVENT1(event, name1, value1)
+ #define SK_TRACE_EVENT2(event, name1, value1, name2, value2)
+
+#endif
+
+#endif
+
+
diff --git a/include/core/SkTypeface.h b/include/core/SkTypeface.h
index e13a21d..03ed11c 100644
--- a/include/core/SkTypeface.h
+++ b/include/core/SkTypeface.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTypeface_DEFINED
#define SkTypeface_DEFINED
@@ -141,10 +134,17 @@ public:
/** Retrieve detailed typeface metrics. Used by the PDF backend.
@param perGlyphInfo Indicate what glyph specific information (advances,
names, etc.) should be populated.
+ @param glyphIDs For per-glyph info, specify subset of the font by
+ giving glyph ids. Each integer represents a glyph
+ id. Passing NULL means all glyphs in the font.
+ @param glyphIDsCount Number of elements in subsetGlyphIds. Ignored if
+ glyphIDs is NULL.
@return The returned object has already been referenced.
*/
SkAdvancedTypefaceMetrics* getAdvancedTypefaceMetrics(
- SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo) const;
+ SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
+ const uint32_t* glyphIDs = NULL,
+ uint32_t glyphIDsCount = 0) const;
protected:
/** uniqueID must be unique (please!) and non-zero
diff --git a/include/core/SkTypes.h b/include/core/SkTypes.h
index 1a3a2e5..a584421 100644
--- a/include/core/SkTypes.h
+++ b/include/core/SkTypes.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTypes_DEFINED
#define SkTypes_DEFINED
@@ -43,12 +36,12 @@
/** Called internally if we run out of memory. The platform implementation must
not return, but should either throw an exception or otherwise exit.
*/
-extern void sk_out_of_memory(void);
+SK_API extern void sk_out_of_memory(void);
/** Called internally if we hit an unrecoverable error.
The platform implementation must not return, but should either throw
an exception or otherwise exit.
*/
-extern void sk_throw(void);
+SK_API extern void sk_throw(void);
enum {
SK_MALLOC_TEMP = 0x01, //!< hint to sk_malloc that the requested memory will be freed in the scope of the stack frame
@@ -62,21 +55,35 @@ enum {
SK_API 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);
+SK_API extern void* sk_malloc_throw(size_t size);
/** Same as standard realloc(), but this one never returns null on failure. It will throw
an exception if it fails.
*/
-extern void* sk_realloc_throw(void* buffer, size_t size);
+SK_API extern void* sk_realloc_throw(void* buffer, size_t size);
/** Free memory returned by sk_malloc(). It is safe to pass null.
*/
-SK_API extern void sk_free(void*);
+SK_API extern void sk_free(void*);
// bzero is safer than memset, but we can't rely on it, so... sk_bzero()
static inline void sk_bzero(void* buffer, size_t size) {
memset(buffer, 0, size);
}
-///////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_OVERRIDE_GLOBAL_NEW
+#include <new>
+
+inline void* operator new(size_t size) {
+ return sk_malloc_throw(size);
+}
+
+inline void operator delete(void* p) {
+ sk_free(p);
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
#define SK_INIT_TO_AVOID_WARNING = 0
@@ -86,6 +93,7 @@ static inline void sk_bzero(void* buffer, size_t size) {
#ifdef SK_DEBUG
#define SkASSERT(cond) SK_DEBUGBREAK(cond)
+ #define SkDEBUGFAIL(message) SkASSERT(false && message)
#define SkDEBUGCODE(code) code
#define SkDECLAREPARAM(type, var) , type var
#define SkPARAM(var) , var
@@ -94,6 +102,7 @@ static inline void sk_bzero(void* buffer, size_t size) {
#define SkAssertResult(cond) SkASSERT(cond)
#else
#define SkASSERT(cond)
+ #define SkDEBUGFAIL(message)
#define SkDEBUGCODE(code)
#define SkDEBUGF(args)
#define SkDECLAREPARAM(type, var)
@@ -209,6 +218,8 @@ static inline bool SkIsU16(long x) {
*/
#define SkAlign4(x) (((x) + 3) >> 2 << 2)
+#define SkIsAlign4(x) (((x) & 3) == 0)
+
typedef uint32_t SkFourByteTag;
#define SkSetFourByteTag(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
@@ -394,20 +405,84 @@ private:
SkAutoFree& operator=(const SkAutoFree&);
};
-class SkAutoMalloc : public SkAutoFree {
+/**
+ * Manage an allocated block of heap memory. This object is the sole manager of
+ * the lifetime of the block, so the caller must not call sk_free() or delete
+ * on the block, unless detach() was called.
+ */
+class SkAutoMalloc : public SkNoncopyable {
public:
- explicit SkAutoMalloc(size_t size)
- : SkAutoFree(sk_malloc_flags(size, SK_MALLOC_THROW | SK_MALLOC_TEMP)) {}
+ explicit SkAutoMalloc(size_t size = 0) {
+ fPtr = size ? sk_malloc_throw(size) : NULL;
+ fSize = size;
+ }
+
+ ~SkAutoMalloc() {
+ sk_free(fPtr);
+ }
+
+ /**
+ * Passed to reset to specify what happens if the requested size is smaller
+ * than the current size (and the current block was dynamically allocated).
+ */
+ enum OnShrink {
+ /**
+ * If the requested size is smaller than the current size, and the
+ * current block is dynamically allocated, free the old block and
+ * malloc a new block of the smaller size.
+ */
+ kAlloc_OnShrink,
+
+ /**
+ * If the requested size is smaller than the current size, and the
+ * current block is dynamically allocated, just return the old
+ * block.
+ */
+ kReuse_OnShrink,
+ };
- SkAutoMalloc(size_t size, unsigned flags)
- : SkAutoFree(sk_malloc_flags(size, flags)) {}
- SkAutoMalloc() {}
+ /**
+ * Reallocates the block to a new size. The ptr may or may not change.
+ */
+ void* reset(size_t size, OnShrink shrink = kAlloc_OnShrink) {
+ if (size == fSize || (kReuse_OnShrink == shrink && size < fSize)) {
+ return fPtr;
+ }
+
+ sk_free(fPtr);
+ fPtr = size ? sk_malloc_throw(size) : NULL;
+ fSize = size;
+
+ return fPtr;
+ }
+
+ /**
+ * Releases the block back to the heap
+ */
+ void free() {
+ this->reset(0);
+ }
+
+ /**
+ * Return the allocated block.
+ */
+ void* get() { return fPtr; }
+ const void* get() const { return fPtr; }
- void* alloc(size_t size,
- unsigned flags = (SK_MALLOC_THROW | SK_MALLOC_TEMP)) {
- sk_free(set(sk_malloc_flags(size, flags)));
- return get();
+ /** Transfer ownership of the current ptr to the caller, setting the
+ internal reference to null. Note the caller is reponsible for calling
+ sk_free on the returned address.
+ */
+ void* detach() {
+ void* ptr = fPtr;
+ fPtr = NULL;
+ fSize = 0;
+ return ptr;
}
+
+private:
+ void* fPtr;
+ size_t fSize; // can be larger than the requested size (see kReuse)
};
/**
@@ -420,11 +495,12 @@ template <size_t kSize> class SkAutoSMalloc : SkNoncopyable {
public:
/**
* Creates initially empty storage. get() returns a ptr, but it is to
- * a zero-byte allocation. Must call realloc(size) to return an allocated
+ * a zero-byte allocation. Must call reset(size) to return an allocated
* block.
*/
SkAutoSMalloc() {
fPtr = fStorage;
+ fSize = 0;
}
/**
@@ -434,7 +510,8 @@ public:
*/
explicit SkAutoSMalloc(size_t size) {
fPtr = fStorage;
- this->realloc(size);
+ fSize = 0;
+ this->reset(size);
}
/**
@@ -461,7 +538,13 @@ public:
* then the return block may be allocated locally, rather than from the
* heap.
*/
- void* realloc(size_t size) {
+ void* reset(size_t size,
+ SkAutoMalloc::OnShrink shrink = SkAutoMalloc::kAlloc_OnShrink) {
+ if (size == fSize || (SkAutoMalloc::kReuse_OnShrink == shrink &&
+ size < fSize)) {
+ return fPtr;
+ }
+
if (fPtr != (void*)fStorage) {
sk_free(fPtr);
}
@@ -476,13 +559,10 @@ public:
private:
void* fPtr;
+ size_t fSize; // can be larger than the requested size (see kReuse)
uint32_t fStorage[(kSize + 3) >> 2];
- // illegal
- SkAutoSMalloc(const SkAutoSMalloc&);
- SkAutoSMalloc& operator=(const SkAutoSMalloc&);
};
#endif /* C++ */
#endif
-
diff --git a/include/core/SkUnPreMultiply.h b/include/core/SkUnPreMultiply.h
index 44ea50e..7088918 100644
--- a/include/core/SkUnPreMultiply.h
+++ b/include/core/SkUnPreMultiply.h
@@ -1,22 +1,15 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkUnPreMultiply_DEFINED
#define SkUnPreMultiply_DEFINED
diff --git a/include/core/SkUnitMapper.h b/include/core/SkUnitMapper.h
index 5d1ea35..2bd482b 100644
--- a/include/core/SkUnitMapper.h
+++ b/include/core/SkUnitMapper.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkUnitMapper_DEFINED
#define SkUnitMapper_DEFINED
diff --git a/include/core/SkUserConfig.h b/include/core/SkUserConfig.h
index 29e64f2..b409e82 100644
--- a/include/core/SkUserConfig.h
+++ b/include/core/SkUserConfig.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkUserConfig_DEFINED
#define SkUserConfig_DEFINED
@@ -53,11 +46,6 @@
#include <utils/misc.h>
#endif
-#ifdef SK_BUILD_FOR_MAC
- #undef SK_BUILD_FOR_MAC
-#endif
-#define SK_BUILD_FOR_UNIX
-
/* Scalars (the fractional value type in skia) can be implemented either as
floats or 16.16 integers (fixed). Exactly one of these two symbols must be
defined.
@@ -68,7 +56,7 @@
/* Somewhat independent of how SkScalar is implemented, Skia also wants to know
if it can use floats at all. Naturally, if SK_SCALAR_IS_FLOAT is defined,
- then so muse SK_CAN_USE_FLOAT, but if scalars are fixed, SK_CAN_USE_FLOAT
+ SK_CAN_USE_FLOAT must be too; but if scalars are fixed, SK_CAN_USE_FLOAT
can go either way.
*/
#define SK_CAN_USE_FLOAT
@@ -119,25 +107,22 @@
#define SkLONGLONG int64_t
-/* Some envorinments do not suport writable globals (eek!). If yours does not,
- define this flag.
- */
-//#define SK_USE_RUNTIME_GLOBALS
-
-
/* To write debug messages to a console, skia will call SkDebugf(...) following
printf conventions (e.g. const char* format, ...). If you want to redirect
this to something other than printf, define yours here
*/
-#define SkDebugf(...) Android_SkDebugf(__FILE__, __LINE__, \
- __FUNCTION__, __VA_ARGS__)
-void Android_SkDebugf(const char* file, int line,
- const char* function, const char* format, ...);
+//#define SkDebugf(...) MyFunction(__VA_ARGS__)
-/* To enable additional blitters (and fontscaler code) to support separate
- alpha channels for R G B channels, define SK_SUPPORT_LCDTEXT
+/*
+ * To specify a different default font cache limit, define this. If this is
+ * undefined, skia will use a built-in value.
*/
-//#define SK_SUPPORT_LCDTEXT
+//#define SK_DEFAULT_FONT_CACHE_LIMIT (1024 * 1024)
+
+/* If defined, use CoreText instead of ATSUI on OS X.
+*/
+//#define SK_USE_MAC_CORE_TEXT
+
/* If zlib is available and you want to support the flate compression
algorithm (used in PDF generation), define SK_ZLIB_INCLUDE to be the
@@ -150,11 +135,22 @@ void Android_SkDebugf(const char* file, int line,
*/
//#define SK_ALLOW_LARGE_PDF_SCALARS
+/* Define this to provide font subsetter in PDF generation.
+ */
+//#define SK_SFNTLY_SUBSETTER "sfntly/subsetter/font_subsetter.h"
+
/* Define this to remove dimension checks on bitmaps. Not all blits will be
correct yet, so this is mostly for debugging the implementation.
*/
//#define SK_ALLOW_OVER_32K_BITMAPS
+/* Define this to set the upper limit for text to support LCD. Values that
+ are very large increase the cost in the font cache and draw slower, without
+ improving readability. If this is undefined, Skia will use its default
+ value (e.g. 48)
+ */
+//#define SK_MAX_SIZE_FOR_LCDTEXT 48
+
/* If SK_DEBUG is defined, then you can optionally define SK_SUPPORT_UNITTEST
which will run additional self-tests at startup. These can take a long time,
so this flag is optional.
@@ -163,6 +159,18 @@ void Android_SkDebugf(const char* file, int line,
#define SK_SUPPORT_UNITTEST
#endif
+/* If your system embeds skia and has complex event logging, define this
+ symbol to name a file that maps the following macros to your system's
+ equivalents:
+ SK_TRACE_EVENT0(event)
+ SK_TRACE_EVENT1(event, name1, value1)
+ SK_TRACE_EVENT2(event, name1, value1, name2, value2)
+ src/utils/SkDebugTrace.h has a trivial implementation that writes to
+ the debug output stream. If SK_USER_TRACE_INCLUDE_FILE is not defined,
+ SkTrace.h will define the above three macros to do nothing.
+*/
+//#undef SK_USER_TRACE_INCLUDE_FILE
+
/* Change the ordering to work in X windows.
*/
#ifdef SK_SAMPLES_FOR_X
@@ -173,4 +181,3 @@ void Android_SkDebugf(const char* file, int line,
#endif
#endif
-
diff --git a/include/core/SkUtils.h b/include/core/SkUtils.h
index a346d48..b700b96 100644
--- a/include/core/SkUtils.h
+++ b/include/core/SkUtils.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkUtils_DEFINED
#define SkUtils_DEFINED
@@ -39,13 +32,6 @@ void sk_memset32_portable(uint32_t dst[], uint32_t value, int count);
typedef void (*SkMemset32Proc)(uint32_t dst[], uint32_t value, int count);
SkMemset32Proc SkMemset32GetPlatformProc();
-#if defined(ANDROID) && !defined(SK_BUILD_FOR_ANDROID_NDK)
- #include "cutils/memory.h"
-
- #define sk_memset16(dst, value, count) android_memset16(dst, value, (count) << 1)
- #define sk_memset32(dst, value, count) android_memset32(dst, value, (count) << 2)
-#endif
-
#ifndef sk_memset16
extern SkMemset16Proc sk_memset16;
#endif
@@ -98,6 +84,21 @@ size_t SkUTF16_FromUnichar(SkUnichar uni, uint16_t utf16[] = NULL);
size_t SkUTF16_ToUTF8(const uint16_t utf16[], int numberOf16BitValues,
char utf8[] = NULL);
+inline bool SkUnichar_IsVariationSelector(SkUnichar uni) {
+/* The 'true' ranges are:
+ * 0x180B <= uni <= 0x180D
+ * 0xFE00 <= uni <= 0xFE0F
+ * 0xE0100 <= uni <= 0xE01EF
+ */
+ if (uni < 0x180B || uni > 0xE01EF) {
+ return false;
+ }
+ if ((uni > 0x180D && uni < 0xFE00) || (uni > 0xFE0F && uni < 0xE0100)) {
+ return false;
+ }
+ return true;
+}
+
///////////////////////////////////////////////////////////////////////////////
class SkAutoTrace {
diff --git a/include/core/SkWriter32.h b/include/core/SkWriter32.h
index c8ebb6a..d7159ff 100644
--- a/include/core/SkWriter32.h
+++ b/include/core/SkWriter32.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkWriter32_DEFINED
#define SkWriter32_DEFINED
@@ -28,11 +21,13 @@ class SkWStream;
class SkWriter32 : SkNoncopyable {
public:
- SkWriter32(size_t minSize) {
- fMinSize = minSize;
- fSize = 0;
- fHead = fTail = NULL;
- fSingleBlock = NULL;
+ SkWriter32(size_t minSize)
+ : fMinSize(minSize),
+ fSize(0),
+ fSingleBlock(NULL),
+ fSingleBlockSize(0),
+ fHead(NULL),
+ fTail(NULL) {
}
~SkWriter32();
diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h
index 6ab9d6d..0d1c207 100644
--- a/include/core/SkXfermode.h
+++ b/include/core/SkXfermode.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkXfermode_DEFINED
#define SkXfermode_DEFINED
@@ -138,6 +131,18 @@ public:
*/
static bool AsMode(SkXfermode*, Mode* mode);
+ /**
+ * Returns true if the xfermode claims to be the specified Mode. This works
+ * correctly even if the xfermode is NULL (which equates to kSrcOver.) Thus
+ * you can say this without checking for a null...
+ *
+ * If (SkXfermode::IsMode(paint.getXfermode(),
+ * SkXfermode::kDstOver_Mode)) {
+ * ...
+ * }
+ */
+ static bool IsMode(SkXfermode* xfer, Mode mode);
+
/** Return an SkXfermode object for the specified mode.
*/
static SkXfermode* Create(Mode mode);
@@ -167,6 +172,7 @@ public:
return AsMode(xfer, mode);
}
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
protected:
SkXfermode(SkFlattenableReadBuffer& rb) : SkFlattenable(rb) {}
@@ -200,21 +206,26 @@ public:
// overrides from SkXfermode
virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]);
+ const SkAlpha aa[]) SK_OVERRIDE;
virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]);
+ const SkAlpha aa[]) SK_OVERRIDE;
virtual void xfer4444(uint16_t dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]);
+ const SkAlpha aa[]) SK_OVERRIDE;
virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]);
+ const SkAlpha aa[]) SK_OVERRIDE;
// overrides from SkFlattenable
- virtual Factory getFactory() { return CreateProc; }
- virtual void flatten(SkFlattenableWriteBuffer&);
+ virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
+ virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
protected:
SkProcXfermode(SkFlattenableReadBuffer&);
+ // allow subclasses to update this after we unflatten
+ void setProc(SkXfermodeProc proc) {
+ fProc = proc;
+ }
+
private:
SkXfermodeProc fProc;
diff --git a/include/effects/Sk1DPathEffect.h b/include/effects/Sk1DPathEffect.h
index db01055..814e547 100644
--- a/include/effects/Sk1DPathEffect.h
+++ b/include/effects/Sk1DPathEffect.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef Sk1DPathEffect_DEFINED
#define Sk1DPathEffect_DEFINED
@@ -64,27 +57,29 @@ public:
SkPath1DPathEffect(const SkPath& path, SkScalar advance, SkScalar phase, Style);
// override from SkPathEffect
- virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
+ virtual bool filterPath(SkPath*, const SkPath&, SkScalar* width) SK_OVERRIDE;
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkPath1DPathEffect, (buffer));
+ }
+
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
protected:
SkPath1DPathEffect(SkFlattenableReadBuffer& buffer);
// overrides from Sk1DPathEffect
- virtual SkScalar begin(SkScalar contourLength);
- virtual SkScalar next(SkPath* dst, SkScalar distance, SkPathMeasure&);
+ virtual SkScalar begin(SkScalar contourLength) SK_OVERRIDE;
+ virtual SkScalar next(SkPath*, SkScalar distance, SkPathMeasure&) SK_OVERRIDE;
// overrides from SkFlattenable
- virtual void flatten(SkFlattenableWriteBuffer& );
- virtual Factory getFactory() { return CreateProc; }
+ virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+ virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
private:
SkPath fPath; // copied from constructor
SkScalar fAdvance; // copied from constructor
SkScalar fInitialOffset; // computed from phase
Style fStyle; // copied from constructor
-
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
- return SkNEW_ARGS(SkPath1DPathEffect, (buffer));
- }
typedef Sk1DPathEffect INHERITED;
};
diff --git a/include/effects/Sk2DPathEffect.h b/include/effects/Sk2DPathEffect.h
index 02ec760..b5d7fbb 100644
--- a/include/effects/Sk2DPathEffect.h
+++ b/include/effects/Sk2DPathEffect.h
@@ -1,40 +1,29 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef Sk2DPathEffect_DEFINED
#define Sk2DPathEffect_DEFINED
+#include "SkPath.h"
#include "SkPathEffect.h"
#include "SkMatrix.h"
-// This class is not exported to java.
class Sk2DPathEffect : public SkPathEffect {
public:
Sk2DPathEffect(const SkMatrix& mat);
// overrides
- // This method is not exported to java.
- virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
+ virtual bool filterPath(SkPath*, const SkPath&, SkScalar* width) SK_OVERRIDE;
// overrides from SkFlattenable
- // This method is not exported to java.
- virtual void flatten(SkFlattenableWriteBuffer&);
-
- // This method is not exported to java.
- virtual Factory getFactory();
+ virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+ virtual Factory getFactory() SK_OVERRIDE;
protected:
/** New virtual, to be overridden by subclasses.
@@ -58,6 +47,8 @@ protected:
// protected so that subclasses can call this during unflattening
Sk2DPathEffect(SkFlattenableReadBuffer&);
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
+
private:
SkMatrix fMatrix, fInverse;
// illegal
@@ -70,4 +61,30 @@ private:
typedef SkPathEffect INHERITED;
};
+class SkPath2DPathEffect : public Sk2DPathEffect {
+public:
+ /**
+ * Stamp the specified path to fill the shape, using the matrix to define
+ * the latice.
+ */
+ SkPath2DPathEffect(const SkMatrix&, const SkPath&);
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
+
+protected:
+ SkPath2DPathEffect(SkFlattenableReadBuffer& buffer);
+
+ virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+ virtual Factory getFactory() SK_OVERRIDE;
+ virtual void next(const SkPoint&, int u, int v, SkPath* dst) SK_OVERRIDE;
+
+private:
+ SkPath fPath;
+
+ typedef Sk2DPathEffect INHERITED;
+};
+
+
#endif
diff --git a/include/effects/SkArithmeticMode.h b/include/effects/SkArithmeticMode.h
new file mode 100644
index 0000000..70d660f
--- /dev/null
+++ b/include/effects/SkArithmeticMode.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkArithmeticMode_DEFINED
+#define SkArithmeticMode_DEFINED
+
+#include "SkXfermode.h"
+
+class SkArithmeticMode : public SkXfermode {
+public:
+ /**
+ * result = clamp[k1 * src * dst + k2 * src + k3 * dst + k4]
+ *
+ * src and dst are treated as being [0.0 .. 1.0]. The polynomial is
+ * evaluated on their unpremultiplied components.
+ *
+ * k1=k2=k3=0, k4=1.0 results in returning opaque white
+ * k1=k3=k4=0, k2=1.0 results in returning the src
+ * k1=k2=k4=0, k3=1.0 results in returning the dst
+ */
+ static SkXfermode* Create(SkScalar k1, SkScalar k2,
+ SkScalar k3, SkScalar k4);
+};
+
+#endif
+
diff --git a/include/effects/SkAvoidXfermode.h b/include/effects/SkAvoidXfermode.h
index b52e6f5..398eaea 100644
--- a/include/effects/SkAvoidXfermode.h
+++ b/include/effects/SkAvoidXfermode.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkAvoidXfermode_DEFINED
#define SkAvoidXfermode_DEFINED
@@ -50,22 +43,24 @@ public:
// overrides from SkXfermode
virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]);
+ const SkAlpha aa[]) SK_OVERRIDE;
virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]);
+ const SkAlpha aa[]) SK_OVERRIDE;
virtual void xfer4444(uint16_t dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]);
+ const SkAlpha aa[]) SK_OVERRIDE;
virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count,
- const SkAlpha aa[]);
+ const SkAlpha aa[]) SK_OVERRIDE;
// overrides from SkFlattenable
- virtual Factory getFactory();
- virtual void flatten(SkFlattenableWriteBuffer&);
+ virtual Factory getFactory() SK_OVERRIDE;
+ virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkAvoidXfermode, (buffer));
}
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
+
protected:
SkAvoidXfermode(SkFlattenableReadBuffer&);
diff --git a/include/effects/SkBlurDrawLooper.h b/include/effects/SkBlurDrawLooper.h
index 846048c..be1a78e 100644
--- a/include/effects/SkBlurDrawLooper.h
+++ b/include/effects/SkBlurDrawLooper.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkBlurDrawLooper_DEFINED
#define SkBlurDrawLooper_DEFINED
@@ -55,6 +48,7 @@ public:
return SkNEW_ARGS(SkBlurDrawLooper, (buffer));
}
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
protected:
SkBlurDrawLooper(SkFlattenableReadBuffer&);
diff --git a/include/effects/SkBlurImageFilter.h b/include/effects/SkBlurImageFilter.h
new file mode 100644
index 0000000..4c9798b
--- /dev/null
+++ b/include/effects/SkBlurImageFilter.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkBlurImageFilter_DEFINED
+#define SkBlurImageFilter_DEFINED
+
+#include "SkImageFilter.h"
+
+class SK_API SkBlurImageFilter : public SkImageFilter {
+public:
+ SkBlurImageFilter(SkScalar sigmaX, SkScalar sigmaY);
+
+ virtual bool asABlur(SkSize* sigma) const SK_OVERRIDE;
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkBlurImageFilter, (buffer));
+ }
+
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
+
+protected:
+ explicit SkBlurImageFilter(SkFlattenableReadBuffer& buffer);
+
+ virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
+ SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
+ virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE;
+ virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
+
+private:
+ SkSize fSigma;
+ typedef SkImageFilter INHERITED;
+};
+
+#endif
+
diff --git a/include/effects/SkBlurMaskFilter.h b/include/effects/SkBlurMaskFilter.h
index daca68d..9e85d87 100644
--- a/include/effects/SkBlurMaskFilter.h
+++ b/include/effects/SkBlurMaskFilter.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkBlurMaskFilter_DEFINED
#define SkBlurMaskFilter_DEFINED
@@ -62,6 +55,8 @@ public:
SkScalar ambient, SkScalar specular,
SkScalar blurRadius);
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
+
private:
SkBlurMaskFilter(); // can't be instantiated
};
diff --git a/include/effects/SkColorMatrix.h b/include/effects/SkColorMatrix.h
index cee5d6e..ee383db 100644
--- a/include/effects/SkColorMatrix.h
+++ b/include/effects/SkColorMatrix.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2007 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkColorMatrix_DEFINED
#define SkColorMatrix_DEFINED
diff --git a/include/effects/SkColorMatrixFilter.h b/include/effects/SkColorMatrixFilter.h
index d8ef81c..1475258 100644
--- a/include/effects/SkColorMatrixFilter.h
+++ b/include/effects/SkColorMatrixFilter.h
@@ -1,26 +1,19 @@
+
/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2007 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkColorMatrixFilter_DEFINED
#define SkColorMatrixFilter_DEFINED
#include "SkColorFilter.h"
#include "SkColorMatrix.h"
-class SkColorMatrixFilter : public SkColorFilter {
+class SK_API SkColorMatrixFilter : public SkColorFilter {
public:
SkColorMatrixFilter();
explicit SkColorMatrixFilter(const SkColorMatrix&);
@@ -30,12 +23,13 @@ public:
void setArray(const SkScalar array[20]);
// overrides from SkColorFilter
- virtual void filterSpan(const SkPMColor src[], int count, SkPMColor[]);
- virtual void filterSpan16(const uint16_t src[], int count, uint16_t[]);
- virtual uint32_t getFlags();
+ virtual void filterSpan(const SkPMColor src[], int count, SkPMColor[]) SK_OVERRIDE;
+ virtual void filterSpan16(const uint16_t src[], int count, uint16_t[]) SK_OVERRIDE;
+ virtual uint32_t getFlags() SK_OVERRIDE;
+ virtual bool asColorMatrix(SkScalar matrix[20]) SK_OVERRIDE;
// overrides for SkFlattenable
- virtual void flatten(SkFlattenableWriteBuffer& buffer);
+ virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE;
struct State {
int32_t fArray[20];
@@ -45,6 +39,8 @@ public:
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer);
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
+
protected:
// overrides for SkFlattenable
virtual Factory getFactory();
diff --git a/include/effects/SkCornerPathEffect.h b/include/effects/SkCornerPathEffect.h
index 823de3f..990bad0 100644
--- a/include/effects/SkCornerPathEffect.h
+++ b/include/effects/SkCornerPathEffect.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkCornerPathEffect_DEFINED
#define SkCornerPathEffect_DEFINED
@@ -42,17 +35,15 @@ public:
// This method is not exported to java.
virtual void flatten(SkFlattenableWriteBuffer&);
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
+
protected:
SkCornerPathEffect(SkFlattenableReadBuffer&);
private:
SkScalar fRadius;
-
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
-
- // illegal
- SkCornerPathEffect(const SkCornerPathEffect&);
- SkCornerPathEffect& operator=(const SkCornerPathEffect&);
typedef SkPathEffect INHERITED;
};
diff --git a/include/effects/SkDashPathEffect.h b/include/effects/SkDashPathEffect.h
index 145f67d..6d34910 100644
--- a/include/effects/SkDashPathEffect.h
+++ b/include/effects/SkDashPathEffect.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkDashPathEffect_DEFINED
#define SkDashPathEffect_DEFINED
@@ -44,6 +37,10 @@ public:
// This method is not exported to java.
virtual void flatten(SkFlattenableWriteBuffer&);
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
+
protected:
SkDashPathEffect(SkFlattenableReadBuffer&);
@@ -56,8 +53,6 @@ private:
SkScalar fIntervalLength;
bool fScaleToFit;
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
-
typedef SkPathEffect INHERITED;
};
diff --git a/include/effects/SkDiscretePathEffect.h b/include/effects/SkDiscretePathEffect.h
index 2950950..5369ddb 100644
--- a/include/effects/SkDiscretePathEffect.h
+++ b/include/effects/SkDiscretePathEffect.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkDiscretePathEffect_DEFINED
#define SkDiscretePathEffect_DEFINED
@@ -41,13 +34,15 @@ public:
// This method is not exported to java.
virtual void flatten(SkFlattenableWriteBuffer&);
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
+
protected:
SkDiscretePathEffect(SkFlattenableReadBuffer&);
private:
SkScalar fSegLength, fPerterb;
-
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
typedef SkPathEffect INHERITED;
};
diff --git a/include/effects/SkDrawExtraPathEffect.h b/include/effects/SkDrawExtraPathEffect.h
index 65e255a..c7611f0 100644
--- a/include/effects/SkDrawExtraPathEffect.h
+++ b/include/effects/SkDrawExtraPathEffect.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SK_DRAW_EXTRA_PATH_EFFECT_H
#define SK_DRAW_EXTRA_PATH_EFFECT_H
class SkAnimator;
diff --git a/include/effects/SkEffects.h b/include/effects/SkEffects.h
new file mode 100644
index 0000000..04091de
--- /dev/null
+++ b/include/effects/SkEffects.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkEffects_DEFINED
+#define SkEffects_DEFINED
+
+class SkEffects {
+public:
+ static void Init();
+};
+
+#endif
diff --git a/include/effects/SkEmbossMaskFilter.h b/include/effects/SkEmbossMaskFilter.h
index b0c12c5..257e19a 100644
--- a/include/effects/SkEmbossMaskFilter.h
+++ b/include/effects/SkEmbossMaskFilter.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkEmbossMaskFilter_DEFINED
#define SkEmbossMaskFilter_DEFINED
@@ -48,6 +41,8 @@ public:
// This method is not exported to java.
virtual void flatten(SkFlattenableWriteBuffer&);
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
+
protected:
SkEmbossMaskFilter(SkFlattenableReadBuffer&);
diff --git a/include/effects/SkGradientShader.h b/include/effects/SkGradientShader.h
index 5623be4..3232703 100644
--- a/include/effects/SkGradientShader.h
+++ b/include/effects/SkGradientShader.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkGradientShader_DEFINED
#define SkGradientShader_DEFINED
@@ -119,6 +112,8 @@ public:
static SkShader* CreateSweep(SkScalar cx, SkScalar cy,
const SkColor colors[], const SkScalar pos[],
int count, SkUnitMapper* mapper = NULL);
+
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
};
#endif
diff --git a/include/effects/SkGroupShape.h b/include/effects/SkGroupShape.h
index 2c851fa..7764003 100644
--- a/include/effects/SkGroupShape.h
+++ b/include/effects/SkGroupShape.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkGroupShape_DEFINED
#define SkGroupShape_DEFINED
@@ -131,6 +138,8 @@ public:
// public for Registrar
static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
+
protected:
// overrides
virtual void onDraw(SkCanvas*);
diff --git a/include/effects/SkKernel33MaskFilter.h b/include/effects/SkKernel33MaskFilter.h
index 45aaef8..2b9e6d4 100644
--- a/include/effects/SkKernel33MaskFilter.h
+++ b/include/effects/SkKernel33MaskFilter.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkKernel33MaskFilter_DEFINED
#define SkKernel33MaskFilter_DEFINED
diff --git a/include/effects/SkLayerDrawLooper.h b/include/effects/SkLayerDrawLooper.h
index 8627ae4..697d7b2 100644
--- a/include/effects/SkLayerDrawLooper.h
+++ b/include/effects/SkLayerDrawLooper.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkLayerDrawLooper_DEFINED
#define SkLayerDrawLooper_DEFINED
@@ -15,7 +22,8 @@ public:
* Bits specifies which aspects of the layer's paint should replace the
* corresponding aspects on the draw's paint.
* kEntirePaint_Bits means use the layer's paint completely.
- * 0 means ignore the layer's paint.
+ * 0 means ignore the layer's paint... except that LayerInfo's fFlagsMask
+ * and fColorMode are always applied.
*/
enum Bits {
kStyle_Bit = 1 << 0, //!< use this layer's Style/stroke settings
@@ -26,7 +34,15 @@ public:
kColorFilter_Bit = 1 << 5, //!< use this layer's colorfilter
kXfermode_Bit = 1 << 6, //!< use this layer's xfermode
- kEntirePaint_Bits = -1, //!< use this layer's paint entirely
+ /**
+ * Use the layer's paint entirely, with these exceptions:
+ * - We never override the draw's paint's text_encoding, since that is
+ * used to interpret the text/len parameters in draw[Pos]Text.
+ * - Flags and Color are always computed using the LayerInfo's
+ * fFlagsMask and fColorMode.
+ */
+ kEntirePaint_Bits = -1,
+
};
typedef int32_t BitFlags;
@@ -90,6 +106,8 @@ public:
return SkNEW_ARGS(SkLayerDrawLooper, (buffer));
}
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
+
protected:
SkLayerDrawLooper(SkFlattenableReadBuffer&);
diff --git a/include/effects/SkLayerRasterizer.h b/include/effects/SkLayerRasterizer.h
index 0373b05..91deb61 100644
--- a/include/effects/SkLayerRasterizer.h
+++ b/include/effects/SkLayerRasterizer.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkLayerRasterizer_DEFINED
#define SkLayerRasterizer_DEFINED
@@ -43,6 +36,10 @@ public:
virtual Factory getFactory();
virtual void flatten(SkFlattenableWriteBuffer&);
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
+
protected:
SkLayerRasterizer(SkFlattenableReadBuffer&);
@@ -53,8 +50,6 @@ protected:
private:
SkDeque fLayers;
-
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
typedef SkRasterizer INHERITED;
};
diff --git a/include/effects/SkPaintFlagsDrawFilter.h b/include/effects/SkPaintFlagsDrawFilter.h
index e4ec466..66a43cc 100644
--- a/include/effects/SkPaintFlagsDrawFilter.h
+++ b/include/effects/SkPaintFlagsDrawFilter.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPaintFlagsDrawFilter_DEFINED
#define SkPaintFlagsDrawFilter_DEFINED
diff --git a/include/effects/SkPixelXorXfermode.h b/include/effects/SkPixelXorXfermode.h
index 1957c9e..a7197ab 100644
--- a/include/effects/SkPixelXorXfermode.h
+++ b/include/effects/SkPixelXorXfermode.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2007 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPixelXorXfermode_DEFINED
#define SkPixelXorXfermode_DEFINED
@@ -36,6 +29,8 @@ public:
return SkNEW_ARGS(SkPixelXorXfermode, (buffer));
}
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
+
protected:
// override from SkXfermode
virtual SkPMColor xferColor(SkPMColor src, SkPMColor dst);
diff --git a/include/effects/SkPorterDuff.h b/include/effects/SkPorterDuff.h
index 54f81ea..44d94f8 100644
--- a/include/effects/SkPorterDuff.h
+++ b/include/effects/SkPorterDuff.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPorterDuff_DEFINED
#define SkPorterDuff_DEFINED
@@ -52,7 +45,7 @@ public:
kMultiply_Mode, //!< [Sa * Da, Sc * Dc]
kScreen_Mode, //!< [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc]
kAdd_Mode, //!< Saturate(S + D)
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
kOverlay_Mode,
#endif
diff --git a/include/effects/SkRectShape.h b/include/effects/SkRectShape.h
index 9b8cfc1..519398c 100644
--- a/include/effects/SkRectShape.h
+++ b/include/effects/SkRectShape.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkRectShape_DEFINED
#define SkRectShape_DEFINED
@@ -40,6 +47,8 @@ public:
// public for Registrar
static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
+
protected:
SkRectShape(SkFlattenableReadBuffer&);
diff --git a/include/effects/SkTableColorFilter.h b/include/effects/SkTableColorFilter.h
new file mode 100644
index 0000000..0aefdbd
--- /dev/null
+++ b/include/effects/SkTableColorFilter.h
@@ -0,0 +1,34 @@
+
+#ifndef SkTableColorFilter_DEFINED
+#define SkTableColorFilter_DEFINED
+
+#include "SkColorFilter.h"
+
+class SkTableColorFilter {
+public:
+ /**
+ * Create a table colorfilter, copying the table into the filter, and
+ * applying it to all 4 components.
+ * a' = table[a];
+ * r' = table[r];
+ * g' = table[g];
+ * b' = table[b];
+ * Compoents are operated on in unpremultiplied space. If the incomming
+ * colors are premultiplied, they are temporarily unpremultiplied, then
+ * the table is applied, and then the result is remultiplied.
+ */
+ static SkColorFilter* Create(const uint8_t table[256]);
+
+ /**
+ * Create a table colorfilter, with a different table for each
+ * component [A, R, G, B]. If a given table is NULL, then it is
+ * treated as identity, with the component left unchanged. If a table
+ * is not null, then its contents are copied into the filter.
+ */
+ static SkColorFilter* CreateARGB(const uint8_t tableA[256],
+ const uint8_t tableR[256],
+ const uint8_t tableG[256],
+ const uint8_t tableB[256]);
+};
+
+#endif
diff --git a/include/effects/SkTableMaskFilter.h b/include/effects/SkTableMaskFilter.h
index a57053d..f213de7 100644
--- a/include/effects/SkTableMaskFilter.h
+++ b/include/effects/SkTableMaskFilter.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTableMaskFilter_DEFINED
#define SkTableMaskFilter_DEFINED
diff --git a/include/effects/SkTestImageFilters.h b/include/effects/SkTestImageFilters.h
new file mode 100755
index 0000000..db020ad
--- /dev/null
+++ b/include/effects/SkTestImageFilters.h
@@ -0,0 +1,157 @@
+
+#ifndef _SkTestImageFilters_h
+#define _SkTestImageFilters_h
+
+#include "SkImageFilter.h"
+
+class SkOffsetImageFilter : public SkImageFilter {
+public:
+ SkOffsetImageFilter(SkScalar dx, SkScalar dy) {
+ fOffset.set(dx, dy);
+ }
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkOffsetImageFilter, (buffer));
+ }
+
+protected:
+ SkOffsetImageFilter(SkFlattenableReadBuffer& buffer);
+
+ virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
+ SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
+ virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE;
+ // overrides from SkFlattenable
+ virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+ virtual Factory getFactory() SK_OVERRIDE;
+
+private:
+ SkVector fOffset;
+
+ typedef SkImageFilter INHERITED;
+};
+
+class SkComposeImageFilter : public SkImageFilter {
+public:
+ SkComposeImageFilter(SkImageFilter* outer, SkImageFilter* inner) {
+ fOuter = outer;
+ fInner = inner;
+ SkSafeRef(outer);
+ SkSafeRef(inner);
+ }
+ virtual ~SkComposeImageFilter();
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkComposeImageFilter, (buffer));
+ }
+
+protected:
+ SkComposeImageFilter(SkFlattenableReadBuffer& buffer);
+
+ virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
+ SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
+ virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE;
+ // overrides from SkFlattenable
+ virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+ virtual Factory getFactory() SK_OVERRIDE;
+
+private:
+ SkImageFilter* fOuter;
+ SkImageFilter* fInner;
+
+ typedef SkImageFilter INHERITED;
+};
+
+#include "SkXfermode.h"
+
+class SkMergeImageFilter : public SkImageFilter {
+public:
+ SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
+ SkXfermode::Mode = SkXfermode::kSrcOver_Mode);
+ SkMergeImageFilter(SkImageFilter* const filters[], int count,
+ const SkXfermode::Mode modes[] = NULL);
+ virtual ~SkMergeImageFilter();
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkMergeImageFilter, (buffer));
+ }
+
+protected:
+ SkMergeImageFilter(SkFlattenableReadBuffer& buffer);
+
+ virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
+ SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
+ virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE;
+ // overrides from SkFlattenable
+ virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+ virtual Factory getFactory() SK_OVERRIDE;
+
+private:
+ SkImageFilter** fFilters;
+ uint8_t* fModes; // SkXfermode::Mode
+ int fCount;
+
+ // private storage, to avoid dynamically allocating storage for our copy
+ // of the filters and modes (unless fCount is so large we can't fit).
+ intptr_t fStorage[16];
+
+ void initAlloc(int count, bool hasModes);
+ void init(SkImageFilter* const [], int count, const SkXfermode::Mode []);
+
+ typedef SkImageFilter INHERITED;
+};
+
+class SkColorFilter;
+
+class SkColorFilterImageFilter : public SkImageFilter {
+public:
+ SkColorFilterImageFilter(SkColorFilter* cf) : fColorFilter(cf) {
+ SkSafeRef(cf);
+ }
+ virtual ~SkColorFilterImageFilter();
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkColorFilterImageFilter, (buffer));
+ }
+
+protected:
+ SkColorFilterImageFilter(SkFlattenableReadBuffer& buffer);
+
+ virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
+ SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
+ // overrides from SkFlattenable
+ virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+ virtual Factory getFactory() SK_OVERRIDE;
+
+private:
+ SkColorFilter* fColorFilter;
+
+ typedef SkImageFilter INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+// Fun mode that scales down (only) and then scales back up to look pixelated
+class SkDownSampleImageFilter : public SkImageFilter {
+public:
+ SkDownSampleImageFilter(SkScalar scale) : fScale(scale) {}
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkDownSampleImageFilter, (buffer));
+ }
+
+protected:
+ SkDownSampleImageFilter(SkFlattenableReadBuffer& buffer);
+
+ virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
+ SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
+ // overrides from SkFlattenable
+ virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+ virtual Factory getFactory() SK_OVERRIDE;
+
+private:
+ SkScalar fScale;
+
+ typedef SkImageFilter INHERITED;
+};
+
+#endif
diff --git a/include/effects/SkTransparentShader.h b/include/effects/SkTransparentShader.h
index 5e87609..e951bba 100644
--- a/include/effects/SkTransparentShader.h
+++ b/include/effects/SkTransparentShader.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTransparentShader_DEFINED
#define SkTransparentShader_DEFINED
@@ -22,19 +15,18 @@
class SkTransparentShader : public SkShader {
public:
SkTransparentShader() {}
- virtual uint32_t getFlags();
+
+ virtual uint32_t getFlags() SK_OVERRIDE;
virtual bool setContext( const SkBitmap& device,
const SkPaint& paint,
- const SkMatrix& matrix);
- virtual void shadeSpan(int x, int y, SkPMColor[], int count);
- virtual void shadeSpan16(int x, int y, uint16_t span[], int count);
+ const SkMatrix& matrix) SK_OVERRIDE;
+ virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t span[], int count) SK_OVERRIDE;
// overrides for SkFlattenable
- virtual Factory getFactory() { return Create; }
- virtual void flatten(SkFlattenableWriteBuffer& buffer) {
- this->INHERITED::flatten(buffer);
- }
-
+ virtual Factory getFactory() SK_OVERRIDE;
+ virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+
private:
// these are a cache from the call to setContext()
const SkBitmap* fDevice;
diff --git a/gpu/include/GrClip.h b/include/gpu/GrClip.h
index 717dfe6..d86eb97 100644
--- a/gpu/include/GrClip.h
+++ b/include/gpu/GrClip.h
@@ -1,29 +1,22 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrClip_DEFINED
#define GrClip_DEFINED
#include "GrClipIterator.h"
#include "GrRect.h"
#include "GrPath.h"
-#include "GrTArray.h"
#include "GrTemplates.h"
+#include "SkTArray.h"
class GrClip {
public:
@@ -68,7 +61,9 @@ public:
GrSetOp getOp(int i) const { return fList[i].fOp; }
bool isRect() const {
- if (1 == fList.count() && kRect_ClipType == fList[0].fType) {
+ if (1 == fList.count() && kRect_ClipType == fList[0].fType &&
+ (kIntersect_SetOp == fList[0].fOp ||
+ kReplace_SetOp == fList[0].fOp)) {
// if we determined that the clip is a single rect
// we ought to have also used that rect as the bounds.
GrAssert(fConservativeBoundsValid);
@@ -124,7 +119,6 @@ private:
switch (fType) {
case kRect_ClipType:
return fRect == e.fRect;
- break;
case kPath_ClipType:
return fPath == e.fPath;
default:
@@ -141,8 +135,7 @@ private:
enum {
kPreAllocElements = 4,
};
- GrAlignedSTStorage<kPreAllocElements, Element> fListStorage;
- GrTArray<Element> fList;
+ SkSTArray<kPreAllocElements, Element> fList;
};
#endif
diff --git a/gpu/include/GrClipIterator.h b/include/gpu/GrClipIterator.h
index f7f74a7..4a5cc71 100644
--- a/gpu/include/GrClipIterator.h
+++ b/include/gpu/GrClipIterator.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrClipIterator_DEFINED
#define GrClipIterator_DEFINED
diff --git a/gpu/include/GrColor.h b/include/gpu/GrColor.h
index 8dc03d2..ed666de 100644
--- a/gpu/include/GrColor.h
+++ b/include/gpu/GrColor.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrColor_DEFINED
#define GrColor_DEFINED
@@ -26,15 +19,12 @@
*/
typedef uint32_t GrColor;
-// indices for address a GrColor as an array of bytes
-
-#define GrColor_INDEX_R 0
-#define GrColor_INDEX_G 1
-#define GrColor_INDEX_B 2
-#define GrColor_INDEX_A 3
-
-// shfit amount to assign a component to a GrColor int
+// shift amount to assign a component to a GrColor int
+// These shift values are chosen for compatibility with GL attrib arrays
+// ES doesn't allow BGRA vertex attrib order so if they were not in this order
+// we'd have to swizzle in shaders. Note the assumption that the cpu is little
+// endian.
#define GrColor_SHIFT_R 0
#define GrColor_SHIFT_G 8
#define GrColor_SHIFT_B 16
diff --git a/gpu/include/GrConfig.h b/include/gpu/GrConfig.h
index 9ee37c7..72b9748 100644
--- a/gpu/include/GrConfig.h
+++ b/include/gpu/GrConfig.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrConfig_DEFINED
#define GrConfig_DEFINED
@@ -68,7 +61,7 @@
#undef GR_IOS_BUILD
#define GR_IOS_BUILD 1
// #error "IOS"
- #elif (defined(ANDROID_NDK) && ANDROID_NDK) || defined(ANDROID)
+ #elif defined(SK_BUILD_FOR_ANDROID)
#undef GR_ANDROID_BUILD
#define GR_ANDROID_BUILD 1
// #error "ANDROID"
@@ -227,12 +220,12 @@ extern GR_API void GrPrintf(const char format[], ...);
*/
#if !defined(GR_ALWAYSBREAK)
#if GR_WIN32_BUILD
- #define GR_ALWAYSBREAK __debugbreak()
+ #define GR_ALWAYSBREAK SkNO_RETURN_HINT(); __debugbreak()
#else
// TODO: do other platforms really not have continuable breakpoints?
// sign extend for 64bit architectures to be sure this is
// in the high address range
- #define GR_ALWAYSBREAK *((int*)(int64_t)(int32_t)0xbeefcafe) = 0;
+ #define GR_ALWAYSBREAK SkNO_RETURN_HINT(); *((int*)(int64_t)(int32_t)0xbeefcafe) = 0;
#endif
#endif
@@ -358,19 +351,36 @@ inline void GrCrash(const char* msg) { GrPrintf(msg); GrAlwaysAssert(false); }
* program.
*/
#if !defined(GR_AGGRESSIVE_SHADER_OPTS)
- #define GR_AGGRESSIVE_SHADER_OPTS 0
+ #define GR_AGGRESSIVE_SHADER_OPTS 1
#endif
/**
* GR_GEOM_BUFFER_LOCK_THRESHOLD gives a threshold (in bytes) for when Gr should
- * lock a GrGeometryBuffer to update its contents. It will use Lock() if the
- * size of the udpated region is greater than the threshold. Otherwise it will
- * use updateData() or updateSubData().
+ * lock a GrGeometryBuffer to update its contents. It will use lock() if the
+ * size of the updated region is greater than the threshold. Otherwise it will
+ * use updateData().
*/
#if !defined(GR_GEOM_BUFFER_LOCK_THRESHOLD)
#define GR_GEOM_BUFFER_LOCK_THRESHOLD (1 << 15)
#endif
+/**
+ * Enables/disables use of offscreen AA
+ */
+#if !defined(GR_USE_OFFSCREEN_AA)
+ #define GR_USE_OFFSCREEN_AA 1
+#endif
+
+/**
+ * GR_MAX_OFFSCREEN_AA_SIZE controls the size at which offscreen AA will tile.
+ * Tiling saves GPU memory by limiting the size of the offscreen buffer. The
+ * max offscreen may be as large as (4*GR_MAX_OFFSCREEN_AA_SIZE)^2 pixels.
+ */
+#if !defined(GR_MAX_OFFSCREEN_AA_SIZE)
+ #define GR_MAX_OFFSCREEN_AA_SIZE 256
+#endif
+
+
///////////////////////////////////////////////////////////////////////////////
// tail section:
//
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
new file mode 100644
index 0000000..0308b5d
--- /dev/null
+++ b/include/gpu/GrContext.h
@@ -0,0 +1,881 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrContext_DEFINED
+#define GrContext_DEFINED
+
+#include "GrClip.h"
+#include "GrPaint.h"
+// not strictly needed but requires WK change in LayerTextureUpdaterCanvas to
+// remove.
+#include "GrRenderTarget.h"
+
+class GrDrawTarget;
+class GrFontCache;
+class GrGpu;
+struct GrGpuStats;
+class GrIndexBuffer;
+class GrIndexBufferAllocPool;
+class GrInOrderDrawBuffer;
+class GrPathRenderer;
+class GrPathRendererChain;
+class GrResourceEntry;
+class GrResourceCache;
+class GrStencilBuffer;
+class GrVertexBuffer;
+class GrVertexBufferAllocPool;
+
+class GR_API GrContext : public GrRefCnt {
+public:
+ /**
+ * Creates a GrContext from within a 3D context.
+ */
+ static GrContext* Create(GrEngine engine,
+ GrPlatform3DContext context3D);
+
+ virtual ~GrContext();
+
+ /**
+ * The GrContext normally assumes that no outsider is setting state
+ * within the underlying 3D API's context/device/whatever. This call informs
+ * the context that the state was modified and it should resend. Shouldn't
+ * be called frequently for good performance.
+ */
+ void resetContext();
+
+ /**
+ * Abandons all gpu resources, assumes 3D API state is unknown. Call this
+ * if you have lost the associated GPU context, and thus internal texture,
+ * buffer, etc. references/IDs are now invalid. Should be called even when
+ * GrContext is no longer going to be used for two reasons:
+ * 1) ~GrContext will not try to free the objects in the 3D API.
+ * 2) If you've created GrResources that outlive the GrContext they will
+ * be marked as invalid (GrResource::isValid()) and won't attempt to
+ * free their underlying resource in the 3D API.
+ * Content drawn since the last GrContext::flush() may be lost.
+ */
+ void contextLost();
+
+ /**
+ * Similar to contextLost, but makes no attempt to reset state.
+ * Use this method when GrContext destruction is pending, but
+ * the graphics context is destroyed first.
+ */
+ void contextDestroyed();
+
+ /**
+ * Frees gpu created by the context. Can be called to reduce GPU memory
+ * pressure.
+ */
+ void freeGpuResources();
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Textures
+
+ /**
+ * Token that refers to an entry in the texture cache. Returned by
+ * functions that lock textures. Passed to unlockTexture.
+ */
+ class TextureCacheEntry {
+ public:
+ TextureCacheEntry() : fEntry(NULL) {}
+ TextureCacheEntry(const TextureCacheEntry& e) : fEntry(e.fEntry) {}
+ TextureCacheEntry& operator= (const TextureCacheEntry& e) {
+ fEntry = e.fEntry;
+ return *this;
+ }
+ GrTexture* texture() const;
+ void reset() { fEntry = NULL; }
+ private:
+ explicit TextureCacheEntry(GrResourceEntry* entry) { fEntry = entry; }
+ void set(GrResourceEntry* entry) { fEntry = entry; }
+ GrResourceEntry* cacheEntry() { return fEntry; }
+ GrResourceEntry* fEntry;
+ friend class GrContext;
+ };
+
+ /**
+ * Key generated by client. Should be a unique key on the texture data.
+ * Does not need to consider that width and height of the texture. Two
+ * textures with the same TextureKey but different bounds will not collide.
+ */
+ typedef uint64_t TextureKey;
+
+ /**
+ * Create a new entry, based on the specified key and texture, and return
+ * its "locked" entry. Must call be balanced with an unlockTexture() call.
+ *
+ * @param key A client-generated key that identifies the contents
+ * of the texture. Respecified to findAndLockTexture
+ * for subsequent uses of the texture.
+ * @param sampler The sampler state used to draw a texture may be used
+ * to determine how to store the pixel data in the texture
+ * cache. (e.g. different versions may exist for different
+ * wrap modes on GPUs with limited or no NPOT texture
+ * support). Only the wrap and filter fields are used. NULL
+ * implies clamp wrap modes and nearest filtering.
+ * @param desc Description of the texture properties.
+ * @param srcData Pointer to the pixel values.
+ * @param rowBytes The number of bytes between rows of the texture. Zero
+ * implies tightly packed rows.
+ */
+ TextureCacheEntry createAndLockTexture(TextureKey key,
+ const GrSamplerState* sampler,
+ const GrTextureDesc& desc,
+ void* srcData, size_t rowBytes);
+
+ /**
+ * Search for an entry based on key and dimensions. If found, "lock" it and
+ * return it. The entry's texture() function will return NULL if not found.
+ * Must be balanced with an unlockTexture() call.
+ *
+ * @param key A client-generated key that identifies the contents
+ * of the texture.
+ * @param width The width of the texture in pixels as specifed in
+ * the GrTextureDesc originally passed to
+ * createAndLockTexture
+ * @param width The height of the texture in pixels as specifed in
+ * the GrTextureDesc originally passed to
+ * createAndLockTexture
+ * @param sampler The sampler state used to draw a texture may be used
+ * to determine the cache entry used. (e.g. different
+ * versions may exist for different wrap modes on GPUs with
+ * limited or no NPOT texture support). Only the wrap and
+ * filter fields are used. NULL implies clamp wrap modes
+ * and nearest filtering.
+ */
+ TextureCacheEntry findAndLockTexture(TextureKey key,
+ int width,
+ int height,
+ const GrSamplerState* sampler);
+ /**
+ * Determines whether a texture is in the cache. If the texture is found it
+ * will not be locked or returned. This call does not affect the priority of
+ * the texture for deletion.
+ */
+ bool isTextureInCache(TextureKey key,
+ int width,
+ int height,
+ const GrSamplerState*) const;
+
+ /**
+ * Enum that determines how closely a returned scratch texture must match
+ * a provided GrTextureDesc.
+ */
+ enum ScratchTexMatch {
+ /**
+ * Finds a texture that exactly matches the descriptor.
+ */
+ kExact_ScratchTexMatch,
+ /**
+ * Finds a texture that approximately matches the descriptor. Will be
+ * at least as large in width and height as desc specifies. If desc
+ * specifies that texture is a render target then result will be a
+ * render target. If desc specifies a render target and doesn't set the
+ * no stencil flag then result will have a stencil. Format and aa level
+ * will always match.
+ */
+ kApprox_ScratchTexMatch
+ };
+
+ /**
+ * Returns a texture matching the desc. It's contents are unknown. Subsequent
+ * requests with the same descriptor are not guaranteed to return the same
+ * texture. The same texture is guaranteed not be returned again until it is
+ * unlocked. Must call be balanced with an unlockTexture() call.
+ *
+ * Textures created by createAndLockTexture() hide the complications of
+ * tiling non-power-of-two textures on APIs that don't support this (e.g.
+ * unextended GLES2). Tiling a npot texture created by lockScratchTexture on
+ * such an API will create gaps in the tiling pattern. This includes clamp
+ * mode. (This may be addressed in a future update.)
+ */
+ TextureCacheEntry lockScratchTexture(const GrTextureDesc& desc, ScratchTexMatch match);
+
+ /**
+ * When done with an entry, call unlockTexture(entry) on it, which returns
+ * it to the cache, where it may be purged.
+ */
+ void unlockTexture(TextureCacheEntry entry);
+
+ /**
+ * Creates a texture that is outside the cache. Does not count against
+ * cache's budget.
+ */
+ GrTexture* createUncachedTexture(const GrTextureDesc&,
+ void* srcData,
+ size_t rowBytes);
+
+ /**
+ * Returns true if the specified use of an indexed texture is supported.
+ */
+ bool supportsIndex8PixelConfig(const GrSamplerState*,
+ int width,
+ int height) const;
+
+ /**
+ * Return the current texture cache limits.
+ *
+ * @param maxTextures If non-null, returns maximum number of textures that
+ * can be held in the cache.
+ * @param maxTextureBytes If non-null, returns maximum number of bytes of
+ * texture memory that can be held in the cache.
+ */
+ void getTextureCacheLimits(int* maxTextures, size_t* maxTextureBytes) const;
+
+ /**
+ * Specify the texture cache limits. If the current cache exceeds either
+ * of these, it will be purged (LRU) to keep the cache within these limits.
+ *
+ * @param maxTextures The maximum number of textures that can be held in
+ * the cache.
+ * @param maxTextureBytes The maximum number of bytes of texture memory
+ * that can be held in the cache.
+ */
+ void setTextureCacheLimits(int maxTextures, size_t maxTextureBytes);
+
+ /**
+ * Return the max width or height of a texture supported by the current gpu
+ */
+ int getMaxTextureSize() const;
+
+ /**
+ * Return the max width or height of a render target supported by the
+ * current gpu
+ */
+ int getMaxRenderTargetSize() const;
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Render targets
+
+ /**
+ * Sets the render target.
+ * @param target the render target to set. (should not be NULL.)
+ */
+ void setRenderTarget(GrRenderTarget* target);
+
+ /**
+ * Gets the current render target.
+ * @return the currently bound render target. Should never be NULL.
+ */
+ const GrRenderTarget* getRenderTarget() const;
+ GrRenderTarget* getRenderTarget();
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Platform Surfaces
+
+ /**
+ * Wraps an existing texture with a GrTexture object.
+ *
+ * OpenGL: if the object is a texture Gr may change its GL texture params
+ * when it is drawn.
+ *
+ * @param desc description of the object to create.
+ *
+ * @return GrTexture object or NULL on failure.
+ */
+ GrTexture* createPlatformTexture(const GrPlatformTextureDesc& desc);
+
+ /**
+ * Wraps an existing render target with a GrRenderTarget object. It is
+ * similar to createPlatformTexture but can be used to draw into surfaces
+ * that are not also textures (e.g. FBO 0 in OpenGL, or an MSAA buffer that
+ * the client will resolve to a texture).
+ *
+ * @param desc description of the object to create.
+ *
+ * @return GrTexture object or NULL on failure.
+ */
+ GrRenderTarget* createPlatformRenderTarget(
+ const GrPlatformRenderTargetDesc& desc);
+
+ /**
+ * This interface is depracted and will be removed in a future revision.
+ * Callers should use createPlatformTexture or createPlatformRenderTarget
+ * instead.
+ *
+ * Wraps an existing 3D API surface in a GrObject. desc.fFlags determines
+ * the type of object returned. If kIsTexture is set the returned object
+ * will be a GrTexture*. Otherwise, it will be a GrRenderTarget*. If both
+ * are set the render target object is accessible by
+ * GrTexture::asRenderTarget().
+ *
+ * GL: if the object is a texture Gr may change its GL texture parameters
+ * when it is drawn.
+ *
+ * @param desc description of the object to create.
+ * @return either a GrTexture* or GrRenderTarget* depending on desc. NULL
+ * on failure.
+ */
+ GrResource* createPlatformSurface(const GrPlatformSurfaceDesc& desc);
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Matrix state
+
+ /**
+ * Gets the current transformation matrix.
+ * @return the current matrix.
+ */
+ const GrMatrix& getMatrix() const;
+
+ /**
+ * Sets the transformation matrix.
+ * @param m the matrix to set.
+ */
+ void setMatrix(const GrMatrix& m);
+
+ /**
+ * Concats the current matrix. The passed matrix is applied before the
+ * current matrix.
+ * @param m the matrix to concat.
+ */
+ void concatMatrix(const GrMatrix& m) const;
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Clip state
+ /**
+ * Gets the current clip.
+ * @return the current clip.
+ */
+ const GrClip& getClip() const;
+
+ /**
+ * Sets the clip.
+ * @param clip the clip to set.
+ */
+ void setClip(const GrClip& clip);
+
+ /**
+ * Convenience method for setting the clip to a rect.
+ * @param rect the rect to set as the new clip.
+ */
+ void setClip(const GrIRect& rect);
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Draws
+
+ /**
+ * Clear the entire or rect of the render target, ignoring any clips.
+ * @param rect the rect to clear or the whole thing if rect is NULL.
+ * @param color the color to clear to.
+ */
+ void clear(const GrIRect* rect, GrColor color);
+
+ /**
+ * Draw everywhere (respecting the clip) with the paint.
+ */
+ void drawPaint(const GrPaint& paint);
+
+ /**
+ * Draw the rect using a paint.
+ * @param paint describes how to color pixels.
+ * @param strokeWidth If strokeWidth < 0, then the rect is filled, else
+ * the rect is mitered stroked based on strokeWidth. If
+ * strokeWidth == 0, then the stroke is always a single
+ * pixel thick.
+ * @param matrix Optional matrix applied to the rect. Applied before
+ * context's matrix or the paint's matrix.
+ * The rects coords are used to access the paint (through texture matrix)
+ */
+ void drawRect(const GrPaint& paint,
+ const GrRect&,
+ GrScalar strokeWidth = -1,
+ const GrMatrix* matrix = NULL);
+
+ /**
+ * Maps a rect of paint coordinates onto the a rect of destination
+ * coordinates. Each rect can optionally be transformed. The srcRect
+ * is stretched over the dstRect. The dstRect is transformed by the
+ * context's matrix and the srcRect is transformed by the paint's matrix.
+ * Additional optional matrices can be provided by parameters.
+ *
+ * @param paint describes how to color pixels.
+ * @param dstRect the destination rect to draw.
+ * @param srcRect rect of paint coordinates to be mapped onto dstRect
+ * @param dstMatrix Optional matrix to transform dstRect. Applied before
+ * context's matrix.
+ * @param srcMatrix Optional matrix to transform srcRect Applied before
+ * paint's matrix.
+ */
+ void drawRectToRect(const GrPaint& paint,
+ const GrRect& dstRect,
+ const GrRect& srcRect,
+ const GrMatrix* dstMatrix = NULL,
+ const GrMatrix* srcMatrix = NULL);
+
+ /**
+ * Draws a path.
+ *
+ * @param paint describes how to color pixels.
+ * @param path the path to draw
+ * @param fill the path filling rule to use.
+ * @param translate optional additional translation applied to the
+ * path.
+ */
+ void drawPath(const GrPaint& paint, const GrPath& path, GrPathFill fill,
+ const GrPoint* translate = NULL);
+
+ /**
+ * Draws vertices with a paint.
+ *
+ * @param paint describes how to color pixels.
+ * @param primitiveType primitives type to draw.
+ * @param vertexCount number of vertices.
+ * @param positions array of vertex positions, required.
+ * @param texCoords optional array of texture coordinates used
+ * to access the paint.
+ * @param colors optional array of per-vertex colors, supercedes
+ * the paint's color field.
+ * @param indices optional array of indices. If NULL vertices
+ * are drawn non-indexed.
+ * @param indexCount if indices is non-null then this is the
+ * number of indices.
+ */
+ void drawVertices(const GrPaint& paint,
+ GrPrimitiveType primitiveType,
+ int vertexCount,
+ const GrPoint positions[],
+ const GrPoint texs[],
+ const GrColor colors[],
+ const uint16_t indices[],
+ int indexCount);
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Misc.
+
+ /**
+ * Flags that affect flush() behavior.
+ */
+ enum FlushBits {
+ /**
+ * A client may want Gr to bind a GrRenderTarget in the 3D API so that
+ * it can be rendered to directly. However, Gr lazily sets state. Simply
+ * calling setRenderTarget() followed by flush() without flags may not
+ * bind the render target. This flag forces the context to bind the last
+ * set render target in the 3D API.
+ */
+ kForceCurrentRenderTarget_FlushBit = 0x1,
+ /**
+ * A client may reach a point where it has partially rendered a frame
+ * through a GrContext that it knows the user will never see. This flag
+ * causes the flush to skip submission of deferred content to the 3D API
+ * during the flush.
+ */
+ kDiscard_FlushBit = 0x2,
+ };
+
+ /**
+ * Call to ensure all drawing to the context has been issued to the
+ * underlying 3D API.
+ * @param flagsBitfield flags that control the flushing behavior. See
+ * FlushBits.
+ */
+ void flush(int flagsBitfield = 0);
+
+ /**
+ * Reads a rectangle of pixels from a render target.
+ * @param target the render target to read from. NULL means the
+ * current render target.
+ * @param left left edge of the rectangle to read (inclusive)
+ * @param top top edge of the rectangle to read (inclusive)
+ * @param width width of rectangle to read in pixels.
+ * @param height height of rectangle to read in pixels.
+ * @param config the pixel config of the destination buffer
+ * @param buffer memory to read the rectangle into.
+ * @param rowBytes number of bytes bewtween consecutive rows. Zero
+ * means rows are tightly packed.
+ *
+ * @return true if the read succeeded, false if not. The read can fail
+ * because of an unsupported pixel config or because no render
+ * target is currently set.
+ */
+ bool readRenderTargetPixels(GrRenderTarget* target,
+ int left, int top, int width, int height,
+ GrPixelConfig config, void* buffer,
+ size_t rowBytes) {
+ return this->internalReadRenderTargetPixels(target, left, top,
+ width, height,
+ config, buffer,
+ rowBytes, 0);
+ }
+
+ /**
+ * Copy the src pixels [buffer, rowbytes, pixelconfig] into a render target
+ * at the specified rectangle.
+ * @param target the render target to write into. NULL means the
+ * current render target.
+ * @param left left edge of the rectangle to write (inclusive)
+ * @param top top edge of the rectangle to write (inclusive)
+ * @param width width of rectangle to write in pixels.
+ * @param height height of rectangle to write in pixels.
+ * @param config the pixel config of the source buffer
+ * @param buffer memory to read the rectangle from.
+ * @param rowBytes number of bytes bewtween consecutive rows. Zero
+ * means rows are tightly packed.
+ */
+ void writeRenderTargetPixels(GrRenderTarget* target,
+ int left, int top, int width, int height,
+ GrPixelConfig config, const void* buffer,
+ size_t rowBytes) {
+ this->internalWriteRenderTargetPixels(target, left, top, width, height,
+ config, buffer, rowBytes, 0);
+ }
+
+ /**
+ * Reads a rectangle of pixels from a texture.
+ * @param texture the texture to read from.
+ * @param left left edge of the rectangle to read (inclusive)
+ * @param top top edge of the rectangle to read (inclusive)
+ * @param width width of rectangle to read in pixels.
+ * @param height height of rectangle to read in pixels.
+ * @param config the pixel config of the destination buffer
+ * @param buffer memory to read the rectangle into.
+ * @param rowBytes number of bytes bewtween consecutive rows. Zero
+ * means rows are tightly packed.
+ *
+ * @return true if the read succeeded, false if not. The read can fail
+ * because of an unsupported pixel config.
+ */
+ bool readTexturePixels(GrTexture* texture,
+ int left, int top, int width, int height,
+ GrPixelConfig config, void* buffer,
+ size_t rowBytes) {
+ return this->internalReadTexturePixels(texture, left, top,
+ width, height,
+ config, buffer, rowBytes, 0);
+ }
+
+ /**
+ * Writes a rectangle of pixels to a texture.
+ * @param texture the render target to read from.
+ * @param left left edge of the rectangle to write (inclusive)
+ * @param top top edge of the rectangle to write (inclusive)
+ * @param width width of rectangle to write in pixels.
+ * @param height height of rectangle to write in pixels.
+ * @param config the pixel config of the source buffer
+ * @param buffer memory to read pixels from
+ * @param rowBytes number of bytes bewtween consecutive rows. Zero
+ * means rows are tightly packed.
+ */
+ void writeTexturePixels(GrTexture* texture,
+ int left, int top, int width, int height,
+ GrPixelConfig config, const void* buffer,
+ size_t rowBytes) {
+ this->internalWriteTexturePixels(texture, left, top, width, height,
+ config, buffer, rowBytes, 0);
+ }
+ /**
+ * Copies all texels from one texture to another.
+ * @param src the texture to copy from.
+ * @param dst the render target to copy to.
+ */
+ void copyTexture(GrTexture* src, GrRenderTarget* dst);
+ /**
+ * Applies a 1D convolution kernel in the X direction to a rectangle of
+ * pixels from a given texture.
+ * @param texture the texture to read from
+ * @param rect the destination rectangle
+ * @param kernel the convolution kernel (kernelWidth elements)
+ * @param kernelWidth the width of the convolution kernel
+ */
+ void convolveInX(GrTexture* texture,
+ const SkRect& rect,
+ const float* kernel,
+ int kernelWidth);
+ /**
+ * Applies a 1D convolution kernel in the Y direction to a rectangle of
+ * pixels from a given texture.
+ * direction.
+ * @param texture the texture to read from
+ * @param rect the destination rectangle
+ * @param kernel the convolution kernel (kernelWidth elements)
+ * @param kernelWidth the width of the convolution kernel
+ */
+ void convolveInY(GrTexture* texture,
+ const SkRect& rect,
+ const float* kernel,
+ int kernelWidth);
+ ///////////////////////////////////////////////////////////////////////////
+ // Helpers
+
+ class AutoRenderTarget : ::GrNoncopyable {
+ public:
+ AutoRenderTarget(GrContext* context, GrRenderTarget* target) {
+ fContext = NULL;
+ fPrevTarget = context->getRenderTarget();
+ if (fPrevTarget != target) {
+ context->setRenderTarget(target);
+ fContext = context;
+ }
+ }
+ ~AutoRenderTarget() {
+ if (fContext) {
+ fContext->setRenderTarget(fPrevTarget);
+ }
+ }
+ private:
+ GrContext* fContext;
+ GrRenderTarget* fPrevTarget;
+ };
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Functions intended for internal use only.
+ GrGpu* getGpu() { return fGpu; }
+ const GrGpu* getGpu() const { return fGpu; }
+ GrFontCache* getFontCache() { return fFontCache; }
+ GrDrawTarget* getTextTarget(const GrPaint& paint);
+ void flushText();
+ const GrIndexBuffer* getQuadIndexBuffer() const;
+ void resetStats();
+ const GrGpuStats& getStats() const;
+ void printStats() const;
+ /**
+ * Stencil buffers add themselves to the cache using
+ * addAndLockStencilBuffer. When a SB's RT-attachment count
+ * reaches zero the SB unlocks itself using unlockStencilBuffer and is
+ * eligible for purging. findStencilBuffer is called to check the cache for
+ * a SB that matching an RT's criteria. If a match is found that has been
+ * unlocked (its attachment count has reached 0) then it will be relocked.
+ */
+ GrResourceEntry* addAndLockStencilBuffer(GrStencilBuffer* sb);
+ void unlockStencilBuffer(GrResourceEntry* sbEntry);
+ GrStencilBuffer* findStencilBuffer(int width, int height, int sampleCnt);
+
+private:
+ // used to keep track of when we need to flush the draw buffer
+ enum DrawCategory {
+ kBuffered_DrawCategory, // last draw was inserted in draw buffer
+ kUnbuffered_DrawCategory, // last draw was not inserted in the draw buffer
+ kText_DrawCategory // text context was last to draw
+ };
+ DrawCategory fLastDrawCategory;
+
+ GrGpu* fGpu;
+ GrResourceCache* fTextureCache;
+ GrFontCache* fFontCache;
+
+ GrPathRendererChain* fPathRendererChain;
+
+ GrVertexBufferAllocPool* fDrawBufferVBAllocPool;
+ GrIndexBufferAllocPool* fDrawBufferIBAllocPool;
+ GrInOrderDrawBuffer* fDrawBuffer;
+
+ GrIndexBuffer* fAAFillRectIndexBuffer;
+ GrIndexBuffer* fAAStrokeRectIndexBuffer;
+ int fMaxOffscreenAASize;
+
+ GrContext(GrGpu* gpu);
+
+ void fillAARect(GrDrawTarget* target,
+ const GrRect& devRect,
+ bool useVertexCoverage);
+
+ void strokeAARect(GrDrawTarget* target,
+ const GrRect& devRect,
+ const GrVec& devStrokeSize,
+ bool useVertexCoverage);
+
+ inline int aaFillRectIndexCount() const;
+ GrIndexBuffer* aaFillRectIndexBuffer();
+
+ inline int aaStrokeRectIndexCount() const;
+ GrIndexBuffer* aaStrokeRectIndexBuffer();
+
+ void setupDrawBuffer();
+
+ void flushDrawBuffer();
+
+ void setPaint(const GrPaint& paint, GrDrawTarget* target);
+
+ GrDrawTarget* prepareToDraw(const GrPaint& paint, DrawCategory drawType);
+
+ GrPathRenderer* getPathRenderer(const GrPath& path,
+ GrPathFill fill,
+ bool antiAlias);
+
+ struct OffscreenRecord;
+
+ // determines whether offscreen AA should be applied
+ bool doOffscreenAA(GrDrawTarget* target,
+ bool isHairLines) const;
+
+ // attempts to setup offscreen AA. All paint state must be transferred to
+ // target by the time this is called.
+ bool prepareForOffscreenAA(GrDrawTarget* target,
+ bool requireStencil,
+ const GrIRect& boundRect,
+ GrPathRenderer* pr,
+ OffscreenRecord* record);
+
+ // sets up target to draw coverage to the supersampled render target
+ void setupOffscreenAAPass1(GrDrawTarget* target,
+ const GrIRect& boundRect,
+ int tileX, int tileY,
+ OffscreenRecord* record);
+
+ // sets up target to sample coverage of supersampled render target back
+ // to the main render target using stage kOffscreenStage.
+ void doOffscreenAAPass2(GrDrawTarget* target,
+ const GrPaint& paint,
+ const GrIRect& boundRect,
+ int tileX, int tileY,
+ OffscreenRecord* record);
+
+ // restored the draw target state and releases offscreen target to cache
+ void cleanupOffscreenAA(GrDrawTarget* target,
+ GrPathRenderer* pr,
+ OffscreenRecord* record);
+
+ void convolve(GrTexture* texture,
+ const SkRect& rect,
+ float imageIncrement[2],
+ const float* kernel,
+ int kernelWidth);
+
+ /**
+ * Flags to the internal read/write pixels funcs
+ */
+ enum PixelOpsFlags {
+ kDontFlush_PixelOpsFlag = 0x1,
+ };
+
+ bool internalReadRenderTargetPixels(GrRenderTarget* target,
+ int left, int top,
+ int width, int height,
+ GrPixelConfig config, void* buffer,
+ size_t rowBytes, uint32_t flags);
+
+ void internalWriteRenderTargetPixels(GrRenderTarget* target,
+ int left, int top,
+ int width, int height,
+ GrPixelConfig, const void* buffer,
+ size_t rowBytes, uint32_t flags);
+
+ bool internalReadTexturePixels(GrTexture* texture,
+ int left, int top,
+ int width, int height,
+ GrPixelConfig config, void* buffer,
+ size_t rowBytes, uint32_t flags);
+
+ void internalWriteTexturePixels(GrTexture* texture,
+ int left, int top,
+ int width, int height,
+ GrPixelConfig config, const void* buffer,
+ size_t rowBytes, uint32_t flags);
+ // needed for access to internalWriteTexturePixels. TODO: make GrContext
+ // be a facade for an internal class. Then functions that are public on the
+ // internal class would have only be callable in src/gpu. The facade would
+ // only have to functions necessary for clients.
+ friend class GrAtlas;
+
+ // computes vertex layout bits based on the paint. If paint expresses
+ // a texture for a stage, the stage coords will be bound to postitions
+ // unless hasTexCoords[s]==true in which case stage s's input coords
+ // are bound to tex coord index s. hasTexCoords == NULL is a shortcut
+ // for an array where all the values are false.
+ static int PaintStageVertexLayoutBits(
+ const GrPaint& paint,
+ const bool hasTexCoords[GrPaint::kTotalStages]);
+
+};
+
+/**
+ * Save/restore the view-matrix in the context.
+ */
+class GrAutoMatrix : GrNoncopyable {
+public:
+ GrAutoMatrix() : fContext(NULL) {}
+ GrAutoMatrix(GrContext* ctx) : fContext(ctx) {
+ fMatrix = ctx->getMatrix();
+ }
+ GrAutoMatrix(GrContext* ctx, const GrMatrix& matrix) : fContext(ctx) {
+ fMatrix = ctx->getMatrix();
+ ctx->setMatrix(matrix);
+ }
+ void set(GrContext* ctx) {
+ if (NULL != fContext) {
+ fContext->setMatrix(fMatrix);
+ }
+ fMatrix = ctx->getMatrix();
+ fContext = ctx;
+ }
+ void set(GrContext* ctx, const GrMatrix& matrix) {
+ if (NULL != fContext) {
+ fContext->setMatrix(fMatrix);
+ }
+ fMatrix = ctx->getMatrix();
+ ctx->setMatrix(matrix);
+ fContext = ctx;
+ }
+ ~GrAutoMatrix() {
+ if (NULL != fContext) {
+ fContext->setMatrix(fMatrix);
+ }
+ }
+
+private:
+ GrContext* fContext;
+ GrMatrix fMatrix;
+};
+
+/**
+ * Gets and locks a scratch texture from a descriptor using
+ * either exact or approximate criteria. Unlocks texture in
+ * the destructor.
+ */
+class GrAutoScratchTexture : ::GrNoncopyable {
+public:
+ GrAutoScratchTexture()
+ : fContext(NULL) {
+ }
+
+ GrAutoScratchTexture(GrContext* context,
+ const GrTextureDesc& desc,
+ GrContext::ScratchTexMatch match =
+ GrContext::kApprox_ScratchTexMatch)
+ : fContext(NULL) {
+ this->set(context, desc, match);
+ }
+
+ ~GrAutoScratchTexture() {
+ if (NULL != fContext) {
+ fContext->unlockTexture(fEntry);
+ }
+ }
+
+ GrTexture* set(GrContext* context,
+ const GrTextureDesc& desc,
+ GrContext::ScratchTexMatch match =
+ GrContext::kApprox_ScratchTexMatch) {
+ if (NULL != fContext) {
+ fContext->unlockTexture(fEntry);
+ }
+ fContext = context;
+ if (NULL != fContext) {
+ fEntry = fContext->lockScratchTexture(desc, match);
+ GrTexture* ret = fEntry.texture();
+ if (NULL == ret) {
+ fContext = NULL;
+ }
+ return ret;
+ } else {
+ return NULL;
+ }
+ }
+
+ GrTexture* texture() { return fEntry.texture(); }
+private:
+ GrContext* fContext;
+ GrContext::TextureCacheEntry fEntry;
+};
+
+#endif
+
diff --git a/gpu/include/GrFontScaler.h b/include/gpu/GrFontScaler.h
index ab73ea4..657647d 100644
--- a/gpu/include/GrFontScaler.h
+++ b/include/gpu/GrFontScaler.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrFontScaler_DEFINED
#define GrFontScaler_DEFINED
diff --git a/include/gpu/GrGLConfig.h b/include/gpu/GrGLConfig.h
new file mode 100644
index 0000000..c9aaec5
--- /dev/null
+++ b/include/gpu/GrGLConfig.h
@@ -0,0 +1,252 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrGLConfig_DEFINED
+#define GrGLConfig_DEFINED
+
+#include "GrTypes.h"
+#include "GrGLDefines.h"
+
+/**
+ * Optional GL config file.
+ */
+#ifdef GR_GL_CUSTOM_SETUP_HEADER
+ #include GR_GL_CUSTOM_SETUP_HEADER
+#endif
+
+#if !defined(GR_GL_FUNCTION_TYPE)
+ #define GR_GL_FUNCTION_TYPE
+#endif
+
+/**
+ * The following are optional defines that can be enabled at the compiler
+ * command line, in a IDE project, in a GrUserConfig.h file, or in a GL custom
+ * file (if one is in use). If a GR_GL_CUSTOM_SETUP_HEADER is used they can
+ * also be placed there.
+ *
+ * GR_GL_LOG_CALLS: if 1 Gr can print every GL call using GrPrintf. Defaults to
+ * 0. Logging can be enabled and disabled at runtime using a debugger via to
+ * global gLogCallsGL. The initial value of gLogCallsGL is controlled by
+ * GR_GL_LOG_CALLS_START.
+ *
+ * GR_GL_LOG_CALLS_START: controls the initial value of gLogCallsGL when
+ * GR_GL_LOG_CALLS is 1. Defaults to 0.
+ *
+ * GR_GL_CHECK_ERROR: if enabled Gr can do a glGetError() after every GL call.
+ * Defaults to 1 if GR_DEBUG is set, otherwise 0. When GR_GL_CHECK_ERROR is 1
+ * this can be toggled in a debugger using the gCheckErrorGL global. The initial
+ * value of gCheckErrorGL is controlled by by GR_GL_CHECK_ERROR_START.
+ *
+ * GR_GL_CHECK_ERROR_START: controls the initial value of gCheckErrorGL
+ * when GR_GL_CHECK_ERROR is 1. Defaults to 1.
+ *
+ * GR_GL_NO_CONSTANT_ATTRIBUTES: if this evaluates to true then the GL backend
+ * will use uniforms instead of attributes in all cases when there is not
+ * per-vertex data. This is important when the underlying GL implementation
+ * doesn't actually support immediate style attribute values (e.g. when
+ * the GL stream is converted to DX as in ANGLE on Chrome). Defaults to 0.
+ *
+ * GR_GL_ATTRIBUTE_MATRICES: If changing uniforms is very expensive it may be
+ * faster to use vertex attributes for matrices (set via glVertexAttrib3fv).
+ * Setting this build flag enables this behavior. GR_GL_NO_CONSTANT_ATTRIBUTES
+ * must not be set since this uses constant attributes for the matrices.
+ * Defaults to 0.
+ *
+ * GR_GL_USE_BUFFER_DATA_NULL_HINT: When specifing new data for a vertex/index
+ * buffer that replaces old data Ganesh can give a hint to the driver that the
+ * previous data will not be used in future draws like this:
+ * glBufferData(GL_..._BUFFER, size, NULL, usage); //<--hint, NULL means
+ * glBufferSubData(GL_..._BUFFER, 0, lessThanSize, data) // old data can't be
+ * // used again.
+ * However, this can be an unoptimization on some platforms, esp. Chrome.
+ * Chrome's cmd buffer will create a new allocation and memset the whole thing
+ * to zero (for security reasons). Defaults to 1 (enabled).
+ *
+ * GR_GL_PER_GL_FUNC_CALLBACK: When set to 1 the GrGLInterface object provides
+ * a function pointer that is called just before every gl function. The ptr must
+ * be valid (i.e. there is no NULL check). However, by default the callback will
+ * be set to a function that does nothing. The signature of the function is:
+ * void function(const GrGLInterface*)
+ * It is not extern "C".
+ * The GrGLInterface field fCallback specifies the function ptr and there is an
+ * additional field fCallbackData of type intptr_t for client data.
+ *
+ * GR_GL_RGBA_8888_PIXEL_OPS_SLOW: Set this to 1 if it is known that performing
+ * glReadPixels / glTex(Sub)Image with format=GL_RGBA, type=GL_UNISIGNED_BYTE is
+ * significantly slower than format=GL_BGRA, type=GL_UNISIGNED_BYTE.
+ *
+ * GR_GL_FULL_READPIXELS_FASTER_THAN_PARTIAL: Set this to 1 if calling
+ * glReadPixels to read the entire framebuffer is faster than calling it with
+ * the same sized rectangle but with a framebuffer bound that is larger than
+ * the rectangle read.
+ */
+
+#if !defined(GR_GL_LOG_CALLS)
+ #define GR_GL_LOG_CALLS GR_DEBUG
+#endif
+
+#if !defined(GR_GL_LOG_CALLS_START)
+ #define GR_GL_LOG_CALLS_START 0
+#endif
+
+#if !defined(GR_GL_CHECK_ERROR)
+ #define GR_GL_CHECK_ERROR GR_DEBUG
+#endif
+
+#if !defined(GR_GL_CHECK_ERROR_START)
+ #define GR_GL_CHECK_ERROR_START 1
+#endif
+
+#if !defined(GR_GL_NO_CONSTANT_ATTRIBUTES)
+ #define GR_GL_NO_CONSTANT_ATTRIBUTES 0
+#endif
+
+#if !defined(GR_GL_ATTRIBUTE_MATRICES)
+ #define GR_GL_ATTRIBUTE_MATRICES 0
+#endif
+
+#if !defined(GR_GL_USE_BUFFER_DATA_NULL_HINT)
+ #define GR_GL_USE_BUFFER_DATA_NULL_HINT 1
+#endif
+
+#if !defined(GR_GL_PER_GL_FUNC_CALLBACK)
+ #define GR_GL_PER_GL_FUNC_CALLBACK 0
+#endif
+
+#if !defined(GR_GL_RGBA_8888_PIXEL_OPS_SLOW)
+ #define GR_GL_RGBA_8888_PIXEL_OPS_SLOW 0
+#endif
+
+#if !defined(GR_GL_FULL_READPIXELS_FASTER_THAN_PARTIAL)
+ #define GR_GL_FULL_READPIXELS_FASTER_THAN_PARTIAL 0
+#endif
+
+#if(GR_GL_NO_CONSTANT_ATTRIBUTES) && (GR_GL_ATTRIBUTE_MATRICES)
+ #error "Cannot combine GR_GL_NO_CONSTANT_ATTRIBUTES and GR_GL_ATTRIBUTE_MATRICES"
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+#if GR_SCALAR_IS_FIXED
+ #define GrGLType GL_FIXED
+#elif GR_SCALAR_IS_FLOAT
+ #define GrGLType GR_GL_FLOAT
+#else
+ #error "unknown GR_SCALAR type"
+#endif
+
+#if GR_TEXT_SCALAR_IS_USHORT
+ #define GrGLTextType GR_GL_UNSIGNED_SHORT
+ #define GR_GL_TEXT_TEXTURE_NORMALIZED 1
+#elif GR_TEXT_SCALAR_IS_FLOAT
+ #define GrGLTextType GR_GL_FLOAT
+ #define GR_GL_TEXT_TEXTURE_NORMALIZED 0
+#elif GR_TEXT_SCALAR_IS_FIXED
+ #define GrGLTextType GR_GL_FIXED
+ #define GR_GL_TEXT_TEXTURE_NORMALIZED 0
+#else
+ #error "unknown GR_TEXT_SCALAR type"
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct GrGLInterface;
+
+extern void GrGLCheckErr(const GrGLInterface* gl,
+ const char* location,
+ const char* call);
+
+extern void GrGLClearErr(const GrGLInterface* gl);
+
+#if GR_GL_CHECK_ERROR
+ extern bool gCheckErrorGL;
+ #define GR_GL_CHECK_ERROR_IMPL(IFACE, X) \
+ if (gCheckErrorGL) \
+ GrGLCheckErr(IFACE, GR_FILE_AND_LINE_STR, #X)
+#else
+ #define GR_GL_CHECK_ERROR_IMPL(IFACE, X)
+#endif
+
+#if GR_GL_LOG_CALLS
+ extern bool gLogCallsGL;
+ #define GR_GL_LOG_CALLS_IMPL(X) \
+ if (gLogCallsGL) \
+ GrPrintf(GR_FILE_AND_LINE_STR "GL: " #X "\n")
+#else
+ #define GR_GL_LOG_CALLS_IMPL(X)
+#endif
+
+#if GR_GL_PER_GL_FUNC_CALLBACK
+ #define GR_GL_CALLBACK_IMPL(IFACE) (IFACE)->fCallback(IFACE)
+#else
+ #define GR_GL_CALLBACK_IMPL(IFACE)
+#endif
+
+#define GR_GL_CALL(IFACE, X) \
+ do { \
+ GR_GL_CALL_NOERRCHECK(IFACE, X); \
+ GR_GL_CHECK_ERROR_IMPL(IFACE, X); \
+ } while (false)
+
+#define GR_GL_CALL_NOERRCHECK(IFACE, X) \
+ do { \
+ GR_GL_CALLBACK_IMPL(IFACE); \
+ (IFACE)->f##X; \
+ GR_GL_LOG_CALLS_IMPL(X); \
+ } while (false)
+
+#define GR_GL_CALL_RET(IFACE, RET, X) \
+ do { \
+ GR_GL_CALL_RET_NOERRCHECK(IFACE, RET, X); \
+ GR_GL_CHECK_ERROR_IMPL(IFACE, X); \
+ } while (false)
+
+#define GR_GL_CALL_RET_NOERRCHECK(IFACE, RET, X) \
+ do { \
+ GR_GL_CALLBACK_IMPL(IFACE); \
+ (RET) = (IFACE)->f##X; \
+ GR_GL_LOG_CALLS_IMPL(X); \
+ } while (false)
+
+#define GR_GL_GET_ERROR(IFACE) (IFACE)->fGetError()
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Some drivers want the var-int arg to be zero-initialized on input.
+ */
+#define GR_GL_INIT_ZERO 0
+#define GR_GL_GetIntegerv(gl, e, p) \
+ do { \
+ *(p) = GR_GL_INIT_ZERO; \
+ GR_GL_CALL(gl, GetIntegerv(e, p)); \
+ } while (0)
+
+#define GR_GL_GetFramebufferAttachmentParameteriv(gl, t, a, pname, p) \
+ do { \
+ *(p) = GR_GL_INIT_ZERO; \
+ GR_GL_CALL(gl, GetFramebufferAttachmentParameteriv(t, a, pname, p)); \
+ } while (0)
+
+#define GR_GL_GetRenderbufferParameteriv(gl, t, pname, p) \
+ do { \
+ *(p) = GR_GL_INIT_ZERO; \
+ GR_GL_CALL(gl, GetRenderbufferParameteriv(t, pname, p)); \
+ } while (0)
+
+#define GR_GL_GetTexLevelParameteriv(gl, t, l, pname, p) \
+ do { \
+ *(p) = GR_GL_INIT_ZERO; \
+ GR_GL_CALL(gl, GetTexLevelParameteriv(t, l, pname, p)); \
+ } while (0)
+
+////////////////////////////////////////////////////////////////////////////////
+
+#endif
diff --git a/include/gpu/GrGLConfig_chrome.h b/include/gpu/GrGLConfig_chrome.h
new file mode 100644
index 0000000..ee3c991
--- /dev/null
+++ b/include/gpu/GrGLConfig_chrome.h
@@ -0,0 +1,30 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef GrGLConfig_chrome_DEFINED
+#define GrGLConfig_chrome_DEFINED
+
+// glGetError() forces a sync with gpu process on chrome
+#define GR_GL_CHECK_ERROR_START 0
+
+// ANGLE creates a temp VB for vertex attributes not specified per-vertex.
+#define GR_GL_NO_CONSTANT_ATTRIBUTES GR_WIN32_BUILD
+
+// For RGBA teximage/readpixels ANGLE will sw-convert to/from BGRA.
+#define GR_GL_RGBA_8888_PIXEL_OPS_SLOW GR_WIN32_BUILD
+
+// ANGLE can go faster if the entire fbo is read rather than a subrect
+#define GR_GL_FULL_READPIXELS_FASTER_THAN_PARTIAL GR_WIN32_BUILD
+
+// cmd buffer allocates memory and memsets it to zero when it sees glBufferData
+// with NULL.
+#define GR_GL_USE_BUFFER_DATA_NULL_HINT 0
+
+// chrome uses this to set the context on each GL call.
+#define GR_GL_PER_GL_FUNC_CALLBACK 1
+
+#endif
diff --git a/gpu/include/GrGLDefines.h b/include/gpu/GrGLDefines.h
index 6c2483b..e66eec4 100644
--- a/gpu/include/GrGLDefines.h
+++ b/include/gpu/GrGLDefines.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrGLDefines_DEFINED
#define GrGLDefines_DEFINED
@@ -181,7 +174,9 @@
#define GR_GL_COLOR_CLEAR_VALUE 0x0C22
#define GR_GL_COLOR_WRITEMASK 0x0C23
#define GR_GL_UNPACK_ALIGNMENT 0x0CF5
+#define GR_GL_UNPACK_FLIP_Y 0x9240
#define GR_GL_PACK_ALIGNMENT 0x0D05
+#define GR_GL_PACK_REVERSE_ROW_ORDER 0x93A4
#define GR_GL_MAX_TEXTURE_SIZE 0x0D33
#define GR_GL_MAX_VIEWPORT_DIMS 0x0D3A
#define GR_GL_SUBPIXEL_BITS 0x0D50
@@ -289,6 +284,9 @@
/* PixelFormat */
#define GR_GL_DEPTH_COMPONENT 0x1902
+#define GR_GL_RED 0x1903
+#define GR_GL_GREEN 0x1904
+#define GR_GL_BLUE 0x1905
#define GR_GL_ALPHA 0x1906
#define GR_GL_RGB 0x1907
#define GR_GL_RGBA 0x1908
@@ -296,6 +294,7 @@
#define GR_GL_LUMINANCE 0x1909
#define GR_GL_LUMINANCE_ALPHA 0x190A
#define GR_GL_PALETTE8_RGBA8 0x8B96
+#define GR_GL_ALPHA8 0x803C
/* PixelType */
/* GL_UNSIGNED_BYTE */
@@ -306,6 +305,7 @@
/* Shaders */
#define GR_GL_FRAGMENT_SHADER 0x8B30
#define GR_GL_VERTEX_SHADER 0x8B31
+#define GR_GL_GEOMETRY_SHADER 0x8DD9
#define GR_GL_MAX_VERTEX_ATTRIBS 0x8869
#define GR_GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
#define GR_GL_MAX_VARYING_VECTORS 0x8DFC
@@ -354,7 +354,9 @@
#define GR_GL_EXTENSIONS 0x1F03
/* Pixel Mode / Transfer */
-#define GR_GL_UNPACK_ROW_LENGTH 0x0CF2
+#define GR_GL_UNPACK_ROW_LENGTH 0x0CF2
+#define GR_GL_PACK_ROW_LENGTH 0x0D02
+
/* TextureMagFilter */
#define GR_GL_NEAREST 0x2600
@@ -368,11 +370,15 @@
#define GR_GL_NEAREST_MIPMAP_LINEAR 0x2702
#define GR_GL_LINEAR_MIPMAP_LINEAR 0x2703
+/* TextureUsage */
+#define GR_GL_FRAMEBUFFER_ATTACHMENT 0x93A3
+
/* TextureParameterName */
#define GR_GL_TEXTURE_MAG_FILTER 0x2800
#define GR_GL_TEXTURE_MIN_FILTER 0x2801
#define GR_GL_TEXTURE_WRAP_S 0x2802
#define GR_GL_TEXTURE_WRAP_T 0x2803
+#define GR_GL_TEXTURE_USAGE 0x93A2
/* TextureTarget */
/* GL_TEXTURE_2D */
@@ -428,15 +434,22 @@
#define GR_GL_CLAMP_TO_EDGE 0x812F
#define GR_GL_MIRRORED_REPEAT 0x8370
+/* Texture Swizzle */
+#define GR_GL_TEXTURE_SWIZZLE_R 0x8E42
+#define GR_GL_TEXTURE_SWIZZLE_G 0x8E43
+#define GR_GL_TEXTURE_SWIZZLE_B 0x8E44
+#define GR_GL_TEXTURE_SWIZZLE_A 0x8E45
+#define GR_GL_TEXTURE_SWIZZLE_RGBA 0x8E46
+
/* Texture mapping */
-#define GR_GL_TEXTURE_ENV 0x2300
-#define GR_GL_TEXTURE_ENV_MODE 0x2200
-#define GR_GL_TEXTURE_1D 0x0DE0
-#define GR_GL_TEXTURE_2D 0x0DE1
-/* GL_TEXTURE_WRAP_S */
-/* GL_TEXTURE_WRAP_T */
-/* GL_TEXTURE_MAG_FILTER */
-/* GL_TEXTURE_MIN_FILTER */
+#define GR_GL_TEXTURE_ENV 0x2300
+#define GR_GL_TEXTURE_ENV_MODE 0x2200
+#define GR_GL_TEXTURE_1D 0x0DE0
+/* GL_TEXTURE_2D */
+/* GL_TEXTURE_WRAP_S */
+/* GL_TEXTURE_WRAP_T */
+/* GL_TEXTURE_MAG_FILTER */
+/* GL_TEXTURE_MIN_FILTER */
#define GR_GL_TEXTURE_ENV_COLOR 0x2201
#define GR_GL_TEXTURE_GEN_S 0x0C60
#define GR_GL_TEXTURE_GEN_T 0x0C61
@@ -452,10 +465,11 @@
#define GR_GL_TEXTURE_ALPHA_SIZE 0x805F
#define GR_GL_TEXTURE_LUMINANCE_SIZE 0x8060
#define GR_GL_TEXTURE_INTENSITY_SIZE 0x8061
-/* GL_NEAREST_MIPMAP_NEAREST */
-/* GL_NEAREST_MIPMAP_LINEAR */
-/* GL_LINEAR_MIPMAP_NEAREST */
-/* GL_LINEAR_MIPMAP_LINEAR */
+#define GR_GL_TEXTURE_INTERNAL_FORMAT 0x1003
+/* GL_NEAREST_MIPMAP_NEAREST */
+/* GL_NEAREST_MIPMAP_LINEAR */
+/* GL_LINEAR_MIPMAP_NEAREST */
+/* GL_LINEAR_MIPMAP_LINEAR */
#define GR_GL_OBJECT_LINEAR 0x2401
#define GR_GL_OBJECT_PLANE 0x2501
#define GR_GL_EYE_LINEAR 0x2400
@@ -594,6 +608,19 @@
#define GR_GL_MEDIUM_INT 0x8DF4
#define GR_GL_HIGH_INT 0x8DF5
+/* Queries */
+#define GR_GL_QUERY_COUNTER_BITS 0x8864
+#define GR_GL_CURRENT_QUERY 0x8865
+#define GR_GL_QUERY_RESULT 0x8866
+#define GR_GL_QUERY_RESULT_AVAILABLE 0x8867
+#define GR_GL_SAMPLES_PASSED 0x8914
+#define GR_GL_ANY_SAMPLES_PASSED 0x8C2F
+#define GR_GL_TIME_ELAPSED 0x88BF
+#define GR_GL_TIMESTAMP 0x8E28
+#define GR_GL_PRIMITIVES_GENERATED 0x8C87
+#define GR_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88
+
+
/* Framebuffer Object. */
#define GR_GL_FRAMEBUFFER 0x8D40
#define GR_GL_READ_FRAMEBUFFER 0x8CA8
@@ -605,6 +632,12 @@
#define GR_GL_RGB5_A1 0x8057
#define GR_GL_RGB565 0x8D62
#define GR_GL_RGBA8 0x8058
+#define GR_GL_RGB8 0x8051
+#define GR_GL_BGRA8 0x93A1
+#define GR_GL_SRGB 0x8C40
+#define GR_GL_SRGB8 0x8C41
+#define GR_GL_SRGB_ALPHA 0x8C42
+#define GR_GL_SRGB8_ALPHA8 0x8C43
#define GR_GL_DEPTH_COMPONENT16 0x81A5
#define GR_GL_STENCIL_INDEX 0x1901
#define GR_GL_STENCIL_INDEX4 0x8D47
@@ -629,6 +662,13 @@
#define GR_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
#define GR_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
#define GR_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+#define GR_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4
+#define GR_GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212
+#define GR_GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213
+#define GR_GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214
+#define GR_GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215
+#define GR_GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216
+#define GR_GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217
#define GR_GL_COLOR_ATTACHMENT0 0x8CE0
#define GR_GL_DEPTH_ATTACHMENT 0x8D00
diff --git a/gpu/include/GrGLInterface.h b/include/gpu/GrGLInterface.h
index 150e8e4..716cff9 100644
--- a/gpu/include/GrGLInterface.h
+++ b/include/gpu/GrGLInterface.h
@@ -1,25 +1,18 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrGLInterface_DEFINED
#define GrGLInterface_DEFINED
#include "GrGLConfig.h"
-#include "GrTypes.h"
+#include "GrRefCnt.h"
#if !defined(GR_GL_FUNCTION_TYPE)
#define GR_GL_FUNCTION_TYPE
@@ -31,33 +24,69 @@
* Helpers for glGetString()
*/
-void gl_version_from_string(int* major, int* minor,
- const char* versionString);
-bool has_gl_extension_from_string(const char* ext,
- const char* extensionString);
+typedef uint32_t GrGLVersion;
+typedef uint32_t GrGLSLVersion;
-bool has_gl_extension(const char* ext);
-void gl_version(int* major, int* minor);
+#define GR_GL_VER(major, minor) ((static_cast<int>(major) << 16) | \
+ static_cast<int>(minor))
+#define GR_GLSL_VER(major, minor) ((static_cast<int>(major) << 16) | \
+ static_cast<int>(minor))
+// these variants assume caller already has a string from glGetString()
+GrGLVersion GrGLGetVersionFromString(const char* versionString);
+GrGLSLVersion GrGLGetGLSLVersionFromString(const char* versionString);
+bool GrGLHasExtensionFromString(const char* ext, const char* extensionString);
+
+// these variants call glGetString()
+bool GrGLHasExtension(const GrGLInterface*, const char* ext);
+GrGLVersion GrGLGetVersion(const GrGLInterface*);
+GrGLSLVersion GrGLGetGLSLVersion(const GrGLInterface*);
////////////////////////////////////////////////////////////////////////////////
-/*
- * Routines managing the global interface used to invoke OpenGL calls.
+/**
+ * Rather than depend on platform-specific GL headers and libraries, we require
+ * the client to provide a struct of GL function pointers. This struct can be
+ * specified per-GrContext as a parameter to GrContext::Create. If NULL is
+ * passed to Create then the "default" GL interface is used. If the default is
+ * also NULL GrContext creation will fail.
+ *
+ * The default interface is returned by GrGLDefaultInterface. This function's
+ * implementation is platform-specifc. Several have been provided, along with an
+ * implementation that simply returns NULL. It is implementation-specific
+ * whether the same GrGLInterface is returned or whether a new one is created
+ * at each call. Some platforms may not be able to use a single GrGLInterface
+ * because extension function ptrs vary across contexts. Note that GrGLInterface
+ * is ref-counted. So if the same object is returned by multiple calls to
+ * GrGLDefaultInterface, each should bump the ref count.
+ *
+ * By defining GR_GL_PER_GL_CALL_IFACE_CALLBACK to 1 the client can specify a
+ * callback function that will be called prior to each GL function call. See
+ * comments in GrGLConfig.h
*/
+
struct GrGLInterface;
-GR_API GrGLInterface* GrGLGetGLInterface();
-GR_API void GrGLSetGLInterface(GrGLInterface* gl_interface);
-/*
- * This is called when GrGLSetGLInterface() hasn't been called before creating a
- * GrGpuGL object. It provides a default implementation. The actual implementation
- * depends on which GrGLDefaultInterface_*.cpp has been linked. There are some
- * platform-specific implementations provided as well as
- * GrGLDefaultInterface_none.cpp which does nothing (effectively requiring an
- * explicit GrGLSetGLInterface call by the host).
+const GrGLInterface* GrGLDefaultInterface();
+
+/**
+ * Creates a GrGLInterface for a "native" GL context (e.g. WGL on windows,
+ * GLX on linux, AGL on Mac). On platforms that have context-specific function
+ * pointers for GL extensions (e.g. windows) the returned interface is only
+ * valid for the context that was current at creation.
*/
-void GrGLSetDefaultGLInterface();
+const GrGLInterface* GrGLCreateNativeInterface();
+
+/**
+ * Creates a GrGLInterface for an OSMesa context.
+ */
+const GrGLInterface* GrGLCreateMesaInterface();
+
+/**
+ * Creates a null GrGLInterface that doesn't draw anything. Used for measuring
+ * CPU overhead.
+ */
+const GrGLInterface* GrGLCreateNullInterface();
typedef unsigned int GrGLenum;
typedef unsigned char GrGLboolean;
@@ -67,9 +96,11 @@ typedef char GrGLchar;
typedef short GrGLshort;
typedef int GrGLint;
typedef int GrGLsizei;
+typedef int64_t GrGLint64;
typedef unsigned char GrGLubyte;
typedef unsigned short GrGLushort;
typedef unsigned int GrGLuint;
+typedef uint64_t GrGLuint64;
typedef float GrGLfloat;
typedef float GrGLclampf;
typedef double GrGLdouble;
@@ -80,25 +111,24 @@ typedef long GrGLsizeiptr;
enum GrGLBinding {
kDesktop_GrGLBinding = 0x01,
- kES1_GrGLBinding = 0x02,
- kES2_GrGLBinding = 0x04
+ kES2_GrGLBinding = 0x02
};
extern "C" {
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLActiveTextureProc)(GrGLenum texture);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLAttachShaderProc)(GrGLuint program, GrGLuint shader);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLBeginQueryProc)(GrGLenum target, GrGLuint id);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLBindAttribLocationProc)(GrGLuint program, GrGLuint index, const char* name);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLBindBufferProc)(GrGLenum target, GrGLuint buffer);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLBindTextureProc)(GrGLenum target, GrGLuint texture);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLBlendColorProc)(GrGLclampf red, GrGLclampf green, GrGLclampf blue, GrGLclampf alpha);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLBindFragDataLocationProc)(GrGLuint program, GrGLuint colorNumber, const GrGLchar* name);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLBlendFuncProc)(GrGLenum sfactor, GrGLenum dfactor);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLBufferDataProc)(GrGLenum target, GrGLsizeiptr size, const GrGLvoid* data, GrGLenum usage);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLBufferSubDataProc)(GrGLenum target, GrGLintptr offset, GrGLsizeiptr size, const GrGLvoid* data);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLClearProc)(GrGLbitfield mask);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLClearColorProc)(GrGLclampf red, GrGLclampf green, GrGLclampf blue, GrGLclampf alpha);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLClearStencilProc)(GrGLint s);
- typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLClientActiveTextureProc)(GrGLenum texture);
- typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLColor4ubProc)(GrGLubyte red, GrGLubyte green, GrGLubyte blue, GrGLubyte alpha);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLColorMaskProc)(GrGLboolean red, GrGLboolean green, GrGLboolean blue, GrGLboolean alpha);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLColorPointerProc)(GrGLint size, GrGLenum type, GrGLsizei stride, const GrGLvoid* pointer);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLCompileShaderProc)(GrGLuint shader);
@@ -108,38 +138,47 @@ extern "C" {
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLCullFaceProc)(GrGLenum mode);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLDeleteBuffersProc)(GrGLsizei n, const GrGLuint* buffers);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLDeleteProgramProc)(GrGLuint program);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLDeleteQueriesProc)(GrGLsizei n, const GrGLuint *ids);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLDeleteShaderProc)(GrGLuint shader);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLDeleteTexturesProc)(GrGLsizei n, const GrGLuint* textures);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLDepthMaskProc)(GrGLboolean flag);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLDisableProc)(GrGLenum cap);
- typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLDisableClientStateProc)(GrGLenum array);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLDisableVertexAttribArrayProc)(GrGLuint index);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLDrawArraysProc)(GrGLenum mode, GrGLint first, GrGLsizei count);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLDrawBufferProc)(GrGLenum mode);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLDrawBuffersProc)(GrGLsizei n, const GrGLenum* bufs);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLDrawElementsProc)(GrGLenum mode, GrGLsizei count, GrGLenum type, const GrGLvoid* indices);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLEnableProc)(GrGLenum cap);
- typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLEnableClientStateProc)(GrGLenum cap);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLEnableVertexAttribArrayProc)(GrGLuint index);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLEndQueryProc)(GrGLenum target);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLFinishProc)();
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLFlushProc)();
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLFrontFaceProc)(GrGLenum mode);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGenBuffersProc)(GrGLsizei n, GrGLuint* buffers);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGenQueriesProc)(GrGLsizei n, GrGLuint *ids);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGenTexturesProc)(GrGLsizei n, GrGLuint* textures);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGetBufferParameterivProc)(GrGLenum target, GrGLenum pname, GrGLint* params);
- typedef GrGLenum (GR_GL_FUNCTION_TYPE *GrGLGetErrorProc)(void);
+ typedef GrGLenum (GR_GL_FUNCTION_TYPE *GrGLGetErrorProc)();
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGetIntegervProc)(GrGLenum pname, GrGLint* params);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGetProgramInfoLogProc)(GrGLuint program, GrGLsizei bufsize, GrGLsizei* length, char* infolog);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGetProgramivProc)(GrGLuint program, GrGLenum pname, GrGLint* params);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGetQueryivProc)(GrGLenum GLtarget, GrGLenum pname, GrGLint *params);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGetQueryObjecti64vProc)(GrGLuint id, GrGLenum pname, GrGLint64 *params);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGetQueryObjectivProc)(GrGLuint id, GrGLenum pname, GrGLint *params);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGetQueryObjectui64vProc)(GrGLuint id, GrGLenum pname, GrGLuint64 *params);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGetQueryObjectuivProc)(GrGLuint id, GrGLenum pname, GrGLuint *params);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGetShaderInfoLogProc)(GrGLuint shader, GrGLsizei bufsize, GrGLsizei* length, char* infolog);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGetShaderivProc)(GrGLuint shader, GrGLenum pname, GrGLint* params);
typedef const GrGLubyte* (GR_GL_FUNCTION_TYPE *GrGLGetStringProc)(GrGLenum name);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGetTexLevelParameterivProc)(GrGLenum target, GrGLint level, GrGLenum pname, GrGLint* params);
typedef GrGLint (GR_GL_FUNCTION_TYPE *GrGLGetUniformLocationProc)(GrGLuint program, const char* name);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLLineWidthProc)(GrGLfloat width);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLLinkProgramProc)(GrGLuint program);
- typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLLoadMatrixfProc)(const GrGLfloat* m);
- typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLMatrixModeProc)(GrGLenum mode);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLPixelStoreiProc)(GrGLenum pname, GrGLint param);
- typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLPointSizeProc)(GrGLfloat size);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLQueryCounterProc)(GrGLuint id, GrGLenum target);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLReadBufferProc)(GrGLenum src);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLReadPixelsProc)(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, GrGLvoid* pixels);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLScissorProc)(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height);
- typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLShadeModelProc)(GrGLenum mode);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLShaderSourceProc)(GrGLuint shader, GrGLsizei count, const char** str, const GrGLint* length);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLStencilFuncProc)(GrGLenum func, GrGLint ref, GrGLuint mask);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLStencilFuncSeparateProc)(GrGLenum face, GrGLenum func, GrGLint ref, GrGLuint mask);
@@ -147,10 +186,9 @@ extern "C" {
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLStencilMaskSeparateProc)(GrGLenum face, GrGLuint mask);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLStencilOpProc)(GrGLenum fail, GrGLenum zfail, GrGLenum zpass);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLStencilOpSeparateProc)(GrGLenum face, GrGLenum fail, GrGLenum zfail, GrGLenum zpass);
- typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLTexCoordPointerProc)(GrGLint size, GrGLenum type, GrGLsizei stride, const GrGLvoid* pointer);
- typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLTexEnviProc)(GrGLenum target, GrGLenum pname, GrGLint param);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLTexImage2DProc)(GrGLenum target, GrGLint level, GrGLint internalformat, GrGLsizei width, GrGLsizei height, GrGLint border, GrGLenum format, GrGLenum type, const GrGLvoid* pixels);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLTexParameteriProc)(GrGLenum target, GrGLenum pname, GrGLint param);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLTexStorage2DProc)(GrGLenum target, GrGLsizei levels, GrGLenum internalformat, GrGLsizei width, GrGLsizei height);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLTexSubImage2DProc)(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, const GrGLvoid* pixels);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform1fProc)(GrGLint location, GrGLfloat v0);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUniform1iProc)(GrGLint location, GrGLint v0);
@@ -174,7 +212,6 @@ extern "C" {
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLUseProgramProc)(GrGLuint program);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLVertexAttrib4fvProc)(GrGLuint indx, const GrGLfloat* values);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLVertexAttribPointerProc)(GrGLuint indx, GrGLint size, GrGLenum type, GrGLboolean normalized, GrGLsizei stride, const GrGLvoid* ptr);
- typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLVertexPointerProc)(GrGLint size, GrGLenum type, GrGLsizei stride, const GrGLvoid* pointer);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLViewportProc)(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height);
// FBO Extension Functions
@@ -187,6 +224,8 @@ extern "C" {
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLFramebufferTexture2DProc)(GrGLenum target, GrGLenum attachment, GrGLenum textarget, GrGLuint texture, GrGLint level);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGenFramebuffersProc)(GrGLsizei n, GrGLuint *framebuffers);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGenRenderbuffersProc)(GrGLsizei n, GrGLuint *renderbuffers);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGetFramebufferAttachmentParameterivProc)(GrGLenum target, GrGLenum attachment, GrGLenum pname, GrGLint* params);
+ typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLGetRenderbufferParameterivProc)(GrGLenum target, GrGLenum pname, GrGLint* params);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLRenderbufferStorageProc)(GrGLenum target, GrGLenum internalformat, GrGLsizei width, GrGLsizei height);
// Multisampling Extension Functions
@@ -205,6 +244,16 @@ extern "C" {
typedef GrGLvoid (GR_GL_FUNCTION_TYPE *GrGLBindFragDataLocationIndexedProc)(GrGLuint program, GrGLuint colorNumber, GrGLuint index, const GrGLchar * name);
} // extern "C"
+#if GR_GL_PER_GL_FUNC_CALLBACK
+typedef void (*GrGLInterfaceCallbackProc)(const GrGLInterface*);
+typedef intptr_t GrGLInterfaceCallbackData;
+#endif
+
+
+enum GrGLCapability {
+ kProbe_GrGLCapability = -1
+};
+
/*
* The following interface exports the OpenGL entry points used by the system.
* Use of OpenGL calls is disallowed. All calls should be invoked through
@@ -214,8 +263,17 @@ extern "C" {
* functions, and extensions. The system assumes that the address of the
* extension pointer will be valid across contexts.
*/
-struct GrGLInterface {
- bool validate(GrEngine engine) const;
+struct GR_API GrGLInterface : public GrRefCnt {
+
+ GrGLInterface();
+
+ bool validate() const;
+ bool supportsDesktop() const {
+ return 0 != (kDesktop_GrGLBinding & fBindingsExported);
+ }
+ bool supportsES2() const {
+ return 0 != (kES2_GrGLBinding & fBindingsExported);
+ }
// Indicator variable specifying the type of GL implementation
// exported: GLES{1|2} or Desktop.
@@ -223,8 +281,10 @@ struct GrGLInterface {
GrGLActiveTextureProc fActiveTexture;
GrGLAttachShaderProc fAttachShader;
+ GrGLBeginQueryProc fBeginQuery;
GrGLBindAttribLocationProc fBindAttribLocation;
GrGLBindBufferProc fBindBuffer;
+ GrGLBindFragDataLocationProc fBindFragDataLocation;
GrGLBindTextureProc fBindTexture;
GrGLBlendColorProc fBlendColor;
GrGLBlendFuncProc fBlendFunc;
@@ -233,8 +293,6 @@ struct GrGLInterface {
GrGLClearProc fClear;
GrGLClearColorProc fClearColor;
GrGLClearStencilProc fClearStencil;
- GrGLClientActiveTextureProc fClientActiveTexture;
- GrGLColor4ubProc fColor4ub;
GrGLColorMaskProc fColorMask;
GrGLColorPointerProc fColorPointer;
GrGLCompileShaderProc fCompileShader;
@@ -244,38 +302,47 @@ struct GrGLInterface {
GrGLCullFaceProc fCullFace;
GrGLDeleteBuffersProc fDeleteBuffers;
GrGLDeleteProgramProc fDeleteProgram;
+ GrGLDeleteQueriesProc fDeleteQueries;
GrGLDeleteShaderProc fDeleteShader;
GrGLDeleteTexturesProc fDeleteTextures;
GrGLDepthMaskProc fDepthMask;
GrGLDisableProc fDisable;
- GrGLDisableClientStateProc fDisableClientState;
GrGLDisableVertexAttribArrayProc fDisableVertexAttribArray;
GrGLDrawArraysProc fDrawArrays;
+ GrGLDrawBufferProc fDrawBuffer;
+ GrGLDrawBuffersProc fDrawBuffers;
GrGLDrawElementsProc fDrawElements;
GrGLEnableProc fEnable;
- GrGLEnableClientStateProc fEnableClientState;
GrGLEnableVertexAttribArrayProc fEnableVertexAttribArray;
+ GrGLEndQueryProc fEndQuery;
+ GrGLFinishProc fFinish;
+ GrGLFlushProc fFlush;
GrGLFrontFaceProc fFrontFace;
GrGLGenBuffersProc fGenBuffers;
+ GrGLGenQueriesProc fGenQueries;
GrGLGenTexturesProc fGenTextures;
GrGLGetBufferParameterivProc fGetBufferParameteriv;
GrGLGetErrorProc fGetError;
GrGLGetIntegervProc fGetIntegerv;
+ GrGLGetQueryObjecti64vProc fGetQueryObjecti64v;
+ GrGLGetQueryObjectivProc fGetQueryObjectiv;
+ GrGLGetQueryObjectui64vProc fGetQueryObjectui64v;
+ GrGLGetQueryObjectuivProc fGetQueryObjectuiv;
+ GrGLGetQueryivProc fGetQueryiv;
GrGLGetProgramInfoLogProc fGetProgramInfoLog;
GrGLGetProgramivProc fGetProgramiv;
GrGLGetShaderInfoLogProc fGetShaderInfoLog;
GrGLGetShaderivProc fGetShaderiv;
GrGLGetStringProc fGetString;
+ GrGLGetTexLevelParameterivProc fGetTexLevelParameteriv;
GrGLGetUniformLocationProc fGetUniformLocation;
GrGLLineWidthProc fLineWidth;
GrGLLinkProgramProc fLinkProgram;
- GrGLLoadMatrixfProc fLoadMatrixf;
- GrGLMatrixModeProc fMatrixMode;
GrGLPixelStoreiProc fPixelStorei;
- GrGLPointSizeProc fPointSize;
+ GrGLQueryCounterProc fQueryCounter;
+ GrGLReadBufferProc fReadBuffer;
GrGLReadPixelsProc fReadPixels;
GrGLScissorProc fScissor;
- GrGLShadeModelProc fShadeModel;
GrGLShaderSourceProc fShaderSource;
GrGLStencilFuncProc fStencilFunc;
GrGLStencilFuncSeparateProc fStencilFuncSeparate;
@@ -283,11 +350,10 @@ struct GrGLInterface {
GrGLStencilMaskSeparateProc fStencilMaskSeparate;
GrGLStencilOpProc fStencilOp;
GrGLStencilOpSeparateProc fStencilOpSeparate;
- GrGLTexCoordPointerProc fTexCoordPointer;
- GrGLTexEnviProc fTexEnvi;
GrGLTexImage2DProc fTexImage2D;
GrGLTexParameteriProc fTexParameteri;
GrGLTexSubImage2DProc fTexSubImage2D;
+ GrGLTexStorage2DProc fTexStorage2D;
GrGLUniform1fProc fUniform1f;
GrGLUniform1iProc fUniform1i;
GrGLUniform1fvProc fUniform1fv;
@@ -310,7 +376,6 @@ struct GrGLInterface {
GrGLUseProgramProc fUseProgram;
GrGLVertexAttrib4fvProc fVertexAttrib4fv;
GrGLVertexAttribPointerProc fVertexAttribPointer;
- GrGLVertexPointerProc fVertexPointer;
GrGLViewportProc fViewport;
// FBO Extension Functions
@@ -323,6 +388,8 @@ struct GrGLInterface {
GrGLFramebufferTexture2DProc fFramebufferTexture2D;
GrGLGenFramebuffersProc fGenFramebuffers;
GrGLGenRenderbuffersProc fGenRenderbuffers;
+ GrGLGetFramebufferAttachmentParameterivProc fGetFramebufferAttachmentParameteriv;
+ GrGLGetRenderbufferParameterivProc fGetRenderbufferParameteriv;
GrGLRenderbufferStorageProc fRenderbufferStorage;
// Multisampling Extension Functions
@@ -340,14 +407,12 @@ struct GrGLInterface {
// Dual Source Blending
GrGLBindFragDataLocationIndexedProc fBindFragDataLocationIndexed;
- // Code that initializes this struct using a static initializer should
- // make this the last entry in the static initializer. It can help to guard
- // against failing to initialize newly-added members of this struct.
- enum { kStaticInitEndGuard } fStaticInitEndGuard;
+ // Per-GL func callback
+#if GR_GL_PER_GL_FUNC_CALLBACK
+ GrGLInterfaceCallbackProc fCallback;
+ GrGLInterfaceCallbackData fCallbackData;
+#endif
-private:
- bool validateShaderFunctions() const;
- bool validateFixedFunctions() const;
};
#endif
diff --git a/gpu/include/GrGlyph.h b/include/gpu/GrGlyph.h
index 4a3b307..a0d81a1 100644
--- a/gpu/include/GrGlyph.h
+++ b/include/gpu/GrGlyph.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrGlyph_DEFINED
#define GrGlyph_DEFINED
diff --git a/gpu/include/GrInstanceCounter.h b/include/gpu/GrInstanceCounter.h
index 11cec2b..b3e21d2 100644
--- a/gpu/include/GrInstanceCounter.h
+++ b/include/gpu/GrInstanceCounter.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrInstanceCounter_DEFINED
#define GrInstanceCounter_DEFINED
diff --git a/gpu/include/GrKey.h b/include/gpu/GrKey.h
index 19133ae..813d82d 100644
--- a/gpu/include/GrKey.h
+++ b/include/gpu/GrKey.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrKey_DEFINED
#define GrKey_DEFINED
diff --git a/include/gpu/GrMatrix.h b/include/gpu/GrMatrix.h
new file mode 100644
index 0000000..055680a
--- /dev/null
+++ b/include/gpu/GrMatrix.h
@@ -0,0 +1,19 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrMatrix_DEFINED
+#define GrMatrix_DEFINED
+
+#include "GrRect.h"
+#include "SkMatrix.h"
+
+typedef SkMatrix GrMatrix;
+
+#endif
diff --git a/include/gpu/GrNoncopyable.h b/include/gpu/GrNoncopyable.h
new file mode 100644
index 0000000..cad722f
--- /dev/null
+++ b/include/gpu/GrNoncopyable.h
@@ -0,0 +1,31 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrNoncopyable_DEFINED
+#define GrNoncopyable_DEFINED
+
+#include "GrTypes.h"
+
+/**
+ * Base for classes that want to disallow copying themselves. It makes its
+ * copy-constructor and assignment operators private (and unimplemented).
+ */
+class GR_API GrNoncopyable {
+public:
+ GrNoncopyable() {}
+
+private:
+ // illegal
+ GrNoncopyable(const GrNoncopyable&);
+ GrNoncopyable& operator=(const GrNoncopyable&);
+};
+
+#endif
+
diff --git a/gpu/include/GrPaint.h b/include/gpu/GrPaint.h
index a7923f5..f1d74b2 100644
--- a/gpu/include/GrPaint.h
+++ b/include/gpu/GrPaint.h
@@ -1,19 +1,12 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrPaint_DEFINED
#define GrPaint_DEFINED
@@ -40,11 +33,13 @@ public:
GrBlendCoeff fDstBlendCoeff;
bool fAntiAlias;
bool fDither;
+ bool fColorMatrixEnabled;
GrColor fColor;
GrColor fColorFilterColor;
SkXfermode::Mode fColorFilterXfermode;
+ float fColorMatrix[20];
void setTexture(int i, GrTexture* texture) {
GrAssert((unsigned)i < kMaxTextures);
@@ -58,14 +53,14 @@ public:
return fTextures[i];
}
- GrSamplerState* getTextureSampler(int i) {
+ GrSamplerState* textureSampler(int i) {
GrAssert((unsigned)i < kMaxTextures);
return fTextureSamplers + i;
}
- const GrSamplerState* getTextureSampler(int i) const {
+ const GrSamplerState& getTextureSampler(int i) const {
GrAssert((unsigned)i < kMaxTextures);
- return fTextureSamplers + i;
+ return fTextureSamplers[i];
}
// The mask can be alpha-only or per channel. It is applied
@@ -84,14 +79,14 @@ public:
// mask's sampler matrix is always applied to the positions
// (i.e. no explicit texture coordinates)
- GrSamplerState* getMaskSampler(int i) {
+ GrSamplerState* maskSampler(int i) {
GrAssert((unsigned)i < kMaxMasks);
return fMaskSamplers + i;
}
- const GrSamplerState* getMaskSampler(int i) const {
+ const GrSamplerState& getMaskSampler(int i) const {
GrAssert((unsigned)i < kMaxMasks);
- return fMaskSamplers + i;
+ return fMaskSamplers[i];
}
// pre-concats sampler matrices for non-NULL textures and masks
@@ -115,6 +110,16 @@ public:
}
GrPaint(const GrPaint& paint) {
+ for (int i = 0; i < kMaxTextures; ++i) {
+ fTextures[i] = NULL;
+ }
+ for (int i = 0; i < kMaxMasks; ++i) {
+ fMaskTextures[i] = NULL;
+ }
+ *this = paint;
+ }
+
+ GrPaint& operator=(const GrPaint& paint) {
fSrcBlendCoeff = paint.fSrcBlendCoeff;
fDstBlendCoeff = paint.fDstBlendCoeff;
fAntiAlias = paint.fAntiAlias;
@@ -124,17 +129,22 @@ public:
fColorFilterColor = paint.fColorFilterColor;
fColorFilterXfermode = paint.fColorFilterXfermode;
+ memcpy(fColorMatrix, paint.fColorMatrix, sizeof(fColorMatrix));
+ fColorMatrixEnabled = paint.fColorMatrixEnabled;
for (int i = 0; i < kMaxTextures; ++i) {
+ GrSafeUnref(fTextures[i]);
fTextureSamplers[i] = paint.fTextureSamplers[i];
fTextures[i] = paint.fTextures[i];
GrSafeRef(fTextures[i]);
}
for (int i = 0; i < kMaxMasks; ++i) {
+ GrSafeUnref(fMaskTextures[i]);
fMaskSamplers[i] = paint.fMaskSamplers[i];
fMaskTextures[i] = paint.fMaskTextures[i];
GrSafeRef(fMaskTextures[i]);
}
+ return *this;
}
~GrPaint() {
@@ -159,6 +169,8 @@ public:
void resetColorFilter() {
fColorFilterXfermode = SkXfermode::kDst_Mode;
fColorFilterColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
+ memset(fColorMatrix, 0, sizeof(fColorMatrix));
+ fColorMatrixEnabled = false;
}
bool hasTexture() const {
@@ -233,14 +245,14 @@ private:
void resetTextures() {
for (int i = 0; i < kMaxTextures; ++i) {
this->setTexture(i, NULL);
- fTextureSamplers[i].setClampNoFilter();
+ fTextureSamplers[i].reset();
}
}
void resetMasks() {
for (int i = 0; i < kMaxMasks; ++i) {
this->setMask(i, NULL);
- fMaskSamplers[i].setClampNoFilter();
+ fMaskSamplers[i].reset();
}
}
};
diff --git a/include/gpu/GrPath.h b/include/gpu/GrPath.h
new file mode 100644
index 0000000..7da0d48
--- /dev/null
+++ b/include/gpu/GrPath.h
@@ -0,0 +1,20 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrPath_DEFINED
+#define GrPath_DEFINED
+
+#include "GrTypes.h"
+#include "SkPath.h"
+
+typedef SkPath GrPath;
+
+#endif
+
diff --git a/include/gpu/GrPoint.h b/include/gpu/GrPoint.h
new file mode 100644
index 0000000..b32123b
--- /dev/null
+++ b/include/gpu/GrPoint.h
@@ -0,0 +1,31 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrPoint_DEFINED
+#define GrPoint_DEFINED
+
+#include "GrTypes.h"
+#include "GrScalar.h"
+#include "SkPoint.h"
+
+#define GrPoint SkPoint
+#define GrVec SkVector
+
+struct GrIPoint16 {
+ int16_t fX, fY;
+
+ void set(intptr_t x, intptr_t y) {
+ fX = GrToS16(x);
+ fY = GrToS16(y);
+ }
+};
+
+#endif
+
diff --git a/gpu/include/GrRect.h b/include/gpu/GrRect.h
index 81f1545..60a4773 100644
--- a/gpu/include/GrRect.h
+++ b/include/gpu/GrRect.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrRect_DEFINED
#define GrRect_DEFINED
diff --git a/include/gpu/GrRefCnt.h b/include/gpu/GrRefCnt.h
new file mode 100644
index 0000000..50c32c6
--- /dev/null
+++ b/include/gpu/GrRefCnt.h
@@ -0,0 +1,34 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrRefCnt_DEFINED
+#define GrRefCnt_DEFINED
+
+#include "GrTypes.h"
+#include "SkRefCnt.h"
+
+typedef SkRefCnt GrRefCnt;
+typedef SkAutoRef GrAutoRef;
+typedef SkAutoUnref GrAutoUnref;
+
+#define GrSafeRef SkSafeRef
+#define GrSafeUnref SkSafeUnref
+#define GrSafeAssign(a, b) SkRefCnt_SafeAssign(a, b)
+
+template<typename T>
+static inline void GrSafeSetNull(T*& obj) {
+ if (NULL != obj) {
+ obj->unref();
+ obj = NULL;
+ }
+}
+
+#endif
+
diff --git a/include/gpu/GrRenderTarget.h b/include/gpu/GrRenderTarget.h
new file mode 100644
index 0000000..13b2160
--- /dev/null
+++ b/include/gpu/GrRenderTarget.h
@@ -0,0 +1,206 @@
+/*
+ Copyright 2011 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+
+#ifndef GrRenderTarget_DEFINED
+#define GrRenderTarget_DEFINED
+
+#include "GrRect.h"
+#include "GrResource.h"
+
+class GrStencilBuffer;
+class GrTexture;
+
+/**
+ * GrRenderTarget represents a 2D buffer of pixels that can be rendered to.
+ * A context's render target is set by setRenderTarget(). Render targets are
+ * created by a createTexture with the kRenderTarget_TextureFlag flag.
+ * Additionally, GrContext provides methods for creating GrRenderTargets
+ * that wrap externally created render targets.
+ */
+class GrRenderTarget : public GrResource {
+public:
+
+ /**
+ * @return the width of the rendertarget
+ */
+ int width() const { return fWidth; }
+ /**
+ * @return the height of the rendertarget
+ */
+ int height() const { return fHeight; }
+
+ /**
+ * @return the pixel config. Can be kUnknown_GrPixelConfig
+ * if client asked us to render to a target that has a pixel
+ * config that isn't equivalent with one of our configs.
+ */
+ GrPixelConfig config() const { return fConfig; }
+
+ /**
+ * @return the texture associated with the rendertarget, may be NULL.
+ */
+ GrTexture* asTexture() {return fTexture;}
+
+ /**
+ * If this RT is multisampled, this is the multisample buffer
+ * @return the 3D API's handle to this object (e.g. FBO ID in OpenGL)
+ */
+ virtual intptr_t getRenderTargetHandle() const = 0;
+
+ /**
+ * If this RT is multisampled, this is the buffer it is resolved to.
+ * Otherwise, same as getRenderTargetHandle().
+ * (In GL a separate FBO ID is used for the msaa and resolved buffers)
+ * @return the 3D API's handle to this object (e.g. FBO ID in OpenGL)
+ */
+ virtual intptr_t getRenderTargetResolvedHandle() const = 0;
+
+ /**
+ * @return true if the render target is multisampled, false otherwise
+ */
+ bool isMultisampled() const { return 0 != fSampleCnt; }
+
+ /**
+ * @return the number of samples-per-pixel or zero if non-MSAA.
+ */
+ int numSamples() const { return fSampleCnt; }
+
+ /**
+ * Call to indicate the multisample contents were modified such that the
+ * render target needs to be resolved before it can be used as texture. Gr
+ * tracks this for its own drawing and thus this only needs to be called
+ * when the render target has been modified outside of Gr. Only meaningful
+ * for Gr-created RT/Textures and Platform RT/Textures created with the
+ * kGrCanResolve flag.
+ * @param rect a rect bounding the area needing resolve. NULL indicates
+ * the whole RT needs resolving.
+ */
+ void flagAsNeedingResolve(const GrIRect* rect = NULL);
+
+ /**
+ * Call to override the region that needs to be resolved.
+ */
+ void overrideResolveRect(const GrIRect rect);
+
+ /**
+ * Call to indicate that GrRenderTarget was externally resolved. This may
+ * allow Gr to skip a redundant resolve step.
+ */
+ void flagAsResolved() { fResolveRect.setLargestInverted(); }
+
+ /**
+ * @return true if the GrRenderTarget requires MSAA resolving
+ */
+ bool needsResolve() const { return !fResolveRect.isEmpty(); }
+
+ /**
+ * Returns a rect bounding the region needing resolving.
+ */
+ const GrIRect& getResolveRect() const { return fResolveRect; }
+
+ // GrResource overrides
+ virtual size_t sizeInBytes() const;
+
+ /**
+ * Reads a rectangle of pixels from the render target.
+ * @param left left edge of the rectangle to read (inclusive)
+ * @param top top edge of the rectangle to read (inclusive)
+ * @param width width of rectangle to read in pixels.
+ * @param height height of rectangle to read in pixels.
+ * @param config the pixel config of the destination buffer
+ * @param buffer memory to read the rectangle into.
+ * @param rowBytes number of bytes bewtween consecutive rows. Zero
+ * means rows are tightly packed.
+ *
+ * @return true if the read succeeded, false if not. The read can fail
+ * because of an unsupported pixel config.
+ */
+ bool readPixels(int left, int top, int width, int height,
+ GrPixelConfig config, void* buffer, size_t rowBytes);
+
+ /**
+ * Copy the src pixels [buffer, rowbytes, pixelconfig] into the render
+ * target at the specified rectangle.
+ * @param left left edge of the rectangle to write (inclusive)
+ * @param top top edge of the rectangle to write (inclusive)
+ * @param width width of rectangle to write in pixels.
+ * @param height height of rectangle to write in pixels.
+ * @param config the pixel config of the source buffer
+ * @param buffer memory to read the rectangle from.
+ * @param rowBytes number of bytes bewtween consecutive rows. Zero
+ * means rows are tightly packed.
+ */
+ void writePixels(int left, int top, int width, int height,
+ GrPixelConfig config, const void* buffer, size_t rowBytes);
+
+ // a MSAA RT may require explicit resolving , it may auto-resolve (e.g. FBO
+ // 0 in GL), or be unresolvable because the client didn't give us the
+ // resolve destination.
+ enum ResolveType {
+ kCanResolve_ResolveType,
+ kAutoResolves_ResolveType,
+ kCantResolve_ResolveType,
+ };
+ virtual ResolveType getResolveType() const = 0;
+
+ /**
+ * GrStencilBuffer is not part of the public API.
+ */
+ GrStencilBuffer* getStencilBuffer() const { return fStencilBuffer; }
+ void setStencilBuffer(GrStencilBuffer* stencilBuffer);
+
+protected:
+ GrRenderTarget(GrGpu* gpu,
+ GrTexture* texture,
+ int width,
+ int height,
+ GrPixelConfig config,
+ int sampleCnt)
+ : INHERITED(gpu)
+ , fStencilBuffer(NULL)
+ , fTexture(texture)
+ , fWidth(width)
+ , fHeight(height)
+ , fConfig(config)
+ , fSampleCnt(sampleCnt) {
+ fResolveRect.setLargestInverted();
+ }
+
+ friend class GrTexture;
+ // When a texture unrefs an owned rendertarget this func
+ // removes the back pointer. This could be done called from
+ // texture's destructor but would have to be done in derived
+ // class. By the time of texture base destructor it has already
+ // lost its pointer to the rt.
+ void onTextureReleaseRenderTarget() {
+ GrAssert(NULL != fTexture);
+ fTexture = NULL;
+ }
+
+private:
+ GrStencilBuffer* fStencilBuffer;
+ GrTexture* fTexture; // not ref'ed
+ int fWidth;
+ int fHeight;
+ GrPixelConfig fConfig;
+ int fSampleCnt;
+ GrIRect fResolveRect;
+
+ typedef GrResource INHERITED;
+};
+
+#endif
diff --git a/gpu/include/GrResource.h b/include/gpu/GrResource.h
index 8cc4d57..e003353 100644
--- a/gpu/include/GrResource.h
+++ b/include/gpu/GrResource.h
@@ -1,25 +1,19 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrResource_DEFINED
#define GrResource_DEFINED
#include "GrRefCnt.h"
class GrGpu;
+class GrContext;
class GrResource : public GrRefCnt {
public:
@@ -54,6 +48,23 @@ public:
*/
bool isValid() const { return NULL != fGpu; }
+ /**
+ * Retrieves the size of the object in GPU memory. This is approximate since
+ * we aren't aware of additional padding or copies made by the driver.
+ *
+ * @return the size of the buffer in bytes
+ */
+ virtual size_t sizeInBytes() const = 0;
+
+ /**
+ * Retrieves the context that owns the resource. Note that it is possible
+ * for this to return NULL. When resources have been release()ed or
+ * abandon()ed they no longer have an unknowning context. Destroying a
+ * GrContext automatically releases all its resources.
+ */
+ const GrContext* getContext() const;
+ GrContext* getContext();
+
protected:
virtual void onRelease() = 0;
diff --git a/gpu/include/GrSamplerState.h b/include/gpu/GrSamplerState.h
index 373ea94..81dfdb3 100644
--- a/gpu/include/GrSamplerState.h
+++ b/include/gpu/GrSamplerState.h
@@ -1,26 +1,21 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrSamplerState_DEFINED
#define GrSamplerState_DEFINED
#include "GrTypes.h"
#include "GrMatrix.h"
+#define MAX_KERNEL_WIDTH 25
+
class GrSamplerState {
public:
enum Filter {
@@ -36,9 +31,16 @@ public:
* Average of 4 bilinear filterings spaced +/- 1 texel from sample
* position in x and y. Intended for averaging 16 texels in a downsample
* pass. (rasterizing such that texture samples fall exactly halfway
- * between texels in x and y spaced 4 texels apart.)
+ * between texels in x and y spaced 4 texels apart.) Only supported
+ * on shader backends.
*/
k4x4Downsample_Filter,
+ /**
+ * Apply a separable convolution kernel.
+ */
+ kConvolution_Filter,
+
+ kDefault_Filter = kNearest_Filter
};
/**
@@ -68,6 +70,8 @@ public:
kRadial_SampleMode, //!< treat as radial gradient
kRadial2_SampleMode, //!< treat as 2-point radial gradient
kSweep_SampleMode, //!< treat as sweep gradient
+
+ kDefault_SampleMode = kNormal_SampleMode
};
/**
@@ -77,53 +81,20 @@ public:
enum WrapMode {
kClamp_WrapMode,
kRepeat_WrapMode,
- kMirror_WrapMode
+ kMirror_WrapMode,
+
+ kDefault_WrapMode = kClamp_WrapMode
};
/**
* Default sampler state is set to clamp, use normal sampling mode, be
* unfiltered, and use identity matrix.
*/
- GrSamplerState() {
- this->setClampNoFilter();
- }
-
- explicit GrSamplerState(Filter filter) {
- fWrapX = kClamp_WrapMode;
- fWrapY = kClamp_WrapMode;
- fSampleMode = kNormal_SampleMode;
- fFilter = filter;
- fMatrix.setIdentity();
- fTextureDomain.setEmpty();
- }
-
- GrSamplerState(WrapMode wx, WrapMode wy, Filter filter) {
- fWrapX = wx;
- fWrapY = wy;
- fSampleMode = kNormal_SampleMode;
- fFilter = filter;
- fMatrix.setIdentity();
- fTextureDomain.setEmpty();
- }
-
- GrSamplerState(WrapMode wx, WrapMode wy,
- const GrMatrix& matrix, Filter filter) {
- fWrapX = wx;
- fWrapY = wy;
- fSampleMode = kNormal_SampleMode;
- fFilter = filter;
- fMatrix = matrix;
- fTextureDomain.setEmpty();
- }
-
- GrSamplerState(WrapMode wx, WrapMode wy, SampleMode sample,
- const GrMatrix& matrix, Filter filter) {
- fWrapX = wx;
- fWrapY = wy;
- fSampleMode = sample;
- fMatrix = matrix;
- fFilter = filter;
- fTextureDomain.setEmpty();
+ GrSamplerState()
+ : fRadial2CenterX1()
+ , fRadial2Radius0()
+ , fRadial2PosRoot() {
+ this->reset();
}
WrapMode getWrapX() const { return fWrapX; }
@@ -133,6 +104,10 @@ public:
const GrRect& getTextureDomain() const { return fTextureDomain; }
bool hasTextureDomain() const {return SkIntToScalar(0) != fTextureDomain.right();}
Filter getFilter() const { return fFilter; }
+ int getKernelWidth() const { return fKernelWidth; }
+ const float* getKernel() const { return fKernel; }
+ const float* getImageIncrement() const { return fImageIncrement; }
+ bool swapsRAndB() const { return fSwapRAndB; }
bool isGradient() const {
return kRadial_SampleMode == fSampleMode ||
@@ -145,12 +120,11 @@ public:
void setSampleMode(SampleMode mode) { fSampleMode = mode; }
/**
- * Sets the sampler's matrix. See SampleMode for explanation of
+ * Access the sampler's matrix. See SampleMode for explanation of
* relationship between the matrix and sample mode.
- * @param matrix the matrix to set
*/
- void setMatrix(const GrMatrix& matrix) { fMatrix = matrix; }
-
+ GrMatrix* matrix() { return &fMatrix; }
+
/**
* Sets the sampler's texture coordinate domain to a
* custom rectangle, rather than the default (0,1).
@@ -159,6 +133,12 @@ public:
void setTextureDomain(const GrRect& textureDomain) { fTextureDomain = textureDomain; }
/**
+ * Swaps the R and B components when reading from the texture. Has no effect
+ * if the texture is alpha only.
+ */
+ void setRAndBSwap(bool swap) { fSwapRAndB = swap; }
+
+ /**
* Multiplies the current sampler matrix a matrix
*
* After this call M' = M*m where M is the old matrix, m is the parameter
@@ -176,18 +156,34 @@ public:
*/
void setFilter(Filter filter) { fFilter = filter; }
- void setClampNoFilter() {
- fWrapX = kClamp_WrapMode;
- fWrapY = kClamp_WrapMode;
- fSampleMode = kNormal_SampleMode;
- fFilter = kNearest_Filter;
- fMatrix.setIdentity();
+ void reset(WrapMode wrapXAndY,
+ Filter filter,
+ const GrMatrix& matrix) {
+ fWrapX = wrapXAndY;
+ fWrapY = wrapXAndY;
+ fSampleMode = kDefault_SampleMode;
+ fFilter = filter;
+ fMatrix = matrix;
fTextureDomain.setEmpty();
+ fSwapRAndB = false;
+ }
+ void reset(WrapMode wrapXAndY,
+ Filter filter) {
+ this->reset(wrapXAndY, filter, GrMatrix::I());
+ }
+ void reset(const GrMatrix& matrix) {
+ this->reset(kDefault_WrapMode, kDefault_Filter, matrix);
+ }
+ void reset() {
+ this->reset(kDefault_WrapMode, kDefault_Filter, GrMatrix::I());
}
GrScalar getRadial2CenterX1() const { return fRadial2CenterX1; }
GrScalar getRadial2Radius0() const { return fRadial2Radius0; }
- bool isRadial2PosRoot() const { return fRadial2PosRoot; }
+ bool isRadial2PosRoot() const { return SkToBool(fRadial2PosRoot); }
+ // do the radial gradient params lead to a linear (rather than quadratic)
+ // equation.
+ bool radial2IsDegenerate() const { return GR_Scalar1 == fRadial2CenterX1; }
/**
* Sets the parameters for kRadial2_SampleMode. The texture
@@ -202,24 +198,37 @@ public:
fRadial2PosRoot = posRoot;
}
- static const GrSamplerState& ClampNoFilter() {
- return gClampNoFilter;
+ void setConvolutionParams(int kernelWidth, const float* kernel, float imageIncrement[2]) {
+ GrAssert(kernelWidth >= 0 && kernelWidth <= MAX_KERNEL_WIDTH);
+ fKernelWidth = kernelWidth;
+ if (NULL != kernel) {
+ memcpy(fKernel, kernel, kernelWidth * sizeof(float));
+ }
+ if (NULL != imageIncrement) {
+ memcpy(fImageIncrement, imageIncrement, sizeof(fImageIncrement));
+ } else {
+ memset(fImageIncrement, 0, sizeof(fImageIncrement));
+ }
}
private:
- WrapMode fWrapX;
- WrapMode fWrapY;
- SampleMode fSampleMode;
- Filter fFilter;
+ WrapMode fWrapX : 8;
+ WrapMode fWrapY : 8;
+ SampleMode fSampleMode : 8;
+ Filter fFilter : 8;
GrMatrix fMatrix;
+ bool fSwapRAndB;
GrRect fTextureDomain;
// these are undefined unless fSampleMode == kRadial2_SampleMode
GrScalar fRadial2CenterX1;
GrScalar fRadial2Radius0;
- bool fRadial2PosRoot;
+ SkBool8 fRadial2PosRoot;
- static const GrSamplerState gClampNoFilter;
+ // These are undefined unless fFilter == kConvolution_Filter
+ uint8_t fKernelWidth;
+ float fImageIncrement[2];
+ float fKernel[MAX_KERNEL_WIDTH];
};
#endif
diff --git a/gpu/include/GrScalar.h b/include/gpu/GrScalar.h
index 35cd61a..4ffc4ca 100644
--- a/gpu/include/GrScalar.h
+++ b/include/gpu/GrScalar.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrScalar_DEFINED
#define GrScalar_DEFINED
@@ -39,7 +32,8 @@
#define GrIntToScalar(a) SkIntToScalar(a)
#define GrScalarHalf(a) SkScalarHalf(a)
#define GrScalarAve(a,b) SkScalarAve(a,b)
-#define GrMul(a,b) SkScalarMul(a,b)
+#define GrMul(a,b) SkScalarMul(a,b) // deprecated, prefer GrScalarMul
+#define GrScalarMul(a,b) SkScalarMul(a,b)
#define GrScalarDiv(a,b) SkScalarDiv(a, b)
#define GrScalarToFloat(a) SkScalarToFloat(a)
#define GrFloatToScalar(a) SkScalarToFloat(a)
diff --git a/include/gpu/GrTemplates.h b/include/gpu/GrTemplates.h
new file mode 100644
index 0000000..63e43ee
--- /dev/null
+++ b/include/gpu/GrTemplates.h
@@ -0,0 +1,69 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrTemplates_DEFINED
+#define GrTemplates_DEFINED
+
+#include "GrNoncopyable.h"
+
+/**
+ * Use to cast a ptr to a different type, and maintain strict-aliasing
+ */
+template <typename Dst, typename Src> Dst GrTCast(Src src) {
+ union {
+ Src src;
+ Dst dst;
+ } data;
+ data.src = src;
+ return data.dst;
+}
+
+/**
+ * saves value of T* in and restores in destructor
+ * e.g.:
+ * {
+ * GrAutoTPtrValueRestore<int*> autoCountRestore;
+ * if (useExtra) {
+ * autoCountRestore.save(&fCount);
+ * fCount += fExtraCount;
+ * }
+ * ...
+ * } // fCount is restored
+ */
+template <typename T> class GrAutoTPtrValueRestore : public GrNoncopyable {
+public:
+ GrAutoTPtrValueRestore() : fPtr(NULL), fVal() {}
+
+ GrAutoTPtrValueRestore(T* ptr) {
+ fPtr = ptr;
+ if (NULL != ptr) {
+ fVal = *ptr;
+ }
+ }
+
+ ~GrAutoTPtrValueRestore() {
+ if (NULL != fPtr) {
+ *fPtr = fVal;
+ }
+ }
+
+ // restores previously saved value (if any) and saves value for passed T*
+ void save(T* ptr) {
+ if (NULL != fPtr) {
+ *fPtr = fVal;
+ }
+ fPtr = ptr;
+ fVal = *ptr;
+ }
+private:
+ T* fPtr;
+ T fVal;
+};
+
+#endif
diff --git a/gpu/include/GrTextContext.h b/include/gpu/GrTextContext.h
index b7a690e..5983e35 100644
--- a/gpu/include/GrTextContext.h
+++ b/include/gpu/GrTextContext.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrTextContext_DEFINED
#define GrTextContext_DEFINED
@@ -51,6 +44,7 @@ private:
GrTextStrike* fStrike;
inline void flushGlyphs();
+ void setupDrawTarget();
enum {
kMinRequestedGlyphs = 1,
diff --git a/include/gpu/GrTexture.h b/include/gpu/GrTexture.h
new file mode 100644
index 0000000..8274140
--- /dev/null
+++ b/include/gpu/GrTexture.h
@@ -0,0 +1,160 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrTexture_DEFINED
+#define GrTexture_DEFINED
+
+#include "GrResource.h"
+
+class GrRenderTarget;
+
+class GrTexture : public GrResource {
+
+public:
+ /**
+ * Retrieves the width of the texture.
+ *
+ * @return the width in texels
+ */
+ int width() const { return fWidth; }
+
+ /**
+ * Retrieves the height of the texture.
+ *
+ * @return the height in texels
+ */
+ int height() const { return fHeight; }
+
+ /**
+ * Convert from texels to normalized texture coords for POT textures
+ * only.
+ */
+ GrFixed normalizeFixedX(GrFixed x) const { GrAssert(GrIsPow2(fWidth));
+ return x >> fShiftFixedX; }
+ GrFixed normalizeFixedY(GrFixed y) const { GrAssert(GrIsPow2(fHeight));
+ return y >> fShiftFixedY; }
+
+ /**
+ * Retrieves the pixel config specified when the texture was created.
+ */
+ GrPixelConfig config() const { return fConfig; }
+
+ /**
+ * Approximate number of bytes used by the texture
+ */
+ virtual size_t sizeInBytes() const {
+ return (size_t) fWidth * fHeight * GrBytesPerPixel(fConfig);
+ }
+
+ /**
+ * Read a rectangle of pixels from the texture.
+ * @param left left edge of the rectangle to read (inclusive)
+ * @param top top edge of the rectangle to read (inclusive)
+ * @param width width of rectangle to read in pixels.
+ * @param height height of rectangle to read in pixels.
+ * @param config the pixel config of the destination buffer
+ * @param buffer memory to read the rectangle into.
+ * @param rowBytes number of bytes bewtween consecutive rows. Zero
+ * means rows are tightly packed.
+ *
+ * @return true if the read succeeded, false if not. The read can fail
+ * because of a unsupported pixel config.
+ */
+ bool readPixels(int left, int top, int width, int height,
+ GrPixelConfig config, void* buffer,
+ size_t rowBytes);
+
+ /**
+ * Writes a rectangle of pixels to the texture.
+ * @param left left edge of the rectangle to write (inclusive)
+ * @param top top edge of the rectangle to write (inclusive)
+ * @param width width of rectangle to write in pixels.
+ * @param height height of rectangle to write in pixels.
+ * @param config the pixel config of the source buffer
+ * @param buffer memory to read pixels from
+ * @param rowBytes number of bytes bewtween consecutive rows. Zero
+ * means rows are tightly packed.
+ */
+ void writePixels(int left, int top, int width, int height,
+ GrPixelConfig config, const void* buffer,
+ size_t rowBytes);
+
+ /**
+ * Retrieves the render target underlying this texture that can be passed to
+ * GrGpu::setRenderTarget().
+ *
+ * @return handle to render target or NULL if the texture is not a
+ * render target
+ */
+ GrRenderTarget* asRenderTarget() { return fRenderTarget; }
+
+ /**
+ * Removes the reference on the associated GrRenderTarget held by this
+ * texture. Afterwards asRenderTarget() will return NULL. The
+ * GrRenderTarget survives the release if another ref is held on it.
+ */
+ void releaseRenderTarget();
+
+ /**
+ * Return the native ID or handle to the texture, depending on the
+ * platform. e.g. on opengl, return the texture ID.
+ */
+ virtual intptr_t getTextureHandle() const = 0;
+
+#if GR_DEBUG
+ void validate() const {
+ this->INHERITED::validate();
+ }
+#else
+ void validate() const {}
+#endif
+
+protected:
+ GrRenderTarget* fRenderTarget; // texture refs its rt representation
+ // base class cons sets to NULL
+ // subclass cons can create and set
+
+ GrTexture(GrGpu* gpu,
+ int width,
+ int height,
+ GrPixelConfig config)
+ : INHERITED(gpu)
+ , fRenderTarget(NULL)
+ , fWidth(width)
+ , fHeight(height)
+ , fConfig(config) {
+ // only make sense if alloc size is pow2
+ fShiftFixedX = 31 - Gr_clz(fWidth);
+ fShiftFixedY = 31 - Gr_clz(fHeight);
+ }
+
+ // GrResource overrides
+ virtual void onRelease() {
+ this->releaseRenderTarget();
+ }
+
+ virtual void onAbandon();
+
+private:
+ int fWidth;
+ int fHeight;
+
+ // these two shift a fixed-point value into normalized coordinates
+ // for this texture if the texture is power of two sized.
+ int fShiftFixedX;
+ int fShiftFixedY;
+
+ GrPixelConfig fConfig;
+
+ typedef GrResource INHERITED;
+};
+
+#endif
+
diff --git a/gpu/include/GrTypes.h b/include/gpu/GrTypes.h
index 9348375..0bcab7d 100644
--- a/gpu/include/GrTypes.h
+++ b/include/gpu/GrTypes.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrTypes_DEFINED
#define GrTypes_DEFINED
@@ -28,22 +21,32 @@
* bitfield.
*/
#define GR_MAKE_BITFIELD_OPS(X) \
- static inline X operator | (X a, X b) { \
+ inline X operator | (X a, X b) { \
return (X) (+a | +b); \
} \
\
- static inline X operator & (X a, X b) { \
+ inline X operator & (X a, X b) { \
return (X) (+a & +b); \
} \
template <typename T> \
- static inline X operator & (T a, X b) { \
+ inline X operator & (T a, X b) { \
return (X) (+a & +b); \
} \
template <typename T> \
- static inline X operator & (X a, T b) { \
+ inline X operator & (X a, T b) { \
return (X) (+a & +b); \
} \
+#define GR_DECL_BITFIELD_OPS_FRIENDS(X) \
+ friend X operator | (X a, X b); \
+ \
+ friend X operator & (X a, X b); \
+ \
+ template <typename T> \
+ friend X operator & (T a, X b); \
+ \
+ template <typename T> \
+ friend X operator & (X a, T b); \
////////////////////////////////////////////////////////////////////////////////
@@ -52,7 +55,7 @@
* n is already a multiple of 4
*/
#define GrALIGN4(n) SkAlign4(n)
-#define GrIsALIGN4(n) (((n) & 3) == 0)
+#define GrIsALIGN4(n) SkIsAlign4(n)
template <typename T> const T& GrMin(const T& a, const T& b) {
return (a < b) ? a : b;
@@ -69,6 +72,10 @@ template <typename T> const T& GrMax(const T& a, const T& b) {
/**
* divide, rounding up
*/
+static inline int32_t GrIDivRoundUp(int x, int y) {
+ GrAssert(y > 0);
+ return (x + (y-1)) / y;
+}
static inline uint32_t GrUIDivRoundUp(uint32_t x, uint32_t y) {
return (x + (y-1)) / y;
}
@@ -142,6 +149,11 @@ static inline uint32_t GrNextPow2(uint32_t n) {
return n ? (1 << (32 - Gr_clz(n - 1))) : 1;
}
+static inline int GrNextPow2(int n) {
+ GrAssert(n >= 0); // this impl only works for non-neg.
+ return n ? (1 << (32 - Gr_clz(n - 1))) : 1;
+}
+
///////////////////////////////////////////////////////////////////////////////
/**
@@ -171,13 +183,11 @@ static inline int16_t GrToS16(intptr_t x) {
enum GrEngine {
kOpenGL_Shaders_GrEngine,
kOpenGL_Fixed_GrEngine,
- kDirect3D9_GrEngine
};
/**
* Engine-specific 3D context handle
- * Unused for GL.
- * IDirect3DDevice9* for D3D9
+ * GrGLInterface* for OpenGL. If NULL will use the default GL interface.
*/
typedef intptr_t GrPlatform3DContext;
@@ -197,8 +207,8 @@ enum GrPrimitiveType {
kTriangleStrip_PrimitiveType,
kTriangleFan_PrimitiveType,
kPoints_PrimitiveType,
- kLines_PrimitiveType,
- kLineStrip_PrimitiveType
+ kLines_PrimitiveType, // 1 pix wide only
+ kLineStrip_PrimitiveType // 1 pix wide only
};
static inline bool GrIsPrimTypeLines(GrPrimitiveType type) {
@@ -238,32 +248,136 @@ enum GrBlendCoeff {
* Important that these are 0-based.
*/
enum GrMaskFormat {
- kA8_GrMaskFormat, //!< 1-byte per pixel
- kA565_GrMaskFormat //!< 2-bytes per pixel
+ kA8_GrMaskFormat, //!< 1-byte per pixel
+ kA565_GrMaskFormat, //!< 2-bytes per pixel
+ kA888_GrMaskFormat, //!< 4-bytes per pixel
+
+ kCount_GrMaskFormats //!< used to allocate arrays sized for mask formats
};
-#define kCount_GrMaskFormats 2
/**
* Return the number of bytes-per-pixel for the specified mask format.
*/
static inline int GrMaskFormatBytesPerPixel(GrMaskFormat format) {
- GrAssert((unsigned)format <= 1);
- return (int)format + 1;
+ GrAssert((unsigned)format <= 2);
+ // kA8 (0) -> 1
+ // kA565 (1) -> 2
+ // kA888 (2) -> 4
+ return 1 << (int)format;
}
/**
* Pixel configurations.
+ *
+ * Unpremultiplied configs are intended for converting pixel data in and out
+ * from skia. Surfaces with these configs have limited support. As an input
+ * (GrPaint texture) the corresponding GrSamplerState must have its filter set
+ * to kNearest_Filter. Otherwise, the draw will fail. When the render target
+ * has an unpremultiplied config draws must use blend coeffs 1,0 (AKA src-mode).
+ * Other coeffs will cause the draw to fail.
*/
enum GrPixelConfig {
kUnknown_GrPixelConfig,
kAlpha_8_GrPixelConfig,
kIndex_8_GrPixelConfig,
kRGB_565_GrPixelConfig,
- kRGBA_4444_GrPixelConfig, //!< premultiplied
- kRGBA_8888_GrPixelConfig, //!< premultiplied
- kRGBX_8888_GrPixelConfig, //!< treat the alpha channel as opaque
+ /**
+ * Premultiplied
+ */
+ kRGBA_4444_GrPixelConfig,
+ /**
+ * Premultiplied. Byte order is r,g,b,a
+ */
+ kRGBA_8888_PM_GrPixelConfig,
+ /**
+ * Unpremultiplied. Byte order is r,g,b,a
+ */
+ kRGBA_8888_UPM_GrPixelConfig,
+ /**
+ * Premultiplied. Byte order is b,g,r,a
+ */
+ kBGRA_8888_PM_GrPixelConfig,
+ /**
+ * Unpremultiplied. Byte order is b,g,r,a
+ */
+ kBGRA_8888_UPM_GrPixelConfig,
};
+// Aliases for pixel configs that match skia's byte order
+#ifndef SK_CPU_LENDIAN
+ #error "Skia gpu currently assumes little endian"
+#endif
+#if 24 == SK_A32_SHIFT && 16 == SK_R32_SHIFT && \
+ 8 == SK_G32_SHIFT && 0 == SK_B32_SHIFT
+ static const GrPixelConfig kSkia8888_PM_GrPixelConfig = kBGRA_8888_PM_GrPixelConfig;
+ static const GrPixelConfig kSkia8888_UPM_GrPixelConfig = kBGRA_8888_UPM_GrPixelConfig;
+#elif 24 == SK_A32_SHIFT && 16 == SK_B32_SHIFT && \
+ 8 == SK_G32_SHIFT && 0 == SK_R32_SHIFT
+ static const GrPixelConfig kSkia8888_PM_GrPixelConfig = kRGBA_8888_PM_GrPixelConfig;
+ static const GrPixelConfig kSkia8888_UPM_GrPixelConfig = kRGBA_8888_UPM_GrPixelConfig;
+#else
+ #error "SK_*32_SHIFT values must correspond to GL_BGRA or GL_RGBA format."
+#endif
+
+// WebKit is relying on this old name for the native skia PM config. This will
+// be deleted ASAP because it is so similar to kRGBA_PM_8888_GrPixelConfig but
+// has a different interpretation when skia is compiled BGRA.
+static const GrPixelConfig kRGBA_8888_GrPixelConfig = kSkia8888_PM_GrPixelConfig;
+
+// Returns true if the pixel config has 8bit r,g,b,a components in that byte
+// order
+static inline bool GrPixelConfigIsRGBA8888(GrPixelConfig config) {
+ switch (config) {
+ case kRGBA_8888_PM_GrPixelConfig:
+ case kRGBA_8888_UPM_GrPixelConfig:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Returns true if the pixel config has 8bit b,g,r,a components in that byte
+// order
+static inline bool GrPixelConfigIsBGRA8888(GrPixelConfig config) {
+ switch (config) {
+ case kBGRA_8888_PM_GrPixelConfig:
+ case kBGRA_8888_UPM_GrPixelConfig:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Returns true if the pixel config is 32 bits per pixel
+static inline bool GrPixelConfigIs32Bit(GrPixelConfig config) {
+ switch (config) {
+ case kRGBA_8888_PM_GrPixelConfig:
+ case kRGBA_8888_UPM_GrPixelConfig:
+ case kBGRA_8888_PM_GrPixelConfig:
+ case kBGRA_8888_UPM_GrPixelConfig:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Takes a config and returns the equivalent config with the R and B order
+// swapped if such a config exists. Otherwise, kUnknown_GrPixelConfig
+static inline GrPixelConfig GrPixelConfigSwapRAndB(GrPixelConfig config) {
+ switch (config) {
+ case kBGRA_8888_PM_GrPixelConfig:
+ return kRGBA_8888_PM_GrPixelConfig;
+ case kBGRA_8888_UPM_GrPixelConfig:
+ return kRGBA_8888_UPM_GrPixelConfig;
+ case kRGBA_8888_PM_GrPixelConfig:
+ return kBGRA_8888_PM_GrPixelConfig;
+ case kRGBA_8888_UPM_GrPixelConfig:
+ return kBGRA_8888_UPM_GrPixelConfig;
+ default:
+ return kUnknown_GrPixelConfig;
+ }
+}
+
static inline size_t GrBytesPerPixel(GrPixelConfig config) {
switch (config) {
case kAlpha_8_GrPixelConfig:
@@ -272,8 +386,10 @@ static inline size_t GrBytesPerPixel(GrPixelConfig config) {
case kRGB_565_GrPixelConfig:
case kRGBA_4444_GrPixelConfig:
return 2;
- case kRGBA_8888_GrPixelConfig:
- case kRGBX_8888_GrPixelConfig:
+ case kRGBA_8888_PM_GrPixelConfig:
+ case kRGBA_8888_UPM_GrPixelConfig:
+ case kBGRA_8888_PM_GrPixelConfig:
+ case kBGRA_8888_UPM_GrPixelConfig:
return 4;
default:
return 0;
@@ -283,7 +399,20 @@ static inline size_t GrBytesPerPixel(GrPixelConfig config) {
static inline bool GrPixelConfigIsOpaque(GrPixelConfig config) {
switch (config) {
case kRGB_565_GrPixelConfig:
- case kRGBX_8888_GrPixelConfig:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Premultiplied alpha is the usual for skia. Therefore, configs that are
+ * ambiguous (alpha-only or color-only) are considered premultiplied.
+ */
+static inline bool GrPixelConfigIsUnpremultiplied(GrPixelConfig config) {
+ switch (config) {
+ case kRGBA_8888_UPM_GrPixelConfig:
+ case kBGRA_8888_UPM_GrPixelConfig:
return true;
default:
return false;
@@ -355,13 +484,13 @@ struct GrTextureDesc {
* fFlags contains kRenderTarget_GrTextureFlag.
*/
GrAALevels fAALevel;
- uint32_t fWidth; //!< Width of the texture
- uint32_t fHeight; //!< Height of the texture
+ int fWidth; //!< Width of the texture
+ int fHeight; //!< Height of the texture
/**
* Format of source data of the texture. Not guaraunteed to be the same as
* internal format used by 3D API.
*/
- GrPixelConfig fFormat;
+ GrPixelConfig fConfig;
};
/**
@@ -430,7 +559,7 @@ enum GrPathFill {
kPathFillCount
};
-static inline GrPathFill NonInvertedFill(GrPathFill fill) {
+static inline GrPathFill GrNonInvertedFill(GrPathFill fill) {
static const GrPathFill gNonInvertedFills[] = {
kWinding_PathFill, // kWinding_PathFill
kEvenOdd_PathFill, // kEvenOdd_PathFill
@@ -447,7 +576,7 @@ static inline GrPathFill NonInvertedFill(GrPathFill fill) {
return gNonInvertedFills[fill];
}
-static inline bool IsFillInverted(GrPathFill fill) {
+static inline bool GrIsFillInverted(GrPathFill fill) {
static const bool gIsFillInverted[] = {
false, // kWinding_PathFill
false, // kEvenOdd_PathFill
@@ -484,6 +613,99 @@ enum GrConvexHint {
///////////////////////////////////////////////////////////////////////////////
+// opaque type for 3D API object handles
+typedef intptr_t GrPlatform3DObject;
+
+/**
+ * Gr can wrap an existing texture created by the client with a GrTexture
+ * object. The client is responsible for ensuring that the texture lives at
+ * least as long as the GrTexture object wrapping it. We require the client to
+ * explicitly provide information about the texture, such as width, height,
+ * and pixel config, rather than querying the 3D APIfor these values. We expect
+ * these to be immutable even if the 3D API doesn't require this (OpenGL).
+ *
+ * Textures that are also render targets are supported as well. Gr will manage
+ * any ancillary 3D API (stencil buffer, FBO id, etc) objects necessary for
+ * Gr to draw into the render target. To access the render target object
+ * call GrTexture::asRenderTarget().
+ *
+ * If in addition to the render target flag, the caller also specifies a sample
+ * count Gr will create an MSAA buffer that resolves into the texture. Gr auto-
+ * resolves when it reads from the texture. The client can explictly resolve
+ * using the GrRenderTarget interface.
+ */
+
+enum GrPlatformTextureFlags {
+ /**
+ * No flags enabled
+ */
+ kNone_GrPlatformTextureFlag = 0x0,
+ /**
+ * Indicates that the texture is also a render target, and thus should have
+ * a GrRenderTarget object.
+ *
+ * D3D (future): client must have created the texture with flags that allow
+ * it to be used as a render target.
+ */
+ kRenderTarget_GrPlatformTextureFlag = 0x1,
+};
+GR_MAKE_BITFIELD_OPS(GrPlatformTextureFlags)
+
+struct GrPlatformTextureDesc {
+ GrPlatformTextureDesc() { memset(this, 0, sizeof(*this)); }
+ GrPlatformTextureFlags fFlags;
+ int fWidth; //<! width in pixels
+ int fHeight; //<! height in pixels
+ GrPixelConfig fConfig; //<! color format
+ /**
+ * If the render target flag is set and sample count is greater than 0
+ * then Gr will create an MSAA buffer that resolves to the texture.
+ */
+ int fSampleCnt;
+ /**
+ * Handle to the 3D API object.
+ * OpenGL: Texture ID.
+ */
+ GrPlatform3DObject fTextureHandle;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Gr can wrap an existing render target created by the client in the 3D API
+ * with a GrRenderTarget object. The client is responsible for ensuring that the
+ * underlying 3D API object lives at least as long as the GrRenderTarget object
+ * wrapping it. We require the client to explicitly provide information about
+ * the target, such as width, height, and pixel config rather than querying the
+ * 3D API for these values. We expect these properties to be immutable even if
+ * the 3D API doesn't require this (OpenGL).
+ */
+
+struct GrPlatformRenderTargetDesc {
+ GrPlatformRenderTargetDesc() { memset(this, 0, sizeof(*this)); }
+ int fWidth; //<! width in pixels
+ int fHeight; //<! height in pixels
+ GrPixelConfig fConfig; //<! color format
+ /**
+ * The number of samples per pixel. Gr uses this to influence decisions
+ * about applying other forms of antialiasing.
+ */
+ int fSampleCnt;
+ /**
+ * Number of bits of stencil per-pixel.
+ */
+ int fStencilBits;
+ /**
+ * Handle to the 3D API object.
+ * OpenGL: FBO ID
+ */
+ GrPlatform3DObject fRenderTargetHandle;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// DEPRECATED. createPlatformSurface is replaced by createPlatformTexture
+// and createPlatformRenderTarget. These enums and structs will be removed.
+
enum GrPlatformSurfaceType {
/**
* Specifies that the object being created is a render target.
@@ -502,10 +724,7 @@ enum GrPlatformSurfaceType {
enum GrPlatformRenderTargetFlags {
kNone_GrPlatformRenderTargetFlagBit = 0x0,
- /**
- * Specifies that the object being created is multisampled.
- */
- kIsMultisampled_GrPlatformRenderTargetFlagBit = 0x1,
+
/**
* Gives permission to Gr to perform the downsample-resolve of a
* multisampled render target. If this is not set then read pixel
@@ -520,12 +739,6 @@ enum GrPlatformRenderTargetFlags {
GR_MAKE_BITFIELD_OPS(GrPlatformRenderTargetFlags)
-// opaque type for 3D API object handles
-typedef intptr_t GrPlatform3DObject;
-
-/**
- * Description of platform surface to create. See below for GL example.
- */
struct GrPlatformSurfaceDesc {
GrPlatformSurfaceType fSurfaceType; // type of surface to create
/**
@@ -541,6 +754,13 @@ struct GrPlatformSurfaceDesc {
* set in fFlags.
*/
int fStencilBits;
+
+ /**
+ * Number of samples per-pixel. Only relevant if kIsRenderTarget is set in
+ * fFlags.
+ */
+ int fSampleCnt;
+
/**
* Texture object in 3D API. Only relevant if fSurfaceType is kTexture or
* kTextureRenderTarget.
@@ -596,11 +816,12 @@ struct GrPlatformSurfaceDesc {
*
* GrPlatformSurfaceDesc renderTargetTextureDesc;
* renderTargetTextureDesc.fSurfaceType = kTextureRenderTarget_GrPlatformSurfaceType;
- * renderTargetTextureDesc.fRenderTargetFlags = (kIsMultisampled_GrPlatformRenderTargetFlagBit | kGrCanResolve_GrPlatformRenderTargetFlagBit);
+ * renderTargetTextureDesc.fRenderTargetFlags = kGrCanResolve_GrPlatformRenderTargetFlagBit;
* renderTargetTextureDesc.fWidth = W;
* renderTargetTextureDesc.fHeight = H;
- * renderTargetTextureDesc.fConfig = kRGBA_8888_GrPixelConfig
+ * renderTargetTextureDesc.fConfig = kSkia8888_PM_GrPixelConfig
* renderTargetTextureDesc.fStencilBits = 8;
+ * renderTargetTextureDesc.fSampleCnt = S;
* renderTargetTextureDesc.fPlatformTexture = textureID;
* renderTargetTextureDesc.fPlatformRenderTarget = drawFBOID;
* renderTargetTextureDesc.fPlatformResolveDestination = readFBOID;
diff --git a/gpu/include/GrUserConfig.h b/include/gpu/GrUserConfig.h
index 201d836..657f74f 100644
--- a/gpu/include/GrUserConfig.h
+++ b/include/gpu/GrUserConfig.h
@@ -1,19 +1,12 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrUserConfig_DEFINED
#define GrUserConfig_DEFINED
@@ -29,27 +22,12 @@
#endif
/*
- * The default 32bit pixel config for texture upload is GL_RGBA on all
- * platforms except on Windows where it is GL_BGRA. If your bitmaps map to a
- * different GL enum, specify that with this define. For portability use
- * GR_BGRA rather than GL_BGRA for platforms where this format is an
- * extension.
- */
-//#define GR_GL_32BPP_COLOR_FORMAT GL_RGBA
-
-/*
* To diagnose texture cache performance, define this to 1 if you want to see
* a log statement everytime we upload an image to create a texture.
*/
//#define GR_DUMP_TEXTURE_UPLOAD 1
/*
- * To log all GL calls define this. Can be turned on and off at runtime by
- * gPrintGL global variable.
- */
-//#define GR_GL_LOG_CALLS 1
-
-/*
* When drawing rects this causes Ganesh to use a vertex buffer containing
* a unit square that is positioned by a matrix. Enable on systems where
* emitting per-rect-draw verts is more expensive than constant/matrix
@@ -65,17 +43,12 @@
/*
* This gives a threshold in bytes of when to lock a GrGeometryBuffer vs using
- * updateData or updateSubData. (Note the depending on the underlying 3D API
- * the update functions may always be implemented using a lock)
+ * updateData. (Note the depending on the underlying 3D API the update functions
+ * may always be implemented using a lock)
*/
//#define GR_GEOM_BUFFER_LOCK_THRESHOLD (1<<15)
///////////////////////////////////////////////////////////////////////////////
-/*
- * temporary flags (may go away soon)
- */
-
-///////////////////////////////////////////////////////////////////////////////
// Decide Ganesh types
#define GR_SCALAR_IS_FIXED 0
diff --git a/include/gpu/SkGLContext.h b/include/gpu/SkGLContext.h
new file mode 100644
index 0000000..f92a770
--- /dev/null
+++ b/include/gpu/SkGLContext.h
@@ -0,0 +1,59 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef SkGLContext_DEFINED
+#define SkGLContext_DEFINED
+
+#include "GrGLInterface.h"
+
+/**
+ * Create an offscreen opengl context with an RGBA8 / 8bit stencil FBO.
+ * Provides a GrGLInterface struct of function pointers for the context.
+ */
+
+class SkGLContext : public SkRefCnt {
+public:
+ SkGLContext();
+ virtual ~SkGLContext();
+
+ /**
+ * Initializes the context and makes it current.
+ */
+ bool init(const int width, const int height);
+
+ int getFBOID() const { return fFBO; }
+
+ const GrGLInterface* gl() const { return fGL; }
+
+ virtual void makeCurrent() const = 0;
+
+protected:
+ /**
+ * Subclass implements this to make a GL context. The returned GrGLInterface
+ * should be populated with functions compatible with the context. The
+ * format and size of backbuffers does not matter since an FBO will be
+ * created.
+ */
+ virtual const GrGLInterface* createGLContext() = 0;
+
+ /**
+ * Subclass should destroy the underlying GL context.
+ */
+ virtual void destroyGLContext() = 0;
+
+private:
+ GrGLuint fFBO;
+ const GrGLInterface* fGL;
+};
+
+/**
+ * Helper macro for using the GL context through the GrGLInterface. Example:
+ * SK_GL(glCtx, GenTextures(1, &texID));
+ */
+#define SK_GL(ctx, X) (ctx).gl()->f ## X
+
+#endif
diff --git a/include/gpu/SkGpuCanvas.h b/include/gpu/SkGpuCanvas.h
index 57a4b1b..825c567 100644
--- a/include/gpu/SkGpuCanvas.h
+++ b/include/gpu/SkGpuCanvas.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkGpuCanvas_DEFINED
#define SkGpuCanvas_DEFINED
@@ -36,10 +29,6 @@ public:
* GrRenderTarget represents the rendering destination in the underlying
* 3D API. Its reference count is incremented in the constructor and
* decremented in the destructor.
- * SkGpuDevice::Current3DApiRenderTarget() can be passed as a special
- * value that will cause the factory to create a render target object
- * that reflects the state of the underlying 3D API at the time of
- * construction.
*/
explicit SkGpuCanvas(GrContext*, GrRenderTarget*);
virtual ~SkGpuCanvas();
diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h
index 601da09..6c4285e 100644
--- a/include/gpu/SkGpuDevice.h
+++ b/include/gpu/SkGpuDevice.h
@@ -1,26 +1,21 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkGpuDevice_DEFINED
#define SkGpuDevice_DEFINED
#include "SkGr.h"
+#include "SkBitmap.h"
#include "SkDevice.h"
#include "SkRegion.h"
+#include "GrContext.h"
struct SkDrawProcs;
struct GrSkDrawProcs;
@@ -33,86 +28,81 @@ class GrTextContext;
class SK_API SkGpuDevice : public SkDevice {
public:
/**
- * The SkGpuDevice will render to the GrRenderTarget, or if the paremeter is
- * null it will create its own render target and manage that target's
- * lifetime.
+ * New device that will create an offscreen renderTarget based on the
+ * config, width, height.
+ *
+ * usage is a special flag that should only be set by SkCanvas
+ * internally.
*/
- SkGpuDevice(GrContext*,
- const SkBitmap& bitmap,
- GrRenderTarget* renderTargetOrNull);
+ SkGpuDevice(GrContext*, SkBitmap::Config,
+ int width, int height,
+ SkDevice::Usage usage = SkDevice::kGeneral_Usage);
/**
- * Magic value that can be passed to constructor. Causes
- * the device to infer rendertarget from underlying 3D API (e.g. GL or D3D).
- * This isn't a valid pointer, don't attempt to dereference.
+ * New device that will render to the specified renderTarget.
*/
- static GrRenderTarget* Current3DApiRenderTarget();
-
- virtual ~SkGpuDevice();
-
- GrContext* context() const { return fContext; }
+ SkGpuDevice(GrContext*, GrRenderTarget*);
/**
- * If this device was built for rendering as a layer (i.e. offscreen),
- * then this will return the platform-specific handle to that GPU resource.
- * For example, in OpenGL, this will return the FBO's texture ID.
- * If this device was not built for rendering as a layer, then 0
- * is returned.
+ * New device that will render to the texture (as a rendertarget).
+ * The GrTexture's asRenderTarget() must be non-NULL or device will not
+ * function.
*/
- intptr_t getLayerTextureHandle() const;
+ SkGpuDevice(GrContext*, GrTexture*);
- // call to set the clip to the specified rect
- void scissor(const SkIRect&);
+ virtual ~SkGpuDevice();
+
+ GrContext* context() const { return fContext; }
/**
* Override from SkGpuDevice, so we can set our FBO to be the render target
* The canvas parameter must be a SkGpuCanvas
*/
virtual void gainFocus(SkCanvas*, const SkMatrix&, const SkRegion&,
- const SkClipStack& clipStack);
+ const SkClipStack& clipStack) SK_OVERRIDE;
- virtual SkGpuTexture* accessTexture() { return (SkGpuTexture*)fTexture; }
+ virtual SkGpuRenderTarget* accessRenderTarget() SK_OVERRIDE;
// overrides from SkDevice
- virtual void clear(SkColor color);
- virtual bool readPixels(const SkIRect& srcRect, SkBitmap* bitmap);
- virtual void writePixels(const SkBitmap& bitmap, int x, int y);
+ virtual void clear(SkColor color) SK_OVERRIDE;
+ virtual void writePixels(const SkBitmap& bitmap, int x, int y,
+ SkCanvas::Config8888 config8888) SK_OVERRIDE;
virtual void setMatrixClip(const SkMatrix& matrix, const SkRegion& clip,
- const SkClipStack&);
+ const SkClipStack&) SK_OVERRIDE;
- virtual void drawPaint(const SkDraw&, const SkPaint& paint);
+ virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE;
virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count,
- const SkPoint[], const SkPaint& paint);
+ const SkPoint[], const SkPaint& paint) SK_OVERRIDE;
virtual void drawRect(const SkDraw&, const SkRect& r,
- const SkPaint& paint);
+ const SkPaint& paint) SK_OVERRIDE;
virtual void drawPath(const SkDraw&, const SkPath& path,
const SkPaint& paint, const SkMatrix* prePathMatrix,
- bool pathIsMutable);
+ bool pathIsMutable) SK_OVERRIDE;
virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
const SkIRect* srcRectOrNull,
- const SkMatrix& matrix, const SkPaint& paint);
+ const SkMatrix&, const SkPaint&) SK_OVERRIDE;
virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
int x, int y, const SkPaint& paint);
virtual void drawText(const SkDraw&, const void* text, size_t len,
- SkScalar x, SkScalar y, const SkPaint& paint);
+ SkScalar x, SkScalar y, const SkPaint&) SK_OVERRIDE;
virtual void drawPosText(const SkDraw&, const void* text, size_t len,
const SkScalar pos[], SkScalar constY,
- int scalarsPerPos, const SkPaint& paint);
+ int scalarsPerPos, const SkPaint&) SK_OVERRIDE;
virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len,
const SkPath& path, const SkMatrix* matrix,
- const SkPaint& paint);
+ const SkPaint&) SK_OVERRIDE;
virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount,
const SkPoint verts[], const SkPoint texs[],
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
- const SkPaint& paint);
+ const SkPaint&) SK_OVERRIDE;
virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
- const SkPaint&);
- virtual bool filterTextFlags(const SkPaint& paint, TextFlags*);
+ const SkPaint&) SK_OVERRIDE;
+ virtual bool filterTextFlags(const SkPaint&, TextFlags*) SK_OVERRIDE;
- virtual void flush() { fContext->flush(false); }
+ virtual void flush();
/**
* Make's this device's rendertarget current in the underlying 3D API.
@@ -120,33 +110,46 @@ public:
*/
virtual void makeRenderTargetCurrent();
+ virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
+ const SkMatrix& ctm,
+ SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
+
protected:
- // override
- virtual SkDeviceFactory* onNewDeviceFactory();
-
- class TexCache;
- TexCache* lockCachedTexture(const SkBitmap& bitmap,
- const GrSamplerState& sampler,
- GrTexture** texture,
- bool forDeviceRenderTarget = false);
- void unlockCachedTexture(TexCache*);
+ typedef GrContext::TextureCacheEntry TexCache;
+ enum TexType {
+ kBitmap_TexType,
+ kDeviceRenderTarget_TexType,
+ kSaveLayerDeviceRenderTarget_TexType
+ };
+ TexCache lockCachedTexture(const SkBitmap& bitmap,
+ const GrSamplerState* sampler,
+ TexType type = kBitmap_TexType);
+ bool isBitmapInTextureCache(const SkBitmap& bitmap,
+ const GrSamplerState& sampler) const;
+ void unlockCachedTexture(TexCache);
class SkAutoCachedTexture {
public:
SkAutoCachedTexture();
SkAutoCachedTexture(SkGpuDevice* device,
const SkBitmap& bitmap,
- const GrSamplerState& sampler,
+ const GrSamplerState* sampler,
GrTexture** texture);
~SkAutoCachedTexture();
- GrTexture* set(SkGpuDevice*, const SkBitmap&, const GrSamplerState&);
+ GrTexture* set(SkGpuDevice*, const SkBitmap&, const GrSamplerState*);
private:
SkGpuDevice* fDevice;
- TexCache* fTex;
+ TexCache fTex;
};
friend class SkAutoTexCache;
+
+ // overrides from SkDevice
+ virtual bool onReadPixels(const SkBitmap& bitmap,
+ int x, int y,
+ SkCanvas::Config8888 config8888) SK_OVERRIDE;
+
private:
GrContext* fContext;
@@ -154,11 +157,14 @@ private:
GrSkDrawProcs* fDrawProcs;
// state for our offscreen render-target
- TexCache* fCache;
- GrTexture* fTexture;
- GrRenderTarget* fRenderTarget;
- bool fNeedClear;
- bool fNeedPrepareRenderTarget;
+ TexCache fCache;
+ GrTexture* fTexture;
+ GrRenderTarget* fRenderTarget;
+ bool fNeedClear;
+ bool fNeedPrepareRenderTarget;
+
+ // called from rt and tex cons
+ void initFromRenderTarget(GrContext*, GrRenderTarget*);
// doesn't set the texture/sampler/matrix state
// caller needs to null out GrPaint's texture if
@@ -184,10 +190,20 @@ private:
GrPaint* grPaint,
bool constantColor);
+ // override from SkDevice
+ virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config,
+ int width, int height,
+ bool isOpaque,
+ Usage usage);
+
SkDrawProcs* initDrawForText(GrTextContext*);
bool bindDeviceAsTexture(GrPaint* paint);
void prepareRenderTarget(const SkDraw&);
+ bool shouldTileBitmap(const SkBitmap& bitmap,
+ const GrSamplerState& sampler,
+ const SkIRect* srcRectPtr,
+ int* tileSize) const;
void internalDrawBitmap(const SkDraw&, const SkBitmap&,
const SkIRect&, const SkMatrix&, GrPaint* grPaint);
diff --git a/include/gpu/SkGpuDeviceFactory.h b/include/gpu/SkGpuDeviceFactory.h
deleted file mode 100644
index 6f62ad6..0000000
--- a/include/gpu/SkGpuDeviceFactory.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#ifndef SkGpuDeviceFactory_DEFINED
-#define SkGpuDeviceFactory_DEFINED
-
-#include "SkDevice.h"
-
-class GrContext;
-
-class SK_API SkGpuDeviceFactory : public SkDeviceFactory {
-public:
- /**
- * The constructor will ref() the context, passing it to each device
- * that it creates. It will be unref()'d in the destructor
- * Non-layered devices created by the factory will draw to the
- * rootRenderTarget. rootRenderTarget is ref-counted by the factory.
- * SkGpuDevice::Current3DApiRenderTarget() can be passed as a special
- * value that will cause the factory to create a render target object
- * that reflects the state of the underlying 3D API at the time of
- * construction.
- */
- SkGpuDeviceFactory(GrContext*, GrRenderTarget* rootRenderTarget);
-
- /**
- * When the root layer is both a GrRenderTarget and a GrTexture it
- * is handy to have the factory hang on to a ref to the GrTexture object.
- * This is because the GrTexture has a ref to the GrRenderTarget but not
- * vice-versa.
- */
- SkGpuDeviceFactory(GrContext*, GrTexture* rootRenderTargetTexture);
-
- virtual ~SkGpuDeviceFactory();
-
- virtual SkDevice* newDevice(SkCanvas*, SkBitmap::Config, int width,
- int height, bool isOpaque, bool isLayer);
-
-private:
- GrContext* fContext;
- GrRenderTarget* fRootRenderTarget;
- GrTexture* fRootTexture;
-};
-
-#endif
-
diff --git a/include/gpu/SkGr.h b/include/gpu/SkGr.h
index 65565c9..f4dab53 100644
--- a/include/gpu/SkGr.h
+++ b/include/gpu/SkGr.h
@@ -1,27 +1,20 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkGr_DEFINED
#define SkGr_DEFINED
#include <stddef.h>
// Gr headers
-#include "GrConfig.h"
+#include "GrTypes.h"
#include "GrContext.h"
#include "GrFontScaler.h"
#include "GrClipIterator.h"
@@ -39,37 +32,9 @@
// #error "inconsistent GR_DEBUG and SK_DEBUG"
#endif
-#if GR_SCALAR_IS_FIXED
- #ifdef SK_SCALAR_IS_FIXED
- #define SK_SCALAR_IS_GR_SCALAR 1
- #else
- #define SK_SCALAR_IS_GR_SCALAR 0
- #endif
- #define SkScalarToGrScalar(x) SkScalarToFixed(x)
-
-#elif GR_SCALAR_IS_FLOAT
-
- #ifdef SK_SCALAR_IS_FLOAT
- #define SK_SCALAR_IS_GR_SCALAR 1
- #else
- #define SK_SCALAR_IS_GR_SCALAR 0
- #endif
- #define SkScalarToGrScalar(x) SkScalarToFloat(x)
-
-#else
- #error "Ganesh scalar type not defined"
-#endif
-
////////////////////////////////////////////////////////////////////////////////
// Sk to Gr Type conversions
-// Verify that SkPoint and GrPoint are compatible if using the same scalar type
-#if 0/*SK_SCALAR_IS_GR_SCALAR*/
- GR_STATIC_ASSERT(sizeof(SkPoint) == sizeof(GrPoint));
- GR_STATIC_ASSERT(offsetof(SkPoint,fX) == offsetof(GrPoint,fX)));
- GR_STATIC_ASSERT(offsetof(SkPoint,fY) == offsetof(GrPoint,fY)));
-#endif
-
GR_STATIC_ASSERT((int)GrSamplerState::kClamp_WrapMode == (int)SkShader::kClamp_TileMode);
GR_STATIC_ASSERT((int)GrSamplerState::kRepeat_WrapMode ==(
int)SkShader::kRepeat_TileMode);
@@ -231,10 +196,11 @@ private:
////////////////////////////////////////////////////////////////////////////////
// Helper functions
-GrTextureEntry* sk_gr_create_bitmap_texture(GrContext* ctx,
- GrTextureKey* key,
- const GrSamplerState& sampler,
- const SkBitmap& bitmap);
+static const GrContext::TextureKey gUNCACHED_KEY = ~0;
+GrContext::TextureCacheEntry sk_gr_create_bitmap_texture(GrContext* ctx,
+ GrContext::TextureKey key,
+ const GrSamplerState* sampler,
+ const SkBitmap& bitmap);
#endif
diff --git a/include/gpu/SkGrTexturePixelRef.h b/include/gpu/SkGrTexturePixelRef.h
index 5bc64f5..720f130 100644
--- a/include/gpu/SkGrTexturePixelRef.h
+++ b/include/gpu/SkGrTexturePixelRef.h
@@ -1,53 +1,69 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkGrTexturePixelRef_DEFINED
#define SkGrTexturePixelRef_DEFINED
+#include "SkBitmap.h"
#include "SkPixelRef.h"
-#include "GrGpu.h"
+#include "GrTexture.h"
+#include "GrRenderTarget.h"
+
-class SkGrTexturePixelRef : public SkPixelRef {
+/**
+ * Common baseclass that implements onLockPixels() by calling onReadPixels().
+ * Since it has a copy, it always returns false for onLockPixelsAreWritable().
+ */
+class SkROLockPixelsPixelRef : public SkPixelRef {
+public:
+ SkROLockPixelsPixelRef();
+ virtual ~SkROLockPixelsPixelRef();
+
+protected:
+ // override from SkPixelRef
+ virtual void* onLockPixels(SkColorTable** ptr);
+ virtual void onUnlockPixels();
+ virtual bool onLockPixelsAreWritable() const; // return false;
+
+private:
+ SkBitmap fBitmap;
+ typedef SkPixelRef INHERITED;
+};
+
+/**
+ * PixelRef that wraps a GrTexture
+ */
+class SkGrTexturePixelRef : public SkROLockPixelsPixelRef {
public:
SkGrTexturePixelRef(GrTexture*);
virtual ~SkGrTexturePixelRef();
// override from SkPixelRef
- virtual SkGpuTexture* getTexture() { return (SkGpuTexture*)fTexture; }
+ virtual SkGpuTexture* getTexture();
protected:
// override from SkPixelRef
- virtual void* onLockPixels(SkColorTable** ptr) {
- if (ptr) {
- *ptr = NULL;
- }
- return NULL;
- }
+ virtual bool onReadPixels(SkBitmap* dst, const SkIRect* subset);
// override from SkPixelRef
- virtual void onUnlockPixels() {}
- virtual bool onReadPixels(SkBitmap* dst, const SkIRect* subset);
+ virtual SkPixelRef* deepCopy(SkBitmap::Config dstConfig) SK_OVERRIDE;
private:
GrTexture* fTexture;
- typedef SkPixelRef INHERITED;
+ typedef SkROLockPixelsPixelRef INHERITED;
};
-class SkGrRenderTargetPixelRef : public SkPixelRef {
+/**
+ * PixelRef that wraps a GrRenderTarget
+ */
+class SkGrRenderTargetPixelRef : public SkROLockPixelsPixelRef {
public:
SkGrRenderTargetPixelRef(GrRenderTarget* rt);
virtual ~SkGrRenderTargetPixelRef();
@@ -57,20 +73,14 @@ public:
protected:
// override from SkPixelRef
- virtual void* onLockPixels(SkColorTable** ptr) {
- if (ptr) {
- *ptr = NULL;
- }
- return NULL;
- }
+ virtual bool onReadPixels(SkBitmap* dst, const SkIRect* subset);
// override from SkPixelRef
- virtual void onUnlockPixels() {}
- virtual bool onReadPixels(SkBitmap* dst, const SkIRect* subset);
+ virtual SkPixelRef* deepCopy(SkBitmap::Config dstConfig) SK_OVERRIDE;
private:
GrRenderTarget* fRenderTarget;
- typedef SkPixelRef INHERITED;
+ typedef SkROLockPixelsPixelRef INHERITED;
};
#endif
diff --git a/include/gpu/SkMesaGLContext.h b/include/gpu/SkMesaGLContext.h
new file mode 100644
index 0000000..5c329ff
--- /dev/null
+++ b/include/gpu/SkMesaGLContext.h
@@ -0,0 +1,50 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef SkMesaGLContext_DEFINED
+#define SkMesaGLContext_DEFINED
+
+#include "SkGLContext.h"
+
+#if SK_MESA
+
+class SkMesaGLContext : public SkGLContext {
+private:
+ typedef intptr_t Context;
+
+public:
+ SkMesaGLContext();
+
+ virtual ~SkMesaGLContext();
+
+ virtual void makeCurrent() const SK_OVERRIDE;
+
+ class AutoContextRestore {
+ public:
+ AutoContextRestore();
+ ~AutoContextRestore();
+
+ private:
+ Context fOldContext;
+ GLint fOldWidth;
+ GLint fOldHeight;
+ GLint fOldFormat;
+ void* fOldImage;
+ };
+
+protected:
+ virtual const GrGLInterface* createGLContext() SK_OVERRIDE;
+ virtual void destroyGLContext() SK_OVERRIDE;
+
+private:
+ Context fContext;
+ GrGLubyte *fImage;
+};
+
+#endif
+
+#endif
diff --git a/include/gpu/SkNativeGLContext.h b/include/gpu/SkNativeGLContext.h
new file mode 100644
index 0000000..36461ba
--- /dev/null
+++ b/include/gpu/SkNativeGLContext.h
@@ -0,0 +1,81 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef SkNativeGLContext_DEFINED
+#define SkNativeGLContext_DEFINED
+
+#include "SkGLContext.h"
+
+#if defined(SK_BUILD_FOR_MAC)
+ #include <AGL/agl.h>
+
+#elif defined(SK_BUILD_FOR_ANDROID)
+ #include <GLES2/gl2.h>
+ #include <EGL/egl.h>
+#elif defined(SK_BUILD_FOR_UNIX)
+ #include <X11/Xlib.h>
+ #include <GL/glx.h>
+#elif defined(SK_BUILD_FOR_WIN32)
+ #include <Windows.h>
+ #include <GL/GL.h>
+#endif
+
+class SkNativeGLContext : public SkGLContext {
+public:
+ SkNativeGLContext();
+
+ virtual ~SkNativeGLContext();
+
+ virtual void makeCurrent() const SK_OVERRIDE;
+
+ class AutoContextRestore {
+ public:
+ AutoContextRestore();
+ ~AutoContextRestore();
+
+ private:
+ #if defined(SK_BUILD_FOR_MAC)
+ AGLContext fOldAGLContext;
+ #elif defined(SK_BUILD_FOR_UNIX)
+ GLXContext fOldGLXContext;
+ Display* fOldDisplay;
+ GLXDrawable fOldDrawable;
+ #elif defined(SK_BUILD_FOR_WIN32)
+ HDC fOldHDC;
+ HGLRC fOldHGLRC;
+ #elif defined(SK_BUILD_FOR_ANDROID)
+ EGLContext fOldEGLContext;
+ EGLDisplay fOldDisplay;
+ EGLSurface fOldSurface;
+ #endif
+ };
+
+protected:
+ virtual const GrGLInterface* createGLContext() SK_OVERRIDE;
+ virtual void destroyGLContext() SK_OVERRIDE;
+
+private:
+#if defined(SK_BUILD_FOR_MAC)
+ AGLContext fContext;
+#elif defined(SK_BUILD_FOR_UNIX)
+ GLXContext fContext;
+ Display* fDisplay;
+ Pixmap fPixmap;
+ GLXPixmap fGlxPixmap;
+#elif defined(SK_BUILD_FOR_WIN32)
+ HWND fWindow;
+ HDC fDeviceContext;
+ HGLRC fGlRenderContext;
+ static ATOM gWC;
+#elif defined(SK_BUILD_FOR_ANDROID)
+ EGLContext fContext;
+ EGLDisplay fDisplay;
+ EGLSurface fSurface;
+#endif
+};
+
+#endif
diff --git a/include/gpu/SkNullGLContext.h b/include/gpu/SkNullGLContext.h
new file mode 100644
index 0000000..9e16cee
--- /dev/null
+++ b/include/gpu/SkNullGLContext.h
@@ -0,0 +1,27 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef SkNullGLContext_DEFINED
+#define SkNullGLContext_DEFINED
+
+#include "SkGLContext.h"
+
+class SkNullGLContext : public SkGLContext {
+
+public:
+ SkNullGLContext() {};
+
+ virtual void makeCurrent() const SK_OVERRIDE {};
+
+protected:
+ virtual const GrGLInterface* createGLContext() SK_OVERRIDE;
+
+ virtual void destroyGLContext() SK_OVERRIDE {};
+};
+
+#endif
+
diff --git a/include/images/SkBitmapRegionDecoder.h b/include/images/SkBitmapRegionDecoder.h
index c039c1b..5c8df3e 100644
--- a/include/images/SkBitmapRegionDecoder.h
+++ b/include/images/SkBitmapRegionDecoder.h
@@ -1,3 +1,11 @@
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
#ifndef SkBitmapRegionDecoder_DEFINED
#define SkBitmapRegionDecoder_DEFINED
diff --git a/include/images/SkFlipPixelRef.h b/include/images/SkFlipPixelRef.h
index 3b4e97a..455a3da 100644
--- a/include/images/SkFlipPixelRef.h
+++ b/include/images/SkFlipPixelRef.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkFlipPixelRef_DEFINED
#define SkFlipPixelRef_DEFINED
@@ -63,7 +56,9 @@ public:
virtual Factory getFactory() const { return Create; }
virtual void flatten(SkFlattenableWriteBuffer&) const;
static SkPixelRef* Create(SkFlattenableReadBuffer& buffer);
-
+
+ SK_DECLARE_PIXEL_REF_REGISTRAR()
+
protected:
virtual void* onLockPixels(SkColorTable**);
virtual void onUnlockPixels();
diff --git a/include/images/SkImageDecoder.h b/include/images/SkImageDecoder.h
index 4343d6d..361e1a0 100644
--- a/include/images/SkImageDecoder.h
+++ b/include/images/SkImageDecoder.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkImageDecoder_DEFINED
#define SkImageDecoder_DEFINED
diff --git a/include/images/SkImageEncoder.h b/include/images/SkImageEncoder.h
index c56e080..a4831f1 100644
--- a/include/images/SkImageEncoder.h
+++ b/include/images/SkImageEncoder.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkImageEncoder_DEFINED
#define SkImageEncoder_DEFINED
diff --git a/include/images/SkImageRef.h b/include/images/SkImageRef.h
index 800f12e..f0f06b6 100644
--- a/include/images/SkImageRef.h
+++ b/include/images/SkImageRef.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkImageRef_DEFINED
#define SkImageRef_DEFINED
diff --git a/include/images/SkImageRef_GlobalPool.h b/include/images/SkImageRef_GlobalPool.h
index a9d4dce..909ee71 100644
--- a/include/images/SkImageRef_GlobalPool.h
+++ b/include/images/SkImageRef_GlobalPool.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2008 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkImageRef_GlobalPool_DEFINED
#define SkImageRef_GlobalPool_DEFINED
@@ -30,6 +23,8 @@ public:
return Create;
}
static SkPixelRef* Create(SkFlattenableReadBuffer&);
+
+ SK_DECLARE_PIXEL_REF_REGISTRAR()
// API to control the global pool
diff --git a/include/images/SkJpegUtility.h b/include/images/SkJpegUtility.h
index e9dd977..74f1a21 100644
--- a/include/images/SkJpegUtility.h
+++ b/include/images/SkJpegUtility.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2010 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkJpegUtility_DEFINED
#define SkJpegUtility_DEFINED
diff --git a/include/images/SkMovie.h b/include/images/SkMovie.h
index 45962a5..f52a786 100644
--- a/include/images/SkMovie.h
+++ b/include/images/SkMovie.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkMovie_DEFINED
#define SkMovie_DEFINED
diff --git a/include/images/SkPageFlipper.h b/include/images/SkPageFlipper.h
index 0d791ee..1a18856 100644
--- a/include/images/SkPageFlipper.h
+++ b/include/images/SkPageFlipper.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPageFlipper_DEFINED
#define SkPageFlipper_DEFINED
diff --git a/include/pdf/SkBitSet.h b/include/pdf/SkBitSet.h
new file mode 100755
index 0000000..484fc2a
--- /dev/null
+++ b/include/pdf/SkBitSet.h
@@ -0,0 +1,78 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkBitSet_DEFINED
+#define SkBitSet_DEFINED
+
+#include "SkTypes.h"
+#include "SkTDArray.h"
+
+class SkBitSet {
+public:
+ /** NumberOfBits must be greater than zero.
+ */
+ explicit SkBitSet(int numberOfBits);
+ explicit SkBitSet(const SkBitSet& source);
+
+ const SkBitSet& operator=(const SkBitSet& rhs);
+ bool operator==(const SkBitSet& rhs);
+ bool operator!=(const SkBitSet& rhs);
+
+ /** Clear all data.
+ */
+ void clearAll();
+
+ /** Set the value of the index-th bit.
+ */
+ void setBit(int index, bool value);
+
+ /** Test if bit index is set.
+ */
+ bool isBitSet(int index) const;
+
+ /** Or bits from source. false is returned if this doesn't have the same
+ * bit count as source.
+ */
+ bool orBits(const SkBitSet& source);
+
+ /** Export indices of set bits to T array.
+ */
+ template<typename T>
+ void exportTo(SkTDArray<T>* array) const {
+ SkASSERT(array);
+ uint32_t* data = reinterpret_cast<uint32_t*>(fBitData.get());
+ for (unsigned int i = 0; i < fDwordCount; ++i) {
+ uint32_t value = data[i];
+ if (value) { // There are set bits
+ unsigned int index = i * 32;
+ for (unsigned int j = 0; j < 32; ++j) {
+ if (0x1 & (value >> j)) {
+ array->push(index + j);
+ }
+ }
+ }
+ }
+ }
+
+private:
+ SkAutoFree fBitData;
+ // Dword (32-bit) count of the bitset.
+ size_t fDwordCount;
+ size_t fBitCount;
+
+ uint32_t* internalGet(int index) const {
+ SkASSERT((size_t)index < fBitCount);
+ size_t internalIndex = index / 32;
+ SkASSERT(internalIndex < fDwordCount);
+ return reinterpret_cast<uint32_t*>(fBitData.get()) + internalIndex;
+ }
+};
+
+
+#endif
diff --git a/include/pdf/SkPDFCatalog.h b/include/pdf/SkPDFCatalog.h
index e02ffa1..68a244f 100644
--- a/include/pdf/SkPDFCatalog.h
+++ b/include/pdf/SkPDFCatalog.h
@@ -1,24 +1,18 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2010 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPDFCatalog_DEFINED
#define SkPDFCatalog_DEFINED
#include <sys/types.h>
+#include "SkPDFDocument.h"
#include "SkPDFTypes.h"
#include "SkRefCnt.h"
#include "SkTDArray.h"
@@ -32,7 +26,7 @@ class SK_API SkPDFCatalog {
public:
/** Create a PDF catalog.
*/
- SkPDFCatalog();
+ explicit SkPDFCatalog(SkPDFDocument::Flags flags);
~SkPDFCatalog();
/** Add the passed object to the catalog. Refs obj.
@@ -62,6 +56,10 @@ public:
*/
size_t getObjectNumberSize(SkPDFObject* obj);
+ /** Return the document flags in effect for this catalog/document.
+ */
+ SkPDFDocument::Flags getDocumentFlags() const { return fDocumentFlags; }
+
/** Output the cross reference table for objects in the catalog.
* Returns the total number of objects.
* @param stream The writable output stream to send the output to.
@@ -70,6 +68,26 @@ public:
*/
int32_t emitXrefTable(SkWStream* stream, bool firstPage);
+ /** Set substitute object for the passed object.
+ */
+ void setSubstitute(SkPDFObject* original, SkPDFObject* substitute);
+
+ /** Find and return any substitute object set for the passed object. If
+ * there is none, return the passed object.
+ */
+ SkPDFObject* getSubstituteObject(SkPDFObject* object);
+
+ /** Set file offsets for the resources of substitute objects.
+ * @param fileOffset Accumulated offset of current document.
+ * @param firstPage Indicate whether this is for the first page only.
+ * @return Total size of resources of substitute objects.
+ */
+ off_t setSubstituteResourcesOffsets(off_t fileOffset, bool firstPage);
+
+ /** Emit the resources of substitute objects.
+ */
+ void emitSubstituteResources(SkWStream* stream, bool firstPage);
+
private:
struct Rec {
Rec(SkPDFObject* object, bool onFirstPage)
@@ -84,9 +102,22 @@ private:
bool fOnFirstPage;
};
- // TODO(vandebo) Make this a hash if it's a performance problem.
+ struct SubstituteMapping {
+ SubstituteMapping(SkPDFObject* original, SkPDFObject* substitute)
+ : fOriginal(original), fSubstitute(substitute) {
+ }
+ SkPDFObject* fOriginal;
+ SkPDFObject* fSubstitute;
+ };
+
+ // TODO(vandebo): Make this a hash if it's a performance problem.
SkTDArray<struct Rec> fCatalog;
+ // TODO(arthurhsu): Make this a hash if it's a performance problem.
+ SkTDArray<SubstituteMapping> fSubstituteMap;
+ SkTDArray<SkPDFObject*> fSubstituteResourcesFirstPage;
+ SkTDArray<SkPDFObject*> fSubstituteResourcesRemaining;
+
// Number of objects on the first page.
uint32_t fFirstPageCount;
// Next object number to assign (on page > 1).
@@ -94,9 +125,13 @@ private:
// Next object number to assign on the first page.
uint32_t fNextFirstPageObjNum;
+ SkPDFDocument::Flags fDocumentFlags;
+
int findObjectIndex(SkPDFObject* obj) const;
int assignObjNum(SkPDFObject* obj);
+
+ SkTDArray<SkPDFObject*>* getSubstituteList(bool firstPage);
};
#endif
diff --git a/include/pdf/SkPDFDevice.h b/include/pdf/SkPDFDevice.h
index 6e4d8db..4551149 100644
--- a/include/pdf/SkPDFDevice.h
+++ b/include/pdf/SkPDFDevice.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2011 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2011 Google Inc.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPDFDevice_DEFINED
#define SkPDFDevice_DEFINED
@@ -30,6 +23,7 @@ class SkPDFDevice;
class SkPDFDict;
class SkPDFFont;
class SkPDFFormXObject;
+class SkPDFGlyphSetMap;
class SkPDFGraphicState;
class SkPDFObject;
class SkPDFShader;
@@ -39,12 +33,6 @@ class SkPDFStream;
struct ContentEntry;
struct GraphicStateEntry;
-class SkPDFDeviceFactory : public SkDeviceFactory {
-public:
- virtual SkDevice* newDevice(SkCanvas*, SkBitmap::Config, int width,
- int height, bool isOpaque, bool isForLayer);
-};
-
/** \class SkPDFDevice
The drawing context for the PDF backend.
@@ -65,62 +53,74 @@ public:
* a scale+translate transform to move the origin from the
* bottom left (PDF default) to the top left. Note2: drawDevice
* (used by layer restore) draws the device after this initial
- * transform is applied, so the PDF device factory does an
+ * transform is applied, so the PDF device does an
* inverse scale+translate to accommodate the one that SkPDFDevice
* always does.
*/
- // TODO(vandebo) The sizes should be SkSize and not SkISize.
+ // TODO(vandebo): The sizes should be SkSize and not SkISize.
SK_API SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize,
const SkMatrix& initialTransform);
SK_API virtual ~SkPDFDevice();
- virtual uint32_t getDeviceCapabilities() { return kVector_Capability; }
-
- virtual void clear(SkColor color);
+ virtual uint32_t getDeviceCapabilities() SK_OVERRIDE;
- virtual bool readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
- return false;
- }
+ virtual void clear(SkColor color) SK_OVERRIDE;
/** These are called inside the per-device-layer loop for each draw call.
When these are called, we have already applied any saveLayer operations,
and are handling any looping from the paint, and any effects from the
DrawFilter.
*/
- virtual void drawPaint(const SkDraw&, const SkPaint& paint);
+ virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE;
virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode,
size_t count, const SkPoint[],
- const SkPaint& paint);
+ const SkPaint& paint) SK_OVERRIDE;
virtual void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint);
virtual void drawPath(const SkDraw&, const SkPath& origpath,
const SkPaint& paint, const SkMatrix* prePathMatrix,
- bool pathIsMutable);
+ bool pathIsMutable) SK_OVERRIDE;
virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
const SkIRect* srcRectOrNull,
- const SkMatrix& matrix, const SkPaint& paint);
+ const SkMatrix& matrix, const SkPaint&) SK_OVERRIDE;
virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap, int x, int y,
- const SkPaint& paint);
+ const SkPaint& paint) SK_OVERRIDE;
virtual void drawText(const SkDraw&, const void* text, size_t len,
- SkScalar x, SkScalar y, const SkPaint& paint);
+ SkScalar x, SkScalar y, const SkPaint&) SK_OVERRIDE;
virtual void drawPosText(const SkDraw&, const void* text, size_t len,
const SkScalar pos[], SkScalar constY,
- int scalarsPerPos, const SkPaint& paint);
+ int scalarsPerPos, const SkPaint&) SK_OVERRIDE;
virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len,
const SkPath& path, const SkMatrix* matrix,
- const SkPaint& paint);
+ const SkPaint& paint) SK_OVERRIDE;
virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode,
int vertexCount, const SkPoint verts[],
const SkPoint texs[], const SkColor colors[],
SkXfermode* xmode, const uint16_t indices[],
- int indexCount, const SkPaint& paint);
+ int indexCount, const SkPaint& paint) SK_OVERRIDE;
virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
- const SkPaint&);
+ const SkPaint&) SK_OVERRIDE;
+
+ enum DrawingArea {
+ kContent_DrawingArea, // Drawing area for the page content.
+ kMargin_DrawingArea, // Drawing area for the margin content.
+ };
+
+ /** Sets the drawing area for the device. Subsequent draw calls are directed
+ * to the specific drawing area (margin or content). The default drawing
+ * area is the content drawing area.
+ *
+ * Currently if margin content is drawn and then a complex (for PDF) xfer
+ * mode is used, like SrcIn, Clear, etc, the margin content will get
+ * clipped. A simple way to avoid the bug is to always draw the margin
+ * content last.
+ */
+ SK_API void setDrawingArea(DrawingArea drawingArea);
// PDF specific methods.
- /** Returns a reference to the resource dictionary for this device.
+ /** Returns the resource dictionary for this device.
*/
- SK_API const SkRefPtr<SkPDFDict>& getResourceDict();
+ SK_API SkPDFDict* getResourceDict();
/** Get the list of resources (PDF objects) used on this page.
* @param resourceList A list to append the resources to.
@@ -137,20 +137,34 @@ public:
/** Returns a SkStream with the page contents. The caller is responsible
for a reference to the returned value.
+ DEPRECATED: use copyContentToData()
*/
SK_API SkStream* content() const;
+ /** Returns a SkStream with the page contents. The caller is responsible
+ * for calling data->unref() when it is finished.
+ */
+ SK_API SkData* copyContentToData() const;
+
SK_API const SkMatrix& initialTransform() const {
return fInitialTransform;
}
+ /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font
+ * that shows on this device.
+ */
+ const SkPDFGlyphSetMap& getFontGlyphUsage() const {
+ return *(fFontGlyphUsage.get());
+ }
+
protected:
- // override
- virtual SkDeviceFactory* onNewDeviceFactory();
+ virtual bool onReadPixels(const SkBitmap& bitmap, int x, int y,
+ SkCanvas::Config8888) SK_OVERRIDE;
+
+ virtual bool allowImageFilter(SkImageFilter*) SK_OVERRIDE;
private:
- friend class SkPDFDeviceFactory;
- // TODO(vandebo) push most of SkPDFDevice's state into a core object in
+ // TODO(vandebo): push most of SkPDFDevice's state into a core object in
// order to get the right access levels without using friend.
friend class ScopedContentEntry;
@@ -164,17 +178,33 @@ private:
SkTDArray<SkPDFGraphicState*> fGraphicStateResources;
SkTDArray<SkPDFObject*> fXObjectResources;
SkTDArray<SkPDFFont*> fFontResources;
- SkTDArray<SkPDFShader*> fShaderResources;
+ SkTDArray<SkPDFObject*> fShaderResources;
SkTScopedPtr<ContentEntry> fContentEntries;
ContentEntry* fLastContentEntry;
+ SkTScopedPtr<ContentEntry> fMarginContentEntries;
+ ContentEntry* fLastMarginContentEntry;
+ DrawingArea fDrawingArea;
+
+ // Accessor and setter functions based on the current DrawingArea.
+ SkTScopedPtr<ContentEntry>* getContentEntries();
+ ContentEntry* getLastContentEntry();
+ void setLastContentEntry(ContentEntry* contentEntry);
+
+ // Glyph ids used for each font on this device.
+ SkTScopedPtr<SkPDFGlyphSetMap> fFontGlyphUsage;
- // For use by the DeviceFactory.
SkPDFDevice(const SkISize& layerSize, const SkClipStack& existingClipStack,
const SkRegion& existingClipRegion);
+ // override from SkDevice
+ virtual SkDevice* onCreateCompatibleDevice(SkBitmap::Config config,
+ int width, int height,
+ bool isOpaque,
+ Usage usage) SK_OVERRIDE;
+
void init();
- void cleanUp();
+ void cleanUp(bool clearFontUsage);
void createFormXObjectFromDevice(SkRefPtr<SkPDFFormXObject>* xobject);
// Clear the passed clip from all existing content entries.
@@ -219,6 +249,11 @@ private:
const SkIRect* srcRect,
const SkPaint& paint);
+ /** Helper method for copyContentToData. It is responsible for copying the
+ * list of content entries |entry| to |data|.
+ */
+ void copyContentEntriesToData(ContentEntry* entry, SkWStream* data) const;
+
// Disable the default copy and assign implementation.
SkPDFDevice(const SkPDFDevice&);
void operator=(const SkPDFDevice&);
diff --git a/include/pdf/SkPDFDocument.h b/include/pdf/SkPDFDocument.h
index 0a76ea2..c1c6fb4 100644
--- a/include/pdf/SkPDFDocument.h
+++ b/include/pdf/SkPDFDocument.h
@@ -1,27 +1,21 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2010 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPDFDocument_DEFINED
#define SkPDFDocument_DEFINED
-#include "SkPDFCatalog.h"
#include "SkPDFTypes.h"
#include "SkRefCnt.h"
#include "SkTDArray.h"
+#include "SkTScopedPtr.h"
+class SkPDFCatalog;
class SkPDFDevice;
class SkPDFPage;
class SkWSteam;
@@ -32,35 +26,55 @@ class SkWSteam;
*/
class SkPDFDocument {
public:
+ enum Flags {
+ kNoCompression_Flag = 0x01, //!< mask disable stream compression.
+ kNoEmbedding_Flag = 0x02, //!< mask do not embed fonts.
+
+ kDraftMode_Flags = 0x03,
+ };
/** Create a PDF document.
*/
- SK_API SkPDFDocument();
+ explicit SK_API SkPDFDocument(Flags flags = (Flags)0);
SK_API ~SkPDFDocument();
- /** Output the PDF to the passed stream.
+ /** Output the PDF to the passed stream. It is an error to call this (it
+ * will return false and not modify stream) if no pages have been added
+ * or there are pages missing (i.e. page 1 and 3 have been added, but not
+ * page 2).
+ *
* @param stream The writable output stream to send the PDF to.
*/
SK_API bool emitPDF(SkWStream* stream);
+ /** Sets the specific page to the passed PDF device. If the specified
+ * page is already set, this overrides it. Returns true if successful.
+ * Will fail if the document has already been emitted.
+ *
+ * @param pageNumber The position to add the passed device (1 based).
+ * @param pdfDevice The page to add to this document.
+ */
+ SK_API bool setPage(int pageNumber, SkPDFDevice* pdfDevice);
+
/** Append the passed pdf device to the document as a new page. Returns
* true if successful. Will fail if the document has already been emitted.
*
* @param pdfDevice The page to add to this document.
*/
- SK_API bool appendPage(const SkRefPtr<SkPDFDevice>& pdfDevice);
+ SK_API bool appendPage(SkPDFDevice* pdfDevice);
/** Get the list of pages in this document.
*/
SK_API const SkTDArray<SkPDFPage*>& getPages();
private:
- SkPDFCatalog fCatalog;
+ SkTScopedPtr<SkPDFCatalog> fCatalog;
int64_t fXRefFileOffset;
SkTDArray<SkPDFPage*> fPages;
SkTDArray<SkPDFDict*> fPageTree;
SkRefPtr<SkPDFDict> fDocCatalog;
SkTDArray<SkPDFObject*> fPageResources;
+ SkTDArray<SkPDFObject*> fSubstitutes;
int fSecondPageFirstResourceIndex;
SkRefPtr<SkPDFDict> fTrailerDict;
diff --git a/include/pdf/SkPDFFont.h b/include/pdf/SkPDFFont.h
index 93a72f1..b884017 100644
--- a/include/pdf/SkPDFFont.h
+++ b/include/pdf/SkPDFFont.h
@@ -1,28 +1,74 @@
+
/*
- * Copyright (C) 2011 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2011 Google Inc.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPDFFont_DEFINED
#define SkPDFFont_DEFINED
#include "SkAdvancedTypefaceMetrics.h"
+#include "SkBitSet.h"
#include "SkPDFTypes.h"
#include "SkTDArray.h"
#include "SkThread.h"
+#include "SkTypeface.h"
class SkPaint;
+class SkPDFCatalog;
+class SkPDFFont;
+
+class SkPDFGlyphSet : public SkNoncopyable {
+public:
+ SkPDFGlyphSet();
+
+ void set(const uint16_t* glyphIDs, int numGlyphs);
+ bool has(uint16_t glyphID) const;
+ void merge(const SkPDFGlyphSet& usage);
+ void exportTo(SkTDArray<uint32_t>* glyphIDs) const;
+
+private:
+ SkBitSet fBitSet;
+};
+
+class SkPDFGlyphSetMap : public SkNoncopyable {
+public:
+ struct FontGlyphSetPair {
+ FontGlyphSetPair(SkPDFFont* font, SkPDFGlyphSet* glyphSet);
+
+ SkPDFFont* fFont;
+ SkPDFGlyphSet* fGlyphSet;
+ };
+
+ SkPDFGlyphSetMap();
+ ~SkPDFGlyphSetMap();
+
+ class F2BIter {
+ public:
+ explicit F2BIter(const SkPDFGlyphSetMap& map);
+ FontGlyphSetPair* next() const;
+ void reset(const SkPDFGlyphSetMap& map);
+
+ private:
+ const SkTDArray<FontGlyphSetPair>* fMap;
+ mutable int fIndex;
+ };
+
+ void merge(const SkPDFGlyphSetMap& usage);
+ void reset();
+
+ void noteGlyphUsage(SkPDFFont* font, const uint16_t* glyphIDs,
+ int numGlyphs);
+
+private:
+ SkPDFGlyphSet* getGlyphSetForFont(SkPDFFont* font);
+
+ SkTDArray<FontGlyphSetPair> fMap;
+};
+
/** \class SkPDFFont
A PDF Object class representing a font. The font may have resources
@@ -45,15 +91,15 @@ public:
/** Returns the font type represented in this font. For Type0 fonts,
* returns the type of the decendant font.
*/
- SK_API SkAdvancedTypefaceMetrics::FontType getType();
+ SK_API virtual SkAdvancedTypefaceMetrics::FontType getType();
- /** Return true if this font has an encoding for the passed glyph id.
+ /** Returns true if this font encoding supports glyph IDs above 255.
*/
- SK_API bool hasGlyph(uint16_t glyphID);
+ SK_API virtual bool multiByteGlyphs() const = 0;
- /** Returns true if this font encoding supports glyph IDs above 255.
+ /** Return true if this font has an encoding for the passed glyph id.
*/
- SK_API bool multiByteGlyphs();
+ SK_API bool hasGlyph(uint16_t glyphID);
/** Convert (in place) the input glyph IDs into the font encoding. If the
* font has more glyphs than can be encoded (like a type 1 font with more
@@ -73,16 +119,68 @@ public:
* @param typeface The typeface to find.
* @param glyphID Specify which section of a large font is of interest.
*/
- SK_API static SkPDFFont* getFontResource(SkTypeface* typeface,
+ SK_API static SkPDFFont* GetFontResource(SkTypeface* typeface,
uint16_t glyphID);
+ /** Subset the font based on usage set. Returns a SkPDFFont instance with
+ * subset.
+ * @param usage Glyph subset requested.
+ * @return NULL if font does not support subsetting, a new instance
+ * of SkPDFFont otherwise.
+ */
+ SK_API virtual SkPDFFont* getFontSubset(const SkPDFGlyphSet* usage);
+
+protected:
+ // Common constructor to handle common members.
+ SkPDFFont(SkAdvancedTypefaceMetrics* fontInfo, SkTypeface* typeface,
+ uint16_t glyphID, bool descendantFont);
+
+ // Accessors for subclass.
+ SkAdvancedTypefaceMetrics* fontInfo();
+ void setFontInfo(SkAdvancedTypefaceMetrics* info);
+ uint16_t firstGlyphID() const;
+ uint16_t lastGlyphID() const;
+ void setLastGlyphID(uint16_t glyphID);
+
+ // Add object to resource list.
+ void addResource(SkPDFObject* object);
+
+ // Accessors for FontDescriptor associated with this object.
+ SkPDFDict* getFontDescriptor();
+ void setFontDescriptor(SkPDFDict* descriptor);
+
+ // Add common entries to FontDescriptor.
+ bool addCommonFontDescriptorEntries(int16_t defaultWidth);
+
+ /** Set fFirstGlyphID and fLastGlyphID to span at most 255 glyphs,
+ * including the passed glyphID.
+ */
+ void adjustGlyphRangeForSingleByteEncoding(int16_t glyphID);
+
+ // Generate ToUnicode table according to glyph usage subset.
+ // If subset is NULL, all available glyph ids will be used.
+ void populateToUnicodeTable(const SkPDFGlyphSet* subset);
+
+ // Create instances of derived types based on fontInfo.
+ static SkPDFFont* Create(SkAdvancedTypefaceMetrics* fontInfo,
+ SkTypeface* typeface, uint16_t glyphID,
+ SkPDFDict* fontDescriptor);
+
+ static bool Find(uint32_t fontID, uint16_t glyphID, int* index);
+
private:
+ class FontRec {
+ public:
+ SkPDFFont* fFont;
+ uint32_t fFontID;
+ uint16_t fGlyphID;
+
+ // A fGlyphID of 0 with no fFont always matches.
+ bool operator==(const FontRec& b) const;
+ FontRec(SkPDFFont* font, uint32_t fontID, uint16_t fGlyphID);
+ };
+
SkRefPtr<SkTypeface> fTypeface;
- SkAdvancedTypefaceMetrics::FontType fType;
-#ifdef SK_DEBUG
- bool fDescendant;
-#endif
- bool fMultiByteGlyphs;
// The glyph IDs accessible with this font. For Type1 (non CID) fonts,
// this will be a subset if the font has more than 255 glyphs.
@@ -94,58 +192,11 @@ private:
SkTDArray<SkPDFObject*> fResources;
SkRefPtr<SkPDFDict> fDescriptor;
- class FontRec {
- public:
- SkPDFFont* fFont;
- uint32_t fFontID;
- uint16_t fGlyphID;
-
- // A fGlyphID of 0 with no fFont always matches.
- bool operator==(const FontRec& b) const;
- FontRec(SkPDFFont* font, uint32_t fontID, uint16_t fGlyphID);
- };
+ SkAdvancedTypefaceMetrics::FontType fFontType;
// This should be made a hash table if performance is a problem.
- static SkTDArray<FontRec>& canonicalFonts();
- static SkMutex& canonicalFontsMutex();
-
- /** Construct a new font dictionary and support objects.
- * @param fontInfo Information about the to create.
- * @param typeface The typeface for the font.
- * @param glyphID The glyph ID the caller is interested in. This
- * is important only for Type1 fonts, which have
- * more than 255 glyphs.
- * @param descendantFont If this is the descendant (true) or root
- * (Type 0 font - false) font dictionary. Only True
- * Type and CID encoded fonts will use a true value.
- * @param fontDescriptor If the font descriptor has already have generated
- * for this font, pass it in here, otherwise pass
- * NULL.
- */
- SkPDFFont(class SkAdvancedTypefaceMetrics* fontInfo, SkTypeface* typeface,
- uint16_t glyphID, bool descendantFont, SkPDFDict* fontDescriptor);
-
- void populateType0Font();
- void populateCIDFont();
- bool populateType1Font(int16_t glyphID);
-
- /** Populate the PDF font dictionary as Type3 font which includes glyph
- * descriptions with instructions for painting the glyphs. This function
- * doesn't use any fields from SkAdvancedTypefaceMetrics (fFontInfo). Font
- * information including glyph paths are queried from the platform
- * dependent SkGlyphCache.
- */
- void populateType3Font(int16_t glyphID);
- bool addFontDescriptor(int16_t defaultWidth);
- void populateToUnicodeTable();
- void addWidthInfoFromRange(int16_t defaultWidth,
- const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry);
- /** Set fFirstGlyphID and fLastGlyphID to span at most 255 glyphs,
- * including the passed glyphID.
- */
- void adjustGlyphRangeForSingleByteEncoding(int16_t glyphID);
-
- static bool find(uint32_t fontID, uint16_t glyphID, int* index);
+ static SkTDArray<FontRec>& CanonicalFonts();
+ static SkMutex& CanonicalFontsMutex();
};
#endif
diff --git a/include/pdf/SkPDFFormXObject.h b/include/pdf/SkPDFFormXObject.h
index 41719f0..0c49152 100644
--- a/include/pdf/SkPDFFormXObject.h
+++ b/include/pdf/SkPDFFormXObject.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2010 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPDFFormXObject_DEFINED
#define SkPDFFormXObject_DEFINED
@@ -36,7 +29,7 @@ class SkPDFCatalog;
// The caller could keep track of the form XObjects it creates and
// canonicalize them, but the Skia API doesn't provide enough context to
// automatically do it (trivially).
-class SkPDFFormXObject : public SkPDFObject {
+class SkPDFFormXObject : public SkPDFStream {
public:
/** Create a PDF form XObject. Entries for the dictionary entries are
* automatically added.
@@ -46,27 +39,9 @@ public:
virtual ~SkPDFFormXObject();
// The SkPDFObject interface.
- virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
- bool indirect);
- virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect);
virtual void getResources(SkTDArray<SkPDFObject*>* resourceList);
- /** Add the value to the stream dictionary with the given key. Refs value.
- * @param key The key for this dictionary entry.
- * @param value The value for this dictionary entry.
- * @return The value argument is returned.
- */
- SkPDFObject* insert(SkPDFName* key, SkPDFObject* value);
-
- /** Add the value to the stream dictionary with the given key. Refs value.
- * @param key The text of the key for this dictionary entry.
- * @param value The value for this dictionary entry.
- * @return The value argument is returned.
- */
- SkPDFObject* insert(const char key[], SkPDFObject* value);
-
private:
- SkRefPtr<SkPDFStream> fStream;
SkTDArray<SkPDFObject*> fResources;
};
diff --git a/include/pdf/SkPDFGraphicState.h b/include/pdf/SkPDFGraphicState.h
index 49809a4..9420405 100644
--- a/include/pdf/SkPDFGraphicState.h
+++ b/include/pdf/SkPDFGraphicState.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2010 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPDFGraphicState_DEFINED
#define SkPDFGraphicState_DEFINED
@@ -52,7 +45,7 @@ public:
* other references.
* @param paint The SkPaint to emulate.
*/
- static SkPDFGraphicState* getGraphicStateForPaint(const SkPaint& paint);
+ static SkPDFGraphicState* GetGraphicStateForPaint(const SkPaint& paint);
/** Make a graphic state that only sets the passed soft mask. The
* reference count of the object is incremented and it is the caller's
@@ -60,7 +53,7 @@ public:
* @param sMask The form xobject to use as a soft mask.
* @param invert Indicates if the alpha of the sMask should be inverted.
*/
- static SkPDFGraphicState* getSMaskGraphicState(SkPDFFormXObject* sMask,
+ static SkPDFGraphicState* GetSMaskGraphicState(SkPDFFormXObject* sMask,
bool invert);
/** Get a graphic state that only unsets the soft mask. The reference
@@ -69,7 +62,7 @@ public:
* reference pattern used when the returned object is new and has no
* other references.
*/
- static SkPDFGraphicState* getNoSMaskGraphicState();
+ static SkPDFGraphicState* GetNoSMaskGraphicState();
private:
const SkPaint fPaint;
@@ -86,12 +79,14 @@ private:
explicit GSCanonicalEntry(SkPDFGraphicState* gs)
: fGraphicState(gs),
fPaint(&gs->fPaint) {}
- explicit GSCanonicalEntry(const SkPaint* paint) : fPaint(paint) {}
+ explicit GSCanonicalEntry(const SkPaint* paint)
+ : fGraphicState(NULL),
+ fPaint(paint) {}
};
// This should be made a hash table if performance is a problem.
- static SkTDArray<GSCanonicalEntry>& canonicalPaints();
- static SkMutex& canonicalPaintsMutex();
+ static SkTDArray<GSCanonicalEntry>& CanonicalPaints();
+ static SkMutex& CanonicalPaintsMutex();
SkPDFGraphicState();
explicit SkPDFGraphicState(const SkPaint& paint);
@@ -100,7 +95,7 @@ private:
static SkPDFObject* GetInvertFunction();
- static int find(const SkPaint& paint);
+ static int Find(const SkPaint& paint);
};
#endif
diff --git a/include/pdf/SkPDFImage.h b/include/pdf/SkPDFImage.h
index 945ff9e..48b0157 100644
--- a/include/pdf/SkPDFImage.h
+++ b/include/pdf/SkPDFImage.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2010 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPDFImage_DEFINED
#define SkPDFImage_DEFINED
@@ -34,7 +27,7 @@ struct SkIRect;
// We could play the same trick here as is done in SkPDFGraphicState, storing
// a copy of the Bitmap object (not the pixels), the pixel generation number,
// and settings used from the paint to canonicalize image objects.
-class SkPDFImage : public SkPDFObject {
+class SkPDFImage : public SkPDFStream {
public:
/** Create a new Image XObject to represent the passed bitmap.
* @param bitmap The image to encode.
@@ -56,13 +49,9 @@ public:
SkPDFImage* addSMask(SkPDFImage* mask);
// The SkPDFObject interface.
- virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
- bool indirect);
- virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect);
virtual void getResources(SkTDArray<SkPDFObject*>* resourceList);
private:
- SkRefPtr<SkPDFStream> fStream;
SkTDArray<SkPDFObject*> fResources;
/** Create a PDF image XObject. Entries for the image properties are
@@ -76,20 +65,6 @@ private:
*/
SkPDFImage(SkStream* imageData, const SkBitmap& bitmap,
const SkIRect& srcRect, bool alpha, const SkPaint& paint);
-
- /** Add the value to the stream dictionary with the given key. Refs value.
- * @param key The key for this dictionary entry.
- * @param value The value for this dictionary entry.
- * @return The value argument is returned.
- */
- SkPDFObject* insert(SkPDFName* key, SkPDFObject* value);
-
- /** Add the value to the stream dictionary with the given key. Refs value.
- * @param key The text of the key for this dictionary entry.
- * @param value The value for this dictionary entry.
- * @return The value argument is returned.
- */
- SkPDFObject* insert(const char key[], SkPDFObject* value);
};
#endif
diff --git a/include/pdf/SkPDFPage.h b/include/pdf/SkPDFPage.h
index 0e30028..38a371a 100644
--- a/include/pdf/SkPDFPage.h
+++ b/include/pdf/SkPDFPage.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2010 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPDFPage_DEFINED
#define SkPDFPage_DEFINED
@@ -37,7 +30,7 @@ public:
* have content on it yet.
* @param content The page content.
*/
- explicit SkPDFPage(const SkRefPtr<SkPDFDevice>& content);
+ explicit SkPDFPage(SkPDFDevice* content);
~SkPDFPage();
/** Before a page and its contents can be sized and emitted, it must
@@ -81,7 +74,7 @@ public:
* nodes of the pageTree.
* @param rootNode An output parameter set to the root node.
*/
- static void generatePageTree(const SkTDArray<SkPDFPage*>& pages,
+ static void GeneratePageTree(const SkTDArray<SkPDFPage*>& pages,
SkPDFCatalog* catalog,
SkTDArray<SkPDFDict*>* pageTree,
SkPDFDict** rootNode);
@@ -90,6 +83,11 @@ public:
*/
SK_API const SkTDArray<SkPDFFont*>& getFontResources() const;
+ /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font
+ * that shows on this page.
+ */
+ const SkPDFGlyphSetMap& getFontGlyphUsage() const;
+
private:
// Multiple pages may reference the content.
SkRefPtr<SkPDFDevice> fDevice;
diff --git a/include/pdf/SkPDFShader.h b/include/pdf/SkPDFShader.h
index 17f7f03..6b6ae03 100644
--- a/include/pdf/SkPDFShader.h
+++ b/include/pdf/SkPDFShader.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2011 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2011 Google Inc.
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPDFShader_DEFINED
#define SkPDFShader_DEFINED
@@ -32,16 +25,8 @@ class SkPDFCatalog;
pattern color space is selected.
*/
-class SkPDFShader : public SkPDFObject {
+class SkPDFShader {
public:
- virtual ~SkPDFShader();
-
- // The SkPDFObject interface.
- virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
- bool indirect);
- virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect);
- virtual void getResources(SkTDArray<SkPDFObject*>* resourceList);
-
/** Get the PDF shader for the passed SkShader. If the SkShader is
* invalid in some way, returns NULL. The reference count of
* the object is incremented and it is the caller's responsibility to
@@ -54,57 +39,27 @@ public:
* @param surfceBBox The bounding box of the drawing surface (with matrix
* already applied).
*/
- static SkPDFShader* getPDFShader(const SkShader& shader,
+ static SkPDFObject* GetPDFShader(const SkShader& shader,
const SkMatrix& matrix,
const SkIRect& surfaceBBox);
-private:
- class State {
- public:
- SkShader::GradientType fType;
- SkShader::GradientInfo fInfo;
- SkAutoFree fColorData;
- SkMatrix fCanvasTransform;
- SkMatrix fShaderTransform;
- SkIRect fBBox;
-
- SkBitmap fImage;
- uint32_t fPixelGeneration;
- SkShader::TileMode fImageTileModes[2];
-
- explicit State(const SkShader& shader, const SkMatrix& canvasTransform,
- const SkIRect& bbox);
- bool operator==(const State& b) const;
- };
-
- SkRefPtr<SkPDFDict> fContent;
- SkTDArray<SkPDFObject*> fResources;
- SkAutoTDelete<const State> fState;
+protected:
+ class State;
class ShaderCanonicalEntry {
public:
- SkPDFShader* fPDFShader;
- const State* fState;
+ ShaderCanonicalEntry(SkPDFObject* pdfShader, const State* state);
+ bool operator==(const ShaderCanonicalEntry& b) const;
- bool operator==(const ShaderCanonicalEntry& b) const {
- return fPDFShader == b.fPDFShader || *fState == *b.fState;
- }
- ShaderCanonicalEntry(SkPDFShader* pdfShader, const State* state)
- : fPDFShader(pdfShader),
- fState(state) {
- }
+ SkPDFObject* fPDFShader;
+ const State* fState;
};
// This should be made a hash table if performance is a problem.
- static SkTDArray<ShaderCanonicalEntry>& canonicalShaders();
- static SkMutex& canonicalShadersMutex();
-
- static SkPDFObject* rangeObject();
-
- SkPDFShader(State* state);
+ static SkTDArray<ShaderCanonicalEntry>& CanonicalShaders();
+ static SkMutex& CanonicalShadersMutex();
+ static void RemoveShader(SkPDFObject* shader);
- void doFunctionShader();
- void doImageShader();
- SkPDFStream* makePSFunction(const SkString& psCode, SkPDFArray* domain);
+ SkPDFShader();
};
#endif
diff --git a/include/pdf/SkPDFStream.h b/include/pdf/SkPDFStream.h
index a975ad6..b3a7ad3 100644
--- a/include/pdf/SkPDFStream.h
+++ b/include/pdf/SkPDFStream.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2010 Google Inc.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPDFStream_DEFINED
#define SkPDFStream_DEFINED
@@ -32,10 +25,17 @@ class SkPDFCatalog;
class SkPDFStream : public SkPDFDict {
public:
/** Create a PDF stream. A Length entry is automatically added to the
- * stream dictionary.
- * @param stream The data part of the stream.
+ * stream dictionary. The stream may be retained (stream->ref() may be
+ * called) so its contents must not be changed after calling this.
+ * @param data The data part of the stream.
*/
+ explicit SkPDFStream(SkData* data);
+ /** Deprecated constructor. */
explicit SkPDFStream(SkStream* stream);
+ /** Create a PDF stream with the same content and dictionary entries
+ * as the passed one.
+ */
+ explicit SkPDFStream(const SkPDFStream& pdfStream);
virtual ~SkPDFStream();
// The SkPDFObject interface.
@@ -43,13 +43,33 @@ public:
bool indirect);
virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect);
+protected:
+ /* Create a PDF stream with no data. The setData method must be called to
+ * set the data.
+ */
+ SkPDFStream();
+
+ void setData(SkStream* stream);
+
private:
- size_t fLength;
- // Only one of the two streams will be valid.
- SkRefPtr<SkStream> fPlainData;
- SkDynamicMemoryWStream fCompressedData;
+ enum State {
+ kUnused_State, //!< The stream hasn't been requested yet.
+ kNoCompression_State, //!< The stream's been requested in an
+ // uncompressed form.
+ kCompressed_State, //!< The stream's already been compressed.
+ };
+ // Indicates what form (or if) the stream has been requested.
+ State fState;
+
+ // TODO(vandebo): Use SkData (after removing deprecated constructor).
+ SkRefPtr<SkStream> fData;
+ SkRefPtr<SkPDFStream> fSubstitute;
typedef SkPDFDict INHERITED;
+
+ // Populate the stream dictionary. This method returns false if
+ // fSubstitute should be used.
+ bool populate(SkPDFCatalog* catalog);
};
#endif
diff --git a/include/pdf/SkPDFTypes.h b/include/pdf/SkPDFTypes.h
index 6b5146a..155b826 100644
--- a/include/pdf/SkPDFTypes.h
+++ b/include/pdf/SkPDFTypes.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2010 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPDFTypes_DEFINED
#define SkPDFTypes_DEFINED
@@ -39,15 +32,6 @@ public:
SkPDFObject();
virtual ~SkPDFObject();
- /** Subclasses must implement this method to print the object to the
- * PDF file.
- * @param catalog The object catalog to use.
- * @param indirect If true, output an object identifier with the object.
- * @param stream The writable output stream to send the output to.
- */
- virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
- bool indirect) = 0;
-
/** Return the size (number of bytes) of this object in the final output
* file. Compound objects or objects that are computationally intensive
* to output should override this method.
@@ -65,6 +49,12 @@ public:
*/
virtual void getResources(SkTDArray<SkPDFObject*>* resourceList);
+ /** Emit this object unless the catalog has a substitute object, in which
+ * case emit that.
+ * @see emitObject
+ */
+ void emit(SkWStream* stream, SkPDFCatalog* catalog, bool indirect);
+
/** Helper function to output an indirect object.
* @param catalog The object catalog to use.
* @param stream The writable output stream to send the output to.
@@ -75,6 +65,32 @@ public:
* @param catalog The object catalog to use.
*/
size_t getIndirectOutputSize(SkPDFCatalog* catalog);
+
+ /** Static helper function to add a resource to a list. The list takes
+ * a reference.
+ * @param resource The resource to add.
+ * @param list The list to add the resource to.
+ */
+ static void AddResourceHelper(SkPDFObject* resource,
+ SkTDArray<SkPDFObject*>* list);
+
+ /** Static helper function to copy and reference the resources (and all
+ * their subresources) into a new list.
+ * @param resources The resource list.
+ * @param result The list to add to.
+ */
+ static void GetResourcesHelper(SkTDArray<SkPDFObject*>* resources,
+ SkTDArray<SkPDFObject*>* result);
+
+protected:
+ /** Subclasses must implement this method to print the object to the
+ * PDF file.
+ * @param catalog The object catalog to use.
+ * @param indirect If true, output an object identifier with the object.
+ * @param stream The writable output stream to send the output to.
+ */
+ virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
+ bool indirect) = 0;
};
/** \class SkPDFObjRef
@@ -187,15 +203,15 @@ public:
bool indirect);
virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect);
- static SkString formatString(const char* input, size_t len);
- static SkString formatString(const uint16_t* input, size_t len,
+ static SkString FormatString(const char* input, size_t len);
+ static SkString FormatString(const uint16_t* input, size_t len,
bool wideChars);
private:
static const size_t kMaxLen = 65535;
const SkString fValue;
- static SkString doFormatString(const void* input, size_t len,
+ static SkString DoFormatString(const void* input, size_t len,
bool wideInput, bool wideOutput);
};
@@ -212,6 +228,8 @@ public:
explicit SkPDFName(const SkString& name);
virtual ~SkPDFName();
+ bool operator==(const SkPDFName& b) const;
+
// The SkPDFObject interface.
virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
bool indirect);
@@ -222,7 +240,7 @@ private:
const SkString fValue;
- static SkString formatName(const SkString& input);
+ static SkString FormatName(const SkString& input);
};
/** \class SkPDFArray
@@ -268,6 +286,21 @@ public:
*/
SkPDFObject* append(SkPDFObject* value);
+ /** Creates a SkPDFInt object and appends it to the array.
+ * @param value The value to add to the array.
+ */
+ void appendInt(int32_t value);
+
+ /** Creates a SkPDFScalar object and appends it to the array.
+ * @param value The value to add to the array.
+ */
+ void appendScalar(SkScalar value);
+
+ /** Creates a SkPDFName object and appends it to the array.
+ * @param value The value to add to the array.
+ */
+ void appendName(const char name[]);
+
private:
static const int kMaxLen = 8191;
SkTDArray<SkPDFObject*> fValue;
@@ -314,18 +347,56 @@ public:
*/
SkPDFObject* insert(const char key[], SkPDFObject* value);
+ /** Add the int to the dictionary with the given key.
+ * @param key The text of the key for this dictionary entry.
+ * @param value The int value for this dictionary entry.
+ */
+ void insertInt(const char key[], int32_t value);
+
+ /** Add the scalar to the dictionary with the given key.
+ * @param key The text of the key for this dictionary entry.
+ * @param value The scalar value for this dictionary entry.
+ */
+ void insertScalar(const char key[], SkScalar value);
+
+ /** Add the name to the dictionary with the given key.
+ * @param key The text of the key for this dictionary entry.
+ * @param name The name for this dictionary entry.
+ */
+ void insertName(const char key[], const char name[]);
+
+ /** Add the name to the dictionary with the given key.
+ * @param key The text of the key for this dictionary entry.
+ * @param name The name for this dictionary entry.
+ */
+ void insertName(const char key[], const SkString& name) {
+ this->insertName(key, name.c_str());
+ }
+
/** Remove all entries from the dictionary.
*/
void clear();
private:
- static const int kMaxLen = 4095;
-
struct Rec {
SkPDFName* key;
SkPDFObject* value;
};
+public:
+ class Iter {
+ public:
+ explicit Iter(const SkPDFDict& dict);
+ SkPDFName* next(SkPDFObject** value);
+
+ private:
+ Rec* fIter;
+ Rec* fStop;
+ };
+
+private:
+ static const int kMaxLen = 4095;
+
SkTDArray<struct Rec> fValue;
};
diff --git a/include/pdf/SkPDFUtils.h b/include/pdf/SkPDFUtils.h
index 50da28c..5b9d74e 100644
--- a/include/pdf/SkPDFUtils.h
+++ b/include/pdf/SkPDFUtils.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2011 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2011 Google Inc.
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkPDFUtils_DEFINED
#define SkPDFUtils_DEFINED
@@ -36,7 +29,7 @@ struct SkRect;
PRINT_NOT_IMPL("NOT_IMPLEMENTED: " #condition "\n"); \
SkDEBUGCODE(SkASSERT(!assert);) \
} \
- } while(0)
+ } while (0)
class SkPDFUtils {
public:
diff --git a/include/pipe/SkGPipe.h b/include/pipe/SkGPipe.h
index 897766f..29b058e 100644
--- a/include/pipe/SkGPipe.h
+++ b/include/pipe/SkGPipe.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkGPipe_DEFINED
#define SkGPipe_DEFINED
@@ -23,6 +16,11 @@
class SkCanvas;
+// XLib.h might have defined Status already (ugh)
+#ifdef Status
+ #undef Status
+#endif
+
class SkGPipeReader {
public:
SkGPipeReader(SkCanvas* target);
@@ -31,13 +29,14 @@ public:
enum Status {
kDone_Status, //!< no more data expected from reader
kEOF_Status, //!< need more data from reader
- kError_Status //!< encountered error
+ kError_Status, //!< encountered error
+ kReadAtom_Status//!< finished reading an atom
};
// data must be 4-byte aligned
// length must be a multiple of 4
- Status playback(const void* data, size_t length, size_t* bytesRead = NULL);
-
+ Status playback(const void* data, size_t length, size_t* bytesRead = NULL,
+ bool readAtom = false);
private:
SkCanvas* fCanvas;
class SkGPipeState* fState;
diff --git a/include/ports/SkHarfBuzzFont.h b/include/ports/SkHarfBuzzFont.h
index b1fce0e..66c5534 100644
--- a/include/ports/SkHarfBuzzFont.h
+++ b/include/ports/SkHarfBuzzFont.h
@@ -1,31 +1,8 @@
/*
- * Copyright (c) 2009, Google Inc. All rights reserved.
+ * Copyright 2009 Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
#ifndef SkHarfBuzzFont_DEFINED
@@ -63,4 +40,3 @@ public:
};
#endif
-
diff --git a/include/ports/SkStream_Win.h b/include/ports/SkStream_Win.h
index 1b17450..8496360 100644
--- a/include/ports/SkStream_Win.h
+++ b/include/ports/SkStream_Win.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkStream_Win_DEFINED
#define SkStream_Win_DEFINED
diff --git a/include/ports/SkTypeface_mac.h b/include/ports/SkTypeface_mac.h
index 61b226b..eb9d25f 100644
--- a/include/ports/SkTypeface_mac.h
+++ b/include/ports/SkTypeface_mac.h
@@ -1,26 +1,24 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTypeface_mac_DEFINED
#define SkTypeface_mac_DEFINED
#include "SkTypeface.h"
-#include <Carbon/Carbon.h>
+#ifdef SK_BUILD_FOR_MAC
+#import <ApplicationServices/ApplicationServices.h>
+#endif
+#ifdef SK_BUILD_FOR_IOS
+#include <CoreText/CoreText.h>
+#endif
/**
* Like the other Typeface create methods, this returns a new reference to the
* corresponding typeface for the specified CTFontRef. The caller must call
diff --git a/include/ports/SkTypeface_win.h b/include/ports/SkTypeface_win.h
index 88678d1..6da843f 100644
--- a/include/ports/SkTypeface_win.h
+++ b/include/ports/SkTypeface_win.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTypeface_win_DEFINED
#define SkTypeface_win_DEFINED
@@ -25,7 +18,15 @@
* corresponding typeface for the specified logfont. The caller is responsible
* for calling unref() when it is finished.
*/
-SK_API extern SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT&);
+SK_API SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT&);
+
+/**
+ * Copy the LOGFONT associated with this typeface into the lf parameter. Note
+ * that the lfHeight will need to be set afterwards, since the typeface does
+ * not track this (the paint does).
+ * typeface may be NULL, in which case we return the logfont for the default font.
+ */
+SK_API void SkLOGFONTFromTypeface(const SkTypeface* typeface, LOGFONT* lf);
#endif
diff --git a/include/text/SkTextLayout.h b/include/text/SkTextLayout.h
index 2152307..e1e3e56 100644
--- a/include/text/SkTextLayout.h
+++ b/include/text/SkTextLayout.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkTextLayout_DEFINED
#define SkTextLayout_DEFINED
diff --git a/include/utils/SkBoundaryPatch.h b/include/utils/SkBoundaryPatch.h
index 835fc3e..9d4b5ad 100644
--- a/include/utils/SkBoundaryPatch.h
+++ b/include/utils/SkBoundaryPatch.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkBoundaryPatch_DEFINED
#define SkBoundaryPatch_DEFINED
diff --git a/include/utils/SkCamera.h b/include/utils/SkCamera.h
index 6d76018..57521b8 100644
--- a/include/utils/SkCamera.h
+++ b/include/utils/SkCamera.h
@@ -1,21 +1,14 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
// Inspired by Rob Johnson's most excellent QuickDraw GX sample code
#ifndef SkCamera_DEFINED
@@ -157,7 +150,7 @@ public:
void rotateY(SkScalar deg);
void rotateZ(SkScalar deg);
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
void setCameraLocation(SkScalar x, SkScalar y, SkScalar z);
#endif
diff --git a/include/utils/SkCubicInterval.h b/include/utils/SkCubicInterval.h
index bd6fc5f..bd1f9b9 100644
--- a/include/utils/SkCubicInterval.h
+++ b/include/utils/SkCubicInterval.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkCubicInterval_DEFINED
#define SkCubicInterval_DEFINED
diff --git a/include/utils/SkCullPoints.h b/include/utils/SkCullPoints.h
index cee64e2..9e2c01a 100644
--- a/include/utils/SkCullPoints.h
+++ b/include/utils/SkCullPoints.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkCullPoints_DEFINED
#define SkCullPoints_DEFINED
diff --git a/include/utils/SkDumpCanvas.h b/include/utils/SkDumpCanvas.h
index 3731bef..5bfd6f6 100644
--- a/include/utils/SkDumpCanvas.h
+++ b/include/utils/SkDumpCanvas.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkDumpCanvas_DEFINED
#define SkDumpCanvas_DEFINED
@@ -33,7 +40,6 @@ public:
kDrawBitmap_Verb,
kDrawText_Verb,
kDrawPicture_Verb,
- kDrawShape_Verb,
kDrawVertices_Verb,
kDrawData_Verb
};
@@ -52,58 +58,53 @@ public:
int getNestLevel() const { return fNestLevel; }
- // overrides from SkCanvas
-
- virtual int save(SaveFlags flags = kMatrixClip_SaveFlag);
+ virtual int save(SaveFlags) SK_OVERRIDE;
virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
- SaveFlags flags = kARGB_ClipLayer_SaveFlag);
- virtual void restore();
+ SaveFlags) SK_OVERRIDE;
+ virtual void restore() SK_OVERRIDE;
- virtual bool translate(SkScalar dx, SkScalar dy);
- virtual bool scale(SkScalar sx, SkScalar sy);
- virtual bool rotate(SkScalar degrees);
- virtual bool skew(SkScalar sx, SkScalar sy);
- virtual bool concat(const SkMatrix& matrix);
- virtual void setMatrix(const SkMatrix& matrix);
+ virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE;
+ virtual bool scale(SkScalar sx, SkScalar sy) SK_OVERRIDE;
+ virtual bool rotate(SkScalar degrees) SK_OVERRIDE;
+ virtual bool skew(SkScalar sx, SkScalar sy) SK_OVERRIDE;
+ virtual bool concat(const SkMatrix& matrix) SK_OVERRIDE;
+ virtual void setMatrix(const SkMatrix& matrix) SK_OVERRIDE;
- virtual bool clipRect(const SkRect& rect,
- SkRegion::Op op = SkRegion::kIntersect_Op);
- virtual bool clipPath(const SkPath& path,
- SkRegion::Op op = SkRegion::kIntersect_Op);
+ virtual bool clipRect(const SkRect&, SkRegion::Op, bool) SK_OVERRIDE;
+ virtual bool clipPath(const SkPath&, SkRegion::Op, bool) SK_OVERRIDE;
virtual bool clipRegion(const SkRegion& deviceRgn,
- SkRegion::Op op = SkRegion::kIntersect_Op);
+ SkRegion::Op) SK_OVERRIDE;
- virtual void drawPaint(const SkPaint& paint);
+ virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE;
virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
- const SkPaint& paint);
- virtual void drawRect(const SkRect& rect, const SkPaint& paint);
- virtual void drawPath(const SkPath& path, const SkPaint& paint);
+ const SkPaint& paint) SK_OVERRIDE;
+ virtual void drawRect(const SkRect& rect, const SkPaint& paint) SK_OVERRIDE;
+ virtual void drawPath(const SkPath& path, const SkPaint& paint) SK_OVERRIDE;
virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
- const SkPaint* paint = NULL);
+ const SkPaint* paint) SK_OVERRIDE;
virtual void drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
- const SkRect& dst, const SkPaint* paint = NULL);
+ const SkRect& dst, const SkPaint* paint) SK_OVERRIDE;
virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m,
- const SkPaint* paint = NULL);
+ const SkPaint* paint) SK_OVERRIDE;
virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
- const SkPaint* paint = NULL);
+ const SkPaint* paint) SK_OVERRIDE;
virtual void drawText(const void* text, size_t byteLength, SkScalar x,
- SkScalar y, const SkPaint& paint);
+ SkScalar y, const SkPaint& paint) SK_OVERRIDE;
virtual void drawPosText(const void* text, size_t byteLength,
- const SkPoint pos[], const SkPaint& paint);
+ const SkPoint pos[], const SkPaint& paint) SK_OVERRIDE;
virtual void drawPosTextH(const void* text, size_t byteLength,
const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint);
+ const SkPaint& paint) SK_OVERRIDE;
virtual void drawTextOnPath(const void* text, size_t byteLength,
const SkPath& path, const SkMatrix* matrix,
- const SkPaint& paint);
- virtual void drawPicture(SkPicture&);
- virtual void drawShape(SkShape*);
+ const SkPaint& paint) SK_OVERRIDE;
+ virtual void drawPicture(SkPicture&) SK_OVERRIDE;
virtual void drawVertices(VertexMode vmode, int vertexCount,
const SkPoint vertices[], const SkPoint texs[],
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
- const SkPaint& paint);
- virtual void drawData(const void*, size_t);
+ const SkPaint& paint) SK_OVERRIDE;
+ virtual void drawData(const void*, size_t) SK_OVERRIDE;
private:
Dumper* fDumper;
@@ -124,7 +125,7 @@ public:
// override from baseclass that does the formatting, and in turn calls
// the function pointer that was passed to the constructor
virtual void dump(SkDumpCanvas*, SkDumpCanvas::Verb, const char str[],
- const SkPaint*);
+ const SkPaint*) SK_OVERRIDE;
private:
void (*fProc)(const char*, void*);
diff --git a/include/utils/SkEGLContext.h b/include/utils/SkEGLContext.h
deleted file mode 100644
index ced31a5..0000000
--- a/include/utils/SkEGLContext.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef SkEGLContext_DEFINED
-#define SkEGLContext_DEFINED
-
-#if defined(SK_MESA)
- #include "GL/osmesa.h"
-#elif defined(SK_BUILD_FOR_MAC)
- #include <AGL/agl.h>
-#elif defined(SK_BUILD_FOR_ANDROID)
- #include "GLES2/gl2.h"
- #include "EGL/egl.h"
-#elif defined(SK_BUILD_FOR_UNIX)
- #include <X11/Xlib.h>
- #include <GL/glx.h>
-#elif defined(SK_BUILD_FOR_WIN32)
- #include <Windows.h>
- #include <GL/GL.h>
-#else
-
-#endif
-
-/**
- * Create an offscreen opengl context
- */
-class SkEGLContext {
-public:
- SkEGLContext();
- ~SkEGLContext();
-
- bool init(const int width, const int height);
-
-private:
-#if defined(SK_MESA)
- OSMesaContext context;
- GLfloat *image;
-#elif defined(SK_BUILD_FOR_MAC)
- AGLContext context;
-#elif defined(SK_BUILD_FOR_ANDROID)
-
-#elif defined(SK_BUILD_FOR_UNIX)
- GLXContext context;
- Display *display;
- Pixmap pixmap;
- GLXPixmap glxPixmap;
-#elif defined(SK_BUILD_FOR_WIN32)
- HWND fWindow;
- HDC fDeviceContext;
- HGLRC fGlRenderContext;
-#else
-
-#endif
-};
-
-#endif
diff --git a/include/utils/SkGLCanvas.h b/include/utils/SkGLCanvas.h
deleted file mode 100644
index eb99527..0000000
--- a/include/utils/SkGLCanvas.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SkGLCanvas_DEFINED
-#define SkGLCanvas_DEFINED
-
-#include "SkCanvas.h"
-
-// Deprecated. You should now use SkGLDevice and SkGLDeviceFactory with
-// SkCanvas.
-class SkGLCanvas : public SkCanvas {
-public:
- SkGLCanvas();
-
- static size_t GetTextureCacheMaxCount();
- static void SetTextureCacheMaxCount(size_t count);
-
- static size_t GetTextureCacheMaxSize();
- static void SetTextureCacheMaxSize(size_t size);
-
- static void DeleteAllTextures();
-
- static void AbandonAllTextures();
-};
-
-#endif
diff --git a/include/utils/SkInterpolator.h b/include/utils/SkInterpolator.h
index c03eb23..289e886 100644
--- a/include/utils/SkInterpolator.h
+++ b/include/utils/SkInterpolator.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkInterpolator_DEFINED
#define SkInterpolator_DEFINED
diff --git a/include/utils/SkJSON.h b/include/utils/SkJSON.h
new file mode 100644
index 0000000..5268af5
--- /dev/null
+++ b/include/utils/SkJSON.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkJSON_DEFINED
+#define SkJSON_DEFINED
+
+#include "SkTypes.h"
+
+class SkStream;
+class SkString;
+
+class SkJSON {
+public:
+ enum Type {
+ kObject,
+ kArray,
+ kString,
+ kInt,
+ kFloat,
+ kBool,
+ };
+
+ class Array;
+
+ class Object {
+ private:
+ struct Slot;
+
+ public:
+ Object();
+ Object(const Object&);
+ ~Object();
+
+ /**
+ * Create a new slot with the specified name and value. The name
+ * parameter is copied, but ownership of the Object parameter is
+ * transferred. The Object parameter may be null, but the name must
+ * not be null.
+ */
+ void addObject(const char name[], Object* value);
+
+ /**
+ * Create a new slot with the specified name and value. The name
+ * parameter is copied, but ownership of the Array parameter is
+ * transferred. The Array parameter may be null, but the name must
+ * not be null.
+ */
+ void addArray(const char name[], Array* value);
+
+ /**
+ * Create a new slot with the specified name and value. Both parameters
+ * are copied. The value parameter may be null, but the name must
+ * not be null.
+ */
+ void addString(const char name[], const char value[]);
+
+ /**
+ * Create a new slot with the specified name and value. The name
+ * parameter is copied, and must not be null.
+ */
+ void addInt(const char name[], int32_t value);
+
+ /**
+ * Create a new slot with the specified name and value. The name
+ * parameter is copied, and must not be null.
+ */
+ void addFloat(const char name[], float value);
+
+ /**
+ * Create a new slot with the specified name and value. The name
+ * parameter is copied, and must not be null.
+ */
+ void addBool(const char name[], bool value);
+
+ /**
+ * Return the number of slots/fields in this object. These can be
+ * iterated using Iter.
+ */
+ int count() const;
+
+ /**
+ * Returns true if a slot matching the name and Type is found.
+ */
+ bool find(const char name[], Type) const;
+ bool findObject(const char name[], Object** = NULL) const;
+ bool findArray(const char name[], Array** = NULL) const;
+ bool findString(const char name[], SkString* = NULL) const;
+ bool findInt(const char name[], int32_t* = NULL) const;
+ bool findFloat(const char name[], float* = NULL) const;
+ bool findBool(const char name[], bool* = NULL) const;
+
+ /**
+ * Finds the first slot matching the name and Type and removes it.
+ * Returns true if found, false if not.
+ */
+ bool remove(const char name[], Type);
+
+ void toDebugf() const;
+
+ /**
+ * Iterator class which returns all of the fields/slots in an Object,
+ * in the order that they were added.
+ */
+ class Iter {
+ public:
+ Iter(const Object&);
+
+ /**
+ * Returns true when there are no more entries in the iterator.
+ * In this case, no other methods should be called.
+ */
+ bool done() const;
+
+ /**
+ * Moves the iterator to the next element. Should only be called
+ * if done() returns false.
+ */
+ void next();
+
+ /**
+ * Returns the type of the current element. Should only be called
+ * if done() returns false.
+ */
+ Type type() const;
+
+ /**
+ * Returns the name of the current element. Should only be called
+ * if done() returns false.
+ */
+ const char* name() const;
+
+ /**
+ * Returns the type of the current element. Should only be called
+ * if done() returns false and type() returns kObject.
+ */
+ Object* objectValue() const;
+
+ /**
+ * Returns the type of the current element. Should only be called
+ * if done() returns false and type() returns kArray.
+ */
+ Array* arrayValue() const;
+
+ /**
+ * Returns the type of the current element. Should only be called
+ * if done() returns false and type() returns kString.
+ */
+ const char* stringValue() const;
+
+ /**
+ * Returns the type of the current element. Should only be called
+ * if done() returns false and type() returns kInt.
+ */
+ int32_t intValue() const;
+
+ /**
+ * Returns the type of the current element. Should only be called
+ * if done() returns false and type() returns kFloat.
+ */
+ float floatValue() const;
+
+ /**
+ * Returns the type of the current element. Should only be called
+ * if done() returns false and type() returns kBool.
+ */
+ bool boolValue() const;
+
+ private:
+ Slot* fSlot;
+ };
+
+ private:
+ Slot* fHead;
+ Slot* fTail;
+
+ const Slot* findSlot(const char name[], Type) const;
+ Slot* addSlot(Slot*);
+ void dumpLevel(int level) const;
+
+ friend class Array;
+ };
+
+ class Array {
+ public:
+ /**
+ * Creates an array with the specified Type and element count. All
+ * entries are initialized to NULL/0/false.
+ */
+ Array(Type, int count);
+
+ /**
+ * Creates an array of ints, initialized by copying the specified
+ * values.
+ */
+ Array(const int32_t values[], int count);
+
+ /**
+ * Creates an array of floats, initialized by copying the specified
+ * values.
+ */
+ Array(const float values[], int count);
+
+ /**
+ * Creates an array of bools, initialized by copying the specified
+ * values.
+ */
+ Array(const bool values[], int count);
+
+ Array(const Array&);
+ ~Array();
+
+ int count() const { return fCount; }
+ Type type() const { return fType; }
+
+ /**
+ * Replace the element at the specified index with the specified
+ * Object (which may be null). Ownership of the Object is transferred.
+ * Should only be called if the Array's type is kObject.
+ */
+ void setObject(int index, Object*);
+
+ /**
+ * Replace the element at the specified index with the specified
+ * Array (which may be null). Ownership of the Array is transferred.
+ * Should only be called if the Array's type is kArray.
+ */
+ void setArray(int index, Array*);
+
+ /**
+ * Replace the element at the specified index with a copy of the
+ * specified string (which may be null). Should only be called if the
+ * Array's type is kString.
+ */
+ void setString(int index, const char str[]);
+
+ Object* const* objects() const {
+ SkASSERT(kObject == fType);
+ return fArray.fObjects;
+ }
+ Array* const* arrays() const {
+ SkASSERT(kObject == fType);
+ return fArray.fArrays;
+ }
+ const char* const* strings() const {
+ SkASSERT(kString == fType);
+ return fArray.fStrings;
+ }
+ int32_t* ints() const {
+ SkASSERT(kInt == fType);
+ return fArray.fInts;
+ }
+ float* floats() const {
+ SkASSERT(kFloat == fType);
+ return fArray.fFloats;
+ }
+ bool* bools() const {
+ SkASSERT(kBool == fType);
+ return fArray.fBools;
+ }
+
+ private:
+ int fCount;
+ Type fType;
+ union {
+ void* fVoids;
+ Object** fObjects;
+ Array** fArrays;
+ char** fStrings;
+ int32_t* fInts;
+ float* fFloats;
+ bool* fBools;
+ } fArray;
+
+ void init(Type, int count, const void* src);
+ void dumpLevel(int level) const;
+
+ friend class Object;
+ };
+};
+
+#endif
diff --git a/include/utils/SkLayer.h b/include/utils/SkLayer.h
index 80a2137..9cba463 100644
--- a/include/utils/SkLayer.h
+++ b/include/utils/SkLayer.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2010 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkLayer_DEFINED
#define SkLayer_DEFINED
diff --git a/include/utils/SkMatrix44.h b/include/utils/SkMatrix44.h
new file mode 100644
index 0000000..93140b0
--- /dev/null
+++ b/include/utils/SkMatrix44.h
@@ -0,0 +1,224 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef SkMatrix44_DEFINED
+#define SkMatrix44_DEFINED
+
+#include "SkMatrix.h"
+#include "SkScalar.h"
+
+#ifdef SK_MSCALAR_IS_DOUBLE
+ typedef double SkMScalar;
+ static inline double SkFloatToMScalar(float x) {
+ return static_cast<double>(x);
+ }
+ static inline float SkMScalarToFloat(double x) {
+ return static_cast<float>(x);
+ }
+ static inline double SkDoubleToMScalar(double x) {
+ return x;
+ }
+ static inline double SkMScalarToDouble(double x) {
+ return x;
+ }
+ static const SkMScalar SK_MScalarPI = 3.141592653589793;
+#else
+ typedef float SkMScalar;
+ static inline float SkFloatToMScalar(float x) {
+ return x;
+ }
+ static inline float SkMScalarToFloat(float x) {
+ return x;
+ }
+ static inline float SkDoubleToMScalar(double x) {
+ return static_cast<float>(x);
+ }
+ static inline double SkMScalarToDouble(float x) {
+ return static_cast<double>(x);
+ }
+ static const SkMScalar SK_MScalarPI = 3.14159265f;
+#endif
+
+#ifdef SK_SCALAR_IS_FLOAT
+ #define SkMScalarToScalar SkMScalarToFloat
+ #define SkScalarToMScalar SkFloatToMScalar
+#else
+ #if SK_MSCALAR_IS_DOUBLE
+ // we don't have fixed <-> double macros, use double<->scalar macros
+ #define SkMScalarToScalar SkDoubleToScalar
+ #define SkScalarToMScalar SkScalarToDouble
+ #else
+ #define SkMScalarToScalar SkFloatToFixed
+ #define SkScalarToMScalar SkFixedToFloat
+ #endif
+#endif
+
+static const SkMScalar SK_MScalar1 = 1;
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct SkVector4 {
+ SkScalar fData[4];
+
+ SkVector4() {
+ this->set(0, 0, 0, 1);
+ }
+ SkVector4(const SkVector4& src) {
+ memcpy(fData, src.fData, sizeof(fData));
+ }
+ SkVector4(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
+ fData[0] = x;
+ fData[1] = y;
+ fData[2] = z;
+ fData[3] = w;
+ }
+
+ SkVector4& operator=(const SkVector4& src) {
+ memcpy(fData, src.fData, sizeof(fData));
+ return *this;
+ }
+
+ bool operator==(const SkVector4& v) {
+ return fData[0] == v.fData[0] && fData[1] == v.fData[1] &&
+ fData[2] == v.fData[2] && fData[3] == v.fData[3];
+ }
+ bool operator!=(const SkVector4& v) {
+ return !(*this == v);
+ }
+ bool equals(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
+ return fData[0] == x && fData[1] == y &&
+ fData[2] == z && fData[3] == w;
+ }
+
+ void set(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
+ fData[0] = x;
+ fData[1] = y;
+ fData[2] = z;
+ fData[3] = w;
+ }
+};
+
+class SK_API SkMatrix44 {
+public:
+ SkMatrix44();
+ SkMatrix44(const SkMatrix44&);
+ SkMatrix44(const SkMatrix44& a, const SkMatrix44& b);
+
+ SkMatrix44& operator=(const SkMatrix44& src) {
+ memcpy(this, &src, sizeof(*this));
+ return *this;
+ }
+
+ bool operator==(const SkMatrix44& other) const {
+ return !memcmp(this, &other, sizeof(*this));
+ }
+ bool operator!=(const SkMatrix44& other) const {
+ return !!memcmp(this, &other, sizeof(*this));
+ }
+
+ SkMatrix44(const SkMatrix&);
+ SkMatrix44& operator=(const SkMatrix& src);
+ operator SkMatrix() const;
+
+ SkMScalar get(int row, int col) const;
+ void set(int row, int col, const SkMScalar& value);
+
+ void asColMajorf(float[]) const;
+ void asColMajord(double[]) const;
+ void asRowMajorf(float[]) const;
+ void asRowMajord(double[]) const;
+
+ bool isIdentity() const;
+ void setIdentity();
+ void reset() { this->setIdentity();}
+
+ void set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
+ SkMScalar m10, SkMScalar m11, SkMScalar m12,
+ SkMScalar m20, SkMScalar m21, SkMScalar m22);
+
+ void setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
+ void preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
+ void postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
+
+ void setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
+ void preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
+ void postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
+
+ void setScale(SkMScalar scale) {
+ this->setScale(scale, scale, scale);
+ }
+ void preScale(SkMScalar scale) {
+ this->preScale(scale, scale, scale);
+ }
+ void postScale(SkMScalar scale) {
+ this->postScale(scale, scale, scale);
+ }
+
+ void setRotateDegreesAbout(SkMScalar x, SkMScalar y, SkMScalar z,
+ SkMScalar degrees) {
+ this->setRotateAbout(x, y, z, degrees * SK_MScalarPI / 180);
+ }
+
+ /** Rotate about the vector [x,y,z]. If that vector is not unit-length,
+ it will be automatically resized.
+ */
+ void setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
+ SkMScalar radians);
+ /** Rotate about the vector [x,y,z]. Does not check the length of the
+ vector, assuming it is unit-length.
+ */
+ void setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
+ SkMScalar radians);
+
+ void setConcat(const SkMatrix44& a, const SkMatrix44& b);
+ void preConcat(const SkMatrix44& m) {
+ this->setConcat(*this, m);
+ }
+ void postConcat(const SkMatrix44& m) {
+ this->setConcat(m, *this);
+ }
+
+ friend SkMatrix44 operator*(const SkMatrix44& a, const SkMatrix44& b) {
+ return SkMatrix44(a, b);
+ }
+
+ /** If this is invertible, return that in inverse and return true. If it is
+ not invertible, return false and ignore the inverse parameter.
+ */
+ bool invert(SkMatrix44* inverse) const;
+
+ /** Apply the matrix to the src vector, returning the new vector in dst.
+ It is legal for src and dst to point to the same memory.
+ */
+ void map(const SkScalar src[4], SkScalar dst[4]) const;
+ void map(SkScalar vec[4]) const {
+ this->map(vec, vec);
+ }
+
+ friend SkVector4 operator*(const SkMatrix44& m, const SkVector4& src) {
+ SkVector4 dst;
+ m.map(src.fData, dst.fData);
+ return dst;
+ }
+
+ void dump() const;
+
+private:
+ /* Stored in the same order as opengl:
+ [3][0] = tx
+ [3][1] = ty
+ [3][2] = tz
+ */
+ SkMScalar fMat[4][4];
+
+ double determinant() const;
+};
+
+#endif
diff --git a/include/utils/SkMeshUtils.h b/include/utils/SkMeshUtils.h
index 1235485..c7cdeca 100644
--- a/include/utils/SkMeshUtils.h
+++ b/include/utils/SkMeshUtils.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkMeshUtils_DEFINED
#define SkMeshUtils_DEFINED
diff --git a/include/utils/SkNWayCanvas.h b/include/utils/SkNWayCanvas.h
index 03bd6d1..4e39c6b 100644
--- a/include/utils/SkNWayCanvas.h
+++ b/include/utils/SkNWayCanvas.h
@@ -1,4 +1,11 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkNWayCanvas_DEFINED
#define SkNWayCanvas_DEFINED
@@ -16,56 +23,53 @@ public:
///////////////////////////////////////////////////////////////////////////
// These are forwarded to the N canvases we're referencing
- virtual int save(SaveFlags flags = kMatrixClip_SaveFlag);
- virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
- SaveFlags flags = kARGB_ClipLayer_SaveFlag);
- virtual void restore();
- virtual bool translate(SkScalar dx, SkScalar dy);
- virtual bool scale(SkScalar sx, SkScalar sy);
- virtual bool rotate(SkScalar degrees);
- virtual bool skew(SkScalar sx, SkScalar sy);
- virtual bool concat(const SkMatrix& matrix);
- virtual void setMatrix(const SkMatrix& matrix);
- virtual bool clipRect(const SkRect& rect,
- SkRegion::Op op = SkRegion::kIntersect_Op);
- virtual bool clipPath(const SkPath& path,
- SkRegion::Op op = SkRegion::kIntersect_Op);
+ virtual int save(SaveFlags) SK_OVERRIDE;
+ virtual int saveLayer(const SkRect* bounds, const SkPaint*,
+ SaveFlags) SK_OVERRIDE;
+ virtual void restore() SK_OVERRIDE;
+ virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE;
+ virtual bool scale(SkScalar sx, SkScalar sy) SK_OVERRIDE;
+ virtual bool rotate(SkScalar degrees) SK_OVERRIDE;
+ virtual bool skew(SkScalar sx, SkScalar sy) SK_OVERRIDE;
+ virtual bool concat(const SkMatrix& matrix) SK_OVERRIDE;
+ virtual void setMatrix(const SkMatrix& matrix) SK_OVERRIDE;
+ virtual bool clipRect(const SkRect&, SkRegion::Op, bool) SK_OVERRIDE;
+ virtual bool clipPath(const SkPath&, SkRegion::Op, bool) SK_OVERRIDE;
virtual bool clipRegion(const SkRegion& deviceRgn,
- SkRegion::Op op = SkRegion::kIntersect_Op);
+ SkRegion::Op) SK_OVERRIDE;
- virtual void drawPaint(const SkPaint& paint);
+ virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE;
virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
- const SkPaint& paint);
- virtual void drawRect(const SkRect& rect, const SkPaint& paint);
- virtual void drawPath(const SkPath& path, const SkPaint& paint);
+ const SkPaint&) SK_OVERRIDE;
+ virtual void drawRect(const SkRect& rect, const SkPaint&) SK_OVERRIDE;
+ virtual void drawPath(const SkPath& path, const SkPaint&) SK_OVERRIDE;
virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
- const SkPaint* paint = NULL);
+ const SkPaint*) SK_OVERRIDE;
virtual void drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
- const SkRect& dst, const SkPaint* paint = NULL);
+ const SkRect& dst, const SkPaint*) SK_OVERRIDE;
virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m,
- const SkPaint* paint = NULL);
+ const SkPaint*) SK_OVERRIDE;
virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
- const SkPaint* paint = NULL);
+ const SkPaint*) SK_OVERRIDE;
virtual void drawText(const void* text, size_t byteLength, SkScalar x,
- SkScalar y, const SkPaint& paint);
+ SkScalar y, const SkPaint&) SK_OVERRIDE;
virtual void drawPosText(const void* text, size_t byteLength,
- const SkPoint pos[], const SkPaint& paint);
+ const SkPoint pos[], const SkPaint&) SK_OVERRIDE;
virtual void drawPosTextH(const void* text, size_t byteLength,
const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint);
+ const SkPaint&) SK_OVERRIDE;
virtual void drawTextOnPath(const void* text, size_t byteLength,
const SkPath& path, const SkMatrix* matrix,
- const SkPaint& paint);
- virtual void drawPicture(SkPicture&);
- virtual void drawShape(SkShape*);
+ const SkPaint&) SK_OVERRIDE;
+ virtual void drawPicture(SkPicture&) SK_OVERRIDE;
virtual void drawVertices(VertexMode vmode, int vertexCount,
const SkPoint vertices[], const SkPoint texs[],
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
- const SkPaint& paint);
+ const SkPaint&) SK_OVERRIDE;
- virtual SkBounder* setBounder(SkBounder* bounder);
- virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter);
+ virtual SkBounder* setBounder(SkBounder*) SK_OVERRIDE;
+ virtual SkDrawFilter* setDrawFilter(SkDrawFilter*) SK_OVERRIDE;
private:
SkTDArray<SkCanvas*> fList;
diff --git a/include/utils/SkNinePatch.h b/include/utils/SkNinePatch.h
index a655621..b0ea46b 100644
--- a/include/utils/SkNinePatch.h
+++ b/include/utils/SkNinePatch.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkNinePatch_DEFINED
#define SkNinePatch_DEFINED
diff --git a/include/utils/SkParse.h b/include/utils/SkParse.h
index 57d040c..7491cd6 100644
--- a/include/utils/SkParse.h
+++ b/include/utils/SkParse.h
@@ -1,24 +1,16 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkParse_DEFINED
#define SkParse_DEFINED
#include "SkColor.h"
-#include "SkMath.h"
class SkParse {
public:
diff --git a/include/utils/SkParsePaint.h b/include/utils/SkParsePaint.h
index d23cd92..b35fcf1 100644
--- a/include/utils/SkParsePaint.h
+++ b/include/utils/SkParsePaint.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkParsePaint_DEFINED
#define SkParsePaint_DEFINED
diff --git a/include/utils/SkParsePath.h b/include/utils/SkParsePath.h
index d271f7e..b48c2c5 100644
--- a/include/utils/SkParsePath.h
+++ b/include/utils/SkParsePath.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkParsePath_DEFINED
#define SkParsePath_DEFINED
diff --git a/include/utils/SkProxyCanvas.h b/include/utils/SkProxyCanvas.h
index 6e55aa6..e96b9b2 100644
--- a/include/utils/SkProxyCanvas.h
+++ b/include/utils/SkProxyCanvas.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkProxyCanvas_DEFINED
#define SkProxyCanvas_DEFINED
@@ -19,64 +26,56 @@ public:
SkCanvas* getProxy() const { return fProxy; }
void setProxy(SkCanvas* proxy);
- // overrides from SkCanvas
-
- virtual int save(SaveFlags flags = kMatrixClip_SaveFlag);
+ virtual int save(SaveFlags flags = kMatrixClip_SaveFlag) SK_OVERRIDE;
virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
- SaveFlags flags = kARGB_ClipLayer_SaveFlag);
- virtual void restore();
+ SaveFlags flags = kARGB_ClipLayer_SaveFlag) SK_OVERRIDE;
+ virtual void restore() SK_OVERRIDE;
- virtual bool translate(SkScalar dx, SkScalar dy);
- virtual bool scale(SkScalar sx, SkScalar sy);
- virtual bool rotate(SkScalar degrees);
- virtual bool skew(SkScalar sx, SkScalar sy);
- virtual bool concat(const SkMatrix& matrix);
- virtual void setMatrix(const SkMatrix& matrix);
+ virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE;
+ virtual bool scale(SkScalar sx, SkScalar sy) SK_OVERRIDE;
+ virtual bool rotate(SkScalar degrees) SK_OVERRIDE;
+ virtual bool skew(SkScalar sx, SkScalar sy) SK_OVERRIDE;
+ virtual bool concat(const SkMatrix& matrix) SK_OVERRIDE;
+ virtual void setMatrix(const SkMatrix& matrix) SK_OVERRIDE;
- virtual bool clipRect(const SkRect& rect,
- SkRegion::Op op = SkRegion::kIntersect_Op);
- virtual bool clipPath(const SkPath& path,
- SkRegion::Op op = SkRegion::kIntersect_Op);
+ virtual bool clipRect(const SkRect&, SkRegion::Op, bool) SK_OVERRIDE;
+ virtual bool clipPath(const SkPath&, SkRegion::Op, bool) SK_OVERRIDE;
virtual bool clipRegion(const SkRegion& deviceRgn,
- SkRegion::Op op = SkRegion::kIntersect_Op);
+ SkRegion::Op op = SkRegion::kIntersect_Op) SK_OVERRIDE;
- virtual void drawPaint(const SkPaint& paint);
+ virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE;
virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
- const SkPaint& paint);
- virtual void drawRect(const SkRect& rect, const SkPaint& paint);
- virtual void drawPath(const SkPath& path, const SkPaint& paint);
+ const SkPaint& paint) SK_OVERRIDE;
+ virtual void drawRect(const SkRect& rect, const SkPaint& paint) SK_OVERRIDE;
+ virtual void drawPath(const SkPath& path, const SkPaint& paint) SK_OVERRIDE;
virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
- const SkPaint* paint = NULL);
+ const SkPaint* paint = NULL) SK_OVERRIDE;
virtual void drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
- const SkRect& dst, const SkPaint* paint = NULL);
+ const SkRect& dst, const SkPaint* paint = NULL) SK_OVERRIDE;
virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m,
- const SkPaint* paint = NULL);
+ const SkPaint* paint = NULL) SK_OVERRIDE;
virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
- const SkPaint* paint = NULL);
+ const SkPaint* paint = NULL) SK_OVERRIDE;
virtual void drawText(const void* text, size_t byteLength, SkScalar x,
- SkScalar y, const SkPaint& paint);
+ SkScalar y, const SkPaint& paint) SK_OVERRIDE;
virtual void drawPosText(const void* text, size_t byteLength,
- const SkPoint pos[], const SkPaint& paint);
+ const SkPoint pos[], const SkPaint& paint) SK_OVERRIDE;
virtual void drawPosTextH(const void* text, size_t byteLength,
const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint);
+ const SkPaint& paint) SK_OVERRIDE;
virtual void drawTextOnPath(const void* text, size_t byteLength,
const SkPath& path, const SkMatrix* matrix,
- const SkPaint& paint);
- virtual void drawPicture(SkPicture&);
- virtual void drawShape(SkShape*);
+ const SkPaint& paint) SK_OVERRIDE;
+ virtual void drawPicture(SkPicture&) SK_OVERRIDE;
virtual void drawVertices(VertexMode vmode, int vertexCount,
const SkPoint vertices[], const SkPoint texs[],
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
- const SkPaint& paint);
- virtual void drawData(const void* data, size_t length);
-
- virtual SkBounder* setBounder(SkBounder* bounder);
- virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter);
+ const SkPaint& paint) SK_OVERRIDE;
+ virtual void drawData(const void* data, size_t length) SK_OVERRIDE;
- virtual SkDevice* createDevice(SkBitmap::Config, int width, int height,
- bool isOpaque, bool isForLayer);
+ virtual SkBounder* setBounder(SkBounder* bounder) SK_OVERRIDE;
+ virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter) SK_OVERRIDE;
private:
SkCanvas* fProxy;
diff --git a/include/utils/SkSfntUtils.h b/include/utils/SkSfntUtils.h
index 1d8f74e..69c9c03 100644
--- a/include/utils/SkSfntUtils.h
+++ b/include/utils/SkSfntUtils.h
@@ -1,4 +1,11 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSfntUtils_DEFINED
#define SkSfntUtils_DEFINED
diff --git a/include/utils/SkTextBox.h b/include/utils/SkTextBox.h
index 3471f5b..e3b365d 100644
--- a/include/utils/SkTextBox.h
+++ b/include/utils/SkTextBox.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTextBox_DEFINED
#define SkTextBox_DEFINED
diff --git a/include/utils/SkUnitMappers.h b/include/utils/SkUnitMappers.h
index 51708b6..a14f1af 100644
--- a/include/utils/SkUnitMappers.h
+++ b/include/utils/SkUnitMappers.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkUnitMappers_DEFINED
#define SkUnitMappers_DEFINED
diff --git a/include/utils/SkWGL.h b/include/utils/SkWGL.h
new file mode 100644
index 0000000..8eae5af
--- /dev/null
+++ b/include/utils/SkWGL.h
@@ -0,0 +1,90 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRefCnt.h"
+
+#ifndef SkWGL_DEFINED
+#define SkWGL_DEFINED
+
+/**
+ * Working with WGL extensions can be a pain. Among the reasons is that You must
+ * have a GL context to get the proc addresses, but you want to use the procs to
+ * create a context in the first place. So you have to create a dummy GL ctx to
+ * get the proc addresses.
+ *
+ * This file helps by providing SkCreateWGLInterface(). It returns a struct of
+ * function pointers that it initializes. It also has a helper function to query
+ * for WGL extensions. It handles the fact that wglGetExtensionsString is itself
+ * an extension.
+ */
+
+#if !defined(WIN32_LEAN_AND_MEAN)
+ #define WIN32_LEAN_AND_MEAN
+ #define SK_LOCAL_LEAN_AND_MEAN
+#endif
+#include <Windows.h>
+#if defined(SK_LOCAL_LEAN_AND_MEAN)
+ #undef WIN32_LEAN_AND_MEAN
+ #undef SK_LOCAL_LEAN_AND_MEAN
+#endif
+
+#define SK_WGL_DRAW_TO_WINDOW 0x2001
+#define SK_WGL_ACCELERATION 0x2003
+#define SK_WGL_SUPPORT_OPENGL 0x2010
+#define SK_WGL_DOUBLE_BUFFER 0x2011
+#define SK_WGL_COLOR_BITS 0x2014
+#define SK_WGL_ALPHA_BITS 0x201B
+#define SK_WGL_STENCIL_BITS 0x2023
+#define SK_WGL_FULL_ACCELERATION 0x2027
+#define SK_WGL_SAMPLE_BUFFERS 0x2041
+#define SK_WGL_SAMPLES 0x2042
+#define SK_WGL_CONTEXT_MAJOR_VERSION 0x2091
+#define SK_WGL_CONTEXT_MINOR_VERSION 0x2092
+#define SK_WGL_CONTEXT_LAYER_PLANE 0x2093
+#define SK_WGL_CONTEXT_FLAGS 0x2094
+#define SK_WGL_CONTEXT_PROFILE_MASK 0x9126
+#define SK_WGL_CONTEXT_DEBUG_BIT 0x0001
+#define SK_WGL_CONTEXT_FORWARD_COMPATIBLE_BIT 0x0002
+#define SK_WGL_CONTEXT_CORE_PROFILE_BIT 0x00000001
+#define SK_WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
+#define SK_WGL_CONTEXT_ES2_PROFILE_BIT 0x00000004
+#define SK_ERROR_INVALID_VERSION 0x2095
+#define SK_ERROR_INVALID_PROFILE 0x2096
+
+class SkWGLExtensions {
+public:
+ SkWGLExtensions();
+ /**
+ * Determines if an extensions is available for a given DC.
+ * WGL_extensions_string is considered a prerequisite for all other
+ * extensions. It is necessary to check this before calling other class
+ * functions.
+ */
+ bool hasExtension(HDC dc, const char* ext) const;
+
+ const char* getExtensionsString(HDC hdc) const;
+ BOOL choosePixelFormat(HDC hdc, const int*, const FLOAT*, UINT, int*, UINT*) const;
+ BOOL getPixelFormatAttribiv(HDC, int, int, UINT, const int*, int*) const;
+ BOOL getPixelFormatAttribfv(HDC hdc, int, int, UINT, const int*, FLOAT*) const;
+ HGLRC createContextAttribs(HDC, HGLRC, const int *) const;
+
+private:
+ typedef const char* (WINAPI *GetExtensionsStringProc)(HDC hdc);
+ typedef BOOL (WINAPI *ChoosePixelFormatProc)(HDC hdc, const int *, const FLOAT *, UINT, int *, UINT *);
+ typedef BOOL (WINAPI *GetPixelFormatAttribivProc)(HDC, int, int, UINT, const int*, int*);
+ typedef BOOL (WINAPI *GetPixelFormatAttribfvProc)(HDC hdc, int, int, UINT, const int*, FLOAT*);
+ typedef HGLRC (WINAPI *CreateContextAttribsProc)(HDC hDC, HGLRC, const int *);
+
+ GetExtensionsStringProc fGetExtensionsString;
+ ChoosePixelFormatProc fChoosePixelFormat;
+ GetPixelFormatAttribfvProc fGetPixelFormatAttribfv;
+ GetPixelFormatAttribivProc fGetPixelFormatAttribiv;
+ CreateContextAttribsProc fCreateContextAttribs;
+};
+
+#endif
diff --git a/include/utils/android/AndroidKeyToSkKey.h b/include/utils/android/AndroidKeyToSkKey.h
index 7b0a035..6bcb148 100644
--- a/include/utils/android/AndroidKeyToSkKey.h
+++ b/include/utils/android/AndroidKeyToSkKey.h
@@ -1,23 +1,16 @@
+
/*
- * Copyright (C) 2011 Skia
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2011 Skia
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef _ANDROID_TO_SKIA_KEYCODES_H
#define _ANDROID_TO_SKIA_KEYCODES_H
-#include "keycodes.h"
+#include "android/keycodes.h"
#include "SkKey.h"
// Convert an Android keycode to an SkKey. This is an incomplete list, only
@@ -32,6 +25,8 @@ SkKey AndroidKeycodeToSkKey(int keycode) {
return kUp_SkKey;
case AKEYCODE_DPAD_DOWN:
return kDown_SkKey;
+ case AKEYCODE_BACK:
+ return kBack_SkKey;
default:
return kNONE_SkKey;
}
diff --git a/include/utils/ios/SkStream_NSData.h b/include/utils/ios/SkStream_NSData.h
new file mode 100755
index 0000000..0829a4f
--- /dev/null
+++ b/include/utils/ios/SkStream_NSData.h
@@ -0,0 +1,41 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef SkStream_NSData_DEFINED
+#define SkStream_NSData_DEFINED
+
+#import <UIKit/UIKit.h>
+#include "SkStream.h"
+
+/** Returns an NSData with a copy of the stream's data. The caller must call
+ retain if it intends to keep the data object beyond the current stack-frame
+ (i.e. internally we're calling [NSData dataWithBytes...]
+ */
+NSData* NSData_dataWithStream(SkStream* stream);
+
+/** Returns an NSData from the named resource (from main bundle).
+ The caller must call retain if it intends to keep the data object beyond
+ the current stack-frame
+ (i.e. internally we're calling [NSData dataWithContentsOfMappedFile...]
+ */
+NSData* NSData_dataFromResource(const char name[], const char suffix[]);
+
+/** Wrap a stream around NSData.
+ */
+class SkStream_NSData : public SkMemoryStream {
+public:
+ SkStream_NSData(NSData* data);
+ virtual ~SkStream_NSData();
+
+ static SkStream_NSData* CreateFromResource(const char name[],
+ const char suffix[]);
+
+private:
+ NSData* fNSData;
+};
+
+#endif
diff --git a/include/utils/mac/SkCGUtils.h b/include/utils/mac/SkCGUtils.h
index db67edf..055e24c 100644
--- a/include/utils/mac/SkCGUtils.h
+++ b/include/utils/mac/SkCGUtils.h
@@ -1,15 +1,25 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkCGUtils_DEFINED
#define SkCGUtils_DEFINED
#include "SkTypes.h"
#ifdef SK_BUILD_FOR_MAC
- #include <Carbon/Carbon.h>
-#else
- #include <CoreGraphics/CoreGraphics.h>
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
+#ifdef SK_BUILD_FOR_IOS
+#include <CoreGraphics/CoreGraphics.h>
#endif
class SkBitmap;
+class SkStream;
/**
* Create an imageref from the specified bitmap using the specified colorspace.
@@ -34,4 +44,6 @@ static inline CGImageRef SkCreateCGImageRef(const SkBitmap& bm) {
*/
void SkCGDrawBitmap(CGContextRef, const SkBitmap&, float x, float y);
+bool SkPDFDocumentToBitmap(SkStream* stream, SkBitmap* output);
+
#endif
diff --git a/include/utils/unix/XkeysToSkKeys.h b/include/utils/unix/XkeysToSkKeys.h
index 1852d99..30eb97d 100644
--- a/include/utils/unix/XkeysToSkKeys.h
+++ b/include/utils/unix/XkeysToSkKeys.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "X11/Xlib.h"
#include "X11/keysym.h"
diff --git a/include/utils/unix/keysym2ucs.h b/include/utils/unix/keysym2ucs.h
index 1ae6fe4..255a930 100644
--- a/include/utils/unix/keysym2ucs.h
+++ b/include/utils/unix/keysym2ucs.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
/*
* This module converts keysym values into the corresponding ISO 10646-1
* (UCS, Unicode) values.
diff --git a/include/utils/win/SkAutoCoInitialize.h b/include/utils/win/SkAutoCoInitialize.h
new file mode 100644
index 0000000..709fa6b
--- /dev/null
+++ b/include/utils/win/SkAutoCoInitialize.h
@@ -0,0 +1,30 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkAutoCo_DEFINED
+#define SkAutoCo_DEFINED
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include "SkTemplates.h"
+
+/**
+ * An instance of this class initializes COM on creation
+ * and closes the COM library on destruction.
+ */
+class SkAutoCoInitialize : SkNoncopyable {
+private:
+ HRESULT fHR;
+public:
+ SkAutoCoInitialize();
+ ~SkAutoCoInitialize();
+ bool succeeded();
+};
+
+#endif
diff --git a/include/utils/win/SkHRESULT.h b/include/utils/win/SkHRESULT.h
new file mode 100644
index 0000000..ff596c7
--- /dev/null
+++ b/include/utils/win/SkHRESULT.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkHRESULT_DEFINED
+#define SkHRESULT_DEFINED
+
+#include "SkTypes.h"
+
+void SkTraceHR(const char* file, unsigned long line,
+ HRESULT hr, const char* msg);
+
+#ifdef SK_DEBUG
+#define SK_TRACEHR(_hr, _msg) SkTraceHR(__FILE__, __LINE__, _hr, _msg)
+#else
+#define SK_TRACEHR(_hr, _msg) _hr
+#endif
+
+#define HR_GENERAL(_ex, _msg, _ret) {\
+ HRESULT _hr = _ex;\
+ if (FAILED(_hr)) {\
+ SK_TRACEHR(_hr, _msg);\
+ return _ret;\
+ }\
+}
+
+//@{
+/**
+These macros are for reporting HRESULT errors.
+The expression will be evaluated.
+If the resulting HRESULT SUCCEEDED then execution will continue normally.
+If the HRESULT FAILED then the macro will return from the current function.
+In variants ending with 'M' the given message will be traced when FAILED.
+The HR variants will return the HRESULT when FAILED.
+The HRB variants will return false when FAILED.
+The HRV variants will simply return when FAILED.
+*/
+#define HR(ex) HR_GENERAL(ex, NULL, _hr)
+#define HRM(ex, msg) HR_GENERAL(ex, msg, _hr)
+
+#define HRB(ex) HR_GENERAL(ex, NULL, false)
+#define HRBM(ex, msg) HR_GENERAL(ex, msg, false)
+
+#define HRV(ex) HR_GENERAL(ex, NULL, )
+#define HRVM(ex, msg) HR_GENERAL(ex, msg, )
+//@}
+#endif
diff --git a/include/utils/win/SkIStream.h b/include/utils/win/SkIStream.h
new file mode 100644
index 0000000..b7d0949
--- /dev/null
+++ b/include/utils/win/SkIStream.h
@@ -0,0 +1,131 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkIStream_DEFINED
+#define SkIStream_DEFINED
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <ole2.h>
+
+class SkStream;
+class SkWStream;
+
+/**
+ * A bare IStream implementation which properly reference counts
+ * but returns E_NOTIMPL for all ISequentialStream and IStream methods.
+ */
+class SkBaseIStream : public IStream {
+private:
+ LONG _refcount;
+
+protected:
+ explicit SkBaseIStream();
+ virtual ~SkBaseIStream();
+
+public:
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid
+ , void ** ppvObject);
+ virtual ULONG STDMETHODCALLTYPE AddRef(void);
+ virtual ULONG STDMETHODCALLTYPE Release(void);
+
+ // ISequentialStream Interface
+public:
+ virtual HRESULT STDMETHODCALLTYPE Read(void* pv, ULONG cb, ULONG* pcbRead);
+
+ virtual HRESULT STDMETHODCALLTYPE Write(void const* pv
+ , ULONG cb
+ , ULONG* pcbWritten);
+
+ // IStream Interface
+public:
+ virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER);
+
+ virtual HRESULT STDMETHODCALLTYPE CopyTo(IStream*
+ , ULARGE_INTEGER
+ , ULARGE_INTEGER*
+ , ULARGE_INTEGER*);
+
+ virtual HRESULT STDMETHODCALLTYPE Commit(DWORD);
+
+ virtual HRESULT STDMETHODCALLTYPE Revert(void);
+
+ virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER
+ , ULARGE_INTEGER
+ , DWORD);
+
+ virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER
+ , ULARGE_INTEGER
+ , DWORD);
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(IStream **);
+
+ virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove
+ , DWORD dwOrigin
+ , ULARGE_INTEGER* lpNewFilePointer);
+
+ virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg
+ , DWORD grfStatFlag);
+};
+
+/**
+ * A minimal read-only IStream implementation which wraps an SkIStream.
+ */
+class SkIStream : public SkBaseIStream {
+private:
+ SkStream *fSkStream;
+ bool fUnrefOnRelease;
+ ULARGE_INTEGER fLocation;
+
+ SkIStream(SkStream* stream, bool unrefOnRelease);
+ virtual ~SkIStream();
+
+public:
+ HRESULT static CreateFromSkStream(SkStream* stream
+ , bool unrefOnRelease
+ , IStream ** ppStream);
+
+ virtual HRESULT STDMETHODCALLTYPE Read(void* pv, ULONG cb, ULONG* pcbRead);
+
+ virtual HRESULT STDMETHODCALLTYPE Write(void const* pv
+ , ULONG cb
+ , ULONG* pcbWritten);
+
+ virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER liDistanceToMove
+ , DWORD dwOrigin
+ , ULARGE_INTEGER* lpNewFilePointer);
+
+ virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg
+ , DWORD grfStatFlag);
+};
+
+/**
+ * A minimal write-only IStream implementation which wraps an SkWIStream.
+ */
+class SkWIStream : public SkBaseIStream {
+private:
+ SkWStream *fSkWStream;
+
+ SkWIStream(SkWStream* stream);
+ virtual ~SkWIStream();
+
+public:
+ HRESULT static CreateFromSkWStream(SkWStream* stream, IStream ** ppStream);
+
+ virtual HRESULT STDMETHODCALLTYPE Write(void const* pv
+ , ULONG cb
+ , ULONG* pcbWritten);
+
+ virtual HRESULT STDMETHODCALLTYPE Commit(DWORD);
+
+ virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG* pStatstg
+ , DWORD grfStatFlag);
+};
+
+#endif
diff --git a/include/utils/win/SkTScopedComPtr.h b/include/utils/win/SkTScopedComPtr.h
new file mode 100644
index 0000000..b9be037
--- /dev/null
+++ b/include/utils/win/SkTScopedComPtr.h
@@ -0,0 +1,64 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkSkTScopedPtr_DEFINED
+#define SkSkTScopedPtr_DEFINED
+
+#include "SkTypes.h"
+#include "SkTemplates.h"
+
+template<typename T>
+class SkBlockComRef : public T {
+private:
+ virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;
+ virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
+};
+
+template<typename T>
+class SkTScopedComPtr : SkNoncopyable {
+private:
+ T *fPtr;
+
+public:
+ explicit SkTScopedComPtr(T *ptr = NULL) : fPtr(ptr) { }
+ ~SkTScopedComPtr() {
+ this->reset();
+ }
+ T &operator*() const { return *fPtr; }
+ SkBlockComRef<T> *operator->() const {
+ return static_cast<SkBlockComRef<T>*>(fPtr);
+ }
+ /**
+ * Returns the address of the underlying pointer.
+ * This is dangerous -- it breaks encapsulation and the reference escapes.
+ * Must only be used on instances currently pointing to NULL,
+ * and only to initialize the instance.
+ */
+ T **operator&() { SkASSERT(fPtr == NULL); return &fPtr; }
+ T *get() const { return fPtr; }
+ void reset() {
+ if (NULL != this->fPtr) {
+ this->fPtr->Release();
+ this->fPtr = NULL;
+ }
+ }
+
+ void swap(SkTScopedComPtr<T>& that) {
+ T* temp = this->fPtr;
+ this->fPtr = that.fPtr;
+ that.fPtr = temp;
+ }
+
+ T* release() {
+ T* temp = this->fPtr;
+ this->fPtr = NULL;
+ return temp;
+ }
+};
+
+#endif
diff --git a/include/views/SkApplication.h b/include/views/SkApplication.h
index 4c4a4fb..8369f68 100644
--- a/include/views/SkApplication.h
+++ b/include/views/SkApplication.h
@@ -1,25 +1,18 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkApplication_DEFINED
#define SkApplication_DEFINED
class SkOSWindow;
-extern SkOSWindow* create_sk_window(void* hwnd);
+extern SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv);
extern void application_init();
extern void application_term();
diff --git a/include/views/SkBGViewArtist.h b/include/views/SkBGViewArtist.h
index 1bca42f..869beab 100644
--- a/include/views/SkBGViewArtist.h
+++ b/include/views/SkBGViewArtist.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkBGViewArtist_DEFINED
#define SkBGViewArtist_DEFINED
diff --git a/include/views/SkBorderView.h b/include/views/SkBorderView.h
index 94ccc1f..02f8725 100644
--- a/include/views/SkBorderView.h
+++ b/include/views/SkBorderView.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkBorderView_DEFINED
#define SkBorderView_DEFINED
diff --git a/include/views/SkEvent.h b/include/views/SkEvent.h
index f6719d6..b3a07e9 100644
--- a/include/views/SkEvent.h
+++ b/include/views/SkEvent.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkEvent_DEFINED
#define SkEvent_DEFINED
@@ -28,62 +21,111 @@
*/
typedef uint32_t 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
+ *
+ * When an event is dispatched from the event queue, it is either sent to
+ * the eventsink matching the target ID (if not 0), or the target proc is
+ * called (if not NULL).
+ */
class SkEvent {
public:
- /** Default construct, creating an empty event.
- */
+ /**
+ * Function pointer that takes an event, returns true if it "handled" it.
+ */
+ typedef bool (*Proc)(const SkEvent& evt);
+
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.
- */
+ explicit SkEvent(const SkString& type, SkEventSinkID = 0);
+ explicit SkEvent(const char type[], SkEventSinkID = 0);
SkEvent(const SkEvent& src);
~SkEvent();
-// /** Return the event's type (will never be null) */
-// const char* getType() const;
/** Copy the event's type into the specified SkString parameter */
- void getType(SkString* str) const;
+ 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;
+ 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);
+ bool isType(const char type[], size_t len = 0) const;
+
+ /**
+ * Set the event's type to the specified string.
+ */
+ void setType(const SkString&);
+
+ /**
+ * Set the event's type to the specified string.
+ */
+ void setType(const char type[], size_t len = 0);
+
+ /**
+ * Return the target ID, or 0 if there is none.
+ *
+ * When an event is dispatched from the event queue, it is either sent to
+ * the eventsink matching the targetID (if not 0), or the target proc is
+ * called (if not NULL).
+ */
+ SkEventSinkID getTargetID() const { return fTargetID; }
+
+ /**
+ * Set the target ID for this event. 0 means none. Calling this will
+ * automatically clear the targetProc to null.
+ *
+ * When an event is dispatched from the event queue, it is either sent to
+ * the eventsink matching the targetID (if not 0), or the target proc is
+ * called (if not NULL).
+ */
+ SkEvent* setTargetID(SkEventSinkID targetID) {
+ fTargetProc = NULL;
+ fTargetID = targetID;
+ return this;
+ }
+
+ /**
+ * Return the target proc, or NULL if it has none.
+ *
+ * When an event is dispatched from the event queue, it is either sent to
+ * the eventsink matching the targetID (if not 0), or the target proc is
+ * called (if not NULL).
+ */
+ Proc getTargetProc() const { return fTargetProc; }
- /** Return the event's unnamed 32bit field. Default value is 0 */
+ /**
+ * Set the target ID for this event. NULL means none. Calling this will
+ * automatically clear the targetID to 0.
+ *
+ * When an event is dispatched from the event queue, it is either sent to
+ * the eventsink matching the targetID (if not 0), or the target proc is
+ * called (if not NULL).
+ */
+ SkEvent* setTargetProc(Proc proc) {
+ fTargetID = 0;
+ fTargetProc = proc;
+ return this;
+ }
+
+ /**
+ * Return the event's unnamed 32bit field. Default value is 0
+ */
uint32_t 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; }
+
+ /**
+ * Set the event's unnamed 32bit field.
+ */
+ 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-null). If there is no matching named field, return false
and ignore the value parameter.
*/
- bool findS32(const char name[], int32_t* value = NULL) const { return fMeta.findS32(name, value); }
+ bool findS32(const char name[], int32_t* value = NULL) 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-null). If there is no matching named field, return false
and ignore the value parameter.
*/
- bool findScalar(const char name[], SkScalar* value = NULL) const { return fMeta.findScalar(name, value); }
+ bool findScalar(const char name[], SkScalar* value = NULL) 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-null), and return the number of SkScalars in count (if count is non-null).
If there is no matching named field, return false and ignore the value and count parameters.
@@ -96,89 +138,82 @@ public:
in value (if value is non-null). 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); }
+ 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); }
const void* findData(const char name[], size_t* byteCount = NULL) const {
return fMeta.findData(name, byteCount);
}
/** 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); }
+ 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); }
+ 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); }
+ 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); }
+ 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); }
bool hasData(const char name[], const void* data, size_t byteCount) const {
return fMeta.hasData(name, data, byteCount);
}
/** 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); }
+ 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); }
+ 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[] = NULL) { 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()); }
+ 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); }
+ 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); }
+ void setPtr(const char name[], void* value) { fMeta.setPtr(name, value); }
+ void setBool(const char name[], bool value) { fMeta.setBool(name, value); }
void setData(const char name[], const void* data, size_t byteCount) {
fMeta.setData(name, data, byteCount);
}
/** Return the underlying metadata object */
- SkMetaData& getMetaData() { return fMeta; }
+ 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
- }
+ const SkMetaData& getMetaData() const { return fMeta; }
/** Call this to initialize the event from the specified XML node */
- void inflate(const SkDOM&, const SkDOM::Node*);
+ void inflate(const SkDOM&, const SkDOM::Node*);
SkDEBUGCODE(void dump(const char title[] = NULL);)
- /** 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);
+ /**
+ * Post to the event queue using the event's targetID or target-proc.
+ *
+ * The event must be dynamically allocated, as ownership is transferred to
+ * the event queue. It cannot be allocated on the stack or in a global.
+ */
+ void post() {
+ return this->postDelay(0);
}
+
+ /**
+ * Post to the event queue using the event's targetID or target-proc and
+ * the specifed millisecond delay.
+ *
+ * The event must be dynamically allocated, as ownership is transferred to
+ * the event queue. It cannot be allocated on the stack or in a global.
+ */
+ void postDelay(SkMSec delay);
+
+ /**
+ * Post to the event queue using the event's targetID or target-proc.
+ * The event will be delivered no sooner than the specified millisecond
+ * time, as measured by SkTime::GetMSecs().
+ *
+ * The event must be dynamically allocated, as ownership is transferred to
+ * the event queue. It cannot be allocated on the stack or in a global.
+ */
+ void postTime(SkMSec time);
///////////////////////////////////////////////
/** Porting layer must call these functions **/
@@ -188,21 +223,21 @@ public:
once before any other event method is called, and should be called after the
call to SkGraphics::Init().
*/
- static void 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();
+ 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();
+ 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();
+ static void ServiceQueueTimer();
/** Return the number of queued events. note that this value may be obsolete
upon return, since another thread may have called ProcessEvent() or
@@ -239,17 +274,20 @@ private:
SkMetaData fMeta;
mutable char* fType; // may be characters with low bit set to know that it is not a pointer
uint32_t f32;
- SkDEBUGCODE(bool fDebugTrace;)
- // these are for our implementation of the event queue
+ // 'there can be only one' (non-zero) between target-id and target-proc
SkEventSinkID fTargetID;
+ Proc fTargetProc;
+
+ // these are for our implementation of the event queue
SkMSec fTime;
SkEvent* fNextEvent; // either in the delay or normal event queue
- void initialize(const char* type, size_t typeLen);
+
+ void initialize(const char* type, size_t typeLen, SkEventSinkID);
static bool Enqueue(SkEvent* evt);
static SkMSec EnqueueTime(SkEvent* evt, SkMSec time);
- static SkEvent* Dequeue(SkEventSinkID* targetID);
+ static SkEvent* Dequeue();
static bool QHasEvents();
};
diff --git a/include/views/SkEventSink.h b/include/views/SkEventSink.h
index 27a6743..69981fa 100644
--- a/include/views/SkEventSink.h
+++ b/include/views/SkEventSink.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkEventSink_DEFINED
#define SkEventSink_DEFINED
@@ -31,53 +24,66 @@ public:
SkEventSink();
virtual ~SkEventSink();
- /** Returns this eventsink's unique ID. Use this to post SkEvents to
- this eventsink.
- */
+ /**
+ * 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.
- */
+ /**
+ * 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
- */
+ /**
+ * 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);
+
+ /**
+ * 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.
+ * This ignores the targetID and target proc in evt.
+ */
+ 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 null if not found
- */
+ /**
+ * DoEvent handles dispatching the event to its target ID or proc.
+ */
+ static EventResult DoEvent(const SkEvent&);
+
+ /**
+ * Returns the matching eventsink, or null if not found
+ */
static SkEventSink* FindSink(SkEventSinkID);
protected:
diff --git a/include/views/SkImageView.h b/include/views/SkImageView.h
index 57215c9..e179141 100644
--- a/include/views/SkImageView.h
+++ b/include/views/SkImageView.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkImageView_DEFINED
#define SkImageView_DEFINED
diff --git a/include/views/SkKey.h b/include/views/SkKey.h
index 3fd5114..4db3108 100644
--- a/include/views/SkKey.h
+++ b/include/views/SkKey.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkKey_DEFINED
#define SkKey_DEFINED
diff --git a/include/views/SkOSMenu.h b/include/views/SkOSMenu.h
index 433a601..0c4a619 100644
--- a/include/views/SkOSMenu.h
+++ b/include/views/SkOSMenu.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkOSMenu_DEFINED
#define SkOSMenu_DEFINED
@@ -22,30 +15,165 @@
class SkOSMenu {
public:
- explicit SkOSMenu(const char title[]);
+ explicit SkOSMenu(const char title[] = "");
~SkOSMenu();
-
- const char* getTitle() const { return fTitle; }
-
- void appendItem(const char title[], const char eventType[], int32_t eventData);
-
- // called by SkOSWindow when it receives an OS menu event
- int countItems() const;
- const char* getItem(int index, uint32_t* cmdID) const;
-
- SkEvent* createEvent(uint32_t os_cmd);
-
-private:
- const char* fTitle;
-
- struct Item {
- const char* fTitle;
- const char* fEventType;
- uint32_t fEventData;
- uint32_t fOSCmd; // internal
+
+ /**
+ * Each of these (except action) has an associated value, which is stored in
+ * the event payload for the item.
+ * Each type has a specific type for its value...
+ * Action : none
+ * List : int (selected index)
+ * Segmented : int (selected index)
+ * Slider : float
+ * Switch : bool
+ * TextField : string
+ * TriState : TriState
+ * Custom : custom object/value
+ */
+ enum Type {
+ kAction_Type,
+ kList_Type,
+ kSlider_Type,
+ kSwitch_Type,
+ kTriState_Type,
+ kTextField_Type,
+ kCustom_Type
};
- SkTDArray<Item> fItems;
+
+ enum TriState {
+ kMixedState = -1,
+ kOffState = 0,
+ kOnState = 1
+ };
+
+ class Item {
+ public:
+ /**
+ * Auto increments a global to generate an unique ID for each new item
+ * Note: Thread safe
+ */
+ Item(const char label[], SkOSMenu::Type type, const char slotName[],
+ SkEvent* evt);
+ ~Item() { delete fEvent; }
+
+ SkEvent* getEvent() const { return fEvent; }
+ int getID() const { return fID; }
+ const char* getLabel() const { return fLabel.c_str(); }
+ const char* getSlotName() const { return fSlotName.c_str(); }
+ Type getType() const { return fType; }
+ void setKeyEquivalent(SkUnichar key) { fKey = key; }
+ SkUnichar getKeyEquivalent() const { return fKey; }
+
+ /**
+ * Helper functions for predefined types
+ */
+ void setBool(bool value) const; //For Switch
+ void setScalar(SkScalar value) const; //For Slider
+ void setInt(int value) const; //For List
+ void setTriState(TriState value) const; //For Tristate
+ void setString(const char value[]) const; //For TextField
+
+ /**
+ * Post event associated with the menu item to target, any changes to
+ * the associated event must be made prior to calling this method
+ */
+ void postEvent() const { (new SkEvent(*(fEvent)))->post(); }
+ private:
+ int fID;
+ SkEvent* fEvent;
+ SkString fLabel;
+ SkString fSlotName;
+ Type fType;
+ SkUnichar fKey;
+ };
+
+ void reset();
+ const char* getTitle() const { return fTitle.c_str(); }
+ void setTitle (const char title[]) { fTitle.set(title); }
+ int getCount() const { return fItems.count(); }
+ const Item* getItemByID(int itemID) const;
+ void getItems(const Item* items[]) const;
+
+ /**
+ * Assign key to the menu item with itemID, will do nothing if there's no
+ * item with the id given
+ */
+ void assignKeyEquivalentToItem(int itemID, SkUnichar key);
+ /**
+ * Call this in a SkView's onHandleChar to trigger any menu items with the
+ * given key equivalent. If such an item is found, the method will return
+ * true and its corresponding event will be triggered (default behavior
+ * defined for switches(toggling), tristates(cycle), and lists(cycle),
+ * for anything else, the event attached is posted without state changes)
+ * If no menu item can be matched with the key, false will be returned
+ */
+ bool handleKeyEquivalent(SkUnichar key);
+
+ /**
+ * The following functions append new items to the menu and returns their
+ * associated unique id, which can be used to by the client to refer to
+ * the menu item created and change its state. slotName specifies the string
+ * identifier of any state/value to be returned in the item's SkEvent object
+ * NOTE: evt must be dynamically allocated
+ */
+ int appendItem(const char label[], Type type, const char slotName[],
+ SkEvent* evt);
+
+ /**
+ * Create predefined items with the given parameters. To be used with the
+ * other helper functions below to retrive/update state information.
+ * Note: the helper functions below assume that slotName is UNIQUE for all
+ * menu items of the same type since it's used to identify the event
+ */
+ int appendAction(const char label[], SkEventSinkID target);
+ int appendList(const char label[], const char slotName[],
+ SkEventSinkID target, int defaultIndex, const char[] ...);
+ int appendSlider(const char label[], const char slotName[],
+ SkEventSinkID target, SkScalar min, SkScalar max,
+ SkScalar defaultValue);
+ int appendSwitch(const char label[], const char slotName[],
+ SkEventSinkID target, bool defaultState = false);
+ int appendTriState(const char label[], const char slotName[],
+ SkEventSinkID target, TriState defaultState = kOffState);
+ int appendTextField(const char label[], const char slotName[],
+ SkEventSinkID target, const char placeholder[] = "");
+
+
+ /**
+ * Helper functions to retrieve information other than the stored value for
+ * some predefined types
+ */
+ static bool FindListItemCount(const SkEvent& evt, int* count);
+ /**
+ * Ensure that the items array can store n SkStrings where n is the count
+ * extracted using FindListItemCount
+ */
+ static bool FindListItems(const SkEvent& evt, SkString items[]);
+ static bool FindSliderMin(const SkEvent& evt, SkScalar* min);
+ static bool FindSliderMax(const SkEvent& evt, SkScalar* max);
+
+ /**
+ * Returns true if an action with the given label is found, false otherwise
+ */
+ static bool FindAction(const SkEvent& evt, const char label[]);
+ /**
+ * The following helper functions will return true if evt is generated from
+ * a predefined item type and retrieve the corresponding state information.
+ * They will return false and leave value unchanged if there's a type
+ * mismatch or slotName is incorrect
+ */
+ static bool FindListIndex(const SkEvent& evt, const char slotName[], int* value);
+ static bool FindSliderValue(const SkEvent& evt, const char slotName[], SkScalar* value);
+ static bool FindSwitchState(const SkEvent& evt, const char slotName[], bool* value);
+ static bool FindTriState(const SkEvent& evt, const char slotName[], TriState* value);
+ static bool FindText(const SkEvent& evt, const char slotName[], SkString* value);
+
+private:
+ SkString fTitle;
+ SkTDArray<Item*> fItems;
+
// illegal
SkOSMenu(const SkOSMenu&);
SkOSMenu& operator=(const SkOSMenu&);
diff --git a/include/views/SkOSWindow_Android.h b/include/views/SkOSWindow_Android.h
index 38a4cf8..bdce5d0 100644
--- a/include/views/SkOSWindow_Android.h
+++ b/include/views/SkOSWindow_Android.h
@@ -1,33 +1,30 @@
+
/*
- * Copyright (C) 2011 Skia
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2011 Skia
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkOSWindow_Android_DEFINED
#define SkOSWindow_Android_DEFINED
#include "SkWindow.h"
-#include "SkEvent.h"
+
+class SkIRect;
class SkOSWindow : public SkWindow {
public:
SkOSWindow(void*) {}
~SkOSWindow() {}
- bool attachGL() { return false; }
+ bool attachGL() { return true; }
void detachGL() {}
void presentGL() {}
+ virtual void onPDFSaved(const char title[], const char desc[],
+ const char path[]);
+
protected:
// overrides from SkWindow
virtual void onHandleInval(const SkIRect&);
diff --git a/include/views/SkOSWindow_Mac.h b/include/views/SkOSWindow_Mac.h
index 232a202..b09f1dd 100644
--- a/include/views/SkOSWindow_Mac.h
+++ b/include/views/SkOSWindow_Mac.h
@@ -1,45 +1,28 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
-#ifndef SkOSWindow_Mac_DEFINED
-#define SkOSWindow_Mac_DEFINED
+#ifndef SkOSWindow_MacCocoa_DEFINED
+#define SkOSWindow_MacCocoa_DEFINED
-#include <Carbon/Carbon.h>
#include "SkWindow.h"
class SkOSWindow : public SkWindow {
public:
SkOSWindow(void* hwnd);
-
+ ~SkOSWindow();
void* getHWND() const { return fHWND; }
- void* getHVIEW() const { return fHVIEW; }
- void updateSize();
-
- static bool PostEvent(SkEvent* evt, SkEventSinkID, SkMSec delay);
-
- static OSStatus EventHandler(EventHandlerCallRef inHandler,
- EventRef inEvent, void* userData);
-
- void doPaint(void* ctx);
-
-
- bool attachGL();
- void detachGL();
- void presentGL();
-
+
+ virtual bool onDispatchClick(int x, int y, Click::State state,
+ void* owner);
+ void detachGL();
+ bool attachGL();
+ void presentGL();
+
protected:
// overrides from SkEventSink
virtual bool onEvent(const SkEvent& evt);
@@ -47,16 +30,15 @@ protected:
virtual void onHandleInval(const SkIRect&);
// overrides from SkView
virtual void onAddMenu(const SkOSMenu*);
+ virtual void onUpdateMenu(const SkOSMenu*);
virtual void onSetTitle(const char[]);
-
private:
void* fHWND;
- void* fHVIEW;
- void* fAGLCtx;
-
+ bool fInvalEventIsPending;
+ void* fNotifier;
+ void* fGLContext;
typedef SkWindow INHERITED;
};
#endif
-
diff --git a/include/views/SkOSWindow_SDL.h b/include/views/SkOSWindow_SDL.h
index 0ff24f3..037de3b 100644
--- a/include/views/SkOSWindow_SDL.h
+++ b/include/views/SkOSWindow_SDL.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkOSWindow_SDL_DEFINED
#define SkOSWindow_SDL_DEFINED
diff --git a/include/views/SkOSWindow_Unix.h b/include/views/SkOSWindow_Unix.h
index 45b53d5..d688fb5 100644
--- a/include/views/SkOSWindow_Unix.h
+++ b/include/views/SkOSWindow_Unix.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkOSWindow_Unix_DEFINED
#define SkOSWindow_Unix_DEFINED
diff --git a/include/views/SkOSWindow_Win.h b/include/views/SkOSWindow_Win.h
index 4b3e916..bd6b4bd 100644
--- a/include/views/SkOSWindow_Win.h
+++ b/include/views/SkOSWindow_Win.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkOSWindow_Win_DEFINED
#define SkOSWindow_Win_DEFINED
diff --git a/include/views/SkOSWindow_iOS.h b/include/views/SkOSWindow_iOS.h
new file mode 100755
index 0000000..ff28484
--- /dev/null
+++ b/include/views/SkOSWindow_iOS.h
@@ -0,0 +1,43 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef SkOSWindow_iOS_DEFINED
+#define SkOSWindow_iOS_DEFINED
+
+#include "SkWindow.h"
+
+class SkOSWindow : public SkWindow {
+public:
+ SkOSWindow(void* hwnd);
+ ~SkOSWindow();
+ void* getHWND() const { return fHWND; }
+
+ virtual bool onDispatchClick(int x, int y, Click::State state,
+ void* owner);
+ void detachGL();
+ bool attachGL();
+ void presentGL();
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onEvent(const SkEvent& evt);
+ // overrides from SkWindow
+ virtual void onHandleInval(const SkIRect&);
+ // overrides from SkView
+ virtual void onAddMenu(const SkOSMenu*);
+ virtual void onUpdateMenu(const SkOSMenu*);
+ virtual void onSetTitle(const char[]);
+
+private:
+ void* fHWND;
+ bool fInvalEventIsPending;
+ void* fNotifier;
+ typedef SkWindow INHERITED;
+};
+
+#endif
+
diff --git a/include/views/SkOSWindow_wxwidgets.h b/include/views/SkOSWindow_wxwidgets.h
index c5dfc7c..a662b40 100644
--- a/include/views/SkOSWindow_wxwidgets.h
+++ b/include/views/SkOSWindow_wxwidgets.h
@@ -1,25 +1,8 @@
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * SkOSWindow_wxwidgets.h
- * wxwidgets
- *
- * Copyright 2005 __MyCompanyName__. All rights reserved.
+ * Copyright 2006 The Android Open Source Project
*
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
#ifndef SkOSWindow_wxwidgets_DEFINED
diff --git a/include/views/SkProgressBarView.h b/include/views/SkProgressBarView.h
index 6341fcb..0e39d1e 100644
--- a/include/views/SkProgressBarView.h
+++ b/include/views/SkProgressBarView.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkProgressBarView_DEFINED
#define SkProgressBarView_DEFINED
diff --git a/include/views/SkScrollBarView.h b/include/views/SkScrollBarView.h
index b8a5209..110d0e1 100644
--- a/include/views/SkScrollBarView.h
+++ b/include/views/SkScrollBarView.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkScrollBarView_DEFINED
#define SkScrollBarView_DEFINED
diff --git a/include/views/SkStackViewLayout.h b/include/views/SkStackViewLayout.h
index 8000319..705ff74 100644
--- a/include/views/SkStackViewLayout.h
+++ b/include/views/SkStackViewLayout.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkStackViewLayout_DEFINED
#define SkStackViewLayout_DEFINED
diff --git a/include/views/SkSystemEventTypes.h b/include/views/SkSystemEventTypes.h
index 8dfe8be..f0f2952 100644
--- a/include/views/SkSystemEventTypes.h
+++ b/include/views/SkSystemEventTypes.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkSystemEventTypes_DEFINED
#define SkSystemEventTypes_DEFINED
diff --git a/include/views/SkTouchGesture.h b/include/views/SkTouchGesture.h
index 79d4e28..527065e 100644
--- a/include/views/SkTouchGesture.h
+++ b/include/views/SkTouchGesture.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkTouchGesture_DEFINED
#define SkTouchGesture_DEFINED
diff --git a/include/views/SkView.h b/include/views/SkView.h
index d3633db..a5349c2 100644
--- a/include/views/SkView.h
+++ b/include/views/SkView.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkView_DEFINED
#define SkView_DEFINED
@@ -21,6 +14,7 @@
#include "SkRect.h"
#include "SkDOM.h"
#include "SkTDict.h"
+#include "SkMatrix.h"
class SkCanvas;
class SkLayerView;
@@ -87,6 +81,12 @@ public:
/** Return a rectangle set to [0, 0, width, height] */
void getLocalBounds(SkRect* bounds) const;
+ /** Loc - the view's offset with respect to its parent in its view hiearchy.
+ NOTE: For more complex transforms, use Local Matrix. The tranformations
+ are applied in the following order:
+ canvas->translate(fLoc.fX, fLoc.fY);
+ canvas->concat(fMatrix);
+ */
/** Return the view's left edge */
SkScalar locX() const { return fLoc.fX; }
/** Return the view's top edge */
@@ -96,6 +96,18 @@ public:
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); }
+
+ /** Local Matrix - matrix used to tranform the view with respect to its
+ parent in its view hiearchy. Use setLocalMatrix to apply matrix
+ transformations to the current view and in turn affect its children.
+ NOTE: For simple offsets, use Loc. The transformations are applied in
+ the following order:
+ canvas->translate(fLoc.fX, fLoc.fY);
+ canvas->concat(fMatrix);
+ */
+ const SkMatrix& getLocalMatrix() const { return fMatrix; }
+ void setLocalMatrix(const SkMatrix& matrix);
+
/** Offset (move) the view by the specified dx and dy. This does not affect the view's size */
void offset(SkScalar dx, SkScalar dy);
@@ -142,6 +154,7 @@ public:
SkPoint fOrig, fPrev, fCurr;
SkIPoint fIOrig, fIPrev, fICurr;
State fState;
+ void* fOwner;
private:
SkEventSinkID fTargetID;
char* fType;
@@ -168,10 +181,6 @@ public:
*/
SkView* sendQueryToParents(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 null if it has none. This does not affect the parent's reference count. */
@@ -348,6 +357,7 @@ protected:
private:
SkScalar fWidth, fHeight;
+ SkMatrix fMatrix;
SkPoint fLoc;
SkView* fParent;
SkView* fFirstChild;
@@ -364,6 +374,8 @@ private:
bool setFocusView(SkView* fvOrNull);
SkView* acceptFocus(FocusDirection);
void detachFromParent_NoLayout();
+ /** Compute the matrix to transform view-local coordinates into global ones */
+ void localToGlobal(SkMatrix* matrix) const;
};
#endif
diff --git a/include/views/SkViewInflate.h b/include/views/SkViewInflate.h
index 3ec65a6..7282091 100644
--- a/include/views/SkViewInflate.h
+++ b/include/views/SkViewInflate.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkViewInflate_DEFINED
#define SkViewInflate_DEFINED
diff --git a/include/views/SkWidget.h b/include/views/SkWidget.h
index db85f01..c3b4530 100644
--- a/include/views/SkWidget.h
+++ b/include/views/SkWidget.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkWidget_DEFINED
#define SkWidget_DEFINED
diff --git a/include/views/SkWidgetViews.h b/include/views/SkWidgetViews.h
index 9b3a816..295c101 100644
--- a/include/views/SkWidgetViews.h
+++ b/include/views/SkWidgetViews.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkWidgetViews_DEFINED
#define SkWidgetViews_DEFINED
diff --git a/include/views/SkWindow.h b/include/views/SkWindow.h
index fd4ce0a..c72163c 100644
--- a/include/views/SkWindow.h
+++ b/include/views/SkWindow.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkWindow_DEFINED
#define SkWindow_DEFINED
@@ -54,13 +47,13 @@ public:
// return the bounds of the dirty/inval rgn, or [0,0,0,0] if none
const SkIRect& getDirtyBounds() const { return fDirtyRgn.getBounds(); }
- bool handleClick(int x, int y, Click::State);
+ bool handleClick(int x, int y, Click::State, void* owner = NULL);
bool handleChar(SkUnichar);
bool handleKey(SkKey);
bool handleKeyUp(SkKey);
- bool handleMenu(uint32_t os_cmd);
void addMenu(SkOSMenu*);
+ const SkTDArray<SkOSMenu*>* getMenus() { return &fMenus; }
const char* getTitle() const { return fTitle.c_str(); }
void setTitle(const char title[]);
@@ -70,15 +63,18 @@ public:
void preConcat(const SkMatrix&);
void postConcat(const SkMatrix&);
+ virtual void onPDFSaved(const char title[], const char desc[],
+ const char path[]) {}
protected:
virtual bool onEvent(const SkEvent&);
- virtual bool onDispatchClick(int x, int y, Click::State);
+ virtual bool onDispatchClick(int x, int y, Click::State, void* owner);
// called if part of our bitmap is invalidated
virtual void onHandleInval(const SkIRect&);
virtual bool onHandleChar(SkUnichar);
virtual bool onHandleKey(SkKey);
virtual bool onHandleKeyUp(SkKey);
- virtual void onAddMenu(const SkOSMenu*) {}
+ virtual void onAddMenu(const SkOSMenu*) {};
+ virtual void onUpdateMenu(const SkOSMenu*) {};
virtual void onSetTitle(const char title[]) {}
// overrides from SkView
@@ -90,7 +86,8 @@ private:
SkBitmap::Config fConfig;
SkBitmap fBitmap;
SkRegion fDirtyRgn;
- Click* fClick; // to track clicks
+
+ SkTDArray<Click*> fClicks; // to track clicks
SkTDArray<SkOSMenu*> fMenus;
@@ -111,7 +108,7 @@ private:
#include "SkOSWindow_Mac.h"
#elif defined(SK_BUILD_FOR_WIN)
#include "SkOSWindow_Win.h"
-#elif defined(ANDROID)
+#elif defined(SK_BUILD_FOR_ANDROID)
#include "SkOSWindow_Android.h"
#elif defined(SK_BUILD_FOR_UNIX)
#include "SkOSWindow_Unix.h"
diff --git a/include/xml/SkBML_WXMLParser.h b/include/xml/SkBML_WXMLParser.h
index faa127d..e16b95c 100644
--- a/include/xml/SkBML_WXMLParser.h
+++ b/include/xml/SkBML_WXMLParser.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkBML_WXMLParser_DEFINED
#define SkBML_WXMLParser_DEFINED
diff --git a/include/xml/SkBML_XMLParser.h b/include/xml/SkBML_XMLParser.h
index f056bca..7a8d6a1 100644
--- a/include/xml/SkBML_XMLParser.h
+++ b/include/xml/SkBML_XMLParser.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkBML_XMLParser_DEFINED
#define SkBML_XMLParser_DEFINED
diff --git a/include/xml/SkDOM.h b/include/xml/SkDOM.h
index 74e2492..60145c8 100644
--- a/include/xml/SkDOM.h
+++ b/include/xml/SkDOM.h
@@ -1,24 +1,16 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkDOM_DEFINED
#define SkDOM_DEFINED
#include "SkChunkAlloc.h"
-#include "SkMath.h"
#include "SkScalar.h"
#include "SkTemplates.h"
diff --git a/include/xml/SkJS.h b/include/xml/SkJS.h
index fe76352..645e03b 100644
--- a/include/xml/SkJS.h
+++ b/include/xml/SkJS.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkTypes.h"
#include "SkWindow.h"
diff --git a/include/xml/SkXMLParser.h b/include/xml/SkXMLParser.h
index 7eccb02..bd8c2f1 100644
--- a/include/xml/SkXMLParser.h
+++ b/include/xml/SkXMLParser.h
@@ -1,23 +1,15 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkXMLParser_DEFINED
#define SkXMLParser_DEFINED
-#include "SkMath.h"
#include "SkString.h"
class SkStream;
diff --git a/include/xml/SkXMLWriter.h b/include/xml/SkXMLWriter.h
index 742e7f1..4e0eda1 100644
--- a/include/xml/SkXMLWriter.h
+++ b/include/xml/SkXMLWriter.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkXMLWriter_DEFINED
#define SkXMLWriter_DEFINED
diff --git a/samplecode/ClockFaceView.cpp b/samplecode/ClockFaceView.cpp
index c829b69..a479d9c 100644
--- a/samplecode/ClockFaceView.cpp
+++ b/samplecode/ClockFaceView.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/GMSampleView.h b/samplecode/GMSampleView.h
new file mode 100644
index 0000000..7decfcb
--- /dev/null
+++ b/samplecode/GMSampleView.h
@@ -0,0 +1,52 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GMSampleView_DEFINED
+#define GMSampleView_DEFINED
+
+#include "SampleCode.h"
+#include "gm.h"
+
+class GMSampleView : public SampleView {
+private:
+ typedef skiagm::GM GM;
+
+public:
+ GMSampleView(GM* gm)
+ : fGM(gm) {}
+
+ virtual ~GMSampleView() {
+ delete fGM;
+ }
+
+protected:
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SkString name("GM:");
+ name.append(fGM->shortName());
+ SampleCode::TitleR(evt, name.c_str());
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ fGM->drawContent(canvas);
+ }
+
+ virtual void onDrawBackground(SkCanvas* canvas) {
+ fGM->drawBackground(canvas);
+ }
+
+private:
+ GM* fGM;
+ typedef SampleView INHERITED;
+};
+
+#endif
diff --git a/samplecode/OverView.cpp b/samplecode/OverView.cpp
index 2ae2119..fc4a9ef 100644
--- a/samplecode/OverView.cpp
+++ b/samplecode/OverView.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkCanvas.h"
#include "SkView.h"
@@ -6,9 +13,14 @@ static const int N = 8;
const SkScalar W = SkIntToScalar(640);
const SkScalar H = SkIntToScalar(480);
+static const char gIsOverview[] = "is-overview";
+bool is_overview(SkView* view) {
+ SkEvent isOverview(gIsOverview);
+ return view->doQuery(&isOverview);
+}
class OverView : public SkView {
public:
- OverView(int count, const SkViewFactory factories[]);
+ OverView(int count, const SkViewFactory* factories[]);
virtual ~OverView();
protected:
@@ -26,6 +38,9 @@ protected:
SampleCode::TitleR(evt, "Overview");
return true;
}
+ if (evt->isType(gIsOverview)) {
+ return true;
+ }
return this->INHERITED::onQuery(evt);
}
@@ -46,17 +61,16 @@ protected:
private:
int fCount;
- const SkViewFactory* fFactories;
+ const SkViewFactory** fFactories;
typedef SkView INHERITED;
};
-SkView* create_overview(int count, const SkViewFactory factories[]);
-SkView* create_overview(int count, const SkViewFactory factories[]) {
+SkView* create_overview(int count, const SkViewFactory* factories[]) {
return SkNEW_ARGS(OverView, (count, factories));
};
-OverView::OverView(int count, const SkViewFactory factories[]) {
+OverView::OverView(int count, const SkViewFactory* factories[]) {
fCount = count;
fFactories = factories;
}
@@ -74,7 +88,7 @@ void OverView::onSizeChange() {
SkScalar locX = 0;
SkScalar locY = 0;
for (int i = 0; i < fCount; i++) {
- SkView* view = fFactories[i]();
+ SkView* view = (*fFactories[i])();
view->setVisibleP(true);
this->attachChildToBack(view)->unref();
view->setLoc(locX, locY);
diff --git a/samplecode/Sample2PtRadial.cpp b/samplecode/Sample2PtRadial.cpp
new file mode 100644
index 0000000..0c44fd6
--- /dev/null
+++ b/samplecode/Sample2PtRadial.cpp
@@ -0,0 +1,52 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+
+
+class TwoPtRadialView : public SampleView {
+public:
+ TwoPtRadialView() {}
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "2PtRadial");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
+
+ SkColor colors[] = { SK_ColorRED, SK_ColorBLUE };
+ SkPoint c0 = { 0, 0 };
+ SkScalar r0 = 100;
+ SkPoint c1 = { 100, 100 };
+ SkScalar r1 = 100;
+ SkShader* s = SkGradientShader::CreateTwoPointRadial(c0, r0, c1, r1, colors,
+ NULL, 2,
+ SkShader::kClamp_TileMode);
+
+ SkPaint paint;
+ paint.setShader(s)->unref();
+ canvas->drawPaint(paint);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new TwoPtRadialView; }
+static SkViewRegister reg(MyFactory);
diff --git a/samplecode/SampleAAClip.cpp b/samplecode/SampleAAClip.cpp
new file mode 100644
index 0000000..d2931fa
--- /dev/null
+++ b/samplecode/SampleAAClip.cpp
@@ -0,0 +1,128 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkAAClip.h"
+
+static void testop(const SkIRect& r0, const SkIRect& r1, SkRegion::Op op,
+ const SkIRect& expectedR) {
+ SkAAClip c0, c1, c2;
+ c0.setRect(r0);
+ c1.setRect(r1);
+ c2.op(c0, c1, op);
+
+ SkIRect r2 = c2.getBounds();
+ SkASSERT(r2 == expectedR);
+}
+
+static const struct {
+ SkIRect r0;
+ SkIRect r1;
+ SkRegion::Op op;
+ SkIRect expectedR;
+} gRec[] = {
+ {{ 1, 2, 9, 3 }, { -3, 2, 5, 11 }, SkRegion::kDifference_Op, { 5, 2, 9, 3 }},
+ {{ 1, 10, 5, 13 }, { 1, 2, 5, 11 }, SkRegion::kDifference_Op, { 1, 11, 5, 13 }},
+ {{ 1, 10, 5, 13 }, { 1, 2, 5, 11 }, SkRegion::kReverseDifference_Op, { 1, 2, 5, 10 }},
+};
+
+static void testop() {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
+ testop(gRec[i].r0, gRec[i].r1, gRec[i].op, gRec[i].expectedR);
+ }
+}
+
+static void drawClip(SkCanvas* canvas, const SkAAClip& clip) {
+ SkMask mask;
+ SkBitmap bm;
+
+ clip.copyToMask(&mask);
+ SkAutoMaskFreeImage amfi(mask.fImage);
+
+ bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(),
+ mask.fBounds.height(), mask.fRowBytes);
+ bm.setPixels(mask.fImage);
+
+ SkPaint paint;
+ canvas->drawBitmap(bm,
+ SK_Scalar1 * mask.fBounds.fLeft,
+ SK_Scalar1 * mask.fBounds.fTop,
+ &paint);
+}
+
+class AAClipView : public SampleView {
+public:
+ AAClipView() {
+ testop();
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "AAClip");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+#if 1
+ SkAAClip aaclip;
+ SkPath path;
+ SkRect bounds;
+
+ bounds.set(0, 0, 20, 20);
+ bounds.inset(SK_ScalarHalf, SK_ScalarHalf);
+
+// path.addRect(bounds);
+// path.addOval(bounds);
+ path.addRoundRect(bounds, 4, 4);
+ aaclip.setPath(path);
+ canvas->translate(30, 30);
+ drawClip(canvas, aaclip);
+
+ SkAAClip aaclip2;
+ path.offset(10, 10);
+ aaclip2.setPath(path);
+ canvas->translate(30, 0);
+ drawClip(canvas, aaclip2);
+
+ SkAAClip aaclip3;
+ aaclip3.op(aaclip, aaclip2, SkRegion::kIntersect_Op);
+ canvas->translate(30, 0);
+ drawClip(canvas, aaclip3);
+
+#endif
+
+#if 0
+ SkRect r;
+ r.set(0, 0, this->width(), this->height());
+ r.inset(20, 20);
+ canvas->clipRect(r);
+
+ SkPath path;
+ path.addRect(r);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(SK_ColorRED);
+ canvas->drawPath(path, paint);
+#endif
+ }
+
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new AAClipView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleAAClip2.cpp b/samplecode/SampleAAClip2.cpp
new file mode 100644
index 0000000..d12e13c
--- /dev/null
+++ b/samplecode/SampleAAClip2.cpp
@@ -0,0 +1,194 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkAAClip.h"
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkImageDecoder.h"
+
+#ifdef SK_BUILD_FOR_WIN
+// windows doesn't have roundf
+inline float roundf(float x) { return (x-floor(x))>0.5 ? ceil(x) : floor(x); }
+#endif
+
+static void drawClip(SkCanvas* canvas, const SkAAClip& clip) {
+ SkMask mask;
+ SkBitmap bm;
+
+ clip.copyToMask(&mask);
+ SkAutoMaskFreeImage amfi(mask.fImage);
+
+ bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(),
+ mask.fBounds.height(), mask.fRowBytes);
+ bm.setPixels(mask.fImage);
+
+ SkPaint paint;
+ canvas->drawBitmap(bm,
+ SK_Scalar1 * mask.fBounds.fLeft,
+ SK_Scalar1 * mask.fBounds.fTop,
+ &paint);
+}
+
+static void paint_rgn(SkCanvas* canvas, const SkAAClip& clip,
+ const SkPaint& paint) {
+ SkMask mask;
+ SkBitmap bm;
+
+ clip.copyToMask(&mask);
+ SkAutoMaskFreeImage amfi(mask.fImage);
+
+ bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(),
+ mask.fBounds.height(), mask.fRowBytes);
+ bm.setPixels(mask.fImage);
+
+ canvas->drawBitmap(bm,
+ SK_Scalar1 * mask.fBounds.fLeft,
+ SK_Scalar1 * mask.fBounds.fTop,
+ &paint);
+}
+
+class AAClipView2 : public SampleView {
+public:
+ AAClipView2() {
+ fBase.set(100, 100, 150, 150);
+ fRect = fBase;
+ fRect.inset(5, 5);
+ fRect.offset(25, 25);
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+ static void setAAClip(SkAAClip* clip, const SkIRect& rect) {
+ SkRect r;
+ r.set(rect);
+ SkPath path;
+ path.addRoundRect(r, SkIntToScalar(5), SkIntToScalar(5));
+ clip->setPath(path);
+ }
+
+ void build_rgn(SkAAClip* clip, SkRegion::Op op) {
+ setAAClip(clip, fBase);
+
+ SkAAClip clip2;
+ setAAClip(&clip2, fRect);
+ clip->op(clip2, op);
+ }
+
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "AAClips");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawOrig(SkCanvas* canvas, bool bg) {
+ SkRect r;
+ SkPaint paint;
+
+ paint.setStyle(SkPaint::kStroke_Style);
+ if (bg)
+ paint.setColor(0xFFBBBBBB);
+
+ r.set(fBase);
+ canvas->drawRect(r, paint);
+ r.set(fRect);
+ canvas->drawRect(r, paint);
+ }
+
+ static void outer_frame(SkCanvas* canvas, const SkIRect& rect) {
+ SkRect r;
+ r.set(rect);
+ r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
+
+ SkPaint paint;
+ paint.setColor(SK_ColorGRAY);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawRect(r, paint);
+ }
+
+ void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) {
+ SkAAClip clip;
+
+ this->build_rgn(&clip, op);
+
+ this->drawOrig(canvas, true);
+
+ SkPaint paint;
+ paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24));
+ paint_rgn(canvas, clip, paint);
+
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(color);
+ paint_rgn(canvas, clip, paint);
+
+ SkAAClip clip2(clip);
+ clip2.translate(0, 80);
+ outer_frame(canvas, clip2.getBounds());
+ paint_rgn(canvas, clip2, paint);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+
+ static const struct {
+ SkColor fColor;
+ const char* fName;
+ SkRegion::Op fOp;
+ } gOps[] = {
+ { SK_ColorBLACK, "Difference", SkRegion::kDifference_Op },
+ { SK_ColorRED, "Intersect", SkRegion::kIntersect_Op },
+ { 0xFF008800, "Union", SkRegion::kUnion_Op },
+ { SK_ColorBLUE, "XOR", SkRegion::kXOR_Op }
+ };
+
+ SkPaint textPaint;
+ textPaint.setAntiAlias(true);
+ textPaint.setTextSize(SK_Scalar1*24);
+
+ this->drawOrig(canvas, false);
+
+ canvas->translate(0, SkIntToScalar(200));
+
+ for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); op++) {
+ canvas->drawText(gOps[op].fName, strlen(gOps[op].fName), SkIntToScalar(75), SkIntToScalar(50), textPaint);
+
+ this->drawRgnOped(canvas, gOps[op].fOp, gOps[op].fColor);
+
+ canvas->translate(SkIntToScalar(200), 0);
+ }
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ return fRect.contains(SkScalarRound(x), SkScalarRound(y)) ? new Click(this) : NULL;
+ }
+
+ virtual bool onClick(Click* click) {
+ fRect.offset(click->fICurr.fX - click->fIPrev.fX,
+ click->fICurr.fY - click->fIPrev.fY);
+ this->inval(NULL);
+ return true;
+ }
+
+private:
+ SkIRect fBase, fRect;
+
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new AAClipView2; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleAARectModes.cpp b/samplecode/SampleAARectModes.cpp
new file mode 100644
index 0000000..7b9e7d5
--- /dev/null
+++ b/samplecode/SampleAARectModes.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+
+static SkCanvas* create_canvas(int w, int h) {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, w, h);
+ bm.allocPixels();
+ bm.eraseColor(0);
+ return new SkCanvas(bm);
+}
+
+static const SkBitmap& extract_bitmap(SkCanvas* canvas) {
+ return canvas->getDevice()->accessBitmap(false);
+}
+
+static const struct {
+ SkXfermode::Mode fMode;
+ const char* fLabel;
+} gModes[] = {
+ { SkXfermode::kClear_Mode, "Clear" },
+ { SkXfermode::kSrc_Mode, "Src" },
+ { SkXfermode::kDst_Mode, "Dst" },
+ { SkXfermode::kSrcOver_Mode, "SrcOver" },
+ { SkXfermode::kDstOver_Mode, "DstOver" },
+ { SkXfermode::kSrcIn_Mode, "SrcIn" },
+ { SkXfermode::kDstIn_Mode, "DstIn" },
+ { SkXfermode::kSrcOut_Mode, "SrcOut" },
+ { SkXfermode::kDstOut_Mode, "DstOut" },
+ { SkXfermode::kSrcATop_Mode, "SrcATop" },
+ { SkXfermode::kDstATop_Mode, "DstATop" },
+ { SkXfermode::kXor_Mode, "Xor" },
+};
+
+const int gWidth = 64;
+const int gHeight = 64;
+const SkScalar W = SkIntToScalar(gWidth);
+const SkScalar H = SkIntToScalar(gHeight);
+
+static SkScalar drawCell(SkCanvas* canvas, SkXfermode* mode,
+ SkAlpha a0, SkAlpha a1) {
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ SkRect r = SkRect::MakeWH(W, H);
+ r.inset(W/10, H/10);
+
+ paint.setColor(SK_ColorBLUE);
+ paint.setAlpha(a0);
+ canvas->drawOval(r, paint);
+
+ paint.setColor(SK_ColorRED);
+ paint.setAlpha(a1);
+ paint.setXfermode(mode);
+
+ SkScalar offset = SK_Scalar1 / 3;
+ SkRect rect = SkRect::MakeXYWH(W / 4 + offset,
+ H / 4 + offset,
+ W / 2, H / 2);
+ canvas->drawRect(rect, paint);
+
+ return H;
+}
+
+static SkShader* make_bg_shader() {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
+ bm.allocPixels();
+ *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = 0xFFFFFFFF;
+ *bm.getAddr32(1, 0) = *bm.getAddr32(0, 1) = SkPackARGB32(0xFF, 0xCC,
+ 0xCC, 0xCC);
+
+ SkShader* s = SkShader::CreateBitmapShader(bm,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+
+ SkMatrix m;
+ m.setScale(SkIntToScalar(6), SkIntToScalar(6));
+ s->setLocalMatrix(m);
+ return s;
+}
+
+class AARectsModesView : public SampleView {
+ SkPaint fBGPaint;
+public:
+ AARectsModesView () {
+ fBGPaint.setShader(make_bg_shader())->unref();
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "AARectsModes");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ const SkRect bounds = SkRect::MakeWH(W, H);
+ static const SkAlpha gAlphaValue[] = { 0xFF, 0x88, 0x88 };
+
+ canvas->translate(SkIntToScalar(4), SkIntToScalar(4));
+
+ for (int alpha = 0; alpha < 4; ++alpha) {
+ canvas->save();
+ canvas->save();
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); ++i) {
+ if (6 == i) {
+ canvas->restore();
+ canvas->translate(W * 5, 0);
+ canvas->save();
+ }
+ SkXfermode* mode = SkXfermode::Create(gModes[i].fMode);
+
+ canvas->drawRect(bounds, fBGPaint);
+ canvas->saveLayer(&bounds, NULL);
+ SkScalar dy = drawCell(canvas, mode,
+ gAlphaValue[alpha & 1],
+ gAlphaValue[alpha & 2]);
+ canvas->restore();
+
+ canvas->translate(0, dy * 5 / 4);
+ SkSafeUnref(mode);
+ }
+ canvas->restore();
+ canvas->restore();
+ canvas->translate(W * 5 / 4, 0);
+ }
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new AARectsModesView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleAARects.cpp b/samplecode/SampleAARects.cpp
index 34a33b0..0490552 100644
--- a/samplecode/SampleAARects.cpp
+++ b/samplecode/SampleAARects.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleAll.cpp b/samplecode/SampleAll.cpp
index abbf8f9..4321532 100644
--- a/samplecode/SampleAll.cpp
+++ b/samplecode/SampleAll.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkCanvas.h"
#include "SkView.h"
diff --git a/samplecode/SampleAnimatedGradient.cpp b/samplecode/SampleAnimatedGradient.cpp
index a7b2a46..3caff1c 100644
--- a/samplecode/SampleAnimatedGradient.cpp
+++ b/samplecode/SampleAnimatedGradient.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkCanvas.h"
#include "SkGradientShader.h"
diff --git a/samplecode/SampleAnimator.cpp b/samplecode/SampleAnimator.cpp
index 99173fc..09742a0 100644
--- a/samplecode/SampleAnimator.cpp
+++ b/samplecode/SampleAnimator.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
@@ -24,6 +31,7 @@ public:
protected:
// overrides
virtual void onDraw(SkCanvas*);
+ virtual bool onQuery(SkEvent* evt);
private:
SkString fBaseURI;
@@ -119,8 +127,8 @@ bool SkAnimatorView::decodeStream(SkStream* stream) {
#include "SkTime.h"
void SkAnimatorView::onDraw(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorWHITE);
if (fAnimator) {
- canvas->drawColor(SK_ColorWHITE);
fAnimator->draw(canvas, 0);
#if 0
canvas->save();
@@ -140,6 +148,14 @@ void SkAnimatorView::onDraw(SkCanvas* canvas) {
}
}
+bool SkAnimatorView::onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Animator");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+}
+
//////////////////////////////////////////////////////////////////////////////
static SkView* MyFactory() {
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index f05fe6e..95923c8 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -1,6 +1,15 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SampleApp.h"
+
+#include "SkData.h"
#include "SkCanvas.h"
#include "SkDevice.h"
-#include "SkGpuCanvas.h"
+#include "SkGpuDevice.h"
#include "SkGraphics.h"
#include "SkImageEncoder.h"
#include "SkPaint.h"
@@ -11,22 +20,46 @@
#include "SampleCode.h"
#include "GrContext.h"
-#include "SkTouchGesture.h"
#include "SkTypeface.h"
-#define TEST_GPIPEx
+#include "GrGLInterface.h"
+#include "GrRenderTarget.h"
+
+#include "SkPDFDevice.h"
+#include "SkPDFDocument.h"
+#include "SkStream.h"
+
+#define TEST_GPIPE
#ifdef TEST_GPIPE
-#define PIPE_FILE
+#define PIPE_FILEx
+#ifdef PIPE_FILE
#define FILE_PATH "/path/to/drawing.data"
#endif
+#define PIPE_NETx
+#ifdef PIPE_NET
+#include "SkSockets.h"
+SkTCPServer gServer;
+#endif
+
+#define DEBUGGERx
+#ifdef DEBUGGER
+extern SkView* create_debugger(const char* data, size_t size);
+extern bool is_debugger(SkView* view);
+SkTDArray<char> gTempDataStore;
+#endif
+
+#endif
+
#define USE_ARROWS_FOR_ZOOM true
//#define DEFAULT_TO_GPU
-extern SkView* create_overview(int, const SkViewFactory[]);
+extern SkView* create_overview(int, const SkViewFactory*[]);
+extern bool is_overview(SkView* view);
+//extern SkView* create_transition(SkView*, SkView*, int);
+//extern bool is_transition(SkView* view);
-#define SK_SUPPORT_GL
#define ANIMATING_EVENTTYPE "nextSample"
#define ANIMATING_DELAY 750
@@ -38,16 +71,218 @@ extern SkView* create_overview(int, const SkViewFactory[]);
#endif
#define FPS_REPEAT_COUNT (10 * FPS_REPEAT_MULTIPLIER)
-#ifdef SK_SUPPORT_GL
- #include "GrGLConfig.h"
-#endif
+static SampleWindow* gSampleWindow;
+
+static void postEventToSink(SkEvent* evt, SkEventSink* sink) {
+ evt->setTargetID(sink->getSinkID())->post();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static const char* skip_until(const char* str, const char* skip) {
+ if (!str) {
+ return NULL;
+ }
+ return strstr(str, skip);
+}
+
+static const char* skip_past(const char* str, const char* skip) {
+ const char* found = skip_until(str, skip);
+ if (!found) {
+ return NULL;
+ }
+ return found + strlen(skip);
+}
+
+static const char* gPrefFileName = "sampleapp_prefs.txt";
+
+static bool readTitleFromPrefs(SkString* title) {
+ SkFILEStream stream(gPrefFileName);
+ if (!stream.isValid()) {
+ return false;
+ }
+
+ int len = stream.getLength();
+ SkString data(len);
+ stream.read(data.writable_str(), len);
+ const char* s = data.c_str();
+
+ s = skip_past(s, "curr-slide-title");
+ s = skip_past(s, "=");
+ s = skip_past(s, "\"");
+ const char* stop = skip_until(s, "\"");
+ if (stop > s) {
+ title->set(s, stop - s);
+ return true;
+ }
+ return false;
+}
+
+static void writeTitleToPrefs(const char* title) {
+ SkFILEWStream stream(gPrefFileName);
+ SkString data;
+ data.printf("curr-slide-title = \"%s\"\n", title);
+ stream.write(data.c_str(), data.size());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class SampleWindow::DefaultDeviceManager : public SampleWindow::DeviceManager {
+public:
+
+ DefaultDeviceManager() {
+ fGrRenderTarget = NULL;
+ fGrContext = NULL;
+ fGL = NULL;
+ fNullGrContext = NULL;
+ fNullGrRenderTarget = NULL;
+ }
+
+ virtual ~DefaultDeviceManager() {
+ SkSafeUnref(fGrRenderTarget);
+ SkSafeUnref(fGrContext);
+ SkSafeUnref(fGL);
+ SkSafeUnref(fNullGrContext);
+ SkSafeUnref(fNullGrRenderTarget);
+ }
+
+ virtual void init(SampleWindow* win) {
+ if (!win->attachGL()) {
+ SkDebugf("Failed to initialize GL");
+ }
+ if (NULL == fGL) {
+ fGL = GrGLCreateNativeInterface();
+ GrAssert(NULL == fGrContext);
+ fGrContext = GrContext::Create(kOpenGL_Shaders_GrEngine,
+ (GrPlatform3DContext) fGL);
+ }
+ if (NULL == fGrContext || NULL == fGL) {
+ SkSafeUnref(fGrContext);
+ SkSafeUnref(fGL);
+ SkDebugf("Failed to setup 3D");
+ win->detachGL();
+ }
+ if (NULL == fNullGrContext) {
+ const GrGLInterface* nullGL = GrGLCreateNullInterface();
+ fNullGrContext = GrContext::Create(kOpenGL_Shaders_GrEngine,
+ (GrPlatform3DContext) nullGL);
+ nullGL->unref();
+ }
+ }
+
+ virtual bool supportsDeviceType(SampleWindow::DeviceType dType) {
+ switch (dType) {
+ case kRaster_DeviceType:
+ case kPicture_DeviceType: // fallthru
+ return true;
+ case kGPU_DeviceType:
+ return NULL != fGrContext && NULL != fGrRenderTarget;
+ case kNullGPU_DeviceType:
+ return NULL != fNullGrContext && NULL != fNullGrRenderTarget;
+ default:
+ return false;
+ }
+ }
+
+ virtual bool prepareCanvas(SampleWindow::DeviceType dType,
+ SkCanvas* canvas,
+ SampleWindow* win) {
+ switch (dType) {
+ case kGPU_DeviceType:
+ if (fGrContext) {
+ canvas->setDevice(new SkGpuDevice(fGrContext,
+ fGrRenderTarget))->unref();
+ } else {
+ return false;
+ }
+ break;
+ case kNullGPU_DeviceType:
+ if (fNullGrContext) {
+ canvas->setDevice(new SkGpuDevice(fNullGrContext,
+ fNullGrRenderTarget))->unref();
+ } else {
+ return false;
+ }
+ break;
+ case kRaster_DeviceType:
+ case kPicture_DeviceType:
+ break;
+ }
+ return true;
+ }
+
+ virtual void publishCanvas(SampleWindow::DeviceType dType,
+ SkCanvas* canvas,
+ SampleWindow* win) {
+ if (fGrContext) {
+ // in case we have queued drawing calls
+ fGrContext->flush();
+ if (NULL != fNullGrContext) {
+ fNullGrContext->flush();
+ }
+ if (dType != kGPU_DeviceType &&
+ dType != kNullGPU_DeviceType) {
+ // need to send the raster bits to the (gpu) window
+ fGrContext->setRenderTarget(fGrRenderTarget);
+ const SkBitmap& bm = win->getBitmap();
+ fGrRenderTarget->writePixels(0, 0, bm.width(), bm.height(),
+ kSkia8888_PM_GrPixelConfig,
+ bm.getPixels(),
+ bm.rowBytes());
+ }
+ }
+ win->presentGL();
+ }
+
+ virtual void windowSizeChanged(SampleWindow* win) {
+ if (fGrContext) {
+ win->attachGL();
+
+ GrPlatformRenderTargetDesc desc;
+ desc.fWidth = SkScalarRound(win->width());
+ desc.fHeight = SkScalarRound(win->height());
+ desc.fConfig = kSkia8888_PM_GrPixelConfig;
+ GR_GL_GetIntegerv(fGL, GR_GL_SAMPLES, &desc.fSampleCnt);
+ GR_GL_GetIntegerv(fGL, GR_GL_STENCIL_BITS, &desc.fStencilBits);
+ GrGLint buffer;
+ GR_GL_GetIntegerv(fGL, GR_GL_FRAMEBUFFER_BINDING, &buffer);
+ desc.fRenderTargetHandle = buffer;
+
+ SkSafeUnref(fGrRenderTarget);
+ fGrRenderTarget = fGrContext->createPlatformRenderTarget(desc);
+ }
+ if (NULL != fNullGrContext) {
+ GrPlatformRenderTargetDesc desc;
+ desc.fWidth = SkScalarRound(win->width());
+ desc.fHeight = SkScalarRound(win->height());
+ desc.fConfig = kSkia8888_PM_GrPixelConfig;
+ desc.fStencilBits = 8;
+ desc.fSampleCnt = 0;
+ desc.fRenderTargetHandle = 0;
+ fNullGrRenderTarget = fNullGrContext->createPlatformRenderTarget(desc);
+ }
+ }
+
+ virtual GrContext* getGrContext(SampleWindow::DeviceType dType) {
+ if (kNullGPU_DeviceType == dType) {
+ return fNullGrContext;
+ } else {
+ return fGrContext;
+ }
+ }
+private:
+ GrContext* fGrContext;
+ const GrGLInterface* fGL;
+ GrRenderTarget* fGrRenderTarget;
+ GrContext* fNullGrContext;
+ GrRenderTarget* fNullGrRenderTarget;
+};
///////////////
static const char view_inval_msg[] = "view-inval-msg";
-static void postInvalDelay(SkEventSinkID sinkID) {
- SkEvent* evt = new SkEvent(view_inval_msg);
- evt->post(sinkID, 1);
+void SampleWindow::postInvalDelay() {
+ (new SkEvent(view_inval_msg, this->getSinkID()))->postDelay(1);
}
static bool isInvalEvent(const SkEvent& evt) {
@@ -55,23 +290,76 @@ static bool isInvalEvent(const SkEvent& evt) {
}
//////////////////
+SkFuncViewFactory::SkFuncViewFactory(SkViewCreateFunc func)
+ : fCreateFunc(func) {
+}
+
+SkView* SkFuncViewFactory::operator() () const {
+ return (*fCreateFunc)();
+}
+
+#include "GMSampleView.h"
+
+SkGMSampleViewFactory::SkGMSampleViewFactory(GMFactoryFunc func)
+ : fFunc(func) {
+}
+
+SkView* SkGMSampleViewFactory::operator() () const {
+ return new GMSampleView(fFunc(NULL));
+}
+
SkViewRegister* SkViewRegister::gHead;
-SkViewRegister::SkViewRegister(SkViewFactory fact) : fFact(fact) {
- static bool gOnce;
- if (!gOnce) {
- gHead = NULL;
- gOnce = true;
- }
+SkViewRegister::SkViewRegister(SkViewFactory* fact) : fFact(fact) {
+ fFact->ref();
+ fChain = gHead;
+ gHead = this;
+}
+SkViewRegister::SkViewRegister(SkViewCreateFunc func) {
+ fFact = new SkFuncViewFactory(func);
fChain = gHead;
gHead = this;
}
-#if defined(SK_SUPPORT_GL)
- #define SK_USE_SHADERS
-#endif
+SkViewRegister::SkViewRegister(GMFactoryFunc func) {
+ fFact = new SkGMSampleViewFactory(func);
+ fChain = gHead;
+ gHead = this;
+}
-#ifdef SK_BUILD_FOR_MAC
+class AutoUnrefArray {
+public:
+ AutoUnrefArray() {}
+ ~AutoUnrefArray() {
+ int count = fObjs.count();
+ for (int i = 0; i < count; ++i) {
+ fObjs[i]->unref();
+ }
+ }
+ SkRefCnt*& push_back() { return *fObjs.append(); }
+
+private:
+ SkTDArray<SkRefCnt*> fObjs;
+};
+
+// registers GMs as Samples
+// This can't be performed during static initialization because it could be
+// run before GMRegistry has been fully built.
+void SkGMRegistyToSampleRegistry() {
+ static bool gOnce;
+ static AutoUnrefArray fRegisters;
+
+ if (!gOnce) {
+ const skiagm::GMRegistry* gmreg = skiagm::GMRegistry::Head();
+ while (gmreg) {
+ fRegisters.push_back() = new SkViewRegister(gmreg->factory());
+ gmreg = gmreg->next();
+ }
+ gOnce = true;
+ }
+}
+
+#if 0
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFURLAccess.h>
@@ -111,51 +399,36 @@ enum FlipAxisEnum {
kFlipAxis_Y = (1 << 1)
};
-enum SkTriState {
- kFalse_SkTriState,
- kTrue_SkTriState,
- kUnknown_SkTriState,
-};
-
-static SkTriState cycle_tristate(SkTriState state) {
- static const SkTriState gCycle[] = {
- /* kFalse_SkTriState -> */ kUnknown_SkTriState,
- /* kTrue_SkTriState -> */ kFalse_SkTriState,
- /* kUnknown_SkTriState -> */ kTrue_SkTriState,
- };
- return gCycle[state];
-}
-
#include "SkDrawFilter.h"
class FlagsDrawFilter : public SkDrawFilter {
public:
- FlagsDrawFilter(SkTriState lcd, SkTriState aa, SkTriState filter,
- SkTriState hinting) :
+ FlagsDrawFilter(SkOSMenu::TriState lcd, SkOSMenu::TriState aa, SkOSMenu::TriState filter,
+ SkOSMenu::TriState hinting) :
fLCDState(lcd), fAAState(aa), fFilterState(filter), fHintingState(hinting) {}
virtual void filter(SkPaint* paint, Type t) {
- if (kText_Type == t && kUnknown_SkTriState != fLCDState) {
- paint->setLCDRenderText(kTrue_SkTriState == fLCDState);
+ if (kText_Type == t && SkOSMenu::kMixedState != fLCDState) {
+ paint->setLCDRenderText(SkOSMenu::kOnState == fLCDState);
}
- if (kUnknown_SkTriState != fAAState) {
- paint->setAntiAlias(kTrue_SkTriState == fAAState);
+ if (SkOSMenu::kMixedState != fAAState) {
+ paint->setAntiAlias(SkOSMenu::kOnState == fAAState);
}
- if (kUnknown_SkTriState != fFilterState) {
- paint->setFilterBitmap(kTrue_SkTriState == fFilterState);
+ if (SkOSMenu::kMixedState != fFilterState) {
+ paint->setFilterBitmap(SkOSMenu::kOnState == fFilterState);
}
- if (kUnknown_SkTriState != fHintingState) {
- paint->setHinting(kTrue_SkTriState == fHintingState ?
+ if (SkOSMenu::kMixedState != fHintingState) {
+ paint->setHinting(SkOSMenu::kOnState == fHintingState ?
SkPaint::kNormal_Hinting :
SkPaint::kSlight_Hinting);
}
}
private:
- SkTriState fLCDState;
- SkTriState fAAState;
- SkTriState fFilterState;
- SkTriState fHintingState;
+ SkOSMenu::TriState fLCDState;
+ SkOSMenu::TriState fAAState;
+ SkOSMenu::TriState fFilterState;
+ SkOSMenu::TriState fHintingState;
};
//////////////////////////////////////////////////////////////////////////////
@@ -168,6 +441,7 @@ static const char gKeyEvtName[] = "SampleCode_Key_Event";
static const char gTitleEvtName[] = "SampleCode_Title_Event";
static const char gPrefSizeEvtName[] = "SampleCode_PrefSize_Event";
static const char gFastTextEvtName[] = "SampleCode_FastText_Event";
+static const char gUpdateWindowTitleEvtName[] = "SampleCode_UpdateWindowTitle";
bool SampleCode::CharQ(const SkEvent& evt, SkUnichar* outUni) {
if (evt.isType(gCharEvtName, sizeof(gCharEvtName) - 1)) {
@@ -198,6 +472,15 @@ void SampleCode::TitleR(SkEvent* evt, const char title[]) {
evt->setString(gTitleEvtName, title);
}
+bool SampleCode::RequestTitle(SkView* view, SkString* title) {
+ SkEvent evt(gTitleEvtName);
+ if (view->doQuery(&evt)) {
+ title->set(evt.findString(gTitleEvtName));
+ return true;
+ }
+ return false;
+}
+
bool SampleCode::PrefSizeQ(const SkEvent& evt) {
return evt.isType(gPrefSizeEvtName, sizeof(gPrefSizeEvtName) - 1);
}
@@ -237,6 +520,15 @@ SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) {
return SkDoubleToScalar(value);
}
+GrContext* SampleCode::GetGr() {
+ return gSampleWindow ? gSampleWindow->getGrContext() : NULL;
+}
+
+// some GMs rely on having a skiagm::GetGr function defined
+namespace skiagm {
+ GrContext* GetGr() { return SampleCode::GetGr(); }
+}
+
//////////////////////////////////////////////////////////////////////////////
static SkView* curr_view(SkWindow* wind) {
@@ -244,111 +536,23 @@ static SkView* curr_view(SkWindow* wind) {
return iter.next();
}
-class SampleWindow : public SkOSWindow {
- SkTDArray<SkViewFactory> fSamples;
-public:
- SampleWindow(void* hwnd);
- virtual ~SampleWindow();
-
- virtual void draw(SkCanvas* canvas);
-
-protected:
- virtual void onDraw(SkCanvas* canvas);
- virtual bool onHandleKey(SkKey key);
- virtual bool onHandleChar(SkUnichar);
- virtual void onSizeChange();
-
- virtual SkCanvas* beforeChildren(SkCanvas*);
- virtual void afterChildren(SkCanvas*);
- virtual void beforeChild(SkView* child, SkCanvas* canvas);
- virtual void afterChild(SkView* child, SkCanvas* canvas);
-
- virtual bool onEvent(const SkEvent& evt);
- virtual bool onQuery(SkEvent* evt);
-
- virtual bool onDispatchClick(int x, int y, Click::State);
- virtual bool onClick(Click* click);
- virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
-
-#if 0
- virtual bool handleChar(SkUnichar uni);
- virtual bool handleEvent(const SkEvent& evt);
- virtual bool handleKey(SkKey key);
- virtual bool handleKeyUp(SkKey key);
- virtual bool onHandleKeyUp(SkKey key);
-#endif
-
-private:
- int fCurrIndex;
-
- SkPicture* fPicture;
- SkGpuCanvas* fGpuCanvas;
- GrContext* fGrContext;
- SkPath fClipPath;
-
- SkTouchGesture fGesture;
- int fZoomLevel;
- SkScalar fZoomScale;
-
- enum CanvasType {
- kRaster_CanvasType,
- kPicture_CanvasType,
- kGPU_CanvasType
- };
- CanvasType fCanvasType;
-
- bool fUseClip;
- bool fNClip;
- bool fRepeatDrawing;
- bool fAnimating;
- bool fRotate;
- bool fScale;
- bool fRequestGrabImage;
- bool fUsePipe;
- bool fMeasureFPS;
- SkMSec fMeasureFPS_Time;
-
- // The following are for the 'fatbits' drawing
- // Latest position of the mouse.
- int fMouseX, fMouseY;
- int fFatBitsScale;
- // Used by the text showing position and color values.
- SkTypeface* fTypeface;
- bool fShowZoomer;
-
- SkTriState fLCDState;
- SkTriState fAAState;
- SkTriState fFilterState;
- SkTriState fHintingState;
- unsigned fFlipAxis;
-
- int fScrollTestX, fScrollTestY;
-
- bool make3DReady();
- void changeZoomLevel(int delta);
-
- void loadView(SkView*);
- void updateTitle();
- bool nextSample();
-
- void toggleZoomer();
- bool zoomIn();
- bool zoomOut();
- void updatePointer(int x, int y);
- void showZoomer(SkCanvas* canvas);
-
- void postAnimatingEvent() {
- if (fAnimating) {
- SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
- evt->post(this->getSinkID(), ANIMATING_DELAY);
+static bool curr_title(SkWindow* wind, SkString* title) {
+ SkView* view = curr_view(wind);
+ if (view) {
+ SkEvent evt(gTitleEvtName);
+ if (view->doQuery(&evt)) {
+ title->set(evt.findString(gTitleEvtName));
+ return true;
}
}
+ return false;
+}
-
- static CanvasType cycle_canvastype(CanvasType);
-
- typedef SkOSWindow INHERITED;
-};
+void SampleWindow::setZoomCenter(float x, float y)
+{
+ fZoomCenterX = SkFloatToScalar(x);
+ fZoomCenterY = SkFloatToScalar(y);
+}
bool SampleWindow::zoomIn()
{
@@ -367,12 +571,6 @@ bool SampleWindow::zoomOut()
return true;
}
-void SampleWindow::toggleZoomer()
-{
- fShowZoomer = !fShowZoomer;
- this->inval(NULL);
-}
-
void SampleWindow::updatePointer(int x, int y)
{
fMouseX = x;
@@ -382,54 +580,19 @@ void SampleWindow::updatePointer(int x, int y)
}
}
-bool SampleWindow::make3DReady() {
-
-#if defined(SK_SUPPORT_GL)
- if (attachGL()) {
- if (NULL != fGrContext) {
- // various gr lifecycle tests
- #if 0
- fGrContext->freeGpuResources();
- #elif 0
- // this will leak resources.
- fGrContext->contextLost();
- #elif 0
- GrAssert(1 == fGrContext->refcnt());
- fGrContext->unref();
- fGrContext = NULL;
- #endif
- }
-
- if (NULL == fGrContext) {
- #if defined(SK_USE_SHADERS)
- fGrContext = GrContext::Create(kOpenGL_Shaders_GrEngine, NULL);
- #else
- fGrContext = GrContext::Create(kOpenGL_Fixed_GrEngine, NULL);
- #endif
- SkDebugf("---- constructor\n");
- }
-
- if (NULL != fGrContext) {
- return true;
- } else {
- detachGL();
- }
- }
-#endif
- SkDebugf("Failed to setup 3D");
- return false;
-}
-
-SampleWindow::CanvasType SampleWindow::cycle_canvastype(CanvasType ct) {
- static const CanvasType gCT[] = {
- kPicture_CanvasType,
- kGPU_CanvasType,
- kRaster_CanvasType
+static inline SampleWindow::DeviceType cycle_devicetype(SampleWindow::DeviceType ct) {
+ static const SampleWindow::DeviceType gCT[] = {
+ SampleWindow::kPicture_DeviceType,
+ SampleWindow::kGPU_DeviceType,
+ SampleWindow::kRaster_DeviceType, // skip the null gpu device in normal cycling
+ SampleWindow::kRaster_DeviceType
};
return gCT[ct];
}
-SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
+SampleWindow::SampleWindow(void* hwnd, int argc, char** argv, DeviceManager* devManager) : INHERITED(hwnd) {
+ gSampleWindow = this;
+
#ifdef PIPE_FILE
//Clear existing file or create file if it doesn't exist
FILE* f = fopen(FILE_PATH, "wb");
@@ -437,28 +600,26 @@ SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
#endif
fPicture = NULL;
- fGpuCanvas = NULL;
-
- fGrContext = NULL;
-
+
#ifdef DEFAULT_TO_GPU
- fCanvasType = kGPU_CanvasType;
+ fDeviceType = kGPU_DeviceType;
#else
- fCanvasType = kRaster_CanvasType;
+ fDeviceType = kRaster_DeviceType;
#endif
fUseClip = false;
fNClip = false;
- fRepeatDrawing = false;
fAnimating = false;
fRotate = false;
+ fPerspAnim = false;
+ fPerspAnimTime = 0;
fScale = false;
fRequestGrabImage = false;
fUsePipe = false;
fMeasureFPS = false;
- fLCDState = kUnknown_SkTriState;
- fAAState = kUnknown_SkTriState;
- fFilterState = kUnknown_SkTriState;
- fHintingState = kUnknown_SkTriState;
+ fLCDState = SkOSMenu::kMixedState;
+ fAAState = SkOSMenu::kMixedState;
+ fFilterState = SkOSMenu::kMixedState;
+ fHintingState = SkOSMenu::kMixedState;
fFlipAxis = 0;
fScrollTestX = fScrollTestY = 0;
@@ -466,15 +627,74 @@ SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
fFatBitsScale = 8;
fTypeface = SkTypeface::CreateFromTypeface(NULL, SkTypeface::kBold);
fShowZoomer = false;
-
+
fZoomLevel = 0;
fZoomScale = SK_Scalar1;
+
+ fMagnify = false;
+ fDebugger = false;
+
+ fSaveToPdf = false;
+ fPdfCanvas = NULL;
+ fTransitionNext = 6;
+ fTransitionPrev = 2;
+
+ int sinkID = this->getSinkID();
+ fAppMenu.setTitle("Global Settings");
+ int itemID;
+
+ itemID =fAppMenu.appendList("Device Type", "Device Type", sinkID, 0,
+ "Raster", "Picture", "OpenGL", NULL);
+ fAppMenu.assignKeyEquivalentToItem(itemID, 'd');
+ itemID = fAppMenu.appendTriState("AA", "AA", sinkID, fAAState);
+ fAppMenu.assignKeyEquivalentToItem(itemID, 'b');
+ itemID = fAppMenu.appendTriState("LCD", "LCD", sinkID, fLCDState);
+ fAppMenu.assignKeyEquivalentToItem(itemID, 'l');
+ itemID = fAppMenu.appendTriState("Filter", "Filter", sinkID, fFilterState);
+ fAppMenu.assignKeyEquivalentToItem(itemID, 'n');
+ itemID = fAppMenu.appendTriState("Hinting", "Hinting", sinkID, fHintingState);
+ fAppMenu.assignKeyEquivalentToItem(itemID, 'h');
+ fUsePipeMenuItemID = fAppMenu.appendSwitch("Pipe", "Pipe" , sinkID, fUsePipe);
+ fAppMenu.assignKeyEquivalentToItem(fUsePipeMenuItemID, 'p');
+#ifdef DEBUGGER
+ itemID = fAppMenu.appendSwitch("Debugger", "Debugger", sinkID, fDebugger);
+ fAppMenu.assignKeyEquivalentToItem(itemID, 'q');
+#endif
+ itemID = fAppMenu.appendSwitch("Slide Show", "Slide Show" , sinkID, false);
+ fAppMenu.assignKeyEquivalentToItem(itemID, 'a');
+ itemID = fAppMenu.appendSwitch("Clip", "Clip" , sinkID, fUseClip);
+ fAppMenu.assignKeyEquivalentToItem(itemID, 'c');
+ itemID = fAppMenu.appendSwitch("Flip X", "Flip X" , sinkID, false);
+ fAppMenu.assignKeyEquivalentToItem(itemID, 'x');
+ itemID = fAppMenu.appendSwitch("Flip Y", "Flip Y" , sinkID, false);
+ fAppMenu.assignKeyEquivalentToItem(itemID, 'y');
+ itemID = fAppMenu.appendSwitch("Zoomer", "Zoomer" , sinkID, fShowZoomer);
+ fAppMenu.assignKeyEquivalentToItem(itemID, 'z');
+ itemID = fAppMenu.appendSwitch("Magnify", "Magnify" , sinkID, fMagnify);
+ fAppMenu.assignKeyEquivalentToItem(itemID, 'm');
+ itemID =fAppMenu.appendList("Transition-Next", "Transition-Next", sinkID,
+ fTransitionNext, "Up", "Up and Right", "Right",
+ "Down and Right", "Down", "Down and Left",
+ "Left", "Up and Left", NULL);
+ fAppMenu.assignKeyEquivalentToItem(itemID, 'j');
+ itemID =fAppMenu.appendList("Transition-Prev", "Transition-Prev", sinkID,
+ fTransitionPrev, "Up", "Up and Right", "Right",
+ "Down and Right", "Down", "Down and Left",
+ "Left", "Up and Left", NULL);
+ fAppMenu.assignKeyEquivalentToItem(itemID, 'k');
+ itemID = fAppMenu.appendAction("Save to PDF", sinkID);
+ fAppMenu.assignKeyEquivalentToItem(itemID, 'e');
+
+ this->addMenu(&fAppMenu);
+ this->addMenu(&fSlideMenu);
+
// this->setConfig(SkBitmap::kRGB_565_Config);
this->setConfig(SkBitmap::kARGB_8888_Config);
this->setVisibleP(true);
this->setClipToBounds(false);
+ SkGMRegistyToSampleRegistry();
{
const SkViewRegister* reg = SkViewRegister::Head();
while (reg) {
@@ -483,20 +703,62 @@ SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
}
}
fCurrIndex = 0;
- this->loadView(fSamples[fCurrIndex]());
+ if (argc > 1) {
+ fCurrIndex = findByTitle(argv[1]);
+ if (fCurrIndex < 0) {
+ fprintf(stderr, "Unknown sample \"%s\"\n", argv[1]);
+ }
+ } else {
+ SkString title;
+ if (readTitleFromPrefs(&title)) {
+ fCurrIndex = findByTitle(title.c_str());
+ }
+ }
-#ifdef SK_BUILD_FOR_MAC
- testpdf();
-#endif
+ if (fCurrIndex < 0) {
+ fCurrIndex = 0;
+ }
+ this->loadView((*fSamples[fCurrIndex])());
+
+ fPDFData = NULL;
+
+ if (NULL == devManager) {
+ fDevManager = new DefaultDeviceManager();
+ } else {
+ devManager->ref();
+ fDevManager = devManager;
+ }
+ fDevManager->init(this);
+
+ // If another constructor set our dimensions, ensure that our
+ // onSizeChange gets called.
+ if (this->height() && this->width()) {
+ this->onSizeChange();
+ }
+
+ // can't call this synchronously, since it may require a subclass to
+ // to implement, or the caller may need us to have returned from the
+ // constructor first. Hence we post an event to ourselves.
+// this->updateTitle();
+ postEventToSink(new SkEvent(gUpdateWindowTitleEvtName), this);
}
SampleWindow::~SampleWindow() {
delete fPicture;
- delete fGpuCanvas;
- if (NULL != fGrContext) {
- fGrContext->unref();
- }
+ delete fPdfCanvas;
fTypeface->unref();
+
+ SkSafeUnref(fDevManager);
+}
+
+int SampleWindow::findByTitle(const char title[]) {
+ int i, count = fSamples.count();
+ for (i = 0; i < count; i++) {
+ if (getSampleTitle(i).equals(title)) {
+ return i;
+ }
+ }
+ return -1;
}
static SkBitmap capture_bitmap(SkCanvas* canvas) {
@@ -548,55 +810,27 @@ static void drawText(SkCanvas* canvas, SkString string, SkScalar left, SkScalar
#define YCLIP_N 8
void SampleWindow::draw(SkCanvas* canvas) {
+ if (!fDevManager->prepareCanvas(fDeviceType, canvas, this)) {
+ return;
+ }
// update the animation time
- gAnimTimePrev = gAnimTime;
- gAnimTime = SkTime::GetMSecs();
-
- SkScalar cx = SkScalarHalf(this->width());
- SkScalar cy = SkScalarHalf(this->height());
-
- if (fZoomLevel) {
- SkMatrix m;
- SkPoint center;
- m = canvas->getTotalMatrix();//.invert(&m);
- m.mapXY(cx, cy, &center);
- cx = center.fX;
- cy = center.fY;
-
- m.setTranslate(-cx, -cy);
- m.postScale(fZoomScale, fZoomScale);
- m.postTranslate(cx, cy);
-
- canvas->concat(m);
+ if (!gAnimTimePrev && !gAnimTime) {
+ // first time make delta be 0
+ gAnimTime = SkTime::GetMSecs();
+ gAnimTimePrev = gAnimTime;
+ } else {
+ gAnimTimePrev = gAnimTime;
+ gAnimTime = SkTime::GetMSecs();
}
-
- if (fFlipAxis) {
- SkMatrix m;
- m.setTranslate(cx, cy);
- if (fFlipAxis & kFlipAxis_X) {
- m.preScale(-SK_Scalar1, SK_Scalar1);
- }
- if (fFlipAxis & kFlipAxis_Y) {
- m.preScale(SK_Scalar1, -SK_Scalar1);
- }
- m.preTranslate(-cx, -cy);
- canvas->concat(m);
+
+ const SkMatrix& localM = fGesture.localM();
+ if (localM.getType() & SkMatrix::kScale_Mask) {
+ canvas->setExternalMatrix(&localM);
}
-
- // Apply any gesture matrix
- if (true) {
- const SkMatrix& localM = fGesture.localM();
- if (localM.getType() & SkMatrix::kScale_Mask) {
- canvas->setExternalMatrix(&localM);
- }
- canvas->concat(localM);
- canvas->concat(fGesture.globalM());
-
- if (fGesture.isActive()) {
- this->inval(NULL);
- }
+ if (fGesture.isActive()) {
+ this->updateMatrix();
}
-
+
if (fNClip) {
this->INHERITED::draw(canvas);
SkBitmap orig = capture_bitmap(canvas);
@@ -630,14 +864,52 @@ void SampleWindow::draw(SkCanvas* canvas) {
} else {
this->INHERITED::draw(canvas);
}
- if (fShowZoomer && fCanvasType != kGPU_CanvasType) {
- // In the GPU case, INHERITED::draw calls beforeChildren, which
- // creates an SkGpuCanvas. All further draw calls are directed
- // at that canvas, which is deleted in afterChildren (which is
- // also called by draw), so we cannot show the zoomer here.
- // Instead, we call it inside afterChildren.
+ if (fShowZoomer && !fSaveToPdf) {
showZoomer(canvas);
}
+ if (fMagnify && !fSaveToPdf) {
+ magnify(canvas);
+ }
+
+ // do this last
+ fDevManager->publishCanvas(fDeviceType, canvas, this);
+}
+
+static float clipW = 200;
+static float clipH = 200;
+void SampleWindow::magnify(SkCanvas* canvas) {
+ SkRect r;
+ int count = canvas->save();
+
+ SkMatrix m = canvas->getTotalMatrix();
+ m.invert(&m);
+ SkPoint offset, center;
+ SkScalar mouseX = fMouseX * SK_Scalar1;
+ SkScalar mouseY = fMouseY * SK_Scalar1;
+ m.mapXY(mouseX - clipW/2, mouseY - clipH/2, &offset);
+ m.mapXY(mouseX, mouseY, &center);
+
+ r.set(0, 0, clipW * m.getScaleX(), clipH * m.getScaleX());
+ r.offset(offset.fX, offset.fY);
+
+ SkPaint paint;
+ paint.setColor(0xFF66AAEE);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(10.f * m.getScaleX());
+ //lense offset
+ //canvas->translate(0, -250);
+ canvas->drawRect(r, paint);
+ canvas->clipRect(r);
+
+ m = canvas->getTotalMatrix();
+ m.setTranslate(-center.fX, -center.fY);
+ m.postScale(0.5f * fFatBitsScale, 0.5f * fFatBitsScale);
+ m.postTranslate(center.fX, center.fY);
+ canvas->concat(m);
+
+ this->INHERITED::draw(canvas);
+
+ canvas->restoreToCount(count);
}
void SampleWindow::showZoomer(SkCanvas* canvas) {
@@ -726,9 +998,6 @@ void SampleWindow::showZoomer(SkCanvas* canvas) {
}
void SampleWindow::onDraw(SkCanvas* canvas) {
- if (fRepeatDrawing) {
- this->inval(NULL);
- }
}
#include "SkColorPriv.h"
@@ -749,49 +1018,39 @@ static void reverseRedAndBlue(const SkBitmap& bm) {
}
}
-SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
- if (kGPU_CanvasType != fCanvasType) {
-#ifdef SK_SUPPORT_GL
- detachGL();
-#endif
- }
-
- switch (fCanvasType) {
- case kRaster_CanvasType:
- canvas = this->INHERITED::beforeChildren(canvas);
- break;
- case kPicture_CanvasType:
- fPicture = new SkPicture;
- canvas = fPicture->beginRecording(9999, 9999);
- break;
- case kGPU_CanvasType: {
- if (make3DReady()) {
- SkDevice* device = canvas->getDevice();
- const SkBitmap& bitmap = device->accessBitmap(true);
-
- GrRenderTarget* renderTarget;
- renderTarget = fGrContext->createRenderTargetFrom3DApiState();
- fGpuCanvas = new SkGpuCanvas(fGrContext, renderTarget);
- renderTarget->unref();
-
- device = fGpuCanvas->createDevice(SkBitmap::kARGB_8888_Config,
- bitmap.width(), bitmap.height(),
- false, false);
- fGpuCanvas->setDevice(device)->unref();
-
- fGpuCanvas->concat(canvas->getTotalMatrix());
- canvas = fGpuCanvas;
+void SampleWindow::saveToPdf()
+{
+ fSaveToPdf = true;
+ this->inval(NULL);
+}
- } else {
+SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
+ if (fSaveToPdf) {
+ const SkBitmap& bmp = canvas->getDevice()->accessBitmap(false);
+ SkISize size = SkISize::Make(bmp.width(), bmp.height());
+ SkPDFDevice* pdfDevice = new SkPDFDevice(size, size,
+ canvas->getTotalMatrix());
+ fPdfCanvas = new SkCanvas(pdfDevice);
+ pdfDevice->unref();
+ canvas = fPdfCanvas;
+ } else {
+ switch (fDeviceType) {
+ case kRaster_DeviceType:
+ case kGPU_DeviceType:
canvas = this->INHERITED::beforeChildren(canvas);
- }
- break;
+ break;
+ case kPicture_DeviceType:
+ fPicture = new SkPicture;
+ canvas = fPicture->beginRecording(9999, 9999);
+ break;
+ case kNullGPU_DeviceType:
+ break;
}
}
if (fUseClip) {
canvas->drawColor(0xFFFF88FF);
- canvas->clipPath(fClipPath);
+ canvas->clipPath(fClipPath, SkRegion::kIntersect_Op, true);
}
return canvas;
@@ -806,13 +1065,47 @@ static void paint_rgn(const SkBitmap& bm, const SkIRect& r,
canvas.clipRegion(inval);
canvas.drawColor(0xFFFF8080);
}
-
+#include "SkData.h"
void SampleWindow::afterChildren(SkCanvas* orig) {
+ if (fSaveToPdf) {
+ fSaveToPdf = false;
+ if (fShowZoomer) {
+ showZoomer(fPdfCanvas);
+ }
+ SkString name;
+ name.printf("%s.pdf", this->getTitle());
+ SkPDFDocument doc;
+ SkPDFDevice* device = static_cast<SkPDFDevice*>(fPdfCanvas->getDevice());
+ doc.appendPage(device);
+#ifdef SK_BUILD_FOR_ANDROID
+ name.prepend("/sdcard/");
+#endif
+
+#ifdef SK_BUILD_FOR_IOS
+ SkDynamicMemoryWStream mstream;
+ doc.emitPDF(&mstream);
+ fPDFData = mstream.copyToData();
+#endif
+ SkFILEWStream stream(name.c_str());
+ if (stream.isValid()) {
+ doc.emitPDF(&stream);
+ const char* desc = "File saved from Skia SampleApp";
+ this->onPDFSaved(this->getTitle(), desc, name.c_str());
+ }
+
+ delete fPdfCanvas;
+ fPdfCanvas = NULL;
+
+ // We took over the draw calls in order to create the PDF, so we need
+ // to redraw.
+ this->inval(NULL);
+ return;
+ }
+
if (fRequestGrabImage) {
fRequestGrabImage = false;
- SkCanvas* canvas = fGpuCanvas ? fGpuCanvas : orig;
- SkDevice* device = canvas->getDevice();
+ SkDevice* device = orig->getDevice();
SkBitmap bmp;
if (device->accessBitmap(false).copyTo(&bmp, SkBitmap::kARGB_8888_Config)) {
static int gSampleGrabCounter;
@@ -823,46 +1116,34 @@ void SampleWindow::afterChildren(SkCanvas* orig) {
}
}
- switch (fCanvasType) {
- case kRaster_CanvasType:
- break;
- case kPicture_CanvasType:
- if (true) {
- SkPicture* pict = new SkPicture(*fPicture);
- fPicture->unref();
- orig->drawPicture(*pict);
- pict->unref();
- } else if (true) {
- SkDynamicMemoryWStream ostream;
- fPicture->serialize(&ostream);
- fPicture->unref();
-
- SkMemoryStream istream(ostream.getStream(), ostream.getOffset());
- SkPicture pict(&istream);
- orig->drawPicture(pict);
- } else {
- fPicture->draw(orig);
- fPicture->unref();
- }
- fPicture = NULL;
- break;
-#ifdef SK_SUPPORT_GL
- case kGPU_CanvasType:
- if (fShowZoomer && fGpuCanvas) {
- this->showZoomer(fGpuCanvas);
- }
- delete fGpuCanvas;
- fGpuCanvas = NULL;
- presentGL();
- break;
-#endif
+ if (kPicture_DeviceType == fDeviceType) {
+ if (true) {
+ SkPicture* pict = new SkPicture(*fPicture);
+ fPicture->unref();
+ this->installDrawFilter(orig);
+ orig->drawPicture(*pict);
+ pict->unref();
+ } else if (true) {
+ SkDynamicMemoryWStream ostream;
+ fPicture->serialize(&ostream);
+ fPicture->unref();
+
+ SkAutoDataUnref data(ostream.copyToData());
+ SkMemoryStream istream(data.data(), data.size());
+ SkPicture pict(&istream);
+ orig->drawPicture(pict);
+ } else {
+ fPicture->draw(orig);
+ fPicture->unref();
+ }
+ fPicture = NULL;
}
// Do this after presentGL and other finishing, rather than in afterChild
if (fMeasureFPS && fMeasureFPS_Time) {
fMeasureFPS_Time = SkTime::GetMSecs() - fMeasureFPS_Time;
this->updateTitle();
- postInvalDelay(this->getSinkID());
+ this->postInvalDelay();
}
// if ((fScrollTestX | fScrollTestY) != 0)
@@ -876,7 +1157,24 @@ void SampleWindow::afterChildren(SkCanvas* orig) {
r.set(50, 50, 50+100, 50+100);
bm.scrollRect(&r, dx, dy, &inval);
paint_rgn(bm, r, inval);
- }
+ }
+#ifdef DEBUGGER
+ SkView* curr = curr_view(this);
+ if (fDebugger && !is_debugger(curr) && !is_transition(curr) && !is_overview(curr)) {
+ //Stop Pipe when fDebugger is active
+ fUsePipe = false;
+ (void)SampleView::SetUsePipe(curr, false);
+ fAppMenu.getItemByID(fUsePipeMenuItemID)->setBool(fUsePipe);
+ this->onUpdateMenu(&fAppMenu);
+
+ //Reset any transformations
+ fGesture.stop();
+ fGesture.reset();
+
+ this->loadView(create_debugger(gTempDataStore.begin(),
+ gTempDataStore.count()));
+ }
+#endif
}
void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) {
@@ -895,9 +1193,24 @@ void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) {
canvas->rotate(SkIntToScalar(30));
canvas->translate(-cx, -cy);
}
+ if (fPerspAnim) {
+ fPerspAnimTime += SampleCode::GetAnimSecondsDelta();
- canvas->setDrawFilter(new FlagsDrawFilter(fLCDState, fAAState,
- fFilterState, fHintingState))->unref();
+ static const SkScalar gAnimPeriod = 10 * SK_Scalar1;
+ static const SkScalar gAnimMag = SK_Scalar1 / 1000;
+ SkScalar t = SkScalarMod(fPerspAnimTime, gAnimPeriod);
+ if (SkScalarFloorToInt(SkScalarDiv(fPerspAnimTime, gAnimPeriod)) & 0x1) {
+ t = gAnimPeriod - t;
+ }
+ t = 2 * t - gAnimPeriod;
+ t = SkScalarMul(SkScalarDiv(t, gAnimPeriod), gAnimMag);
+ SkMatrix m;
+ m.reset();
+ m.setPerspY(t);
+ canvas->concat(m);
+ }
+
+ this->installDrawFilter(canvas);
if (fMeasureFPS) {
fMeasureFPS_Time = 0; // 0 means the child is not aware of repeat-draw
@@ -907,7 +1220,10 @@ void SampleWindow::beforeChild(SkView* child, SkCanvas* canvas) {
} else {
(void)SampleView::SetRepeatDraw(child, 1);
}
- (void)SampleView::SetUsePipe(child, fUsePipe);
+ if (fPerspAnim) {
+ this->inval(NULL);
+ }
+ //(void)SampleView::SetUsePipe(child, fUsePipe);
}
void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) {
@@ -928,28 +1244,116 @@ static SkBitmap::Config cycle_configs(SkBitmap::Config c) {
return gConfigCycle[c];
}
-void SampleWindow::changeZoomLevel(int delta) {
- fZoomLevel += delta;
+void SampleWindow::changeZoomLevel(float delta) {
+ fZoomLevel += SkFloatToScalar(delta);
if (fZoomLevel > 0) {
- fZoomLevel = SkMin32(fZoomLevel, MAX_ZOOM_LEVEL);
- fZoomScale = SkIntToScalar(fZoomLevel + 1);
+ fZoomLevel = SkMinScalar(fZoomLevel, MAX_ZOOM_LEVEL);
+ fZoomScale = fZoomLevel + SK_Scalar1;
} else if (fZoomLevel < 0) {
- fZoomLevel = SkMax32(fZoomLevel, MIN_ZOOM_LEVEL);
- fZoomScale = SK_Scalar1 / (1 - fZoomLevel);
+ fZoomLevel = SkMaxScalar(fZoomLevel, MIN_ZOOM_LEVEL);
+ fZoomScale = SK_Scalar1 / (SK_Scalar1 - fZoomLevel);
} else {
fZoomScale = SK_Scalar1;
}
+ this->updateMatrix();
+}
+void SampleWindow::updateMatrix(){
+ SkMatrix m;
+ m.reset();
+ if (fZoomLevel) {
+ SkPoint center;
+ //m = this->getLocalMatrix();//.invert(&m);
+ m.mapXY(fZoomCenterX, fZoomCenterY, &center);
+ SkScalar cx = center.fX;
+ SkScalar cy = center.fY;
+
+ m.setTranslate(-cx, -cy);
+ m.postScale(fZoomScale, fZoomScale);
+ m.postTranslate(cx, cy);
+ }
+
+ if (fFlipAxis) {
+ m.preTranslate(fZoomCenterX, fZoomCenterY);
+ if (fFlipAxis & kFlipAxis_X) {
+ m.preScale(-SK_Scalar1, SK_Scalar1);
+ }
+ if (fFlipAxis & kFlipAxis_Y) {
+ m.preScale(SK_Scalar1, -SK_Scalar1);
+ }
+ m.preTranslate(-fZoomCenterX, -fZoomCenterY);
+ //canvas->concat(m);
+ }
+ // Apply any gesture matrix
+ m.preConcat(fGesture.localM());
+ m.preConcat(fGesture.globalM());
+
+ this->setLocalMatrix(m);
+
+ this->updateTitle();
this->inval(NULL);
}
+bool SampleWindow::previousSample() {
+ fCurrIndex = (fCurrIndex - 1 + fSamples.count()) % fSamples.count();
+ SkView* view = (*fSamples[fCurrIndex])();
+ this->loadView(view);
+// this->loadView(create_transition(curr_view(this), (*fSamples[fCurrIndex])(),
+// fTransitionPrev));
+ return true;
+}
bool SampleWindow::nextSample() {
fCurrIndex = (fCurrIndex + 1) % fSamples.count();
- this->loadView(fSamples[fCurrIndex]());
+ SkView* view = (*fSamples[fCurrIndex])();
+ this->loadView(view);
+// this->loadView(create_transition(curr_view(this), (*fSamples[fCurrIndex])(),
+// fTransitionNext));
+ return true;
+}
+
+bool SampleWindow::goToSample(int i) {
+ fCurrIndex = (i) % fSamples.count();
+ SkView* view = (*fSamples[fCurrIndex])();
+ this->loadView(view);
+// this->loadView(create_transition(curr_view(this),(*fSamples[fCurrIndex])(), 6));
return true;
}
+SkString SampleWindow::getSampleTitle(int i) {
+ SkView* view = (*fSamples[i])();
+ SkString title;
+ SampleCode::RequestTitle(view, &title);
+ view->unref();
+ return title;
+}
+
+int SampleWindow::sampleCount() {
+ return fSamples.count();
+}
+
+void SampleWindow::showOverview() {
+ this->loadView(create_overview(fSamples.count(), fSamples.begin()));
+// this->loadView(create_transition(curr_view(this),
+// create_overview(fSamples.count(), fSamples.begin()),
+// 4));
+}
+
+void SampleWindow::installDrawFilter(SkCanvas* canvas) {
+ canvas->setDrawFilter(new FlagsDrawFilter(fLCDState, fAAState,
+ fFilterState, fHintingState))->unref();
+}
+
+void SampleWindow::postAnimatingEvent() {
+ if (fAnimating) {
+ (new SkEvent(ANIMATING_EVENTTYPE, this->getSinkID()))->postDelay(ANIMATING_DELAY);
+ }
+}
+
bool SampleWindow::onEvent(const SkEvent& evt) {
+ if (evt.isType(gUpdateWindowTitleEvtName)) {
+ this->updateTitle();
+ return true;
+ }
if (evt.isType(ANIMATING_EVENTTYPE)) {
if (fAnimating) {
this->nextSample();
@@ -957,15 +1361,76 @@ bool SampleWindow::onEvent(const SkEvent& evt) {
}
return true;
}
+ if (evt.isType("replace-transition-view")) {
+ this->loadView((SkView*)SkEventSink::FindSink(evt.getFast32()));
+ return true;
+ }
if (evt.isType("set-curr-index")) {
- fCurrIndex = evt.getFast32() % fSamples.count();
- this->loadView(fSamples[fCurrIndex]());
+ this->goToSample(evt.getFast32());
return true;
}
if (isInvalEvent(evt)) {
this->inval(NULL);
return true;
}
+ int selected = -1;
+ if (SkOSMenu::FindListIndex(evt, "Device Type", &selected)) {
+ this->setDeviceType((DeviceType)selected);
+ return true;
+ }
+ if (SkOSMenu::FindSwitchState(evt, "Pipe", &fUsePipe)) {
+#ifdef PIPE_NET
+ if (!fUsePipe)
+ gServer.disconnectAll();
+#endif
+ (void)SampleView::SetUsePipe(curr_view(this), fUsePipe);
+ this->updateTitle();
+ this->inval(NULL);
+ return true;
+ }
+ if (SkOSMenu::FindSwitchState(evt, "Slide Show", NULL)) {
+ this->toggleSlideshow();
+ return true;
+ }
+ if (SkOSMenu::FindTriState(evt, "AA", &fAAState) ||
+ SkOSMenu::FindTriState(evt, "LCD", &fLCDState) ||
+ SkOSMenu::FindTriState(evt, "Filter", &fFilterState) ||
+ SkOSMenu::FindTriState(evt, "Hinting", &fHintingState) ||
+ SkOSMenu::FindSwitchState(evt, "Clip", &fUseClip) ||
+ SkOSMenu::FindSwitchState(evt, "Zoomer", &fShowZoomer) ||
+ SkOSMenu::FindSwitchState(evt, "Magnify", &fMagnify) ||
+ SkOSMenu::FindListIndex(evt, "Transition-Next", &fTransitionNext) ||
+ SkOSMenu::FindListIndex(evt, "Transition-Prev", &fTransitionPrev)) {
+ this->inval(NULL);
+ this->updateTitle();
+ return true;
+ }
+ if (SkOSMenu::FindSwitchState(evt, "Flip X", NULL)) {
+ fFlipAxis ^= kFlipAxis_X;
+ this->updateMatrix();
+ return true;
+ }
+ if (SkOSMenu::FindSwitchState(evt, "Flip Y", NULL)) {
+ fFlipAxis ^= kFlipAxis_Y;
+ this->updateMatrix();
+ return true;
+ }
+ if (SkOSMenu::FindAction(evt,"Save to PDF")) {
+ this->saveToPdf();
+ return true;
+ }
+#ifdef DEBUGGER
+ if (SkOSMenu::FindSwitchState(evt, "Debugger", &fDebugger)) {
+ if (fDebugger) {
+ fUsePipe = true;
+ (void)SampleView::SetUsePipe(curr_view(this), true);
+ } else {
+ this->loadView(fSamples[fCurrIndex]());
+ }
+ this->inval(NULL);
+ return true;
+ }
+#endif
return this->INHERITED::onEvent(evt);
}
@@ -975,7 +1440,7 @@ bool SampleWindow::onQuery(SkEvent* query) {
return true;
}
if (query->isType("get-slide-title")) {
- SkView* view = fSamples[query->getFast32()]();
+ SkView* view = (*fSamples[query->getFast32()])();
SkEvent evt(gTitleEvtName);
if (view->doQuery(&evt)) {
query->setString("title", evt.findString(gTitleEvtName));
@@ -987,6 +1452,10 @@ bool SampleWindow::onQuery(SkEvent* query) {
SkEvent evt(gFastTextEvtName);
return curr_view(this)->doQuery(&evt);
}
+ if (query->isType("ignore-window-bitmap")) {
+ query->setFast32(this->getGrContext() != NULL);
+ return true;
+ }
return this->INHERITED::onQuery(query);
}
@@ -1013,7 +1482,7 @@ bool SampleWindow::onHandleChar(SkUnichar uni) {
}
}
}
-
+
int dx = 0xFF;
int dy = 0xFF;
@@ -1044,88 +1513,83 @@ bool SampleWindow::onHandleChar(SkUnichar uni) {
}
switch (uni) {
- case 'a':
- fAnimating = !fAnimating;
- this->postAnimatingEvent();
- this->updateTitle();
- return true;
- case 'b':
- fAAState = cycle_tristate(fAAState);
- this->updateTitle();
- this->inval(NULL);
- break;
- case 'c':
- fUseClip = !fUseClip;
- this->inval(NULL);
- this->updateTitle();
- return true;
- case 'd':
- SkGraphics::SetFontCacheUsed(0);
- return true;
case 'f':
- fMeasureFPS = !fMeasureFPS;
- this->inval(NULL);
+ // only
+ toggleFPS();
break;
case 'g':
fRequestGrabImage = true;
this->inval(NULL);
break;
- case 'h':
- fHintingState = cycle_tristate(fHintingState);
- this->updateTitle();
- this->inval(NULL);
- break;
case 'i':
this->zoomIn();
break;
- case 'l':
- fLCDState = cycle_tristate(fLCDState);
- this->updateTitle();
- this->inval(NULL);
- break;
- case 'n':
- fFilterState = cycle_tristate(fFilterState);
- this->updateTitle();
- this->inval(NULL);
- break;
case 'o':
this->zoomOut();
break;
- case 'p':
- fUsePipe = !fUsePipe;
- this->updateTitle();
- this->inval(NULL);
- break;
case 'r':
fRotate = !fRotate;
this->inval(NULL);
this->updateTitle();
return true;
- case 's':
- fScale = !fScale;
+ case 'k':
+ fPerspAnim = !fPerspAnim;
this->inval(NULL);
this->updateTitle();
return true;
- case 'x':
- fFlipAxis ^= kFlipAxis_X;
- this->updateTitle();
+ case '\\':
+ if (fDevManager->supportsDeviceType(kNullGPU_DeviceType)) {
+ fDeviceType= kNullGPU_DeviceType;
+ this->inval(NULL);
+ this->updateTitle();
+ }
+ return true;
+ case 's':
+ fScale = !fScale;
this->inval(NULL);
- break;
- case 'y':
- fFlipAxis ^= kFlipAxis_Y;
this->updateTitle();
- this->inval(NULL);
- break;
- case 'z':
- this->toggleZoomer();
- break;
+ return true;
default:
break;
}
-
+
+ if (fAppMenu.handleKeyEquivalent(uni)|| fSlideMenu.handleKeyEquivalent(uni)) {
+ this->onUpdateMenu(&fAppMenu);
+ this->onUpdateMenu(&fSlideMenu);
+ return true;
+ }
return this->INHERITED::onHandleChar(uni);
}
+void SampleWindow::setDeviceType(DeviceType type) {
+ if (type != fDeviceType && fDevManager->supportsDeviceType(fDeviceType))
+ fDeviceType = type;
+ this->updateTitle();
+ this->inval(NULL);
+}
+
+void SampleWindow::toggleSlideshow() {
+ fAnimating = !fAnimating;
+ this->postAnimatingEvent();
+ this->updateTitle();
+}
+
+void SampleWindow::toggleRendering() {
+ DeviceType origDevType = fDeviceType;
+ do {
+ fDeviceType = cycle_devicetype(fDeviceType);
+ } while (origDevType != fDeviceType &&
+ !fDevManager->supportsDeviceType(fDeviceType));
+ this->updateTitle();
+ this->inval(NULL);
+}
+
+void SampleWindow::toggleFPS() {
+ fMeasureFPS = !fMeasureFPS;
+ this->updateTitle();
+ this->inval(NULL);
+}
+
#include "SkDumpCanvas.h"
bool SampleWindow::onHandleKey(SkKey key) {
@@ -1139,7 +1603,6 @@ bool SampleWindow::onHandleKey(SkKey key) {
}
}
}
-
switch (key) {
case kRight_SkKey:
if (this->nextSample()) {
@@ -1147,41 +1610,34 @@ bool SampleWindow::onHandleKey(SkKey key) {
}
break;
case kLeft_SkKey:
- fCanvasType = cycle_canvastype(fCanvasType);
- this->updateTitle();
- this->inval(NULL);
+ toggleRendering();
return true;
case kUp_SkKey:
if (USE_ARROWS_FOR_ZOOM) {
- this->changeZoomLevel(1);
+ this->changeZoomLevel(1.f);
} else {
fNClip = !fNClip;
this->inval(NULL);
+ this->updateTitle();
}
- this->updateTitle();
return true;
case kDown_SkKey:
if (USE_ARROWS_FOR_ZOOM) {
- this->changeZoomLevel(-1);
+ this->changeZoomLevel(-1.f);
} else {
this->setConfig(cycle_configs(this->getBitmap().config()));
+ this->updateTitle();
}
- this->updateTitle();
return true;
- case kOK_SkKey:
- if (false) {
- SkDebugfDumper dumper;
- SkDumpCanvas dc(&dumper);
- this->draw(&dc);
- } else {
- fRepeatDrawing = !fRepeatDrawing;
- if (fRepeatDrawing) {
- this->inval(NULL);
- }
+ case kOK_SkKey: {
+ SkString title;
+ if (curr_title(this, &title)) {
+ writeTitleToPrefs(title.c_str());
}
return true;
+ }
case kBack_SkKey:
- this->loadView(NULL);
+ this->showOverview();
return true;
default:
break;
@@ -1193,7 +1649,8 @@ bool SampleWindow::onHandleKey(SkKey key) {
static const char gGestureClickType[] = "GestureClickType";
-bool SampleWindow::onDispatchClick(int x, int y, Click::State state) {
+bool SampleWindow::onDispatchClick(int x, int y, Click::State state,
+ void* owner) {
if (Click::kMoved_State == state) {
updatePointer(x, y);
}
@@ -1203,8 +1660,14 @@ bool SampleWindow::onDispatchClick(int x, int y, Click::State state) {
// check for the resize-box
if (w - x < 16 && h - y < 16) {
return false; // let the OS handle the click
- } else {
- return this->INHERITED::onDispatchClick(x, y, state);
+ }
+ else if (fMagnify) {
+ //it's only necessary to update the drawing if there's a click
+ this->inval(NULL);
+ return false; //prevent dragging while magnify is enabled
+ }
+ else {
+ return this->INHERITED::onDispatchClick(x, y, state, owner);
}
}
@@ -1225,19 +1688,20 @@ SkView::Click* SampleWindow::onFindClickHandler(SkScalar x, SkScalar y) {
bool SampleWindow::onClick(Click* click) {
if (GestureClick::IsGesture(click)) {
- float x = SkScalarToFloat(click->fCurr.fX);
- float y = SkScalarToFloat(click->fCurr.fY);
+ float x = static_cast<float>(click->fICurr.fX);
+ float y = static_cast<float>(click->fICurr.fY);
+
switch (click->fState) {
case SkView::Click::kDown_State:
- fGesture.touchBegin(click, x, y);
+ fGesture.touchBegin(click->fOwner, x, y);
break;
case SkView::Click::kMoved_State:
- fGesture.touchMoved(click, x, y);
- this->inval(NULL);
+ fGesture.touchMoved(click->fOwner, x, y);
+ this->updateMatrix();
break;
case SkView::Click::kUp_State:
- fGesture.touchEnd(click);
- this->inval(NULL);
+ fGesture.touchEnd(click->fOwner);
+ this->updateMatrix();
break;
}
return true;
@@ -1253,15 +1717,24 @@ void SampleWindow::loadView(SkView* view) {
if (prev) {
prev->detachFromParent();
}
-
- if (NULL == view) {
- view = create_overview(fSamples.count(), fSamples.begin());
- }
+
view->setVisibleP(true);
view->setClipToBounds(false);
this->attachChildToFront(view)->unref();
view->setSize(this->width(), this->height());
+ //repopulate the slide menu when a view is loaded
+ fSlideMenu.reset();
+#ifdef DEBUGGER
+ if (!is_debugger(view) && !is_overview(view) && !is_transition(view) && fDebugger) {
+ //Force Pipe to be on if using debugger
+ fUsePipe = true;
+ }
+#endif
+ (void)SampleView::SetUsePipe(view, fUsePipe);
+ if (SampleView::IsSampleView(view))
+ ((SampleView*)view)->requestMenu(&fSlideMenu);
+ this->onUpdateMenu(&fSlideMenu);
this->updateTitle();
}
@@ -1279,36 +1752,32 @@ static const char* configToString(SkBitmap::Config c) {
return gConfigNames[c];
}
-static const char* gCanvasTypePrefix[] = {
+static const char* gDeviceTypePrefix[] = {
"raster: ",
"picture: ",
- "opengl: "
+ "opengl: ",
+ "null-gl: "
};
-static const char* trystate_str(SkTriState state,
+static const char* trystate_str(SkOSMenu::TriState state,
const char trueStr[], const char falseStr[]) {
- if (kTrue_SkTriState == state) {
+ if (SkOSMenu::kOnState == state) {
return trueStr;
- } else if (kFalse_SkTriState == state) {
+ } else if (SkOSMenu::kOffState == state) {
return falseStr;
}
return NULL;
}
void SampleWindow::updateTitle() {
- SkString title;
+ SkView* view = curr_view(this);
- SkView::F2BIter iter(this);
- SkView* view = iter.next();
- SkEvent evt(gTitleEvtName);
- if (view->doQuery(&evt)) {
- title.set(evt.findString(gTitleEvtName));
- }
- if (title.size() == 0) {
+ SkString title;
+ if (!curr_title(this, &title)) {
title.set("<unknown>");
}
- title.prepend(gCanvasTypePrefix[fCanvasType]);
+ title.prepend(gDeviceTypePrefix[fDeviceType]);
title.prepend(" ");
title.prepend(configToString(this->getBitmap().config()));
@@ -1325,6 +1794,9 @@ void SampleWindow::updateTitle() {
if (fNClip) {
title.prepend("<C> ");
}
+ if (fPerspAnim) {
+ title.prepend("<K> ");
+ }
title.prepend(trystate_str(fLCDState, "LCD ", "lcd "));
title.prepend(trystate_str(fAAState, "AA ", "aa "));
@@ -1333,7 +1805,7 @@ void SampleWindow::updateTitle() {
title.prepend(fFlipAxis & kFlipAxis_Y ? "Y " : NULL);
if (fZoomLevel) {
- title.prependf("{%d} ", fZoomLevel);
+ title.prependf("{%.2f} ", SkScalarToFloat(fZoomLevel));
}
if (fMeasureFPS) {
@@ -1351,7 +1823,7 @@ void SampleWindow::updateTitle() {
void SampleWindow::onSizeChange() {
this->INHERITED::onSizeChange();
-
+
SkView::F2BIter iter(this);
SkView* view = iter.next();
view->setSize(this->width(), this->height());
@@ -1378,7 +1850,16 @@ void SampleWindow::onSizeChange() {
#endif
}
+ fZoomCenterX = SkScalarHalf(this->width());
+ fZoomCenterY = SkScalarHalf(this->height());
+
+#ifdef SK_BUILD_FOR_ANDROID
+ // FIXME: The first draw after a size change does not work on Android, so
+ // we post an invalidate.
+ this->postInvalDelay();
+#endif
this->updateTitle(); // to refresh our config
+ fDevManager->windowSizeChanged(this);
}
///////////////////////////////////////////////////////////////////////////////
@@ -1430,7 +1911,11 @@ class SimplePC : public SkGPipeController {
public:
SimplePC(SkCanvas* target);
~SimplePC();
-
+
+ /**
+ * User this method to halt/restart pipe
+ */
+ void setWriteToPipe(bool writeToPipe) { fWriteToPipe = writeToPipe; }
virtual void* requestBlock(size_t minRequest, size_t* actual);
virtual void notifyWritten(size_t bytes);
@@ -1441,6 +1926,7 @@ private:
size_t fBytesWritten;
int fAtomsWritten;
SkGPipeReader::Status fStatus;
+ bool fWriteToPipe;
size_t fTotalWritten;
};
@@ -1451,16 +1937,35 @@ SimplePC::SimplePC(SkCanvas* target) : fReader(target) {
fStatus = SkGPipeReader::kDone_Status;
fTotalWritten = 0;
fAtomsWritten = 0;
+ fWriteToPipe = true;
}
SimplePC::~SimplePC() {
// SkASSERT(SkGPipeReader::kDone_Status == fStatus);
- sk_free(fBlock);
-
if (fTotalWritten) {
- SkDebugf("--- %d bytes %d atoms, status %d\n", fTotalWritten,
- fAtomsWritten, fStatus);
+ if (fWriteToPipe) {
+ SkDebugf("--- %d bytes %d atoms, status %d\n", fTotalWritten,
+ fAtomsWritten, fStatus);
+#ifdef PIPE_FILE
+ //File is open in append mode
+ FILE* f = fopen(FILE_PATH, "ab");
+ SkASSERT(f != NULL);
+ fwrite((const char*)fBlock + fBytesWritten, 1, bytes, f);
+ fclose(f);
+#endif
+#ifdef PIPE_NET
+ if (fAtomsWritten > 1 && fTotalWritten > 4) { //ignore done
+ gServer.acceptConnections();
+ gServer.writePacket(fBlock, fTotalWritten);
+ }
+#endif
+#ifdef DEBUGGER
+ gTempDataStore.reset();
+ gTempDataStore.append(fTotalWritten, (const char*)fBlock);
+#endif
+ }
}
+ sk_free(fBlock);
}
void* SimplePC::requestBlock(size_t minRequest, size_t* actual) {
@@ -1475,37 +1980,37 @@ void* SimplePC::requestBlock(size_t minRequest, size_t* actual) {
void SimplePC::notifyWritten(size_t bytes) {
SkASSERT(fBytesWritten + bytes <= fBlockSize);
-
-#ifdef PIPE_FILE
- //File is open in append mode
- FILE* f = fopen(FILE_PATH, "ab");
- SkASSERT(f != NULL);
- fwrite((const char*)fBlock + fBytesWritten, 1, bytes, f);
- fclose(f);
-#endif
-
fStatus = fReader.playback((const char*)fBlock + fBytesWritten, bytes);
SkASSERT(SkGPipeReader::kError_Status != fStatus);
fBytesWritten += bytes;
fTotalWritten += bytes;
-
+
fAtomsWritten += 1;
}
#endif
-
-void SampleView::onDraw(SkCanvas* canvas) {
+void SampleView::draw(SkCanvas* canvas) {
#ifdef TEST_GPIPE
- SimplePC controller(canvas);
- SkGPipeWriter writer;
if (fUsePipe) {
+ SkGPipeWriter writer;
+ SimplePC controller(canvas);
uint32_t flags = SkGPipeWriter::kCrossProcess_Flag;
-// flags = 0;
canvas = writer.startRecording(&controller, flags);
+ //Must draw before controller goes out of scope and sends data
+ this->INHERITED::draw(canvas);
+ //explicitly end recording to ensure writer is flushed before the memory
+ //is freed in the deconstructor of the controller
+ writer.endRecording();
+ controller.setWriteToPipe(fUsePipe);
}
+ else
+ this->INHERITED::draw(canvas);
+#else
+ this->INHERITED::draw(canvas);
#endif
-
+}
+void SampleView::onDraw(SkCanvas* canvas) {
this->onDrawBackground(canvas);
for (int i = 0; i < fRepeatCount; i++) {
@@ -1620,9 +2125,9 @@ static void test() {
}
}
-SkOSWindow* create_sk_window(void* hwnd) {
+SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) {
// test();
- return new SampleWindow(hwnd);
+ return new SampleWindow(hwnd, argc, argv, NULL);
}
void get_preferred_size(int* x, int* y, int* width, int* height) {
diff --git a/samplecode/SampleApp.h b/samplecode/SampleApp.h
new file mode 100644
index 0000000..871d47e
--- /dev/null
+++ b/samplecode/SampleApp.h
@@ -0,0 +1,197 @@
+
+/*
+ * Copyright 2011 Skia
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SampleWindow_DEFINED
+#define SampleWindow_DEFINED
+
+#include "SkWindow.h"
+
+#include "SampleCode.h"
+#include "SkPath.h"
+#include "SkScalar.h"
+#include "SkTDArray.h"
+#include "SkTouchGesture.h"
+#include "SkWindow.h"
+#include "SkOSMenu.h"
+
+class GrContext;
+class GrRenderTarget;
+
+class SkEvent;
+class SkCanvas;
+class SkPicture;
+class SkTypeface;
+class SkData;
+
+class SampleWindow : public SkOSWindow {
+ SkTDArray<const SkViewFactory*> fSamples;
+public:
+ enum DeviceType {
+ kRaster_DeviceType,
+ kPicture_DeviceType,
+ kGPU_DeviceType,
+ kNullGPU_DeviceType
+ };
+ /**
+ * SampleApp ports can subclass this manager class if they want to:
+ * * filter the types of devices supported
+ * * customize plugging of SkDevice objects into an SkCanvas
+ * * customize publishing the results of draw to the OS window
+ * * manage GrContext / GrRenderTarget lifetimes
+ */
+ class DeviceManager : public SkRefCnt {
+ public:
+ // called at end of SampleWindow cons
+ virtual void init(SampleWindow* win) = 0;
+
+ // called when selecting a new device type
+ // can disallow a device type by returning false.
+ virtual bool supportsDeviceType(DeviceType dType) = 0;
+
+ // called before drawing. should install correct device
+ // type on the canvas. Will skip drawing if returns false.
+ virtual bool prepareCanvas(DeviceType dType,
+ SkCanvas* canvas,
+ SampleWindow* win) = 0;
+
+ // called after drawing, should get the results onto the
+ // screen.
+ virtual void publishCanvas(DeviceType dType,
+ SkCanvas* canvas,
+ SampleWindow* win) = 0;
+
+ // called when window changes size, guaranteed to be called
+ // at least once before first draw (after init)
+ virtual void windowSizeChanged(SampleWindow* win) = 0;
+
+ // return the GrContext backing gpu devices
+ virtual GrContext* getGrContext(DeviceType dType) = 0;
+ };
+
+ SampleWindow(void* hwnd, int argc, char** argv, DeviceManager*);
+ virtual ~SampleWindow();
+
+ virtual void draw(SkCanvas* canvas);
+
+ void setDeviceType(DeviceType type);
+ void toggleRendering();
+ void toggleSlideshow();
+ void toggleFPS();
+ void showOverview();
+
+ GrContext* getGrContext() const { return fDevManager->getGrContext(fDeviceType); }
+
+ void setZoomCenter(float x, float y);
+ void changeZoomLevel(float delta);
+ bool nextSample();
+ bool previousSample();
+ bool goToSample(int i);
+ SkString getSampleTitle(int i);
+ int sampleCount();
+ bool handleTouch(int ownerId, float x, float y,
+ SkView::Click::State state);
+ void saveToPdf();
+ SkData* getPDFData() { return fPDFData; }
+ void postInvalDelay();
+
+protected:
+ virtual void onDraw(SkCanvas* canvas);
+ virtual bool onHandleKey(SkKey key);
+ virtual bool onHandleChar(SkUnichar);
+ virtual void onSizeChange();
+
+ virtual SkCanvas* beforeChildren(SkCanvas*);
+ virtual void afterChildren(SkCanvas*);
+ virtual void beforeChild(SkView* child, SkCanvas* canvas);
+ virtual void afterChild(SkView* child, SkCanvas* canvas);
+
+ virtual bool onEvent(const SkEvent& evt);
+ virtual bool onQuery(SkEvent* evt);
+
+ virtual bool onDispatchClick(int x, int y, Click::State, void* owner);
+ virtual bool onClick(Click* click);
+ virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
+
+private:
+ class DefaultDeviceManager;
+
+ int fCurrIndex;
+
+ SkPicture* fPicture;
+ SkPath fClipPath;
+
+ SkTouchGesture fGesture;
+ SkScalar fZoomLevel;
+ SkScalar fZoomScale;
+
+ DeviceType fDeviceType;
+ DeviceManager* fDevManager;
+
+ bool fSaveToPdf;
+ SkCanvas* fPdfCanvas;
+ SkData* fPDFData;
+
+ bool fUseClip;
+ bool fNClip;
+ bool fAnimating;
+ bool fRotate;
+ bool fPerspAnim;
+ SkScalar fPerspAnimTime;
+ bool fScale;
+ bool fRequestGrabImage;
+ bool fMeasureFPS;
+ SkMSec fMeasureFPS_Time;
+ bool fMagnify;
+
+
+ bool fUsePipe;
+ int fUsePipeMenuItemID;
+ bool fDebugger;
+
+ // The following are for the 'fatbits' drawing
+ // Latest position of the mouse.
+ int fMouseX, fMouseY;
+ int fFatBitsScale;
+ // Used by the text showing position and color values.
+ SkTypeface* fTypeface;
+ bool fShowZoomer;
+
+ SkOSMenu::TriState fLCDState;
+ SkOSMenu::TriState fAAState;
+ SkOSMenu::TriState fFilterState;
+ SkOSMenu::TriState fHintingState;
+ unsigned fFlipAxis;
+
+ int fScrollTestX, fScrollTestY;
+ SkScalar fZoomCenterX, fZoomCenterY;
+
+ //Stores global settings
+ SkOSMenu fAppMenu;
+ //Stores slide specific settings
+ SkOSMenu fSlideMenu;
+ int fTransitionNext;
+ int fTransitionPrev;
+
+ void loadView(SkView*);
+ void updateTitle();
+
+ bool zoomIn();
+ bool zoomOut();
+ void updatePointer(int x, int y);
+ void magnify(SkCanvas* canvas);
+ void showZoomer(SkCanvas* canvas);
+ void updateMatrix();
+ void postAnimatingEvent();
+ void installDrawFilter(SkCanvas*);
+ int findByTitle(const char*);
+
+ typedef SkOSWindow INHERITED;
+};
+
+#endif
diff --git a/samplecode/SampleArc.cpp b/samplecode/SampleArc.cpp
index 8e3ad88..d418a4b 100644
--- a/samplecode/SampleArc.cpp
+++ b/samplecode/SampleArc.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleAvoid.cpp b/samplecode/SampleAvoid.cpp
index 868a67c..81050a3 100644
--- a/samplecode/SampleAvoid.cpp
+++ b/samplecode/SampleAvoid.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleBigBlur.cpp b/samplecode/SampleBigBlur.cpp
new file mode 100644
index 0000000..f5e632c
--- /dev/null
+++ b/samplecode/SampleBigBlur.cpp
@@ -0,0 +1,50 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SampleCode.h"
+#include "SkBlurMaskFilter.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+
+class BigBlurView : public SampleView {
+public:
+ BigBlurView() {
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "BigBlur");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ canvas->save();
+ paint.setColor(SK_ColorBLUE);
+ SkMaskFilter* mf = SkBlurMaskFilter::Create(
+ 128,
+ SkBlurMaskFilter::kNormal_BlurStyle,
+ SkBlurMaskFilter::kHighQuality_BlurFlag);
+ paint.setMaskFilter(mf)->unref();
+ canvas->translate(200, 200);
+ canvas->drawCircle(100, 100, 200, paint);
+ canvas->restore();
+ }
+
+private:
+ typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new BigBlurView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleBigGradient.cpp b/samplecode/SampleBigGradient.cpp
index 5ebb516..8e08e15 100644
--- a/samplecode/SampleBigGradient.cpp
+++ b/samplecode/SampleBigGradient.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleBitmapRect.cpp b/samplecode/SampleBitmapRect.cpp
index 002b2b9..95ea1a7 100644
--- a/samplecode/SampleBitmapRect.cpp
+++ b/samplecode/SampleBitmapRect.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
@@ -17,28 +24,34 @@
#include "SkOSFile.h"
#include "SkStream.h"
-static SkBitmap make_bitmap() {
- SkBitmap bm;
- bm.setConfig(SkBitmap::kARGB_8888_Config, 64, 64);
- bm.allocPixels();
- SkCanvas canvas(bm);
+#include "SkGpuDevice.h"
+
+static void make_bitmap(SkBitmap* bitmap, GrContext* ctx) {
+ SkCanvas canvas;
+
+ if (ctx) {
+ SkDevice* dev = new SkGpuDevice(ctx, SkBitmap::kARGB_8888_Config, 64, 64);
+ canvas.setDevice(dev)->unref();
+ *bitmap = dev->accessBitmap(false);
+ } else {
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config, 64, 64);
+ bitmap->allocPixels();
+ canvas.setBitmapDevice(*bitmap);
+ }
+
canvas.drawColor(SK_ColorRED);
SkPaint paint;
paint.setAntiAlias(true);
const SkPoint pts[] = { { 0, 0 }, { 64, 64 } };
const SkColor colors[] = { SK_ColorWHITE, SK_ColorBLUE };
paint.setShader(SkGradientShader::CreateLinear(pts, colors, NULL, 2,
- SkShader::kClamp_TileMode))->unref();
+ SkShader::kClamp_TileMode))->unref();
canvas.drawCircle(32, 32, 32, paint);
- return bm;
}
class BitmapRectView : public SampleView {
public:
- SkBitmap fBitmap;
-
BitmapRectView() {
- fBitmap = make_bitmap();
this->setBGColor(SK_ColorGRAY);
}
@@ -53,6 +66,8 @@ protected:
}
virtual void onDrawContent(SkCanvas* canvas) {
+ GrContext* ctx = SampleCode::GetGr();
+
const SkIRect src[] = {
{ 0, 0, 32, 32 },
{ 0, 0, 80, 80 },
@@ -62,7 +77,10 @@ protected:
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(SK_ColorGREEN);
+ paint.setColor(ctx ? SK_ColorGREEN : SK_ColorYELLOW);
+
+ SkBitmap bitmap;
+ make_bitmap(&bitmap, ctx);
SkRect dstR = { 0, 200, 128, 380 };
@@ -71,8 +89,8 @@ protected:
SkRect srcR;
srcR.set(src[i]);
- canvas->drawBitmap(fBitmap, 0, 0, &paint);
- canvas->drawBitmapRect(fBitmap, &src[i], dstR, &paint);
+ canvas->drawBitmap(bitmap, 0, 0, &paint);
+ canvas->drawBitmapRect(bitmap, &src[i], dstR, &paint);
canvas->drawRect(dstR, paint);
canvas->drawRect(srcR, paint);
diff --git a/samplecode/SampleBlur.cpp b/samplecode/SampleBlur.cpp
index d2ea2b0..aa92343 100644
--- a/samplecode/SampleBlur.cpp
+++ b/samplecode/SampleBlur.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkBlurMaskFilter.h"
#include "SkColorPriv.h"
@@ -41,7 +48,7 @@ static SkBitmap make_bitmap() {
return bm;
}
-class BlurView : public SkView {
+class BlurView : public SampleView {
SkBitmap fBM;
public:
BlurView() {
@@ -61,7 +68,7 @@ protected:
canvas->drawColor(0xFFDDDDDD);
}
- virtual void onDraw(SkCanvas* canvas) {
+ virtual void onDrawContent(SkCanvas* canvas) {
drawBG(canvas);
SkBlurMaskFilter::BlurStyle NONE = SkBlurMaskFilter::BlurStyle(-999);
diff --git a/samplecode/SampleBox.cpp b/samplecode/SampleBox.cpp
index d445df7..0b1da07 100644
--- a/samplecode/SampleBox.cpp
+++ b/samplecode/SampleBox.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleCamera.cpp b/samplecode/SampleCamera.cpp
index 2db3968..a4af2de 100644
--- a/samplecode/SampleCamera.cpp
+++ b/samplecode/SampleCamera.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleCircle.cpp b/samplecode/SampleCircle.cpp
index 2abc28d..c3f986d 100644
--- a/samplecode/SampleCircle.cpp
+++ b/samplecode/SampleCircle.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleClamp.cpp b/samplecode/SampleClamp.cpp
index 88c1b91..c521f81 100644
--- a/samplecode/SampleClamp.cpp
+++ b/samplecode/SampleClamp.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleClip.cpp b/samplecode/SampleClip.cpp
new file mode 100644
index 0000000..570f0b9
--- /dev/null
+++ b/samplecode/SampleClip.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+
+#define W 150
+#define H 200
+
+static void show_text(SkCanvas* canvas, bool doAA) {
+ SkRandom rand;
+ SkPaint paint;
+ paint.setAntiAlias(doAA);
+ paint.setLCDRenderText(true);
+ paint.setTextSize(SkIntToScalar(20));
+
+ for (int i = 0; i < 200; ++i) {
+ paint.setColor((SK_A32_MASK << SK_A32_SHIFT) | rand.nextU());
+ canvas->drawText("Hamburgefons", 12,
+ rand.nextSScalar1() * W, rand.nextSScalar1() * H + 20,
+ paint);
+ }
+}
+
+static bool valid(int i) {
+ return i < 15 && i > 7;
+}
+
+static void show_fill(SkCanvas* canvas, bool doAA) {
+ SkRandom rand;
+ SkPaint paint;
+ paint.setAntiAlias(doAA);
+
+ for (int i = 0; i < 50; ++i) {
+ SkRect r;
+ SkPath p;
+
+ r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
+ rand.nextUScalar1() * W, rand.nextUScalar1() * H);
+ paint.setColor(rand.nextU());
+ canvas->drawRect(r, paint);
+
+ r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
+ rand.nextUScalar1() * W, rand.nextUScalar1() * H);
+ paint.setColor(rand.nextU());
+ p.addOval(r);
+ canvas->drawPath(p, paint);
+ }
+}
+
+static SkScalar randRange(SkRandom& rand, SkScalar min, SkScalar max) {
+ SkASSERT(min <= max);
+ return min + SkScalarMul(rand.nextUScalar1(), max - min);
+}
+
+static void show_stroke(SkCanvas* canvas, bool doAA, SkScalar strokeWidth, int n) {
+ SkRandom rand;
+ SkPaint paint;
+ paint.setAntiAlias(doAA);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(strokeWidth);
+
+ for (int i = 0; i < n; ++i) {
+ SkRect r;
+ SkPath p;
+
+ r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
+ rand.nextUScalar1() * W, rand.nextUScalar1() * H);
+ paint.setColor(rand.nextU());
+ canvas->drawRect(r, paint);
+
+ r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
+ rand.nextUScalar1() * W, rand.nextUScalar1() * H);
+ paint.setColor(rand.nextU());
+ p.addOval(r);
+ canvas->drawPath(p, paint);
+
+ const SkScalar minx = -SkIntToScalar(W)/4;
+ const SkScalar maxx = 5*SkIntToScalar(W)/4;
+ const SkScalar miny = -SkIntToScalar(H)/4;
+ const SkScalar maxy = 5*SkIntToScalar(H)/4;
+ paint.setColor(rand.nextU());
+ canvas->drawLine(randRange(rand, minx, maxx), randRange(rand, miny, maxy),
+ randRange(rand, minx, maxx), randRange(rand, miny, maxy),
+ paint);
+ }
+}
+
+static void show_hair(SkCanvas* canvas, bool doAA) {
+ show_stroke(canvas, doAA, 0, 150);
+}
+
+static void show_thick(SkCanvas* canvas, bool doAA) {
+ show_stroke(canvas, doAA, SkIntToScalar(5), 50);
+}
+
+typedef void (*CanvasProc)(SkCanvas*, bool);
+
+#include "SkAAClip.h"
+
+class ClipView : public SampleView {
+public:
+ ClipView() {
+ SkAAClip clip;
+ SkIRect r = { -2, -3, 842, 18 };
+ clip.setRect(r);
+ }
+
+ virtual ~ClipView() {
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "Clip");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ canvas->drawColor(SK_ColorWHITE);
+ canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
+
+ static const CanvasProc gProc[] = {
+ show_text, show_thick, show_hair, show_fill
+ };
+
+ SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) };
+ SkPath clipPath;
+ r.inset(SK_Scalar1 / 4, SK_Scalar1 / 4);
+ clipPath.addRoundRect(r, SkIntToScalar(20), SkIntToScalar(20));
+
+// clipPath.toggleInverseFillType();
+
+ for (int aa = 0; aa <= 1; ++aa) {
+ canvas->save();
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gProc); ++i) {
+ canvas->save();
+ canvas->clipPath(clipPath, SkRegion::kIntersect_Op, true);
+// canvas->drawColor(SK_ColorWHITE);
+ gProc[i](canvas, SkToBool(aa));
+ canvas->restore();
+ canvas->translate(W * SK_Scalar1 * 8 / 7, 0);
+ }
+ canvas->restore();
+ canvas->translate(0, H * SK_Scalar1 * 8 / 7);
+ }
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ClipView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleCode.h b/samplecode/SampleCode.h
index c42ee25..197e0f1 100644
--- a/samplecode/SampleCode.h
+++ b/samplecode/SampleCode.h
@@ -1,3 +1,12 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
#ifndef SampleCode_DEFINED
#define SampleCode_DEFINED
@@ -5,6 +14,8 @@
#include "SkEvent.h"
#include "SkKey.h"
#include "SkView.h"
+class SkOSMenu;
+class GrContext;
class SampleCode {
public:
@@ -13,6 +24,7 @@ public:
static bool TitleQ(const SkEvent&);
static void TitleR(SkEvent*, const char title[]);
+ static bool RequestTitle(SkView* view, SkString* title);
static bool PrefSizeQ(const SkEvent&);
static void PrefSizeR(SkEvent*, SkScalar width, SkScalar height);
@@ -23,23 +35,65 @@ public:
static SkMSec GetAnimTimeDelta();
static SkScalar GetAnimSecondsDelta();
static SkScalar GetAnimScalar(SkScalar speedPerSec, SkScalar period = 0);
+
+ static GrContext* GetGr();
};
//////////////////////////////////////////////////////////////////////////////
-typedef SkView* (*SkViewFactory)();
+// interface that constructs SkViews
+class SkViewFactory : public SkRefCnt {
+public:
+ virtual SkView* operator() () const = 0;
+};
-class SkViewRegister : SkNoncopyable {
+typedef SkView* (*SkViewCreateFunc)();
+
+// wraps SkViewCreateFunc in SkViewFactory interface
+class SkFuncViewFactory : public SkViewFactory {
public:
- explicit SkViewRegister(SkViewFactory);
+ SkFuncViewFactory(SkViewCreateFunc func);
+ virtual SkView* operator() () const SK_OVERRIDE;
+
+private:
+ SkViewCreateFunc fCreateFunc;
+};
+
+namespace skiagm {
+class GM;
+}
+
+// factory function that creates a skiagm::GM
+typedef skiagm::GM* (*GMFactoryFunc)(void*);
+
+// Takes a GM factory function and implements the SkViewFactory interface
+// by making the GM and wrapping it in a GMSampleView. GMSampleView bridges
+// the SampleView interface to skiagm::GM.
+class SkGMSampleViewFactory : public SkViewFactory {
+public:
+ SkGMSampleViewFactory(GMFactoryFunc func);
+ virtual SkView* operator() () const SK_OVERRIDE;
+private:
+ GMFactoryFunc fFunc;
+};
+
+class SkViewRegister : public SkRefCnt {
+public:
+ explicit SkViewRegister(SkViewFactory*);
+ explicit SkViewRegister(SkViewCreateFunc);
+ explicit SkViewRegister(GMFactoryFunc);
+
+ ~SkViewRegister() {
+ fFact->unref();
+ }
static const SkViewRegister* Head() { return gHead; }
SkViewRegister* next() const { return fChain; }
- SkViewFactory factory() const { return fFact; }
+ const SkViewFactory* factory() const { return fFact; }
private:
- SkViewFactory fFact;
+ SkViewFactory* fFact;
SkViewRegister* fChain;
static SkViewRegister* gHead;
@@ -49,7 +103,7 @@ private:
class SampleView : public SkView {
public:
- SampleView() : fRepeatCount(1), fBGColor(SK_ColorWHITE) {
+ SampleView() : fBGColor(SK_ColorWHITE), fRepeatCount(1) {
fUsePipe = false;
}
@@ -58,21 +112,31 @@ public:
static bool IsSampleView(SkView*);
static bool SetRepeatDraw(SkView*, int count);
static bool SetUsePipe(SkView*, bool);
+
+ /**
+ * Call this to request menu items from a SampleView.
+ * Subclassing notes: A subclass of SampleView can overwrite this method
+ * to add new items of various types to the menu and change its title.
+ * The events attached to any new menu items must be handled in its onEvent
+ * method. See SkOSMenu.h for helper functions.
+ */
+ virtual void requestMenu(SkOSMenu* menu) {}
protected:
virtual void onDrawBackground(SkCanvas*);
virtual void onDrawContent(SkCanvas*) = 0;
-
+
// overrides
virtual bool onEvent(const SkEvent& evt);
virtual bool onQuery(SkEvent* evt);
+ virtual void draw(SkCanvas*);
virtual void onDraw(SkCanvas*);
+ bool fUsePipe;
+ SkColor fBGColor;
+
private:
int fRepeatCount;
- SkColor fBGColor;
-
- bool fUsePipe;
typedef SkView INHERITED;
};
diff --git a/samplecode/SampleColorFilter.cpp b/samplecode/SampleColorFilter.cpp
index 0e1fb11..52bf950 100644
--- a/samplecode/SampleColorFilter.cpp
+++ b/samplecode/SampleColorFilter.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleComplexClip.cpp b/samplecode/SampleComplexClip.cpp
index 672d055..e7f9a01 100644
--- a/samplecode/SampleComplexClip.cpp
+++ b/samplecode/SampleComplexClip.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkCanvas.h"
#include "SkPath.h"
diff --git a/samplecode/SampleConcavePaths.cpp b/samplecode/SampleConcavePaths.cpp
new file mode 100644
index 0000000..1659ec0
--- /dev/null
+++ b/samplecode/SampleConcavePaths.cpp
@@ -0,0 +1,153 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkGradientShader.h"
+#include "SkGraphics.h"
+#include "SkImageDecoder.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkParsePath.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+
+#include "SkGeometry.h"
+
+class ConcavePathView : public SampleView {
+public:
+ ConcavePathView() {}
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "ConcavePaths");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kFill_Style);
+
+ // Concave test
+ if (1) {
+ SkPath path;
+ canvas->translate(0, 0);
+ path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
+ path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
+ path.lineTo(SkIntToScalar(30), SkIntToScalar(30));
+ path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
+ canvas->drawPath(path, paint);
+ }
+ // Reverse concave test
+ if (1) {
+ SkPath path;
+ canvas->save();
+ canvas->translate(100, 0);
+ path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
+ path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
+ path.lineTo(SkIntToScalar(30), SkIntToScalar(30));
+ path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ }
+ // Bowtie (intersection)
+ if (1) {
+ SkPath path;
+ canvas->save();
+ canvas->translate(200, 0);
+ path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
+ path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
+ path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
+ path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ }
+ // "fake" bowtie (concave, but no intersection)
+ if (1) {
+ SkPath path;
+ canvas->save();
+ canvas->translate(300, 0);
+ path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
+ path.lineTo(SkIntToScalar(50), SkIntToScalar(40));
+ path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
+ path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
+ path.lineTo(SkIntToScalar(50), SkIntToScalar(60));
+ path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ }
+ // Fish test (intersection/concave)
+ if (1) {
+ SkPath path;
+ canvas->save();
+ canvas->translate(0, 100);
+ path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
+ path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
+ path.lineTo(SkIntToScalar(70), SkIntToScalar(50));
+ path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
+ path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
+ path.lineTo(SkIntToScalar(0), SkIntToScalar(50));
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ }
+ // Collinear test
+ if (1) {
+ SkPath path;
+ canvas->save();
+ canvas->translate(100, 100);
+ path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
+ path.lineTo(SkIntToScalar(50), SkIntToScalar(20));
+ path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
+ path.lineTo(SkIntToScalar(50), SkIntToScalar(80));
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ }
+ // Hole test
+ if (1) {
+ SkPath path;
+ canvas->save();
+ canvas->translate(200, 100);
+ path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
+ path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
+ path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
+ path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
+ path.moveTo(SkIntToScalar(30), SkIntToScalar(30));
+ path.lineTo(SkIntToScalar(30), SkIntToScalar(70));
+ path.lineTo(SkIntToScalar(70), SkIntToScalar(70));
+ path.lineTo(SkIntToScalar(70), SkIntToScalar(30));
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ }
+ }
+
+ virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+ this->inval(NULL);
+ return this->INHERITED::onFindClickHandler(x, y);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new ConcavePathView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleCull.cpp b/samplecode/SampleCull.cpp
index 7b4eab6..778d0fc 100644
--- a/samplecode/SampleCull.cpp
+++ b/samplecode/SampleCull.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleDash.cpp b/samplecode/SampleDash.cpp
index 4cef07f..fc0d678 100644
--- a/samplecode/SampleDash.cpp
+++ b/samplecode/SampleDash.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleDecode.cpp b/samplecode/SampleDecode.cpp
index b192c5d..9188257 100644
--- a/samplecode/SampleDecode.cpp
+++ b/samplecode/SampleDecode.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleDegenerateTwoPtRadials.cpp b/samplecode/SampleDegenerateTwoPtRadials.cpp
new file mode 100644
index 0000000..5b8f46d
--- /dev/null
+++ b/samplecode/SampleDegenerateTwoPtRadials.cpp
@@ -0,0 +1,92 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "Sk64.h"
+#include "SkGradientShader.h"
+
+static void draw_gradient2(SkCanvas* canvas, const SkRect& rect, SkScalar delta) {
+ SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorMAGENTA };
+ SkScalar pos[] = { 0, SkFloatToScalar(0.25f), SkFloatToScalar(0.75f), SK_Scalar1 };
+
+ SkScalar l = rect.fLeft;
+ SkScalar t = rect.fTop;
+ SkScalar w = rect.width();
+ SkScalar h = rect.height();
+
+ SkASSERT(0 == SkScalarMod(w, SK_Scalar1 * 5));
+
+ SkPoint c0 = { l + 2 * w / 5 + delta, t + h / 2 };
+ SkPoint c1 = { l + 3 * w / 5, t + h / 2 };
+ SkScalar r0 = w / 5;
+ SkScalar r1 = 2 * w / 5;
+ SkShader* s = SkGradientShader::CreateTwoPointRadial(c0, r0, c1, r1, colors,
+ pos, SK_ARRAY_COUNT(pos),
+ SkShader::kClamp_TileMode);
+ SkPaint paint;
+ paint.setShader(s)->unref();
+
+ canvas->drawRect(rect, paint);
+}
+
+
+class DegenerateTwoPtRadialsView : public SampleView {
+
+public:
+ DegenerateTwoPtRadialsView() {
+ fTime = 0;
+ this->setBGColor(0xFFDDDDDD);
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "DegenerateTwoPtRadials");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ fTime += SampleCode::GetAnimSecondsDelta();
+ SkScalar delta = fTime / 15.f;
+ int intPart = SkScalarFloor(delta);
+ delta = delta - SK_Scalar1 * intPart;
+ if (intPart % 2) {
+ delta = SK_Scalar1 - delta;
+ }
+ delta -= SK_ScalarHalf;
+ static const int DELTA_SCALE = 500;
+ delta /= DELTA_SCALE;
+
+ SkRect rect;
+ SkScalar w = SK_Scalar1 * 500;
+ SkScalar h = SK_Scalar1 * 500;
+ SkScalar l = SK_Scalar1 * 100;
+ SkScalar t = SK_Scalar1 * 100;
+ draw_gradient2(canvas, SkRect::MakeXYWH(l, t, w, h), delta);
+ char txt[512];
+ sprintf(txt, "gap at \"tangent\" pt = %f", SkScalarToFloat(delta));
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(SK_ColorBLACK);
+ canvas->drawText(txt, strlen(txt), l + w/2 + w*DELTA_SCALE*delta, t + h + SK_Scalar1 * 10, paint);
+ this->inval(NULL);
+ }
+
+private:
+ SkScalar fTime;
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new DegenerateTwoPtRadialsView; }
+static SkViewRegister reg(MyFactory);
diff --git a/samplecode/SampleDither.cpp b/samplecode/SampleDither.cpp
index 3e77a5d..85ac2b1 100644
--- a/samplecode/SampleDither.cpp
+++ b/samplecode/SampleDither.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleDitherBitmap.cpp b/samplecode/SampleDitherBitmap.cpp
index 0d62446..c243782 100644
--- a/samplecode/SampleDitherBitmap.cpp
+++ b/samplecode/SampleDitherBitmap.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkColorPriv.h"
#include "SkGradientShader.h"
diff --git a/samplecode/SampleDraw.cpp b/samplecode/SampleDraw.cpp
index deb1fb2..c418585 100644
--- a/samplecode/SampleDraw.cpp
+++ b/samplecode/SampleDraw.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleDrawBitmap.cpp b/samplecode/SampleDrawBitmap.cpp
new file mode 100644
index 0000000..aaf1123
--- /dev/null
+++ b/samplecode/SampleDrawBitmap.cpp
@@ -0,0 +1,84 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkDevice.h"
+
+static void create_bitmap(SkBitmap* bitmap) {
+ const int W = 100;
+ const int H = 100;
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config, W, H);
+ bitmap->allocPixels();
+
+ SkCanvas canvas(*bitmap);
+ canvas.drawColor(SK_ColorRED);
+ SkPaint paint;
+ paint.setColor(SK_ColorBLUE);
+ canvas.drawCircle(SkIntToScalar(W)/2, SkIntToScalar(H)/2, SkIntToScalar(W)/2, paint);
+}
+
+class DrawBitmapView : public SampleView {
+ SkPath fPath;
+public:
+ DrawBitmapView() {}
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "DrawBitmap");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkBitmap bitmap;
+ create_bitmap(&bitmap);
+ int x = bitmap.width() / 2;
+ int y = bitmap.height() / 2;
+ SkBitmap subset;
+ bitmap.extractSubset(&subset, SkIRect::MakeXYWH(x, y, x, y));
+
+ canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
+
+ canvas->drawBitmap(bitmap, 0, 0);
+ canvas->drawBitmap(subset, 0, 0);
+
+ // Now do the same but with a device bitmap as source image
+ SkRefPtr<SkDevice> primaryDevice(canvas->getDevice());
+ SkRefPtr<SkDevice> secondDevice(canvas->createCompatibleDevice(
+ SkBitmap::kARGB_8888_Config, bitmap.width(),
+ bitmap.height(), true));
+ secondDevice->unref();
+ SkCanvas secondCanvas(secondDevice.get());
+ secondCanvas.writePixels(bitmap, 0, 0);
+
+ SkBitmap deviceBitmap = secondDevice->accessBitmap(false);
+ SkBitmap deviceSubset;
+ deviceBitmap.extractSubset(&deviceSubset,
+ SkIRect::MakeXYWH(x, y, x, y));
+
+ canvas->translate(SkIntToScalar(120), SkIntToScalar(0));
+
+ canvas->drawBitmap(deviceBitmap, 0, 0);
+ canvas->drawBitmap(deviceSubset, 0, 0);
+
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new DrawBitmapView; }
+static SkViewRegister reg(MyFactory);
diff --git a/samplecode/SampleDrawLooper.cpp b/samplecode/SampleDrawLooper.cpp
index 30879f7..7e317d7 100644
--- a/samplecode/SampleDrawLooper.cpp
+++ b/samplecode/SampleDrawLooper.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleEffects.cpp b/samplecode/SampleEffects.cpp
index a63c08d..bf83bae 100644
--- a/samplecode/SampleEffects.cpp
+++ b/samplecode/SampleEffects.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkCanvas.h"
#include "SkPaint.h"
@@ -127,4 +134,3 @@ private:
static SkView* MyFactory() { return new EffectsView; }
static SkViewRegister reg(MyFactory);
-
diff --git a/samplecode/SampleEmboss.cpp b/samplecode/SampleEmboss.cpp
index 8b3f194..bf12636 100644
--- a/samplecode/SampleEmboss.cpp
+++ b/samplecode/SampleEmboss.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleEmptyPath.cpp b/samplecode/SampleEmptyPath.cpp
new file mode 100644
index 0000000..cffe6cf
--- /dev/null
+++ b/samplecode/SampleEmptyPath.cpp
@@ -0,0 +1,130 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+
+class EmptyPathView : public SampleView {
+public:
+ EmptyPathView() {}
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "EmptyPath");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void drawEmpty(SkCanvas* canvas,
+ SkColor color,
+ const SkRect& clip,
+ SkPaint::Style style,
+ SkPath::FillType fill) {
+ SkPath path;
+ path.setFillType(fill);
+ SkPaint paint;
+ paint.setColor(color);
+ paint.setStyle(style);
+ canvas->save();
+ canvas->clipRect(clip);
+ canvas->drawPath(path, paint);
+ canvas->restore();
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ struct FillAndName {
+ SkPath::FillType fFill;
+ const char* fName;
+ };
+ static const FillAndName gFills[] = {
+ {SkPath::kWinding_FillType, "Winding"},
+ {SkPath::kEvenOdd_FillType, "Even / Odd"},
+ {SkPath::kInverseWinding_FillType, "Inverse Winding"},
+ {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
+ };
+ struct StyleAndName {
+ SkPaint::Style fStyle;
+ const char* fName;
+ };
+ static const StyleAndName gStyles[] = {
+ {SkPaint::kFill_Style, "Fill"},
+ {SkPaint::kStroke_Style, "Stroke"},
+ {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
+ };
+
+ SkPaint titlePaint;
+ titlePaint.setColor(SK_ColorBLACK);
+ titlePaint.setAntiAlias(true);
+ titlePaint.setLCDRenderText(true);
+ titlePaint.setTextSize(24 * SK_Scalar1);
+ const char title[] = "Empty Paths Drawn Into Rectangle Clips With Indicated Style and Fill";
+ canvas->drawText(title, strlen(title),
+ 40 * SK_Scalar1,
+ 100*SK_Scalar1,
+ titlePaint);
+
+ SkRandom rand;
+ SkRect rect = SkRect::MakeWH(125*SK_Scalar1, 100*SK_Scalar1);
+ int i = 0;
+ canvas->save();
+ canvas->translate(80 * SK_Scalar1, 0);
+ canvas->save();
+ for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+ for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+ if (0 == i % 4) {
+ canvas->restore();
+ canvas->translate(0, rect.height() + 50 * SK_Scalar1);
+ canvas->save();
+ } else {
+ canvas->translate(rect.width() + 100 * SK_Scalar1, 0);
+ }
+ ++i;
+
+
+ SkColor color = rand.nextU();
+ color = 0xff000000| color; // force solid
+ this->drawEmpty(canvas, color, rect,
+ gStyles[style].fStyle, gFills[fill].fFill);
+
+ SkPaint rectPaint;
+ rectPaint.setColor(SK_ColorBLACK);
+ rectPaint.setStyle(SkPaint::kStroke_Style);
+ rectPaint.setStrokeWidth(-1);
+ rectPaint.setAntiAlias(true);
+ canvas->drawRect(rect, rectPaint);
+
+ char label[1024];
+ sprintf(label, "%s, %s", gStyles[style].fName,
+ gFills[fill].fName);
+ SkPaint labelPaint;
+ labelPaint.setColor(color);
+ labelPaint.setAntiAlias(true);
+ labelPaint.setLCDRenderText(true);
+ canvas->drawText(label, strlen(label),
+ 0, rect.height() + 15 * SK_Scalar1,
+ labelPaint);
+ }
+ }
+ canvas->restore();
+ canvas->restore();
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new EmptyPathView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleEncode.cpp b/samplecode/SampleEncode.cpp
index f4ea195..6999a06 100644
--- a/samplecode/SampleEncode.cpp
+++ b/samplecode/SampleEncode.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleExtractAlpha.cpp b/samplecode/SampleExtractAlpha.cpp
deleted file mode 100644
index 860272d..0000000
--- a/samplecode/SampleExtractAlpha.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-#include "SampleCode.h"
-#include "SkColorPriv.h"
-#include "SkGradientShader.h"
-#include "SkView.h"
-#include "SkCanvas.h"
-#include "SkUtils.h"
-
-static SkBitmap make_bitmap() {
- SkBitmap bm;
- SkColorTable* ctable = new SkColorTable(256);
-
- SkPMColor* c = ctable->lockColors();
- for (int i = 0; i < 256; i++) {
- c[i] = SkPackARGB32(255 - i, 0, 0, 0);
- }
- ctable->unlockColors(true);
- bm.setConfig(SkBitmap::kIndex8_Config, 256, 256);
- bm.allocPixels(ctable);
- ctable->unref();
-
- bm.lockPixels();
- const float cx = bm.width() * 0.5f;
- const float cy = bm.height() * 0.5f;
- for (int y = 0; y < bm.height(); y++) {
- float dy = y - cy;
- dy *= dy;
- uint8_t* p = bm.getAddr8(0, y);
- for (int x = 0; x < 256; x++) {
- float dx = x - cx;
- dx *= dx;
- float d = (dx + dy) / (cx/2);
- int id = (int)d;
- if (id > 255) {
- id = 255;
- }
- p[x] = id;
- }
- }
- bm.unlockPixels();
- return bm;
-}
-
-class ExtractAlphaView : public SampleView {
- SkBitmap fBM8;
- SkBitmap fBM32;
- SkBitmap fBM4;
-public:
- ExtractAlphaView() {
- fBM8 = make_bitmap();
- fBM8.copyTo(&fBM32, SkBitmap::kARGB_8888_Config);
- fBM8.copyTo(&fBM4, SkBitmap::kARGB_4444_Config);
-
- this->setBGColor(0xFFDDDDDD);
- }
-
-protected:
- // overrides from SkEventSink
- virtual bool onQuery(SkEvent* evt) {
- if (SampleCode::TitleQ(*evt)) {
- SampleCode::TitleR(evt, "DitherBitmap");
- return true;
- }
- return this->INHERITED::onQuery(evt);
- }
-
- virtual void onDrawContent(SkCanvas* canvas) {
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setStyle(SkPaint::kStroke_Style);
-
- SkMatrix matrix;
- matrix.setScale(3.55f, 80.f);
- canvas->setMatrix(matrix);
-
- paint.setStrokeWidth(0.0588f);
- canvas->drawLine(10, 5, 30, 4.8f, paint);
-
- paint.setStrokeWidth(0.06f);
- canvas->drawLine(20, 5, 40, 4.8f, paint);
- }
-
-private:
- typedef SampleView INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-static SkView* MyFactory() { return new ExtractAlphaView; }
-static SkViewRegister reg(MyFactory);
-
diff --git a/samplecode/SampleFillType.cpp b/samplecode/SampleFillType.cpp
index 393c5f7..ae97720 100644
--- a/samplecode/SampleFillType.cpp
+++ b/samplecode/SampleFillType.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleFilter.cpp b/samplecode/SampleFilter.cpp
index a9089fa..350523d 100644
--- a/samplecode/SampleFilter.cpp
+++ b/samplecode/SampleFilter.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleFilter2.cpp b/samplecode/SampleFilter2.cpp
index c1a16a8..da4147e 100644
--- a/samplecode/SampleFilter2.cpp
+++ b/samplecode/SampleFilter2.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleFontCache.cpp b/samplecode/SampleFontCache.cpp
index 0b8187a..2546890 100644
--- a/samplecode/SampleFontCache.cpp
+++ b/samplecode/SampleFontCache.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleFontScalerTest.cpp b/samplecode/SampleFontScalerTest.cpp
index 0b0d349..062eca3 100644
--- a/samplecode/SampleFontScalerTest.cpp
+++ b/samplecode/SampleFontScalerTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
@@ -38,7 +45,7 @@ public:
fFaces[i] = SkTypeface::CreateFromName(gFaces[i].fName,
gFaces[i].fStyle);
}
- this->setBGColor(0xFFDDDDDD);
+// this->setBGColor(0xFFDDDDDD);
}
virtual ~FontScalerTestView() {
@@ -57,6 +64,12 @@ protected:
return this->INHERITED::onQuery(evt);
}
+ static void rotate_about(SkCanvas* canvas, SkScalar degrees, SkScalar px, SkScalar py) {
+ canvas->translate(px, py);
+ canvas->rotate(degrees);
+ canvas->translate(-px, -py);
+ }
+
virtual void onDrawContent(SkCanvas* canvas) {
SkPaint paint;
@@ -74,35 +87,43 @@ protected:
canvas->drawPath(path, paint);
}
- canvas->translate(200, 20);
- canvas->rotate(30);
-
+// paint.setSubpixelText(true);
paint.setAntiAlias(true);
paint.setLCDRenderText(true);
SkSafeUnref(paint.setTypeface(SkTypeface::CreateFromName("Times Roman", SkTypeface::kNormal)));
// const char* text = "abcdefghijklmnopqrstuvwxyz";
- const char* text = "HnHnHnHnHnHnHnHnH";
- size_t textLen = strlen(text);
-
- SkScalar x = SkIntToScalar(10);
- SkScalar y = SkIntToScalar(20);
-
- {
- SkPaint p;
- p.setColor(SK_ColorRED);
- SkRect r;
- r.set(0, 0, x, y*20);
- canvas->drawRect(r, p);
- }
-
- int index = 0;
- for (int ps = 9; ps <= 24; ps++) {
- textLen = strlen(text);
- paint.setTextSize(SkIntToScalar(ps));
- canvas->drawText(text, textLen, x, y, paint);
- y += paint.getFontMetrics(NULL);
- index += 1;
+ const char* text = "Hamburgefons ooo mmm";
+ const size_t textLen = strlen(text);
+
+ for (int j = 0; j < 2; ++j) {
+ for (int i = 0; i < 6; ++i) {
+ SkScalar x = SkIntToScalar(10);
+ SkScalar y = SkIntToScalar(20);
+
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->translate(SkIntToScalar(50 + i * 230),
+ SkIntToScalar(20));
+ rotate_about(canvas, i * 5, x, y * 10);
+
+ {
+ SkPaint p;
+ p.setAntiAlias(true);
+ SkRect r;
+ r.set(x-3, 15, x-1, 280);
+ canvas->drawRect(r, p);
+ }
+
+ int index = 0;
+ for (int ps = 6; ps <= 22; ps++) {
+ paint.setTextSize(SkIntToScalar(ps));
+ canvas->drawText(text, textLen, x, y, paint);
+ y += paint.getFontMetrics(NULL);
+ index += 1;
+ }
+ }
+ canvas->translate(0, 400);
+ paint.setSubpixelText(true);
}
}
diff --git a/samplecode/SampleFuzz.cpp b/samplecode/SampleFuzz.cpp
index 5c41886..36149c3 100644
--- a/samplecode/SampleFuzz.cpp
+++ b/samplecode/SampleFuzz.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
@@ -38,7 +45,7 @@ static float huge() {
}
static float make_number() {
- float v;
+ float v = 0;
int sel;
if (return_large == true && R(3) == 1) sel = R(6); else sel = R(4);
@@ -124,9 +131,11 @@ static void do_fuzz(SkCanvas* canvas) {
case 2: {
SkXfermode::Mode mode;
switch (R(3)) {
- case 0: mode = SkXfermode::kSrc_Mode; break;
+ case 0: mode = SkXfermode::kSrc_Mode; break;
case 1: mode = SkXfermode::kXor_Mode; break;
- case 2: mode = SkXfermode::kSrcOver_Mode; break;
+ case 2:
+ default: // silence warning
+ mode = SkXfermode::kSrcOver_Mode; break;
}
paint.setXfermodeMode(mode);
}
@@ -347,7 +356,6 @@ protected:
}
virtual void onDrawContent(SkCanvas* canvas) {
- SkIRect r = canvas->getTotalClip().getBounds();
do_fuzz(canvas);
this->inval(NULL);
}
diff --git a/samplecode/SampleGM.cpp b/samplecode/SampleGM.cpp
deleted file mode 100644
index ec5b22a..0000000
--- a/samplecode/SampleGM.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-#include "SampleCode.h"
-#include "SkView.h"
-#include "SkCanvas.h"
-
-#include "gm.h"
-
-using namespace skiagm;
-
-// need to explicitly declare this, or we get some weird infinite loop llist
-template GMRegistry* GMRegistry::gHead;
-
-class Iter {
-public:
- Iter() {
- fReg = GMRegistry::Head();
- }
-
- void reset() {
- fReg = GMRegistry::Head();
- }
-
- GM* next() {
- if (fReg) {
- GMRegistry::Factory fact = fReg->factory();
- fReg = fReg->next();
- return fact(0);
- }
- return NULL;
- }
-
- static int Count() {
- const GMRegistry* reg = GMRegistry::Head();
- int count = 0;
- while (reg) {
- count += 1;
- reg = reg->next();
- }
- return count;
- }
-
-private:
- const GMRegistry* fReg;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-class GMView : public SampleView {
- Iter fIter;
- GM* fGM;
-public:
- GMView() {
- fGM = fIter.next();
- this->postNextGM();
-
- this->setBGColor(0xFFDDDDDD);
- }
-
- virtual ~GMView() {
- delete fGM;
- }
-
-protected:
- // overrides from SkEventSink
- virtual bool onQuery(SkEvent* evt) {
- if (SampleCode::TitleQ(*evt)) {
- SampleCode::TitleR(evt, "GM");
- return true;
- }
- return this->INHERITED::onQuery(evt);
- }
-
- virtual bool onEvent(const SkEvent& evt) {
- if (evt.isType("next-gm")) {
- delete fGM;
- if (!(fGM = fIter.next())) {
- fIter.reset();
- fGM = fIter.next();
- }
- this->inval(NULL);
- this->postNextGM();
- return true;
- }
- return this->INHERITED::onEvent(evt);
- }
-
- virtual void onDrawContent(SkCanvas* canvas) {
- fGM->draw(canvas);
- }
-
-private:
- void postNextGM() {
- (new SkEvent("next-gm"))->post(this->getSinkID(), 1500);
- }
-
- typedef SampleView INHERITED;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-static SkView* MyFactory() { return new GMView; }
-static SkViewRegister reg(MyFactory);
-
-///////////////////////////////////////////////////////////////////////////////
-
-using namespace skiagm;
-
-GM::GM() {}
-GM::~GM() {}
-
-void GM::draw(SkCanvas* canvas) {
- this->onDraw(canvas);
-}
-
-
diff --git a/samplecode/SampleGradients.cpp b/samplecode/SampleGradients.cpp
index 902b0bd..18536cf 100644
--- a/samplecode/SampleGradients.cpp
+++ b/samplecode/SampleGradients.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleHairCurves.cpp b/samplecode/SampleHairCurves.cpp
new file mode 100644
index 0000000..152cbeb
--- /dev/null
+++ b/samplecode/SampleHairCurves.cpp
@@ -0,0 +1,112 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+
+class HairCurvesView : public SampleView {
+public:
+ HairCurvesView() {
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "HairCurves");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(-1);
+ canvas->save();
+ canvas->scale(1000 * SK_Scalar1, 1000 * SK_Scalar1);
+ SkRandom rand;
+ SkPath curves;
+ SkPath hulls;
+ SkPath ctrlPts;
+ for (int i = 0; i < 100; ++i) {
+ SkScalar pts[] = {
+ rand.nextUScalar1(), rand.nextUScalar1(),
+ rand.nextUScalar1(), rand.nextUScalar1(),
+ rand.nextUScalar1(), rand.nextUScalar1(),
+ rand.nextUScalar1(), rand.nextUScalar1()
+ };
+ curves.moveTo(pts[0], pts[1]);
+ curves.cubicTo(pts[2], pts[3],
+ pts[4], pts[5],
+ pts[6], pts[7]);
+
+ hulls.moveTo(pts[0], pts[1]);
+ hulls.lineTo(pts[2], pts[3]);
+ hulls.lineTo(pts[4], pts[5]);
+ hulls.lineTo(pts[6], pts[7]);
+
+ ctrlPts.addCircle(pts[0], pts[1], SK_Scalar1 / 200);
+ ctrlPts.addCircle(pts[2], pts[3], SK_Scalar1 / 200);
+ ctrlPts.addCircle(pts[4], pts[5], SK_Scalar1 / 200);
+ ctrlPts.addCircle(pts[6], pts[7], SK_Scalar1 / 200);
+ }
+ for (int i = 0; i < 100; ++i) {
+ SkScalar pts[] = {
+ rand.nextUScalar1(), rand.nextUScalar1(),
+ rand.nextUScalar1(), rand.nextUScalar1(),
+ rand.nextUScalar1(), rand.nextUScalar1(),
+ };
+ curves.moveTo(pts[0], pts[1]);
+ curves.quadTo(pts[2], pts[3],
+ pts[4], pts[5]);
+
+ hulls.moveTo(pts[0], pts[1]);
+ hulls.lineTo(pts[2], pts[3]);
+ hulls.lineTo(pts[4], pts[5]);
+
+ ctrlPts.addCircle(pts[0], pts[1], SK_Scalar1 / 200);
+ ctrlPts.addCircle(pts[2], pts[3], SK_Scalar1 / 200);
+ ctrlPts.addCircle(pts[4], pts[5], SK_Scalar1 / 200);
+ }
+ for (int i = 0; i < 100; ++i) {
+ SkScalar pts[] = {
+ rand.nextUScalar1(), rand.nextUScalar1(),
+ rand.nextUScalar1(), rand.nextUScalar1(),
+ };
+ curves.moveTo(pts[0], pts[1]);
+ curves.lineTo(pts[2], pts[3]);
+
+ ctrlPts.addCircle(pts[0], pts[1], SK_Scalar1 / 200);
+ ctrlPts.addCircle(pts[2], pts[3], SK_Scalar1 / 200);
+ }
+
+ paint.setColor(SK_ColorBLACK);
+ canvas->drawPath(curves, paint);
+ paint.setColor(SK_ColorRED);
+ //canvas->drawPath(hulls, paint);
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(SK_ColorBLUE);
+ //canvas->drawPath(ctrlPts, paint);
+
+ canvas->restore();
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new HairCurvesView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleHairModes.cpp b/samplecode/SampleHairModes.cpp
new file mode 100644
index 0000000..cc22b17
--- /dev/null
+++ b/samplecode/SampleHairModes.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+
+static SkCanvas* create_canvas(int w, int h) {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, w, h);
+ bm.allocPixels();
+ bm.eraseColor(0);
+ return new SkCanvas(bm);
+}
+
+static const SkBitmap& extract_bitmap(SkCanvas* canvas) {
+ return canvas->getDevice()->accessBitmap(false);
+}
+
+static const struct {
+ SkXfermode::Mode fMode;
+ const char* fLabel;
+} gModes[] = {
+ { SkXfermode::kClear_Mode, "Clear" },
+ { SkXfermode::kSrc_Mode, "Src" },
+ { SkXfermode::kDst_Mode, "Dst" },
+ { SkXfermode::kSrcOver_Mode, "SrcOver" },
+ { SkXfermode::kDstOver_Mode, "DstOver" },
+ { SkXfermode::kSrcIn_Mode, "SrcIn" },
+ { SkXfermode::kDstIn_Mode, "DstIn" },
+ { SkXfermode::kSrcOut_Mode, "SrcOut" },
+ { SkXfermode::kDstOut_Mode, "DstOut" },
+ { SkXfermode::kSrcATop_Mode, "SrcATop" },
+ { SkXfermode::kDstATop_Mode, "DstATop" },
+ { SkXfermode::kXor_Mode, "Xor" },
+};
+
+const int gWidth = 64;
+const int gHeight = 64;
+const SkScalar W = SkIntToScalar(gWidth);
+const SkScalar H = SkIntToScalar(gHeight);
+
+static SkScalar drawCell(SkCanvas* canvas, SkXfermode* mode, SkAlpha a0, SkAlpha a1) {
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ SkRect r = SkRect::MakeWH(W, H);
+ r.inset(W/10, H/10);
+
+ paint.setColor(SK_ColorBLUE);
+ paint.setAlpha(a0);
+ canvas->drawOval(r, paint);
+
+ paint.setColor(SK_ColorRED);
+ paint.setAlpha(a1);
+ paint.setXfermode(mode);
+ for (int angle = 0; angle < 24; ++angle) {
+ SkScalar x = SkScalarCos(SkIntToScalar(angle) * (SK_ScalarPI * 2) / 24) * gWidth;
+ SkScalar y = SkScalarSin(SkIntToScalar(angle) * (SK_ScalarPI * 2) / 24) * gHeight;
+ paint.setStrokeWidth(SK_Scalar1 * angle * 2 / 24);
+ canvas->drawLine(W/2, H/2, W/2 + x, H/2 + y, paint);
+ }
+
+ return H;
+}
+
+static SkShader* make_bg_shader() {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
+ bm.allocPixels();
+ *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = 0xFFFFFFFF;
+ *bm.getAddr32(1, 0) = *bm.getAddr32(0, 1) = SkPackARGB32(0xFF, 0xCC, 0xCC, 0xCC);
+
+ SkShader* s = SkShader::CreateBitmapShader(bm,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+
+ SkMatrix m;
+ m.setScale(SkIntToScalar(6), SkIntToScalar(6));
+ s->setLocalMatrix(m);
+ return s;
+}
+
+class HairModesView : public SampleView {
+ SkPaint fBGPaint;
+public:
+ HairModesView() {
+ fBGPaint.setShader(make_bg_shader())->unref();
+ }
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "HairlineModes");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ const SkRect bounds = SkRect::MakeWH(W, H);
+ static const SkAlpha gAlphaValue[] = { 0xFF, 0x88, 0x88 };
+
+ canvas->translate(SkIntToScalar(4), SkIntToScalar(4));
+
+ for (int alpha = 0; alpha < 4; ++alpha) {
+ canvas->save();
+ canvas->save();
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); ++i) {
+ if (6 == i) {
+ canvas->restore();
+ canvas->translate(W * 5, 0);
+ canvas->save();
+ }
+ SkXfermode* mode = SkXfermode::Create(gModes[i].fMode);
+
+ canvas->drawRect(bounds, fBGPaint);
+ canvas->saveLayer(&bounds, NULL);
+ SkScalar dy = drawCell(canvas, mode,
+ gAlphaValue[alpha & 1],
+ gAlphaValue[alpha & 2]);
+ canvas->restore();
+
+ canvas->translate(0, dy * 5 / 4);
+ SkSafeUnref(mode);
+ }
+ canvas->restore();
+ canvas->restore();
+ canvas->translate(W * 5 / 4, 0);
+ }
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new HairModesView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleHairline.cpp b/samplecode/SampleHairline.cpp
index 8368f5b..065087e 100644
--- a/samplecode/SampleHairline.cpp
+++ b/samplecode/SampleHairline.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleImage.cpp b/samplecode/SampleImage.cpp
index 2944299..8867baf 100644
--- a/samplecode/SampleImage.cpp
+++ b/samplecode/SampleImage.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleImageDir.cpp b/samplecode/SampleImageDir.cpp
index 8ef59ad..8d6f5e0 100644
--- a/samplecode/SampleImageDir.cpp
+++ b/samplecode/SampleImageDir.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
@@ -29,6 +36,10 @@ static void drawmarshmallow(SkCanvas* canvas) {
SkMatrix m;
SkImageDecoder::DecodeFile("/Users/reed/Downloads/3elfs.jpg", &bitmap);
+ if (!bitmap.pixelRef()) {
+ return;
+ }
+
SkShader* s = SkShader::CreateBitmapShader(bitmap,
SkShader::kRepeat_TileMode,
SkShader::kRepeat_TileMode);
@@ -61,33 +72,33 @@ static void DrawRoundRect(SkCanvas& canvas) {
// set up clipper
SkRect skclip;
- skclip.set(SkIntToFixed(284), SkIntToFixed(40), SkIntToFixed(1370), SkIntToFixed(708));
+ skclip.set(SkIntToScalar(284), SkIntToScalar(40), SkIntToScalar(1370), SkIntToScalar(708));
// ret = canvas.clipRect(skclip);
// SkASSERT(ret);
- matrix.set(SkMatrix::kMTransX, SkFloatToFixed(-1153.28));
- matrix.set(SkMatrix::kMTransY, SkFloatToFixed(1180.50));
+ matrix.set(SkMatrix::kMTransX, SkFloatToScalar(-1153.28f));
+ matrix.set(SkMatrix::kMTransY, SkFloatToScalar(1180.50f));
- matrix.set(SkMatrix::kMScaleX, SkFloatToFixed(0.177171));
- matrix.set(SkMatrix::kMScaleY, SkFloatToFixed(0.177043));
+ matrix.set(SkMatrix::kMScaleX, SkFloatToScalar(0.177171f));
+ matrix.set(SkMatrix::kMScaleY, SkFloatToScalar(0.177043f));
- matrix.set(SkMatrix::kMSkewX, SkFloatToFixed(0.126968));
- matrix.set(SkMatrix::kMSkewY, SkFloatToFixed(-0.126876));
+ matrix.set(SkMatrix::kMSkewX, SkFloatToScalar(0.126968f));
+ matrix.set(SkMatrix::kMSkewY, SkFloatToScalar(-0.126876f));
- matrix.set(SkMatrix::kMPersp0, SkFloatToFixed(0.0));
- matrix.set(SkMatrix::kMPersp1, SkFloatToFixed(0.0));
+ matrix.set(SkMatrix::kMPersp0, SkFloatToScalar(0.0f));
+ matrix.set(SkMatrix::kMPersp1, SkFloatToScalar(0.0f));
ret = canvas.concat(matrix);
paint.setAntiAlias(true);
paint.setColor(0xb2202020);
paint.setStyle(SkPaint::kStroke_Style);
- paint.setStrokeWidth(SkFloatToFixed(68.13));
+ paint.setStrokeWidth(SkFloatToScalar(68.13f));
SkRect r;
- r.set(SkFloatToFixed(-313.714417), SkFloatToFixed(-4.826389), SkFloatToFixed(18014.447266), SkFloatToFixed(1858.154541));
- canvas.drawRoundRect(r, SkFloatToFixed(91.756363), SkFloatToFixed(91.756363), paint);
+ r.set(SkFloatToScalar(-313.714417f), SkFloatToScalar(-4.826389f), SkFloatToScalar(18014.447266f), SkFloatToScalar(1858.154541f));
+ canvas.drawRoundRect(r, SkFloatToScalar(91.756363f), SkFloatToScalar(91.756363f), paint);
}
static bool SetImageRef(SkBitmap* bitmap, SkStream* stream,
diff --git a/samplecode/SampleLCD.cpp b/samplecode/SampleLCD.cpp
index 098958f..5f8cb0b 100644
--- a/samplecode/SampleLCD.cpp
+++ b/samplecode/SampleLCD.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleLayerMask.cpp b/samplecode/SampleLayerMask.cpp
index 9bd00ae..883642c 100644
--- a/samplecode/SampleLayerMask.cpp
+++ b/samplecode/SampleLayerMask.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkCanvas.h"
#include "SkPaint.h"
diff --git a/samplecode/SampleLayers.cpp b/samplecode/SampleLayers.cpp
index 6fc9c83..06fdd3f 100644
--- a/samplecode/SampleLayers.cpp
+++ b/samplecode/SampleLayers.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleLineClipper.cpp b/samplecode/SampleLineClipper.cpp
index ac6b013..8565470 100644
--- a/samplecode/SampleLineClipper.cpp
+++ b/samplecode/SampleLineClipper.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
@@ -146,7 +153,7 @@ enum {
H = 480/3
};
-class LineClipperView : public SkView {
+class LineClipperView : public SampleView {
SkMSec fNow;
int fCounter;
int fProcIndex;
@@ -185,10 +192,6 @@ protected:
return this->INHERITED::onQuery(evt);
}
- void drawBG(SkCanvas* canvas) {
- canvas->drawColor(SK_ColorWHITE);
- }
-
static void drawVLine(SkCanvas* canvas, SkScalar x, const SkPaint& paint) {
canvas->drawLine(x, -999, x, 999, paint);
}
@@ -197,9 +200,7 @@ protected:
canvas->drawLine(-999, y, 999, y, paint);
}
- virtual void onDraw(SkCanvas* canvas) {
- this->drawBG(canvas);
-
+ virtual void onDrawContent(SkCanvas* canvas) {
SkMSec now = SampleCode::GetAnimTime();
if (fNow != now) {
fNow = now;
@@ -229,6 +230,7 @@ protected:
paint1.setColor(SK_ColorRED);
paint1.setStyle(SkPaint::kStroke_Style);
gProcs[fProcIndex](fPts, fClip, canvas, paint, paint1);
+ this->inval(NULL);
}
virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
@@ -245,7 +247,7 @@ protected:
}
private:
- typedef SkView INHERITED;
+ typedef SampleView INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/samplecode/SampleLines.cpp b/samplecode/SampleLines.cpp
index 03dd30f..0048d39 100644
--- a/samplecode/SampleLines.cpp
+++ b/samplecode/SampleLines.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleMeasure.cpp b/samplecode/SampleMeasure.cpp
index 8078e03..35ad5bd 100644
--- a/samplecode/SampleMeasure.cpp
+++ b/samplecode/SampleMeasure.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleMipMap.cpp b/samplecode/SampleMipMap.cpp
index 3d95156..de5aac5 100644
--- a/samplecode/SampleMipMap.cpp
+++ b/samplecode/SampleMipMap.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleMovie.cpp b/samplecode/SampleMovie.cpp
index af34198..17fbc79 100644
--- a/samplecode/SampleMovie.cpp
+++ b/samplecode/SampleMovie.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleNinePatch.cpp b/samplecode/SampleNinePatch.cpp
index e158287..bab7b23 100644
--- a/samplecode/SampleNinePatch.cpp
+++ b/samplecode/SampleNinePatch.cpp
@@ -1,28 +1,58 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
-#include "SkView.h"
#include "SkCanvas.h"
-#include "SkImageDecoder.h"
-#include "SkNinePatch.h"
#include "SkPaint.h"
-#include "SkUnPreMultiply.h"
+#include "SkGpuDevice.h"
+
+static void make_bitmap(SkBitmap* bitmap, GrContext* ctx, SkIRect* center) {
+ SkDevice* dev;
+ SkCanvas canvas;
+
+ const int kFixed = 28;
+ const int kStretchy = 8;
+ const int kSize = 2*kFixed + kStretchy;
+
+ if (ctx) {
+ dev = new SkGpuDevice(ctx, SkBitmap::kARGB_8888_Config, kSize, kSize);
+ *bitmap = dev->accessBitmap(false);
+ } else {
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config, kSize, kSize);
+ bitmap->allocPixels();
+ dev = new SkDevice(*bitmap);
+ }
+
+ canvas.setDevice(dev)->unref();
+ canvas.clear(0);
+
+ SkRect r = SkRect::MakeWH(SkIntToScalar(kSize), SkIntToScalar(kSize));
+ const SkScalar strokeWidth = SkIntToScalar(6);
+ const SkScalar radius = SkIntToScalar(kFixed) - strokeWidth/2;
+
+ center->setXYWH(kFixed, kFixed, kStretchy, kStretchy);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ paint.setColor(0xFFFF0000);
+ canvas.drawRoundRect(r, radius, radius, paint);
+ r.setXYWH(SkIntToScalar(kFixed), 0, SkIntToScalar(kStretchy), SkIntToScalar(kSize));
+ paint.setColor(0x8800FF00);
+ canvas.drawRect(r, paint);
+ r.setXYWH(0, SkIntToScalar(kFixed), SkIntToScalar(kSize), SkIntToScalar(kStretchy));
+ paint.setColor(0x880000FF);
+ canvas.drawRect(r, paint);
+}
+
class NinePatchView : public SampleView {
public:
- SkBitmap fBM;
-
- NinePatchView() {
- SkImageDecoder::DecodeFile("/skimages/btn_default_normal_disable.9.png", &fBM);
-
- // trim off the edge guide-lines
- SkBitmap tmp;
- SkIRect r;
- r.set(1, 1, fBM.width() - 1, fBM.height() - 1);
- fBM.extractSubset(&tmp, r);
- fBM.swap(tmp);
-
- fX = SkIntToScalar(fBM.width());
- fY = 0;
- }
+ NinePatchView() {}
protected:
// overrides from SkEventSink
@@ -33,75 +63,40 @@ protected:
}
return this->INHERITED::onQuery(evt);
}
-
- virtual void onDrawBackground(SkCanvas* canvas) {
- SkPaint p;
- p.setDither(true);
- p.setColor(0xFF909090);
- canvas->drawPaint(p);
- }
- static void test_rects(SkCanvas* canvas, const SkBitmap& bm, const SkPaint* paint) {
- static const SkIRect src[] = {
- { 0, 0, 18, 34 },
- { 18, 0, 19, 34 },
- { 19, 0, 36, 34 },
- { 0, 34, 18, 35 },
- { 18, 34, 19, 35 },
- { 19, 34, 36, 35 },
- { 0, 35, 18, 72 },
- { 18, 35, 19, 72 },
- { 19, 35, 36, 72 },
- };
- static const SkRect dst[] = {
- { 0, 0, 18, 34 },
- { 18, 0, 283, 34 },
- { 283, 0, 300, 34 },
- { 0, 34, 18, 163 },
- { 18, 34, 283, 163 },
- { 283, 34, 300, 163 },
- { 0, 163, 18, 200 },
- { 18, 163, 283, 200 },
- { 283, 163, 300, 200 },
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkBitmap bm;
+ SkIRect center;
+ make_bitmap(&bm, SampleCode::GetGr(), &center);
+
+ // amount of bm that should not be stretched (unless we have to)
+ const SkScalar fixed = SkIntToScalar(bm.width() - center.width());
+
+ const SkTSize<SkScalar> size[] = {
+ { fixed * 4 / 5, fixed * 4 / 5 }, // shrink in both axes
+ { fixed * 4 / 5, fixed * 4 }, // shrink in X
+ { fixed * 4, fixed * 4 / 5 }, // shrink in Y
+ { fixed * 4, fixed * 4 }
};
- for (size_t i = 0; i < SK_ARRAY_COUNT(src); i++) {
- canvas->drawBitmapRect(bm, &src[i], dst[i], paint);
- }
- }
- virtual void onDrawContent(SkCanvas* canvas) {
- canvas->drawBitmap(fBM, 0, 0);
-
- SkIRect margins;
- SkRect dst;
- int d = 25;
-
- margins.set(d, d, d, d);
- margins.fLeft = fBM.width()/2 - 1;
- margins.fTop = fBM.height()/2 - 1;
- margins.fRight = fBM.width() - margins.fLeft - 1;
- margins.fBottom = fBM.height() - margins.fTop - 1;
-
- // canvas->translate(fX/5, fY/5);
- canvas->translate(0, 76);
-
- dst.set(0, 0, SkIntToScalar(200), SkIntToScalar(200));
-
+ canvas->drawBitmap(bm, SkIntToScalar(10), SkIntToScalar(10), NULL);
+
+ SkScalar x = SkIntToScalar(100);
+ SkScalar y = SkIntToScalar(100);
+
SkPaint paint;
- paint.setAntiAlias(false);
- paint.setDither(true);
- paint.setFilterBitmap(false);
- // SkNinePatch::DrawNine(canvas, dst, fBM, margins, &paint);
- test_rects(canvas, fBM, &paint);
+ paint.setFilterBitmap(true);
+
+ for (int iy = 0; iy < 2; ++iy) {
+ for (int ix = 0; ix < 2; ++ix) {
+ int i = ix * 2 + iy;
+ SkRect r = SkRect::MakeXYWH(x + ix * fixed, y + iy * fixed,
+ size[i].width(), size[i].height());
+ canvas->drawBitmapNine(bm, center, r, &paint);
+ }
+ }
}
- virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
- fX = x / 1.5f;
- fY = y / 1.5f;
- fX = x; fY = y;
- this->inval(NULL);
- return this->INHERITED::onFindClickHandler(x, y);
- }
private:
SkScalar fX, fY;
typedef SampleView INHERITED;
diff --git a/samplecode/SampleOvalTest.cpp b/samplecode/SampleOvalTest.cpp
index f625529..dab4fbc 100644
--- a/samplecode/SampleOvalTest.cpp
+++ b/samplecode/SampleOvalTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleOverflow.cpp b/samplecode/SampleOverflow.cpp
index d3ecff7..05b28eb 100644
--- a/samplecode/SampleOverflow.cpp
+++ b/samplecode/SampleOverflow.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SamplePageFlip.cpp b/samplecode/SamplePageFlip.cpp
index 7c5bf48..b2d96f0 100644
--- a/samplecode/SamplePageFlip.cpp
+++ b/samplecode/SamplePageFlip.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
@@ -8,7 +15,7 @@
#include <pthread.h>
-#define WIDTH 200
+#define WIDTH 160
#define HEIGHT 200
static bool gDone;
@@ -49,6 +56,9 @@ static void* draw_proc(void* context) {
SkRect oval;
oval.setEmpty();
+ SkRect clipR = SkRect::MakeWH(SkIntToScalar(bm->width()), SkIntToScalar(bm->height()));
+ clipR.inset(SK_Scalar1/4, SK_Scalar1/4);
+
while (!gDone) {
ref->inval(oval, true);
oval.set(x, y, x + SkIntToScalar(OVALW), y + SkIntToScalar(OVALH));
@@ -60,34 +70,23 @@ static void* draw_proc(void* context) {
// this must be local to the loop, since it needs to forget the pixels
// its writing to after each iteration, since we do the swap
SkCanvas canvas(update.bitmap());
-
-// SkDebugf("----- dirty [%d %d %d %d]\n", dirty.getBounds().fLeft, dirty.getBounds().fTop, dirty.getBounds().width(), dirty.getBounds().height());
canvas.clipRegion(update.dirty());
-
canvas.drawColor(0, SkXfermode::kClear_Mode);
+ canvas.clipRect(clipR, SkRegion::kIntersect_Op, true);
+
canvas.drawOval(oval, paint);
}
bounce(&x, &dx, WIDTH-OVALW);
bounce(&y, &dy, HEIGHT-OVALH);
-
-#if 1
- for (int i = 0; i < 1000; i++) {
- for (int j = 0; j < 10000; j++) {
- SkFixedMul(j, 10);
- }
- }
-#endif
}
return NULL;
}
static const SkBitmap::Config gConfigs[] = {
SkBitmap::kARGB_8888_Config,
-#if 1
SkBitmap::kRGB_565_Config,
SkBitmap::kARGB_4444_Config,
SkBitmap::kA8_Config
-#endif
};
class PageFlipView : public SampleView {
diff --git a/samplecode/SamplePatch.cpp b/samplecode/SamplePatch.cpp
index ea365c7..edc7804 100644
--- a/samplecode/SamplePatch.cpp
+++ b/samplecode/SamplePatch.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SamplePath.cpp b/samplecode/SamplePath.cpp
index cd45ed9..7e2750a 100644
--- a/samplecode/SamplePath.cpp
+++ b/samplecode/SamplePath.cpp
@@ -1,4 +1,11 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SamplePathClip.cpp b/samplecode/SamplePathClip.cpp
index 8139171..5ca39e8 100644
--- a/samplecode/SamplePathClip.cpp
+++ b/samplecode/SamplePathClip.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SamplePathEffects.cpp b/samplecode/SamplePathEffects.cpp
index 75566b0..1317b82 100644
--- a/samplecode/SamplePathEffects.cpp
+++ b/samplecode/SamplePathEffects.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SamplePathFill.cpp b/samplecode/SamplePathFill.cpp
index 845b7a8..bcc00d3 100644
--- a/samplecode/SamplePathFill.cpp
+++ b/samplecode/SamplePathFill.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SamplePicture.cpp b/samplecode/SamplePicture.cpp
index d7b6b22..d2c9d65 100644
--- a/samplecode/SamplePicture.cpp
+++ b/samplecode/SamplePicture.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkDumpCanvas.h"
#include "SkView.h"
@@ -14,7 +21,6 @@
#include "SkUtils.h"
#include "SkColorPriv.h"
#include "SkColorFilter.h"
-#include "SkShape.h"
#include "SkTime.h"
#include "SkTypeface.h"
#include "SkXfermode.h"
@@ -22,67 +28,6 @@
#include "SkStream.h"
#include "SkXMLParser.h"
-class SignalShape : public SkShape {
-public:
- SignalShape() : fSignal(0) {}
-
- SkShape* setSignal(int n) {
- fSignal = n;
- return this;
- }
-
-protected:
- virtual void onDraw(SkCanvas* canvas) {
- // SkDebugf("---- sc %d\n", canvas->getSaveCount() - 1);
- }
-
-private:
- int fSignal;
-};
-
-static SkPMColor SignalProc(SkPMColor src, SkPMColor dst) {
- return dst;
-}
-
-/* Picture playback will skip blocks of draw calls that follow a clip() call
- that returns empty, and jump down to the corresponding restore() call.
-
- This is a great preformance win for drawing very large/tall pictures with
- a small visible window (think scrolling a long document). These tests make
- sure that (a) we are performing the culling, and (b) we don't get confused
- by nested save() calls, nor by calls to restoreToCount().
- */
-static void test_saveRestoreCulling() {
- SkPaint signalPaint;
- SignalShape signalShape;
-
- SkPicture pic;
- SkRect r = SkRect::MakeWH(0, 0);
- int n;
- SkCanvas* canvas = pic.beginRecording(100, 100);
- int startN = canvas->getSaveCount();
- SkDebugf("---- start sc %d\n", startN);
- canvas->drawShape(signalShape.setSignal(1));
- canvas->save();
- canvas->drawShape(signalShape.setSignal(2));
- n = canvas->save();
- canvas->drawShape(signalShape.setSignal(3));
- canvas->save();
- canvas->clipRect(r);
- canvas->drawShape(signalShape.setSignal(4));
- canvas->restoreToCount(n);
- canvas->drawShape(signalShape.setSignal(5));
- canvas->restore();
- canvas->drawShape(signalShape.setSignal(6));
- SkASSERT(canvas->getSaveCount() == startN);
-
- SkBitmap bm;
- bm.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
- bm.allocPixels();
- SkCanvas c(bm);
- c.drawPicture(pic);
-}
-
///////////////////////////////////////////////////////////////////////////////
#include "SkImageRef_GlobalPool.h"
@@ -137,8 +82,6 @@ public:
// unref fPicture in our destructor, and it will in turn take care of
// the other references to fSubPicture
fSubPicture->unref();
-
- test_saveRestoreCulling();
}
virtual ~PictureView() {
@@ -230,7 +173,7 @@ private:
#define INVAL_ALL_TYPE "inval-all"
void delayInval(SkMSec delay) {
- (new SkEvent(INVAL_ALL_TYPE))->post(this->getSinkID(), delay);
+ (new SkEvent(INVAL_ALL_TYPE, this->getSinkID()))->postDelay(delay);
}
virtual bool onEvent(const SkEvent& evt) {
diff --git a/samplecode/SamplePoints.cpp b/samplecode/SamplePoints.cpp
index a2804b4..717cd8c 100644
--- a/samplecode/SamplePoints.cpp
+++ b/samplecode/SamplePoints.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SamplePolyToPoly.cpp b/samplecode/SamplePolyToPoly.cpp
index aea0cb4..dbda4da 100644
--- a/samplecode/SamplePolyToPoly.cpp
+++ b/samplecode/SamplePolyToPoly.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
@@ -56,8 +63,9 @@ public:
{ SkIntToScalar(32), SkIntToScalar(17) }
};
- SkMatrix m0, m1;
+ SkMatrix m0;
m0.setPolyToPoly(src, dst, 3);
+ // SkMatrix m1;
// SkSetPoly3To3(&m1, src, dst);
// m0.dump();
// m1.dump();
diff --git a/samplecode/SampleRegion.cpp b/samplecode/SampleRegion.cpp
index 822bd6f..48153ef 100644
--- a/samplecode/SampleRegion.cpp
+++ b/samplecode/SampleRegion.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleRepeatTile.cpp b/samplecode/SampleRepeatTile.cpp
index 9867074..16a23ad 100644
--- a/samplecode/SampleRepeatTile.cpp
+++ b/samplecode/SampleRepeatTile.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleShaderText.cpp b/samplecode/SampleShaderText.cpp
index 2748b55..bed4835 100644
--- a/samplecode/SampleShaderText.cpp
+++ b/samplecode/SampleShaderText.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
@@ -118,7 +125,7 @@ protected:
virtual void onDrawContent(SkCanvas* canvas) {
const char text[] = "Shaded Text";
const int textLen = SK_ARRAY_COUNT(text) - 1;
- static int pointSize = 48;
+ static int pointSize = 36;
int w = pointSize * textLen;
int h = pointSize;
@@ -166,17 +173,31 @@ protected:
canvas->save();
canvas->translate(SkIntToScalar(20), SkIntToScalar(10));
+ SkPath path;
+ path.arcTo(SkRect::MakeXYWH(SkIntToScalar(-40), SkIntToScalar(15),
+ SkIntToScalar(300), SkIntToScalar(90)),
+ SkIntToScalar(225), SkIntToScalar(90),
+ false);
+ path.close();
+
static const int testsPerCol = 8;
static const int rowHeight = 60;
static const int colWidth = 300;
canvas->save();
for (size_t s = 0; s < SK_ARRAY_COUNT(shaders); s++) {
canvas->save();
- canvas->translate(SkIntToScalar((s / testsPerCol) * colWidth),
- SkIntToScalar((s % testsPerCol) * rowHeight));
+ int i = 2*s;
+ canvas->translate(SkIntToScalar((i / testsPerCol) * colWidth),
+ SkIntToScalar((i % testsPerCol) * rowHeight));
paint.setShader(shaders[s])->unref();
canvas->drawText(text, textLen, 0, textBase, paint);
canvas->restore();
+ canvas->save();
+ ++i;
+ canvas->translate(SkIntToScalar((i / testsPerCol) * colWidth),
+ SkIntToScalar((i % testsPerCol) * rowHeight));
+ canvas->drawTextOnPath(text, textLen, path, NULL, paint);
+ canvas->restore();
}
canvas->restore();
diff --git a/samplecode/SampleShaders.cpp b/samplecode/SampleShaders.cpp
index c1bb0fd..99cd680 100644
--- a/samplecode/SampleShaders.cpp
+++ b/samplecode/SampleShaders.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleShapes.cpp b/samplecode/SampleShapes.cpp
index dc10f1a..5a5bb4c 100644
--- a/samplecode/SampleShapes.cpp
+++ b/samplecode/SampleShapes.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkCanvas.h"
#include "SkPaint.h"
@@ -127,16 +134,14 @@ protected:
matrix.preScale(SK_Scalar1*2, SK_Scalar1*2);
gs->appendShape(&fGroup, matrix);
-#if 0
- canvas->drawShape(gs);
-#else
+#if 1
SkPicture* pict = new SkPicture;
SkCanvas* cv = pict->beginRecording(1000, 1000);
cv->scale(SK_ScalarHalf, SK_ScalarHalf);
- cv->drawShape(gs);
+ gs->draw(cv);
cv->translate(SkIntToScalar(680), SkIntToScalar(480));
cv->scale(-SK_Scalar1, SK_Scalar1);
- cv->drawShape(gs);
+ gs->draw(cv);
pict->endRecording();
drawpicture(canvas, *pict);
diff --git a/samplecode/SampleSkLayer.cpp b/samplecode/SampleSkLayer.cpp
index 11976e9..bff6034 100644
--- a/samplecode/SampleSkLayer.cpp
+++ b/samplecode/SampleSkLayer.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkCanvas.h"
#include "SkPaint.h"
diff --git a/samplecode/SampleSlides.cpp b/samplecode/SampleSlides.cpp
index 3b7d05b..d39cee0 100644
--- a/samplecode/SampleSlides.cpp
+++ b/samplecode/SampleSlides.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
@@ -87,23 +94,18 @@ static void discrete_pe(SkPaint* paint) {
paint->setPathEffect(new SkDiscretePathEffect(10, 4))->unref();
}
-class TilePathEffect : public Sk2DPathEffect {
- static SkMatrix make_mat() {
- SkMatrix m;
- m.setScale(12, 12);
- return m;
- }
-public:
- TilePathEffect() : Sk2DPathEffect(make_mat()) {}
+static SkPathEffect* MakeTileEffect() {
+ SkMatrix m;
+ m.setScale(SkIntToScalar(12), SkIntToScalar(12));
-protected:
- virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) {
- dst->addCircle(loc.fX, loc.fY, 5);
- }
-};
+ SkPath path;
+ path.addCircle(0, 0, SkIntToScalar(5));
+
+ return new SkPath2DPathEffect(m, path);
+}
static void tile_pe(SkPaint* paint) {
- paint->setPathEffect(new TilePathEffect)->unref();
+ paint->setPathEffect(MakeTileEffect())->unref();
}
static const PE_Proc gPE2[] = { fill_pe, discrete_pe, tile_pe };
@@ -312,7 +314,6 @@ static void textonpath_slide(SkCanvas* canvas) {
#include "SkOSFile.h"
#include "SkRandom.h"
#include "SkStream.h"
-#include "SkNinePatch.h"
static SkShader* make_shader0(SkIPoint* size) {
SkBitmap bm;
@@ -563,46 +564,18 @@ static void r6(SkLayerRasterizer* rast, SkPaint& p)
#include "Sk2DPathEffect.h"
-class Dot2DPathEffect : public Sk2DPathEffect {
-public:
- Dot2DPathEffect(SkScalar radius, const SkMatrix& matrix)
- : Sk2DPathEffect(matrix), fRadius(radius) {}
-
- virtual void flatten(SkFlattenableWriteBuffer& buffer)
- {
- this->INHERITED::flatten(buffer);
-
- buffer.writeScalar(fRadius);
- }
- virtual Factory getFactory() { return CreateProc; }
-
-protected:
- virtual void next(const SkPoint& loc, int u, int v, SkPath* dst)
- {
- dst->addCircle(loc.fX, loc.fY, fRadius);
- }
-
- Dot2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer)
- {
- fRadius = buffer.readScalar();
- }
-private:
- SkScalar fRadius;
-
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer)
- {
- return new Dot2DPathEffect(buffer);
- }
-
- typedef Sk2DPathEffect INHERITED;
-};
+static SkPathEffect* MakeDotEffect(SkScalar radius, const SkMatrix& matrix) {
+ SkPath path;
+ path.addCircle(0, 0, radius);
+ return new SkPath2DPathEffect(matrix, path);
+}
static void r7(SkLayerRasterizer* rast, SkPaint& p)
{
SkMatrix lattice;
lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
- p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*4, lattice))->unref();
+ p.setPathEffect(MakeDotEffect(SK_Scalar1*4, lattice))->unref();
rast->addLayer(p);
}
@@ -613,7 +586,7 @@ static void r8(SkLayerRasterizer* rast, SkPaint& p)
SkMatrix lattice;
lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
- p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*2, lattice))->unref();
+ p.setPathEffect(MakeDotEffect(SK_Scalar1*2, lattice))->unref();
p.setXfermodeMode(SkXfermode::kClear_Mode);
rast->addLayer(p);
diff --git a/samplecode/SampleSpiral.cpp b/samplecode/SampleSpiral.cpp
index 1a41440..89810fa 100644
--- a/samplecode/SampleSpiral.cpp
+++ b/samplecode/SampleSpiral.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleStrokePath.cpp b/samplecode/SampleStrokePath.cpp
index ae630ef..1fb5fea 100644
--- a/samplecode/SampleStrokePath.cpp
+++ b/samplecode/SampleStrokePath.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkCanvas.h"
#include "SkParsePath.h"
diff --git a/samplecode/SampleStrokeRect.cpp b/samplecode/SampleStrokeRect.cpp
index 20c9e2c..e9d3c2e 100644
--- a/samplecode/SampleStrokeRect.cpp
+++ b/samplecode/SampleStrokeRect.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleStrokeText.cpp b/samplecode/SampleStrokeText.cpp
index bcb9e4f..f90dc55 100644
--- a/samplecode/SampleStrokeText.cpp
+++ b/samplecode/SampleStrokeText.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleTests.cpp b/samplecode/SampleTests.cpp
index 4ce8640..5542bf6 100644
--- a/samplecode/SampleTests.cpp
+++ b/samplecode/SampleTests.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
utils#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleText.cpp b/samplecode/SampleText.cpp
index 2676530..6a0eba8 100644
--- a/samplecode/SampleText.cpp
+++ b/samplecode/SampleText.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleTextAlpha.cpp b/samplecode/SampleTextAlpha.cpp
index ccfed68..09134c4 100644
--- a/samplecode/SampleTextAlpha.cpp
+++ b/samplecode/SampleTextAlpha.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkBlurMaskFilter.h"
diff --git a/samplecode/SampleTextBox.cpp b/samplecode/SampleTextBox.cpp
index 37a6be0..5f37380 100644
--- a/samplecode/SampleTextBox.cpp
+++ b/samplecode/SampleTextBox.cpp
@@ -1,7 +1,15 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkBlurMaskFilter.h"
#include "SkCanvas.h"
+#include "SkColorShader.h"
#include "SkGradientShader.h"
#include "SkGraphics.h"
#include "SkImageDecoder.h"
@@ -20,6 +28,8 @@
#include "SkStream.h"
#include "SkKey.h"
+extern void skia_set_text_gamma(float blackGamma, float whiteGamma);
+
#ifdef SK_BUILD_FOR_WIN
extern SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT&);
#endif
@@ -47,7 +57,7 @@ public:
tf0->unref();
tf1->unref();
#endif
- }
+ }
protected:
// overrides from SkEventSink
@@ -60,17 +70,22 @@ protected:
return this->INHERITED::onQuery(evt);
}
- virtual void onDrawContent(SkCanvas* canvas) {
+ void drawTest(SkCanvas* canvas, SkScalar w, SkScalar h, SkColor fg, SkColor bg) {
+ SkAutoCanvasRestore acr(canvas, true);
+
+ canvas->clipRect(SkRect::MakeWH(w, h));
+ canvas->drawColor(bg);
SkScalar margin = 20;
SkTextBox tbox;
tbox.setMode(SkTextBox::kLineBreak_Mode);
tbox.setBox(margin, margin,
- this->width() - margin, this->height() - margin);
+ w - margin, h - margin);
tbox.setSpacing(SkIntToScalar(3)/3, 0);
SkPaint paint;
paint.setAntiAlias(true);
paint.setLCDRenderText(true);
+ paint.setColor(fg);
tbox.setText(gText, strlen(gText), paint);
for (int i = 9; i < 24; i += 2) {
@@ -80,8 +95,19 @@ protected:
}
}
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkScalar width = this->width() / 3;
+ drawTest(canvas, width, this->height(), SK_ColorBLACK, SK_ColorWHITE);
+ canvas->translate(width, 0);
+ drawTest(canvas, width, this->height(), SK_ColorWHITE, SK_ColorBLACK);
+ canvas->translate(width, 0);
+ drawTest(canvas, width, this->height()/2, SK_ColorGRAY, SK_ColorWHITE);
+ canvas->translate(0, this->height()/2);
+ drawTest(canvas, width, this->height()/2, SK_ColorGRAY, SK_ColorBLACK);
+ }
+
private:
- typedef SkView INHERITED;
+ typedef SampleView INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
diff --git a/samplecode/SampleTextEffects.cpp b/samplecode/SampleTextEffects.cpp
index f256b2e..6eadffd 100644
--- a/samplecode/SampleTextEffects.cpp
+++ b/samplecode/SampleTextEffects.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
@@ -138,41 +145,17 @@ static void r6(SkLayerRasterizer* rast, SkPaint& p) {
#include "Sk2DPathEffect.h"
-class Dot2DPathEffect : public Sk2DPathEffect {
-public:
- Dot2DPathEffect(SkScalar radius, const SkMatrix& matrix)
- : Sk2DPathEffect(matrix), fRadius(radius) {}
-
- virtual void flatten(SkFlattenableWriteBuffer& buffer) {
- this->INHERITED::flatten(buffer);
-
- buffer.writeScalar(fRadius);
- }
- virtual Factory getFactory() { return CreateProc; }
-
-protected:
- virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) {
- dst->addCircle(loc.fX, loc.fY, fRadius);
- }
-
- Dot2DPathEffect(SkFlattenableReadBuffer& buffer) : Sk2DPathEffect(buffer) {
- fRadius = buffer.readScalar();
- }
-private:
- SkScalar fRadius;
-
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
- return new Dot2DPathEffect(buffer);
- }
-
- typedef Sk2DPathEffect INHERITED;
-};
+static SkPathEffect* MakeDotEffect(SkScalar radius, const SkMatrix& matrix) {
+ SkPath path;
+ path.addCircle(0, 0, radius);
+ return new SkPath2DPathEffect(matrix, path);
+}
static void r7(SkLayerRasterizer* rast, SkPaint& p) {
SkMatrix lattice;
lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
- p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*4, lattice))->unref();
+ p.setPathEffect(MakeDotEffect(SK_Scalar1*4, lattice))->unref();
rast->addLayer(p);
}
@@ -182,7 +165,7 @@ static void r8(SkLayerRasterizer* rast, SkPaint& p) {
SkMatrix lattice;
lattice.setScale(SK_Scalar1*6, SK_Scalar1*6, 0, 0);
lattice.postSkew(SK_Scalar1/3, 0, 0, 0);
- p.setPathEffect(new Dot2DPathEffect(SK_Scalar1*2, lattice))->unref();
+ p.setPathEffect(MakeDotEffect(SK_Scalar1*2, lattice))->unref();
p.setXfermodeMode(SkXfermode::kClear_Mode);
rast->addLayer(p);
diff --git a/samplecode/SampleTextOnPath.cpp b/samplecode/SampleTextOnPath.cpp
index 96e8c9a..f3c98f8 100644
--- a/samplecode/SampleTextOnPath.cpp
+++ b/samplecode/SampleTextOnPath.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleTextureDomain.cpp b/samplecode/SampleTextureDomain.cpp
index be000f9..4291468 100755
--- a/samplecode/SampleTextureDomain.cpp
+++ b/samplecode/SampleTextureDomain.cpp
@@ -1,6 +1,14 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkCanvas.h"
#include "SkDevice.h"
+#include "SkBlurMaskFilter.h"
namespace {
SkBitmap make_bitmap() {
@@ -31,7 +39,7 @@ protected:
// overrides from SkEventSink
virtual bool onQuery(SkEvent* evt) {
if (SampleCode::TitleQ(*evt)) {
- SampleCode::TitleR(evt, "Texture Domian");
+ SampleCode::TitleR(evt, "Texture Domain");
return true;
}
return this->INHERITED::onQuery(evt);
@@ -54,8 +62,8 @@ protected:
// Note: GPU-backed bitmaps follow a different rendering path
// when copying from one GPU device to another.
SkRefPtr<SkDevice> primaryDevice(canvas->getDevice());
- SkRefPtr<SkDevice> secondDevice(canvas->createDevice(
- SkBitmap::kARGB_8888_Config, 5, 5, true, true));
+ SkRefPtr<SkDevice> secondDevice(canvas->createCompatibleDevice(
+ SkBitmap::kARGB_8888_Config, 5, 5, true));
secondDevice->unref();
SkCanvas secondCanvas(secondDevice.get());
@@ -68,6 +76,34 @@ protected:
srcRect.setXYWH(1, 1, 3, 3);
dstRect.setXYWH(405.0f, 5.0f, 305.0f, 305.0f);
canvas->drawBitmapRect(deviceBitmap, &srcRect, dstRect, &paint);
+
+ // Test that bitmap blurring using a subrect
+ // renders correctly
+ srcRect.setXYWH(1, 1, 3, 3);
+ dstRect.setXYWH(5.0f, 405.0f, 305.0f, 305.0f);
+ SkMaskFilter* mf = SkBlurMaskFilter::Create(
+ 5,
+ SkBlurMaskFilter::kNormal_BlurStyle,
+ SkBlurMaskFilter::kHighQuality_BlurFlag |
+ SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
+ paint.setMaskFilter(mf)->unref();
+ canvas->drawBitmapRect(deviceBitmap, &srcRect, dstRect, &paint);
+
+ // Blur and a rotation + NULL src rect
+ // This should not trigger the texture domain code
+ // but it will test a code path in SkGpuDevice::drawBitmap
+ // that handles blurs with rects transformed to non-
+ // orthogonal rects. It also tests the NULL src rect handling
+ mf = SkBlurMaskFilter::Create(
+ 5,
+ SkBlurMaskFilter::kNormal_BlurStyle,
+ SkBlurMaskFilter::kHighQuality_BlurFlag);
+ paint.setMaskFilter(mf)->unref();
+
+ dstRect.setXYWH(-150.0f, -150.0f, 300.0f, 300.0f);
+ canvas->translate(550, 550);
+ canvas->rotate(45);
+ canvas->drawBitmapRect(fBM, NULL, dstRect, &paint);
}
private:
typedef SkView INHERITED;
diff --git a/samplecode/SampleTiling.cpp b/samplecode/SampleTiling.cpp
index 4752ed1..d72544b 100644
--- a/samplecode/SampleTiling.cpp
+++ b/samplecode/SampleTiling.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
@@ -56,17 +63,22 @@ static const int gWidth = 32;
static const int gHeight = 32;
class TilingView : public SampleView {
- SkPicture fTextPicture;
+ SkPicture* fTextPicture;
SkBlurDrawLooper fLooper;
public:
TilingView()
: fLooper(SkIntToScalar(1), SkIntToScalar(2), SkIntToScalar(2),
0x88000000) {
+ fTextPicture = new SkPicture();
for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); i++) {
makebm(&fTexture[i], gConfigs[i], gWidth, gHeight);
}
}
+ ~TilingView() {
+ fTextPicture->unref();
+ }
+
SkBitmap fTexture[SK_ARRAY_COUNT(gConfigs)];
protected:
@@ -94,8 +106,8 @@ protected:
SkScalar x = SkIntToScalar(10);
SkCanvas* textCanvas = NULL;
- if (fTextPicture.width() == 0) {
- textCanvas = fTextPicture.beginRecording(1000, 1000);
+ if (fTextPicture->width() == 0) {
+ textCanvas = fTextPicture->beginRecording(1000, 1000);
}
if (textCanvas) {
@@ -148,7 +160,7 @@ protected:
}
}
- canvas->drawPicture(fTextPicture);
+ canvas->drawPicture(*fTextPicture);
}
private:
diff --git a/samplecode/SampleTinyBitmap.cpp b/samplecode/SampleTinyBitmap.cpp
index 0841474..605d829 100644
--- a/samplecode/SampleTinyBitmap.cpp
+++ b/samplecode/SampleTinyBitmap.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkColorPriv.h"
#include "SkShader.h"
diff --git a/samplecode/SampleTriangles.cpp b/samplecode/SampleTriangles.cpp
index be9da8f..e2ba652 100644
--- a/samplecode/SampleTriangles.cpp
+++ b/samplecode/SampleTriangles.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleTypeface.cpp b/samplecode/SampleTypeface.cpp
index 63f1d5a..ccdb086 100644
--- a/samplecode/SampleTypeface.cpp
+++ b/samplecode/SampleTypeface.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleUnitMapper.cpp b/samplecode/SampleUnitMapper.cpp
index b20aece..d323ecb 100644
--- a/samplecode/SampleUnitMapper.cpp
+++ b/samplecode/SampleUnitMapper.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleVertices.cpp b/samplecode/SampleVertices.cpp
index 74e757f..b59442d 100644
--- a/samplecode/SampleVertices.cpp
+++ b/samplecode/SampleVertices.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
@@ -17,7 +24,6 @@
#include "SkOSFile.h"
#include "SkStream.h"
-#include "SkNinePatch.h"
static SkShader* make_shader0(SkIPoint* size) {
SkBitmap bm;
diff --git a/samplecode/SampleWarp.cpp b/samplecode/SampleWarp.cpp
index bf4ef0d..b421c60 100644
--- a/samplecode/SampleWarp.cpp
+++ b/samplecode/SampleWarp.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleWritePixels.cpp b/samplecode/SampleWritePixels.cpp
new file mode 100644
index 0000000..45e9f41
--- /dev/null
+++ b/samplecode/SampleWritePixels.cpp
@@ -0,0 +1,70 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkCornerPathEffect.h"
+#include "SkCullPoints.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+
+static void create_bitmap(SkBitmap* bitmap) {
+ const int W = 100;
+ const int H = 100;
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config, W, H);
+ bitmap->allocPixels();
+
+ SkCanvas canvas(*bitmap);
+ canvas.drawColor(SK_ColorRED);
+ SkPaint paint;
+ paint.setColor(SK_ColorBLUE);
+ canvas.drawCircle(SkIntToScalar(W)/2, SkIntToScalar(H)/2, SkIntToScalar(W)/2, paint);
+}
+
+class WritePixelsView : public SampleView {
+ SkPath fPath;
+public:
+ WritePixelsView() {}
+
+protected:
+ // overrides from SkEventSink
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "WritePixels");
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+
+ virtual void onDrawContent(SkCanvas* canvas) {
+ SkBitmap bitmap;
+ create_bitmap(&bitmap);
+ int x = bitmap.width() / 2;
+ int y = bitmap.height() / 2;
+
+ SkBitmap subset;
+ bitmap.extractSubset(&subset, SkIRect::MakeXYWH(x, y, x, y));
+
+ canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
+
+ canvas->writePixels(bitmap, 0, 0);
+ canvas->writePixels(subset, 0, 0);
+ }
+
+private:
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new WritePixelsView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/samplecode/SampleXfermodes.cpp b/samplecode/SampleXfermodes.cpp
index 0a3c4c7..ffea954 100644
--- a/samplecode/SampleXfermodes.cpp
+++ b/samplecode/SampleXfermodes.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
diff --git a/samplecode/SampleXfermodesBlur.cpp b/samplecode/SampleXfermodesBlur.cpp
index 166e4e5..11b1268 100644
--- a/samplecode/SampleXfermodesBlur.cpp
+++ b/samplecode/SampleXfermodesBlur.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
@@ -24,6 +31,11 @@
#include "SkImageDecoder.h"
#include "SkBlurMaskFilter.h"
+#ifdef SK_BUILD_FOR_MAC
+#import <ApplicationServices/ApplicationServices.h>
+SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef fontRef);
+#endif
+
static void setNamedTypeface(SkPaint* paint, const char name[]) {
SkTypeface* face = SkTypeface::CreateFromName(name, SkTypeface::kNormal);
paint->setTypeface(face);
@@ -61,12 +73,32 @@ class XfermodesBlurView : public SampleView {
r.set(ww/3, hh/3, ww*19/20, hh*19/20);
r.offset(x, y);
canvas->drawRect(r, p);
+
+#ifdef SK_BUILD_FOR_MAC
+ static const char* gNames[] = { "Arial", "Times", "Courier", "Lucida" };
+ for (int j = 0; j < SK_ARRAY_COUNT(gNames); ++j) {
+ CFStringRef name = CFStringCreateWithCString(NULL, gNames[j], kCFStringEncodingUTF8);
+ CTFontRef font = CTFontCreateWithName(name, 0, NULL);
+ SkTypeface* face = SkCreateTypefaceFromCTFont(font);
+ SkDebugf("%s ct:%p face:%p ats:%p\n", gNames[j], font, face, CTFontGetPlatformFont(font, NULL));
+ for (int i = 9; i <= 24; ++i) {
+ CTFontRef newFont = CTFontCreateCopyWithAttributes(font, i, NULL, NULL);
+ SkTypeface* newFace = SkCreateTypefaceFromCTFont(newFont);
+ SkDebugf("size:%d ct:%p face:%p ats:%p\n", i, newFont, newFace, CTFontGetPlatformFont(newFont, NULL));
+ newFace->unref();
+ CFRelease(newFont);
+ }
+ face->unref();
+ CFRelease(font);
+ CFRelease(name);
+ }
+#endif
}
public:
const static int W = 64;
const static int H = 64;
- XfermodesBlurView() {
+ XfermodesBlurView() {
const int W = 64;
const int H = 64;
@@ -88,6 +120,30 @@ protected:
virtual void onDrawContent(SkCanvas* canvas) {
canvas->translate(SkIntToScalar(10), SkIntToScalar(20));
+ if (false) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setTextSize(50);
+ paint.setTypeface(SkTypeface::CreateFromName("Arial Unicode MS", SkTypeface::kNormal));
+ SkSafeUnref(paint.getTypeface());
+ char buffer[10];
+ size_t len = SkUTF8_FromUnichar(0x8500, buffer);
+ canvas->drawText(buffer, len, 40, 40, paint);
+ return;
+ }
+ if (false) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ SkRect r0 = { 0, 0, 10.5f, 20 };
+ SkRect r1 = { 10.5f, 10, 20, 30 };
+ paint.setColor(SK_ColorRED);
+ canvas->drawRect(r0, paint);
+ paint.setColor(SK_ColorBLUE);
+ canvas->drawRect(r1, paint);
+ return;
+ }
+
const struct {
SkXfermode::Mode fMode;
const char* fLabel;
diff --git a/samplecode/TransitionView.cpp b/samplecode/TransitionView.cpp
new file mode 100644
index 0000000..99d1275
--- /dev/null
+++ b/samplecode/TransitionView.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkTime.h"
+#include "SkInterpolator.h"
+
+extern bool is_overview(SkView* view);
+
+static const char gIsTransitionQuery[] = "is-transition";
+static const char gReplaceTransitionEvt[] = "replace-transition-view";
+
+bool is_transition(SkView* view) {
+ SkEvent isTransition(gIsTransitionQuery);
+ return view->doQuery(&isTransition);
+}
+
+class TransitionView : public SampleView {
+public:
+ TransitionView(SkView* prev, SkView* next, int direction) : fInterp(4, 2){
+ fAnimationDirection = (Direction)(1 << (direction % 8));
+
+ fPrev = prev;
+ fPrev->setClipToBounds(false);
+ fPrev->setVisibleP(true);
+ (void)SampleView::SetUsePipe(fPrev, false);
+ //Not calling unref because fPrev is assumed to have been created, so
+ //this will result in a transfer of ownership
+ this->attachChildToBack(fPrev);
+
+ fNext = next;
+ fNext->setClipToBounds(true);
+ fNext->setVisibleP(true);
+ (void)SampleView::SetUsePipe(fNext, false);
+ //Calling unref because next is a newly created view and TransitionView
+ //is now the sole owner of fNext
+ this->attachChildToFront(fNext)->unref();
+
+ fDone = false;
+ //SkDebugf("--created transition\n");
+ }
+
+ ~TransitionView(){
+ //SkDebugf("--deleted transition\n");
+ }
+
+ virtual void requestMenu(SkOSMenu* menu) {
+ if (SampleView::IsSampleView(fNext))
+ ((SampleView*)fNext)->requestMenu(menu);
+ }
+
+protected:
+ virtual bool onQuery(SkEvent* evt) {
+ if (SampleCode::TitleQ(*evt)) {
+ SkString title;
+ if (SampleCode::RequestTitle(fNext, &title)) {
+ SampleCode::TitleR(evt, title.c_str());
+ return true;
+ }
+ return false;
+ }
+ if (evt->isType(gIsTransitionQuery)) {
+ return true;
+ }
+ return this->INHERITED::onQuery(evt);
+ }
+ virtual bool onEvent(const SkEvent& evt) {
+ if (evt.isType(gReplaceTransitionEvt)) {
+ fPrev->detachFromParent();
+ fPrev = (SkView*)SkEventSink::FindSink(evt.getFast32());
+ (void)SampleView::SetUsePipe(fPrev, false);
+ //attach the new fPrev and call unref to balance the ref in onDraw
+ this->attachChildToBack(fPrev)->unref();
+ this->inval(NULL);
+ return true;
+ }
+ if (evt.isType("transition-done")) {
+ fNext->setLoc(0, 0);
+ fNext->setClipToBounds(false);
+ SkEvent* evt = new SkEvent(gReplaceTransitionEvt,
+ this->getParent()->getSinkID());
+ evt->setFast32(fNext->getSinkID());
+ //increate ref count of fNext so it survives detachAllChildren
+ fNext->ref();
+ this->detachAllChildren();
+ evt->post();
+ return true;
+ }
+ return this->INHERITED::onEvent(evt);
+ }
+ virtual void onDrawBackground(SkCanvas* canvas) {}
+ virtual void onDrawContent(SkCanvas* canvas) {
+ if (fDone)
+ return;
+
+ if (is_overview(fNext) || is_overview(fPrev)) {
+ fUsePipe = false;
+ }
+
+ SkScalar values[4];
+ SkInterpolator::Result result = fInterp.timeToValues(SkTime::GetMSecs(), values);
+ //SkDebugf("transition %x %d pipe:%d\n", this, result, fUsePipe);
+ //SkDebugf("%f %f %f %f %d\n", values[0], values[1], values[2], values[3], result);
+ if (SkInterpolator::kNormal_Result == result) {
+ fPrev->setLocX(values[kPrevX]);
+ fPrev->setLocY(values[kPrevY]);
+ fNext->setLocX(values[kNextX]);
+ fNext->setLocY(values[kNextY]);
+ this->inval(NULL);
+ }
+ else {
+ (new SkEvent("transition-done", this->getSinkID()))->post();
+ fDone = true;
+ }
+ }
+
+ virtual void onSizeChange() {
+ this->INHERITED::onSizeChange();
+
+ fNext->setSize(this->width(), this->height());
+ fPrev->setSize(this->width(), this->height());
+
+ SkScalar lr = 0, ud = 0;
+ if (fAnimationDirection & (kLeftDirection|kULDirection|kDLDirection))
+ lr = this->width();
+ if (fAnimationDirection & (kRightDirection|kURDirection|kDRDirection))
+ lr = -this->width();
+ if (fAnimationDirection & (kUpDirection|kULDirection|kURDirection))
+ ud = this->height();
+ if (fAnimationDirection & (kDownDirection|kDLDirection|kDRDirection))
+ ud = -this->height();
+
+ fBegin[kPrevX] = fBegin[kPrevY] = 0;
+ fBegin[kNextX] = lr;
+ fBegin[kNextY] = ud;
+ fNext->setLocX(lr);
+ fNext->setLocY(ud);
+
+ if (is_transition(fPrev))
+ lr = ud = 0;
+ fEnd[kPrevX] = -lr;
+ fEnd[kPrevY] = -ud;
+ fEnd[kNextX] = fEnd[kNextY] = 0;
+ SkScalar blend[] = {0.8, 0.0, 0.0, 1.0};
+ fInterp.setKeyFrame(0, SkTime::GetMSecs(), fBegin, blend);
+ fInterp.setKeyFrame(1, SkTime::GetMSecs()+500, fEnd, blend);
+ }
+
+private:
+ enum {
+ kPrevX = 0,
+ kPrevY = 1,
+ kNextX = 2,
+ kNextY = 3
+ };
+ SkView* fPrev;
+ SkView* fNext;
+ bool fDone;
+ SkInterpolator fInterp;
+
+ enum Direction{
+ kUpDirection = 1,
+ kURDirection = 1 << 1,
+ kRightDirection = 1 << 2,
+ kDRDirection = 1 << 3,
+ kDownDirection = 1 << 4,
+ kDLDirection = 1 << 5,
+ kLeftDirection = 1 << 6,
+ kULDirection = 1 << 7
+ };
+
+ Direction fAnimationDirection;
+ SkScalar fBegin[4];
+ SkScalar fEnd[4];
+
+ typedef SampleView INHERITED;
+};
+
+SkView* create_transition(SkView* prev, SkView* next, int direction) {
+ return SkNEW_ARGS(TransitionView, (prev, next, direction));
+}; \ No newline at end of file
diff --git a/samplecode/samplecode_files.mk b/samplecode/samplecode_files.mk
index 4c660e5..cb757de 100644
--- a/samplecode/samplecode_files.mk
+++ b/samplecode/samplecode_files.mk
@@ -56,8 +56,6 @@ SOURCE := \
OverView.cpp \
SampleFuzz.cpp \
SampleShaders.cpp \
- SampleText.cpp \
- SampleTextBox.cpp \
SampleImage.cpp \
SampleMovie.cpp \
SampleImageDir.cpp \
diff --git a/samplecode/vertexdump.cpp b/samplecode/vertexdump.cpp
index c124ad8..ae310a5 100644
--- a/samplecode/vertexdump.cpp
+++ b/samplecode/vertexdump.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkPoint.h"
void setup_vertexbug(SkPoint verts[], SkPoint texs[], uint16_t index[]);
diff --git a/src/animator/SkAnimate.h b/src/animator/SkAnimate.h
index a4281d3..b7018b9 100644
--- a/src/animator/SkAnimate.h
+++ b/src/animator/SkAnimate.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkAnimate.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkAnimate_DEFINED
#define SkAnimate_DEFINED
diff --git a/src/animator/SkAnimateActive.cpp b/src/animator/SkAnimateActive.cpp
index 4ee7ded..4177aa0 100644
--- a/src/animator/SkAnimateActive.cpp
+++ b/src/animator/SkAnimateActive.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkAnimateActive.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkAnimateActive.h"
#include "SkAnimateBase.h"
@@ -150,9 +142,12 @@ 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)
+ switch (state.fMode) {
+ case SkApply::kMode_immediate:
+ case SkApply::kMode_create:
duration = state.fSteps ? state.fSteps * SK_MSec1 : 1;
-// else if (state.fMode == SkApply::kMode_hold) {
+ break;
+// case SkApply::kMode_hold: {
// int entries = animate->entries();
// SkScriptValue value;
// value.fOperand = animate->getValues()[entries - 1];
@@ -160,7 +155,9 @@ void SkActive::calcDurations(int index)
// bool result = SkScriptEngine::ConvertTo(NULL, SkType_Int, &value);
// SkASSERT(result);
// duration = value.fOperand.fS32 * SK_MSec1;
-// }
+// break;
+// }
+ }
state.fDuration = duration;
SkMSec maxTime = state.fBegin + duration;
if (fMaxTime < maxTime)
diff --git a/src/animator/SkAnimateActive.h b/src/animator/SkAnimateActive.h
index b0c4483..33d0164 100644
--- a/src/animator/SkAnimateActive.h
+++ b/src/animator/SkAnimateActive.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkAnimateActive.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkAnimateActive_DEFINED
#define SkAnimateActive_DEFINED
diff --git a/src/animator/SkAnimateBase.cpp b/src/animator/SkAnimateBase.cpp
index 10a3b5b..2c9e862 100644
--- a/src/animator/SkAnimateBase.cpp
+++ b/src/animator/SkAnimateBase.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkAnimateBase.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkAnimateBase.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkAnimateBase.h b/src/animator/SkAnimateBase.h
index 64b9722..df8d38a 100644
--- a/src/animator/SkAnimateBase.h
+++ b/src/animator/SkAnimateBase.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkAnimateBase.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkAnimateBase_DEFINED
#define SkAnimateBase_DEFINED
diff --git a/src/animator/SkAnimateField.cpp b/src/animator/SkAnimateField.cpp
index f1439a2..ac96bbc 100644
--- a/src/animator/SkAnimateField.cpp
+++ b/src/animator/SkAnimateField.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkAnimateField.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkAnimate.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkAnimateMaker.cpp b/src/animator/SkAnimateMaker.cpp
index 8a78678..414e728 100644
--- a/src/animator/SkAnimateMaker.cpp
+++ b/src/animator/SkAnimateMaker.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkAnimateMaker.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkAnimateMaker.h"
#include "SkAnimator.h"
@@ -129,9 +121,11 @@ extern "C" {
void SkAnimateMaker::delayEnable(SkApply* apply, SkMSec time) {
int index = fDelayed.find(apply);
- if (index < 0)
+ if (index < 0) {
*fDelayed.append() = apply;
- (new SkEvent(SK_EventType_Delay))->postTime(fAnimator->getSinkID(), time);
+ }
+
+ (new SkEvent(SK_EventType_Delay, fAnimator->getSinkID()))->postTime(time);
}
void SkAnimateMaker::deleteMembers() {
diff --git a/src/animator/SkAnimateMaker.h b/src/animator/SkAnimateMaker.h
index dae8caf..f20a7d4 100644
--- a/src/animator/SkAnimateMaker.h
+++ b/src/animator/SkAnimateMaker.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkAnimateMaker.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkAnimateMaker_DEFINED
#define SkAnimateMaker_DEFINED
diff --git a/src/animator/SkAnimateProperties.h b/src/animator/SkAnimateProperties.h
index 9e3da9a..b070640 100644
--- a/src/animator/SkAnimateProperties.h
+++ b/src/animator/SkAnimateProperties.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkAnimateProperties.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkAnimateProperties_DEFINED
#define SkAnimateProperties_DEFINED
diff --git a/src/animator/SkAnimateSet.cpp b/src/animator/SkAnimateSet.cpp
index dd636da..d0b4dfc 100644
--- a/src/animator/SkAnimateSet.cpp
+++ b/src/animator/SkAnimateSet.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkAnimateSet.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkAnimateSet.h"
#include "SkAnimateMaker.h"
@@ -86,8 +78,9 @@ void SkSet::onEndElement(SkAnimateMaker& maker) {
SkASSERT(fValues.getType() == outType);
if (fFieldInfo->fType == SkType_Array)
comps = fValues.count();
- else
+ else {
SkASSERT(fValues.count() == comps);
+ }
}
if (formula.size() > 0) {
comps = 1;
diff --git a/src/animator/SkAnimateSet.h b/src/animator/SkAnimateSet.h
index 9f9ecfb..c735a08 100644
--- a/src/animator/SkAnimateSet.h
+++ b/src/animator/SkAnimateSet.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkAnimateSet.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkAnimateSet_DEFINED
#define SkAnimateSet_DEFINED
diff --git a/src/animator/SkAnimator.cpp b/src/animator/SkAnimator.cpp
index 830f453..c1fba65 100644
--- a/src/animator/SkAnimator.cpp
+++ b/src/animator/SkAnimator.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkAnimator.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkAnimator.h"
#include "SkAnimateMaker.h"
@@ -27,7 +19,7 @@
#include "SkScript2.h" // compiled script experiment
#include "SkSystemEventTypes.h"
#include "SkTypedArray.h"
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
#include "SkDrawExtraPathEffect.h"
#endif
#ifdef SK_DEBUG
@@ -395,7 +387,7 @@ void SkAnimator::initialize() {
SkDELETE(fMaker);
fMaker = SkNEW_ARGS(SkAnimateMaker, (this, NULL, NULL));
decodeMemory(gMathPrimer, sizeof(gMathPrimer)-1);
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
InitializeSkExtraPathEffects(this);
#endif
}
@@ -487,7 +479,7 @@ void SkAnimator::onEventPost(SkEvent* evt, SkEventSinkID sinkID)
#else
SkASSERT(sinkID == this->getSinkID() || this->getHostEventSinkID() == sinkID);
#endif
- SkEvent::Post(evt, sinkID);
+ evt->setTargetID(sinkID)->post();
}
void SkAnimator::onEventPostTime(SkEvent* evt, SkEventSinkID sinkID, SkMSec time)
@@ -501,7 +493,7 @@ void SkAnimator::onEventPostTime(SkEvent* evt, SkEventSinkID sinkID, SkMSec time
#else
SkASSERT(sinkID == this->getSinkID() || this->getHostEventSinkID() == sinkID);
#endif
- SkEvent::PostTime(evt, sinkID, time);
+ evt->setTargetID(sinkID)->postTime(time);
}
void SkAnimator::reset() {
diff --git a/src/animator/SkAnimatorScript.cpp b/src/animator/SkAnimatorScript.cpp
index cc111ca..6aae006 100644
--- a/src/animator/SkAnimatorScript.cpp
+++ b/src/animator/SkAnimatorScript.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkAnimatorScript.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkAnimatorScript.h"
#include "SkAnimateBase.h"
@@ -473,7 +465,7 @@ bool SkAnimatorScript::Unbox(void* m, SkScriptValue* scriptValue) {
scriptValue->fOperand.fString = SkNEW_ARGS(SkString, (boxedValue->value));
} break;
default: {
- const char* id;
+ const char* id = NULL;
bool success = maker->findKey(displayable, &id);
SkASSERT(success);
scriptValue->fOperand.fString = SkNEW_ARGS(SkString, (id));
diff --git a/src/animator/SkAnimatorScript.h b/src/animator/SkAnimatorScript.h
index 2fdb029..a23f90d 100644
--- a/src/animator/SkAnimatorScript.h
+++ b/src/animator/SkAnimatorScript.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkAnimatorScript.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkAnimatorScript_DEFINED
#define SkAnimatorScript_DEFINED
diff --git a/src/animator/SkAnimatorScript2.cpp b/src/animator/SkAnimatorScript2.cpp
index 3b8ec69..ae51fdc 100644
--- a/src/animator/SkAnimatorScript2.cpp
+++ b/src/animator/SkAnimatorScript2.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkAnimatorScript2.h"
#include "SkAnimateBase.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkAnimatorScript2.h b/src/animator/SkAnimatorScript2.h
index 61261e9..e6bf58e 100644
--- a/src/animator/SkAnimatorScript2.h
+++ b/src/animator/SkAnimatorScript2.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkAnimatorScript2_DEFINED
#define SkAnimatorScript2_DEFINED
diff --git a/src/animator/SkBase64.cpp b/src/animator/SkBase64.cpp
index e192a52..076f649 100644
--- a/src/animator/SkBase64.cpp
+++ b/src/animator/SkBase64.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkBase64.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkBase64.h"
@@ -82,7 +74,8 @@ handlePad:
padTwo = true;
break;
} while (byte < 4);
- int two, three;
+ int two = 0;
+ int three = 0;
if (writeDestination) {
int one = (uint8_t) (bytes[0] << 2);
two = bytes[1];
diff --git a/src/animator/SkBase64.h b/src/animator/SkBase64.h
index 12ccf8c..69d256c 100644
--- a/src/animator/SkBase64.h
+++ b/src/animator/SkBase64.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkBase64.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkBase64_DEFINED
#define SkBase64_DEFINED
diff --git a/src/animator/SkBoundable.cpp b/src/animator/SkBoundable.cpp
index f2125ea..017b6b8 100644
--- a/src/animator/SkBoundable.cpp
+++ b/src/animator/SkBoundable.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkBoundable.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkBoundable.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkBoundable.h b/src/animator/SkBoundable.h
index 67f5a12..1e70505 100644
--- a/src/animator/SkBoundable.h
+++ b/src/animator/SkBoundable.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkBoundable.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkBoundable_DEFINED
#define SkBoundable_DEFINED
diff --git a/src/animator/SkBuildCondensedInfo.cpp b/src/animator/SkBuildCondensedInfo.cpp
index 5e4eedc..30da67e 100644
--- a/src/animator/SkBuildCondensedInfo.cpp
+++ b/src/animator/SkBuildCondensedInfo.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkBuildCondensedInfo.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTypes.h"
#if defined SK_BUILD_CONDENSED
diff --git a/src/animator/SkCondensedDebug.cpp b/src/animator/SkCondensedDebug.cpp
index e7b7ff1..c1c7007 100644
--- a/src/animator/SkCondensedDebug.cpp
+++ b/src/animator/SkCondensedDebug.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkCondensedDebug.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTypes.h"
#ifndef SK_BUILD_FOR_UNIX
diff --git a/src/animator/SkCondensedRelease.cpp b/src/animator/SkCondensedRelease.cpp
index a493cb3..234e67e 100644
--- a/src/animator/SkCondensedRelease.cpp
+++ b/src/animator/SkCondensedRelease.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkCondensedRelease.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTypes.h"
#ifndef SK_BUILD_FOR_UNIX
diff --git a/src/animator/SkDisplayAdd.cpp b/src/animator/SkDisplayAdd.cpp
index 8a97a06..1cf89a1 100644
--- a/src/animator/SkDisplayAdd.cpp
+++ b/src/animator/SkDisplayAdd.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayAdd.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayAdd.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDisplayAdd.h b/src/animator/SkDisplayAdd.h
index 0f3edc9..47948fb 100644
--- a/src/animator/SkDisplayAdd.h
+++ b/src/animator/SkDisplayAdd.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayAdd.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayAdd_DEFINED
#define SkDisplayAdd_DEFINED
diff --git a/src/animator/SkDisplayApply.cpp b/src/animator/SkDisplayApply.cpp
index e456f26..d54ee26 100644
--- a/src/animator/SkDisplayApply.cpp
+++ b/src/animator/SkDisplayApply.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayApply.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayApply.h"
#include "SkAnimateActive.h"
@@ -146,8 +138,9 @@ void SkApply::applyValues(int animatorIndex, SkOperand* values, int count,
animator->packARGB(&values->fScalar, count, &converted);
values = converted.begin();
count = converted.count();
- } else
+ } else {
SkASSERT(count == 1);
+ }
}
// SkASSERT(type == SkType_ARGB || type == SkType_String ||info->isSettable());
if (type == SkType_String || type == SkType_DynamicString)
diff --git a/src/animator/SkDisplayApply.h b/src/animator/SkDisplayApply.h
index d51e467..018b894 100644
--- a/src/animator/SkDisplayApply.h
+++ b/src/animator/SkDisplayApply.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayApply.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayApply_DEFINED
#define SkDisplayApply_DEFINED
diff --git a/src/animator/SkDisplayBounds.cpp b/src/animator/SkDisplayBounds.cpp
index d0499ce..69ec47e 100644
--- a/src/animator/SkDisplayBounds.cpp
+++ b/src/animator/SkDisplayBounds.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayBounds.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayBounds.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDisplayBounds.h b/src/animator/SkDisplayBounds.h
index 6fcd09c..bc3a987 100644
--- a/src/animator/SkDisplayBounds.h
+++ b/src/animator/SkDisplayBounds.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayBounds.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayBounds_DEFINED
#define SkDisplayBounds_DEFINED
diff --git a/src/animator/SkDisplayEvent.cpp b/src/animator/SkDisplayEvent.cpp
index 6253cdf..e3116d7 100644
--- a/src/animator/SkDisplayEvent.cpp
+++ b/src/animator/SkDisplayEvent.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayEvent.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayEvent.h"
#include "SkAnimateMaker.h"
@@ -263,7 +255,7 @@ bool SkDisplayEvent::setProperty(int index, SkScriptValue& value) {
return true;
}
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
#include "SkMetaData.h"
#include "SkParse.h"
diff --git a/src/animator/SkDisplayEvent.h b/src/animator/SkDisplayEvent.h
index 837cfec..8b541fc 100644
--- a/src/animator/SkDisplayEvent.h
+++ b/src/animator/SkDisplayEvent.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayEvent.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayEvent_DEFINED
#define SkDisplayEvent_DEFINED
diff --git a/src/animator/SkDisplayEvents.cpp b/src/animator/SkDisplayEvents.cpp
index e6a01ba..38f82a0 100644
--- a/src/animator/SkDisplayEvents.cpp
+++ b/src/animator/SkDisplayEvents.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayEvents.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayEvents.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDisplayEvents.h b/src/animator/SkDisplayEvents.h
index 73721d4..2874ac5 100644
--- a/src/animator/SkDisplayEvents.h
+++ b/src/animator/SkDisplayEvents.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayEvents.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayEvents_DEFINED
#define SkDisplayEvents_DEFINED
diff --git a/src/animator/SkDisplayInclude.cpp b/src/animator/SkDisplayInclude.cpp
index 26b1e69..860264e 100644
--- a/src/animator/SkDisplayInclude.cpp
+++ b/src/animator/SkDisplayInclude.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayInclude.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayInclude.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDisplayInclude.h b/src/animator/SkDisplayInclude.h
index 81ad76a..d3fe4da 100644
--- a/src/animator/SkDisplayInclude.h
+++ b/src/animator/SkDisplayInclude.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayInclude.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayInclude_DEFINED
#define SkDisplayInclude_DEFINED
diff --git a/src/animator/SkDisplayInput.cpp b/src/animator/SkDisplayInput.cpp
index 3688930..77bc5de 100644
--- a/src/animator/SkDisplayInput.cpp
+++ b/src/animator/SkDisplayInput.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayInput.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayInput.h"
diff --git a/src/animator/SkDisplayInput.h b/src/animator/SkDisplayInput.h
index ac7c7c1..79d82b5 100644
--- a/src/animator/SkDisplayInput.h
+++ b/src/animator/SkDisplayInput.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayInput.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayInput_DEFINED
#define SkDisplayInput_DEFINED
diff --git a/src/animator/SkDisplayList.cpp b/src/animator/SkDisplayList.cpp
index 57f29f7..8424b12 100644
--- a/src/animator/SkDisplayList.cpp
+++ b/src/animator/SkDisplayList.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayList.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayList.h"
#include "SkAnimateActive.h"
diff --git a/src/animator/SkDisplayList.h b/src/animator/SkDisplayList.h
index 3743e35..f520b55 100644
--- a/src/animator/SkDisplayList.h
+++ b/src/animator/SkDisplayList.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayList.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayList_DEFINED
#define SkDisplayList_DEFINED
diff --git a/src/animator/SkDisplayMath.cpp b/src/animator/SkDisplayMath.cpp
index 66bd1f8..c4d496d 100644
--- a/src/animator/SkDisplayMath.cpp
+++ b/src/animator/SkDisplayMath.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayMath.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayMath.h"
diff --git a/src/animator/SkDisplayMath.h b/src/animator/SkDisplayMath.h
index de26319..e21d03f 100644
--- a/src/animator/SkDisplayMath.h
+++ b/src/animator/SkDisplayMath.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayMath.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayMath_DEFINED
#define SkDisplayMath_DEFINED
diff --git a/src/animator/SkDisplayMovie.cpp b/src/animator/SkDisplayMovie.cpp
index ed74329..4fbf3f3 100644
--- a/src/animator/SkDisplayMovie.cpp
+++ b/src/animator/SkDisplayMovie.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayMovie.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayMovie.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDisplayMovie.h b/src/animator/SkDisplayMovie.h
index 2b8a893..a599fb6 100644
--- a/src/animator/SkDisplayMovie.h
+++ b/src/animator/SkDisplayMovie.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayMovie.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayMovie_DEFINED
#define SkDisplayMovie_DEFINED
diff --git a/src/animator/SkDisplayNumber.cpp b/src/animator/SkDisplayNumber.cpp
index 3bb96d7..282dab6 100644
--- a/src/animator/SkDisplayNumber.cpp
+++ b/src/animator/SkDisplayNumber.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayNumber.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayNumber.h"
diff --git a/src/animator/SkDisplayNumber.h b/src/animator/SkDisplayNumber.h
index 515c35b..7092e21 100644
--- a/src/animator/SkDisplayNumber.h
+++ b/src/animator/SkDisplayNumber.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayNumber.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayNumber_DEFINED
#define SkDisplayNumber_DEFINED
diff --git a/src/animator/SkDisplayPost.cpp b/src/animator/SkDisplayPost.cpp
index 17e7c76..8283a9c 100644
--- a/src/animator/SkDisplayPost.cpp
+++ b/src/animator/SkDisplayPost.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayPost.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayPost.h"
#include "SkAnimateMaker.h"
@@ -51,13 +43,13 @@ SkPost::SkPost() : delay(0), /*initialized(SkBool(-1)), */ mode(kImmediate), fMa
}
SkPost::~SkPost() {
- for (SkData** part = fParts.begin(); part < fParts.end(); part++)
+ for (SkDataInput** part = fParts.begin(); part < fParts.end(); part++)
delete *part;
}
bool SkPost::add(SkAnimateMaker& , SkDisplayable* child) {
- SkASSERT(child && child->isData());
- SkData* part = (SkData*) child;
+ SkASSERT(child && child->isDataInput());
+ SkDataInput* part = (SkDataInput*) child;
*fParts.append() = part;
return true;
}
@@ -113,8 +105,8 @@ void SkPost::dump(SkAnimateMaker* maker) {
//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;
+ //SkDataInput** ptr = fParts.end();
+ //SkDataInput* data;
//const char* ID;
while ((name = iter.next(&type, &number)) != NULL) {
//ptr--;
@@ -190,7 +182,7 @@ bool SkPost::enable(SkAnimateMaker& maker ) {
fEvent.getMetaData().reset();
if (preserveID.size() > 0)
fEvent.setString("id", preserveID);
- for (SkData** part = fParts.begin(); part < fParts.end(); part++) {
+ for (SkDataInput** part = fParts.begin(); part < fParts.end(); part++) {
if ((*part)->add())
maker.setErrorCode(SkDisplayXMLParserError::kErrorAddingDataToPost);
}
@@ -284,7 +276,7 @@ bool SkPost::hasEnable() const {
void SkPost::onEndElement(SkAnimateMaker& maker) {
fTargetMaker = fMaker = &maker;
if (fChildHasID == false) {
- for (SkData** part = fParts.begin(); part < fParts.end(); part++)
+ for (SkDataInput** part = fParts.begin(); part < fParts.end(); part++)
delete *part;
fParts.reset();
}
diff --git a/src/animator/SkDisplayPost.h b/src/animator/SkDisplayPost.h
index 4b75b07..b417bab 100644
--- a/src/animator/SkDisplayPost.h
+++ b/src/animator/SkDisplayPost.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayPost.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayPost_DEFINED
#define SkDisplayPost_DEFINED
@@ -24,7 +16,7 @@
#include "SkMemberInfo.h"
#include "SkIntArray.h"
-class SkData;
+class SkDataInput;
class SkAnimateMaker;
class SkPost : public SkDisplayable {
@@ -60,7 +52,7 @@ protected:
SkBool8 fDirty;
private:
void findSinkID();
- friend class SkData;
+ friend class SkDataInput;
typedef SkDisplayable INHERITED;
};
diff --git a/src/animator/SkDisplayRandom.cpp b/src/animator/SkDisplayRandom.cpp
index ab078cd..ac6c3a1 100644
--- a/src/animator/SkDisplayRandom.cpp
+++ b/src/animator/SkDisplayRandom.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayRandom.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayRandom.h"
#include "SkInterpolator.h"
diff --git a/src/animator/SkDisplayRandom.h b/src/animator/SkDisplayRandom.h
index b40907e..87956d2 100644
--- a/src/animator/SkDisplayRandom.h
+++ b/src/animator/SkDisplayRandom.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayRandom.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayRandom_DEFINED
#define SkDisplayRandom_DEFINED
diff --git a/src/animator/SkDisplayScreenplay.cpp b/src/animator/SkDisplayScreenplay.cpp
index 58180e7..463f948 100644
--- a/src/animator/SkDisplayScreenplay.cpp
+++ b/src/animator/SkDisplayScreenplay.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayScreenplay.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayScreenplay.h"
diff --git a/src/animator/SkDisplayScreenplay.h b/src/animator/SkDisplayScreenplay.h
index cb8103d..0265548 100644
--- a/src/animator/SkDisplayScreenplay.h
+++ b/src/animator/SkDisplayScreenplay.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayScreenplay.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayScreenplay_DEFINED
#define SkDisplayScreenplay_DEFINED
diff --git a/src/animator/SkDisplayType.cpp b/src/animator/SkDisplayType.cpp
index 90fcd89..4dfa62f 100644
--- a/src/animator/SkDisplayType.cpp
+++ b/src/animator/SkDisplayType.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayType.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayType.h"
#include "SkAnimateMaker.h"
@@ -119,7 +111,7 @@ SkDisplayable* SkDisplayType::CreateInstance(SkAnimateMaker* maker, SkDisplayTyp
CASE_DRAW_NEW(Color);
CASE_NEW(CubicTo);
CASE_NEW(Dash);
- CASE_NEW(Data);
+ CASE_NEW(DataInput);
CASE_NEW(Discrete);
// displayable
// drawable
@@ -274,7 +266,7 @@ const SkMemberInfo* SkDisplayType::GetMembers(SkAnimateMaker* maker,
CASE_GET_DRAW_INFO(Color);
CASE_GET_INFO(CubicTo);
CASE_GET_INFO(Dash);
- CASE_GET_INFO(Data);
+ CASE_GET_INFO(DataInput);
CASE_GET_INFO(Discrete);
// displayable
// drawable
@@ -441,7 +433,7 @@ const TypeNames gTypeNames[] = {
DRAW_NAME("color", SkType_Color),
{ "cubicTo", SkType_CubicTo INIT_BOOL_FIELDS },
{ "dash", SkType_Dash INIT_BOOL_FIELDS },
- { "data", SkType_Data INIT_BOOL_FIELDS },
+ { "data", SkType_DataInput INIT_BOOL_FIELDS },
{ "discrete", SkType_Discrete INIT_BOOL_FIELDS },
// displayable
// drawable
@@ -634,7 +626,7 @@ bool SkDisplayType::IsDisplayable(SkAnimateMaker* , SkDisplayTypes type) {
case SkType_Color:
case SkType_CubicTo:
case SkType_Dash:
- case SkType_Data:
+ case SkType_DataInput:
case SkType_Discrete:
case SkType_Displayable:
case SkType_Drawable:
diff --git a/src/animator/SkDisplayType.h b/src/animator/SkDisplayType.h
index a29b285..fe82b31 100644
--- a/src/animator/SkDisplayType.h
+++ b/src/animator/SkDisplayType.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayType.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayType_DEFINED
#define SkDisplayType_DEFINED
@@ -75,7 +67,7 @@ enum SkDisplayTypes {
SkType_Color,
SkType_CubicTo,
SkType_Dash,
- SkType_Data,
+ SkType_DataInput,
SkType_Discrete,
SkType_Displayable,
SkType_Drawable,
diff --git a/src/animator/SkDisplayTypes.cpp b/src/animator/SkDisplayTypes.cpp
index b5bc573..6132eb7 100644
--- a/src/animator/SkDisplayTypes.cpp
+++ b/src/animator/SkDisplayTypes.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayTypes.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayTypes.h"
#include "SkAnimateBase.h"
diff --git a/src/animator/SkDisplayTypes.h b/src/animator/SkDisplayTypes.h
index 0ac57ba..75cace6 100644
--- a/src/animator/SkDisplayTypes.h
+++ b/src/animator/SkDisplayTypes.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayTypes.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayTypes_DEFINED
#define SkDisplayTypes_DEFINED
diff --git a/src/animator/SkDisplayXMLParser.cpp b/src/animator/SkDisplayXMLParser.cpp
index db6c838..68dc259 100644
--- a/src/animator/SkDisplayXMLParser.cpp
+++ b/src/animator/SkDisplayXMLParser.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayXMLParser.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayXMLParser.h"
#include "SkAnimateMaker.h"
@@ -165,8 +157,8 @@ bool SkDisplayXMLParser::onAddAttributeLen(const char attrName[], const char att
}
#if defined(SK_BUILD_FOR_WIN32)
- #define SK_strcasecmp stricmp
- #define SK_strncasecmp strnicmp
+ #define SK_strcasecmp _stricmp
+ #define SK_strncasecmp _strnicmp
#else
#define SK_strcasecmp strcasecmp
#define SK_strncasecmp strncasecmp
diff --git a/src/animator/SkDisplayXMLParser.h b/src/animator/SkDisplayXMLParser.h
index 2c2bec1..c18e48f 100644
--- a/src/animator/SkDisplayXMLParser.h
+++ b/src/animator/SkDisplayXMLParser.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayXMLParser.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayXMLParser_DEFINED
#define SkDisplayXMLParser_DEFINED
diff --git a/src/animator/SkDisplayable.cpp b/src/animator/SkDisplayable.cpp
index e50e1ab..ebcc8a3 100644
--- a/src/animator/SkDisplayable.cpp
+++ b/src/animator/SkDisplayable.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayable.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDisplayable.h"
#include "SkDisplayApply.h"
diff --git a/src/animator/SkDisplayable.h b/src/animator/SkDisplayable.h
index cbc96de..a3db002 100644
--- a/src/animator/SkDisplayable.h
+++ b/src/animator/SkDisplayable.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDisplayable.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDisplayable_DEFINED
#define SkDisplayable_DEFINED
@@ -96,7 +88,7 @@ public:
virtual bool setProperty(int index, SkScriptValue& );
void setReference(const SkMemberInfo* info, SkDisplayable* ref);
#ifdef SK_DEBUG
- bool isData() const { return getType() == SkType_Data; };
+ bool isDataInput() const { return getType() == SkType_DataInput; };
bool isEvent() const { return getType() == SkType_Event; }
virtual bool isMatrixPart() const { return false; }
bool isPatch() const { return getType() == SkType_3D_Patch; }
diff --git a/src/animator/SkDraw3D.cpp b/src/animator/SkDraw3D.cpp
index 137de9f..ce2bec4 100644
--- a/src/animator/SkDraw3D.cpp
+++ b/src/animator/SkDraw3D.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDraw3D.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDraw3D.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDraw3D.h b/src/animator/SkDraw3D.h
index 5ab61cd..e6549ea 100644
--- a/src/animator/SkDraw3D.h
+++ b/src/animator/SkDraw3D.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDraw3D.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDraw3D_DEFINED
#define SkDraw3D_DEFINED
diff --git a/src/animator/SkDrawBitmap.cpp b/src/animator/SkDrawBitmap.cpp
index 25355be..a1d49d6 100644
--- a/src/animator/SkDrawBitmap.cpp
+++ b/src/animator/SkDrawBitmap.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawBitmap.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawBitmap.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDrawBitmap.h b/src/animator/SkDrawBitmap.h
index f846193..e6d6d44 100644
--- a/src/animator/SkDrawBitmap.h
+++ b/src/animator/SkDrawBitmap.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawBitmap.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawBitmap_DEFINED
#define SkDrawBitmap_DEFINED
diff --git a/src/animator/SkDrawBlur.cpp b/src/animator/SkDrawBlur.cpp
index 0ebabce..57e8e20 100644
--- a/src/animator/SkDrawBlur.cpp
+++ b/src/animator/SkDrawBlur.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawBlur.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawBlur.h"
diff --git a/src/animator/SkDrawBlur.h b/src/animator/SkDrawBlur.h
index 14ceba0..220e211 100644
--- a/src/animator/SkDrawBlur.h
+++ b/src/animator/SkDrawBlur.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawBlur.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawBlur_DEFINED
#define SkDrawBlur_DEFINED
diff --git a/src/animator/SkDrawClip.cpp b/src/animator/SkDrawClip.cpp
index 1c01c6a..521bbc5 100644
--- a/src/animator/SkDrawClip.cpp
+++ b/src/animator/SkDrawClip.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawClip.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawClip.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDrawClip.h b/src/animator/SkDrawClip.h
index 2fed99a..6265775 100644
--- a/src/animator/SkDrawClip.h
+++ b/src/animator/SkDrawClip.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawClip.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawClip_DEFINED
#define SkDrawClip_DEFINED
diff --git a/src/animator/SkDrawColor.cpp b/src/animator/SkDrawColor.cpp
index 009ca10..811a5d6 100644
--- a/src/animator/SkDrawColor.cpp
+++ b/src/animator/SkDrawColor.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawColor.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawColor.h"
#ifdef SK_DEBUG
diff --git a/src/animator/SkDrawColor.h b/src/animator/SkDrawColor.h
index 89b87cc..29c73c3 100644
--- a/src/animator/SkDrawColor.h
+++ b/src/animator/SkDrawColor.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawColor.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawColor_DEFINED
#define SkDrawColor_DEFINED
diff --git a/src/animator/SkDrawDash.cpp b/src/animator/SkDrawDash.cpp
index bdac9cd..0d93293 100644
--- a/src/animator/SkDrawDash.cpp
+++ b/src/animator/SkDrawDash.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawDash.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawDash.h"
#include "SkDashPathEffect.h"
diff --git a/src/animator/SkDrawDash.h b/src/animator/SkDrawDash.h
index c2108c1..483d2a3 100644
--- a/src/animator/SkDrawDash.h
+++ b/src/animator/SkDrawDash.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawDash.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawDash_DEFINED
#define SkDrawDash_DEFINED
diff --git a/src/animator/SkDrawDiscrete.cpp b/src/animator/SkDrawDiscrete.cpp
index e1089c2..655c83d 100644
--- a/src/animator/SkDrawDiscrete.cpp
+++ b/src/animator/SkDrawDiscrete.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawDiscrete.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawDiscrete.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDrawDiscrete.h b/src/animator/SkDrawDiscrete.h
index 78485ee..bd33d2f 100644
--- a/src/animator/SkDrawDiscrete.h
+++ b/src/animator/SkDrawDiscrete.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawDiscrete.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawDiscrete_DEFINED
#define SkDrawDiscrete_DEFINED
diff --git a/src/animator/SkDrawEmboss.cpp b/src/animator/SkDrawEmboss.cpp
index 77f6dfd..2284504 100644
--- a/src/animator/SkDrawEmboss.cpp
+++ b/src/animator/SkDrawEmboss.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawEmboss.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawEmboss.h"
diff --git a/src/animator/SkDrawEmboss.h b/src/animator/SkDrawEmboss.h
index fe6911b..50ce71a 100644
--- a/src/animator/SkDrawEmboss.h
+++ b/src/animator/SkDrawEmboss.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawEmboss.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawEmboss_DEFINED
#define SkDrawEmboss_DEFINED
diff --git a/src/animator/SkDrawExtraPathEffect.cpp b/src/animator/SkDrawExtraPathEffect.cpp
index 76b55c6..12e0368 100644
--- a/src/animator/SkDrawExtraPathEffect.cpp
+++ b/src/animator/SkDrawExtraPathEffect.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawExtraPathEffect.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawExtraPathEffect.h"
#include "SkDrawPath.h"
diff --git a/src/animator/SkDrawFull.cpp b/src/animator/SkDrawFull.cpp
index c6568db..762b3da 100644
--- a/src/animator/SkDrawFull.cpp
+++ b/src/animator/SkDrawFull.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawFull.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawFull.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDrawFull.h b/src/animator/SkDrawFull.h
index cfbb643..a2dcf49 100644
--- a/src/animator/SkDrawFull.h
+++ b/src/animator/SkDrawFull.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawFull.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawFull_DEFINED
#define SkDrawFull_DEFINED
diff --git a/src/animator/SkDrawGradient.cpp b/src/animator/SkDrawGradient.cpp
index e9061b5..37fc7e8 100644
--- a/src/animator/SkDrawGradient.cpp
+++ b/src/animator/SkDrawGradient.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawGradient.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawGradient.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDrawGradient.h b/src/animator/SkDrawGradient.h
index 30a86df..251e975 100644
--- a/src/animator/SkDrawGradient.h
+++ b/src/animator/SkDrawGradient.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawGradient.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawGradient_DEFINED
#define SkDrawGradient_DEFINED
diff --git a/src/animator/SkDrawGroup.cpp b/src/animator/SkDrawGroup.cpp
index aa53564..939bd9f 100644
--- a/src/animator/SkDrawGroup.cpp
+++ b/src/animator/SkDrawGroup.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawGroup.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawGroup.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDrawGroup.h b/src/animator/SkDrawGroup.h
index 0009a4c..8124650 100644
--- a/src/animator/SkDrawGroup.h
+++ b/src/animator/SkDrawGroup.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawGroup.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawGroup_DEFINED
#define SkDrawGroup_DEFINED
diff --git a/src/animator/SkDrawLine.cpp b/src/animator/SkDrawLine.cpp
index 166cbbc..fe93c4e 100644
--- a/src/animator/SkDrawLine.cpp
+++ b/src/animator/SkDrawLine.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawLine.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawLine.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDrawLine.h b/src/animator/SkDrawLine.h
index 8f771cf..e90c997 100644
--- a/src/animator/SkDrawLine.h
+++ b/src/animator/SkDrawLine.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawLine.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawLine_DEFINED
#define SkDrawLine_DEFINED
diff --git a/src/animator/SkDrawMatrix.cpp b/src/animator/SkDrawMatrix.cpp
index dbdbf19..96e8292 100644
--- a/src/animator/SkDrawMatrix.cpp
+++ b/src/animator/SkDrawMatrix.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawMatrix.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawMatrix.h"
#include "SkAnimateMaker.h"
@@ -127,10 +119,10 @@ void SkDrawMatrix::dump(SkAnimateMaker* maker) {
result = fMatrix.getTranslateY();
if (result)
SkDebugf("ty=\"%g\" ", SkScalarToFloat(result));
- result = fMatrix.getPerspX();
+ result = SkPerspToScalar(fMatrix.getPerspX());
if (result)
SkDebugf("perspect-x=\"%g\" ", SkScalarToFloat(result));
- result = fMatrix.getPerspY();
+ result = SkPerspToScalar(fMatrix.getPerspY());
if (result)
SkDebugf("perspect-y=\"%g\" ", SkScalarToFloat(result));
SkDebugf("/>\n");
@@ -198,14 +190,9 @@ void SkDrawMatrix::onEndElement(SkAnimateMaker& ) {
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]);
+ fMatrix.setPerspX(SkScalarToPersp(vals[6]));
+ fMatrix.setPerspY(SkScalarToPersp(vals[7]));
+// fMatrix.setPerspW(SkScalarToPersp(vals[8]));
goto setConcat;
}
if (fChildHasID == false) {
@@ -237,18 +224,10 @@ bool SkDrawMatrix::setProperty(int index, SkScriptValue& scriptValue) {
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
+ fMatrix.setPerspX(SkScalarToPersp((number)));
break;
case SK_PROPERTY(perspectY):
-#ifdef SK_SCALAR_IS_FIXED
- fMatrix.setPerspY(SkFixedToFract(number));
-#else
- fMatrix.setPerspY(number);
-#endif
+ fMatrix.setPerspY(SkScalarToPersp((number)));
break;
case SK_PROPERTY(rotate): {
SkMatrix temp;
diff --git a/src/animator/SkDrawMatrix.h b/src/animator/SkDrawMatrix.h
index 8339d8c..e303424 100644
--- a/src/animator/SkDrawMatrix.h
+++ b/src/animator/SkDrawMatrix.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawMatrix.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawMatrix_DEFINED
#define SkDrawMatrix_DEFINED
diff --git a/src/animator/SkDrawOval.cpp b/src/animator/SkDrawOval.cpp
index 0e3a9ae..ab0fc81 100644
--- a/src/animator/SkDrawOval.cpp
+++ b/src/animator/SkDrawOval.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawOval.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawOval.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDrawOval.h b/src/animator/SkDrawOval.h
index 0e7ae3f..afdc252 100644
--- a/src/animator/SkDrawOval.h
+++ b/src/animator/SkDrawOval.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawOval.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawOval_DEFINED
#define SkDrawOval_DEFINED
diff --git a/src/animator/SkDrawPaint.cpp b/src/animator/SkDrawPaint.cpp
index f21a15a..4d1bd8b 100644
--- a/src/animator/SkDrawPaint.cpp
+++ b/src/animator/SkDrawPaint.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawPaint.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawPaint.h"
#include "SkAnimateMaker.h"
@@ -98,11 +90,11 @@ SkDrawPaint::~SkDrawPaint() {
delete typeface;
}
-bool SkDrawPaint::add(SkAnimateMaker& maker, SkDisplayable* child) {
+bool SkDrawPaint::add(SkAnimateMaker* maker, SkDisplayable* child) {
SkASSERT(child && child->isPaintPart());
SkPaintPart* part = (SkPaintPart*) child;
- if (part->add())
- maker.setErrorCode(SkDisplayXMLParserError::kErrorAddingToPaint);
+ if (part->add() && maker)
+ maker->setErrorCode(SkDisplayXMLParserError::kErrorAddingToPaint);
return true;
}
diff --git a/src/animator/SkDrawPaint.h b/src/animator/SkDrawPaint.h
index ea77acd..a2a893e 100644
--- a/src/animator/SkDrawPaint.h
+++ b/src/animator/SkDrawPaint.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawPaint.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawPaint_DEFINED
#define SkDrawPaint_DEFINED
@@ -34,7 +26,7 @@ class SkDrawPaint : public SkDrawable {
DECLARE_DRAW_MEMBER_INFO(Paint);
SkDrawPaint();
virtual ~SkDrawPaint();
- virtual bool add(SkAnimateMaker& , SkDisplayable* child);
+ virtual bool add(SkAnimateMaker* , SkDisplayable* child);
virtual SkDisplayable* deepCopy(SkAnimateMaker* );
virtual bool draw(SkAnimateMaker& );
#ifdef SK_DUMP_ENABLED
diff --git a/src/animator/SkDrawPath.cpp b/src/animator/SkDrawPath.cpp
index 895e597..10e9203 100644
--- a/src/animator/SkDrawPath.cpp
+++ b/src/animator/SkDrawPath.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawPath.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawPath.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDrawPath.h b/src/animator/SkDrawPath.h
index 673051a..5c26312 100644
--- a/src/animator/SkDrawPath.h
+++ b/src/animator/SkDrawPath.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawPath.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawPath_DEFINED
#define SkDrawPath_DEFINED
diff --git a/src/animator/SkDrawPoint.cpp b/src/animator/SkDrawPoint.cpp
index 383a599..94fe4d2 100644
--- a/src/animator/SkDrawPoint.cpp
+++ b/src/animator/SkDrawPoint.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawPoint.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawPoint.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDrawPoint.h b/src/animator/SkDrawPoint.h
index d06e5b7..0ecf447 100644
--- a/src/animator/SkDrawPoint.h
+++ b/src/animator/SkDrawPoint.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawPoint.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawPoint_DEFINED
#define SkDrawPoint_DEFINED
diff --git a/src/animator/SkDrawRectangle.cpp b/src/animator/SkDrawRectangle.cpp
index f2054bd..19edf50 100644
--- a/src/animator/SkDrawRectangle.cpp
+++ b/src/animator/SkDrawRectangle.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawRectangle.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawRectangle.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDrawRectangle.h b/src/animator/SkDrawRectangle.h
index 9f8bc0a..49c9cf4 100644
--- a/src/animator/SkDrawRectangle.h
+++ b/src/animator/SkDrawRectangle.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawRectangle.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawRectangle_DEFINED
#define SkDrawRectangle_DEFINED
diff --git a/src/animator/SkDrawSaveLayer.cpp b/src/animator/SkDrawSaveLayer.cpp
index bc2288f..a7592db 100644
--- a/src/animator/SkDrawSaveLayer.cpp
+++ b/src/animator/SkDrawSaveLayer.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawSaveLayer.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawSaveLayer.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDrawSaveLayer.h b/src/animator/SkDrawSaveLayer.h
index 52a36a4..5c3e068 100644
--- a/src/animator/SkDrawSaveLayer.h
+++ b/src/animator/SkDrawSaveLayer.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawSaveLayer.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawSaveLayer_DEFINED
#define SkDrawSaveLayer_DEFINED
diff --git a/src/animator/SkDrawShader.cpp b/src/animator/SkDrawShader.cpp
index b38718e..5019622 100644
--- a/src/animator/SkDrawShader.cpp
+++ b/src/animator/SkDrawShader.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawShader.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawShader.h"
#include "SkDrawBitmap.h"
diff --git a/src/animator/SkDrawShader.h b/src/animator/SkDrawShader.h
index 35ca419..b6a487a 100644
--- a/src/animator/SkDrawShader.h
+++ b/src/animator/SkDrawShader.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawShader.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawShader_DEFINED
#define SkDrawShader_DEFINED
diff --git a/src/animator/SkDrawText.cpp b/src/animator/SkDrawText.cpp
index dcc3a75..b8d38b4 100644
--- a/src/animator/SkDrawText.cpp
+++ b/src/animator/SkDrawText.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawText.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawText.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDrawText.h b/src/animator/SkDrawText.h
index cb1d1b9..7dd2e26 100644
--- a/src/animator/SkDrawText.h
+++ b/src/animator/SkDrawText.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawText.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawText_DEFINED
#define SkDrawText_DEFINED
diff --git a/src/animator/SkDrawTextBox.cpp b/src/animator/SkDrawTextBox.cpp
index 4c4ac76..d97dc5c 100644
--- a/src/animator/SkDrawTextBox.cpp
+++ b/src/animator/SkDrawTextBox.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawTextBox.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawTextBox.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDrawTextBox.h b/src/animator/SkDrawTextBox.h
index ee97c22..d8d7f0c 100644
--- a/src/animator/SkDrawTextBox.h
+++ b/src/animator/SkDrawTextBox.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawTextBox.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawTextBox_DEFINED
#define SkDrawTextBox_DEFINED
diff --git a/src/animator/SkDrawTo.cpp b/src/animator/SkDrawTo.cpp
index 342f7d4..bc5cd6d 100644
--- a/src/animator/SkDrawTo.cpp
+++ b/src/animator/SkDrawTo.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawTo.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawTo.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkDrawTo.h b/src/animator/SkDrawTo.h
index 0ad78e8..b6365af 100644
--- a/src/animator/SkDrawTo.h
+++ b/src/animator/SkDrawTo.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawTo.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawTo_DEFINED
#define SkDrawTo_DEFINED
diff --git a/src/animator/SkDrawTransparentShader.cpp b/src/animator/SkDrawTransparentShader.cpp
index c1da687..bb5392a 100644
--- a/src/animator/SkDrawTransparentShader.cpp
+++ b/src/animator/SkDrawTransparentShader.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawTransparentShader.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawTransparentShader.h"
#include "SkTransparentShader.h"
diff --git a/src/animator/SkDrawTransparentShader.h b/src/animator/SkDrawTransparentShader.h
index e831883..df1c6eb 100644
--- a/src/animator/SkDrawTransparentShader.h
+++ b/src/animator/SkDrawTransparentShader.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawTransparentShader.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawTransparentShader_DEFINED
#define SkDrawTransparentShader_DEFINED
diff --git a/src/animator/SkDrawable.cpp b/src/animator/SkDrawable.cpp
index 6968fe1..8db0333 100644
--- a/src/animator/SkDrawable.cpp
+++ b/src/animator/SkDrawable.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawable.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDrawable.h"
diff --git a/src/animator/SkDrawable.h b/src/animator/SkDrawable.h
index 7284a25..139ce85 100644
--- a/src/animator/SkDrawable.h
+++ b/src/animator/SkDrawable.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDrawable.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDrawable_DEFINED
#define SkDrawable_DEFINED
diff --git a/src/animator/SkDump.cpp b/src/animator/SkDump.cpp
index 426a1e6..bd91277 100644
--- a/src/animator/SkDump.cpp
+++ b/src/animator/SkDump.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDump.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDump.h"
diff --git a/src/animator/SkDump.h b/src/animator/SkDump.h
index 73a6957..3222f06 100644
--- a/src/animator/SkDump.h
+++ b/src/animator/SkDump.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkDump.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkDump_DEFINED
#define SkDump_DEFINED
diff --git a/src/animator/SkExtras.h b/src/animator/SkExtras.h
index 88e9b2d..dcd3905 100644
--- a/src/animator/SkExtras.h
+++ b/src/animator/SkExtras.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkExtras.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkExtras_DEFINED
#define SkExtras_DEFINED
diff --git a/src/animator/SkGetCondensedInfo.cpp b/src/animator/SkGetCondensedInfo.cpp
index ee91caa..a583cef 100644
--- a/src/animator/SkGetCondensedInfo.cpp
+++ b/src/animator/SkGetCondensedInfo.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkGetCondensedInfo.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkMemberInfo.h"
diff --git a/src/animator/SkHitClear.cpp b/src/animator/SkHitClear.cpp
index e7e301d..70b3e73 100644
--- a/src/animator/SkHitClear.cpp
+++ b/src/animator/SkHitClear.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkHitClear.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkHitClear.h"
diff --git a/src/animator/SkHitClear.h b/src/animator/SkHitClear.h
index f2b50c0..9c40209 100644
--- a/src/animator/SkHitClear.h
+++ b/src/animator/SkHitClear.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkHitClear.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkHitClear_DEFINED
#define SkHitClear_DEFINED
diff --git a/src/animator/SkHitTest.cpp b/src/animator/SkHitTest.cpp
index 585249a..dc4e739 100644
--- a/src/animator/SkHitTest.cpp
+++ b/src/animator/SkHitTest.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkHitTest.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkHitTest.h"
diff --git a/src/animator/SkHitTest.h b/src/animator/SkHitTest.h
index b3a9d85..68d5cc5 100644
--- a/src/animator/SkHitTest.h
+++ b/src/animator/SkHitTest.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkHitTest.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkHitTest_DEFINED
#define SkHitTest_DEFINED
diff --git a/src/animator/SkIntArray.h b/src/animator/SkIntArray.h
index b2a49c1..6769a9e 100644
--- a/src/animator/SkIntArray.h
+++ b/src/animator/SkIntArray.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkIntArray.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkIntArray_DEFINED
#define SkIntArray_DEFINED
@@ -25,7 +17,7 @@
class SkActive;
class SkAnimateBase;
-class SkData;
+class SkDataInput;
class SkDisplayable;
class SkDisplayEvent;
class SkDrawable;
@@ -46,7 +38,7 @@ typedef SkIntArray(SkScalar) SkTDScalarArray;
typedef SkLongArray(SkActive*) SkTDActiveArray;
typedef SkLongArray(SkAnimateBase*) SkTDAnimateArray;
-typedef SkLongArray(SkData*) SkTDDataArray;
+typedef SkLongArray(SkDataInput*) SkTDDataArray;
typedef SkLongArray(SkDisplayable*) SkTDDisplayableArray;
typedef SkLongArray(SkDisplayEvent*) SkTDDisplayEventArray;
typedef SkLongArray(SkDrawable*) SkTDDrawableArray;
diff --git a/src/animator/SkMatrixParts.cpp b/src/animator/SkMatrixParts.cpp
index 56bb2d0..f00bb8e 100644
--- a/src/animator/SkMatrixParts.cpp
+++ b/src/animator/SkMatrixParts.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkMatrixParts.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkMatrixParts.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkMatrixParts.h b/src/animator/SkMatrixParts.h
index d97d9fb..5f6cd54 100644
--- a/src/animator/SkMatrixParts.h
+++ b/src/animator/SkMatrixParts.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkMatrixParts.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkMatrixParts_DEFINED
#define SkMatrixParts_DEFINED
diff --git a/src/animator/SkMemberInfo.cpp b/src/animator/SkMemberInfo.cpp
index 50536c2..7fae503 100644
--- a/src/animator/SkMemberInfo.cpp
+++ b/src/animator/SkMemberInfo.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkMemberInfo.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkMemberInfo.h"
#include "SkAnimateMaker.h"
@@ -97,8 +89,9 @@ bool SkMemberInfo::getArrayValue(const SkDisplayable* displayable, int index, Sk
if (dispArray->values.count() <= index)
return false;
type = dispArray->values.getType();
- } else
+ } else {
SkASSERT(0); // incomplete
+ }
size_t byteSize = GetSize(type);
memcpy(value, valuePtr + index * byteSize, byteSize);
return true;
@@ -265,7 +258,7 @@ scriptCommon: {
SkASSERT(success);
if (scriptValue.fType == SkType_Displayable) {
if (type == SkType_String) {
- const char* charPtr;
+ const char* charPtr = NULL;
maker.findKey(scriptValue.fOperand.fDisplayable, &charPtr);
scriptValue.fOperand.fString = new SkString(charPtr);
scriptValue.fType = SkType_String;
diff --git a/src/animator/SkMemberInfo.h b/src/animator/SkMemberInfo.h
index 4f25145..f2e690c 100644
--- a/src/animator/SkMemberInfo.h
+++ b/src/animator/SkMemberInfo.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkMemberInfo.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkMemberInfo_DEFINED
#define SkMemberInfo_DEFINED
diff --git a/src/animator/SkOpArray.cpp b/src/animator/SkOpArray.cpp
index eb3fcec..1f14476 100644
--- a/src/animator/SkOpArray.cpp
+++ b/src/animator/SkOpArray.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkOpArray.h"
SkOpArray::SkOpArray() : fType(SkOperand2::kNoType) {
diff --git a/src/animator/SkOpArray.h b/src/animator/SkOpArray.h
index 5c511c0..d5b9fe7 100644
--- a/src/animator/SkOpArray.h
+++ b/src/animator/SkOpArray.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkOpArray_DEFINED
#define SkOpArray_DEFINED
diff --git a/src/animator/SkOperand.h b/src/animator/SkOperand.h
index 2c7e93b..0bd1fa3 100644
--- a/src/animator/SkOperand.h
+++ b/src/animator/SkOperand.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkOperand.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkOperand_DEFINED
#define SkOperand_DEFINED
diff --git a/src/animator/SkOperand2.h b/src/animator/SkOperand2.h
index f482e66..4f09a01 100644
--- a/src/animator/SkOperand2.h
+++ b/src/animator/SkOperand2.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkOperand2_DEFINED
#define SkOperand2_DEFINED
diff --git a/src/animator/SkOperandInterpolator.h b/src/animator/SkOperandInterpolator.h
index f155276..82fa272 100644
--- a/src/animator/SkOperandInterpolator.h
+++ b/src/animator/SkOperandInterpolator.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkOperandInterpolator.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkOperandInterpolator_DEFINED
#define SkOperandInterpolator_DEFINED
diff --git a/src/animator/SkOperandIterpolator.cpp b/src/animator/SkOperandIterpolator.cpp
index 2bddd34..dcc454d 100644
--- a/src/animator/SkOperandIterpolator.cpp
+++ b/src/animator/SkOperandIterpolator.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkOperandIterpolator.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkOperandInterpolator.h"
#include "SkScript.h"
diff --git a/src/animator/SkPaintParts.cpp b/src/animator/SkPaintParts.cpp
index 48799c6..2959238 100644
--- a/src/animator/SkPaintParts.cpp
+++ b/src/animator/SkPaintParts.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkPaintParts.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkPaintParts.h"
#include "SkDrawPaint.h"
@@ -61,7 +53,7 @@ bool SkDrawPathEffect::add() {
fPaint->fOwnsPathEffect = true;
return false;
}
- fPaint->add(*(SkAnimateMaker*) NULL, this);
+ fPaint->add(NULL, this);
return false;
}
diff --git a/src/animator/SkPaintParts.h b/src/animator/SkPaintParts.h
index c8c978f..964bc35 100644
--- a/src/animator/SkPaintParts.h
+++ b/src/animator/SkPaintParts.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkPaintParts.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkPaintParts_DEFINED
#define SkPaintParts_DEFINED
diff --git a/src/animator/SkParseSVGPath.cpp b/src/animator/SkParseSVGPath.cpp
index 86eeee8..1b375aa 100644
--- a/src/animator/SkParseSVGPath.cpp
+++ b/src/animator/SkParseSVGPath.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkSVGPath.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include <ctype.h>
#include "SkDrawPath.h"
diff --git a/src/animator/SkPathParts.cpp b/src/animator/SkPathParts.cpp
index 46d2232..5af8150 100644
--- a/src/animator/SkPathParts.cpp
+++ b/src/animator/SkPathParts.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkPathParts.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkPathParts.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkPathParts.h b/src/animator/SkPathParts.h
index 72e4185..cc81cdd 100644
--- a/src/animator/SkPathParts.h
+++ b/src/animator/SkPathParts.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkPathParts.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkPathParts_DEFINED
#define SkPathParts_DEFINED
diff --git a/src/animator/SkPostParts.cpp b/src/animator/SkPostParts.cpp
index 254b17d..4b776a8 100644
--- a/src/animator/SkPostParts.cpp
+++ b/src/animator/SkPostParts.cpp
@@ -1,36 +1,28 @@
-/* libs/graphics/animator/SkPostParts.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkPostParts.h"
#include "SkDisplayPost.h"
#if SK_USE_CONDENSED_INFO == 0
-const SkMemberInfo SkData::fInfo[] = {
+const SkMemberInfo SkDataInput::fInfo[] = {
SK_MEMBER_INHERITED
};
#endif
-DEFINE_GET_MEMBER(SkData);
+DEFINE_GET_MEMBER(SkDataInput);
-SkData::SkData() : fParent(NULL) {}
+SkDataInput::SkDataInput() : fParent(NULL) {}
-bool SkData::add() {
+bool SkDataInput::add() {
SkASSERT(name.size() > 0);
const char* dataName = name.c_str();
if (fInt != (int) SK_NaN32)
@@ -44,22 +36,22 @@ bool SkData::add() {
return false;
}
-void SkData::dirty() {
+void SkDataInput::dirty() {
fParent->dirty();
}
-SkDisplayable* SkData::getParent() const {
+SkDisplayable* SkDataInput::getParent() const {
return fParent;
}
-bool SkData::setParent(SkDisplayable* displayable) {
+bool SkDataInput::setParent(SkDisplayable* displayable) {
if (displayable->isPost() == false)
return true;
fParent = (SkPost*) displayable;
return false;
}
-void SkData::onEndElement(SkAnimateMaker&) {
+void SkDataInput::onEndElement(SkAnimateMaker&) {
add();
}
diff --git a/src/animator/SkPostParts.h b/src/animator/SkPostParts.h
index ef41fe5..4101b2b 100644
--- a/src/animator/SkPostParts.h
+++ b/src/animator/SkPostParts.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkPostParts.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkPostParts_DEFINED
#define SkPostParts_DEFINED
@@ -22,9 +14,9 @@
class SkPost;
-class SkData: public SkInput {
- DECLARE_MEMBER_INFO(Data);
- SkData();
+class SkDataInput: public SkInput {
+ DECLARE_MEMBER_INFO(DataInput);
+ SkDataInput();
bool add();
virtual void dirty();
virtual SkDisplayable* getParent() const;
diff --git a/src/animator/SkScript.cpp b/src/animator/SkScript.cpp
index 96b73cd..aa06169 100644
--- a/src/animator/SkScript.cpp
+++ b/src/animator/SkScript.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkScript.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkScript.h"
#include "SkMath.h"
@@ -192,6 +184,7 @@ SkScriptEngine::SkScriptEngine(SkOpType returnType) :
noInitialSuppress.fOperator = kUnassigned;
noInitialSuppress.fOpStackDepth = 0;
noInitialSuppress.fSuppress = false;
+ noInitialSuppress.fElse = 0;
fSuppressStack.push(noInitialSuppress);
*fOpStack.push() = kParen;
fTrackArray.appendClear();
@@ -1226,6 +1219,7 @@ flipSuppress:
suppress.fSuppress = true;
suppress.fOperator = match;
suppress.fOpStackDepth = fOpStack.count();
+ suppress.fElse = false;
fSuppressStack.push(suppress);
} else {
fTypeStack.pop();
diff --git a/src/animator/SkScript.h b/src/animator/SkScript.h
index bb7d978..95930e8 100644
--- a/src/animator/SkScript.h
+++ b/src/animator/SkScript.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkScript.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkScript_DEFINED
#define SkScript_DEFINED
diff --git a/src/animator/SkScript2.h b/src/animator/SkScript2.h
index 4d8bd8c..05073e4 100644
--- a/src/animator/SkScript2.h
+++ b/src/animator/SkScript2.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkScript2_DEFINED
#define SkScript2_DEFINED
diff --git a/src/animator/SkScriptCallBack.h b/src/animator/SkScriptCallBack.h
index 725e493..b2a1958 100644
--- a/src/animator/SkScriptCallBack.h
+++ b/src/animator/SkScriptCallBack.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkScriptCallBack_DEFINED
#define SkScriptCallBack_DEFINED
diff --git a/src/animator/SkScriptDecompile.cpp b/src/animator/SkScriptDecompile.cpp
index 98db1fb..933e0d7 100644
--- a/src/animator/SkScriptDecompile.cpp
+++ b/src/animator/SkScriptDecompile.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkScriptDecompile.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkScript2.h"
diff --git a/src/animator/SkScriptRuntime.cpp b/src/animator/SkScriptRuntime.cpp
index 1284198..6a96633 100644
--- a/src/animator/SkScriptRuntime.cpp
+++ b/src/animator/SkScriptRuntime.cpp
@@ -1,5 +1,13 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkScriptRuntime.h"
#include "SkScript2.h"
+#include "SkMath.h"
#include "SkParse.h"
#include "SkScriptCallBack.h"
#include "SkString.h"
diff --git a/src/animator/SkScriptRuntime.h b/src/animator/SkScriptRuntime.h
index c864fe4..5de7b30 100644
--- a/src/animator/SkScriptRuntime.h
+++ b/src/animator/SkScriptRuntime.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkScriptRuntime_DEFINED
#define SkScriptRuntime_DEFINED
diff --git a/src/animator/SkScriptTokenizer.cpp b/src/animator/SkScriptTokenizer.cpp
index edcc2af..b2b6e4f 100644
--- a/src/animator/SkScriptTokenizer.cpp
+++ b/src/animator/SkScriptTokenizer.cpp
@@ -1,4 +1,12 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkScript2.h"
+#include "SkData.h"
#include "SkFloatingPoint.h"
#include "SkMath.h"
#include "SkParse.h"
@@ -497,8 +505,9 @@ bool SkScriptEngine2::innerScript(const char** scriptPtr, SkScriptValue2* value)
}
lastPush = false;
continue;
- } else
+ } else {
SkASSERT(token_length(script) > 0);
+ }
}
if (lastPush != false && fTokenLength > 0) {
if (ch == '(') {
@@ -594,7 +603,7 @@ scalarCommon:
}
if (ch == '.') {
if (fTokenLength == 0) {
- SkScriptValue2 scriptValue;
+ SkDEBUGCODE(SkScriptValue2 scriptValue;)
SkDEBUGCODE(scriptValue.fOperand.fObject = NULL);
int tokenLength = token_length(++script);
const char* token = script;
@@ -736,11 +745,12 @@ scalarCommon:
}
if (fStream.getOffset() > 0) {
addToken(kEnd);
+ SkAutoDataUnref data(fStream.copyToData());
#ifdef SK_DEBUG
- decompile((const unsigned char*)fStream.getStream(), fStream.getOffset());
+ decompile(data.bytes(), data.size());
#endif
SkScriptRuntime runtime(fCallBackArray);
- runtime.executeTokens((unsigned char*) fStream.getStream());
+ runtime.executeTokens((unsigned char*) data.bytes());
SkScriptValue2 value1;
runtime.getResult(&value1.fOperand);
value1.fType = fReturnType;
@@ -1029,8 +1039,9 @@ void SkScriptEngine2::processLogicalOp(Op op) {
SkASSERT(fValueStack.top().fType == SkOperand2::kS32); // !!! add error handling, and conversion to int?
addTokenValue(fValueStack.top(), kAccumulator);
fValueStack.pop();
- } else
+ } 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);
@@ -1124,8 +1135,8 @@ bool SkScriptEngine2::processOp() {
else if (value2.fType == SkOperand2::kString)
typeOp = (TypeOp) (typeOp + 2);
SkDynamicMemoryWStream stream;
- SkOperand2::OpType saveType;
- SkBool saveOperand;
+ SkOperand2::OpType saveType = SkOperand2::kNoType;
+ SkBool saveOperand = false;
if (constantOperands) {
fActiveStream = &stream;
saveType = fAccumulatorType;
@@ -1142,11 +1153,12 @@ bool SkScriptEngine2::processOp() {
addToken(typeOp);
if (constantOperands) {
addToken(kEnd);
+ SkAutoDataUnref data(fStream.copyToData());
#ifdef SK_DEBUG
- decompile((const unsigned char*) stream.getStream(), stream.getOffset());
+ decompile(data.bytes(), data.size());
#endif
SkScriptRuntime runtime(fCallBackArray);
- runtime.executeTokens((unsigned char*) stream.getStream());
+ runtime.executeTokens((unsigned char*)data.bytes());
runtime.getResult(&value1.fOperand);
if (attributes->fResultIsBoolean == kResultIsBoolean)
value1.fType = SkOperand2::kS32;
diff --git a/src/animator/SkSnapshot.cpp b/src/animator/SkSnapshot.cpp
index 48d2438..4e78bbd 100644
--- a/src/animator/SkSnapshot.cpp
+++ b/src/animator/SkSnapshot.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkSnapshot.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTypes.h"
diff --git a/src/animator/SkSnapshot.h b/src/animator/SkSnapshot.h
index 7392edc..beb26ca 100644
--- a/src/animator/SkSnapshot.h
+++ b/src/animator/SkSnapshot.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkSnapshot.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSnapShot_DEFINED
#define SkSnapShot_DEFINED
diff --git a/src/animator/SkTDArray_Experimental.h b/src/animator/SkTDArray_Experimental.h
index 94d7871..e598a6d 100644
--- a/src/animator/SkTDArray_Experimental.h
+++ b/src/animator/SkTDArray_Experimental.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkTDArray_Experimental.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkTDArray_Experimental_DEFINED
#define SkTDArray_Experimental_DEFINED
diff --git a/src/animator/SkTextOnPath.cpp b/src/animator/SkTextOnPath.cpp
index 1a06746..e7f7651 100644
--- a/src/animator/SkTextOnPath.cpp
+++ b/src/animator/SkTextOnPath.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkTextOnPath.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTextOnPath.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkTextOnPath.h b/src/animator/SkTextOnPath.h
index 3c78b5b..b0ce234 100644
--- a/src/animator/SkTextOnPath.h
+++ b/src/animator/SkTextOnPath.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkTextOnPath.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkTextOnPath_DEFINED
#define SkTextOnPath_DEFINED
diff --git a/src/animator/SkTextToPath.cpp b/src/animator/SkTextToPath.cpp
index 44036a3..cf78ff5 100644
--- a/src/animator/SkTextToPath.cpp
+++ b/src/animator/SkTextToPath.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkTextToPath.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTextToPath.h"
#include "SkAnimateMaker.h"
diff --git a/src/animator/SkTextToPath.h b/src/animator/SkTextToPath.h
index 6d93239..cb2a15e 100644
--- a/src/animator/SkTextToPath.h
+++ b/src/animator/SkTextToPath.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkTextToPath.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkTextToPath_DEFINED
#define SkTextToPath_DEFINED
diff --git a/src/animator/SkTime.cpp b/src/animator/SkTime.cpp
index a36a95a..35c7eb8 100644
--- a/src/animator/SkTime.cpp
+++ b/src/animator/SkTime.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkTime.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTime.h"
diff --git a/src/animator/SkTypedArray.cpp b/src/animator/SkTypedArray.cpp
index 075c607..e94e57d 100644
--- a/src/animator/SkTypedArray.cpp
+++ b/src/animator/SkTypedArray.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkTypedArray.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTypedArray.h"
diff --git a/src/animator/SkTypedArray.h b/src/animator/SkTypedArray.h
index a658f29..222c8df 100644
--- a/src/animator/SkTypedArray.h
+++ b/src/animator/SkTypedArray.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkTypedArray.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkTypedArray_DEFINED
#define SkTypedArray_DEFINED
diff --git a/src/animator/SkXMLAnimatorWriter.cpp b/src/animator/SkXMLAnimatorWriter.cpp
index b26bc73..6d299b6 100644
--- a/src/animator/SkXMLAnimatorWriter.cpp
+++ b/src/animator/SkXMLAnimatorWriter.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkXMLAnimatorWriter.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkXMLAnimatorWriter.h"
#include "SkAnimator.h"
diff --git a/src/animator/SkXMLAnimatorWriter.h b/src/animator/SkXMLAnimatorWriter.h
index c5830cd..bd6ccf4 100644
--- a/src/animator/SkXMLAnimatorWriter.h
+++ b/src/animator/SkXMLAnimatorWriter.h
@@ -1,19 +1,11 @@
-/* libs/graphics/animator/SkXMLAnimatorWriter.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkXMLAnimatorWriter_DEFINED
#define SkXMLAnimatorWriter_DEFINED
diff --git a/src/core/ARGB32_Clamp_Bilinear_BitmapShader.h b/src/core/ARGB32_Clamp_Bilinear_BitmapShader.h
index c7e23af..e76ab08 100644
--- a/src/core/ARGB32_Clamp_Bilinear_BitmapShader.h
+++ b/src/core/ARGB32_Clamp_Bilinear_BitmapShader.h
@@ -1,4 +1,11 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
class ARGB32_Clamp_Bilinear_BitmapShader : public SkBitmapShader {
public:
ARGB32_Clamp_Bilinear_BitmapShader(const SkBitmap& src)
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
deleted file mode 100644
index 4adde0a..0000000
--- a/src/core/Makefile.am
+++ /dev/null
@@ -1,91 +0,0 @@
-AM_CPPFLAGS = -I$(top_builddir)/include/core
-
-noinst_LIBRARIES = libskia.a
-libskia_a_SOURCES = Sk64.cpp \
-SkAlphaRuns.cpp \
-SkBitmap.cpp \
-SkBitmapProcShader.cpp \
-SkBitmapProcState.cpp \
-SkBitmapProcState_matrixProcs.cpp \
-SkBitmapSampler.cpp \
-SkBitmapShader.cpp \
-SkBitmap_scroll.cpp \
-SkBlitRow_D16.cpp \
-SkBlitRow_D4444.cpp \
-SkBlitter.cpp \
-SkBlitter_4444.cpp \
-SkBlitter_A1.cpp \
-SkBlitter_A8.cpp \
-SkBlitter_ARGB32.cpp \
-SkBlitter_RGB16.cpp \
-SkBlitter_Sprite.cpp \
-SkBuffer.cpp \
-SkCanvas.cpp \
-SkChunkAlloc.cpp \
-SkColor.cpp \
-SkColorFilter.cpp \
-SkColorTable.cpp \
-SkComposeShader.cpp \
-SkConcaveToTriangles.cpp \
-SkCordic.cpp \
-skCubicClipper.cpp \
-SkDebug.cpp \
-SkDebug_stdio.cpp \
-SkDeque.cpp \
-SkDevice.cpp \
-SkDither.cpp \
-SkDraw.cpp \
-SkEdge.cpp \
-SkFilterProc.cpp \
-SkFlattenable.cpp \
-SkFloat.cpp \
-SkFloatBits.cpp \
-SkGeometry.cpp \
-SkGlobals.cpp \
-SkGlyphCache.cpp \
-SkGraphics.cpp \
-SkMMapStream.cpp \
-SkMask.cpp \
-SkMaskFilter.cpp \
-SkMath.cpp \
-SkMatrix.cpp \
-SkMemory_stdlib.cpp \
-SkPackBits.cpp \
-SkPaint.cpp \
-SkPath.cpp \
-SkPathEffect.cpp \
-SkPathHeap.cpp \
-SkPathMeasure.cpp \
-SkPicture.cpp \
-SkPictureFlat.cpp \
-SkPicturePlayback.cpp \
-SkPictureRecord.cpp \
-SkPixelRef.cpp \
-SkPoint.cpp \
-SkProcSpriteBlitter.cpp \
-SkPtrRecorder.cpp \
-SkRasterizer.cpp \
-SkRect.cpp \
-SkRefCnt.cpp \
-SkRegion.cpp \
-SkRegion_path.cpp \
-SkScalar.cpp \
-SkScalerContext.cpp \
-SkScan.cpp \
-SkScan_AntiPath.cpp \
-SkScan_Antihair.cpp \
-SkScan_Hairline.cpp \
-SkScan_Path.cpp \
-SkShader.cpp \
-SkSpriteBlitter_ARGB32.cpp \
-SkSpriteBlitter_RGB16.cpp \
-SkStream.cpp \
-SkString.cpp \
-SkStroke.cpp \
-SkStrokerPriv.cpp \
-SkTSearch.cpp \
-SkTypeface.cpp \
-SkUnPreMultiply.cpp \
-SkUtils.cpp \
-SkWriter32.cpp \
-SkXfermode.cpp
diff --git a/src/core/Sk64.cpp b/src/core/Sk64.cpp
index 4381b50..0d74904 100644
--- a/src/core/Sk64.cpp
+++ b/src/core/Sk64.cpp
@@ -1,21 +1,14 @@
-/* libs/corecg/Sk64.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "Sk64.h"
+#include "SkMath.h"
#define shift_left(hi, lo) \
hi = (hi << 1) | (lo >> 31); \
diff --git a/src/core/SkAAClip.cpp b/src/core/SkAAClip.cpp
new file mode 100644
index 0000000..096fd6b
--- /dev/null
+++ b/src/core/SkAAClip.cpp
@@ -0,0 +1,2134 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkAAClip.h"
+#include "SkBlitter.h"
+#include "SkColorPriv.h"
+#include "SkPath.h"
+#include "SkScan.h"
+#include "SkThread.h"
+#include "SkUtils.h"
+
+class AutoAAClipValidate {
+public:
+ AutoAAClipValidate(const SkAAClip& clip) : fClip(clip) {
+ fClip.validate();
+ }
+ ~AutoAAClipValidate() {
+ fClip.validate();
+ }
+private:
+ const SkAAClip& fClip;
+};
+
+#ifdef SK_DEBUG
+ #define AUTO_AACLIP_VALIDATE(clip) AutoAAClipValidate acv(clip)
+#else
+ #define AUTO_AACLIP_VALIDATE(clip)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+#define kMaxInt32 0x7FFFFFFF
+
+static inline bool x_in_rect(int x, const SkIRect& rect) {
+ return (unsigned)(x - rect.fLeft) < (unsigned)rect.width();
+}
+
+static inline bool y_in_rect(int y, const SkIRect& rect) {
+ return (unsigned)(y - rect.fTop) < (unsigned)rect.height();
+}
+
+/*
+ * Data runs are packed [count, alpha]
+ */
+
+struct SkAAClip::YOffset {
+ int32_t fY;
+ uint32_t fOffset;
+};
+
+struct SkAAClip::RunHead {
+ int32_t fRefCnt;
+ int32_t fRowCount;
+ int32_t fDataSize;
+
+ YOffset* yoffsets() {
+ return (YOffset*)((char*)this + sizeof(RunHead));
+ }
+ const YOffset* yoffsets() const {
+ return (const YOffset*)((const char*)this + sizeof(RunHead));
+ }
+ uint8_t* data() {
+ return (uint8_t*)(this->yoffsets() + fRowCount);
+ }
+ const uint8_t* data() const {
+ return (const uint8_t*)(this->yoffsets() + fRowCount);
+ }
+
+ static RunHead* Alloc(int rowCount, size_t dataSize) {
+ size_t size = sizeof(RunHead) + rowCount * sizeof(YOffset) + dataSize;
+ RunHead* head = (RunHead*)sk_malloc_throw(size);
+ head->fRefCnt = 1;
+ head->fRowCount = rowCount;
+ head->fDataSize = dataSize;
+ return head;
+ }
+
+ static int ComputeRowSizeForWidth(int width) {
+ // 2 bytes per segment, where each segment can store up to 255 for count
+ int segments = 0;
+ while (width > 0) {
+ segments += 1;
+ int n = SkMin32(width, 255);
+ width -= n;
+ }
+ return segments * 2; // each segment is row[0] + row[1] (n + alpha)
+ }
+
+ static RunHead* AllocRect(const SkIRect& bounds) {
+ SkASSERT(!bounds.isEmpty());
+ int width = bounds.width();
+ size_t rowSize = ComputeRowSizeForWidth(width);
+ RunHead* head = RunHead::Alloc(1, rowSize);
+ YOffset* yoff = head->yoffsets();
+ yoff->fY = bounds.height() - 1;
+ yoff->fOffset = 0;
+ uint8_t* row = head->data();
+ while (width > 0) {
+ int n = SkMin32(width, 255);
+ row[0] = n;
+ row[1] = 0xFF;
+ width -= n;
+ row += 2;
+ }
+ return head;
+ }
+};
+
+class SkAAClip::Iter {
+public:
+ Iter(const SkAAClip&);
+
+ bool done() const { return fDone; }
+ int top() const { return fTop; }
+ int bottom() const { return fBottom; }
+ const uint8_t* data() const { return fData; }
+ void next();
+
+private:
+ const YOffset* fCurrYOff;
+ const YOffset* fStopYOff;
+ const uint8_t* fData;
+
+ int fTop, fBottom;
+ bool fDone;
+};
+
+SkAAClip::Iter::Iter(const SkAAClip& clip) {
+ if (clip.isEmpty()) {
+ fDone = true;
+ fTop = fBottom = clip.fBounds.fBottom;
+ fData = NULL;
+ return;
+ }
+
+ const RunHead* head = clip.fRunHead;
+ fCurrYOff = head->yoffsets();
+ fStopYOff = fCurrYOff + head->fRowCount;
+ fData = head->data() + fCurrYOff->fOffset;
+
+ // setup first value
+ fTop = clip.fBounds.fTop;
+ fBottom = clip.fBounds.fTop + fCurrYOff->fY + 1;
+ fDone = false;
+}
+
+void SkAAClip::Iter::next() {
+ if (!fDone) {
+ const YOffset* prev = fCurrYOff;
+ const YOffset* curr = prev + 1;
+ SkASSERT(curr <= fStopYOff);
+
+ fTop = fBottom;
+ if (curr >= fStopYOff) {
+ fDone = true;
+ fBottom = kMaxInt32;
+ fData = NULL;
+ } else {
+ fBottom += curr->fY - prev->fY;
+ fData += curr->fOffset - prev->fOffset;
+ fCurrYOff = curr;
+ }
+ }
+}
+
+#ifdef SK_DEBUG
+// assert we're exactly width-wide, and then return the number of bytes used
+static size_t compute_row_length(const uint8_t row[], int width) {
+ const uint8_t* origRow = row;
+ while (width > 0) {
+ int n = row[0];
+ SkASSERT(n > 0);
+ SkASSERT(n <= width);
+ row += 2;
+ width -= n;
+ }
+ SkASSERT(0 == width);
+ return row - origRow;
+}
+
+void SkAAClip::validate() const {
+ if (NULL == fRunHead) {
+ SkASSERT(fBounds.isEmpty());
+ return;
+ }
+
+ const RunHead* head = fRunHead;
+ SkASSERT(head->fRefCnt > 0);
+ SkASSERT(head->fRowCount > 0);
+ SkASSERT(head->fDataSize > 0);
+
+ const YOffset* yoff = head->yoffsets();
+ const YOffset* ystop = yoff + head->fRowCount;
+ const int lastY = fBounds.height() - 1;
+
+ // Y and offset must be monotonic
+ int prevY = -1;
+ int32_t prevOffset = -1;
+ while (yoff < ystop) {
+ SkASSERT(prevY < yoff->fY);
+ SkASSERT(yoff->fY <= lastY);
+ prevY = yoff->fY;
+ SkASSERT(prevOffset < (int32_t)yoff->fOffset);
+ prevOffset = yoff->fOffset;
+ const uint8_t* row = head->data() + yoff->fOffset;
+ size_t rowLength = compute_row_length(row, fBounds.width());
+ SkASSERT(yoff->fOffset + rowLength <= (size_t) head->fDataSize);
+ yoff += 1;
+ }
+ // check the last entry;
+ --yoff;
+ SkASSERT(yoff->fY == lastY);
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void count_left_right_zeros(const uint8_t* row, int width,
+ int* leftZ, int* riteZ) {
+ int zeros = 0;
+ do {
+ if (row[1]) {
+ break;
+ }
+ int n = row[0];
+ SkASSERT(n > 0);
+ SkASSERT(n <= width);
+ zeros += n;
+ row += 2;
+ width -= n;
+ } while (width > 0);
+ *leftZ = zeros;
+
+ zeros = 0;
+ while (width > 0) {
+ int n = row[0];
+ SkASSERT(n > 0);
+ if (0 == row[1]) {
+ zeros += n;
+ } else {
+ zeros = 0;
+ }
+ row += 2;
+ width -= n;
+ }
+ *riteZ = zeros;
+}
+
+#ifdef SK_DEBUG
+static void test_count_left_right_zeros() {
+ static bool gOnce;
+ if (gOnce) {
+ return;
+ }
+ gOnce = true;
+
+ const uint8_t data0[] = { 0, 0, 10, 0xFF };
+ const uint8_t data1[] = { 0, 0, 5, 0xFF, 2, 0, 3, 0xFF };
+ const uint8_t data2[] = { 7, 0, 5, 0, 2, 0, 3, 0xFF };
+ const uint8_t data3[] = { 0, 5, 5, 0xFF, 2, 0, 3, 0 };
+ const uint8_t data4[] = { 2, 3, 2, 0, 5, 0xFF, 3, 0 };
+ const uint8_t data5[] = { 10, 0, 10, 0 };
+ const uint8_t data6[] = { 2, 2, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
+
+ const uint8_t* array[] = {
+ data0, data1, data2, data3, data4, data5, data6
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
+ const uint8_t* data = array[i];
+ const int expectedL = *data++;
+ const int expectedR = *data++;
+ int L = 12345, R = 12345;
+ count_left_right_zeros(data, 10, &L, &R);
+ SkASSERT(expectedL == L);
+ SkASSERT(expectedR == R);
+ }
+}
+#endif
+
+// modify row in place, trimming off (zeros) from the left and right sides.
+// return the number of bytes that were completely eliminated from the left
+static int trim_row_left_right(uint8_t* row, int width, int leftZ, int riteZ) {
+ int trim = 0;
+ while (leftZ > 0) {
+ SkASSERT(0 == row[1]);
+ int n = row[0];
+ SkASSERT(n > 0);
+ SkASSERT(n <= width);
+ width -= n;
+ row += 2;
+ if (n > leftZ) {
+ row[-2] = n - leftZ;
+ break;
+ }
+ trim += 2;
+ leftZ -= n;
+ SkASSERT(leftZ >= 0);
+ }
+
+ if (riteZ) {
+ // walk row to the end, and then we'll back up to trim riteZ
+ while (width > 0) {
+ int n = row[0];
+ SkASSERT(n <= width);
+ width -= n;
+ row += 2;
+ }
+ // now skip whole runs of zeros
+ do {
+ row -= 2;
+ SkASSERT(0 == row[1]);
+ int n = row[0];
+ SkASSERT(n > 0);
+ if (n > riteZ) {
+ row[0] = n - riteZ;
+ break;
+ }
+ riteZ -= n;
+ SkASSERT(riteZ >= 0);
+ } while (riteZ > 0);
+ }
+
+ return trim;
+}
+
+#ifdef SK_DEBUG
+// assert that this row is exactly this width
+static void assert_row_width(const uint8_t* row, int width) {
+ while (width > 0) {
+ int n = row[0];
+ SkASSERT(n > 0);
+ SkASSERT(n <= width);
+ width -= n;
+ row += 2;
+ }
+ SkASSERT(0 == width);
+}
+
+static void test_trim_row_left_right() {
+ static bool gOnce;
+ if (gOnce) {
+ return;
+ }
+ gOnce = true;
+
+ uint8_t data0[] = { 0, 0, 0, 10, 10, 0xFF };
+ uint8_t data1[] = { 2, 0, 0, 10, 5, 0, 2, 0, 3, 0xFF };
+ uint8_t data2[] = { 5, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF };
+ uint8_t data3[] = { 6, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF };
+ uint8_t data4[] = { 0, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
+ uint8_t data5[] = { 1, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
+ uint8_t data6[] = { 0, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
+ uint8_t data7[] = { 1, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
+ uint8_t data8[] = { 2, 2, 2, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
+ uint8_t data9[] = { 5, 2, 4, 10, 2, 0, 2, 0, 2, 0, 2, 0xFF, 2, 0 };
+ uint8_t data10[] ={ 74, 0, 4, 150, 9, 0, 65, 0, 76, 0xFF };
+
+ uint8_t* array[] = {
+ data0, data1, data2, data3, data4,
+ data5, data6, data7, data8, data9,
+ data10
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
+ uint8_t* data = array[i];
+ const int trimL = *data++;
+ const int trimR = *data++;
+ const int expectedSkip = *data++;
+ const int origWidth = *data++;
+ assert_row_width(data, origWidth);
+ int skip = trim_row_left_right(data, origWidth, trimL, trimR);
+ SkASSERT(expectedSkip == skip);
+ int expectedWidth = origWidth - trimL - trimR;
+ assert_row_width(data + skip, expectedWidth);
+ }
+}
+#endif
+
+bool SkAAClip::trimLeftRight() {
+ SkDEBUGCODE(test_trim_row_left_right();)
+
+ if (this->isEmpty()) {
+ return false;
+ }
+
+ AUTO_AACLIP_VALIDATE(*this);
+
+ const int width = fBounds.width();
+ RunHead* head = fRunHead;
+ YOffset* yoff = head->yoffsets();
+ YOffset* stop = yoff + head->fRowCount;
+ uint8_t* base = head->data();
+
+ int leftZeros = width;
+ int riteZeros = width;
+ while (yoff < stop) {
+ int L, R;
+ count_left_right_zeros(base + yoff->fOffset, width, &L, &R);
+ if (L < leftZeros) {
+ leftZeros = L;
+ }
+ if (R < riteZeros) {
+ riteZeros = R;
+ }
+ if (0 == (leftZeros | riteZeros)) {
+ // no trimming to do
+ return true;
+ }
+ yoff += 1;
+ }
+
+ SkASSERT(leftZeros || riteZeros);
+ if (width == (leftZeros + riteZeros)) {
+ return this->setEmpty();
+ }
+
+ this->validate();
+
+ fBounds.fLeft += leftZeros;
+ fBounds.fRight -= riteZeros;
+ SkASSERT(!fBounds.isEmpty());
+
+ // For now we don't realloc the storage (for time), we just shrink in place
+ // This means we don't have to do any memmoves either, since we can just
+ // play tricks with the yoff->fOffset for each row
+ yoff = head->yoffsets();
+ while (yoff < stop) {
+ uint8_t* row = base + yoff->fOffset;
+ SkDEBUGCODE((void)compute_row_length(row, width);)
+ yoff->fOffset += trim_row_left_right(row, width, leftZeros, riteZeros);
+ SkDEBUGCODE((void)compute_row_length(base + yoff->fOffset, width - leftZeros - riteZeros);)
+ yoff += 1;
+ }
+ return true;
+}
+
+static bool row_is_all_zeros(const uint8_t* row, int width) {
+ SkASSERT(width > 0);
+ do {
+ if (row[1]) {
+ return false;
+ }
+ int n = row[0];
+ SkASSERT(n <= width);
+ width -= n;
+ row += 2;
+ } while (width > 0);
+ SkASSERT(0 == width);
+ return true;
+}
+
+bool SkAAClip::trimTopBottom() {
+ if (this->isEmpty()) {
+ return false;
+ }
+
+ this->validate();
+
+ const int width = fBounds.width();
+ RunHead* head = fRunHead;
+ YOffset* yoff = head->yoffsets();
+ YOffset* stop = yoff + head->fRowCount;
+ const uint8_t* base = head->data();
+
+ // Look to trim away empty rows from the top.
+ //
+ int skip = 0;
+ while (yoff < stop) {
+ const uint8_t* data = base + yoff->fOffset;
+ if (!row_is_all_zeros(data, width)) {
+ break;
+ }
+ skip += 1;
+ yoff += 1;
+ }
+ SkASSERT(skip <= head->fRowCount);
+ if (skip == head->fRowCount) {
+ return this->setEmpty();
+ }
+ if (skip > 0) {
+ // adjust fRowCount and fBounds.fTop, and slide all the data up
+ // as we remove [skip] number of YOffset entries
+ yoff = head->yoffsets();
+ int dy = yoff[skip - 1].fY + 1;
+ for (int i = skip; i < head->fRowCount; ++i) {
+ SkASSERT(yoff[i].fY >= dy);
+ yoff[i].fY -= dy;
+ }
+ YOffset* dst = head->yoffsets();
+ size_t size = head->fRowCount * sizeof(YOffset) + head->fDataSize;
+ memmove(dst, dst + skip, size - skip * sizeof(YOffset));
+
+ fBounds.fTop += dy;
+ SkASSERT(!fBounds.isEmpty());
+ head->fRowCount -= skip;
+ SkASSERT(head->fRowCount > 0);
+
+ this->validate();
+ // need to reset this after the memmove
+ base = head->data();
+ }
+
+ // Look to trim away empty rows from the bottom.
+ // We know that we have at least one non-zero row, so we can just walk
+ // backwards without checking for running past the start.
+ //
+ stop = yoff = head->yoffsets() + head->fRowCount;
+ do {
+ yoff -= 1;
+ } while (row_is_all_zeros(base + yoff->fOffset, width));
+ skip = stop - yoff - 1;
+ SkASSERT(skip >= 0 && skip < head->fRowCount);
+ if (skip > 0) {
+ // removing from the bottom is easier than from the top, as we don't
+ // have to adjust any of the Y values, we just have to trim the array
+ memmove(stop - skip, stop, head->fDataSize);
+
+ fBounds.fBottom = fBounds.fTop + yoff->fY + 1;
+ SkASSERT(!fBounds.isEmpty());
+ head->fRowCount -= skip;
+ SkASSERT(head->fRowCount > 0);
+ }
+ this->validate();
+
+ return true;
+}
+
+// can't validate before we're done, since trimming is part of the process of
+// making us valid after the Builder. Since we build from top to bottom, its
+// possible our fBounds.fBottom is bigger than our last scanline of data, so
+// we trim fBounds.fBottom back up.
+//
+// TODO: check for duplicates in X and Y to further compress our data
+//
+bool SkAAClip::trimBounds() {
+ if (this->isEmpty()) {
+ return false;
+ }
+
+ const RunHead* head = fRunHead;
+ const YOffset* yoff = head->yoffsets();
+
+ SkASSERT(head->fRowCount > 0);
+ const YOffset& lastY = yoff[head->fRowCount - 1];
+ SkASSERT(lastY.fY + 1 <= fBounds.height());
+ fBounds.fBottom = fBounds.fTop + lastY.fY + 1;
+ SkASSERT(lastY.fY + 1 == fBounds.height());
+ SkASSERT(!fBounds.isEmpty());
+
+ return this->trimTopBottom() && this->trimLeftRight();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkAAClip::freeRuns() {
+ if (fRunHead) {
+ SkASSERT(fRunHead->fRefCnt >= 1);
+ if (1 == sk_atomic_dec(&fRunHead->fRefCnt)) {
+ sk_free(fRunHead);
+ }
+ }
+}
+
+SkAAClip::SkAAClip() {
+ fBounds.setEmpty();
+ fRunHead = NULL;
+}
+
+SkAAClip::SkAAClip(const SkAAClip& src) {
+ SkDEBUGCODE(fBounds.setEmpty();) // need this for validate
+ fRunHead = NULL;
+ *this = src;
+}
+
+SkAAClip::~SkAAClip() {
+ this->freeRuns();
+}
+
+SkAAClip& SkAAClip::operator=(const SkAAClip& src) {
+ AUTO_AACLIP_VALIDATE(*this);
+ src.validate();
+
+ if (this != &src) {
+ this->freeRuns();
+ fBounds = src.fBounds;
+ fRunHead = src.fRunHead;
+ if (fRunHead) {
+ sk_atomic_inc(&fRunHead->fRefCnt);
+ }
+ }
+ return *this;
+}
+
+bool operator==(const SkAAClip& a, const SkAAClip& b) {
+ a.validate();
+ b.validate();
+
+ if (&a == &b) {
+ return true;
+ }
+ if (a.fBounds != b.fBounds) {
+ return false;
+ }
+
+ const SkAAClip::RunHead* ah = a.fRunHead;
+ const SkAAClip::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 (!a.fRunHead || !b.fRunHead) {
+ return false;
+ }
+
+ return ah->fRowCount == bh->fRowCount &&
+ ah->fDataSize == bh->fDataSize &&
+ !memcmp(ah->data(), bh->data(), ah->fDataSize);
+}
+
+void SkAAClip::swap(SkAAClip& other) {
+ AUTO_AACLIP_VALIDATE(*this);
+ other.validate();
+
+ SkTSwap(fBounds, other.fBounds);
+ SkTSwap(fRunHead, other.fRunHead);
+}
+
+bool SkAAClip::set(const SkAAClip& src) {
+ *this = src;
+ return !this->isEmpty();
+}
+
+bool SkAAClip::setEmpty() {
+ this->freeRuns();
+ fBounds.setEmpty();
+ fRunHead = NULL;
+ return false;
+}
+
+bool SkAAClip::setRect(const SkIRect& bounds) {
+ if (bounds.isEmpty()) {
+ return this->setEmpty();
+ }
+
+ AUTO_AACLIP_VALIDATE(*this);
+
+#if 0
+ SkRect r;
+ r.set(bounds);
+ SkPath path;
+ path.addRect(r);
+ return this->setPath(path);
+#else
+ this->freeRuns();
+ fBounds = bounds;
+ fRunHead = RunHead::AllocRect(bounds);
+ SkASSERT(!this->isEmpty());
+ return true;
+#endif
+}
+
+bool SkAAClip::setRect(const SkRect& r, bool doAA) {
+ if (r.isEmpty()) {
+ return this->setEmpty();
+ }
+
+ AUTO_AACLIP_VALIDATE(*this);
+
+ // TODO: special case this
+
+ SkPath path;
+ path.addRect(r);
+ return this->setPath(path, NULL, doAA);
+}
+
+static void append_run(SkTDArray<uint8_t>& array, uint8_t value, int count) {
+ SkASSERT(count >= 0);
+ while (count > 0) {
+ int n = count;
+ if (n > 255) {
+ n = 255;
+ }
+ uint8_t* data = array.append(2);
+ data[0] = n;
+ data[1] = value;
+ count -= n;
+ }
+}
+
+bool SkAAClip::setRegion(const SkRegion& rgn) {
+ if (rgn.isEmpty()) {
+ return this->setEmpty();
+ }
+ if (rgn.isRect()) {
+ return this->setRect(rgn.getBounds());
+ }
+
+#if 0
+ SkAAClip clip;
+ SkRegion::Iterator iter(rgn);
+ for (; !iter.done(); iter.next()) {
+ clip.op(iter.rect(), SkRegion::kUnion_Op);
+ }
+ this->swap(clip);
+ return !this->isEmpty();
+#else
+ const SkIRect& bounds = rgn.getBounds();
+ const int offsetX = bounds.fLeft;
+ const int offsetY = bounds.fTop;
+
+ SkTDArray<YOffset> yArray;
+ SkTDArray<uint8_t> xArray;
+
+ yArray.setReserve(SkMin32(bounds.height(), 1024));
+ xArray.setReserve(SkMin32(bounds.width() * 128, 64 * 1024));
+
+ SkRegion::Iterator iter(rgn);
+ int prevRight = 0;
+ int prevBot = 0;
+ YOffset* currY = NULL;
+
+ for (; !iter.done(); iter.next()) {
+ const SkIRect& r = iter.rect();
+ SkASSERT(bounds.contains(r));
+
+ int bot = r.fBottom - offsetY;
+ SkASSERT(bot >= prevBot);
+ if (bot > prevBot) {
+ if (currY) {
+ // flush current row
+ append_run(xArray, 0, bounds.width() - prevRight);
+ }
+ // did we introduce an empty-gap from the prev row?
+ int top = r.fTop - offsetY;
+ if (top > prevBot) {
+ currY = yArray.append();
+ currY->fY = top - 1;
+ currY->fOffset = xArray.count();
+ append_run(xArray, 0, bounds.width());
+ }
+ // create a new record for this Y value
+ currY = yArray.append();
+ currY->fY = bot - 1;
+ currY->fOffset = xArray.count();
+ prevRight = 0;
+ prevBot = bot;
+ }
+
+ int x = r.fLeft - offsetX;
+ append_run(xArray, 0, x - prevRight);
+
+ int w = r.fRight - r.fLeft;
+ append_run(xArray, 0xFF, w);
+ prevRight = x + w;
+ SkASSERT(prevRight <= bounds.width());
+ }
+ // flush last row
+ append_run(xArray, 0, bounds.width() - prevRight);
+
+ // now pack everything into a RunHead
+ RunHead* head = RunHead::Alloc(yArray.count(), xArray.bytes());
+ memcpy(head->yoffsets(), yArray.begin(), yArray.bytes());
+ memcpy(head->data(), xArray.begin(), xArray.bytes());
+
+ this->setEmpty();
+ fBounds = bounds;
+ fRunHead = head;
+ this->validate();
+ return true;
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+const uint8_t* SkAAClip::findRow(int y, int* lastYForRow) const {
+ SkASSERT(fRunHead);
+
+ if (!y_in_rect(y, fBounds)) {
+ return NULL;
+ }
+ y -= fBounds.y(); // our yoffs values are relative to the top
+
+ const YOffset* yoff = fRunHead->yoffsets();
+ while (yoff->fY < y) {
+ yoff += 1;
+ SkASSERT(yoff - fRunHead->yoffsets() < fRunHead->fRowCount);
+ }
+
+ if (lastYForRow) {
+ *lastYForRow = fBounds.y() + yoff->fY;
+ }
+ return fRunHead->data() + yoff->fOffset;
+}
+
+const uint8_t* SkAAClip::findX(const uint8_t data[], int x, int* initialCount) const {
+ SkASSERT(x_in_rect(x, fBounds));
+ x -= fBounds.x();
+
+ // first skip up to X
+ for (;;) {
+ int n = data[0];
+ if (x < n) {
+ *initialCount = n - x;
+ break;
+ }
+ data += 2;
+ x -= n;
+ }
+ return data;
+}
+
+bool SkAAClip::quickContains(int left, int top, int right, int bottom) const {
+ if (this->isEmpty()) {
+ return false;
+ }
+ if (!fBounds.contains(left, top, right, bottom)) {
+ return false;
+ }
+#if 0
+ if (this->isRect()) {
+ return true;
+ }
+#endif
+
+ int lastY;
+ const uint8_t* row = this->findRow(top, &lastY);
+ if (lastY < bottom) {
+ return false;
+ }
+ // now just need to check in X
+ int count;
+ row = this->findX(row, left, &count);
+#if 0
+ return count >= (right - left) && 0xFF == row[1];
+#else
+ int rectWidth = right - left;
+ while (0xFF == row[1]) {
+ if (count >= rectWidth) {
+ return true;
+ }
+ rectWidth -= count;
+ row += 2;
+ count = row[0];
+ }
+ return false;
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class SkAAClip::Builder {
+ SkIRect fBounds;
+ struct Row {
+ int fY;
+ int fWidth;
+ SkTDArray<uint8_t>* fData;
+ };
+ SkTDArray<Row> fRows;
+ Row* fCurrRow;
+ int fPrevY;
+ int fWidth;
+ int fMinY;
+
+public:
+ Builder(const SkIRect& bounds) : fBounds(bounds) {
+ fPrevY = -1;
+ fWidth = bounds.width();
+ fCurrRow = NULL;
+ fMinY = bounds.fTop;
+ }
+
+ ~Builder() {
+ Row* row = fRows.begin();
+ Row* stop = fRows.end();
+ while (row < stop) {
+ delete row->fData;
+ row += 1;
+ }
+ }
+
+ const SkIRect& getBounds() const { return fBounds; }
+
+ void addRun(int x, int y, U8CPU alpha, int count) {
+ SkASSERT(count > 0);
+ SkASSERT(fBounds.contains(x, y));
+ SkASSERT(fBounds.contains(x + count - 1, y));
+
+ x -= fBounds.left();
+ y -= fBounds.top();
+
+ Row* row = fCurrRow;
+ if (y != fPrevY) {
+ SkASSERT(y > fPrevY);
+ fPrevY = y;
+ row = this->flushRow(true);
+ row->fY = y;
+ row->fWidth = 0;
+ SkASSERT(row->fData);
+ SkASSERT(0 == row->fData->count());
+ fCurrRow = row;
+ }
+
+ SkASSERT(row->fWidth <= x);
+ SkASSERT(row->fWidth < fBounds.width());
+
+ SkTDArray<uint8_t>& data = *row->fData;
+
+ int gap = x - row->fWidth;
+ if (gap) {
+ AppendRun(data, 0, gap);
+ row->fWidth += gap;
+ SkASSERT(row->fWidth < fBounds.width());
+ }
+
+ AppendRun(data, alpha, count);
+ row->fWidth += count;
+ SkASSERT(row->fWidth <= fBounds.width());
+ }
+
+ void addColumn(int x, int y, U8CPU alpha, int height) {
+ SkASSERT(fBounds.contains(x, y + height - 1));
+
+ this->addRun(x, y, alpha, 1);
+ this->flushRowH(fCurrRow);
+ y -= fBounds.fTop;
+ SkASSERT(y == fCurrRow->fY);
+ fCurrRow->fY = y + height - 1;
+ }
+
+ void addRectRun(int x, int y, int width, int height) {
+ SkASSERT(fBounds.contains(x + width - 1, y + height - 1));
+ this->addRun(x, y, 0xFF, width);
+
+ // we assum the rect must be all we'll see for these scanlines
+ // so we ensure our row goes all the way to our right
+ this->flushRowH(fCurrRow);
+
+ y -= fBounds.fTop;
+ SkASSERT(y == fCurrRow->fY);
+ fCurrRow->fY = y + height - 1;
+ }
+
+ void addAntiRectRun(int x, int y, int width, int height,
+ SkAlpha leftAlpha, SkAlpha rightAlpha) {
+ SkASSERT(fBounds.contains(x + width - 1 +
+ (leftAlpha > 0 ? 1 : 0) + (rightAlpha > 0 ? 1 : 0),
+ y + height - 1));
+ SkASSERT(width >= 0);
+
+ // Conceptually we're always adding 3 runs, but we should
+ // merge or omit them if possible.
+ if (leftAlpha == 0xFF) {
+ width++;
+ } else if (leftAlpha > 0) {
+ this->addRun(x++, y, leftAlpha, 1);
+ }
+ if (rightAlpha == 0xFF) {
+ width++;
+ }
+ if (width > 0) {
+ this->addRun(x, y, 0xFF, width);
+ }
+ if (rightAlpha > 0 && rightAlpha < 255) {
+ this->addRun(x + width, y, rightAlpha, 1);
+ }
+
+ // we assume the rect must be all we'll see for these scanlines
+ // so we ensure our row goes all the way to our right
+ this->flushRowH(fCurrRow);
+
+ y -= fBounds.fTop;
+ SkASSERT(y == fCurrRow->fY);
+ fCurrRow->fY = y + height - 1;
+ }
+
+ bool finish(SkAAClip* target) {
+ this->flushRow(false);
+
+ const Row* row = fRows.begin();
+ const Row* stop = fRows.end();
+
+ size_t dataSize = 0;
+ while (row < stop) {
+ dataSize += row->fData->count();
+ row += 1;
+ }
+
+ if (0 == dataSize) {
+ return target->setEmpty();
+ }
+
+ SkASSERT(fMinY >= fBounds.fTop);
+ SkASSERT(fMinY < fBounds.fBottom);
+ int adjustY = fMinY - fBounds.fTop;
+ fBounds.fTop = fMinY;
+
+ RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
+ YOffset* yoffset = head->yoffsets();
+ uint8_t* data = head->data();
+ uint8_t* baseData = data;
+
+ row = fRows.begin();
+ SkDEBUGCODE(int prevY = row->fY - 1;)
+ while (row < stop) {
+ SkASSERT(prevY < row->fY); // must be monotonic
+ SkDEBUGCODE(prevY = row->fY);
+
+ yoffset->fY = row->fY - adjustY;
+ yoffset->fOffset = data - baseData;
+ yoffset += 1;
+
+ size_t n = row->fData->count();
+ memcpy(data, row->fData->begin(), n);
+#ifdef SK_DEBUG
+ size_t bytesNeeded = compute_row_length(data, fBounds.width());
+ SkASSERT(bytesNeeded == n);
+#endif
+ data += n;
+
+ row += 1;
+ }
+
+ target->freeRuns();
+ target->fBounds = fBounds;
+ target->fRunHead = head;
+ return target->trimBounds();
+ }
+
+ void dump() {
+ this->validate();
+ int y;
+ for (y = 0; y < fRows.count(); ++y) {
+ const Row& row = fRows[y];
+ SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth);
+ const SkTDArray<uint8_t>& data = *row.fData;
+ int count = data.count();
+ SkASSERT(!(count & 1));
+ const uint8_t* ptr = data.begin();
+ for (int x = 0; x < count; x += 2) {
+ SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]);
+ ptr += 2;
+ }
+ SkDebugf("\n");
+ }
+ }
+
+ void validate() {
+#ifdef SK_DEBUG
+ int prevY = -1;
+ for (int i = 0; i < fRows.count(); ++i) {
+ const Row& row = fRows[i];
+ SkASSERT(prevY < row.fY);
+ SkASSERT(fWidth == row.fWidth);
+ int count = row.fData->count();
+ const uint8_t* ptr = row.fData->begin();
+ SkASSERT(!(count & 1));
+ int w = 0;
+ for (int x = 0; x < count; x += 2) {
+ int n = ptr[0];
+ SkASSERT(n > 0);
+ w += n;
+ SkASSERT(w <= fWidth);
+ ptr += 2;
+ }
+ SkASSERT(w == fWidth);
+ prevY = row.fY;
+ }
+#endif
+ }
+
+ // only called by BuilderBlitter
+ void setMinY(int y) {
+ fMinY = y;
+ }
+
+private:
+ void flushRowH(Row* row) {
+ // flush current row if needed
+ if (row->fWidth < fWidth) {
+ AppendRun(*row->fData, 0, fWidth - row->fWidth);
+ row->fWidth = fWidth;
+ }
+ }
+
+ Row* flushRow(bool readyForAnother) {
+ Row* next = NULL;
+ int count = fRows.count();
+ if (count > 0) {
+ this->flushRowH(&fRows[count - 1]);
+ }
+ if (count > 1) {
+ // are our last two runs the same?
+ Row* prev = &fRows[count - 2];
+ Row* curr = &fRows[count - 1];
+ SkASSERT(prev->fWidth == fWidth);
+ SkASSERT(curr->fWidth == fWidth);
+ if (*prev->fData == *curr->fData) {
+ prev->fY = curr->fY;
+ if (readyForAnother) {
+ curr->fData->rewind();
+ next = curr;
+ } else {
+ delete curr->fData;
+ fRows.removeShuffle(count - 1);
+ }
+ } else {
+ if (readyForAnother) {
+ next = fRows.append();
+ next->fData = new SkTDArray<uint8_t>;
+ }
+ }
+ } else {
+ if (readyForAnother) {
+ next = fRows.append();
+ next->fData = new SkTDArray<uint8_t>;
+ }
+ }
+ return next;
+ }
+
+ static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) {
+ do {
+ int n = count;
+ if (n > 255) {
+ n = 255;
+ }
+ uint8_t* ptr = data.append(2);
+ ptr[0] = n;
+ ptr[1] = alpha;
+ count -= n;
+ } while (count > 0);
+ }
+};
+
+class SkAAClip::BuilderBlitter : public SkBlitter {
+public:
+ BuilderBlitter(Builder* builder) {
+ fBuilder = builder;
+ fLeft = builder->getBounds().fLeft;
+ fRight = builder->getBounds().fRight;
+ fMinY = SK_MaxS32;
+ }
+
+ void finish() {
+ if (fMinY < SK_MaxS32) {
+ fBuilder->setMinY(fMinY);
+ }
+ }
+
+ /**
+ Must evaluate clips in scan-line order, so don't want to allow blitV(),
+ but an AAClip can be clipped down to a single pixel wide, so we
+ must support it (given AntiRect semantics: minimum width is 2).
+ Instead we'll rely on the runtime asserts to guarantee Y monotonicity;
+ any failure cases that misses may have minor artifacts.
+ */
+ virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE {
+ this->recordMinY(y);
+ fBuilder->addColumn(x, y, alpha, height);
+ }
+
+ virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE {
+ this->recordMinY(y);
+ fBuilder->addRectRun(x, y, width, height);
+ }
+
+ virtual void blitAntiRect(int x, int y, int width, int height,
+ SkAlpha leftAlpha, SkAlpha rightAlpha) SK_OVERRIDE {
+ this->recordMinY(y);
+ fBuilder->addAntiRectRun(x, y, width, height, leftAlpha, rightAlpha);
+ }
+
+ virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE
+ { unexpected(); }
+
+ virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE {
+ return NULL;
+ }
+
+ virtual void blitH(int x, int y, int width) SK_OVERRIDE {
+ this->recordMinY(y);
+ fBuilder->addRun(x, y, 0xFF, width);
+ }
+
+ virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
+ const int16_t runs[]) SK_OVERRIDE {
+ this->recordMinY(y);
+ for (;;) {
+ int count = *runs;
+ if (count <= 0) {
+ return;
+ }
+
+ // The supersampler's buffer can be the width of the device, so
+ // we may have to trim the run to our bounds. If so, we assert that
+ // the extra spans are always alpha==0
+ int localX = x;
+ int localCount = count;
+ if (x < fLeft) {
+ SkASSERT(0 == *alpha);
+ int gap = fLeft - x;
+ SkASSERT(gap <= count);
+ localX += gap;
+ localCount -= gap;
+ }
+ int right = x + count;
+ if (right > fRight) {
+ SkASSERT(0 == *alpha);
+ localCount -= right - fRight;
+ SkASSERT(localCount >= 0);
+ }
+
+ if (localCount) {
+ fBuilder->addRun(localX, y, *alpha, localCount);
+ }
+ // Next run
+ runs += count;
+ alpha += count;
+ x += count;
+ }
+ }
+
+private:
+ Builder* fBuilder;
+ int fLeft; // cache of builder's bounds' left edge
+ int fRight;
+ int fMinY;
+
+ /*
+ * We track this, in case the scan converter skipped some number of
+ * scanlines at the (relative to the bounds it was given). This allows
+ * the builder, during its finish, to trip its bounds down to the "real"
+ * top.
+ */
+ void recordMinY(int y) {
+ if (y < fMinY) {
+ fMinY = y;
+ }
+ }
+
+ void unexpected() {
+ SkDebugf("---- did not expect to get called here");
+ sk_throw();
+ }
+};
+
+bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
+ AUTO_AACLIP_VALIDATE(*this);
+
+ if (clip && clip->isEmpty()) {
+ return this->setEmpty();
+ }
+
+ SkIRect ibounds;
+ path.getBounds().roundOut(&ibounds);
+
+ SkRegion tmpClip;
+ if (NULL == clip) {
+ tmpClip.setRect(ibounds);
+ clip = &tmpClip;
+ }
+
+ if (path.isInverseFillType()) {
+ ibounds = clip->getBounds();
+ } else {
+ if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
+ return this->setEmpty();
+ }
+ }
+
+ Builder builder(ibounds);
+ BuilderBlitter blitter(&builder);
+
+ if (doAA) {
+ SkScan::AntiFillPath(path, *clip, &blitter, true);
+ } else {
+ SkScan::FillPath(path, *clip, &blitter);
+ }
+
+ blitter.finish();
+ return builder.finish(this);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
+ const uint8_t* rowA, const SkIRect& rectA,
+ const uint8_t* rowB, const SkIRect& rectB);
+
+static void sectRowProc(SkAAClip::Builder& builder, int bottom,
+ const uint8_t* rowA, const SkIRect& rectA,
+ const uint8_t* rowB, const SkIRect& rectB) {
+
+}
+
+typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
+
+static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
+ // Multiply
+ return SkMulDiv255Round(alphaA, alphaB);
+}
+
+static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
+ // SrcOver
+ return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
+}
+
+static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
+ // SrcOut
+ return SkMulDiv255Round(alphaA, 0xFF - alphaB);
+}
+
+static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
+ // XOR
+ return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
+}
+
+static AlphaProc find_alpha_proc(SkRegion::Op op) {
+ switch (op) {
+ case SkRegion::kIntersect_Op:
+ return sectAlphaProc;
+ case SkRegion::kDifference_Op:
+ return diffAlphaProc;
+ case SkRegion::kUnion_Op:
+ return unionAlphaProc;
+ case SkRegion::kXOR_Op:
+ return xorAlphaProc;
+ default:
+ SkDEBUGFAIL("unexpected region op");
+ return sectAlphaProc;
+ }
+}
+
+static const uint8_t gEmptyRow[] = {
+ 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
+ 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
+ 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
+ 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
+ 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
+ 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
+ 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
+ 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
+};
+
+class RowIter {
+public:
+ RowIter(const uint8_t* row, const SkIRect& bounds) {
+ fRow = row;
+ fLeft = bounds.fLeft;
+ fBoundsRight = bounds.fRight;
+ if (row) {
+ fRight = bounds.fLeft + row[0];
+ SkASSERT(fRight <= fBoundsRight);
+ fAlpha = row[1];
+ fDone = false;
+ } else {
+ fDone = true;
+ fRight = kMaxInt32;
+ fAlpha = 0;
+ }
+ }
+
+ bool done() const { return fDone; }
+ int left() const { return fLeft; }
+ int right() const { return fRight; }
+ U8CPU alpha() const { return fAlpha; }
+ void next() {
+ if (!fDone) {
+ fLeft = fRight;
+ if (fRight == fBoundsRight) {
+ fDone = true;
+ fRight = kMaxInt32;
+ fAlpha = 0;
+ } else {
+ fRow += 2;
+ fRight += fRow[0];
+ fAlpha = fRow[1];
+ SkASSERT(fRight <= fBoundsRight);
+ }
+ }
+ }
+
+private:
+ const uint8_t* fRow;
+ int fLeft;
+ int fRight;
+ int fBoundsRight;
+ bool fDone;
+ uint8_t fAlpha;
+};
+
+static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
+ if (rite == riteA) {
+ iter.next();
+ leftA = iter.left();
+ riteA = iter.right();
+ }
+}
+
+static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
+ SkASSERT(min < max);
+ SkASSERT(boundsMin < boundsMax);
+ if (min >= boundsMax || max <= boundsMin) {
+ return false;
+ }
+ if (min < boundsMin) {
+ min = boundsMin;
+ }
+ if (max > boundsMax) {
+ max = boundsMax;
+ }
+ return true;
+}
+
+static void operatorX(SkAAClip::Builder& builder, int lastY,
+ RowIter& iterA, RowIter& iterB,
+ AlphaProc proc, const SkIRect& bounds) {
+ int leftA = iterA.left();
+ int riteA = iterA.right();
+ int leftB = iterB.left();
+ int riteB = iterB.right();
+
+ int prevRite = bounds.fLeft;
+
+ do {
+ U8CPU alphaA = 0;
+ U8CPU alphaB = 0;
+ int left, rite;
+
+ if (leftA < leftB) {
+ left = leftA;
+ alphaA = iterA.alpha();
+ if (riteA <= leftB) {
+ rite = riteA;
+ } else {
+ rite = leftA = leftB;
+ }
+ } else if (leftB < leftA) {
+ left = leftB;
+ alphaB = iterB.alpha();
+ if (riteB <= leftA) {
+ rite = riteB;
+ } else {
+ rite = leftB = leftA;
+ }
+ } else {
+ left = leftA; // or leftB, since leftA == leftB
+ rite = leftA = leftB = SkMin32(riteA, riteB);
+ alphaA = iterA.alpha();
+ alphaB = iterB.alpha();
+ }
+
+ if (left >= bounds.fRight) {
+ break;
+ }
+ if (rite > bounds.fRight) {
+ rite = bounds.fRight;
+ }
+
+ if (left >= bounds.fLeft) {
+ SkASSERT(rite > left);
+ builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
+ prevRite = rite;
+ }
+
+ adjust_row(iterA, leftA, riteA, rite);
+ adjust_row(iterB, leftB, riteB, rite);
+ } while (!iterA.done() || !iterB.done());
+
+ if (prevRite < bounds.fRight) {
+ builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
+ }
+}
+
+static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
+ if (bot == botA) {
+ iter.next();
+ topA = botA;
+ SkASSERT(botA == iter.top());
+ botA = iter.bottom();
+ }
+}
+
+static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
+ const SkAAClip& B, SkRegion::Op op) {
+ AlphaProc proc = find_alpha_proc(op);
+ const SkIRect& bounds = builder.getBounds();
+
+ SkAAClip::Iter iterA(A);
+ SkAAClip::Iter iterB(B);
+
+ SkASSERT(!iterA.done());
+ int topA = iterA.top();
+ int botA = iterA.bottom();
+ SkASSERT(!iterB.done());
+ int topB = iterB.top();
+ int botB = iterB.bottom();
+
+ do {
+ const uint8_t* rowA = NULL;
+ const uint8_t* rowB = NULL;
+ int top, bot;
+
+ if (topA < topB) {
+ top = topA;
+ rowA = iterA.data();
+ if (botA <= topB) {
+ bot = botA;
+ } else {
+ bot = topA = topB;
+ }
+
+ } else if (topB < topA) {
+ top = topB;
+ rowB = iterB.data();
+ if (botB <= topA) {
+ bot = botB;
+ } else {
+ bot = topB = topA;
+ }
+ } else {
+ top = topA; // or topB, since topA == topB
+ bot = topA = topB = SkMin32(botA, botB);
+ rowA = iterA.data();
+ rowB = iterB.data();
+ }
+
+ if (top >= bounds.fBottom) {
+ break;
+ }
+
+ if (bot > bounds.fBottom) {
+ bot = bounds.fBottom;
+ }
+ SkASSERT(top < bot);
+
+ if (!rowA && !rowB) {
+ builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
+ } else if (top >= bounds.fTop) {
+ SkASSERT(bot <= bounds.fBottom);
+ RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
+ RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
+ operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
+ }
+
+ adjust_iter(iterA, topA, botA, bot);
+ adjust_iter(iterB, topB, botB, bot);
+ } while (!iterA.done() || !iterB.done());
+}
+
+bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
+ SkRegion::Op op) {
+ AUTO_AACLIP_VALIDATE(*this);
+
+ if (SkRegion::kReplace_Op == op) {
+ return this->set(clipBOrig);
+ }
+
+ const SkAAClip* clipA = &clipAOrig;
+ const SkAAClip* clipB = &clipBOrig;
+
+ if (SkRegion::kReverseDifference_Op == op) {
+ SkTSwap(clipA, clipB);
+ op = SkRegion::kDifference_Op;
+ }
+
+ bool a_empty = clipA->isEmpty();
+ bool b_empty = clipB->isEmpty();
+
+ SkIRect bounds;
+ switch (op) {
+ case SkRegion::kDifference_Op:
+ if (a_empty) {
+ return this->setEmpty();
+ }
+ if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
+ return this->set(*clipA);
+ }
+ bounds = clipA->fBounds;
+ break;
+
+ case SkRegion::kIntersect_Op:
+ if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
+ clipB->fBounds)) {
+ return this->setEmpty();
+ }
+ break;
+
+ case SkRegion::kUnion_Op:
+ case SkRegion::kXOR_Op:
+ if (a_empty) {
+ return this->set(*clipB);
+ }
+ if (b_empty) {
+ return this->set(*clipA);
+ }
+ bounds = clipA->fBounds;
+ bounds.join(clipB->fBounds);
+ break;
+
+ default:
+ SkDEBUGFAIL("unknown region op");
+ return !this->isEmpty();
+ }
+
+ SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
+ SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
+
+ Builder builder(bounds);
+ operateY(builder, *clipA, *clipB, op);
+
+ return builder.finish(this);
+}
+
+/*
+ * It can be expensive to build a local aaclip before applying the op, so
+ * we first see if we can restrict the bounds of new rect to our current
+ * bounds, or note that the new rect subsumes our current clip.
+ */
+
+bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) {
+ SkIRect rStorage;
+ const SkIRect* r = &rOrig;
+
+ switch (op) {
+ case SkRegion::kIntersect_Op:
+ if (!rStorage.intersect(rOrig, fBounds)) {
+ // no overlap, so we're empty
+ return this->setEmpty();
+ }
+ if (rStorage == fBounds) {
+ // we were wholly inside the rect, no change
+ return !this->isEmpty();
+ }
+ if (this->quickContains(rStorage)) {
+ // the intersection is wholly inside us, we're a rect
+ return this->setRect(rStorage);
+ }
+ r = &rStorage; // use the intersected bounds
+ break;
+ case SkRegion::kDifference_Op:
+ break;
+ case SkRegion::kUnion_Op:
+ if (rOrig.contains(fBounds)) {
+ return this->setRect(rOrig);
+ }
+ break;
+ default:
+ break;
+ }
+
+ SkAAClip clip;
+ clip.setRect(*r);
+ return this->op(*this, clip, op);
+}
+
+bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) {
+ SkRect rStorage, boundsStorage;
+ const SkRect* r = &rOrig;
+
+ boundsStorage.set(fBounds);
+ switch (op) {
+ case SkRegion::kIntersect_Op:
+ case SkRegion::kDifference_Op:
+ if (!rStorage.intersect(rOrig, boundsStorage)) {
+ return this->setEmpty();
+ }
+ r = &rStorage; // use the intersected bounds
+ break;
+ case SkRegion::kUnion_Op:
+ if (rOrig.contains(boundsStorage)) {
+ return this->setRect(rOrig);
+ }
+ break;
+ default:
+ break;
+ }
+
+ SkAAClip clip;
+ clip.setRect(*r, doAA);
+ return this->op(*this, clip, op);
+}
+
+bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
+ return this->op(*this, clip, op);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const {
+ if (NULL == dst) {
+ return !this->isEmpty();
+ }
+
+ if (this->isEmpty()) {
+ return dst->setEmpty();
+ }
+
+ if (this != dst) {
+ sk_atomic_inc(&fRunHead->fRefCnt);
+ dst->fRunHead = fRunHead;
+ dst->fBounds = fBounds;
+ }
+ dst->fBounds.offset(dx, dy);
+ return true;
+}
+
+static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
+ const uint8_t* SK_RESTRICT row,
+ int width) {
+ while (width > 0) {
+ int n = row[0];
+ SkASSERT(width >= n);
+ memset(mask, row[1], n);
+ mask += n;
+ row += 2;
+ width -= n;
+ }
+ SkASSERT(0 == width);
+}
+
+void SkAAClip::copyToMask(SkMask* mask) const {
+ mask->fFormat = SkMask::kA8_Format;
+ if (this->isEmpty()) {
+ mask->fBounds.setEmpty();
+ mask->fImage = NULL;
+ mask->fRowBytes = 0;
+ return;
+ }
+
+ mask->fBounds = fBounds;
+ mask->fRowBytes = fBounds.width();
+ size_t size = mask->computeImageSize();
+ mask->fImage = SkMask::AllocImage(size);
+
+ Iter iter(*this);
+ uint8_t* dst = mask->fImage;
+ const int width = fBounds.width();
+
+ int y = fBounds.fTop;
+ while (!iter.done()) {
+ do {
+ expand_row_to_mask(dst, iter.data(), width);
+ dst += mask->fRowBytes;
+ } while (++y < iter.bottom());
+ iter.next();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
+ int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
+ // we don't read our initial n from data, since the caller may have had to
+ // clip it, hence the initialCount parameter.
+ int n = initialCount;
+ for (;;) {
+ if (n > width) {
+ n = width;
+ }
+ SkASSERT(n > 0);
+ runs[0] = n;
+ runs += n;
+
+ aa[0] = data[1];
+ aa += n;
+
+ data += 2;
+ width -= n;
+ if (0 == width) {
+ break;
+ }
+ // load the next count
+ n = data[0];
+ }
+ runs[0] = 0; // sentinel
+}
+
+SkAAClipBlitter::~SkAAClipBlitter() {
+ sk_free(fScanlineScratch);
+}
+
+void SkAAClipBlitter::ensureRunsAndAA() {
+ if (NULL == fScanlineScratch) {
+ // add 1 so we can store the terminating run count of 0
+ int count = fAAClipBounds.width() + 1;
+ // we use this either for fRuns + fAA, or a scaline of a mask
+ // which may be as deep as 32bits
+ fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor));
+ fRuns = (int16_t*)fScanlineScratch;
+ fAA = (SkAlpha*)(fRuns + count);
+ }
+}
+
+void SkAAClipBlitter::blitH(int x, int y, int width) {
+ SkASSERT(width > 0);
+ SkASSERT(fAAClipBounds.contains(x, y));
+ SkASSERT(fAAClipBounds.contains(x + width - 1, y));
+
+ int lastY;
+ const uint8_t* row = fAAClip->findRow(y, &lastY);
+ int initialCount;
+ row = fAAClip->findX(row, x, &initialCount);
+
+ if (initialCount >= width) {
+ SkAlpha alpha = row[1];
+ if (0 == alpha) {
+ return;
+ }
+ if (0xFF == alpha) {
+ fBlitter->blitH(x, y, width);
+ return;
+ }
+ }
+
+ this->ensureRunsAndAA();
+ expandToRuns(row, initialCount, width, fRuns, fAA);
+
+ fBlitter->blitAntiH(x, y, fAA, fRuns);
+}
+
+static void merge(const uint8_t* SK_RESTRICT row, int rowN,
+ const SkAlpha* SK_RESTRICT srcAA,
+ const int16_t* SK_RESTRICT srcRuns,
+ SkAlpha* SK_RESTRICT dstAA,
+ int16_t* SK_RESTRICT dstRuns,
+ int width) {
+ SkDEBUGCODE(int accumulated = 0;)
+ int srcN = srcRuns[0];
+ // do we need this check?
+ if (0 == srcN) {
+ return;
+ }
+
+ for (;;) {
+ SkASSERT(rowN > 0);
+ SkASSERT(srcN > 0);
+
+ unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
+ int minN = SkMin32(srcN, rowN);
+ dstRuns[0] = minN;
+ dstRuns += minN;
+ dstAA[0] = newAlpha;
+ dstAA += minN;
+
+ if (0 == (srcN -= minN)) {
+ srcN = srcRuns[0]; // refresh
+ srcRuns += srcN;
+ srcAA += srcN;
+ srcN = srcRuns[0]; // reload
+ if (0 == srcN) {
+ break;
+ }
+ }
+ if (0 == (rowN -= minN)) {
+ row += 2;
+ rowN = row[0]; // reload
+ }
+
+ SkDEBUGCODE(accumulated += minN;)
+ SkASSERT(accumulated <= width);
+ }
+ dstRuns[0] = 0;
+}
+
+void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
+ const int16_t runs[]) {
+ int lastY;
+ const uint8_t* row = fAAClip->findRow(y, &lastY);
+ int initialCount;
+ row = fAAClip->findX(row, x, &initialCount);
+
+ this->ensureRunsAndAA();
+
+ merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
+ fBlitter->blitAntiH(x, y, fAA, fRuns);
+}
+
+void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
+ if (fAAClip->quickContains(x, y, x + 1, y + height)) {
+ fBlitter->blitV(x, y, height, alpha);
+ return;
+ }
+
+ for (;;) {
+ int lastY;
+ const uint8_t* row = fAAClip->findRow(y, &lastY);
+ int dy = lastY - y + 1;
+ if (dy > height) {
+ dy = height;
+ }
+ height -= dy;
+
+ int initialCount;
+ row = fAAClip->findX(row, x, &initialCount);
+ SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
+ if (newAlpha) {
+ fBlitter->blitV(x, y, dy, newAlpha);
+ }
+ SkASSERT(height >= 0);
+ if (height <= 0) {
+ break;
+ }
+ y = lastY + 1;
+ }
+}
+
+void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
+ if (fAAClip->quickContains(x, y, x + width, y + height)) {
+ fBlitter->blitRect(x, y, width, height);
+ return;
+ }
+
+ while (--height >= 0) {
+ this->blitH(x, y, width);
+ y += 1;
+ }
+}
+
+typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row,
+ int initialRowCount, void* dst);
+
+static void small_memcpy(void* dst, const void* src, size_t n) {
+ memcpy(dst, src, n);
+}
+
+static void small_bzero(void* dst, size_t n) {
+ sk_bzero(dst, n);
+}
+
+static inline uint8_t mergeOne(uint8_t value, unsigned alpha) {
+ return SkMulDiv255Round(value, alpha);
+}
+static inline uint16_t mergeOne(uint16_t value, unsigned alpha) {
+ unsigned r = SkGetPackedR16(value);
+ unsigned g = SkGetPackedG16(value);
+ unsigned b = SkGetPackedB16(value);
+ return SkPackRGB16(SkMulDiv255Round(r, alpha),
+ SkMulDiv255Round(r, alpha),
+ SkMulDiv255Round(r, alpha));
+}
+static inline SkPMColor mergeOne(SkPMColor value, unsigned alpha) {
+ unsigned a = SkGetPackedA32(value);
+ unsigned r = SkGetPackedR32(value);
+ unsigned g = SkGetPackedG32(value);
+ unsigned b = SkGetPackedB32(value);
+ return SkPackARGB32(SkMulDiv255Round(a, alpha),
+ SkMulDiv255Round(r, alpha),
+ SkMulDiv255Round(g, alpha),
+ SkMulDiv255Round(b, alpha));
+}
+
+template <typename T> void mergeT(const T* SK_RESTRICT src, int srcN,
+ const uint8_t* SK_RESTRICT row, int rowN,
+ T* SK_RESTRICT dst) {
+ SkDEBUGCODE(int accumulated = 0;)
+ for (;;) {
+ SkASSERT(rowN > 0);
+ SkASSERT(srcN > 0);
+
+ int n = SkMin32(rowN, srcN);
+ unsigned rowA = row[1];
+ if (0xFF == rowA) {
+ small_memcpy(dst, src, n * sizeof(T));
+ } else if (0 == rowA) {
+ small_bzero(dst, n * sizeof(T));
+ } else {
+ for (int i = 0; i < n; ++i) {
+ dst[i] = mergeOne(src[i], rowA);
+ }
+ }
+
+ if (0 == (srcN -= n)) {
+ break;
+ }
+
+ src += n;
+ dst += n;
+
+ SkASSERT(rowN == n);
+ row += 2;
+ rowN = row[0];
+ }
+}
+
+static MergeAAProc find_merge_aa_proc(SkMask::Format format) {
+ switch (format) {
+ case SkMask::kBW_Format:
+ SkDEBUGFAIL("unsupported");
+ return NULL;
+ case SkMask::kA8_Format:
+ case SkMask::k3D_Format: {
+ void (*proc8)(const uint8_t*, int, const uint8_t*, int, uint8_t*) = mergeT;
+ return (MergeAAProc)proc8;
+ }
+ case SkMask::kLCD16_Format: {
+ void (*proc16)(const uint16_t*, int, const uint8_t*, int, uint16_t*) = mergeT;
+ return (MergeAAProc)proc16;
+ }
+ case SkMask::kLCD32_Format: {
+ void (*proc32)(const SkPMColor*, int, const uint8_t*, int, SkPMColor*) = mergeT;
+ return (MergeAAProc)proc32;
+ }
+ default:
+ SkDEBUGFAIL("unsupported");
+ return NULL;
+ }
+}
+
+static U8CPU bit2byte(int bitInAByte) {
+ SkASSERT(bitInAByte <= 0xFF);
+ // negation turns any non-zero into 0xFFFFFF??, so we just shift down
+ // some value >= 8 to get a full FF value
+ return -bitInAByte >> 8;
+}
+
+static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) {
+ SkASSERT(SkMask::kBW_Format == srcMask.fFormat);
+ SkASSERT(SkMask::kA8_Format == dstMask->fFormat);
+
+ const int width = srcMask.fBounds.width();
+ const int height = srcMask.fBounds.height();
+
+ const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage;
+ const size_t srcRB = srcMask.fRowBytes;
+ uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage;
+ const size_t dstRB = dstMask->fRowBytes;
+
+ const int wholeBytes = width >> 3;
+ const int leftOverBits = width & 7;
+
+ for (int y = 0; y < height; ++y) {
+ uint8_t* SK_RESTRICT d = dst;
+ for (int i = 0; i < wholeBytes; ++i) {
+ int srcByte = src[i];
+ d[0] = bit2byte(srcByte & (1 << 7));
+ d[1] = bit2byte(srcByte & (1 << 6));
+ d[2] = bit2byte(srcByte & (1 << 5));
+ d[3] = bit2byte(srcByte & (1 << 4));
+ d[4] = bit2byte(srcByte & (1 << 3));
+ d[5] = bit2byte(srcByte & (1 << 2));
+ d[6] = bit2byte(srcByte & (1 << 1));
+ d[7] = bit2byte(srcByte & (1 << 0));
+ d += 8;
+ }
+ if (leftOverBits) {
+ int srcByte = src[wholeBytes];
+ for (int x = 0; x < leftOverBits; ++x) {
+ *d++ = bit2byte(srcByte & 0x80);
+ srcByte <<= 1;
+ }
+ }
+ src += srcRB;
+ dst += dstRB;
+ }
+}
+
+void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) {
+ SkASSERT(fAAClip->getBounds().contains(clip));
+
+ if (fAAClip->quickContains(clip)) {
+ fBlitter->blitMask(origMask, clip);
+ return;
+ }
+
+ const SkMask* mask = &origMask;
+
+ // if we're BW, we need to upscale to A8 (ugh)
+ SkMask grayMask;
+ grayMask.fImage = NULL;
+ if (SkMask::kBW_Format == origMask.fFormat) {
+ grayMask.fFormat = SkMask::kA8_Format;
+ grayMask.fBounds = origMask.fBounds;
+ grayMask.fRowBytes = origMask.fBounds.width();
+ size_t size = grayMask.computeImageSize();
+ grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size,
+ SkAutoMalloc::kReuse_OnShrink);
+
+ upscaleBW2A8(&grayMask, origMask);
+ mask = &grayMask;
+ }
+
+ this->ensureRunsAndAA();
+
+ // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D
+ // data into a temp block to support it better (ugh)
+
+ const void* src = mask->getAddr(clip.fLeft, clip.fTop);
+ const size_t srcRB = mask->fRowBytes;
+ const int width = clip.width();
+ MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat);
+
+ SkMask rowMask;
+ rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat;
+ rowMask.fBounds.fLeft = clip.fLeft;
+ rowMask.fBounds.fRight = clip.fRight;
+ rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1
+ rowMask.fImage = (uint8_t*)fScanlineScratch;
+
+ int y = clip.fTop;
+ const int stopY = y + clip.height();
+
+ do {
+ int localStopY;
+ const uint8_t* row = fAAClip->findRow(y, &localStopY);
+ // findRow returns last Y, not stop, so we add 1
+ localStopY = SkMin32(localStopY + 1, stopY);
+
+ int initialCount;
+ row = fAAClip->findX(row, clip.fLeft, &initialCount);
+ do {
+ mergeProc(src, width, row, initialCount, rowMask.fImage);
+ rowMask.fBounds.fTop = y;
+ rowMask.fBounds.fBottom = y + 1;
+ fBlitter->blitMask(rowMask, rowMask.fBounds);
+ src = (const void*)((const char*)src + srcRB);
+ } while (++y < localStopY);
+ } while (y < stopY);
+}
+
+const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
+ return NULL;
+}
+
diff --git a/src/core/SkAAClip.h b/src/core/SkAAClip.h
new file mode 100644
index 0000000..6036427
--- /dev/null
+++ b/src/core/SkAAClip.h
@@ -0,0 +1,132 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkAAClip_DEFINED
+#define SkAAClip_DEFINED
+
+#include "SkBlitter.h"
+#include "SkRegion.h"
+
+class SkAAClip {
+public:
+ SkAAClip();
+ SkAAClip(const SkAAClip&);
+ ~SkAAClip();
+
+ SkAAClip& operator=(const SkAAClip&);
+ friend bool operator==(const SkAAClip&, const SkAAClip&);
+ friend bool operator!=(const SkAAClip& a, const SkAAClip& b) {
+ return !(a == b);
+ }
+
+ void swap(SkAAClip&);
+
+ bool isEmpty() const { return NULL == fRunHead; }
+ const SkIRect& getBounds() const { return fBounds; }
+
+ bool setEmpty();
+ bool setRect(const SkIRect&);
+ bool setRect(const SkRect&, bool doAA = true);
+ bool setPath(const SkPath&, const SkRegion* clip = NULL, bool doAA = true);
+ bool setRegion(const SkRegion&);
+ bool set(const SkAAClip&);
+
+ bool op(const SkAAClip&, const SkAAClip&, SkRegion::Op);
+
+ // Helpers for op()
+ bool op(const SkIRect&, SkRegion::Op);
+ bool op(const SkRect&, SkRegion::Op, bool doAA);
+ bool op(const SkAAClip&, SkRegion::Op);
+
+ bool translate(int dx, int dy, SkAAClip* dst) const;
+ bool translate(int dx, int dy) {
+ return this->translate(dx, dy, this);
+ }
+
+ /**
+ * Allocates a mask the size of the aaclip, and expands its data into
+ * the mask, using kA8_Format
+ */
+ void copyToMask(SkMask*) const;
+
+ // called internally
+
+ bool quickContains(int left, int top, int right, int bottom) const;
+ bool quickContains(const SkIRect& r) const {
+ return this->quickContains(r.fLeft, r.fTop, r.fRight, r.fBottom);
+ }
+
+ const uint8_t* findRow(int y, int* lastYForRow) const;
+ const uint8_t* findX(const uint8_t data[], int x, int* initialCount) const;
+
+ class Iter;
+ struct RunHead;
+ struct YOffset;
+ class Builder;
+
+#ifdef SK_DEBUG
+ void validate() const;
+#else
+ void validate() const {}
+#endif
+
+private:
+ SkIRect fBounds;
+ RunHead* fRunHead;
+
+ void freeRuns();
+ bool trimBounds();
+ bool trimTopBottom();
+ bool trimLeftRight();
+
+ friend class Builder;
+ class BuilderBlitter;
+ friend class BuilderBlitter;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class SkAAClipBlitter : public SkBlitter {
+public:
+ SkAAClipBlitter() : fScanlineScratch(NULL) {}
+ virtual ~SkAAClipBlitter();
+
+ void init(SkBlitter* blitter, const SkAAClip* aaclip) {
+ SkASSERT(aaclip && !aaclip->isEmpty());
+ fBlitter = blitter;
+ fAAClip = aaclip;
+ fAAClipBounds = aaclip->getBounds();
+ }
+
+ virtual void blitH(int x, int y, int width) SK_OVERRIDE;
+ virtual void blitAntiH(int x, int y, const SkAlpha[],
+ const int16_t runs[]) SK_OVERRIDE;
+ virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE;
+ virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE;
+ virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE;
+ virtual const SkBitmap* justAnOpaqueColor(uint32_t* value) SK_OVERRIDE;
+
+private:
+ SkBlitter* fBlitter;
+ const SkAAClip* fAAClip;
+ SkIRect fAAClipBounds;
+
+ // point into fScanlineScratch
+ int16_t* fRuns;
+ SkAlpha* fAA;
+
+ enum {
+ kSize = 32 * 32
+ };
+ SkAutoSMalloc<kSize> fGrayMaskScratch; // used for blitMask
+ void* fScanlineScratch; // enough for a mask at 32bit, or runs+aa
+
+ void ensureRunsAndAA();
+};
+
+#endif
diff --git a/src/core/SkAdvancedTypefaceMetrics.cpp b/src/core/SkAdvancedTypefaceMetrics.cpp
index 05d5c28..8af70fb 100644
--- a/src/core/SkAdvancedTypefaceMetrics.cpp
+++ b/src/core/SkAdvancedTypefaceMetrics.cpp
@@ -1,33 +1,61 @@
+
/*
- * Copyright (C) 2011 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2011 Google Inc.
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkAdvancedTypefaceMetrics.h"
#include "SkTypes.h"
-#ifdef SK_BUILD_FOR_UNIX
+#if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
#include <ft2build.h>
#include FT_FREETYPE_H
#endif
#ifdef SK_BUILD_FOR_MAC
-#include <Carbon/Carbon.h>
+#import <ApplicationServices/ApplicationServices.h>
+#endif
+
+#ifdef SK_BUILD_FOR_IOS
+#include <CoreText/CoreText.h>
+#include <CoreGraphics/CoreGraphics.h>
+#include <CoreFoundation/CoreFoundation.h>
#endif
namespace skia_advanced_typeface_metrics_utils {
+const int16_t kInvalidAdvance = SK_MinS16;
+const int16_t kDontCareAdvance = SK_MinS16 + 1;
+
+template <typename Data>
+void stripUninterestingTrailingAdvancesFromRange(
+ SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range) {
+ SkASSERT(false);
+}
+
+template <>
+void stripUninterestingTrailingAdvancesFromRange<int16_t>(
+ SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>* range) {
+ SkASSERT(range);
+
+ int expectedAdvanceCount = range->fEndId - range->fStartId + 1;
+ if (range->fAdvance.count() < expectedAdvanceCount) {
+ return;
+ }
+
+ for (int i = expectedAdvanceCount - 1; i >= 0; --i) {
+ if (range->fAdvance[i] != kDontCareAdvance &&
+ range->fAdvance[i] != kInvalidAdvance &&
+ range->fAdvance[i] != 0) {
+ range->fEndId = range->fStartId + i;
+ break;
+ }
+ }
+}
+
template <typename Data>
void resetRange(SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range,
int startId) {
@@ -45,6 +73,29 @@ SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* appendRange(
}
template <typename Data>
+void zeroWildcardsInRange(
+ SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range) {
+ SkASSERT(false);
+}
+
+template <>
+void zeroWildcardsInRange<int16_t>(
+ SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>* range) {
+ SkASSERT(range);
+ if (range->fType != SkAdvancedTypefaceMetrics::WidthRange::kRange) {
+ return;
+ }
+ SkASSERT(range->fAdvance.count() == range->fEndId - range->fStartId + 1);
+
+ // Zero out wildcards.
+ for (int i = 0; i < range->fAdvance.count(); ++i) {
+ if (range->fAdvance[i] == kDontCareAdvance) {
+ range->fAdvance[i] = 0;
+ }
+ }
+}
+
+template <typename Data>
void finishRange(
SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* range,
int endId,
@@ -52,83 +103,147 @@ void finishRange(
type) {
range->fEndId = endId;
range->fType = type;
+ stripUninterestingTrailingAdvancesFromRange(range);
int newLength;
if (type == SkAdvancedTypefaceMetrics::AdvanceMetric<Data>::kRange) {
- newLength = endId - range->fStartId + 1;
+ newLength = range->fEndId - range->fStartId + 1;
} else {
+ if (range->fEndId == range->fStartId) {
+ range->fType =
+ SkAdvancedTypefaceMetrics::AdvanceMetric<Data>::kRange;
+ }
newLength = 1;
}
SkASSERT(range->fAdvance.count() >= newLength);
range->fAdvance.setCount(newLength);
+ zeroWildcardsInRange(range);
}
template <typename Data, typename FontHandle>
SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* getAdvanceData(
FontHandle fontHandle,
int num_glyphs,
+ const uint32_t* subsetGlyphIDs,
+ uint32_t subsetGlyphIDsLength,
bool (*getAdvance)(FontHandle fontHandle, int gId, Data* data)) {
- // Assuming that an ASCII representation of a width or a glyph id is,
- // on average, 3 characters long gives the following cut offs for
- // using different range types:
- // When currently in a range
- // - Removing 4 0's is a win
- // - Removing 5 repeats is a win
- // When not currently in a range
- // - Removing 1 0 is a win
- // - Removing 3 repeats is a win
+ // Assuming that on average, the ASCII representation of an advance plus
+ // a space is 8 characters and the ASCII representation of a glyph id is 3
+ // characters, then the following cut offs for using different range types
+ // apply:
+ // The cost of stopping and starting the range is 7 characers
+ // a. Removing 4 0's or don't care's is a win
+ // The cost of stopping and starting the range plus a run is 22
+ // characters
+ // b. Removing 3 repeating advances is a win
+ // c. Removing 2 repeating advances and 3 don't cares is a win
+ // When not currently in a range the cost of a run over a range is 16
+ // characaters, so:
+ // d. Removing a leading 0/don't cares is a win because it is omitted
+ // e. Removing 2 repeating advances is a win
SkTScopedPtr<SkAdvancedTypefaceMetrics::AdvanceMetric<Data> > result;
SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* curRange;
SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* prevRange = NULL;
- curRange = appendRange(&result, 0);
- Data lastAdvance = SK_MinS16;
- int repeats = 0;
- for (int gId = 0; gId <= num_glyphs; gId++) {
- Data advance;
- if (gId < num_glyphs) {
- SkAssertResult(getAdvance(fontHandle, gId, &advance));
- } else {
- advance = SK_MinS16;
+ Data lastAdvance = kInvalidAdvance;
+ int repeatedAdvances = 0;
+ int wildCardsInRun = 0;
+ int leadingWildCards = 0;
+ int trailingWildCards = 0;
+ uint32_t subsetIndex = 0;
+
+ // Limit the loop count to glyph id ranges provided.
+ int firstIndex = 0;
+ int lastIndex = num_glyphs;
+ if (subsetGlyphIDs) {
+ firstIndex = static_cast<int>(subsetGlyphIDs[0]);
+ lastIndex =
+ static_cast<int>(subsetGlyphIDs[subsetGlyphIDsLength - 1]) + 1;
+ }
+ curRange = appendRange(&result, firstIndex);
+
+ for (int gId = firstIndex; gId <= lastIndex; gId++) {
+ Data advance = kInvalidAdvance;
+ if (gId < lastIndex) {
+ // Get glyph id only when subset is NULL, or the id is in subset.
+ if (!subsetGlyphIDs ||
+ (subsetIndex < subsetGlyphIDsLength &&
+ static_cast<uint32_t>(gId) == subsetGlyphIDs[subsetIndex])) {
+ SkAssertResult(getAdvance(fontHandle, gId, &advance));
+ ++subsetIndex;
+ } else {
+ advance = kDontCareAdvance;
+ }
}
if (advance == lastAdvance) {
- repeats++;
- } else if (curRange->fAdvance.count() == repeats + 1) {
- if (lastAdvance == 0 && repeats >= 0) {
+ repeatedAdvances++;
+ trailingWildCards = 0;
+ } else if (advance == kDontCareAdvance) {
+ wildCardsInRun++;
+ trailingWildCards++;
+ } else if (curRange->fAdvance.count() ==
+ repeatedAdvances + 1 + wildCardsInRun) { // All in run.
+ if (lastAdvance == 0) {
resetRange(curRange, gId);
- } else if (repeats >= 2) {
+ trailingWildCards = 0;
+ } else if (repeatedAdvances + 1 >= 2 || trailingWildCards >= 4) {
finishRange(curRange, gId - 1,
SkAdvancedTypefaceMetrics::WidthRange::kRun);
prevRange = curRange;
curRange = appendRange(&curRange->fNext, gId);
+ trailingWildCards = 0;
}
- repeats = 0;
+ repeatedAdvances = 0;
+ wildCardsInRun = trailingWildCards;
+ leadingWildCards = trailingWildCards;
+ trailingWildCards = 0;
} else {
- if (lastAdvance == 0 && repeats >= 3) {
- finishRange(curRange, gId - repeats - 2,
+ if (lastAdvance == 0 &&
+ repeatedAdvances + 1 + wildCardsInRun >= 4) {
+ finishRange(curRange,
+ gId - repeatedAdvances - wildCardsInRun - 2,
SkAdvancedTypefaceMetrics::WidthRange::kRange);
prevRange = curRange;
curRange = appendRange(&curRange->fNext, gId);
- } else if (repeats >= 4) {
- finishRange(curRange, gId - repeats - 2,
+ trailingWildCards = 0;
+ } else if (trailingWildCards >= 4 && repeatedAdvances + 1 < 2) {
+ finishRange(curRange,
+ gId - trailingWildCards - 1,
SkAdvancedTypefaceMetrics::WidthRange::kRange);
- curRange = appendRange(&curRange->fNext, gId - repeats - 1);
+ prevRange = curRange;
+ curRange = appendRange(&curRange->fNext, gId);
+ trailingWildCards = 0;
+ } else if (lastAdvance != 0 &&
+ (repeatedAdvances + 1 >= 3 ||
+ (repeatedAdvances + 1 >= 2 && wildCardsInRun >= 3))) {
+ finishRange(curRange,
+ gId - repeatedAdvances - wildCardsInRun - 2,
+ SkAdvancedTypefaceMetrics::WidthRange::kRange);
+ curRange =
+ appendRange(&curRange->fNext,
+ gId - repeatedAdvances - wildCardsInRun - 1);
curRange->fAdvance.append(1, &lastAdvance);
finishRange(curRange, gId - 1,
SkAdvancedTypefaceMetrics::WidthRange::kRun);
prevRange = curRange;
curRange = appendRange(&curRange->fNext, gId);
+ trailingWildCards = 0;
}
- repeats = 0;
+ repeatedAdvances = 0;
+ wildCardsInRun = trailingWildCards;
+ leadingWildCards = trailingWildCards;
+ trailingWildCards = 0;
}
curRange->fAdvance.append(1, &advance);
- lastAdvance = advance;
+ if (advance != kDontCareAdvance) {
+ lastAdvance = advance;
+ }
}
- if (curRange->fStartId == num_glyphs) {
+ if (curRange->fStartId == lastIndex) {
SkASSERT(prevRange);
- SkASSERT(prevRange->fNext->fStartId == num_glyphs);
+ SkASSERT(prevRange->fNext->fStartId == lastIndex);
prevRange->fNext.reset();
} else {
- finishRange(curRange, num_glyphs - 1,
+ finishRange(curRange, lastIndex - 1,
SkAdvancedTypefaceMetrics::WidthRange::kRange);
}
return result.release();
@@ -140,16 +255,22 @@ SkAdvancedTypefaceMetrics::AdvanceMetric<Data>* getAdvanceData(
template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
HDC hdc,
int num_glyphs,
+ const uint32_t* subsetGlyphIDs,
+ uint32_t subsetGlyphIDsLength,
bool (*getAdvance)(HDC hdc, int gId, int16_t* data));
-#elif defined(SK_BUILD_FOR_UNIX)
+#elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
FT_Face face,
int num_glyphs,
+ const uint32_t* subsetGlyphIDs,
+ uint32_t subsetGlyphIDsLength,
bool (*getAdvance)(FT_Face face, int gId, int16_t* data));
-#elif defined(SK_BUILD_FOR_MAC)
+#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(
CTFontRef ctFont,
int num_glyphs,
+ const uint32_t* subsetGlyphIDs,
+ uint32_t subsetGlyphIDsLength,
bool (*getAdvance)(CTFontRef ctFont, int gId, int16_t* data));
#endif
template void resetRange(
diff --git a/src/core/SkAlphaRuns.cpp b/src/core/SkAlphaRuns.cpp
index a5fc3c9..116d132 100644
--- a/src/core/SkAlphaRuns.cpp
+++ b/src/core/SkAlphaRuns.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkAlphaRuns.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkAntiRun.h"
#include "SkUtils.h"
diff --git a/src/core/SkAntiRun.h b/src/core/SkAntiRun.h
index 669e5d2..56b5ee5 100644
--- a/src/core/SkAntiRun.h
+++ b/src/core/SkAntiRun.h
@@ -1,38 +1,46 @@
-/* libs/graphics/sgl/SkAntiRun.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkAntiRun_DEFINED
#define SkAntiRun_DEFINED
#include "SkBlitter.h"
+/** Sparse array of run-length-encoded alpha (supersampling coverage) values.
+ Sparseness allows us to independently compose several paths into the
+ same SkAlphaRuns buffer.
+*/
+
class SkAlphaRuns {
public:
int16_t* fRuns;
uint8_t* fAlpha;
+ /// Returns true if the scanline contains only a single run,
+ /// of alpha value 0.
bool empty() const {
SkASSERT(fRuns[0] > 0);
return fAlpha[0] == 0 && fRuns[fRuns[0]] == 0;
}
+ /// Reinitialize for a new scanline.
void reset(int width);
/**
+ * Insert into the buffer a run starting at (x-offsetX):
+ * if startAlpha > 0
+ * one pixel with value += startAlpha,
+ * max 255
+ * if middleCount > 0
+ * middleCount pixels with value += maxValue
+ * if stopAlpha > 0
+ * one pixel with value += stopAlpha
* Returns the offsetX value that should be passed on the next call,
* assuming we're on the same scanline. If the caller is switching
* scanlines, then offsetX should be 0 when this is called.
@@ -43,8 +51,22 @@ public:
SkDEBUGCODE(void assertValid(int y, int maxStep) const;)
SkDEBUGCODE(void dump() const;)
+ /**
+ * Break the runs in the buffer at offsets x and x+count, properly
+ * updating the runs to the right and left.
+ * i.e. from the state AAAABBBB, run-length encoded as A4B4,
+ * Break(..., 2, 5) would produce AAAABBBB rle as A2A2B3B1.
+ * Allows add() to sum another run to some of the new sub-runs.
+ * i.e. adding ..CCCCC. would produce AADDEEEB, rle as A2D2E3B1.
+ */
static void Break(int16_t runs[], uint8_t alpha[], int x, int count);
+ /**
+ * Cut (at offset x in the buffer) a run into two shorter runs with
+ * matching alpha values.
+ * Used by the RectClipBlitter to trim a RLE encoding to match the
+ * clipping rectangle.
+ */
static void BreakAt(int16_t runs[], uint8_t alpha[], int x) {
while (x > 0) {
int n = runs[0];
diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp
index 20af3f0..2b3e7c4 100644
--- a/src/core/SkBitmap.cpp
+++ b/src/core/SkBitmap.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006-2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2008 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkBitmap.h"
#include "SkColorPriv.h"
#include "SkDither.h"
@@ -180,7 +173,7 @@ int SkBitmap::ComputeBytesPerPixel(SkBitmap::Config config) {
bpp = 4;
break;
default:
- SkASSERT(!"unknown config");
+ SkDEBUGFAIL("unknown config");
bpp = 0; // error
break;
}
@@ -218,7 +211,7 @@ int SkBitmap::ComputeRowBytes(Config c, int width) {
rowBytes.shiftLeft(2);
break;
default:
- SkASSERT(!"unknown config");
+ SkDEBUGFAIL("unknown config");
break;
}
return isPos32Bits(rowBytes) ? rowBytes.get32() : 0;
@@ -350,6 +343,14 @@ void SkBitmap::unlockPixels() const {
SkDEBUGCODE(this->validate();)
}
+bool SkBitmap::lockPixelsAreWritable() const {
+ if (fPixelRef) {
+ return fPixelRef->lockPixelsAreWritable();
+ } else {
+ return fPixels != NULL;
+ }
+}
+
void SkBitmap::setPixels(void* p, SkColorTable* ctable) {
this->freePixels();
fPixels = p;
@@ -408,6 +409,7 @@ uint32_t SkBitmap::getGenerationID() const {
}
void SkBitmap::notifyPixelsChanged() const {
+ SkASSERT(!this->isImmutable());
if (fPixelRef) {
fPixelRef->notifyPixelsChanged();
} else {
@@ -455,8 +457,8 @@ Sk64 SkBitmap::getSafeSize64() const {
return ComputeSafeSize64(getConfig(), fWidth, fHeight, fRowBytes);
}
-bool SkBitmap::copyPixelsTo(void* const dst, size_t dstSize, int dstRowBytes)
- const {
+bool SkBitmap::copyPixelsTo(void* const dst, size_t dstSize,
+ int dstRowBytes, bool preserveDstPad) const {
if (dstRowBytes == -1)
dstRowBytes = fRowBytes;
@@ -467,7 +469,7 @@ bool SkBitmap::copyPixelsTo(void* const dst, size_t dstSize, int dstRowBytes)
dst == NULL || (getPixels() == NULL && pixelRef() == NULL))
return false;
- if (static_cast<uint32_t>(dstRowBytes) == fRowBytes) {
+ if (!preserveDstPad && static_cast<uint32_t>(dstRowBytes) == fRowBytes) {
size_t safeSize = getSafeSize();
if (safeSize > dstSize || safeSize == 0)
return false;
@@ -501,43 +503,21 @@ bool SkBitmap::copyPixelsTo(void* const dst, size_t dstSize, int dstRowBytes)
}
}
-bool SkBitmap::copyPixelsFrom(const void* const src, size_t srcSize,
- int srcRowBytes) {
-
- if (srcRowBytes == -1)
- srcRowBytes = fRowBytes;
- SkASSERT(srcRowBytes >= 0);
+///////////////////////////////////////////////////////////////////////////////
- size_t safeSize = getSafeSize();
- uint32_t rowBytes = ComputeRowBytes(getConfig(), fWidth);
- if (getConfig() == kRLE_Index8_Config || src == NULL ||
- static_cast<uint32_t>(srcRowBytes) < rowBytes ||
- safeSize == 0 ||
- srcSize < ComputeSafeSize(getConfig(), fWidth, fHeight, srcRowBytes)) {
- return false;
- }
+bool SkBitmap::isImmutable() const {
+ return fPixelRef ? fPixelRef->isImmutable() :
+ fFlags & kImageIsImmutable_Flag;
+}
- SkAutoLockPixels lock(*this);
- if (static_cast<uint32_t>(srcRowBytes) == fRowBytes) {
- // This implementation will write bytes beyond the end of each row,
- // excluding the last row, if the bitmap's stride is greater than
- // strictly required by the current config.
- memcpy(getPixels(), src, safeSize);
+void SkBitmap::setImmutable() {
+ if (fPixelRef) {
+ fPixelRef->setImmutable();
} else {
- // Just copy the bytes we need on each line.
- const uint8_t* srcP = reinterpret_cast<const uint8_t*>(src);
- uint8_t* dstP = reinterpret_cast<uint8_t*>(getPixels());
- for (uint32_t row = 0; row < fHeight;
- row++, srcP += srcRowBytes, dstP += fRowBytes) {
- memcpy(dstP, srcP, rowBytes);
- }
+ fFlags |= kImageIsImmutable_Flag;
}
-
- return true;
}
-///////////////////////////////////////////////////////////////////////////////
-
bool SkBitmap::isOpaque() const {
switch (fConfig) {
case kNo_Config:
@@ -567,7 +547,7 @@ bool SkBitmap::isOpaque() const {
return true;
default:
- SkASSERT(!"unknown bitmap config pased to isOpaque");
+ SkDEBUGFAIL("unknown bitmap config pased to isOpaque");
return false;
}
}
@@ -583,6 +563,18 @@ void SkBitmap::setIsOpaque(bool isOpaque) {
}
}
+bool SkBitmap::isVolatile() const {
+ return (fFlags & kImageIsVolatile_Flag) != 0;
+}
+
+void SkBitmap::setIsVolatile(bool isVolatile) {
+ if (isVolatile) {
+ fFlags |= kImageIsVolatile_Flag;
+ } else {
+ fFlags &= ~kImageIsVolatile_Flag;
+ }
+}
+
void* SkBitmap::getAddr(int x, int y) const {
SkASSERT((unsigned)x < (unsigned)this->width());
SkASSERT((unsigned)y < (unsigned)this->height());
@@ -606,11 +598,11 @@ void* SkBitmap::getAddr(int x, int y) const {
base += x >> 3;
break;
case kRLE_Index8_Config:
- SkASSERT(!"Can't return addr for kRLE_Index8_Config");
+ SkDEBUGFAIL("Can't return addr for kRLE_Index8_Config");
base = NULL;
break;
default:
- SkASSERT(!"Can't return addr for config");
+ SkDEBUGFAIL("Can't return addr for config");
base = NULL;
break;
}
@@ -960,6 +952,29 @@ bool SkBitmap::copyTo(SkBitmap* dst, Config dstConfig, Allocator* alloc) const {
return true;
}
+bool SkBitmap::deepCopyTo(SkBitmap* dst, Config dstConfig) const {
+ if (!this->canCopyTo(dstConfig)) {
+ return false;
+ }
+
+ // If we have a PixelRef, and it supports deep copy, use it.
+ // Currently supported only by texture-backed bitmaps.
+ if (fPixelRef) {
+ SkPixelRef* pixelRef = fPixelRef->deepCopy(dstConfig);
+ if (pixelRef) {
+ dst->setConfig(dstConfig, fWidth, fHeight);
+ dst->setPixelRef(pixelRef)->unref();
+ return true;
+ }
+ }
+
+ if (this->getTexture()) {
+ return false;
+ } else {
+ return this->copyTo(dst, dstConfig, NULL);
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@@ -1205,7 +1220,7 @@ SkFixed SkBitmap::ComputeMipLevel(SkFixed sx, SkFixed sy) {
///////////////////////////////////////////////////////////////////////////////
-static bool GetBitmapAlpha(const SkBitmap& src, uint8_t SK_RESTRICT alpha[],
+static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha,
int alphaRowBytes) {
SkASSERT(alpha != NULL);
SkASSERT(alphaRowBytes >= src.width());
@@ -1313,15 +1328,14 @@ bool SkBitmap::extractAlpha(SkBitmap* dst, const SkPaint* paint,
tmpBitmap.swap(*dst);
return true;
}
-
- SkAutoMaskImage srcCleanup(&srcM, true);
+ srcM.fImage = SkMask::AllocImage(srcM.computeImageSize());
+ SkAutoMaskFreeImage srcCleanup(srcM.fImage);
GetBitmapAlpha(*this, srcM.fImage, srcM.fRowBytes);
if (!filter->filterMask(&dstM, srcM, identity, NULL)) {
goto NO_FILTER_CASE;
}
-
- SkAutoMaskImage dstCleanup(&dstM, false);
+ SkAutoMaskFreeImage dstCleanup(dstM.fImage);
tmpBitmap.setConfig(SkBitmap::kA8_Config, dstM.fBounds.width(),
dstM.fBounds.height(), dstM.fRowBytes);
@@ -1487,7 +1501,7 @@ void SkBitmap::unflatten(SkFlattenableReadBuffer& buffer) {
case SERIALIZE_PIXELTYPE_NONE:
break;
default:
- SkASSERT(!"unrecognized pixeltype in serialized data");
+ SkDEBUGFAIL("unrecognized pixeltype in serialized data");
sk_throw();
}
}
@@ -1510,7 +1524,7 @@ SkBitmap::RLEPixels::~RLEPixels() {
void SkBitmap::validate() const {
SkASSERT(fConfig < kConfigCount);
SkASSERT(fRowBytes >= (unsigned)ComputeRowBytes((Config)fConfig, fWidth));
- SkASSERT(fFlags <= kImageIsOpaque_Flag);
+ SkASSERT(fFlags <= (kImageIsOpaque_Flag | kImageIsVolatile_Flag));
SkASSERT(fPixelLockCount >= 0);
SkASSERT(NULL == fColorTable || (unsigned)fColorTable->getRefCnt() < 10000);
SkASSERT((uint8_t)ComputeBytesPerPixel((Config)fConfig) == fBytesPerPixel);
@@ -1527,4 +1541,3 @@ void SkBitmap::validate() const {
#endif
}
#endif
-
diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp
index a16e96a..32b6f9e 100644
--- a/src/core/SkBitmapProcShader.cpp
+++ b/src/core/SkBitmapProcShader.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBitmapProcShader.h"
#include "SkColorPriv.h"
#include "SkPixelRef.h"
@@ -74,6 +81,10 @@ static bool only_scale_and_translate(const SkMatrix& matrix) {
return (matrix.getType() & ~mask) == 0;
}
+bool SkBitmapProcShader::isOpaque() const {
+ return fRawBitmap.isOpaque();
+}
+
bool SkBitmapProcShader::setContext(const SkBitmap& device,
const SkPaint& paint,
const SkMatrix& matrix) {
@@ -228,6 +239,7 @@ void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
#include "SkUnPreMultiply.h"
#include "SkColorShader.h"
+#include "SkEmptyShader.h"
// returns true and set color if the bitmap can be drawn as a single color
// (for efficiency)
@@ -264,7 +276,10 @@ SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
void* storage, size_t storageSize) {
SkShader* shader;
SkColor color;
- if (canUseColorShader(src, &color)) {
+ if (src.isNull()) {
+ SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
+ }
+ else if (canUseColorShader(src, &color)) {
SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
(color));
} else {
@@ -274,8 +289,7 @@ SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
return shader;
}
-static SkFlattenable::Registrar gBitmapProcShaderReg("SkBitmapProcShader",
- SkBitmapProcShader::CreateProc);
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkBitmapProcShader)
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkBitmapProcShader.h b/src/core/SkBitmapProcShader.h
index bd19b75..4f8d0c5 100644
--- a/src/core/SkBitmapProcShader.h
+++ b/src/core/SkBitmapProcShader.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkBitmapShader.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkBitmapProcShader_DEFINED
#define SkBitmapProcShader_DEFINED
@@ -26,6 +18,7 @@ public:
SkBitmapProcShader(const SkBitmap& src, TileMode tx, TileMode ty);
// overrides from SkShader
+ virtual bool isOpaque() const SK_OVERRIDE;
virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&);
virtual uint32_t getFlags() { return fFlags; }
virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count);
@@ -44,6 +37,7 @@ public:
// override from flattenable
virtual bool toDumpString(SkString* str) const;
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
protected:
SkBitmapProcShader(SkFlattenableReadBuffer& );
virtual void flatten(SkFlattenableWriteBuffer& );
diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp
index e54818d..3d34b20 100644
--- a/src/core/SkBitmapProcState.cpp
+++ b/src/core/SkBitmapProcState.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBitmapProcState.h"
#include "SkBitmapProcState_filter.h"
#include "SkColorPriv.h"
diff --git a/src/core/SkBitmapProcState.h b/src/core/SkBitmapProcState.h
index 303696f..98c8782 100644
--- a/src/core/SkBitmapProcState.h
+++ b/src/core/SkBitmapProcState.h
@@ -1,18 +1,11 @@
+
/*
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+ * Copyright 2007 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkBitmapProcState_DEFINED
#define SkBitmapProcState_DEFINED
diff --git a/src/core/SkBitmapProcState_filter.h b/src/core/SkBitmapProcState_filter.h
index d187983..f69e17a 100644
--- a/src/core/SkBitmapProcState_filter.h
+++ b/src/core/SkBitmapProcState_filter.h
@@ -1,24 +1,11 @@
+
/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2009 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
-#ifdef __arm__
-#ifdef ANDROID
- #include <machine/cpu-features.h>
-#endif
-#endif
#include "SkColorPriv.h"
diff --git a/src/core/SkBitmapProcState_matrix.h b/src/core/SkBitmapProcState_matrix.h
index 553bd89..f427e96 100644
--- a/src/core/SkBitmapProcState_matrix.h
+++ b/src/core/SkBitmapProcState_matrix.h
@@ -1,19 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+#include "SkMath.h"
+
#define SCALE_NOFILTER_NAME MAKENAME(_nofilter_scale)
#define SCALE_FILTER_NAME MAKENAME(_filter_scale)
diff --git a/src/core/SkBitmapProcState_sample.h b/src/core/SkBitmapProcState_sample.h
index 978d144..e6b587f 100644
--- a/src/core/SkBitmapProcState_sample.h
+++ b/src/core/SkBitmapProcState_sample.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkUtils.h"
#if DSTSIZE==32
diff --git a/src/core/SkBitmapProcState_shaderproc.h b/src/core/SkBitmapProcState_shaderproc.h
index 9a9e8c4..a3a8a99 100644
--- a/src/core/SkBitmapProcState_shaderproc.h
+++ b/src/core/SkBitmapProcState_shaderproc.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#define SCALE_FILTER_NAME MAKENAME(_filter_DX_shaderproc)
static void SCALE_FILTER_NAME(const SkBitmapProcState& s, int x, int y,
diff --git a/src/core/SkBitmapSampler.cpp b/src/core/SkBitmapSampler.cpp
index 045efd1..37cbc5a 100644
--- a/src/core/SkBitmapSampler.cpp
+++ b/src/core/SkBitmapSampler.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkBitmapSampler.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkBitmapSampler.h"
@@ -27,7 +19,7 @@ static SkTileModeProc get_tilemode_proc(SkShader::TileMode mode)
case SkShader::kMirror_TileMode:
return do_mirror_mod;
default:
- SkASSERT(!"unknown mode");
+ SkDEBUGFAIL("unknown mode");
return NULL;
}
}
@@ -346,7 +338,7 @@ SkBitmapSampler* SkBitmapSampler::Create(const SkBitmap& bm, bool doFilter,
else
return SkNEW_ARGS(ARGB32_Point_Mirror_Mod_Sampler, (bm));
default:
- SkASSERT(!"unknown mode");
+ SkDEBUGFAIL("unknown mode");
}
}
else { // tmx != tmy
@@ -373,7 +365,7 @@ SkBitmapSampler* SkBitmapSampler::Create(const SkBitmap& bm, bool doFilter,
else
return SkNEW_ARGS(RGB16_Point_Mirror_Mod_Sampler, (bm));
default:
- SkASSERT(!"unknown mode");
+ SkDEBUGFAIL("unknown mode");
}
}
else { // tmx != tmy
@@ -400,7 +392,7 @@ SkBitmapSampler* SkBitmapSampler::Create(const SkBitmap& bm, bool doFilter,
else
return SkNEW_ARGS(Index8_Point_Mirror_Mod_Sampler, (bm));
default:
- SkASSERT(!"unknown mode");
+ SkDEBUGFAIL("unknown mode");
}
}
else { // tmx != tmy
@@ -416,7 +408,7 @@ SkBitmapSampler* SkBitmapSampler::Create(const SkBitmap& bm, bool doFilter,
break;
default:
- SkASSERT(!"unknown device");
+ SkDEBUGFAIL("unknown device");
}
return SkNEW_ARGS(SkNullBitmapSampler, (bm, doFilter, tmx, tmy));
}
diff --git a/src/core/SkBitmapSampler.h b/src/core/SkBitmapSampler.h
index eeef3b3..47ec331 100644
--- a/src/core/SkBitmapSampler.h
+++ b/src/core/SkBitmapSampler.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkBitmapSampler.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkBitmapSampler_DEFINED
#define SkBitmapSampler_DEFINED
diff --git a/src/core/SkBitmapSamplerTemplate.h b/src/core/SkBitmapSamplerTemplate.h
index 00df10c..7b56af7 100644
--- a/src/core/SkBitmapSamplerTemplate.h
+++ b/src/core/SkBitmapSamplerTemplate.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkBitmapSamplerTemplate.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
/* this guy is pulled in multiple times, with the following symbols defined each time:
diff --git a/src/core/SkBitmapShader16BilerpTemplate.h b/src/core/SkBitmapShader16BilerpTemplate.h
index b70801e..0769e1c 100644
--- a/src/core/SkBitmapShader16BilerpTemplate.h
+++ b/src/core/SkBitmapShader16BilerpTemplate.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkBitmapShader16BilerpTemplate.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkFilterProc.h"
diff --git a/src/core/SkBitmapShaderTemplate.h b/src/core/SkBitmapShaderTemplate.h
index 7254aa5..bfb10d9 100644
--- a/src/core/SkBitmapShaderTemplate.h
+++ b/src/core/SkBitmapShaderTemplate.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkBitmapShaderTemplate.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef NOFILTER_BITMAP_SHADER_PREAMBLE
diff --git a/src/core/SkBitmap_scroll.cpp b/src/core/SkBitmap_scroll.cpp
index f9f197d..54110e8 100644
--- a/src/core/SkBitmap_scroll.cpp
+++ b/src/core/SkBitmap_scroll.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBitmap.h"
#include "SkRegion.h"
@@ -69,8 +76,6 @@ bool SkBitmap::scrollRect(const SkIRect* subset, int dx, int dy,
return true;
}
- // if we get this far, then we need to shift the pixels
-
char* dst = (char*)this->getPixels();
const char* src = dst;
int rowBytes = this->rowBytes(); // need rowBytes to be signed
@@ -87,7 +92,7 @@ bool SkBitmap::scrollRect(const SkIRect* subset, int dx, int dy,
// now invert rowbytes so we copy backwards in the loop
rowBytes = -rowBytes;
}
-
+
if (dx <= 0) {
src -= dx << shift;
width += dx;
@@ -96,6 +101,12 @@ bool SkBitmap::scrollRect(const SkIRect* subset, int dx, int dy,
width -= dx;
}
+ // If the X-translation would push it completely beyond the region,
+ // then there's nothing to draw.
+ if (width <= 0) {
+ return true;
+ }
+
width <<= shift; // now width is the number of bytes to move per line
while (--height >= 0) {
memmove(dst, src, width);
@@ -104,4 +115,3 @@ bool SkBitmap::scrollRect(const SkIRect* subset, int dx, int dy,
}
return true;
}
-
diff --git a/src/core/SkBlitBWMaskTemplate.h b/src/core/SkBlitBWMaskTemplate.h
index e433d36..ecbdfb3 100644
--- a/src/core/SkBlitBWMaskTemplate.h
+++ b/src/core/SkBlitBWMaskTemplate.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkBlitBWMaskTemplate.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkBitmap.h"
#include "SkMask.h"
diff --git a/src/core/SkBlitMask.h b/src/core/SkBlitMask.h
new file mode 100644
index 0000000..299f6d1
--- /dev/null
+++ b/src/core/SkBlitMask.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkBlitMask_DEFINED
+#define SkBlitMask_DEFINED
+
+#include "SkBitmap.h"
+#include "SkColor.h"
+#include "SkMask.h"
+
+class SkBlitMask {
+public:
+ /**
+ * Returns true if the device config and mask format were supported.
+ * else return false (nothing was drawn)
+ */
+ static bool BlitColor(const SkBitmap& device, const SkMask& mask,
+ const SkIRect& clip, SkColor color);
+
+ /**
+ * Function pointer that blits the mask into a device (dst) colorized
+ * by color. The number of pixels to blit is specified by width and height,
+ * but each scanline is offset by dstRB (rowbytes) and srcRB respectively.
+ */
+ typedef void (*ColorProc)(void* dst, size_t dstRB,
+ const void* mask, size_t maskRB,
+ SkColor color, int width, int height);
+
+ /**
+ * Function pointer that blits a row of src colors through a row of a mask
+ * onto a row of dst colors. The RowFactory that returns this function ptr
+ * will have been told the formats for the mask and the dst.
+ */
+ typedef void (*RowProc)(void* dst, const void* mask,
+ const SkPMColor* src, int width);
+
+ /**
+ * Public entry-point to return a blitmask ColorProc.
+ * May return NULL if config or format are not supported.
+ */
+ static ColorProc ColorFactory(SkBitmap::Config, SkMask::Format, SkColor);
+
+ /**
+ * Return either platform specific optimized blitmask ColorProc,
+ * or NULL if no optimized routine is available.
+ */
+ static ColorProc PlatformColorProcs(SkBitmap::Config, SkMask::Format, SkColor);
+
+ enum RowFlags {
+ kSrcIsOpaque_RowFlag = 1 << 0
+ };
+
+ /**
+ * Public entry-point to return a blitmask RowProc.
+ * May return NULL if config or format are not supported.
+ */
+ static RowProc RowFactory(SkBitmap::Config, SkMask::Format, RowFlags);
+
+ /**
+ * Return either platform specific optimized blitmask RowProc,
+ * or NULL if no optimized routine is available.
+ */
+ static RowProc PlatformRowProcs(SkBitmap::Config, SkMask::Format, RowFlags);
+};
+
+#endif
diff --git a/src/core/SkBlitMask_D32.cpp b/src/core/SkBlitMask_D32.cpp
new file mode 100644
index 0000000..341627a
--- /dev/null
+++ b/src/core/SkBlitMask_D32.cpp
@@ -0,0 +1,683 @@
+#include "SkBlitMask.h"
+#include "SkColor.h"
+#include "SkColorPriv.h"
+
+static void D32_A8_Color(void* SK_RESTRICT dst, size_t dstRB,
+ const void* SK_RESTRICT maskPtr, size_t maskRB,
+ SkColor color, int width, int height) {
+ SkPMColor pmc = SkPreMultiplyColor(color);
+ size_t dstOffset = dstRB - (width << 2);
+ size_t maskOffset = maskRB - width;
+ SkPMColor* SK_RESTRICT device = (SkPMColor *)dst;
+ const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr;
+
+ do {
+ int w = width;
+ do {
+ unsigned aa = *mask++;
+ *device = SkBlendARGB32(pmc, *device, aa);
+ device += 1;
+ } while (--w != 0);
+ device = (uint32_t*)((char*)device + dstOffset);
+ mask += maskOffset;
+ } while (--height != 0);
+}
+
+static void D32_A8_Opaque(void* SK_RESTRICT dst, size_t dstRB,
+ const void* SK_RESTRICT maskPtr, size_t maskRB,
+ SkColor color, int width, int height) {
+ SkPMColor pmc = SkPreMultiplyColor(color);
+ SkPMColor* SK_RESTRICT device = (SkPMColor*)dst;
+ const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr;
+
+ maskRB -= width;
+ dstRB -= (width << 2);
+ do {
+ int w = width;
+ do {
+ unsigned aa = *mask++;
+ *device = SkAlphaMulQ(pmc, SkAlpha255To256(aa)) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
+ device += 1;
+ } while (--w != 0);
+ device = (uint32_t*)((char*)device + dstRB);
+ mask += maskRB;
+ } while (--height != 0);
+}
+
+static void D32_A8_Black(void* SK_RESTRICT dst, size_t dstRB,
+ const void* SK_RESTRICT maskPtr, size_t maskRB,
+ SkColor, int width, int height) {
+ SkPMColor* SK_RESTRICT device = (SkPMColor*)dst;
+ const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr;
+
+ maskRB -= width;
+ dstRB -= (width << 2);
+ do {
+ int w = width;
+ do {
+ unsigned aa = *mask++;
+ *device = (aa << SK_A32_SHIFT) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
+ device += 1;
+ } while (--w != 0);
+ device = (uint32_t*)((char*)device + dstRB);
+ mask += maskRB;
+ } while (--height != 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static inline int upscale31To32(int value) {
+ SkASSERT((unsigned)value <= 31);
+ return value + (value >> 4);
+}
+
+static inline int blend32(int src, int dst, int scale) {
+ SkASSERT((unsigned)src <= 0xFF);
+ SkASSERT((unsigned)dst <= 0xFF);
+ SkASSERT((unsigned)scale <= 32);
+ return dst + ((src - dst) * scale >> 5);
+}
+
+static void blit_lcd16_row(SkPMColor dst[], const uint16_t src[],
+ SkColor color, int width, SkPMColor) {
+ int srcA = SkColorGetA(color);
+ int srcR = SkColorGetR(color);
+ int srcG = SkColorGetG(color);
+ int srcB = SkColorGetB(color);
+
+ srcA = SkAlpha255To256(srcA);
+
+ for (int i = 0; i < width; i++) {
+ uint16_t mask = src[i];
+ if (0 == mask) {
+ continue;
+ }
+
+ SkPMColor d = dst[i];
+
+ /* We want all of these in 5bits, hence the shifts in case one of them
+ * (green) is 6bits.
+ */
+ int maskR = SkGetPackedR16(mask) >> (SK_R16_BITS - 5);
+ int maskG = SkGetPackedG16(mask) >> (SK_G16_BITS - 5);
+ int maskB = SkGetPackedB16(mask) >> (SK_B16_BITS - 5);
+
+ // Now upscale them to 0..32, so we can use blend32
+ maskR = upscale31To32(maskR);
+ maskG = upscale31To32(maskG);
+ maskB = upscale31To32(maskB);
+
+ maskR = maskR * srcA >> 8;
+ maskG = maskG * srcA >> 8;
+ maskB = maskB * srcA >> 8;
+
+ int dstR = SkGetPackedR32(d);
+ int dstG = SkGetPackedG32(d);
+ int dstB = SkGetPackedB32(d);
+
+ // LCD blitting is only supported if the dst is known/required
+ // to be opaque
+ dst[i] = SkPackARGB32(0xFF,
+ blend32(srcR, dstR, maskR),
+ blend32(srcG, dstG, maskG),
+ blend32(srcB, dstB, maskB));
+ }
+}
+
+static void blit_lcd16_opaque_row(SkPMColor dst[], const uint16_t src[],
+ SkColor color, int width, SkPMColor opaqueDst) {
+ int srcR = SkColorGetR(color);
+ int srcG = SkColorGetG(color);
+ int srcB = SkColorGetB(color);
+
+ for (int i = 0; i < width; i++) {
+ uint16_t mask = src[i];
+ if (0 == mask) {
+ continue;
+ }
+ if (0xFFFF == mask) {
+ dst[i] = opaqueDst;
+ continue;
+ }
+
+ SkPMColor d = dst[i];
+
+ /* We want all of these in 5bits, hence the shifts in case one of them
+ * (green) is 6bits.
+ */
+ int maskR = SkGetPackedR16(mask) >> (SK_R16_BITS - 5);
+ int maskG = SkGetPackedG16(mask) >> (SK_G16_BITS - 5);
+ int maskB = SkGetPackedB16(mask) >> (SK_B16_BITS - 5);
+
+ // Now upscale them to 0..32, so we can use blend32
+ maskR = upscale31To32(maskR);
+ maskG = upscale31To32(maskG);
+ maskB = upscale31To32(maskB);
+
+ int dstR = SkGetPackedR32(d);
+ int dstG = SkGetPackedG32(d);
+ int dstB = SkGetPackedB32(d);
+
+ // LCD blitting is only supported if the dst is known/required
+ // to be opaque
+ dst[i] = SkPackARGB32(0xFF,
+ blend32(srcR, dstR, maskR),
+ blend32(srcG, dstG, maskG),
+ blend32(srcB, dstB, maskB));
+ }
+}
+
+static void D32_LCD16_Proc(void* SK_RESTRICT dst, size_t dstRB,
+ const void* SK_RESTRICT mask, size_t maskRB,
+ SkColor color, int width, int height) {
+
+ SkPMColor* dstRow = (SkPMColor*)dst;
+ const uint16_t* srcRow = (const uint16_t*)mask;
+ SkPMColor opaqueDst;
+
+ void (*proc)(SkPMColor dst[], const uint16_t src[],
+ SkColor color, int width, SkPMColor);
+ if (0xFF == SkColorGetA(color)) {
+ proc = blit_lcd16_opaque_row;
+ opaqueDst = SkPreMultiplyColor(color);
+ } else {
+ proc = blit_lcd16_row;
+ opaqueDst = 0; // ignored
+ }
+
+ do {
+ proc(dstRow, srcRow, color, width, opaqueDst);
+ dstRow = (SkPMColor*)((char*)dstRow + dstRB);
+ srcRow = (const uint16_t*)((const char*)srcRow + maskRB);
+ } while (--height != 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void blit_lcd32_opaque_row(SkPMColor* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT src,
+ SkColor color, int width) {
+ int srcR = SkColorGetR(color);
+ int srcG = SkColorGetG(color);
+ int srcB = SkColorGetB(color);
+
+ for (int i = 0; i < width; i++) {
+ SkPMColor mask = src[i];
+ if (0 == mask) {
+ continue;
+ }
+
+ SkPMColor d = dst[i];
+
+ int maskR = SkGetPackedR32(mask);
+ int maskG = SkGetPackedG32(mask);
+ int maskB = SkGetPackedB32(mask);
+
+ // Now upscale them to 0..256, so we can use SkAlphaBlend
+ maskR = SkAlpha255To256(maskR);
+ maskG = SkAlpha255To256(maskG);
+ maskB = SkAlpha255To256(maskB);
+
+ int dstR = SkGetPackedR32(d);
+ int dstG = SkGetPackedG32(d);
+ int dstB = SkGetPackedB32(d);
+
+ // LCD blitting is only supported if the dst is known/required
+ // to be opaque
+ dst[i] = SkPackARGB32(0xFF,
+ SkAlphaBlend(srcR, dstR, maskR),
+ SkAlphaBlend(srcG, dstG, maskG),
+ SkAlphaBlend(srcB, dstB, maskB));
+ }
+}
+
+static void blit_lcd32_row(SkPMColor* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT src,
+ SkColor color, int width) {
+ int srcA = SkColorGetA(color);
+ int srcR = SkColorGetR(color);
+ int srcG = SkColorGetG(color);
+ int srcB = SkColorGetB(color);
+
+ srcA = SkAlpha255To256(srcA);
+
+ for (int i = 0; i < width; i++) {
+ SkPMColor mask = src[i];
+ if (0 == mask) {
+ continue;
+ }
+
+ SkPMColor d = dst[i];
+
+ int maskR = SkGetPackedR32(mask);
+ int maskG = SkGetPackedG32(mask);
+ int maskB = SkGetPackedB32(mask);
+
+ // Now upscale them to 0..256, so we can use SkAlphaBlend
+ maskR = SkAlpha255To256(maskR);
+ maskG = SkAlpha255To256(maskG);
+ maskB = SkAlpha255To256(maskB);
+
+ maskR = maskR * srcA >> 8;
+ maskG = maskG * srcA >> 8;
+ maskB = maskB * srcA >> 8;
+
+ int dstR = SkGetPackedR32(d);
+ int dstG = SkGetPackedG32(d);
+ int dstB = SkGetPackedB32(d);
+
+ // LCD blitting is only supported if the dst is known/required
+ // to be opaque
+ dst[i] = SkPackARGB32(0xFF,
+ SkAlphaBlend(srcR, dstR, maskR),
+ SkAlphaBlend(srcG, dstG, maskG),
+ SkAlphaBlend(srcB, dstB, maskB));
+ }
+}
+
+static void D32_LCD32_Blend(void* SK_RESTRICT dst, size_t dstRB,
+ const void* SK_RESTRICT mask, size_t maskRB,
+ SkColor color, int width, int height) {
+ SkASSERT(height > 0);
+ SkPMColor* SK_RESTRICT dstRow = (SkPMColor*)dst;
+ const SkPMColor* SK_RESTRICT srcRow = (const SkPMColor*)mask;
+
+ do {
+ blit_lcd32_row(dstRow, srcRow, color, width);
+ dstRow = (SkPMColor*)((char*)dstRow + dstRB);
+ srcRow = (const SkPMColor*)((const char*)srcRow + maskRB);
+ } while (--height != 0);
+}
+
+static void D32_LCD32_Opaque(void* SK_RESTRICT dst, size_t dstRB,
+ const void* SK_RESTRICT mask, size_t maskRB,
+ SkColor color, int width, int height) {
+ SkASSERT(height > 0);
+ SkPMColor* SK_RESTRICT dstRow = (SkPMColor*)dst;
+ const SkPMColor* SK_RESTRICT srcRow = (const SkPMColor*)mask;
+
+ do {
+ blit_lcd32_opaque_row(dstRow, srcRow, color, width);
+ dstRow = (SkPMColor*)((char*)dstRow + dstRB);
+ srcRow = (const SkPMColor*)((const char*)srcRow + maskRB);
+ } while (--height != 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkBlitMask::ColorProc D32_A8_Factory(SkColor color) {
+ if (SK_ColorBLACK == color) {
+ return D32_A8_Black;
+ } else if (0xFF == SkColorGetA(color)) {
+ return D32_A8_Opaque;
+ } else {
+ return D32_A8_Color;
+ }
+}
+
+static SkBlitMask::ColorProc D32_LCD32_Factory(SkColor color) {
+ return (0xFF == SkColorGetA(color)) ? D32_LCD32_Opaque : D32_LCD32_Blend;
+}
+
+SkBlitMask::ColorProc SkBlitMask::ColorFactory(SkBitmap::Config config,
+ SkMask::Format format,
+ SkColor color) {
+ ColorProc proc = PlatformColorProcs(config, format, color);
+ if (proc) {
+ return proc;
+ }
+
+ switch (config) {
+ case SkBitmap::kARGB_8888_Config:
+ switch (format) {
+ case SkMask::kA8_Format:
+ return D32_A8_Factory(color);
+ case SkMask::kLCD16_Format:
+ return D32_LCD16_Proc;
+ case SkMask::kLCD32_Format:
+ return D32_LCD32_Factory(color);
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+bool SkBlitMask::BlitColor(const SkBitmap& device, const SkMask& mask,
+ const SkIRect& clip, SkColor color) {
+ ColorProc proc = ColorFactory(device.config(), mask.fFormat, color);
+ if (proc) {
+ int x = clip.fLeft;
+ int y = clip.fTop;
+ proc(device.getAddr32(x, y), device.rowBytes(), mask.getAddr(x, y),
+ mask.fRowBytes, color, clip.width(), clip.height());
+ return true;
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static void BW_RowProc_Blend(SkPMColor* SK_RESTRICT dst,
+ const uint8_t* SK_RESTRICT mask,
+ const SkPMColor* SK_RESTRICT src, int count) {
+ int i, octuple = (count + 7) >> 3;
+ for (i = 0; i < octuple; ++i) {
+ int m = *mask++;
+ if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); }
+ if (m & 0x40) { dst[1] = SkPMSrcOver(src[1], dst[1]); }
+ if (m & 0x20) { dst[2] = SkPMSrcOver(src[2], dst[2]); }
+ if (m & 0x10) { dst[3] = SkPMSrcOver(src[3], dst[3]); }
+ if (m & 0x08) { dst[4] = SkPMSrcOver(src[4], dst[4]); }
+ if (m & 0x04) { dst[5] = SkPMSrcOver(src[5], dst[5]); }
+ if (m & 0x02) { dst[6] = SkPMSrcOver(src[6], dst[6]); }
+ if (m & 0x01) { dst[7] = SkPMSrcOver(src[7], dst[7]); }
+ src += 8;
+ dst += 8;
+ }
+ count &= 7;
+ if (count > 0) {
+ int m = *mask;
+ do {
+ if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); }
+ m <<= 1;
+ src += 1;
+ dst += 1;
+ } while (--count > 0);
+ }
+}
+
+static void BW_RowProc_Opaque(SkPMColor* SK_RESTRICT dst,
+ const uint8_t* SK_RESTRICT mask,
+ const SkPMColor* SK_RESTRICT src, int count) {
+ int i, octuple = (count + 7) >> 3;
+ for (i = 0; i < octuple; ++i) {
+ int m = *mask++;
+ if (m & 0x80) { dst[0] = src[0]; }
+ if (m & 0x40) { dst[1] = src[1]; }
+ if (m & 0x20) { dst[2] = src[2]; }
+ if (m & 0x10) { dst[3] = src[3]; }
+ if (m & 0x08) { dst[4] = src[4]; }
+ if (m & 0x04) { dst[5] = src[5]; }
+ if (m & 0x02) { dst[6] = src[6]; }
+ if (m & 0x01) { dst[7] = src[7]; }
+ src += 8;
+ dst += 8;
+ }
+ count &= 7;
+ if (count > 0) {
+ int m = *mask;
+ do {
+ if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); }
+ m <<= 1;
+ src += 1;
+ dst += 1;
+ } while (--count > 0);
+ }
+}
+
+static void A8_RowProc_Blend(SkPMColor* SK_RESTRICT dst,
+ const uint8_t* SK_RESTRICT mask,
+ const SkPMColor* SK_RESTRICT src, int count) {
+ for (int i = 0; i < count; ++i) {
+ if (mask[i]) {
+ dst[i] = SkBlendARGB32(src[i], dst[i], mask[i]);
+ }
+ }
+}
+
+// expand the steps that SkAlphaMulQ performs, but this way we can
+// exand.. add.. combine
+// instead of
+// expand..combine add expand..combine
+//
+#define EXPAND0(v, m, s) ((v) & (m)) * (s)
+#define EXPAND1(v, m, s) (((v) >> 8) & (m)) * (s)
+#define COMBINE(e0, e1, m) ((((e0) >> 8) & (m)) | ((e1) & ~(m)))
+
+static void A8_RowProc_Opaque(SkPMColor* SK_RESTRICT dst,
+ const uint8_t* SK_RESTRICT mask,
+ const SkPMColor* SK_RESTRICT src, int count) {
+ const uint32_t rbmask = gMask_00FF00FF;
+ for (int i = 0; i < count; ++i) {
+ int m = mask[i];
+ if (m) {
+ m += (m >> 7);
+#if 1
+ // this is slightly slower than the expand/combine version, but it
+ // is much closer to the old results, so we use it for now to reduce
+ // rebaselining.
+ dst[i] = SkAlphaMulQ(src[i], m) + SkAlphaMulQ(dst[i], 256 - m);
+#else
+ uint32_t v = src[i];
+ uint32_t s0 = EXPAND0(v, rbmask, m);
+ uint32_t s1 = EXPAND1(v, rbmask, m);
+ v = dst[i];
+ uint32_t d0 = EXPAND0(v, rbmask, m);
+ uint32_t d1 = EXPAND1(v, rbmask, m);
+ dst[i] = COMBINE(s0 + d0, s1 + d1, rbmask);
+#endif
+ }
+ }
+}
+
+static int upscale31To255(int value) {
+ value = (value << 3) | (value >> 2);
+ return value;
+}
+
+static int mul(int a, int b) {
+ return a * b >> 8;
+}
+
+static int src_alpha_blend(int src, int dst, int srcA, int mask) {
+
+ return dst + mul(src - mul(srcA, dst), mask);
+}
+
+static void LCD16_RowProc_Blend(SkPMColor* SK_RESTRICT dst,
+ const uint16_t* SK_RESTRICT mask,
+ const SkPMColor* SK_RESTRICT src, int count) {
+ for (int i = 0; i < count; ++i) {
+ uint16_t m = mask[i];
+ if (0 == m) {
+ continue;
+ }
+
+ SkPMColor s = src[i];
+ SkPMColor d = dst[i];
+
+ int srcA = SkGetPackedA32(s);
+ int srcR = SkGetPackedR32(s);
+ int srcG = SkGetPackedG32(s);
+ int srcB = SkGetPackedB32(s);
+
+ srcA += srcA >> 7;
+
+ /* We want all of these in 5bits, hence the shifts in case one of them
+ * (green) is 6bits.
+ */
+ int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5);
+ int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5);
+ int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5);
+
+ maskR = upscale31To255(maskR);
+ maskG = upscale31To255(maskG);
+ maskB = upscale31To255(maskB);
+
+ int dstR = SkGetPackedR32(d);
+ int dstG = SkGetPackedG32(d);
+ int dstB = SkGetPackedB32(d);
+
+ // LCD blitting is only supported if the dst is known/required
+ // to be opaque
+ dst[i] = SkPackARGB32(0xFF,
+ src_alpha_blend(srcR, dstR, srcA, maskR),
+ src_alpha_blend(srcG, dstG, srcA, maskG),
+ src_alpha_blend(srcB, dstB, srcA, maskB));
+ }
+}
+
+static void LCD16_RowProc_Opaque(SkPMColor* SK_RESTRICT dst,
+ const uint16_t* SK_RESTRICT mask,
+ const SkPMColor* SK_RESTRICT src, int count) {
+ for (int i = 0; i < count; ++i) {
+ uint16_t m = mask[i];
+ if (0 == m) {
+ continue;
+ }
+
+ SkPMColor s = src[i];
+ SkPMColor d = dst[i];
+
+ int srcR = SkGetPackedR32(s);
+ int srcG = SkGetPackedG32(s);
+ int srcB = SkGetPackedB32(s);
+
+ /* We want all of these in 5bits, hence the shifts in case one of them
+ * (green) is 6bits.
+ */
+ int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5);
+ int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5);
+ int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5);
+
+ // Now upscale them to 0..32, so we can use blend32
+ maskR = upscale31To32(maskR);
+ maskG = upscale31To32(maskG);
+ maskB = upscale31To32(maskB);
+
+ int dstR = SkGetPackedR32(d);
+ int dstG = SkGetPackedG32(d);
+ int dstB = SkGetPackedB32(d);
+
+ // LCD blitting is only supported if the dst is known/required
+ // to be opaque
+ dst[i] = SkPackARGB32(0xFF,
+ blend32(srcR, dstR, maskR),
+ blend32(srcG, dstG, maskG),
+ blend32(srcB, dstB, maskB));
+ }
+}
+
+static void LCD32_RowProc_Blend(SkPMColor* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT mask,
+ const SkPMColor* SK_RESTRICT src, int count) {
+ for (int i = 0; i < count; ++i) {
+ SkPMColor m = mask[i];
+ if (0 == m) {
+ continue;
+ }
+
+ SkPMColor s = src[i];
+ int srcA = SkGetPackedA32(s);
+ int srcR = SkGetPackedR32(s);
+ int srcG = SkGetPackedG32(s);
+ int srcB = SkGetPackedB32(s);
+
+ srcA = SkAlpha255To256(srcA);
+
+ SkPMColor d = dst[i];
+
+ int maskR = SkGetPackedR32(m);
+ int maskG = SkGetPackedG32(m);
+ int maskB = SkGetPackedB32(m);
+
+ // Now upscale them to 0..256
+ maskR = SkAlpha255To256(maskR);
+ maskG = SkAlpha255To256(maskG);
+ maskB = SkAlpha255To256(maskB);
+
+ int dstR = SkGetPackedR32(d);
+ int dstG = SkGetPackedG32(d);
+ int dstB = SkGetPackedB32(d);
+
+ // LCD blitting is only supported if the dst is known/required
+ // to be opaque
+ dst[i] = SkPackARGB32(0xFF,
+ src_alpha_blend(srcR, dstR, srcA, maskR),
+ src_alpha_blend(srcG, dstG, srcA, maskG),
+ src_alpha_blend(srcB, dstB, srcA, maskB));
+ }
+}
+
+static void LCD32_RowProc_Opaque(SkPMColor* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT mask,
+ const SkPMColor* SK_RESTRICT src, int count) {
+ for (int i = 0; i < count; ++i) {
+ SkPMColor m = mask[i];
+ if (0 == m) {
+ continue;
+ }
+
+ SkPMColor s = src[i];
+ SkPMColor d = dst[i];
+
+ int maskR = SkGetPackedR32(m);
+ int maskG = SkGetPackedG32(m);
+ int maskB = SkGetPackedB32(m);
+
+ int srcR = SkGetPackedR32(s);
+ int srcG = SkGetPackedG32(s);
+ int srcB = SkGetPackedB32(s);
+
+ int dstR = SkGetPackedR32(d);
+ int dstG = SkGetPackedG32(d);
+ int dstB = SkGetPackedB32(d);
+
+ // Now upscale them to 0..256, so we can use SkAlphaBlend
+ maskR = SkAlpha255To256(maskR);
+ maskG = SkAlpha255To256(maskG);
+ maskB = SkAlpha255To256(maskB);
+
+ // LCD blitting is only supported if the dst is known/required
+ // to be opaque
+ dst[i] = SkPackARGB32(0xFF,
+ SkAlphaBlend(srcR, dstR, maskR),
+ SkAlphaBlend(srcG, dstG, maskG),
+ SkAlphaBlend(srcB, dstB, maskB));
+ }
+}
+
+SkBlitMask::RowProc SkBlitMask::RowFactory(SkBitmap::Config config,
+ SkMask::Format format,
+ RowFlags flags) {
+// make this opt-in until chrome can rebaseline
+ RowProc proc = PlatformRowProcs(config, format, flags);
+ if (proc) {
+ return proc;
+ }
+
+ static const RowProc gProcs[] = {
+ // need X coordinate to handle BW
+ NULL, NULL, //(RowProc)BW_RowProc_Blend, (RowProc)BW_RowProc_Opaque,
+ (RowProc)A8_RowProc_Blend, (RowProc)A8_RowProc_Opaque,
+ (RowProc)LCD16_RowProc_Blend, (RowProc)LCD16_RowProc_Opaque,
+ (RowProc)LCD32_RowProc_Blend, (RowProc)LCD32_RowProc_Opaque,
+ };
+
+ int index;
+ switch (config) {
+ case SkBitmap::kARGB_8888_Config:
+ switch (format) {
+ case SkMask::kBW_Format: index = 0; break;
+ case SkMask::kA8_Format: index = 2; break;
+ case SkMask::kLCD16_Format: index = 4; break;
+ case SkMask::kLCD32_Format: index = 6; break;
+ default:
+ return NULL;
+ }
+ if (flags & kSrcIsOpaque_RowFlag) {
+ index |= 1;
+ }
+ SkASSERT((size_t)index < SK_ARRAY_COUNT(gProcs));
+ return gProcs[index];
+ default:
+ break;
+ }
+ return NULL;
+}
+
diff --git a/src/core/SkBlitRow_D16.cpp b/src/core/SkBlitRow_D16.cpp
index 5b51c37..c815468 100644
--- a/src/core/SkBlitRow_D16.cpp
+++ b/src/core/SkBlitRow_D16.cpp
@@ -1,3 +1,10 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkBlitRow.h"
#include "SkColorPriv.h"
#include "SkDither.h"
diff --git a/src/core/SkBlitRow_D32.cpp b/src/core/SkBlitRow_D32.cpp
index 642fe7f..97aa665 100644
--- a/src/core/SkBlitRow_D32.cpp
+++ b/src/core/SkBlitRow_D32.cpp
@@ -1,4 +1,12 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkBlitRow.h"
+#include "SkBlitMask.h"
#include "SkColorPriv.h"
#include "SkUtils.h"
@@ -146,13 +154,15 @@ SkBlitRow::Proc32 SkBlitRow::ColorProcFactory() {
return proc;
}
-void SkBlitRow::Color32(SkPMColor dst[], const SkPMColor src[],
+void SkBlitRow::Color32(SkPMColor* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT src,
int count, SkPMColor color) {
if (count > 0) {
if (0 == color) {
if (src != dst) {
memcpy(dst, src, count * sizeof(SkPMColor));
}
+ return;
}
unsigned colorA = SkGetPackedA32(color);
if (255 == colorA) {
@@ -168,84 +178,3 @@ void SkBlitRow::Color32(SkPMColor dst[], const SkPMColor src[],
}
}
-///////////////////////////////////////////////////////////////////////////////
-
-static void D32_Mask_Color(void* dst, size_t dstRB, SkBitmap::Config,
- const uint8_t* mask, size_t maskRB, SkColor color,
- int width, int height) {
- SkPMColor pmc = SkPreMultiplyColor(color);
- size_t dstOffset = dstRB - (width << 2);
- size_t maskOffset = maskRB - width;
- SkPMColor *device = (SkPMColor *)dst;
- do {
- int w = width;
- do {
- unsigned aa = *mask++;
- *device = SkBlendARGB32(pmc, *device, aa);
- device += 1;
- } while (--w != 0);
- device = (uint32_t*)((char*)device + dstOffset);
- mask += maskOffset;
- } while (--height != 0);
-}
-
-static void D32_Mask_Opaque(void* dst, size_t dstRB, SkBitmap::Config,
- const uint8_t* mask, size_t maskRB, SkColor color,
- int width, int height) {
- SkPMColor pmc = SkPreMultiplyColor(color);
- uint32_t* device = (uint32_t*)dst;
-
- maskRB -= width;
- dstRB -= (width << 2);
- do {
- int w = width;
- do {
- unsigned aa = *mask++;
- *device = SkAlphaMulQ(pmc, SkAlpha255To256(aa)) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
- device += 1;
- } while (--w != 0);
- device = (uint32_t*)((char*)device + dstRB);
- mask += maskRB;
- } while (--height != 0);
-}
-
-static void D32_Mask_Black(void* dst, size_t dstRB, SkBitmap::Config,
- const uint8_t* mask, size_t maskRB, SkColor,
- int width, int height) {
- uint32_t* device = (uint32_t*)dst;
-
- maskRB -= width;
- dstRB -= (width << 2);
- do {
- int w = width;
- do {
- unsigned aa = *mask++;
- *device = (aa << SK_A32_SHIFT) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa));
- device += 1;
- } while (--w != 0);
- device = (uint32_t*)((char*)device + dstRB);
- mask += maskRB;
- } while (--height != 0);
-}
-
-SkBlitMask::Proc SkBlitMask::Factory(SkBitmap::Config config, SkColor color) {
- SkBlitMask::Proc proc = PlatformProcs(config, color);
- proc = NULL;
- if (NULL == proc) {
- switch (config) {
- case SkBitmap::kARGB_8888_Config:
- if (SK_ColorBLACK == color) {
- proc = D32_Mask_Black;
- } else if (0xFF == SkColorGetA(color)) {
- proc = D32_Mask_Opaque;
- } else {
- proc = D32_Mask_Color;
- }
- break;
- default:
- break;
- }
- }
- return proc;
-}
-
diff --git a/src/core/SkBlitRow_D4444.cpp b/src/core/SkBlitRow_D4444.cpp
index e60c721..d66d2b7 100644
--- a/src/core/SkBlitRow_D4444.cpp
+++ b/src/core/SkBlitRow_D4444.cpp
@@ -1,3 +1,10 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkBlitRow.h"
#include "SkColorPriv.h"
#include "SkDither.h"
diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp
index 08b21dc..ec16066 100644
--- a/src/core/SkBlitter.cpp
+++ b/src/core/SkBlitter.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkBlitter.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkBlitter.h"
#include "SkAntiRun.h"
@@ -32,12 +24,12 @@ const SkBitmap* SkBlitter::justAnOpaqueColor(uint32_t* value) {
}
void SkBlitter::blitH(int x, int y, int width) {
- SkASSERT(!"unimplemented");
+ SkDEBUGFAIL("unimplemented");
}
void SkBlitter::blitAntiH(int x, int y, const SkAlpha antialias[],
const int16_t runs[]) {
- SkASSERT(!"unimplemented");
+ SkDEBUGFAIL("unimplemented");
}
void SkBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
@@ -55,11 +47,25 @@ void SkBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
}
void SkBlitter::blitRect(int x, int y, int width, int height) {
+ SkASSERT(width > 0);
while (--height >= 0) {
this->blitH(x, y++, width);
}
}
+/// Default implementation doesn't check for any easy optimizations
+/// such as alpha == 0 or 255; also uses blitV(), which some subclasses
+/// may not support.
+void SkBlitter::blitAntiRect(int x, int y, int width, int height,
+ SkAlpha leftAlpha, SkAlpha rightAlpha) {
+ this->blitV(x++, y, height, leftAlpha);
+ if (width > 0) {
+ this->blitRect(x, y, width, height);
+ x += width;
+ }
+ this->blitV(x, y, height, rightAlpha);
+}
+
//////////////////////////////////////////////////////////////////////////////
static inline void bits_to_runs(SkBlitter* blitter, int x, int y,
@@ -159,7 +165,7 @@ void SkBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
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);
+ const uint8_t* aa = mask.getAddr8(clip.fLeft, clip.fTop);
sk_memset16((uint16_t*)runs, 1, width);
runs[width] = 0;
@@ -343,6 +349,37 @@ void SkRectClipBlitter::blitRect(int left, int y, int width, int height) {
}
}
+void SkRectClipBlitter::blitAntiRect(int left, int y, int width, int height,
+ SkAlpha leftAlpha, SkAlpha rightAlpha) {
+ SkIRect r;
+
+ // The *true* width of the rectangle blitted is width+2:
+ r.set(left, y, left + width + 2, y + height);
+ if (r.intersect(fClipRect)) {
+ if (r.fLeft != left) {
+ SkASSERT(r.fLeft > left);
+ leftAlpha = 255;
+ }
+ if (r.fRight != left + width + 2) {
+ SkASSERT(r.fRight < left + width + 2);
+ rightAlpha = 255;
+ }
+ if (255 == leftAlpha && 255 == rightAlpha) {
+ fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
+ } else if (1 == r.width()) {
+ if (r.fLeft == left) {
+ fBlitter->blitV(r.fLeft, r.fTop, r.height(), leftAlpha);
+ } else {
+ SkASSERT(r.fLeft == left + width + 1);
+ fBlitter->blitV(r.fLeft, r.fTop, r.height(), rightAlpha);
+ }
+ } else {
+ fBlitter->blitAntiRect(r.fLeft, r.fTop, r.width() - 2, r.height(),
+ leftAlpha, rightAlpha);
+ }
+ }
+}
+
void SkRectClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
SkASSERT(mask.fBounds.contains(clip));
@@ -438,6 +475,44 @@ void SkRgnClipBlitter::blitRect(int x, int y, int width, int height) {
}
}
+void SkRgnClipBlitter::blitAntiRect(int x, int y, int width, int height,
+ SkAlpha leftAlpha, SkAlpha rightAlpha) {
+ // The *true* width of the rectangle to blit is width + 2
+ SkIRect bounds;
+ bounds.set(x, y, x + width + 2, y + height);
+
+ SkRegion::Cliperator iter(*fRgn, bounds);
+
+ while (!iter.done()) {
+ const SkIRect& r = iter.rect();
+ SkASSERT(bounds.contains(r));
+ SkASSERT(r.fLeft >= x);
+ SkASSERT(r.fRight <= x + width + 2);
+
+ SkAlpha effectiveLeftAlpha = (r.fLeft == x) ? leftAlpha : 255;
+ SkAlpha effectiveRightAlpha = (r.fRight == x + width + 2) ?
+ rightAlpha : 255;
+
+ if (255 == effectiveLeftAlpha && 255 == effectiveRightAlpha) {
+ fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
+ } else if (1 == r.width()) {
+ if (r.fLeft == x) {
+ fBlitter->blitV(r.fLeft, r.fTop, r.height(),
+ effectiveLeftAlpha);
+ } else {
+ SkASSERT(r.fLeft == x + width + 1);
+ fBlitter->blitV(r.fLeft, r.fTop, r.height(),
+ effectiveRightAlpha);
+ }
+ } else {
+ fBlitter->blitAntiRect(r.fLeft, r.fTop, r.width() - 2, r.height(),
+ effectiveLeftAlpha, effectiveRightAlpha);
+ }
+ iter.next();
+ }
+}
+
+
void SkRgnClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
SkASSERT(mask.fBounds.contains(clip));
@@ -521,7 +596,7 @@ public:
SkASSERT(fMask->fBounds.contains(x + count - 1, y));
size_t size = fMask->computeImageSize();
- const uint8_t* alpha = fMask->getAddr(x, y);
+ const uint8_t* alpha = fMask->getAddr8(x, y);
const uint8_t* mulp = alpha + size;
const uint8_t* addp = mulp + size;
@@ -724,7 +799,7 @@ static XferInterp interpret_xfermode(const SkPaint& paint, SkXfermode* xfer,
SkBitmap::Config deviceConfig) {
SkXfermode::Mode mode;
- if (SkXfermode::IsMode(xfer, &mode)) {
+ if (SkXfermode::AsMode(xfer, &mode)) {
switch (mode) {
case SkXfermode::kSrc_Mode:
if (just_solid_color(paint)) {
@@ -871,7 +946,7 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device,
break;
default:
- SkASSERT(!"unsupported device config");
+ SkDEBUGFAIL("unsupported device config");
SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
break;
}
diff --git a/src/core/SkBlitter_4444.cpp b/src/core/SkBlitter_4444.cpp
index d976f2d..ec62523 100644
--- a/src/core/SkBlitter_4444.cpp
+++ b/src/core/SkBlitter_4444.cpp
@@ -1,20 +1,12 @@
-/* libs/graphics/sgl/SkBlitter_ARGB32.cpp
- **
- ** Copyright 2006, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkCoreBlitters.h"
#include "SkColorPriv.h"
#include "SkDither.h"
@@ -343,7 +335,7 @@ void SkARGB4444_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
int height = clip.height();
SkPMColor16* device = fDevice.getAddr16(x, y);
- const uint8_t* alpha = mask.getAddr(x, y);
+ const uint8_t* alpha = mask.getAddr8(x, y);
SkPMColor16 srcColor = fPMColor16;
unsigned devRB = fDevice.rowBytes() - (width << 1);
unsigned maskRB = mask.fRowBytes - width;
diff --git a/src/core/SkBlitter_A1.cpp b/src/core/SkBlitter_A1.cpp
index d1416ff..5638477 100644
--- a/src/core/SkBlitter_A1.cpp
+++ b/src/core/SkBlitter_A1.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkBlitter_A1.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkCoreBlitters.h"
diff --git a/src/core/SkBlitter_A8.cpp b/src/core/SkBlitter_A8.cpp
index 2eb762f..92a4971 100644
--- a/src/core/SkBlitter_A8.cpp
+++ b/src/core/SkBlitter_A8.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkBlitter_A8.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkCoreBlitters.h"
#include "SkColorPriv.h"
@@ -148,7 +140,7 @@ void SkA8_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
int width = clip.width();
int height = clip.height();
uint8_t* device = fDevice.getAddr8(x, y);
- const uint8_t* alpha = mask.getAddr(x, y);
+ const uint8_t* alpha = mask.getAddr8(x, y);
unsigned srcA = fSrcA;
while (--height >= 0) {
@@ -336,7 +328,7 @@ void SkA8_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
int width = clip.width();
int height = clip.height();
uint8_t* device = fDevice.getAddr8(x, y);
- const uint8_t* alpha = mask.getAddr(x, y);
+ const uint8_t* alpha = mask.getAddr8(x, y);
SkPMColor* span = fBuffer;
diff --git a/src/core/SkBlitter_ARGB32.cpp b/src/core/SkBlitter_ARGB32.cpp
index dec355a..24ab330 100644
--- a/src/core/SkBlitter_ARGB32.cpp
+++ b/src/core/SkBlitter_ARGB32.cpp
@@ -1,116 +1,19 @@
-/* libs/graphics/sgl/SkBlitter_ARGB32.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkCoreBlitters.h"
#include "SkColorPriv.h"
#include "SkShader.h"
#include "SkUtils.h"
#include "SkXfermode.h"
-
-#if defined(SK_SUPPORT_LCDTEXT)
-namespace skia_blitter_support {
-// subpixel helper functions from SkBlitter_ARGB32_Subpixel.cpp
-uint32_t* adjustForSubpixelClip(const SkMask& mask,
- const SkIRect& clip, const SkBitmap& device,
- int* widthAdjustment, int* heightAdjustment,
- const uint32_t** alpha32);
-extern uint32_t BlendLCDPixelWithColor(const uint32_t alphaPixel, const uint32_t originalPixel,
- const uint32_t sourcePixel);
-extern uint32_t BlendLCDPixelWithOpaqueColor(const uint32_t alphaPixel, const uint32_t originalPixel,
- const uint32_t sourcePixel);
-extern uint32_t BlendLCDPixelWithBlack(const uint32_t alphaPixel, const uint32_t originalPixel);
-}
-
-using namespace skia_blitter_support;
-#endif
+#include "SkBlitMask.h"
///////////////////////////////////////////////////////////////////////////////
-static inline int upscale31To32(int value) {
- SkASSERT((unsigned)value <= 31);
- return value + (value >> 4);
-}
-
-static inline int blend32(int src, int dst, int scale) {
- SkASSERT((unsigned)src <= 0xFF);
- SkASSERT((unsigned)dst <= 0xFF);
- SkASSERT((unsigned)scale <= 32);
- return dst + ((src - dst) * scale >> 5);
-}
-
-static void blit_lcd16_opaque(SkPMColor dst[], const uint16_t src[],
- SkPMColor color, int width) {
- int srcR = SkGetPackedR32(color);
- int srcG = SkGetPackedG32(color);
- int srcB = SkGetPackedB32(color);
-
- for (int i = 0; i < width; i++) {
- uint16_t mask = src[i];
- if (0 == mask) {
- continue;
- }
-
- SkPMColor d = dst[i];
-
- /* We want all of these in 5bits, hence the shifts in case one of them
- * (green) is 6bits.
- */
- int maskR = SkGetPackedR16(mask) >> (SK_R16_BITS - 5);
- int maskG = SkGetPackedG16(mask) >> (SK_G16_BITS - 5);
- int maskB = SkGetPackedB16(mask) >> (SK_B16_BITS - 5);
-
- // Now upscale them to 0..256, so we can use SkAlphaBlend
- maskR = upscale31To32(maskR);
- maskG = upscale31To32(maskG);
- maskB = upscale31To32(maskB);
-
- int maskA = SkMax32(SkMax32(maskR, maskG), maskB);
-
- int dstA = SkGetPackedA32(d);
- int dstR = SkGetPackedR32(d);
- int dstG = SkGetPackedG32(d);
- int dstB = SkGetPackedB32(d);
-
- dst[i] = SkPackARGB32(blend32(0xFF, dstA, maskA),
- blend32(srcR, dstR, maskR),
- blend32(srcG, dstG, maskG),
- blend32(srcB, dstB, maskB));
- }
-}
-
-static void blitmask_lcd16(const SkBitmap& device, const SkMask& mask,
- const SkIRect& clip, SkPMColor srcColor) {
- int x = clip.fLeft;
- int y = clip.fTop;
- int width = clip.width();
- int height = clip.height();
-
- SkPMColor* dstRow = device.getAddr32(x, y);
- const uint16_t* srcRow = mask.getAddrLCD16(x, y);
-
- do {
- blit_lcd16_opaque(dstRow, srcRow, srcColor, width);
- dstRow = (SkPMColor*)((char*)dstRow + device.rowBytes());
- srcRow = (const uint16_t*)((const char*)srcRow + mask.fRowBytes);
- } while (--height != 0);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-
static void SkARGB32_Blit32(const SkBitmap& device, const SkMask& mask,
const SkIRect& clip, SkPMColor srcColor) {
U8CPU alpha = SkGetPackedA32(srcColor);
@@ -126,7 +29,7 @@ static void SkARGB32_Blit32(const SkBitmap& device, const SkMask& mask,
int height = clip.height();
SkPMColor* dstRow = device.getAddr32(x, y);
- const SkPMColor* srcRow = reinterpret_cast<const SkPMColor*>(mask.getAddr(x, y));
+ const SkPMColor* srcRow = reinterpret_cast<const SkPMColor*>(mask.getAddr8(x, y));
do {
proc(dstRow, srcRow, width, alpha);
@@ -150,9 +53,6 @@ SkARGB32_Blitter::SkARGB32_Blitter(const SkBitmap& device, const SkPaint& paint)
fPMColor = SkPackARGB32(fSrcA, fSrcR, fSrcG, fSrcB);
fColor32Proc = SkBlitRow::ColorProcFactory();
-
- // init the pro for blitmask
- fBlitMaskProc = SkBlitMask::Factory(SkBitmap::kARGB_8888_Config, color);
}
const SkBitmap* SkARGB32_Blitter::justAnOpaqueColor(uint32_t* value) {
@@ -254,84 +154,33 @@ void SkARGB32_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
return;
}
+ if (SkBlitMask::BlitColor(fDevice, mask, clip, fColor)) {
+ return;
+ }
+
if (mask.fFormat == SkMask::kBW_Format) {
SkARGB32_BlendBW(fDevice, mask, clip, fPMColor, SkAlpha255To256(255 - fSrcA));
- return;
} else if (SkMask::kARGB32_Format == mask.fFormat) {
SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
- return;
- } else if (SkMask::kLCD16_Format == mask.fFormat) {
- blitmask_lcd16(fDevice, mask, clip, fPMColor);
- return;
}
-
- int x = clip.fLeft;
- int y = clip.fTop;
-
- fBlitMaskProc(fDevice.getAddr32(x, y), fDevice.rowBytes(),
- SkBitmap::kARGB_8888_Config,
- mask.getAddr(x, y), mask.fRowBytes,
- fColor, clip.width(), clip.height());
}
void SkARGB32_Opaque_Blitter::blitMask(const SkMask& mask,
const SkIRect& clip) {
SkASSERT(mask.fBounds.contains(clip));
+ if (SkBlitMask::BlitColor(fDevice, mask, clip, fColor)) {
+ return;
+ }
+
if (mask.fFormat == SkMask::kBW_Format) {
SkARGB32_BlitBW(fDevice, mask, clip, fPMColor);
- return;
} else if (SkMask::kARGB32_Format == mask.fFormat) {
SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
- return;
- } else if (SkMask::kLCD16_Format == mask.fFormat) {
- blitmask_lcd16(fDevice, mask, clip, fPMColor);
- return;
}
-
- int x = clip.fLeft;
- int y = clip.fTop;
- int width = clip.width();
- int height = clip.height();
-
-#if defined(SK_SUPPORT_LCDTEXT)
- const bool lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format;
- const bool verticalLCDMode = mask.fFormat == SkMask::kVerticalLCD_Format;
-
- // In LCD mode the masks have either an extra couple of rows or columns on the edges.
- if (lcdMode || verticalLCDMode) {
- int widthAdjustment, heightAdjustment;
- const uint32_t* alpha32;
- uint32_t* device = adjustForSubpixelClip(mask, clip, fDevice, &widthAdjustment, &heightAdjustment, &alpha32);
-
- width += widthAdjustment;
- height += heightAdjustment;
-
- unsigned devRB = fDevice.rowBytes() - (width << 2);
- unsigned alphaExtraRowWords = mask.rowWordsLCD() - width;
- SkPMColor srcColor = fPMColor;
-
- do {
- unsigned w = width;
- do {
- const uint32_t alphaPixel = *alpha32++;
- const uint32_t originalPixel = *device;
- *device++ = BlendLCDPixelWithOpaqueColor(alphaPixel, originalPixel, srcColor);
- } while (--w != 0);
- device = (uint32_t*)((char*)device + devRB);
- alpha32 += alphaExtraRowWords;
- } while (--height != 0);
-
- return;
- }
-#endif
-
- fBlitMaskProc(fDevice.getAddr32(x, y), fDevice.rowBytes(),
- SkBitmap::kARGB_8888_Config,
- mask.getAddr(x, y), mask.fRowBytes, fColor, width, height);
}
-//////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
void SkARGB32_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
if (alpha == 0 || fSrcA == 0) {
@@ -346,17 +195,9 @@ void SkARGB32_Blitter::blitV(int x, int y, int height, SkAlpha 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[0] = color + SkAlphaMulQ(device[0], dst_scale);
device = (uint32_t*)((char*)device + rowBytes);
}
}
@@ -384,74 +225,6 @@ void SkARGB32_Blitter::blitRect(int x, int y, int width, int height) {
///////////////////////////////////////////////////////////////////////
-void SkARGB32_Black_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
- SkASSERT(mask.fBounds.contains(clip));
-
- if (mask.fFormat == SkMask::kBW_Format) {
- SkPMColor black = (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT);
-
- SkARGB32_BlitBW(fDevice, mask, clip, black);
- } else if (SkMask::kARGB32_Format == mask.fFormat) {
- SkARGB32_Blit32(fDevice, mask, clip, fPMColor);
- } else if (SkMask::kLCD16_Format == mask.fFormat) {
- blitmask_lcd16(fDevice, mask, clip, fPMColor);
- } else {
-#if defined(SK_SUPPORT_LCDTEXT)
- const bool lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format;
- const bool verticalLCDMode = mask.fFormat == SkMask::kVerticalLCD_Format;
-#endif
-
- // In LCD mode the masks have either an extra couple of rows or columns on the edges.
- unsigned width = clip.width();
- unsigned height = clip.height();
-
- SkASSERT((int)height > 0);
- SkASSERT((int)width > 0);
-
-#if defined(SK_SUPPORT_LCDTEXT)
- if (lcdMode || verticalLCDMode) {
- int widthAdjustment, heightAdjustment;
- const uint32_t* alpha32;
- uint32_t* device = adjustForSubpixelClip(mask, clip, fDevice, &widthAdjustment, &heightAdjustment, &alpha32);
-
- width += widthAdjustment;
- height += heightAdjustment;
-
- unsigned deviceRB = fDevice.rowBytes() - (width << 2);
- unsigned alphaExtraRowWords = mask.rowWordsLCD() - width;
-
- do {
- unsigned w = width;
- do {
- const uint32_t alphaPixel = *alpha32++;
- const uint32_t originalPixel = *device;
- *device++ = BlendLCDPixelWithBlack(alphaPixel, originalPixel);
- } while (--w != 0);
- device = (uint32_t*)((char*)device + deviceRB);
- alpha32 += alphaExtraRowWords;
- } while (--height != 0);
-
- return;
- }
-#endif
-
- uint32_t* device = fDevice.getAddr32(clip.fLeft, clip.fTop);
- unsigned maskRB = mask.fRowBytes - width;
- unsigned deviceRB = fDevice.rowBytes() - (width << 2);
- const uint8_t* alpha = mask.getAddr(clip.fLeft, clip.fTop);
- do {
- unsigned w = width;
- do {
- unsigned aa = *alpha++;
- *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);
- }
-}
-
void SkARGB32_Black_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
const int16_t runs[]) {
uint32_t* device = fDevice.getAddr32(x, y);
@@ -483,7 +256,7 @@ void SkARGB32_Black_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
}
}
-//////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device,
const SkPaint& paint) : INHERITED(device, paint) {
@@ -525,8 +298,6 @@ void SkARGB32_Shader_Blitter::blitH(int x, int y, int width) {
}
}
-///////////////////////////////////////////////////////////////////////////////////////////////
-
void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
const int16_t runs[]) {
SkPMColor* span = fBuffer;
@@ -600,3 +371,61 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
}
}
}
+
+void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
+ // we only handle kA8 with an xfermode
+ if (fXfermode && (SkMask::kA8_Format != mask.fFormat)) {
+ this->INHERITED::blitMask(mask, clip);
+ return;
+ }
+
+ SkASSERT(mask.fBounds.contains(clip));
+
+ SkBlitMask::RowProc proc = NULL;
+ if (!fXfermode) {
+ unsigned flags = 0;
+ if (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) {
+ flags |= SkBlitMask::kSrcIsOpaque_RowFlag;
+ }
+ proc = SkBlitMask::RowFactory(SkBitmap::kARGB_8888_Config, mask.fFormat,
+ (SkBlitMask::RowFlags)flags);
+ if (NULL == proc) {
+ this->INHERITED::blitMask(mask, clip);
+ return;
+ }
+ }
+
+ const int x = clip.fLeft;
+ const int width = clip.width();
+ int y = clip.fTop;
+ int height = clip.height();
+
+ char* dstRow = (char*)fDevice.getAddr32(x, y);
+ const size_t dstRB = fDevice.rowBytes();
+ const uint8_t* maskRow = (const uint8_t*)mask.getAddr(x, y);
+ const size_t maskRB = mask.fRowBytes;
+
+ SkShader* shader = fShader;
+ SkPMColor* span = fBuffer;
+
+ if (fXfermode) {
+ SkASSERT(SkMask::kA8_Format == mask.fFormat);
+ SkXfermode* xfer = fXfermode;
+ do {
+ shader->shadeSpan(x, y, span, width);
+ xfer->xfer32((SkPMColor*)dstRow, span, width, maskRow);
+ dstRow += dstRB;
+ maskRow += maskRB;
+ y += 1;
+ } while (--height > 0);
+ } else {
+ do {
+ shader->shadeSpan(x, y, span, width);
+ proc(dstRow, maskRow, span, width);
+ dstRow += dstRB;
+ maskRow += maskRB;
+ y += 1;
+ } while (--height > 0);
+ }
+}
+
diff --git a/src/core/SkBlitter_ARGB32_Subpixel.cpp b/src/core/SkBlitter_ARGB32_Subpixel.cpp
deleted file mode 100644
index 5d334ae..0000000
--- a/src/core/SkBlitter_ARGB32_Subpixel.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/* libs/graphics/sgl/SkBlitter_ARGB32_Subpixel.cpp
-**
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-/* LCD blend functions:
-
- These functions take an alpha pixel of the following form:
- red, green, blue -> an alpha value for the given colour component.
- alpha -> the max of the red, green and blue alpha values.
-
- These alpha pixels result from subpixel renderering. The R/G/B values have
- already been corrected for RGB/BGR element ordering.
-
- The alpha pixel is blended with an original pixel and a source colour,
- resulting in a new pixel value.
-*/
-
-#include "SkBitmap.h"
-#include "SkColorPriv.h"
-#include "SkMask.h"
-#include "SkRect.h"
-
-namespace skia_blitter_support {
-
-/** Given a clip region which describes the desired location of a glyph and a
- bitmap to which an LCD glyph is to be blitted, return a pointer to the
- SkBitmap's pixels and output width and height adjusts for the glyph as well
- as a pointer into the glyph.
-
- Recall that LCD glyphs have extra rows (vertical mode) or columns
- (horizontal mode) at the edges as a result of low-pass filtering. If we
- wanted to put a glyph on the hard-left edge of bitmap, we would have to know
- to start one pixel into the glyph, as well as to only add 1 to the recorded
- glyph width etc. This function encapsulates that behaviour.
-
- @param mask The glyph to be blitted.
- @param clip The clip region describing the desired location of the glyph.
- @param device The SkBitmap target for the blit.
- @param widthAdjustment (output) a number to add to the glyph's nominal width.
- @param heightAdjustment (output) a number to add to the glyph's nominal width.
- @param alpha32 (output) a pointer into the 32-bit subpixel alpha data for the glyph
-*/
-uint32_t* adjustForSubpixelClip(const SkMask& mask,
- const SkIRect& clip, const SkBitmap& device,
- int* widthAdjustment, int* heightAdjustment,
- const uint32_t** alpha32) {
- const bool lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format;
- const bool verticalLCDMode = mask.fFormat == SkMask::kVerticalLCD_Format;
- const int leftOffset = clip.fLeft > 0 ? lcdMode : 0;
- const int topOffset = clip.fTop > 0 ? verticalLCDMode : 0;
- const int rightOffset = lcdMode && clip.fRight < device.width();
- const int bottomOffset = verticalLCDMode && clip.fBottom < device.height();
-
- uint32_t* device32 = device.getAddr32(clip.fLeft - leftOffset, clip.fTop - topOffset);
- *alpha32 = mask.getAddrLCD(clip.fLeft + (lcdMode && !leftOffset),
- clip.fTop + (verticalLCDMode && !topOffset));
-
- *widthAdjustment = leftOffset + rightOffset;
- *heightAdjustment = topOffset + bottomOffset;
-
- return device32;
-}
-
-uint32_t BlendLCDPixelWithColor(const uint32_t alphaPixel, const uint32_t originalPixel,
- const uint32_t sourcePixel) {
- unsigned alphaRed = SkAlpha255To256(SkGetPackedR32(alphaPixel));
- unsigned alphaGreen = SkAlpha255To256(SkGetPackedG32(alphaPixel));
- unsigned alphaBlue = SkAlpha255To256(SkGetPackedB32(alphaPixel));
-
- unsigned sourceRed = SkGetPackedR32(sourcePixel);
- unsigned sourceGreen = SkGetPackedG32(sourcePixel);
- unsigned sourceBlue = SkGetPackedB32(sourcePixel);
- unsigned sourceAlpha = SkAlpha255To256(SkGetPackedA32(sourcePixel));
-
- alphaRed = (alphaRed * sourceAlpha) >> 8;
- alphaGreen = (alphaGreen * sourceAlpha) >> 8;
- alphaBlue = (alphaBlue * sourceAlpha) >> 8;
- unsigned alphaAlpha = SkMax32(SkMax32(alphaRed, alphaBlue), alphaGreen);
-
- unsigned originalRed = SkGetPackedR32(originalPixel);
- unsigned originalGreen = SkGetPackedG32(originalPixel);
- unsigned originalBlue = SkGetPackedB32(originalPixel);
- unsigned originalAlpha = SkGetPackedA32(originalPixel);
-
- return SkPackARGB32(SkMin32(255u, alphaAlpha + originalAlpha),
- ((sourceRed * alphaRed) >> 8) + ((originalRed * (256 - alphaRed)) >> 8),
- ((sourceGreen * alphaGreen) >> 8) + ((originalGreen * (256 - alphaGreen)) >> 8),
- ((sourceBlue * alphaBlue) >> 8) + ((originalBlue * (256 - alphaBlue)) >> 8));
-
-}
-
-uint32_t BlendLCDPixelWithOpaqueColor(const uint32_t alphaPixel, const uint32_t originalPixel,
- const uint32_t sourcePixel) {
- unsigned alphaRed = SkAlpha255To256(SkGetPackedR32(alphaPixel));
- unsigned alphaGreen = SkAlpha255To256(SkGetPackedG32(alphaPixel));
- unsigned alphaBlue = SkAlpha255To256(SkGetPackedB32(alphaPixel));
- unsigned alphaAlpha = SkGetPackedA32(alphaPixel);
-
- unsigned sourceRed = SkGetPackedR32(sourcePixel);
- unsigned sourceGreen = SkGetPackedG32(sourcePixel);
- unsigned sourceBlue = SkGetPackedB32(sourcePixel);
-
- unsigned originalRed = SkGetPackedR32(originalPixel);
- unsigned originalGreen = SkGetPackedG32(originalPixel);
- unsigned originalBlue = SkGetPackedB32(originalPixel);
- unsigned originalAlpha = SkGetPackedA32(originalPixel);
-
- return SkPackARGB32(SkMin32(255u, alphaAlpha + originalAlpha),
- ((sourceRed * alphaRed) >> 8) + ((originalRed * (256 - alphaRed)) >> 8),
- ((sourceGreen * alphaGreen) >> 8) + ((originalGreen * (256 - alphaGreen)) >> 8),
- ((sourceBlue * alphaBlue) >> 8) + ((originalBlue * (256 - alphaBlue)) >> 8));
-}
-
-uint32_t BlendLCDPixelWithBlack(const uint32_t alphaPixel, const uint32_t originalPixel) {
- unsigned alphaRed = SkAlpha255To256(SkGetPackedR32(alphaPixel));
- unsigned alphaGreen = SkAlpha255To256(SkGetPackedG32(alphaPixel));
- unsigned alphaBlue = SkAlpha255To256(SkGetPackedB32(alphaPixel));
- unsigned alphaAlpha = SkGetPackedA32(alphaPixel);
-
- unsigned originalRed = SkGetPackedR32(originalPixel);
- unsigned originalGreen = SkGetPackedG32(originalPixel);
- unsigned originalBlue = SkGetPackedB32(originalPixel);
- unsigned originalAlpha = SkGetPackedA32(originalPixel);
-
- return SkPackARGB32(SkMin32(255u, alphaAlpha + originalAlpha),
- (originalRed * (256 - alphaRed)) >> 8,
- (originalGreen * (256 - alphaGreen)) >> 8,
- (originalBlue * (256 - alphaBlue)) >> 8);
-}
-
-} // namespace skia_blitter_support
diff --git a/src/core/SkBlitter_RGB16.cpp b/src/core/SkBlitter_RGB16.cpp
index 882866b..8a4d454 100644
--- a/src/core/SkBlitter_RGB16.cpp
+++ b/src/core/SkBlitter_RGB16.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkBlitter_RGB16.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkBlitRow.h"
#include "SkCoreBlitters.h"
@@ -63,10 +55,12 @@ class SkRGB16_Blitter : public SkRasterBlitter {
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 int16_t runs[]);
+ virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
+ const int16_t* 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 SkIRect&);
+ virtual void blitMask(const SkMask&,
+ const SkIRect&);
virtual const SkBitmap* justAnOpaqueColor(uint32_t*);
protected:
@@ -88,10 +82,12 @@ class SkRGB16_Opaque_Blitter : public SkRGB16_Blitter {
public:
SkRGB16_Opaque_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 int16_t runs[]);
+ virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
+ const int16_t* 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 SkIRect&);
+ virtual void blitMask(const SkMask&,
+ const SkIRect&);
private:
typedef SkRGB16_Blitter INHERITED;
@@ -102,7 +98,8 @@ class SkRGB16_Black_Blitter : public SkRGB16_Opaque_Blitter {
public:
SkRGB16_Black_Blitter(const SkBitmap& device, const SkPaint& paint);
virtual void blitMask(const SkMask&, const SkIRect&);
- virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]);
+ virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
+ const int16_t* runs);
private:
typedef SkRGB16_Opaque_Blitter INHERITED;
@@ -114,7 +111,8 @@ 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 int16_t runs[]);
+ virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
+ const int16_t* runs);
virtual void blitRect(int x, int y, int width, int height);
protected:
@@ -134,7 +132,8 @@ class SkRGB16_Shader16_Blitter : public SkRGB16_Shader_Blitter {
public:
SkRGB16_Shader16_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 int16_t runs[]);
+ virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
+ const int16_t* runs);
virtual void blitRect(int x, int y, int width, int height);
private:
@@ -146,7 +145,8 @@ 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 int16_t runs[]);
+ virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
+ const int16_t* runs);
private:
SkXfermode* fXfermode;
@@ -202,14 +202,13 @@ static inline black_8_pixels(U8CPU mask, uint16_t dst[])
#define SK_BLITBWMASK_DEVTYPE uint16_t
#include "SkBlitBWMaskTemplate.h"
-void SkRGB16_Black_Blitter::blitMask(const SkMask& SK_RESTRICT mask,
- const SkIRect& SK_RESTRICT clip)
- SK_RESTRICT {
+void SkRGB16_Black_Blitter::blitMask(const SkMask& mask,
+ const SkIRect& clip) {
if (mask.fFormat == SkMask::kBW_Format) {
SkRGB16_Black_BlitBW(fDevice, mask, clip);
} else {
uint16_t* SK_RESTRICT device = fDevice.getAddr16(clip.fLeft, clip.fTop);
- const uint8_t* SK_RESTRICT alpha = mask.getAddr(clip.fLeft, clip.fTop);
+ const uint8_t* SK_RESTRICT alpha = mask.getAddr8(clip.fLeft, clip.fTop);
unsigned width = clip.width();
unsigned height = clip.height();
unsigned deviceRB = fDevice.rowBytes() - (width << 1);
@@ -235,8 +234,7 @@ void SkRGB16_Black_Blitter::blitMask(const SkMask& SK_RESTRICT mask,
void SkRGB16_Black_Blitter::blitAntiH(int x, int y,
const SkAlpha* SK_RESTRICT antialias,
- const int16_t* SK_RESTRICT runs)
- SK_RESTRICT {
+ const int16_t* SK_RESTRICT runs) {
uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
for (;;) {
@@ -273,7 +271,7 @@ SkRGB16_Opaque_Blitter::SkRGB16_Opaque_Blitter(const SkBitmap& device,
const SkPaint& paint)
: INHERITED(device, paint) {}
-void SkRGB16_Opaque_Blitter::blitH(int x, int y, int width) SK_RESTRICT {
+void SkRGB16_Opaque_Blitter::blitH(int x, int y, int width) {
SkASSERT(width > 0);
SkASSERT(x + width <= fDevice.width());
uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
@@ -298,7 +296,7 @@ static inline int Bool2Int(int value) {
void SkRGB16_Opaque_Blitter::blitAntiH(int x, int y,
const SkAlpha* SK_RESTRICT antialias,
- const int16_t* SK_RESTRICT runs) SK_RESTRICT {
+ const int16_t* SK_RESTRICT runs) {
uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
uint16_t srcColor = fRawColor16;
uint32_t srcExpanded = fExpandedRaw16;
@@ -372,15 +370,15 @@ static U16CPU blend_compact(uint32_t src32, uint32_t dst32, unsigned scale5) {
return SkCompact_rgb_16(dst32 + ((src32 - dst32) * scale5 >> 5));
}
-void SkRGB16_Opaque_Blitter::blitMask(const SkMask& SK_RESTRICT mask,
- const SkIRect& SK_RESTRICT clip) SK_RESTRICT {
+void SkRGB16_Opaque_Blitter::blitMask(const SkMask& mask,
+ const SkIRect& clip) {
if (mask.fFormat == SkMask::kBW_Format) {
SkRGB16_BlitBW(fDevice, mask, clip, fColor16);
return;
}
uint16_t* SK_RESTRICT device = fDevice.getAddr16(clip.fLeft, clip.fTop);
- const uint8_t* SK_RESTRICT alpha = mask.getAddr(clip.fLeft, clip.fTop);
+ const uint8_t* SK_RESTRICT alpha = mask.getAddr8(clip.fLeft, clip.fTop);
int width = clip.width();
int height = clip.height();
unsigned deviceRB = fDevice.rowBytes() - (width << 1);
@@ -572,7 +570,7 @@ static inline void blend32_16_row(SkPMColor src, uint16_t dst[], int count) {
} while (--count != 0);
}
-void SkRGB16_Blitter::blitH(int x, int y, int width) SK_RESTRICT {
+void SkRGB16_Blitter::blitH(int x, int y, int width) {
SkASSERT(width > 0);
SkASSERT(x + width <= fDevice.width());
uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
@@ -583,7 +581,7 @@ void SkRGB16_Blitter::blitH(int x, int y, int width) SK_RESTRICT {
void SkRGB16_Blitter::blitAntiH(int x, int y,
const SkAlpha* SK_RESTRICT antialias,
- const int16_t* SK_RESTRICT runs) SK_RESTRICT {
+ const int16_t* SK_RESTRICT runs) {
uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
uint32_t srcExpanded = fExpandedRaw16;
unsigned scale = fScale;
@@ -632,15 +630,15 @@ static inline void blend_8_pixels(U8CPU bw, uint16_t dst[], unsigned dst_scale,
#define SK_BLITBWMASK_DEVTYPE uint16_t
#include "SkBlitBWMaskTemplate.h"
-void SkRGB16_Blitter::blitMask(const SkMask& SK_RESTRICT mask,
- const SkIRect& SK_RESTRICT clip) SK_RESTRICT {
+void SkRGB16_Blitter::blitMask(const SkMask& mask,
+ const SkIRect& clip) {
if (mask.fFormat == SkMask::kBW_Format) {
SkRGB16_BlendBW(fDevice, mask, clip, 256 - fScale, fColor16);
return;
}
uint16_t* SK_RESTRICT device = fDevice.getAddr16(clip.fLeft, clip.fTop);
- const uint8_t* SK_RESTRICT alpha = mask.getAddr(clip.fLeft, clip.fTop);
+ const uint8_t* SK_RESTRICT alpha = mask.getAddr8(clip.fLeft, clip.fTop);
int width = clip.width();
int height = clip.height();
unsigned deviceRB = fDevice.rowBytes() - (width << 1);
@@ -697,7 +695,7 @@ SkRGB16_Shader16_Blitter::SkRGB16_Shader16_Blitter(const SkBitmap& device,
SkASSERT(SkShader::CanCallShadeSpan16(fShaderFlags));
}
-void SkRGB16_Shader16_Blitter::blitH(int x, int y, int width) SK_RESTRICT {
+void SkRGB16_Shader16_Blitter::blitH(int x, int y, int width) {
SkASSERT(x + width <= fDevice.width());
uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
@@ -760,8 +758,7 @@ void SkRGB16_Shader16_Blitter::blitRect(int x, int y, int width, int height) {
void SkRGB16_Shader16_Blitter::blitAntiH(int x, int y,
const SkAlpha* SK_RESTRICT antialias,
- const int16_t* SK_RESTRICT runs)
- SK_RESTRICT {
+ const int16_t* SK_RESTRICT runs) {
SkShader* shader = fShader;
SkPMColor* SK_RESTRICT span = fBuffer;
uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
@@ -893,8 +890,7 @@ static inline int count_nonzero_span(const int16_t runs[], const SkAlpha aa[]) {
void SkRGB16_Shader_Blitter::blitAntiH(int x, int y,
const SkAlpha* SK_RESTRICT antialias,
- const int16_t* SK_RESTRICT runs)
- SK_RESTRICT {
+ const int16_t* SK_RESTRICT runs) {
SkShader* shader = fShader;
SkPMColor* SK_RESTRICT span = fBuffer;
uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
@@ -971,7 +967,7 @@ void SkRGB16_Shader_Xfermode_Blitter::blitH(int x, int y, int width) {
void SkRGB16_Shader_Xfermode_Blitter::blitAntiH(int x, int y,
const SkAlpha* SK_RESTRICT antialias,
- const int16_t* SK_RESTRICT runs) SK_RESTRICT {
+ const int16_t* SK_RESTRICT runs) {
SkShader* shader = fShader;
SkXfermode* mode = fXfermode;
SkPMColor* SK_RESTRICT span = fBuffer;
diff --git a/src/core/SkBlitter_Sprite.cpp b/src/core/SkBlitter_Sprite.cpp
index d11adbc..c2a0062 100644
--- a/src/core/SkBlitter_Sprite.cpp
+++ b/src/core/SkBlitter_Sprite.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkBlitter_Sprite.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSpriteBlitter.h"
@@ -36,20 +28,20 @@ void SkSpriteBlitter::setup(const SkBitmap& device, int left, int top,
#ifdef SK_DEBUG
void SkSpriteBlitter::blitH(int x, int y, int width) {
- SkASSERT(!"how did we get here?");
+ SkDEBUGFAIL("how did we get here?");
}
void SkSpriteBlitter::blitAntiH(int x, int y, const SkAlpha antialias[],
const int16_t runs[]) {
- SkASSERT(!"how did we get here?");
+ SkDEBUGFAIL("how did we get here?");
}
void SkSpriteBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
- SkASSERT(!"how did we get here?");
+ SkDEBUGFAIL("how did we get here?");
}
void SkSpriteBlitter::blitMask(const SkMask&, const SkIRect& clip) {
- SkASSERT(!"how did we get here?");
+ SkDEBUGFAIL("how did we get here?");
}
#endif
diff --git a/src/core/SkBuffer.cpp b/src/core/SkBuffer.cpp
index 5768ca4..915264d 100644
--- a/src/core/SkBuffer.cpp
+++ b/src/core/SkBuffer.cpp
@@ -1,19 +1,11 @@
-/* libs/corecg/SkBuffer.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkBuffer.h"
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 7d29f74..edfb3a9 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006-2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2008 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkCanvas.h"
#include "SkBounder.h"
#include "SkDevice.h"
@@ -21,12 +14,12 @@
#include "SkDrawFilter.h"
#include "SkDrawLooper.h"
#include "SkPicture.h"
+#include "SkRasterClip.h"
#include "SkScalarCompare.h"
-#include "SkShape.h"
#include "SkTemplates.h"
+#include "SkTextFormatParams.h"
#include "SkTLazy.h"
#include "SkUtils.h"
-#include <new>
//#define SK_TRACE_SAVERESTORE
@@ -73,14 +66,14 @@ static SkCanvas::EdgeType paint2EdgeType(const SkPaint* paint) {
struct DeviceCM {
DeviceCM* fNext;
SkDevice* fDevice;
- SkRegion fClip;
+ SkRasterClip fClip;
const SkMatrix* fMatrix;
SkPaint* fPaint; // may be null (in the future)
// optional, related to canvas' external matrix
const SkMatrix* fMVMatrix;
const SkMatrix* fExtMatrix;
- DeviceCM(SkDevice* device, int x, int y, const SkPaint* paint)
+ DeviceCM(SkDevice* device, int x, int y, const SkPaint* paint)
: fNext(NULL) {
if (NULL != device) {
device->ref();
@@ -88,18 +81,18 @@ struct DeviceCM {
}
fDevice = device;
fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
- }
+ }
- ~DeviceCM() {
+ ~DeviceCM() {
if (NULL != fDevice) {
fDevice->unlockPixels();
fDevice->unref();
}
- SkDELETE(fPaint);
- }
+ SkDELETE(fPaint);
+ }
- void updateMC(const SkMatrix& totalMatrix, const SkRegion& totalClip,
- const SkClipStack& clipStack, SkRegion* updateClip) {
+ void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip,
+ const SkClipStack& clipStack, SkRasterClip* updateClip) {
int x = fDevice->getOrigin().x();
int y = fDevice->getOrigin().y();
int width = fDevice->width();
@@ -117,16 +110,16 @@ struct DeviceCM {
totalClip.translate(-x, -y, &fClip);
}
- fClip.op(0, 0, width, height, SkRegion::kIntersect_Op);
+ fClip.op(SkIRect::MakeWH(width, height), SkRegion::kIntersect_Op);
// intersect clip, but don't translate it (yet)
if (updateClip) {
- updateClip->op(x, y, x + width, y + height,
+ updateClip->op(SkIRect::MakeXYWH(x, y, width, height),
SkRegion::kDifference_Op);
}
- fDevice->setMatrixClip(*fMatrix, fClip, clipStack);
+ fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack);
#ifdef SK_DEBUG
if (!fClip.isEmpty()) {
@@ -161,9 +154,9 @@ private:
class SkCanvas::MCRec {
public:
MCRec* fNext;
- SkMatrix* fMatrix; // points to either fMatrixStorage or prev MCRec
- SkRegion* fRegion; // points to either fRegionStorage or prev MCRec
- SkDrawFilter* fFilter; // the current filter (or null)
+ SkMatrix* fMatrix; // points to either fMatrixStorage or prev MCRec
+ SkRasterClip* fRasterClip; // points to either fRegionStorage or prev MCRec
+ SkDrawFilter* fFilter; // the current filter (or null)
DeviceCM* fLayer;
/* If there are any layers in the stack, this points to the top-most
@@ -172,7 +165,7 @@ public:
reference counted, since the real owner is either our fLayer field,
or a previous one in a lower level.)
*/
- DeviceCM* fTopLayer;
+ DeviceCM* fTopLayer;
MCRec(const MCRec* prev, int flags) {
if (NULL != prev) {
@@ -184,10 +177,10 @@ public:
}
if (flags & SkCanvas::kClip_SaveFlag) {
- fRegionStorage = *prev->fRegion;
- fRegion = &fRegionStorage;
+ fRasterClipStorage = *prev->fRasterClip;
+ fRasterClip = &fRasterClipStorage;
} else {
- fRegion = prev->fRegion;
+ fRasterClip = prev->fRasterClip;
}
fFilter = prev->fFilter;
@@ -198,7 +191,7 @@ public:
fMatrixStorage.reset();
fMatrix = &fMatrixStorage;
- fRegion = &fRegionStorage;
+ fRasterClip = &fRasterClipStorage;
fFilter = NULL;
fTopLayer = NULL;
}
@@ -214,8 +207,8 @@ public:
}
private:
- SkMatrix fMatrixStorage;
- SkRegion fRegionStorage;
+ SkMatrix fMatrixStorage;
+ SkRasterClip fRasterClipStorage;
};
class SkDrawIter : public SkDraw {
@@ -242,7 +235,8 @@ public:
const DeviceCM* rec = fCurrLayer;
fMatrix = rec->fMatrix;
- fClip = &rec->fClip;
+ fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW();
+ fRC = &rec->fClip;
fDevice = rec->fDevice;
fBitmap = &fDevice->accessBitmap(true);
fPaint = rec->fPaint;
@@ -318,30 +312,35 @@ private:
};
bool AutoDrawLooper::next(SkDrawFilter::Type drawType) {
+ fPaint = NULL;
if (fDone) {
- fPaint = NULL;
return false;
}
- if (!fLooper && !fFilter) {
+
+ if (fLooper || fFilter) {
+ SkPaint* paint = fLazyPaint.set(fOrigPaint);
+ if (fLooper && !fLooper->next(fCanvas, paint)) {
+ fDone = true;
+ return false;
+ }
+ if (fFilter) {
+ fFilter->filter(paint, drawType);
+ if (NULL == fLooper) {
+ // no looper means we only draw once
+ fDone = true;
+ }
+ }
+ fPaint = paint;
+ } else {
fDone = true;
fPaint = &fOrigPaint;
- return true;
}
- SkPaint* paint = fLazyPaint.set(fOrigPaint);
- if (fLooper && !fLooper->next(fCanvas, paint)) {
- fDone = true;
+ // call this after any possible paint modifiers
+ if (fPaint->nothingToDraw()) {
fPaint = NULL;
return false;
}
- if (fFilter) {
- fFilter->filter(paint, drawType);
- if (NULL == fLooper) {
- // no looper means we only draw once
- fDone = true;
- }
- }
- fPaint = paint;
return true;
}
@@ -399,10 +398,13 @@ private:
SkDevice* SkCanvas::init(SkDevice* device) {
fBounder = NULL;
+ fLocalBoundsCompareType.setEmpty();
fLocalBoundsCompareTypeDirty = true;
+ fLocalBoundsCompareTypeBW.setEmpty();
fLocalBoundsCompareTypeDirtyBW = true;
fLastDeviceToGainFocus = NULL;
fDeviceCMDirty = false;
+ fLayerCount = 0;
fMCRec = (MCRec*)fMCStack.push_back();
new (fMCRec) MCRec(NULL, 0);
@@ -411,22 +413,17 @@ SkDevice* SkCanvas::init(SkDevice* device) {
fMCRec->fTopLayer = fMCRec->fLayer;
fMCRec->fNext = NULL;
+ fExternalMatrix.reset();
+ fExternalInverse.reset();
fUseExternalMatrix = false;
return this->setDevice(device);
}
-SkCanvas::SkCanvas(SkDeviceFactory* factory)
- : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
+SkCanvas::SkCanvas()
+: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
inc_canvas();
-
- if (factory) {
- factory->ref();
- } else {
- factory = SkNEW(SkRasterDeviceFactory);
- }
- fDeviceFactory = factory;
-
+
this->init(NULL);
}
@@ -434,10 +431,6 @@ SkCanvas::SkCanvas(SkDevice* device)
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
inc_canvas();
- fDeviceFactory = device->getDeviceFactory();
- SkASSERT(fDeviceFactory);
- fDeviceFactory->ref();
-
this->init(device);
}
@@ -445,21 +438,17 @@ SkCanvas::SkCanvas(const SkBitmap& bitmap)
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
inc_canvas();
- SkDevice* device = SkNEW_ARGS(SkDevice, (this, bitmap, false));
- fDeviceFactory = device->getDeviceFactory();
- SkASSERT(fDeviceFactory);
- fDeviceFactory->ref();
-
- this->init(device)->unref();
+ this->init(SkNEW_ARGS(SkDevice, (bitmap)))->unref();
}
SkCanvas::~SkCanvas() {
// free up the contents of our deque
this->restoreToCount(1); // restore everything but the last
+ SkASSERT(0 == fLayerCount);
+
this->internalRestore(); // restore the last, since we're going away
SkSafeUnref(fBounder);
- SkSafeUnref(fDeviceFactory);
dec_canvas();
}
@@ -480,6 +469,11 @@ SkDrawFilter* SkCanvas::setDrawFilter(SkDrawFilter* filter) {
///////////////////////////////////////////////////////////////////////////////
+SkISize SkCanvas::getDeviceSize() const {
+ SkDevice* d = this->getDevice();
+ return d ? SkISize::Make(d->width(), d->height()) : SkISize::Make(0, 0);
+}
+
SkDevice* SkCanvas::getDevice() const {
// return root device
SkDeque::F2BIter iter(fMCStack);
@@ -533,9 +527,9 @@ SkDevice* SkCanvas::setDevice(SkDevice* device) {
*/
if (NULL == device) {
- rec->fRegion->setEmpty();
+ rec->fRasterClip->setEmpty();
while ((rec = (MCRec*)iter.next()) != NULL) {
- (void)rec->fRegion->setEmpty();
+ (void)rec->fRasterClip->setEmpty();
}
fClipStack.reset();
} else {
@@ -545,50 +539,55 @@ SkDevice* SkCanvas::setDevice(SkDevice* device) {
bounds.set(0, 0, device->width(), device->height());
// now jam our 1st clip to be bounds, and intersect the rest with that
- rec->fRegion->setRect(bounds);
+ rec->fRasterClip->setRect(bounds);
while ((rec = (MCRec*)iter.next()) != NULL) {
- (void)rec->fRegion->op(bounds, SkRegion::kIntersect_Op);
+ (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op);
}
- fClipStack.clipDevRect(bounds, SkRegion::kIntersect_Op);
}
return device;
}
-SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap, bool forLayer) {
- SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (this, bitmap, forLayer)));
+SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) {
+ SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (bitmap)));
device->unref();
return device;
}
-bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
+bool SkCanvas::readPixels(SkBitmap* bitmap,
+ int x, int y,
+ Config8888 config8888) {
SkDevice* device = this->getDevice();
if (!device) {
return false;
}
- return device->readPixels(srcRect, bitmap);
-}
-
-SkDeviceFactory* SkCanvas::setDeviceFactory(SkDeviceFactory* factory) {
- SkRefCnt_SafeAssign(fDeviceFactory, factory);
- return factory;
+ return device->readPixels(bitmap, x, y, config8888);
}
-//////////////////////////////////////////////////////////////////////////////
-
-bool SkCanvas::readPixels(SkBitmap* bitmap) {
+bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
SkDevice* device = this->getDevice();
- if (!device) {
- return false;
- }
+
SkIRect bounds;
bounds.set(0, 0, device->width(), device->height());
- return this->readPixels(bounds, bitmap);
+ if (!bounds.intersect(srcRect)) {
+ return false;
+ }
+
+ SkBitmap tmp;
+ tmp.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(),
+ bounds.height());
+ if (this->readPixels(&tmp, bounds.fLeft, bounds.fTop)) {
+ bitmap->swap(tmp);
+ return true;
+ } else {
+ return false;
+ }
}
-void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
+void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y,
+ Config8888 config8888) {
SkDevice* device = this->getDevice();
if (device) {
- device->writePixels(bitmap, x, y);
+ device->writePixels(bitmap, x, y, config8888);
}
}
@@ -597,7 +596,7 @@ void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
void SkCanvas::updateDeviceCMCache() {
if (fDeviceCMDirty) {
const SkMatrix& totalMatrix = this->getTotalMatrix();
- const SkRegion& totalClip = this->getTotalClip();
+ const SkRasterClip& totalClip = *fMCRec->fRasterClip;
DeviceCM* layer = fMCRec->fTopLayer;
if (NULL == layer->fNext) { // only one layer
@@ -607,8 +606,7 @@ void SkCanvas::updateDeviceCMCache() {
fExternalInverse);
}
} else {
- SkRegion clip;
- clip = totalClip; // make a copy
+ SkRasterClip clip(totalClip);
do {
layer->updateMC(totalMatrix, clip, fClipStack, &clip);
if (fUseExternalMatrix) {
@@ -705,12 +703,12 @@ int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
fDeviceCMDirty = true;
- SkIRect ir;
- const SkIRect& clipBounds = this->getTotalClip().getBounds();
- if (clipBounds.isEmpty()) {
+ SkIRect clipBounds;
+ if (!this->getClipDeviceBounds(&clipBounds)) {
return count;
}
+ SkIRect ir;
if (NULL != bounds) {
SkRect r;
@@ -718,8 +716,9 @@ int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
r.roundOut(&ir);
// early exit if the layer's bounds are clipped out
if (!ir.intersect(clipBounds)) {
- if (bounds_affects_clip(flags))
- fMCRec->fRegion->setEmpty();
+ if (bounds_affects_clip(flags)) {
+ fMCRec->fRasterClip->setEmpty();
+ }
return count;
}
} else { // no user bounds, so just use the clip
@@ -729,15 +728,36 @@ int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op);
// early exit if the clip is now empty
if (bounds_affects_clip(flags) &&
- !fMCRec->fRegion->op(ir, SkRegion::kIntersect_Op)) {
+ !fMCRec->fRasterClip->op(ir, SkRegion::kIntersect_Op)) {
return count;
}
+ // Kill the imagefilter if our device doesn't allow it
+ SkLazyPaint lazyP;
+ if (paint && paint->getImageFilter()) {
+ if (!this->getTopDevice()->allowImageFilter(paint->getImageFilter())) {
+ SkPaint* p = lazyP.set(*paint);
+ p->setImageFilter(NULL);
+ paint = p;
+ }
+ }
+
bool isOpaque;
SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque);
- SkDevice* device = this->createDevice(config, ir.width(), ir.height(),
- isOpaque, true);
+ SkDevice* device;
+ if (paint && paint->getImageFilter()) {
+ device = this->createCompatibleDevice(config, ir.width(), ir.height(),
+ isOpaque);
+ } else {
+ device = this->createLayerDevice(config, ir.width(), ir.height(),
+ isOpaque);
+ }
+ if (NULL == device) {
+ SkDebugf("Unable to create device for layer.");
+ return count;
+ }
+
device->setOrigin(ir.fLeft, ir.fTop);
DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint));
device->unref();
@@ -746,6 +766,7 @@ int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
fMCRec->fLayer = layer;
fMCRec->fTopLayer = layer; // this field is NOT an owner of layer
+ fLayerCount += 1;
return count;
}
@@ -775,7 +796,7 @@ void SkCanvas::internalRestore() {
fLocalBoundsCompareTypeDirtyBW = true;
fClipStack.restore();
- // reserve our layer (if any)
+ // reserve our layer (if any)
DeviceCM* layer = fMCRec->fLayer; // may be null
// now detach it from fMCRec so we can pop(). Gets freed after its drawn
fMCRec->fLayer = NULL;
@@ -796,9 +817,12 @@ void SkCanvas::internalRestore() {
layer->fPaint);
// reset this, since drawDevice will have set it to true
fDeviceCMDirty = true;
+
+ SkASSERT(fLayerCount > 0);
+ fLayerCount -= 1;
}
SkDELETE(layer);
- }
+ }
SkASSERT(fClipStack.getSaveCount() == this->getSaveCount() - 1);
}
@@ -812,11 +836,17 @@ void SkCanvas::restoreToCount(int count) {
if (count < 1) {
count = 1;
}
- while (fMCStack.count() > count) {
+
+ int n = this->getSaveCount() - count;
+ for (int i = 0; i < n; ++i) {
this->restore();
}
}
+bool SkCanvas::isDrawingToLayer() const {
+ return fLayerCount > 0;
+}
+
/////////////////////////////////////////////////////////////////////////////
// can't draw it if its empty, or its too big for a fixed-point width or height
@@ -841,7 +871,35 @@ void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect
this->commonDrawBitmap(bitmap, srcRect, matrix, *paint);
}
-void SkCanvas::drawDevice(SkDevice* device, int x, int y,
+#include "SkImageFilter.h"
+
+class DeviceImageFilterProxy : public SkImageFilter::Proxy {
+public:
+ DeviceImageFilterProxy(SkDevice* device) : fDevice(device) {}
+
+ virtual SkDevice* createDevice(int w, int h) SK_OVERRIDE;
+ virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
+ const SkMatrix& ctm,
+ SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
+
+private:
+ SkDevice* fDevice;
+};
+
+SkDevice* DeviceImageFilterProxy::createDevice(int w, int h) {
+ return fDevice->createCompatibleDevice(SkBitmap::kARGB_8888_Config,
+ w, h, false);
+}
+
+bool DeviceImageFilterProxy::filterImage(SkImageFilter* filter,
+ const SkBitmap& src,
+ const SkMatrix& ctm,
+ SkBitmap* result,
+ SkIPoint* offset) {
+ return fDevice->filterImage(filter, src, ctm, result, offset);
+}
+
+void SkCanvas::drawDevice(SkDevice* srcDev, int x, int y,
const SkPaint* paint) {
SkPaint tmp;
if (NULL == paint) {
@@ -851,8 +909,22 @@ void SkCanvas::drawDevice(SkDevice* device, int x, int y,
LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type)
while (iter.next()) {
- iter.fDevice->drawDevice(iter, device, x - iter.getX(), y - iter.getY(),
- looper.paint());
+ SkDevice* dstDev = iter.fDevice;
+ paint = &looper.paint();
+ SkImageFilter* filter = paint->getImageFilter();
+ SkIPoint pos = { x - iter.getX(), y - iter.getY() };
+ if (filter) {
+ DeviceImageFilterProxy proxy(dstDev);
+ SkBitmap dst;
+ const SkBitmap& src = srcDev->accessBitmap(false);
+ if (filter->filterImage(&proxy, src, *iter.fMatrix, &dst, &pos)) {
+ SkPaint tmp(*paint);
+ tmp.setImageFilter(NULL);
+ dstDev->drawSprite(iter, dst, pos.x(), pos.y(), tmp);
+ }
+ } else {
+ dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
+ }
}
LOOPER_END
}
@@ -912,7 +984,7 @@ void SkCanvas::resetMatrix() {
//////////////////////////////////////////////////////////////////////////////
-bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) {
+bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
AutoValidateClip avc(this);
fDeviceCMDirty = true;
@@ -925,12 +997,10 @@ bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) {
// the region code to scan-convert the path, only to discover that it
// is really just a rect.
SkRect r;
- SkIRect ir;
fMCRec->fMatrix->mapRect(&r, rect);
- fClipStack.clipDevRect(r, op);
- r.round(&ir);
- return fMCRec->fRegion->op(ir, op);
+ fClipStack.clipDevRect(r, op, doAA);
+ return fMCRec->fRasterClip->op(r, op, doAA);
} else {
// since we're rotate or some such thing, we convert the rect to a path
// and clip against that, since it can handle any matrix. However, to
@@ -939,12 +1009,12 @@ bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) {
SkPath path;
path.addRect(rect);
- return this->SkCanvas::clipPath(path, op);
+ return this->SkCanvas::clipPath(path, op, doAA);
}
}
-static bool clipPathHelper(const SkCanvas* canvas, SkRegion* currRgn,
- const SkPath& devPath, SkRegion::Op op) {
+static bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip,
+ const SkPath& devPath, SkRegion::Op op, bool doAA) {
// base is used to limit the size (and therefore memory allocation) of the
// region that results from scan converting devPath.
SkRegion base;
@@ -953,29 +1023,29 @@ static bool clipPathHelper(const SkCanvas* canvas, SkRegion* currRgn,
// since we are intersect, we can do better (tighter) with currRgn's
// bounds, than just using the device. However, if currRgn is complex,
// our region blitter may hork, so we do that case in two steps.
- if (currRgn->isRect()) {
- return currRgn->setPath(devPath, *currRgn);
+ if (currClip->isRect()) {
+ return currClip->setPath(devPath, *currClip, doAA);
} else {
- base.setRect(currRgn->getBounds());
- SkRegion rgn;
- rgn.setPath(devPath, base);
- return currRgn->op(rgn, op);
+ base.setRect(currClip->getBounds());
+ SkRasterClip clip;
+ clip.setPath(devPath, base, doAA);
+ return currClip->op(clip, op);
}
} else {
const SkBitmap& bm = canvas->getDevice()->accessBitmap(false);
base.setRect(0, 0, bm.width(), bm.height());
if (SkRegion::kReplace_Op == op) {
- return currRgn->setPath(devPath, base);
+ return currClip->setPath(devPath, base, doAA);
} else {
- SkRegion rgn;
- rgn.setPath(devPath, base);
- return currRgn->op(rgn, op);
+ SkRasterClip clip;
+ clip.setPath(devPath, base, doAA);
+ return currClip->op(clip, op);
}
}
}
-bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op) {
+bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
AutoValidateClip avc(this);
fDeviceCMDirty = true;
@@ -985,10 +1055,20 @@ bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op) {
SkPath devPath;
path.transform(*fMCRec->fMatrix, &devPath);
+ // Check if the transfomation, or the original path itself
+ // made us empty. Note this can also happen if we contained NaN
+ // values. computing the bounds detects this, and will set our
+ // bounds to empty if that is the case. (see SkRect::set(pts, count))
+ if (devPath.getBounds().isEmpty()) {
+ // resetting the path will remove any NaN or other wanky values
+ // that might upset our scan converter.
+ devPath.reset();
+ }
+
// if we called path.swap() we could avoid a deep copy of this path
- fClipStack.clipDevPath(devPath, op);
+ fClipStack.clipDevPath(devPath, op, doAA);
- return clipPathHelper(this, fMCRec->fRegion, devPath, op);
+ return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA);
}
bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
@@ -1002,7 +1082,7 @@ bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
// we have to ignore it, and use the region directly?
fClipStack.clipDevRect(rgn.getBounds());
- return fMCRec->fRegion->op(rgn, op);
+ return fMCRec->fRasterClip->op(rgn, op);
}
#ifdef SK_DEBUG
@@ -1011,25 +1091,25 @@ void SkCanvas::validateClip() const {
const SkDevice* device = this->getDevice();
SkIRect ir;
ir.set(0, 0, device->width(), device->height());
- SkRegion clipRgn(ir);
+ SkRasterClip tmpClip(ir);
SkClipStack::B2FIter iter(fClipStack);
const SkClipStack::B2FIter::Clip* clip;
while ((clip = iter.next()) != NULL) {
if (clip->fPath) {
- clipPathHelper(this, &clipRgn, *clip->fPath, clip->fOp);
+ clipPathHelper(this, &tmpClip, *clip->fPath, clip->fOp, clip->fDoAA);
} else if (clip->fRect) {
clip->fRect->round(&ir);
- clipRgn.op(ir, clip->fOp);
+ tmpClip.op(ir, clip->fOp);
} else {
- clipRgn.setEmpty();
+ tmpClip.setEmpty();
}
}
#if 0 // enable this locally for testing
// now compare against the current rgn
const SkRegion& rgn = this->getTotalClip();
- SkASSERT(rgn == clipRgn);
+ SkASSERT(rgn == tmpClip);
#endif
}
#endif
@@ -1057,10 +1137,10 @@ void SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const {
*/
bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const {
- if (!rect.hasValidCoordinates())
+ if (!rect.isFinite())
return true;
- if (fMCRec->fRegion->isEmpty()) {
+ if (fMCRec->fRasterClip->isEmpty()) {
return true;
}
@@ -1069,7 +1149,7 @@ bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const {
fMCRec->fMatrix->mapRect(&dst, rect);
SkIRect idst;
dst.roundOut(&idst);
- return !SkIRect::Intersects(idst, fMCRec->fRegion->getBounds());
+ return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds());
} else {
const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et);
@@ -1098,7 +1178,7 @@ bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const {
antialiasing (worst case)
*/
- if (fMCRec->fRegion->isEmpty()) {
+ if (fMCRec->fRasterClip->isEmpty()) {
return true;
}
@@ -1117,11 +1197,8 @@ bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const {
}
bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const {
- const SkRegion& clip = *fMCRec->fRegion;
- if (clip.isEmpty()) {
- if (bounds) {
- bounds->setEmpty();
- }
+ SkIRect ibounds;
+ if (!getClipDeviceBounds(&ibounds)) {
return false;
}
@@ -1135,26 +1212,43 @@ bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const {
}
if (NULL != bounds) {
- SkRect r;
- // get the clip's bounds
- const SkIRect& ibounds = clip.getBounds();
+ SkRect r;
// adjust it outwards if we are antialiasing
int inset = (kAA_EdgeType == et);
r.iset(ibounds.fLeft - inset, ibounds.fTop - inset,
ibounds.fRight + inset, ibounds.fBottom + inset);
-
- // invert into local coordinates
inverse.mapRect(bounds, r);
}
return true;
}
+bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
+ const SkRasterClip& clip = *fMCRec->fRasterClip;
+ if (clip.isEmpty()) {
+ if (bounds) {
+ bounds->setEmpty();
+ }
+ return false;
+ }
+
+ if (NULL != bounds) {
+ *bounds = clip.getBounds();
+ }
+ return true;
+}
+
const SkMatrix& SkCanvas::getTotalMatrix() const {
return *fMCRec->fMatrix;
}
+SkCanvas::ClipType SkCanvas::getClipType() const {
+ if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType;
+ if (fMCRec->fRasterClip->isRect()) return kRect_ClipType;
+ return kComplex_ClipType;
+}
+
const SkRegion& SkCanvas::getTotalClip() const {
- return *fMCRec->fRegion;
+ return fMCRec->fRasterClip->forceGetBW();
}
const SkClipStack& SkCanvas::getTotalClipStack() const {
@@ -1176,11 +1270,30 @@ void SkCanvas::setExternalMatrix(const SkMatrix* matrix) {
}
}
-SkDevice* SkCanvas::createDevice(SkBitmap::Config config, int width, int height,
- bool isOpaque, bool forLayer) {
- return fDeviceFactory->newDevice(this, config, width, height, isOpaque, forLayer);
+SkDevice* SkCanvas::createLayerDevice(SkBitmap::Config config,
+ int width, int height,
+ bool isOpaque) {
+ SkDevice* device = this->getTopDevice();
+ if (device) {
+ return device->createCompatibleDeviceForSaveLayer(config, width, height,
+ isOpaque);
+ } else {
+ return NULL;
+ }
+}
+
+SkDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config,
+ int width, int height,
+ bool isOpaque) {
+ SkDevice* device = this->getDevice();
+ if (device) {
+ return device->createCompatibleDevice(config, width, height, isOpaque);
+ } else {
+ return NULL;
+ }
}
+
//////////////////////////////////////////////////////////////////////////////
// These are the virtual drawing methods
//////////////////////////////////////////////////////////////////////////////
@@ -1194,6 +1307,10 @@ void SkCanvas::clear(SkColor color) {
}
void SkCanvas::drawPaint(const SkPaint& paint) {
+ this->internalDrawPaint(paint);
+}
+
+void SkCanvas::internalDrawPaint(const SkPaint& paint) {
LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type)
while (iter.next()) {
@@ -1239,7 +1356,7 @@ void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
}
void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
- if (paint.canComputeFastBounds()) {
+ if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
SkRect storage;
const SkRect& bounds = path.getBounds();
if (this->quickReject(paint.computeFastBounds(bounds, &storage),
@@ -1247,6 +1364,12 @@ void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
return;
}
}
+ if (path.isEmpty()) {
+ if (path.isInverseFillType()) {
+ this->internalDrawPaint(paint);
+ }
+ return;
+ }
LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type)
@@ -1261,14 +1384,18 @@ void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
const SkPaint* paint) {
SkDEBUGCODE(bitmap.validate();)
- if (NULL == paint || (paint->getMaskFilter() == NULL)) {
- SkRect fastBounds;
- fastBounds.set(x, y,
- x + SkIntToScalar(bitmap.width()),
- y + SkIntToScalar(bitmap.height()));
- if (this->quickReject(fastBounds, paint2EdgeType(paint))) {
+ SkRect bounds;
+ bounds.set(x, y,
+ x + SkIntToScalar(bitmap.width()),
+ y + SkIntToScalar(bitmap.height()));
+ if (NULL == paint) {
+ if (this->quickReject(bounds, paint2EdgeType(paint))) {
return;
}
+ } else if (paint->canComputeFastBounds() &&
+ this->quickReject(paint->computeFastBounds(bounds, &bounds),
+ paint2EdgeType(paint))) {
+ return;
}
SkMatrix matrix;
@@ -1276,19 +1403,28 @@ void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
this->internalDrawBitmap(bitmap, NULL, matrix, paint);
}
-void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
- const SkRect& dst, const SkPaint* paint) {
+// this one is non-virtual, so it can be called safely by other canvas apis
+void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
+ const SkRect& dst, const SkPaint* paint) {
if (bitmap.width() == 0 || bitmap.height() == 0 || dst.isEmpty()) {
return;
}
-
+
// do this now, to avoid the cost of calling extract for RLE bitmaps
- if (this->quickReject(dst, paint2EdgeType(paint))) {
- return;
+ if (NULL == paint) {
+ if (this->quickReject(dst, paint2EdgeType(paint))) {
+ return;
+ }
+ } else if (paint->canComputeFastBounds()) {
+ SkRect fastBounds;
+ if (this->quickReject(paint->computeFastBounds(dst, &fastBounds),
+ paint2EdgeType(paint))) {
+ return;
+ }
}
const SkBitmap* bitmapPtr = &bitmap;
-
+
SkMatrix matrix;
SkRect tmpSrc;
if (src) {
@@ -1308,7 +1444,7 @@ void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
SkIntToScalar(bitmap.height()));
}
matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
-
+
// ensure that src is "valid" before we pass it to our internal routines
// and to SkDevice. i.e. sure it is contained inside the original bitmap.
SkIRect tmpISrc;
@@ -1322,6 +1458,12 @@ void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
this->internalDrawBitmap(*bitmapPtr, src, matrix, paint);
}
+void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
+ const SkRect& dst, const SkPaint* paint) {
+ SkDEBUGCODE(bitmap.validate();)
+ this->internalDrawBitmapRect(bitmap, src, dst, paint);
+}
+
void SkCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
const SkPaint* paint) {
SkDEBUGCODE(bitmap.validate();)
@@ -1341,6 +1483,77 @@ void SkCanvas::commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* srcRect,
LOOPER_END
}
+void SkCanvas::internalDrawBitmapNine(const SkBitmap& bitmap,
+ const SkIRect& center, const SkRect& dst,
+ const SkPaint* paint) {
+ if (NULL == paint) {
+ if (this->quickReject(dst, paint2EdgeType(paint))) {
+ return;
+ }
+ } else if (paint->canComputeFastBounds()) {
+ SkRect fastBounds;
+ if (this->quickReject(paint->computeFastBounds(dst, &fastBounds),
+ paint2EdgeType(paint))) {
+ return;
+ }
+ }
+
+ const int32_t w = bitmap.width();
+ const int32_t h = bitmap.height();
+
+ SkIRect c = center;
+ // pin center to the bounds of the bitmap
+ c.fLeft = SkMax32(0, center.fLeft);
+ c.fTop = SkMax32(0, center.fTop);
+ c.fRight = SkPin32(center.fRight, c.fLeft, w);
+ c.fBottom = SkPin32(center.fBottom, c.fTop, h);
+
+ const int32_t srcX[4] = { 0, c.fLeft, c.fRight, w };
+ const int32_t srcY[4] = { 0, c.fTop, c.fBottom, h };
+ SkScalar dstX[4] = {
+ dst.fLeft, dst.fLeft + SkIntToScalar(c.fLeft),
+ dst.fRight - SkIntToScalar(w - c.fRight), dst.fRight
+ };
+ SkScalar dstY[4] = {
+ dst.fTop, dst.fTop + SkIntToScalar(c.fTop),
+ dst.fBottom - SkIntToScalar(h - c.fBottom), dst.fBottom
+ };
+
+ if (dstX[1] > dstX[2]) {
+ dstX[1] = dstX[0] + (dstX[3] - dstX[0]) * c.fLeft / (w - c.width());
+ dstX[2] = dstX[1];
+ }
+
+ if (dstY[1] > dstY[2]) {
+ dstY[1] = dstY[0] + (dstY[3] - dstY[0]) * c.fTop / (h - c.height());
+ dstY[2] = dstY[1];
+ }
+
+ SkIRect s;
+ SkRect d;
+ for (int y = 0; y < 3; y++) {
+ s.fTop = srcY[y];
+ s.fBottom = srcY[y+1];
+ d.fTop = dstY[y];
+ d.fBottom = dstY[y+1];
+ for (int x = 0; x < 3; x++) {
+ s.fLeft = srcX[x];
+ s.fRight = srcX[x+1];
+ d.fLeft = dstX[x];
+ d.fRight = dstX[x+1];
+ this->internalDrawBitmapRect(bitmap, &s, d, paint);
+ }
+ }
+}
+
+void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
+ const SkRect& dst, const SkPaint* paint) {
+ SkDEBUGCODE(bitmap.validate();)
+
+ // Need a device entry-point, so gpu can use a mesh
+ this->internalDrawBitmapNine(bitmap, center, dst, paint);
+}
+
void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y,
const SkPaint* paint) {
SkDEBUGCODE(bitmap.validate();)
@@ -1384,6 +1597,78 @@ private:
SkLazyPaint fLazy;
};
+void SkCanvas::DrawRect(const SkDraw& draw, const SkPaint& paint,
+ const SkRect& r, SkScalar textSize) {
+ if (paint.getStyle() == SkPaint::kFill_Style) {
+ draw.fDevice->drawRect(draw, r, paint);
+ } else {
+ SkPaint p(paint);
+ p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
+ draw.fDevice->drawRect(draw, r, p);
+ }
+}
+
+void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
+ const char text[], size_t byteLength,
+ SkScalar x, SkScalar y) {
+ SkASSERT(byteLength == 0 || text != NULL);
+
+ // nothing to draw
+ if (text == NULL || byteLength == 0 ||
+ draw.fClip->isEmpty() ||
+ (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
+ return;
+ }
+
+ SkScalar width = 0;
+ SkPoint start;
+
+ start.set(0, 0); // to avoid warning
+ if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
+ SkPaint::kStrikeThruText_Flag)) {
+ width = paint.measureText(text, byteLength);
+
+ SkScalar offsetX = 0;
+ if (paint.getTextAlign() == SkPaint::kCenter_Align) {
+ offsetX = SkScalarHalf(width);
+ } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
+ offsetX = width;
+ }
+ start.set(x - offsetX, y);
+ }
+
+ if (0 == width) {
+ return;
+ }
+
+ uint32_t flags = paint.getFlags();
+
+ if (flags & (SkPaint::kUnderlineText_Flag |
+ SkPaint::kStrikeThruText_Flag)) {
+ 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_Flag) {
+ SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
+ start.fY);
+ r.fTop = offset;
+ r.fBottom = offset + height;
+ DrawRect(draw, paint, r, textSize);
+ }
+ if (flags & SkPaint::kStrikeThruText_Flag) {
+ SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
+ start.fY);
+ r.fTop = offset;
+ r.fBottom = offset + height;
+ DrawRect(draw, paint, r, textSize);
+ }
+ }
+}
+
void SkCanvas::drawText(const void* text, size_t byteLength,
SkScalar x, SkScalar y, const SkPaint& paint) {
LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
@@ -1391,6 +1676,8 @@ void SkCanvas::drawText(const void* text, size_t byteLength,
while (iter.next()) {
SkDeviceFilteredPaint dfp(iter.fDevice, looper.paint());
iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
+ DrawTextDecorations(iter, dfp.paint(),
+ static_cast<const char*>(text), byteLength, x, y);
}
LOOPER_END
@@ -1436,11 +1723,10 @@ void SkCanvas::drawTextOnPath(const void* text, size_t byteLength,
LOOPER_END
}
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
void SkCanvas::drawPosTextOnPath(const void* text, size_t byteLength,
const SkPoint pos[], const SkPaint& paint,
const SkPath& path, const SkMatrix* matrix) {
-
LOOPER_BEGIN(paint, SkDrawFilter::kText_Type)
while (iter.next()) {
@@ -1622,11 +1908,6 @@ void SkCanvas::drawPicture(SkPicture& picture) {
restoreToCount(saveCount);
}
-void SkCanvas::drawShape(SkShape* shape) {
- // shape baseclass takes care of save/restore
- shape->draw(this);
-}
-
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkChunkAlloc.cpp b/src/core/SkChunkAlloc.cpp
index e0c03a8..56b4abe 100644
--- a/src/core/SkChunkAlloc.cpp
+++ b/src/core/SkChunkAlloc.cpp
@@ -1,19 +1,11 @@
-/* libs/corecg/SkChunkAlloc.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkChunkAlloc.h"
diff --git a/src/core/SkClampRange.cpp b/src/core/SkClampRange.cpp
index 32ea964..1f7cce3 100644
--- a/src/core/SkClampRange.cpp
+++ b/src/core/SkClampRange.cpp
@@ -1,19 +1,12 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkClampRange.h"
/*
diff --git a/src/core/SkClipStack.cpp b/src/core/SkClipStack.cpp
index 4ad4d41..f885240 100644
--- a/src/core/SkClipStack.cpp
+++ b/src/core/SkClipStack.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkClipStack.h"
#include "SkPath.h"
#include <new>
@@ -14,21 +21,26 @@ struct SkClipStack::Rec {
int fSaveCount;
SkRegion::Op fOp;
State fState;
+ bool fDoAA;
- Rec(int saveCount, const SkRect& rect, SkRegion::Op op) : fRect(rect) {
+ Rec(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) : fRect(rect) {
fSaveCount = saveCount;
fOp = op;
fState = kRect_State;
+ fDoAA = doAA;
}
- Rec(int saveCount, const SkPath& path, SkRegion::Op op) : fPath(path) {
+ Rec(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) : fPath(path) {
+ fRect.setEmpty();
fSaveCount = saveCount;
fOp = op;
fState = kPath_State;
+ fDoAA = doAA;
}
bool operator==(const Rec& b) const {
- if (fSaveCount != b.fSaveCount || fOp != b.fOp || fState != b.fState) {
+ if (fSaveCount != b.fSaveCount || fOp != b.fOp || fState != b.fState ||
+ fDoAA != b.fDoAA) {
return false;
}
switch (fState) {
@@ -130,7 +142,7 @@ void SkClipStack::restore() {
}
}
-void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op) {
+void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
Rec* rec = (Rec*)fDeque.back();
if (rec && rec->canBeIntersected(fSaveCount, op)) {
switch (rec->fState) {
@@ -149,10 +161,10 @@ void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op) {
break;
}
}
- new (fDeque.push_back()) Rec(fSaveCount, rect, op);
+ new (fDeque.push_back()) Rec(fSaveCount, rect, op, doAA);
}
-void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op) {
+void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) {
Rec* rec = (Rec*)fDeque.back();
if (rec && rec->canBeIntersected(fSaveCount, op)) {
const SkRect& pathBounds = path.getBounds();
@@ -173,7 +185,7 @@ void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op) {
break;
}
}
- new (fDeque.push_back()) Rec(fSaveCount, path, op);
+ new (fDeque.push_back()) Rec(fSaveCount, path, op, doAA);
}
///////////////////////////////////////////////////////////////////////////////
@@ -183,9 +195,11 @@ SkClipStack::B2FIter::B2FIter() {
bool operator==(const SkClipStack::B2FIter::Clip& a,
const SkClipStack::B2FIter::Clip& b) {
- return a.fOp == b.fOp &&
- ((a.fRect == NULL && b.fRect == NULL) || *a.fRect == *b.fRect) &&
- ((a.fPath == NULL && b.fPath == NULL) || *a.fPath == *b.fPath);
+ return a.fOp == b.fOp && a.fDoAA == b.fDoAA &&
+ ((a.fRect == NULL && b.fRect == NULL) ||
+ (a.fRect != NULL && b.fRect != NULL && *a.fRect == *b.fRect)) &&
+ ((a.fPath == NULL && b.fPath == NULL) ||
+ (a.fPath != NULL && b.fPath != NULL && *a.fPath == *b.fPath));
}
bool operator!=(const SkClipStack::B2FIter::Clip& a,
@@ -218,6 +232,7 @@ const SkClipStack::B2FIter::Clip* SkClipStack::B2FIter::next() {
break;
}
fClip.fOp = rec->fOp;
+ fClip.fDoAA = rec->fDoAA;
return &fClip;
}
diff --git a/src/core/SkColor.cpp b/src/core/SkColor.cpp
index 4256179..fe7b8f8 100644
--- a/src/core/SkColor.cpp
+++ b/src/core/SkColor.cpp
@@ -1,49 +1,25 @@
-/* libs/graphics/sgl/SkColor.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkColor.h"
#include "SkColorPriv.h"
SkPMColor SkPreMultiplyARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
- if (a != 255) {
-#if 0
- unsigned scale = SkAlpha255To256(a);
- r = SkAlphaMul(r, scale);
- g = SkAlphaMul(g, scale);
- b = SkAlphaMul(b, scale);
-#else
- r = SkMulDiv255Round(r, a);
- g = SkMulDiv255Round(g, a);
- b = SkMulDiv255Round(b, a);
-#endif
- }
- return SkPackARGB32(a, r, g, b);
+ return SkPremultiplyARGBInline(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);
+ return SkPremultiplyARGBInline(SkColorGetA(c), SkColorGetR(c),
+ SkColorGetG(c), SkColorGetB(c));
}
-//////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
static inline SkScalar ByteToScalar(U8CPU x) {
SkASSERT(x <= 255);
diff --git a/src/core/SkColorFilter.cpp b/src/core/SkColorFilter.cpp
index 6e0746f..2ca88bb 100644
--- a/src/core/SkColorFilter.cpp
+++ b/src/core/SkColorFilter.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkColorFilter.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkColorFilter.h"
#include "SkShader.h"
@@ -23,9 +15,17 @@ bool SkColorFilter::asColorMode(SkColor* color, SkXfermode::Mode* mode) {
return false;
}
+bool SkColorFilter::asColorMatrix(SkScalar matrix[20]) {
+ return false;
+}
+
+bool SkColorFilter::asComponentTable(SkBitmap*) {
+ return false;
+}
+
void SkColorFilter::filterSpan16(const uint16_t s[], int count, uint16_t d[]) {
SkASSERT(this->getFlags() & SkColorFilter::kHasFilter16_Flag);
- SkASSERT(!"missing implementation of SkColorFilter::filterSpan16");
+ SkDEBUGFAIL("missing implementation of SkColorFilter::filterSpan16");
if (d != s) {
memcpy(d, s, count * sizeof(uint16_t));
diff --git a/src/core/SkColorTable.cpp b/src/core/SkColorTable.cpp
index 308287c..4a9480d 100644
--- a/src/core/SkColorTable.cpp
+++ b/src/core/SkColorTable.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006-2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2009 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkBitmap.h"
#include "SkFlattenable.h"
#include "SkStream.h"
diff --git a/src/core/SkComposeShader.cpp b/src/core/SkComposeShader.cpp
index 62bb2d6..c8d3299 100644
--- a/src/core/SkComposeShader.cpp
+++ b/src/core/SkComposeShader.cpp
@@ -1,23 +1,16 @@
-/* libs/graphics/effects/SkShaderExtras.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkComposeShader.h"
#include "SkColorFilter.h"
#include "SkColorPriv.h"
+#include "SkColorShader.h"
#include "SkXfermode.h"
///////////////////////////////////////////////////////////////////////////////
@@ -33,7 +26,13 @@ SkComposeShader::SkComposeShader(SkShader* sA, SkShader* sB, SkXfermode* mode) {
SkComposeShader::SkComposeShader(SkFlattenableReadBuffer& buffer) :
INHERITED(buffer) {
fShaderA = static_cast<SkShader*>(buffer.readFlattenable());
+ if (NULL == fShaderA) {
+ fShaderA = SkNEW_ARGS(SkColorShader, (0));
+ }
fShaderB = static_cast<SkShader*>(buffer.readFlattenable());
+ if (NULL == fShaderB) {
+ fShaderB = SkNEW_ARGS(SkColorShader, (0));
+ }
fMode = static_cast<SkXfermode*>(buffer.readFlattenable());
}
diff --git a/src/core/SkConcaveToTriangles.cpp b/src/core/SkConcaveToTriangles.cpp
index fa718e5..2ca6795 100644
--- a/src/core/SkConcaveToTriangles.cpp
+++ b/src/core/SkConcaveToTriangles.cpp
@@ -1,20 +1,13 @@
+
/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2009 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
////////////////////////////////////////////////////////////////////////////////
// This is an implementation of the triangulation algorithm described by Alain
// Fournier and Delfin Montuno, in "Triangulating Simple Polygons and Equivalent
diff --git a/src/core/SkConcaveToTriangles.h b/src/core/SkConcaveToTriangles.h
index cede026..e7eb09b 100644
--- a/src/core/SkConcaveToTriangles.h
+++ b/src/core/SkConcaveToTriangles.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2009 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkConcaveToTriangles_DEFINED
#define SkConcaveToTriangles_DEFINED
diff --git a/src/core/SkConfig8888.h b/src/core/SkConfig8888.h
new file mode 100644
index 0000000..fe2f2cc
--- /dev/null
+++ b/src/core/SkConfig8888.h
@@ -0,0 +1,287 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+
+namespace {
+
+/**
+ Copies all pixels from a bitmap to a dst ptr with a given rowBytes and
+ Config8888. The bitmap must have kARGB_8888_Config.
+ */
+inline void SkCopyBitmapToConfig8888(uint32_t* dstPixels,
+ size_t dstRowBytes,
+ SkCanvas::Config8888 dstConfig8888,
+ const SkBitmap& srcBmp);
+
+/**
+ * Copies all pixels in a bitmap to a dst ptr with row bytes. The src bitmap
+ * is assumed to have pixels and be kARGB_8888_Config. No conversion is applied
+ */
+inline void SkCopyARGB8888BitmapTo(uint32_t* dstPixels,
+ size_t dstRowBytes,
+ const SkBitmap& srcBmp);
+
+/**
+ Copies over all pixels in a bitmap from a src ptr with a given rowBytes and
+ Config8888. The bitmap must have pixels and be kARGB_8888_Config.
+ */
+inline void SkCopyConfig8888ToBitmap(const SkBitmap& dstBmp,
+ const uint32_t* srcPixels,
+ size_t srcRowBytes,
+ SkCanvas::Config8888 srcConfig8888);
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Implementation
+
+namespace {
+
+template <int A_IDX, int R_IDX, int G_IDX, int B_IDX>
+inline uint32_t pack_config8888(uint32_t a, uint32_t r,
+ uint32_t g, uint32_t b) {
+#ifdef SK_CPU_LENDIAN
+ return (a << (A_IDX * 8)) | (r << (R_IDX * 8)) |
+ (g << (G_IDX * 8)) | (b << (B_IDX * 8));
+#else
+ return (a << ((3-A_IDX) * 8)) | (r << ((3-R_IDX) * 8)) |
+ (g << ((3-G_IDX) * 8)) | (b << ((3-B_IDX) * 8));
+#endif
+}
+
+template <int A_IDX, int R_IDX, int G_IDX, int B_IDX>
+inline void unpack_config8888(uint32_t color,
+ uint32_t* a, uint32_t* r,
+ uint32_t* g, uint32_t* b) {
+#ifdef SK_CPU_LENDIAN
+ *a = (color >> (A_IDX * 8)) & 0xff;
+ *r = (color >> (R_IDX * 8)) & 0xff;
+ *g = (color >> (G_IDX * 8)) & 0xff;
+ *b = (color >> (B_IDX * 8)) & 0xff;
+#else
+ *a = (color >> ((3 - A_IDX) * 8)) & 0xff;
+ *r = (color >> ((3 - R_IDX) * 8)) & 0xff;
+ *g = (color >> ((3 - G_IDX) * 8)) & 0xff;
+ *b = (color >> ((3 - B_IDX) * 8)) & 0xff;
+#endif
+}
+
+template <bool UNPM, int A_IDX, int R_IDX, int G_IDX, int B_IDX>
+inline void bitmap_copy_to_config8888(uint32_t* dstPixels,
+ size_t dstRowBytes,
+ const SkBitmap& srcBmp) {
+ SkASSERT(SkBitmap::kARGB_8888_Config == srcBmp.config());
+ SkAutoLockPixels alp(srcBmp);
+ int w = srcBmp.width();
+ int h = srcBmp.height();
+ size_t srcRowBytes = srcBmp.rowBytes();
+
+ intptr_t src = reinterpret_cast<intptr_t>(srcBmp.getPixels());
+ intptr_t dst = reinterpret_cast<intptr_t>(dstPixels);
+
+ for (int y = 0; y < h; ++y) {
+ const SkPMColor* srcRow = reinterpret_cast<SkPMColor*>(src);
+ uint32_t* dstRow = reinterpret_cast<uint32_t*>(dst);
+ for (int x = 0; x < w; ++x) {
+ SkPMColor pmcolor = srcRow[x];
+ if (UNPM) {
+ U8CPU a, r, g, b;
+ a = SkGetPackedA32(pmcolor);
+ if (a) {
+ // We're doing the explicit divide to match WebKit layout
+ // test expectations. We can modify and rebaseline if there
+ // it can be shown that there is a more performant way to
+ // unpremul.
+ r = SkGetPackedR32(pmcolor) * 0xff / a;
+ g = SkGetPackedG32(pmcolor) * 0xff / a;
+ b = SkGetPackedB32(pmcolor) * 0xff / a;
+ dstRow[x] = pack_config8888<A_IDX, R_IDX,
+ G_IDX, B_IDX>(a, r, g, b);
+ } else {
+ dstRow[x] = 0;
+ }
+ } else {
+ dstRow[x] = pack_config8888<A_IDX, R_IDX,
+ G_IDX, B_IDX>(
+ SkGetPackedA32(pmcolor),
+ SkGetPackedR32(pmcolor),
+ SkGetPackedG32(pmcolor),
+ SkGetPackedB32(pmcolor));
+ }
+ }
+ dst += dstRowBytes;
+ src += srcRowBytes;
+ }
+}
+
+template <bool PM, int A_IDX, int R_IDX, int G_IDX, int B_IDX>
+inline void config8888_copy_to_bitmap(const SkBitmap& dstBmp,
+ const uint32_t* srcPixels,
+ size_t srcRowBytes) {
+ SkASSERT(SkBitmap::kARGB_8888_Config == dstBmp.config());
+ SkAutoLockPixels alp(dstBmp);
+ int w = dstBmp.width();
+ int h = dstBmp.height();
+ size_t dstRowBytes = dstBmp.rowBytes();
+
+ intptr_t src = reinterpret_cast<intptr_t>(srcPixels);
+ intptr_t dst = reinterpret_cast<intptr_t>(dstBmp.getPixels());
+
+ for (int y = 0; y < h; ++y) {
+ const uint32_t* srcRow = reinterpret_cast<uint32_t*>(src);
+ SkPMColor* dstRow = reinterpret_cast<SkPMColor*>(dst);
+ for (int x = 0; x < w; ++x) {
+ uint32_t c8888 = srcRow[x];
+ uint32_t a, r, g, b;
+ unpack_config8888<A_IDX, R_IDX, G_IDX, B_IDX>(c8888, &a, &r,
+ &g, &b);
+ if (PM) {
+ // This matches WebKit's conversion which we are replacing.
+ // We can consider alternative rounding rules for performance.
+ r = SkMulDiv255Ceiling(r, a);
+ g = SkMulDiv255Ceiling(g, a);
+ b = SkMulDiv255Ceiling(b, a);
+ }
+ // NoCheck: https://bugs.webkit.org/show_bug.cgi?id=74025
+ dstRow[x] = SkPackARGB32NoCheck(a, r, g, b);
+ }
+ src += srcRowBytes;
+ dst += dstRowBytes;
+ }
+}
+
+#ifdef SK_CPU_LENDIAN
+ static const int SK_NATIVE_A_IDX = SK_A32_SHIFT / 8;
+ static const int SK_NATIVE_R_IDX = SK_R32_SHIFT / 8;
+ static const int SK_NATIVE_G_IDX = SK_G32_SHIFT / 8;
+ static const int SK_NATIVE_B_IDX = SK_B32_SHIFT / 8;
+#else
+ static const int SK_NATIVE_A_IDX = 3 - (SK_A32_SHIFT / 8);
+ static const int SK_NATIVE_R_IDX = 3 - (SK_R32_SHIFT / 8);
+ static const int SK_NATIVE_G_IDX = 3 - (SK_G32_SHIFT / 8);
+ static const int SK_NATIVE_B_IDX = 3 - (SK_B32_SHIFT / 8);
+#endif
+
+inline void SkCopyBitmapToConfig8888(uint32_t* dstPixels,
+ size_t dstRowBytes,
+ SkCanvas::Config8888 dstConfig8888,
+ const SkBitmap& srcBmp) {
+ switch (dstConfig8888) {
+ case SkCanvas::kNative_Premul_Config8888:
+ bitmap_copy_to_config8888<false,
+ SK_NATIVE_A_IDX, SK_NATIVE_R_IDX,
+ SK_NATIVE_G_IDX, SK_NATIVE_B_IDX>(
+ dstPixels,
+ dstRowBytes,
+ srcBmp);
+ break;
+ case SkCanvas::kNative_Unpremul_Config8888:
+ bitmap_copy_to_config8888<true,
+ SK_NATIVE_A_IDX, SK_NATIVE_R_IDX,
+ SK_NATIVE_G_IDX, SK_NATIVE_B_IDX>(
+ dstPixels,
+ dstRowBytes,
+ srcBmp);
+ break;
+ case SkCanvas::kBGRA_Premul_Config8888:
+ bitmap_copy_to_config8888<false, 3, 2, 1, 0> (
+ dstPixels, dstRowBytes, srcBmp);
+ break;
+ case SkCanvas::kBGRA_Unpremul_Config8888:
+ bitmap_copy_to_config8888<true, 3, 2, 1, 0> (
+ dstPixels, dstRowBytes, srcBmp);
+ break;
+ case SkCanvas::kRGBA_Premul_Config8888:
+ bitmap_copy_to_config8888<false, 3, 0, 1, 2> (
+ dstPixels, dstRowBytes, srcBmp);
+ break;
+ case SkCanvas::kRGBA_Unpremul_Config8888:
+ bitmap_copy_to_config8888<true, 3, 0, 1, 2> (
+ dstPixels, dstRowBytes, srcBmp);
+ break;
+ default:
+ SkDEBUGFAIL("unexpected Config8888");
+ break;
+ }
+}
+
+inline void SkCopyConfig8888ToBitmap(const SkBitmap& dstBmp,
+ const uint32_t* srcPixels,
+ size_t srcRowBytes,
+ SkCanvas::Config8888 srcConfig8888) {
+ switch (srcConfig8888) {
+ case SkCanvas::kNative_Premul_Config8888:
+ config8888_copy_to_bitmap<false,
+ SK_NATIVE_A_IDX, SK_NATIVE_R_IDX,
+ SK_NATIVE_G_IDX, SK_NATIVE_B_IDX>(
+ dstBmp,
+ srcPixels,
+ srcRowBytes);
+ break;
+ case SkCanvas::kNative_Unpremul_Config8888:
+ config8888_copy_to_bitmap<true,
+ SK_NATIVE_A_IDX, SK_NATIVE_R_IDX,
+ SK_NATIVE_G_IDX, SK_NATIVE_B_IDX>(
+ dstBmp,
+ srcPixels,
+ srcRowBytes);
+ break;
+ case SkCanvas::kBGRA_Premul_Config8888:
+ config8888_copy_to_bitmap<false, 3, 2, 1, 0> (
+ dstBmp, srcPixels, srcRowBytes);
+ break;
+ case SkCanvas::kBGRA_Unpremul_Config8888:
+ config8888_copy_to_bitmap<true, 3, 2, 1, 0> (
+ dstBmp, srcPixels, srcRowBytes);
+ break;
+ case SkCanvas::kRGBA_Premul_Config8888:
+ config8888_copy_to_bitmap<false, 3, 0, 1, 2> (
+ dstBmp, srcPixels, srcRowBytes);
+ break;
+ case SkCanvas::kRGBA_Unpremul_Config8888:
+ config8888_copy_to_bitmap<true, 3, 0, 1, 2> (
+ dstBmp, srcPixels, srcRowBytes);
+ break;
+ default:
+ SkDEBUGFAIL("unexpected Config8888");
+ break;
+ }
+}
+
+inline void SkCopyARGB8888BitmapTo(uint32_t* dstPixels,
+ size_t dstRowBytes,
+ const SkBitmap& srcBmp) {
+ SkASSERT(SkBitmap::kARGB_8888_Config == srcBmp.config());
+
+ SkAutoLockPixels alp(srcBmp);
+
+ int w = srcBmp.width();
+ int h = srcBmp.height();
+ size_t srcRowBytes = srcBmp.rowBytes();
+
+ size_t tightRowBytes = w * 4;
+
+ char* src = reinterpret_cast<char*>(srcBmp.getPixels());
+ char* dst = reinterpret_cast<char*>(dstPixels);
+
+ if (tightRowBytes == srcRowBytes &&
+ tightRowBytes == dstRowBytes) {
+ memcpy(dst, src, tightRowBytes * h);
+ } else {
+ for (int y = 0; y < h; ++y) {
+ memcpy(dst, src, tightRowBytes);
+ dst += dstRowBytes;
+ src += srcRowBytes;
+ }
+ }
+}
+
+}
diff --git a/src/core/SkCordic.cpp b/src/core/SkCordic.cpp
index 539bc9b..8fb60c5 100644
--- a/src/core/SkCordic.cpp
+++ b/src/core/SkCordic.cpp
@@ -1,19 +1,11 @@
-/* libs/corecg/SkCordic.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkCordic.h"
#include "SkMath.h"
diff --git a/src/core/SkCordic.h b/src/core/SkCordic.h
index 9f45a81..b70f987 100644
--- a/src/core/SkCordic.h
+++ b/src/core/SkCordic.h
@@ -1,19 +1,11 @@
-/* libs/corecg/SkCordic.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkCordic_DEFINED
#define SkCordic_DEFINED
diff --git a/src/core/SkCoreBlitters.h b/src/core/SkCoreBlitters.h
index b8724c2..4947198 100644
--- a/src/core/SkCoreBlitters.h
+++ b/src/core/SkCoreBlitters.h
@@ -1,19 +1,9 @@
-/* libs/graphics/sgl/SkCoreBlitters.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkCoreBlitters_DEFINED
#define SkCoreBlitters_DEFINED
@@ -104,7 +94,6 @@ protected:
SkColor fColor;
SkPMColor fPMColor;
SkBlitRow::ColorProc fColor32Proc;
- SkBlitMask::Proc fBlitMaskProc;
private:
unsigned fSrcA, fSrcR, fSrcG, fSrcB;
@@ -129,7 +118,6 @@ class SkARGB32_Black_Blitter : public SkARGB32_Opaque_Blitter {
public:
SkARGB32_Black_Blitter(const SkBitmap& device, const SkPaint& paint)
: INHERITED(device, paint) {}
- virtual void blitMask(const SkMask&, const SkIRect&);
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]);
private:
@@ -142,6 +130,7 @@ public:
virtual ~SkARGB32_Shader_Blitter();
virtual void blitH(int x, int y, int width);
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]);
+ virtual void blitMask(const SkMask&, const SkIRect&);
private:
SkXfermode* fXfermode;
diff --git a/src/core/SkCubicClipper.cpp b/src/core/SkCubicClipper.cpp
index 6e47513..662591f 100644
--- a/src/core/SkCubicClipper.cpp
+++ b/src/core/SkCubicClipper.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2009 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkCubicClipper.h"
#include "SkGeometry.h"
diff --git a/src/core/SkCubicClipper.h b/src/core/SkCubicClipper.h
index 9a45b31..c52eabe 100644
--- a/src/core/SkCubicClipper.h
+++ b/src/core/SkCubicClipper.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2009 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkCubicClipper_DEFINED
#define SkCubicClipper_DEFINED
diff --git a/src/core/SkData.cpp b/src/core/SkData.cpp
new file mode 100644
index 0000000..f9f4043
--- /dev/null
+++ b/src/core/SkData.cpp
@@ -0,0 +1,103 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#include "SkData.h"
+
+SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) {
+ fPtr = ptr;
+ fSize = size;
+ fReleaseProc = proc;
+ fReleaseProcContext = context;
+}
+
+SkData::~SkData() {
+ if (fReleaseProc) {
+ fReleaseProc(fPtr, fSize, fReleaseProcContext);
+ }
+}
+
+size_t SkData::copyRange(size_t offset, size_t length, void* buffer) const {
+ size_t available = fSize;
+ if (offset >= available || 0 == length) {
+ return 0;
+ }
+ available -= offset;
+ if (length > available) {
+ length = available;
+ }
+ SkASSERT(length > 0);
+
+ memcpy(buffer, this->bytes() + offset, length);
+ return length;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkData* SkData::NewEmpty() {
+ static SkData* gEmptyRef;
+ if (NULL == gEmptyRef) {
+ gEmptyRef = new SkData(NULL, 0, NULL, NULL);
+ }
+ gEmptyRef->ref();
+ return gEmptyRef;
+}
+
+// assumes fPtr was allocated via sk_malloc
+static void sk_free_releaseproc(const void* ptr, size_t, void*) {
+ sk_free((void*)ptr);
+}
+
+SkData* SkData::NewFromMalloc(const void* data, size_t length) {
+ return new SkData(data, length, sk_free_releaseproc, NULL);
+}
+
+SkData* SkData::NewWithCopy(const void* data, size_t length) {
+ if (0 == length) {
+ return SkData::NewEmpty();
+ }
+
+ void* copy = sk_malloc_throw(length); // balanced in sk_free_releaseproc
+ memcpy(copy, data, length);
+ return new SkData(copy, length, sk_free_releaseproc, NULL);
+}
+
+SkData* SkData::NewWithProc(const void* data, size_t length,
+ ReleaseProc proc, void* context) {
+ return new SkData(data, length, proc, context);
+}
+
+// assumes context is a SkData
+static void sk_dataref_releaseproc(const void*, size_t, void* context) {
+ SkData* src = reinterpret_cast<SkData*>(context);
+ src->unref();
+}
+
+SkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) {
+ /*
+ We could, if we wanted/need to, just make a deep copy of src's data,
+ rather than referencing it. This would duplicate the storage (of the
+ subset amount) but would possibly allow src to go out of scope sooner.
+ */
+
+ size_t available = src->size();
+ if (offset >= available || 0 == length) {
+ return SkData::NewEmpty();
+ }
+ available -= offset;
+ if (length > available) {
+ length = available;
+ }
+ SkASSERT(length > 0);
+
+ src->ref(); // this will be balanced in sk_dataref_releaseproc
+ return new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
+ const_cast<SkData*>(src));
+}
+
diff --git a/src/core/SkDebug.cpp b/src/core/SkDebug.cpp
index 64ea8b4..4b33836 100644
--- a/src/core/SkDebug.cpp
+++ b/src/core/SkDebug.cpp
@@ -1,19 +1,11 @@
-/* libs/corecg/SkDebug.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTypes.h"
diff --git a/src/core/SkDeque.cpp b/src/core/SkDeque.cpp
index 9d685ee..385b48d 100644
--- a/src/core/SkDeque.cpp
+++ b/src/core/SkDeque.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkDeque.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDeque.h"
@@ -225,9 +217,7 @@ void SkDeque::pop_back() {
///////////////////////////////////////////////////////////////////////////////
-SkDeque::F2BIter::F2BIter() {
- fPos = NULL;
-}
+SkDeque::F2BIter::F2BIter() : fHead(NULL), fPos(NULL), fElemSize(0) {}
SkDeque::F2BIter::F2BIter(const SkDeque& d) {
this->reset(d);
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index aee5a5e..aaafb14 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -1,64 +1,58 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkDevice.h"
#include "SkDraw.h"
+#include "SkImageFilter.h"
#include "SkMetaData.h"
#include "SkRect.h"
-//#define TRACE_FACTORY_LIFETIME
-
-#ifdef TRACE_FACTORY_LIFETIME
- static int gFactoryCounter;
-#endif
-
-SkDeviceFactory::SkDeviceFactory() {
-#ifdef TRACE_FACTORY_LIFETIME
- SkDebugf("+++ factory index %d\n", gFactoryCounter);
- ++gFactoryCounter;
-#endif
-}
-
-SkDeviceFactory::~SkDeviceFactory() {
-#ifdef TRACE_FACTORY_LIFETIME
- --gFactoryCounter;
- SkDebugf("--- factory index %d\n", gFactoryCounter);
-#endif
-}
-
///////////////////////////////////////////////////////////////////////////////
-SkDevice::SkDevice(SkCanvas* canvas) : fCanvas(canvas), fMetaData(NULL) {
+SkDevice::SkDevice(const SkBitmap& bitmap) : fBitmap(bitmap) {
fOrigin.setZero();
- fCachedDeviceFactory = NULL;
+ fMetaData = NULL;
}
-SkDevice::SkDevice(SkCanvas* canvas, const SkBitmap& bitmap, bool isForLayer)
- : fCanvas(canvas), fBitmap(bitmap), fMetaData(NULL) {
+SkDevice::SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque) {
fOrigin.setZero();
- // auto-allocate if we're for offscreen drawing
- if (isForLayer) {
- if (NULL == fBitmap.getPixels() && NULL == fBitmap.pixelRef()) {
- fBitmap.allocPixels();
- if (!fBitmap.isOpaque()) {
- fBitmap.eraseColor(0);
- }
- }
+ fMetaData = NULL;
+
+ fBitmap.setConfig(config, width, height);
+ fBitmap.allocPixels();
+ fBitmap.setIsOpaque(isOpaque);
+ if (!isOpaque) {
+ fBitmap.eraseColor(0);
}
- fCachedDeviceFactory = NULL;
}
SkDevice::~SkDevice() {
delete fMetaData;
- SkSafeUnref(fCachedDeviceFactory);
}
-SkDeviceFactory* SkDevice::onNewDeviceFactory() {
- return SkNEW(SkRasterDeviceFactory);
+SkDevice* SkDevice::createCompatibleDevice(SkBitmap::Config config,
+ int width, int height,
+ bool isOpaque) {
+ return this->onCreateCompatibleDevice(config, width, height,
+ isOpaque, kGeneral_Usage);
}
-SkDeviceFactory* SkDevice::getDeviceFactory() {
- if (NULL == fCachedDeviceFactory) {
- fCachedDeviceFactory = this->onNewDeviceFactory();
- }
- return fCachedDeviceFactory;
+SkDevice* SkDevice::createCompatibleDeviceForSaveLayer(SkBitmap::Config config,
+ int width, int height,
+ bool isOpaque) {
+ return this->onCreateCompatibleDevice(config, width, height,
+ isOpaque, kSaveLayer_Usage);
+}
+
+SkDevice* SkDevice::onCreateCompatibleDevice(SkBitmap::Config config,
+ int width, int height,
+ bool isOpaque,
+ Usage usage) {
+ return SkNEW_ARGS(SkDevice,(config, width, height, isOpaque));
}
SkMetaData& SkDevice::getMetaData() {
@@ -71,11 +65,15 @@ SkMetaData& SkDevice::getMetaData() {
}
void SkDevice::lockPixels() {
- fBitmap.lockPixels();
+ if (fBitmap.lockPixelsAreWritable()) {
+ fBitmap.lockPixels();
+ }
}
void SkDevice::unlockPixels() {
- fBitmap.unlockPixels();
+ if (fBitmap.lockPixelsAreWritable()) {
+ fBitmap.unlockPixels();
+ }
}
const SkBitmap& SkDevice::accessBitmap(bool changePixels) {
@@ -86,19 +84,13 @@ const SkBitmap& SkDevice::accessBitmap(bool changePixels) {
return fBitmap;
}
-void SkDevice::getBounds(SkIRect* bounds) const {
+void SkDevice::getGlobalBounds(SkIRect* bounds) const {
if (bounds) {
- bounds->set(0, 0, fBitmap.width(), fBitmap.height());
+ bounds->setXYWH(fOrigin.x(), fOrigin.y(),
+ fBitmap.width(), fBitmap.height());
}
}
-bool SkDevice::intersects(const SkIRect& r, SkIRect* sect) const {
- SkIRect bounds;
-
- this->getBounds(&bounds);
- return sect ? sect->intersect(r, bounds) : SkIRect::Intersects(r, bounds);
-}
-
void SkDevice::clear(SkColor color) {
fBitmap.eraseColor(color);
}
@@ -109,37 +101,187 @@ void SkDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& region,
const SkClipStack& clipStack) {
}
-///////////////////////////////////////////////////////////////////////////////
+bool SkDevice::filterImage(SkImageFilter*, const SkBitmap& src,
+ const SkMatrix& ctm,
+ SkBitmap* result, SkIPoint* offset) {
+ return false;
+}
-bool SkDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
- const SkBitmap& src = this->accessBitmap(false);
+bool SkDevice::allowImageFilter(SkImageFilter*) {
+ return true;
+}
- SkIRect bounds;
- bounds.set(0, 0, src.width(), src.height());
- if (!bounds.intersect(srcRect)) {
+///////////////////////////////////////////////////////////////////////////////
+
+bool SkDevice::readPixels(SkBitmap* bitmap, int x, int y,
+ SkCanvas::Config8888 config8888) {
+ if (SkBitmap::kARGB_8888_Config != bitmap->config() ||
+ NULL != bitmap->getTexture()) {
return false;
}
- SkBitmap subset;
- if (!src.extractSubset(&subset, bounds)) {
+ const SkBitmap& src = this->accessBitmap(false);
+
+ SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap->width(),
+ bitmap->height());
+ SkIRect devbounds = SkIRect::MakeWH(src.width(), src.height());
+ if (!srcRect.intersect(devbounds)) {
return false;
}
SkBitmap tmp;
- if (!subset.copyTo(&tmp, SkBitmap::kARGB_8888_Config)) {
- return false;
+ SkBitmap* bmp;
+ if (bitmap->isNull()) {
+ tmp.setConfig(SkBitmap::kARGB_8888_Config, bitmap->width(),
+ bitmap->height());
+ if (!tmp.allocPixels()) {
+ return false;
+ }
+ bmp = &tmp;
+ } else {
+ bmp = bitmap;
+ }
+
+ SkIRect subrect = srcRect;
+ subrect.offset(-x, -y);
+ SkBitmap bmpSubset;
+ bmp->extractSubset(&bmpSubset, subrect);
+
+ bool result = this->onReadPixels(bmpSubset,
+ srcRect.fLeft,
+ srcRect.fTop,
+ config8888);
+ if (result && bmp == &tmp) {
+ tmp.swap(*bitmap);
}
+ return result;
+}
+
+#ifdef SK_CPU_LENDIAN
+ #if 24 == SK_A32_SHIFT && 16 == SK_R32_SHIFT && \
+ 8 == SK_G32_SHIFT && 0 == SK_B32_SHIFT
+ const SkCanvas::Config8888 SkDevice::kPMColorAlias =
+ SkCanvas::kBGRA_Premul_Config8888;
+ #elif 24 == SK_A32_SHIFT && 0 == SK_R32_SHIFT && \
+ 8 == SK_G32_SHIFT && 16 == SK_B32_SHIFT
+ const SkCanvas::Config8888 SkDevice::kPMColorAlias =
+ SkCanvas::kRGBA_Premul_Config8888;
+ #else
+ const SkCanvas::Config8888 SkDevice::kPMColorAlias =
+ (SkCanvas::Config8888) -1;
+ #endif
+#else
+ #if 0 == SK_A32_SHIFT && 8 == SK_R32_SHIFT && \
+ 16 == SK_G32_SHIFT && 24 == SK_B32_SHIFT
+ const SkCanvas::Config8888 SkDevice::kPMColorAlias =
+ SkCanvas::kBGRA_Premul_Config8888;
+ #elif 0 == SK_A32_SHIFT && 24 == SK_R32_SHIFT && \
+ 16 == SK_G32_SHIFT && 8 == SK_B32_SHIFT
+ const SkCanvas::Config8888 SkDevice::kPMColorAlias =
+ SkCanvas::kRGBA_Premul_Config8888;
+ #else
+ const SkCanvas::Config8888 SkDevice::kPMColorAlias =
+ (SkCanvas::Config8888) -1;
+ #endif
+#endif
- tmp.swap(*bitmap);
+#include <SkConfig8888.h>
+
+bool SkDevice::onReadPixels(const SkBitmap& bitmap,
+ int x, int y,
+ SkCanvas::Config8888 config8888) {
+ SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
+ SkASSERT(!bitmap.isNull());
+ SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height())));
+
+ SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(),
+ bitmap.height());
+ const SkBitmap& src = this->accessBitmap(false);
+
+ SkBitmap subset;
+ if (!src.extractSubset(&subset, srcRect)) {
+ return false;
+ }
+ if (SkBitmap::kARGB_8888_Config != subset.config()) {
+ // It'd be preferable to do this directly to bitmap.
+ subset.copyTo(&subset, SkBitmap::kARGB_8888_Config);
+ }
+ SkAutoLockPixels alp(bitmap);
+ uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels());
+ if ((SkCanvas::kNative_Premul_Config8888 == config8888 ||
+ kPMColorAlias == config8888)) {
+ SkCopyARGB8888BitmapTo(bmpPixels, bitmap.rowBytes(), subset);
+ } else {
+ SkCopyBitmapToConfig8888(bmpPixels,
+ bitmap.rowBytes(),
+ config8888,
+ subset);
+ }
return true;
}
-void SkDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
+void SkDevice::writePixels(const SkBitmap& bitmap,
+ int x, int y,
+ SkCanvas::Config8888 config8888) {
+ if (bitmap.isNull() || bitmap.getTexture()) {
+ return;
+ }
+ const SkBitmap* sprite = &bitmap;
+ // check whether we have to handle a config8888 that doesn't match SkPMColor
+ if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
+ SkCanvas::kNative_Premul_Config8888 != config8888 &&
+ kPMColorAlias != config8888) {
+
+ // We're going to have to convert from a config8888 to the native config
+ // First we clip to the device bounds.
+ SkBitmap dstBmp = this->accessBitmap(true);
+ SkIRect spriteRect = SkIRect::MakeXYWH(x, y,
+ bitmap.width(), bitmap.height());
+ SkIRect devRect = SkIRect::MakeWH(dstBmp.width(), dstBmp.height());
+ if (!spriteRect.intersect(devRect)) {
+ return;
+ }
+
+ // write directly to the device if it has pixels and is SkPMColor
+ bool drawSprite;
+ if (SkBitmap::kARGB_8888_Config == dstBmp.config() && !dstBmp.isNull()) {
+ // we can write directly to the dst when doing the conversion
+ dstBmp.extractSubset(&dstBmp, spriteRect);
+ drawSprite = false;
+ } else {
+ // we convert to a temporary bitmap and draw that as a sprite
+ dstBmp.setConfig(SkBitmap::kARGB_8888_Config,
+ spriteRect.width(),
+ spriteRect.height());
+ if (!dstBmp.allocPixels()) {
+ return;
+ }
+ drawSprite = true;
+ }
+
+ // copy pixels to dstBmp and convert from config8888 to native config.
+ SkAutoLockPixels alp(bitmap);
+ uint32_t* srcPixels = bitmap.getAddr32(spriteRect.fLeft - x,
+ spriteRect.fTop - y);
+ SkCopyConfig8888ToBitmap(dstBmp,
+ srcPixels,
+ bitmap.rowBytes(),
+ config8888);
+
+ if (drawSprite) {
+ // we've clipped the sprite when we made a copy
+ x = spriteRect.fLeft;
+ y = spriteRect.fTop;
+ sprite = &dstBmp;
+ } else {
+ return;
+ }
+ }
+
SkPaint paint;
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
-
SkCanvas canvas(this);
- canvas.drawSprite(bitmap, x, y, &paint);
+ canvas.drawSprite(*sprite, x, y, &paint);
}
///////////////////////////////////////////////////////////////////////////////
@@ -202,7 +344,7 @@ void SkDevice::drawTextOnPath(const SkDraw& draw, const void* text,
draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
}
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
void SkDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len,
const SkPoint pos[], const SkPaint& paint,
const SkPath& path, const SkMatrix* matrix) {
@@ -222,26 +364,24 @@ void SkDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device,
int x, int y, const SkPaint& paint) {
- draw.drawSprite(device->accessBitmap(false), x, y, paint);
+ const SkBitmap& src = device->accessBitmap(false);
+ draw.drawSprite(src, x, y, paint);
}
///////////////////////////////////////////////////////////////////////////////
bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
- if (!paint.isLCDRenderText()) {
+ if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
// we're cool with the paint as is
return false;
}
if (SkBitmap::kARGB_8888_Config != fBitmap.config() ||
- paint.getShader() ||
- paint.getXfermode() || // unless its srcover
- paint.getMaskFilter() ||
paint.getRasterizer() ||
- paint.getColorFilter() ||
paint.getPathEffect() ||
paint.isFakeBoldText() ||
- paint.getStyle() != SkPaint::kFill_Style) {
+ paint.getStyle() != SkPaint::kFill_Style ||
+ !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) {
// turn off lcd
flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
flags->fHinting = paint.getHinting();
@@ -251,15 +391,3 @@ bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
return false;
}
-///////////////////////////////////////////////////////////////////////////////
-
-SkDevice* SkRasterDeviceFactory::newDevice(SkCanvas* canvas,
- SkBitmap::Config config, int width,
- int height, bool isOpaque,
- bool isForLayer) {
- SkBitmap bitmap;
- bitmap.setConfig(config, width, height);
- bitmap.setIsOpaque(isOpaque);
-
- return SkNEW_ARGS(SkDevice, (canvas, bitmap, isForLayer));
-}
diff --git a/src/core/SkDither.cpp b/src/core/SkDither.cpp
index 53a8573..bdd8c2f 100644
--- a/src/core/SkDither.cpp
+++ b/src/core/SkDither.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkDither.h"
/* The base dither matrix we use to derive optimized ones for 565 and 4444
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index 5001296..c6fd406 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkDraw.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDraw.h"
#include "SkBlitter.h"
@@ -24,12 +16,13 @@
#include "SkMaskFilter.h"
#include "SkPaint.h"
#include "SkPathEffect.h"
+#include "SkRasterClip.h"
#include "SkRasterizer.h"
#include "SkScan.h"
#include "SkShader.h"
#include "SkStroke.h"
#include "SkTemplatesPriv.h"
-#include "SkTextFormatParams.h"
+#include "SkTLazy.h"
#include "SkUtils.h"
#include "SkAutoKern.h"
@@ -159,7 +152,7 @@ static BitmapXferProc ChooseBitmapXferProc(const SkBitmap& bitmap,
}
SkXfermode::Mode mode;
- if (!SkXfermode::IsMode(paint.getXfermode(), &mode)) {
+ if (!SkXfermode::AsMode(paint.getXfermode(), &mode)) {
return NULL;
}
@@ -238,7 +231,7 @@ static void CallBitmapXferProc(const SkBitmap& bitmap, const SkIRect& rect,
shiftPerPixel = 0;
break;
default:
- SkASSERT(!"Can't use xferproc on this config");
+ SkDEBUGFAIL("Can't use xferproc on this config");
return;
}
@@ -258,7 +251,7 @@ static void CallBitmapXferProc(const SkBitmap& bitmap, const SkIRect& rect,
void SkDraw::drawPaint(const SkPaint& paint) const {
SkDEBUGCODE(this->validate();)
- if (fClip->isEmpty()) {
+ if (fRC->isEmpty()) {
return;
}
@@ -268,29 +261,32 @@ void SkDraw::drawPaint(const SkPaint& paint) const {
return;
}
- /* If we don't have a shader (i.e. we're just a solid color) we may
- be faster to operate directly on the device bitmap, rather than invoking
- a blitter. Esp. true for xfermodes, which require a colorshader to be
- present, which is just redundant work. Since we're drawing everywhere
- in the clip, we don't have to worry about antialiasing.
- */
- uint32_t procData = 0; // to avoid the warning
- BitmapXferProc proc = ChooseBitmapXferProc(*fBitmap, paint, &procData);
- if (proc) {
- if (D_Dst_BitmapXferProc == proc) { // nothing to do
- return;
- }
+ if (fRC->isBW()) {
+ /* If we don't have a shader (i.e. we're just a solid color) we may
+ be faster to operate directly on the device bitmap, rather than invoking
+ a blitter. Esp. true for xfermodes, which require a colorshader to be
+ present, which is just redundant work. Since we're drawing everywhere
+ in the clip, we don't have to worry about antialiasing.
+ */
+ uint32_t procData = 0; // to avoid the warning
+ BitmapXferProc proc = ChooseBitmapXferProc(*fBitmap, paint, &procData);
+ if (proc) {
+ if (D_Dst_BitmapXferProc == proc) { // nothing to do
+ return;
+ }
- SkRegion::Iterator iter(*fClip);
- while (!iter.done()) {
- CallBitmapXferProc(*fBitmap, iter.rect(), proc, procData);
- iter.next();
+ SkRegion::Iterator iter(fRC->bwRgn());
+ while (!iter.done()) {
+ CallBitmapXferProc(*fBitmap, iter.rect(), proc, procData);
+ iter.next();
+ }
+ return;
}
- } else {
- // normal case: use a blitter
- SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
- SkScan::FillIRect(devRect, fClip, blitter.get());
}
+
+ // normal case: use a blitter
+ SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
+ SkScan::FillIRect(devRect, *fRC, blitter.get());
}
///////////////////////////////////////////////////////////////////////////////
@@ -299,6 +295,7 @@ struct PtProcRec {
SkCanvas::PointMode fMode;
const SkPaint* fPaint;
const SkRegion* fClip;
+ const SkRasterClip* fRC;
// computed values
SkFixed fRadius;
@@ -307,8 +304,11 @@ struct PtProcRec {
SkBlitter*);
bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix,
- const SkRegion* clip);
- Proc chooseProc(SkBlitter* blitter);
+ const SkRasterClip*);
+ Proc chooseProc(SkBlitter** blitter);
+
+private:
+ SkAAClipBlitterWrapper fWrapper;
};
static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
@@ -328,8 +328,8 @@ static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
static void bw_pt_rect_16_hair_proc(const PtProcRec& rec,
const SkPoint devPts[], int count,
SkBlitter* blitter) {
- SkASSERT(rec.fClip->isRect());
- const SkIRect& r = rec.fClip->getBounds();
+ SkASSERT(rec.fRC->isRect());
+ const SkIRect& r = rec.fRC->getBounds();
uint32_t value;
const SkBitmap* bitmap = blitter->justAnOpaqueColor(&value);
SkASSERT(bitmap);
@@ -361,14 +361,14 @@ static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
int count, SkBlitter* blitter) {
for (int i = 0; i < count; i += 2) {
- SkScan::HairLine(devPts[i], devPts[i+1], rec.fClip, blitter);
+ SkScan::HairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
}
}
static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
int count, SkBlitter* blitter) {
for (int i = 0; i < count - 1; i++) {
- SkScan::HairLine(devPts[i], devPts[i+1], rec.fClip, blitter);
+ SkScan::HairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
}
}
@@ -377,14 +377,14 @@ static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
int count, SkBlitter* blitter) {
for (int i = 0; i < count; i += 2) {
- SkScan::AntiHairLine(devPts[i], devPts[i+1], rec.fClip, blitter);
+ SkScan::AntiHairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
}
}
static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
int count, SkBlitter* blitter) {
for (int i = 0; i < count - 1; i++) {
- SkScan::AntiHairLine(devPts[i], devPts[i+1], rec.fClip, blitter);
+ SkScan::AntiHairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
}
}
@@ -403,7 +403,7 @@ static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[],
r.fRight = x + radius;
r.fBottom = y + radius;
- SkScan::FillXRect(r, rec.fClip, blitter);
+ SkScan::FillXRect(r, *rec.fRC, blitter);
}
}
@@ -420,13 +420,13 @@ static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[],
r.fRight = x + radius;
r.fBottom = y + radius;
- SkScan::AntiFillXRect(r, rec.fClip, blitter);
+ SkScan::AntiFillXRect(r, *rec.fRC, blitter);
}
}
// If this guy returns true, then chooseProc() must return a valid proc
bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
- const SkMatrix* matrix, const SkRegion* clip) {
+ const SkMatrix* matrix, const SkRasterClip* rc) {
if (paint.getPathEffect()) {
return false;
}
@@ -434,7 +434,8 @@ bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
if (0 == width) {
fMode = mode;
fPaint = &paint;
- fClip = clip;
+ fClip = NULL;
+ fRC = rc;
fRadius = SK_Fixed1 >> 1;
return true;
}
@@ -449,7 +450,8 @@ bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
fMode = mode;
fPaint = &paint;
- fClip = clip;
+ fClip = NULL;
+ fRC = rc;
fRadius = SkScalarToFixed(SkScalarMul(width, sx)) >> 1;
return true;
}
@@ -457,9 +459,19 @@ bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
return false;
}
-PtProcRec::Proc PtProcRec::chooseProc(SkBlitter* blitter) {
+PtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) {
Proc proc = NULL;
+ SkBlitter* blitter = *blitterPtr;
+ if (fRC->isBW()) {
+ fClip = &fRC->bwRgn();
+ } else {
+ fWrapper.init(*fRC, blitter);
+ fClip = &fWrapper.getRgn();
+ blitter = fWrapper.getBlitter();
+ *blitterPtr = blitter;
+ }
+
// for our arrays
SkASSERT(0 == SkCanvas::kPoints_PointMode);
SkASSERT(1 == SkCanvas::kLines_PointMode);
@@ -535,8 +547,7 @@ void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
SkDEBUGCODE(this->validate();)
// nothing to draw
- if (fClip->isEmpty() ||
- (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
+ if (fRC->isEmpty()) {
return;
}
@@ -554,13 +565,13 @@ void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
}
PtProcRec rec;
- if (!forceUseDevice && rec.init(mode, paint, fMatrix, fClip)) {
+ if (!forceUseDevice && rec.init(mode, paint, fMatrix, fRC)) {
SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
SkPoint devPts[MAX_DEV_PTS];
const SkMatrix* matrix = fMatrix;
SkBlitter* bltr = blitter.get();
- PtProcRec::Proc proc = rec.chooseProc(bltr);
+ PtProcRec::Proc proc = rec.chooseProc(&bltr);
// we have to back up subsequent passes if we're in polygon mode
const size_t backup = (SkCanvas::kPolygon_PointMode == mode);
@@ -705,8 +716,7 @@ void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
SkDEBUGCODE(this->validate();)
// nothing to draw
- if (fClip->isEmpty() ||
- (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
+ if (fRC->isEmpty()) {
return;
}
@@ -718,7 +728,7 @@ void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
rtype = kPath_RectType;
}
#endif
-
+
if (kPath_RectType == rtype) {
SkPath tmp;
tmp.addRect(rect);
@@ -749,13 +759,13 @@ void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
// extra space for hairlines
ir.inset(-1, -1);
}
- if (fClip->quickReject(ir))
+ if (fRC->quickReject(ir))
return;
}
SkAutoBlitterChoose blitterStorage(*fBitmap, matrix, paint);
+ const SkRasterClip& clip = *fRC;
SkBlitter* blitter = blitterStorage.get();
- const SkRegion* clip = fClip;
// we want to "fill" if we are kFill or kStrokeAndFill, since in the latter
// case we are also hairline (if we've gotten to here), which devolves to
@@ -783,7 +793,7 @@ void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
}
break;
default:
- SkASSERT(!"bad rtype");
+ SkDEBUGFAIL("bad rtype");
}
}
@@ -792,43 +802,36 @@ void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const {
return;
}
- SkMask dstM;
- const SkMask* mask = &srcM;
-
- dstM.fImage = NULL;
- SkAutoMaskImage ami(&dstM, false);
+ const SkMask* mask = &srcM;
+ SkMask dstM;
if (paint.getMaskFilter() &&
paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, NULL)) {
mask = &dstM;
+ } else {
+ dstM.fImage = NULL;
}
+ SkAutoMaskFreeImage ami(dstM.fImage);
if (fBounder && !fBounder->doIRect(mask->fBounds)) {
return;
}
- SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
+ SkAutoBlitterChoose blitterChooser(*fBitmap, *fMatrix, paint);
+ SkBlitter* blitter = blitterChooser.get();
- blitter->blitMaskRegion(*mask, *fClip);
-}
+ SkAAClipBlitterWrapper wrapper;
+ const SkRegion* clipRgn;
-class SkAutoPaintRestoreColorStrokeWidth {
-public:
- SkAutoPaintRestoreColorStrokeWidth(const SkPaint& paint) {
- fPaint = (SkPaint*)&paint;
- fColor = paint.getColor();
- fWidth = paint.getStrokeWidth();
- }
- ~SkAutoPaintRestoreColorStrokeWidth() {
- fPaint->setColor(fColor);
- fPaint->setStrokeWidth(fWidth);
+ if (fRC->isBW()) {
+ clipRgn = &fRC->bwRgn();
+ } else {
+ wrapper.init(*fRC, blitter);
+ clipRgn = &wrapper.getRgn();
+ blitter = wrapper.getBlitter();
}
-
-private:
- SkPaint* fPaint;
- SkColor fColor;
- SkScalar fWidth;
-};
+ blitter->blitMaskRegion(*mask, *clipRgn);
+}
static SkScalar fast_len(const SkVector& vec) {
SkScalar x = SkScalarAbs(vec.fX);
@@ -839,33 +842,75 @@ static SkScalar fast_len(const SkVector& vec) {
return x + SkScalarHalf(y);
}
-// our idea is to return true if there is no appreciable skew or non-square scale
-// for that we'll transform (0,1) and (1,0), and check that the resulting dot-prod
-// is nearly one
-static bool map_radius(const SkMatrix& matrix, SkScalar* value) {
+static bool xfermodeSupportsCoverageAsAlpha(SkXfermode* xfer) {
+ SkXfermode::Coeff dc;
+ if (!SkXfermode::AsCoeff(xfer, NULL, &dc)) {
+ return false;
+ }
+
+ switch (dc) {
+ case SkXfermode::kOne_Coeff:
+ case SkXfermode::kISA_Coeff:
+ case SkXfermode::kISC_Coeff:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool SkDrawTreatAsHairline(const SkPaint& paint, const SkMatrix& matrix,
+ SkAlpha* newAlpha) {
+ SkASSERT(newAlpha);
+ if (SkPaint::kStroke_Style != paint.getStyle()) {
+ return false;
+ }
+ SkScalar strokeWidth = paint.getStrokeWidth();
+ if (0 == strokeWidth) {
+ *newAlpha = paint.getAlpha();
+ return true;
+ }
+
+ // if we get here, we need to try to fake a thick-stroke with a modulated
+ // hairline
+
+ if (!paint.isAntiAlias()) {
+ return false;
+ }
+ if (!xfermodeSupportsCoverageAsAlpha(paint.getXfermode())) {
+ return false;
+ }
if (matrix.hasPerspective()) {
return false;
}
+
SkVector src[2], dst[2];
- src[0].set(*value, 0);
- src[1].set(0, *value);
+ src[0].set(strokeWidth, 0);
+ src[1].set(0, strokeWidth);
matrix.mapVectors(dst, src, 2);
SkScalar len0 = fast_len(dst[0]);
SkScalar len1 = fast_len(dst[1]);
if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) {
- *value = SkScalarAve(len0, len1);
+ SkScalar modulate = SkScalarAve(len0, len1);
+#if 0
+ *newAlpha = SkToU8(SkScalarRoundToInt(modulate * paint.getAlpha()));
+#else
+ // this is the old technique, which we preserve for now so we don't
+ // change previous results (testing)
+ // the new way seems fine, its just (a tiny bit) different
+ int scale = (int)SkScalarMul(modulate, 256);
+ *newAlpha = paint.getAlpha() * scale >> 8;
+#endif
return true;
}
return false;
}
-void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& paint,
+void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
const SkMatrix* prePathMatrix, bool pathIsMutable) const {
SkDEBUGCODE(this->validate();)
// nothing to draw
- if (fClip->isEmpty() ||
- (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
+ if (fRC->isEmpty()) {
return;
}
@@ -876,8 +921,8 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& paint,
const SkMatrix* matrix = fMatrix;
if (prePathMatrix) {
- if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style ||
- paint.getRasterizer()) {
+ if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style ||
+ origPaint.getRasterizer()) {
SkPath* result = pathPtr;
if (!pathIsMutable) {
@@ -897,41 +942,30 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& paint,
// at this point we're done with prePathMatrix
SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
- /*
- If the device thickness < 1.0, then make it a hairline, and
- modulate alpha if the thickness is even smaller (e.g. thickness == 0.5
- should modulate the alpha by 1/2)
- */
+ const SkPaint* paint = &origPaint;
+ SkTLazy<SkPaint> lazyPaint;
- SkAutoPaintRestoreColorStrokeWidth aprc(paint);
-
- // can we approximate a thin (but not hairline) stroke with an alpha-modulated
- // hairline? Only if the matrix scales evenly in X and Y, and the device-width is
- // less than a pixel
- if (paint.isAntiAlias() &&
- paint.getStyle() == SkPaint::kStroke_Style && paint.getXfermode() == NULL) {
- SkScalar width = paint.getStrokeWidth();
- if (width > 0 && map_radius(*matrix, &width)) {
- int scale = (int)SkScalarMul(width, 256);
- int alpha = paint.getAlpha() * scale >> 8;
-
- // pretend to be a hairline, with a modulated alpha
- ((SkPaint*)&paint)->setAlpha(alpha);
- ((SkPaint*)&paint)->setStrokeWidth(0);
+ {
+ SkAlpha newAlpha;
+ if (SkDrawTreatAsHairline(origPaint, *matrix, &newAlpha)) {
+ lazyPaint.set(origPaint);
+ lazyPaint.get()->setAlpha(newAlpha);
+ lazyPaint.get()->setStrokeWidth(0);
+ paint = lazyPaint.get();
}
}
- if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
- doFill = paint.getFillPath(*pathPtr, &tmpPath);
+ if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) {
+ doFill = paint->getFillPath(*pathPtr, &tmpPath);
pathPtr = &tmpPath;
}
- if (paint.getRasterizer()) {
+ if (paint->getRasterizer()) {
SkMask mask;
- if (paint.getRasterizer()->rasterize(*pathPtr, *matrix,
- &fClip->getBounds(), paint.getMaskFilter(), &mask,
+ if (paint->getRasterizer()->rasterize(*pathPtr, *matrix,
+ &fRC->getBounds(), paint->getMaskFilter(), &mask,
SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
- this->drawDevMask(mask, paint);
+ this->drawDevMask(mask, *paint);
SkMask::FreeImage(mask.fImage);
}
return;
@@ -943,32 +977,34 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& paint,
// transform the path into device space
pathPtr->transform(*matrix, devPathPtr);
- SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
+ SkAutoBlitterChoose blitter(*fBitmap, *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())) {
+ if (paint->getMaskFilter() &&
+ paint->getMaskFilter()->filterPath(*devPathPtr, *fMatrix, *fRC,
+ fBounder, blitter.get())) {
return; // filterPath() called the blitter, so we're done
}
- if (fBounder && !fBounder->doPath(*devPathPtr, paint, doFill)) {
+ if (fBounder && !fBounder->doPath(*devPathPtr, *paint, doFill)) {
return;
}
+ void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*);
if (doFill) {
- if (paint.isAntiAlias()) {
- SkScan::AntiFillPath(*devPathPtr, *fClip, blitter.get());
+ if (paint->isAntiAlias()) {
+ proc = SkScan::AntiFillPath;
} else {
- SkScan::FillPath(*devPathPtr, *fClip, blitter.get());
+ proc = SkScan::FillPath;
}
} else { // hairline
- if (paint.isAntiAlias()) {
- SkScan::AntiHairPath(*devPathPtr, fClip, blitter.get());
+ if (paint->isAntiAlias()) {
+ proc = SkScan::AntiHairPath;
} else {
- SkScan::HairPath(*devPathPtr, fClip, blitter.get());
+ proc = SkScan::HairPath;
}
}
+ proc(*devPathPtr, *fRC, blitter.get());
}
/** For the purposes of drawing bitmaps, if a matrix is "almost" translate
@@ -1068,7 +1104,7 @@ void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap,
}
}
-static bool clipped_out(const SkMatrix& m, const SkRegion& c,
+static bool clipped_out(const SkMatrix& m, const SkRasterClip& c,
const SkRect& srcR) {
SkRect dstR;
SkIRect devIR;
@@ -1078,22 +1114,27 @@ static bool clipped_out(const SkMatrix& m, const SkRegion& c,
return c.quickReject(devIR);
}
-static bool clipped_out(const SkMatrix& matrix, const SkRegion& clip,
+static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip,
int width, int height) {
SkRect r;
r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height));
return clipped_out(matrix, clip, r);
}
+static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y,
+ const SkBitmap& bitmap) {
+ return clip.isBW() ||
+ clip.quickContains(x, y, x + bitmap.width(), y + bitmap.height());
+}
+
void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
const SkPaint& origPaint) const {
SkDEBUGCODE(this->validate();)
// nothing to draw
- if (fClip->isEmpty() ||
+ if (fRC->isEmpty() ||
bitmap.width() == 0 || bitmap.height() == 0 ||
- bitmap.getConfig() == SkBitmap::kNo_Config ||
- (origPaint.getAlpha() == 0 && origPaint.getXfermode() == NULL)) {
+ bitmap.getConfig() == SkBitmap::kNo_Config) {
return;
}
@@ -1112,7 +1153,7 @@ void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
return;
}
- if (clipped_out(matrix, *fClip, bitmap.width(), bitmap.height())) {
+ if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) {
return;
}
@@ -1135,31 +1176,22 @@ void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
if (bitmap.getConfig() != SkBitmap::kA8_Config &&
just_translate(matrix, bitmap)) {
- int ix = SkScalarRound(matrix.getTranslateX());
- int iy = SkScalarRound(matrix.getTranslateY());
- uint32_t storage[kBlitterStorageLongCount];
- SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
- ix, iy, storage, sizeof(storage));
- if (blitter) {
- SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage);
-
- SkIRect ir;
- ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
-
- SkRegion::Cliperator iter(*fClip, ir);
- const SkIRect& cr = iter.rect();
-
- for (; !iter.done(); iter.next()) {
- SkASSERT(!cr.isEmpty());
- blitter->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
+ int ix = SkScalarRound(matrix.getTranslateX());
+ int iy = SkScalarRound(matrix.getTranslateY());
+ if (clipHandlesSprite(*fRC, ix, iy, bitmap)) {
+ uint32_t storage[kBlitterStorageLongCount];
+ SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
+ ix, iy, storage, sizeof(storage));
+ if (blitter) {
+ SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage);
+
+ SkIRect ir;
+ ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
+
+ SkScan::FillIRect(ir, *fRC, blitter);
+ return;
}
- return;
}
-#if 0
- SkDebugf("---- MISSING sprite case: config=%d [%d %d], device=%d, xfer=%p, alpha=0x%X colorFilter=%p\n",
- bitmap.config(), bitmap.width(), bitmap.height(), fBitmap->config(),
- paint.getXfermode(), paint.getAlpha(), paint.getColorFilter());
-#endif
}
// now make a temp draw on the stack, and use it
@@ -1185,24 +1217,23 @@ void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y,
SkDEBUGCODE(this->validate();)
// nothing to draw
- if (fClip->isEmpty() ||
+ if (fRC->isEmpty() ||
bitmap.width() == 0 || bitmap.height() == 0 ||
- bitmap.getConfig() == SkBitmap::kNo_Config ||
- (origPaint.getAlpha() == 0 && origPaint.getXfermode() == NULL)) {
+ bitmap.getConfig() == SkBitmap::kNo_Config) {
return;
}
SkIRect bounds;
bounds.set(x, y, x + bitmap.width(), y + bitmap.height());
- if (fClip->quickReject(bounds)) {
+ if (fRC->quickReject(bounds)) {
return; // nothing to draw
}
SkPaint paint(origPaint);
paint.setStyle(SkPaint::kFill_Style);
- if (NULL == paint.getColorFilter()) {
+ if (NULL == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, bitmap)) {
uint32_t storage[kBlitterStorageLongCount];
SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
x, y, storage, sizeof(storage));
@@ -1214,13 +1245,7 @@ void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y,
return;
}
- SkRegion::Cliperator iter(*fClip, bounds);
- const SkIRect& cr = iter.rect();
-
- for (; !iter.done(); iter.next()) {
- SkASSERT(!cr.isEmpty());
- blitter->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
- }
+ SkScan::FillIRect(bounds, *fRC, blitter);
return;
}
}
@@ -1298,47 +1323,6 @@ void SkDraw::drawText_asPaths(const char text[], size_t byteLength,
}
}
-static void draw_paint_rect(const 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(const SkDraw* draw, const SkPaint& paint,
- SkScalar width, const SkPoint& start) {
- uint32_t flags = paint.getFlags();
-
- if (flags & (SkPaint::kUnderlineText_Flag |
- SkPaint::kStrikeThruText_Flag)) {
- 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_Flag) {
- SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
- start.fY);
- r.fTop = offset;
- r.fBottom = offset + height;
- draw_paint_rect(draw, paint, r, textSize);
- }
- if (flags & SkPaint::kStrikeThruText_Flag) {
- SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
- start.fY);
- r.fTop = offset;
- r.fBottom = offset + height;
- draw_paint_rect(draw, paint, r, textSize);
- }
- }
-}
-
// disable warning : local variable used without having been initialized
#if defined _WIN32 && _MSC_VER >= 1300
#pragma warning ( push )
@@ -1353,9 +1337,9 @@ static void D1G_NoBounder_RectClip(const SkDraw1Glyph& state,
int left = SkFixedFloor(fx);
int top = SkFixedFloor(fy);
SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
- SkASSERT(state.fClip->isRect());
- SkASSERT(NULL == state.fBounder);
- SkASSERT(state.fClipBounds == state.fClip->getBounds());
+ SkASSERT(NULL == state.fBounder);
+ SkASSERT((NULL == state.fClip && state.fAAClip) ||
+ (state.fClip && NULL == state.fAAClip && state.fClip->isRect()));
left += glyph.fLeft;
top += glyph.fTop;
@@ -1363,42 +1347,42 @@ static void D1G_NoBounder_RectClip(const SkDraw1Glyph& state,
int right = left + glyph.fWidth;
int bottom = top + glyph.fHeight;
- SkMask mask;
- SkIRect storage;
- SkIRect* bounds = &mask.fBounds;
-
- mask.fBounds.set(left, top, right, bottom);
-
- // this extra test is worth it, assuming that most of the time it succeeds
- // since we can avoid writing to storage
- if (!state.fClipBounds.containsNoEmptyCheck(left, top, right, bottom)) {
- if (!storage.intersectNoEmptyCheck(mask.fBounds, state.fClipBounds))
- return;
- bounds = &storage;
- }
-
- uint8_t* aa = (uint8_t*)glyph.fImage;
- if (NULL == aa) {
- aa = (uint8_t*)state.fCache->findImage(glyph);
- if (NULL == aa) {
- return; // can't rasterize glyph
+ SkMask mask;
+ SkIRect storage;
+ SkIRect* bounds = &mask.fBounds;
+
+ mask.fBounds.set(left, top, right, bottom);
+
+ // this extra test is worth it, assuming that most of the time it succeeds
+ // since we can avoid writing to storage
+ if (!state.fClipBounds.containsNoEmptyCheck(left, top, right, bottom)) {
+ if (!storage.intersectNoEmptyCheck(mask.fBounds, state.fClipBounds))
+ return;
+ bounds = &storage;
+ }
+
+ uint8_t* aa = (uint8_t*)glyph.fImage;
+ if (NULL == aa) {
+ aa = (uint8_t*)state.fCache->findImage(glyph);
+ if (NULL == aa) {
+ return; // can't rasterize glyph
}
- }
+ }
- mask.fRowBytes = glyph.rowBytes();
- mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
- mask.fImage = aa;
- state.fBlitter->blitMask(mask, *bounds);
+ mask.fRowBytes = glyph.rowBytes();
+ mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
+ mask.fImage = aa;
+ state.fBlitter->blitMask(mask, *bounds);
}
static void D1G_NoBounder_RgnClip(const SkDraw1Glyph& state,
SkFixed fx, SkFixed fy,
- const SkGlyph& glyph) {
+ const SkGlyph& glyph) {
int left = SkFixedFloor(fx);
int top = SkFixedFloor(fy);
SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
- SkASSERT(!state.fClip->isRect());
- SkASSERT(NULL == state.fBounder);
+ SkASSERT(!state.fClip->isRect());
+ SkASSERT(NULL == state.fBounder);
SkMask mask;
@@ -1406,67 +1390,80 @@ static void D1G_NoBounder_RgnClip(const SkDraw1Glyph& state,
top += glyph.fTop;
mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
- SkRegion::Cliperator clipper(*state.fClip, mask.fBounds);
-
- if (!clipper.done()) {
- const SkIRect& cr = clipper.rect();
- const uint8_t* aa = (const uint8_t*)glyph.fImage;
- if (NULL == aa) {
- aa = (uint8_t*)state.fCache->findImage(glyph);
- if (NULL == aa) {
- return;
+ SkRegion::Cliperator clipper(*state.fClip, mask.fBounds);
+
+ if (!clipper.done()) {
+ const SkIRect& cr = clipper.rect();
+ const uint8_t* aa = (const uint8_t*)glyph.fImage;
+ if (NULL == aa) {
+ aa = (uint8_t*)state.fCache->findImage(glyph);
+ if (NULL == aa) {
+ return;
}
- }
+ }
- mask.fRowBytes = glyph.rowBytes();
- mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
- mask.fImage = (uint8_t*)aa;
- do {
- state.fBlitter->blitMask(mask, cr);
- clipper.next();
- } while (!clipper.done());
- }
+ mask.fRowBytes = glyph.rowBytes();
+ mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
+ mask.fImage = (uint8_t*)aa;
+ do {
+ state.fBlitter->blitMask(mask, cr);
+ clipper.next();
+ } while (!clipper.done());
+ }
}
static void D1G_Bounder(const SkDraw1Glyph& state,
SkFixed fx, SkFixed fy,
- const SkGlyph& glyph) {
+ const SkGlyph& glyph) {
int left = SkFixedFloor(fx);
int top = SkFixedFloor(fy);
SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
-
+
SkMask mask;
-
+
left += glyph.fLeft;
top += glyph.fTop;
-
+
mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
SkRegion::Cliperator clipper(*state.fClip, mask.fBounds);
-
- if (!clipper.done()) {
- const SkIRect& cr = clipper.rect();
- const uint8_t* aa = (const uint8_t*)glyph.fImage;
- if (NULL == aa) {
- aa = (uint8_t*)state.fCache->findImage(glyph);
- if (NULL == aa) {
- return;
+
+ if (!clipper.done()) {
+ const SkIRect& cr = clipper.rect();
+ const uint8_t* aa = (const uint8_t*)glyph.fImage;
+ if (NULL == aa) {
+ aa = (uint8_t*)state.fCache->findImage(glyph);
+ if (NULL == aa) {
+ return;
}
- }
-
+ }
+
// we need to pass the origin, which we approximate with our
// (unadjusted) left,top coordinates (the caller called fixedfloor)
- if (state.fBounder->doIRectGlyph(cr,
+ if (state.fBounder->doIRectGlyph(cr,
left - glyph.fLeft,
top - glyph.fTop, glyph)) {
- mask.fRowBytes = glyph.rowBytes();
- mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
- mask.fImage = (uint8_t*)aa;
- do {
- state.fBlitter->blitMask(mask, cr);
- clipper.next();
- } while (!clipper.done());
- }
- }
+ mask.fRowBytes = glyph.rowBytes();
+ mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
+ mask.fImage = (uint8_t*)aa;
+ do {
+ state.fBlitter->blitMask(mask, cr);
+ clipper.next();
+ } while (!clipper.done());
+ }
+ }
+}
+
+static void D1G_Bounder_AAClip(const SkDraw1Glyph& state,
+ SkFixed fx, SkFixed fy,
+ const SkGlyph& glyph) {
+ int left = SkFixedFloor(fx);
+ int top = SkFixedFloor(fy);
+ SkIRect bounds;
+ bounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
+
+ if (state.fBounder->doIRectGlyph(bounds, left, top, glyph)) {
+ D1G_NoBounder_RectClip(state, fx, fy, glyph);
+ }
}
static bool hasCustomD1GProc(const SkDraw& draw) {
@@ -1481,41 +1478,38 @@ SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter,
SkGlyphCache* cache) {
fDraw = draw;
fBounder = draw->fBounder;
- fClip = draw->fClip;
- fClipBounds = fClip->getBounds();
fBlitter = blitter;
fCache = cache;
if (hasCustomD1GProc(*draw)) {
+ // todo: fix this assumption about clips w/ custom
+ fClip = draw->fClip;
+ fClipBounds = fClip->getBounds();
return draw->fProcs->fD1GProc;
}
- if (NULL == fBounder) {
- if (fClip->isRect()) {
+ if (draw->fRC->isBW()) {
+ fAAClip = NULL;
+ fClip = &draw->fRC->bwRgn();
+ fClipBounds = fClip->getBounds();
+ if (NULL == fBounder) {
+ if (fClip->isRect()) {
+ return D1G_NoBounder_RectClip;
+ } else {
+ return D1G_NoBounder_RgnClip;
+ }
+ } else {
+ return D1G_Bounder;
+ }
+ } else { // aaclip
+ fAAClip = &draw->fRC->aaRgn();
+ fClip = NULL;
+ fClipBounds = fAAClip->getBounds();
+ if (NULL == fBounder) {
return D1G_NoBounder_RectClip;
} else {
- return D1G_NoBounder_RgnClip;
+ return D1G_Bounder_AAClip;
}
- } else {
- return D1G_Bounder;
- }
-}
-
-enum RoundBaseline {
- kDont_Round_Baseline,
- kRound_X_Baseline,
- kRound_Y_Baseline
-};
-
-static RoundBaseline computeRoundBaseline(const SkMatrix& mat) {
- if (mat[1] == 0 && mat[3] == 0) {
- // we're 0 or 180 degrees, round the y coordinate of the baseline
- return kRound_Y_Baseline;
- } else if (mat[0] == 0 && mat[4] == 0) {
- // we're 90 or 270 degrees, round the x coordinate of the baseline
- return kRound_X_Baseline;
- } else {
- return kDont_Round_Baseline;
}
}
@@ -1528,46 +1522,24 @@ void SkDraw::drawText(const char text[], size_t byteLength,
SkDEBUGCODE(this->validate();)
// nothing to draw
- if (text == NULL || byteLength == 0 ||
- fClip->isEmpty() ||
- (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
+ if (text == NULL || byteLength == 0 || fRC->isEmpty()) {
return;
}
- SkScalar underlineWidth = 0;
- SkPoint underlineStart;
-
- underlineStart.set(0, 0); // to avoid warning
- if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
- SkPaint::kStrikeThruText_Flag)) {
- underlineWidth = paint.measureText(text, byteLength);
-
- 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.isLinearText() ||*/
(fMatrix->hasPerspective())) {
this->drawText_asPaths(text, byteLength, x, y, paint);
- handle_aftertext(this, paint, underlineWidth, underlineStart);
return;
}
SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc();
const SkMatrix* matrix = fMatrix;
- SkFixed finalFYMask = ~0xFFFF; // trunc fy;
if (hasCustomD1GProc(*this)) {
// only support the fMVMatrix (for now) for the GPU case, which also
// sets the fD1GProc
if (fMVMatrix) {
matrix = fMVMatrix;
- finalFYMask = ~0; // don't truncate
}
}
@@ -1606,27 +1578,32 @@ void SkDraw::drawText(const char text[], size_t byteLength,
SkFixed fxMask = ~0;
SkFixed fyMask = ~0;
if (paint.isSubpixelText()) {
- RoundBaseline roundBaseline = computeRoundBaseline(*matrix);
- if (kRound_Y_Baseline == roundBaseline) {
+ SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*matrix);
+ if (kX_SkAxisAlignment == baseline) {
fyMask = 0;
-// fy = (fy + 0x8000) & ~0xFFFF;
- } else if (kRound_X_Baseline == roundBaseline) {
+ } else if (kY_SkAxisAlignment == baseline) {
fxMask = 0;
}
}
// apply the bias here, so we don't have to add 1/2 in the loop
fx += SK_FixedHalf;
fy += SK_FixedHalf;
- fyMask &= finalFYMask;
- SkAutoBlitterChoose blitter;
+ SkAAClipBlitter aaBlitter;
+ SkAutoBlitterChoose blitterChooser;
+ SkBlitter* blitter = NULL;
if (needsRasterTextBlit(*this)) {
- blitter.choose(*fBitmap, *matrix, paint);
+ blitterChooser.choose(*fBitmap, *matrix, paint);
+ blitter = blitterChooser.get();
+ if (fRC->isAA()) {
+ aaBlitter.init(blitter, &fRC->aaRgn());
+ blitter = &aaBlitter;
+ }
}
SkAutoKern autokern;
- SkDraw1Glyph d1g;
- SkDraw1Glyph::Proc proc = d1g.init(this, blitter.get(), cache);
+ SkDraw1Glyph d1g;
+ SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache);
while (text < stop) {
const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
@@ -1634,16 +1611,11 @@ void SkDraw::drawText(const char text[], size_t byteLength,
fx += autokern.adjust(glyph);
if (glyph.fWidth) {
- proc(d1g, fx, fy, glyph);
+ proc(d1g, fx, fy, glyph);
}
fx += glyph.fAdvanceX;
fy += glyph.fAdvanceY;
}
-
- if (underlineWidth) {
- autoCache.release(); // release this now to free up the RAM
- handle_aftertext(this, paint, underlineWidth, underlineStart);
- }
}
// last parameter is interpreted as SkFixed [x, y]
@@ -1747,9 +1719,7 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
SkDEBUGCODE(this->validate();)
// nothing to draw
- if (text == NULL || byteLength == 0 ||
- fClip->isEmpty() ||
- (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
+ if (text == NULL || byteLength == 0 || fRC->isEmpty()) {
return;
}
@@ -1773,21 +1743,28 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
SkAutoGlyphCache autoCache(paint, matrix);
SkGlyphCache* cache = autoCache.getCache();
- SkAutoBlitterChoose blitter;
+ SkAAClipBlitterWrapper wrapper;
+ SkAutoBlitterChoose blitterChooser;
+ SkBlitter* blitter = NULL;
if (needsRasterTextBlit(*this)) {
- blitter.choose(*fBitmap, *matrix, paint);
+ blitterChooser.choose(*fBitmap, *matrix, paint);
+ blitter = blitterChooser.get();
+ if (fRC->isAA()) {
+ wrapper.init(*fRC, blitter);
+ blitter = wrapper.getBlitter();
+ }
}
const char* stop = text + byteLength;
AlignProc alignProc = pick_align_proc(paint.getTextAlign());
SkDraw1Glyph d1g;
- SkDraw1Glyph::Proc proc = d1g.init(this, blitter.get(), cache);
+ SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache);
TextMapState tms(*matrix, constY);
TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition);
if (paint.isSubpixelText()) {
// maybe we should skip the rounding if linearText is set
- RoundBaseline roundBaseline = computeRoundBaseline(*matrix);
+ SkAxisAlignment roundBaseline = SkComputeAxisAlignmentForHText(*matrix);
if (SkPaint::kLeft_Align == paint.getTextAlign()) {
while (text < stop) {
@@ -1799,9 +1776,9 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
SkFixed fxMask = ~0;
SkFixed fyMask = ~0;
- if (kRound_Y_Baseline == roundBaseline) {
+ if (kX_SkAxisAlignment == roundBaseline) {
fyMask = 0;
- } else if (kRound_X_Baseline == roundBaseline) {
+ } else if (kY_SkAxisAlignment == roundBaseline) {
fxMask = 0;
}
@@ -1815,6 +1792,7 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
}
} else {
while (text < stop) {
+ const char* currentText = text;
const SkGlyph* glyph = &glyphCacheProc(cache, &text, 0, 0);
if (glyph->fWidth) {
@@ -1832,15 +1810,16 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
fx = fixedLoc.fX;
fy = fixedLoc.fY;
- if (kRound_Y_Baseline == roundBaseline) {
+ if (kX_SkAxisAlignment == roundBaseline) {
fyMask = 0;
- } else if (kRound_X_Baseline == roundBaseline) {
+ } else if (kY_SkAxisAlignment == roundBaseline) {
fxMask = 0;
}
}
// have to call again, now that we've been "aligned"
- glyph = &glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
+ glyph = &glyphCacheProc(cache, &currentText,
+ fx & fxMask, fy & fyMask);
// the assumption is that the advance hasn't changed
SkASSERT(prevAdvX == glyph->fAdvanceX);
SkASSERT(prevAdvY == glyph->fAdvanceY);
@@ -1943,7 +1922,7 @@ static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas,
dst->close();
break;
default:
- SkASSERT(!"unknown verb");
+ SkDEBUGFAIL("unknown verb");
break;
}
}
@@ -1955,9 +1934,7 @@ void SkDraw::drawTextOnPath(const char text[], size_t byteLength,
SkASSERT(byteLength == 0 || text != NULL);
// nothing to draw
- if (text == NULL || byteLength == 0 ||
- fClip->isEmpty() ||
- (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
+ if (text == NULL || byteLength == 0 || fRC->isEmpty()) {
return;
}
@@ -1998,13 +1975,12 @@ void SkDraw::drawTextOnPath(const char text[], size_t byteLength,
}
}
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
void SkDraw::drawPosTextOnPath(const char text[], size_t byteLength,
const SkPoint pos[], const SkPaint& paint,
const SkPath& path, const SkMatrix* matrix) const {
// nothing to draw
- if (text == NULL || byteLength == 0 || fClip->isEmpty() ||
- (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
+ if (text == NULL || byteLength == 0 || fRC->isEmpty()) {
return;
}
@@ -2191,7 +2167,7 @@ VertState::Proc VertState::chooseProc(SkCanvas::VertexMode mode) {
}
}
-typedef void (*HairProc)(const SkPoint&, const SkPoint&, const SkRegion*,
+typedef void (*HairProc)(const SkPoint&, const SkPoint&, const SkRasterClip&,
SkBlitter*);
static HairProc ChooseHairProc(bool doAntiAlias) {
@@ -2302,8 +2278,7 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
SkASSERT(0 == count || NULL != vertices);
// abort early if there is nothing to draw
- if (count < 3 || (indices && indexCount < 3) || fClip->isEmpty() ||
- (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
+ if (count < 3 || (indices && indexCount < 3) || fRC->isEmpty()) {
return;
}
@@ -2400,8 +2375,11 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
continue;
}
}
- SkScan::FillTriangle(devVerts[state.f0], devVerts[state.f1],
- devVerts[state.f2], fClip, blitter.get());
+
+ SkPoint tmp[] = {
+ devVerts[state.f0], devVerts[state.f1], devVerts[state.f2]
+ };
+ SkScan::FillTriangle(tmp, *fRC, blitter.get());
}
// now restore the shader's original local matrix
if (NULL != shader) {
@@ -2414,10 +2392,11 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
} else {
// no colors[] and no texture
HairProc hairProc = ChooseHairProc(paint.isAntiAlias());
+ const SkRasterClip& clip = *fRC;
while (vertProc(&state)) {
- hairProc(devVerts[state.f0], devVerts[state.f1], fClip, blitter.get());
- hairProc(devVerts[state.f1], devVerts[state.f2], fClip, blitter.get());
- hairProc(devVerts[state.f2], devVerts[state.f0], fClip, blitter.get());
+ hairProc(devVerts[state.f0], devVerts[state.f1], clip, blitter.get());
+ hairProc(devVerts[state.f1], devVerts[state.f2], clip, blitter.get());
+ hairProc(devVerts[state.f2], devVerts[state.f0], clip, blitter.get());
}
}
}
@@ -2431,8 +2410,9 @@ void SkDraw::validate() const {
SkASSERT(fBitmap != NULL);
SkASSERT(fMatrix != NULL);
SkASSERT(fClip != NULL);
+ SkASSERT(fRC != NULL);
- const SkIRect& cr = fClip->getBounds();
+ const SkIRect& cr = fRC->getBounds();
SkIRect br;
br.set(0, 0, fBitmap->width(), fBitmap->height());
@@ -2549,9 +2529,6 @@ static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
return false;
}
- SkIPoint margin;
- margin.set(0, 0);
-
// init our bounds from the path
{
SkRect pathBounds = devPath.getBounds();
@@ -2559,10 +2536,11 @@ static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
pathBounds.roundOut(bounds);
}
+ SkIPoint margin;
if (filter) {
SkASSERT(filterMatrix);
- SkMask srcM, dstM;
+ SkMask srcM, dstM;
srcM.fBounds = *bounds;
srcM.fFormat = SkMask::kA8_Format;
@@ -2570,18 +2548,12 @@ static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) {
return false;
}
- *bounds = dstM.fBounds;
- }
-
- if (clipBounds && !SkIRect::Intersects(*clipBounds, *bounds)) {
- return false;
}
- // (possibly) trim the srcM bounds to reflect the clip
+ // (possibly) trim the bounds to reflect the clip
// (plus whatever slop the filter needs)
- if (clipBounds && !clipBounds->contains(*bounds)) {
- SkIRect tmp = *bounds;
- (void)tmp.intersect(*clipBounds);
+ if (clipBounds) {
+ SkIRect tmp = *clipBounds;
// Ugh. Guard against gigantic margins from wacky filters. Without this
// check we can request arbitrary amounts of slop beyond our visible
// clip, and bring down the renderer (at least on finite RAM machines
@@ -2591,28 +2563,31 @@ static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
static const int MAX_MARGIN = 128;
tmp.inset(-SkMin32(margin.fX, MAX_MARGIN),
-SkMin32(margin.fY, MAX_MARGIN));
- (void)bounds->intersect(tmp);
+ if (!bounds->intersect(tmp)) {
+ return false;
+ }
}
return true;
}
static void draw_into_mask(const SkMask& mask, const SkPath& devPath) {
- SkBitmap bm;
- SkDraw draw;
- SkRegion clipRgn;
- SkMatrix matrix;
- SkPaint paint;
+ SkBitmap bm;
+ SkDraw draw;
+ SkRasterClip clip;
+ 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());
+ clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height()));
matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
-SkIntToScalar(mask.fBounds.fTop));
draw.fBitmap = &bm;
- draw.fClip = &clipRgn;
+ draw.fRC = &clip;
+ draw.fClip = &clip.bwRgn();
draw.fMatrix = &matrix;
draw.fBounder = NULL;
paint.setAntiAlias(true);
diff --git a/src/core/SkDrawProcs.h b/src/core/SkDrawProcs.h
index 7d69465..74aa9bb 100644
--- a/src/core/SkDrawProcs.h
+++ b/src/core/SkDrawProcs.h
@@ -1,14 +1,23 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkDrawProcs_DEFINED
#define SkDrawProcs_DEFINED
#include "SkDraw.h"
+class SkAAClip;
class SkBlitter;
struct SkDraw1Glyph {
const SkDraw* fDraw;
SkBounder* fBounder;
const SkRegion* fClip;
+ const SkAAClip* fAAClip;
SkBlitter* fBlitter;
SkGlyphCache* fCache;
SkIRect fClipBounds;
@@ -24,5 +33,14 @@ struct SkDrawProcs {
SkDraw1Glyph::Proc fD1GProc;
};
+/**
+ * If the current paint is set to stroke, has a compatible xfermode, and the
+ * stroke-width when applied to the matrix is <= 1.0, then this returns true,
+ * and sets newAlpha (simulating a stroke by drawing a hairline + newAlpha).
+ * If any of these conditions are false, then this returns false and modulate
+ * is ignored.
+ */
+bool SkDrawTreatAsHairline(const SkPaint&, const SkMatrix&, SkAlpha* newAlpha);
+
#endif
diff --git a/src/core/SkDrawing.cpp b/src/core/SkDrawing.cpp
deleted file mode 100644
index f54afcc..0000000
--- a/src/core/SkDrawing.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-#include "SkDrawing.h"
-#include "SkCanvas.h"
-
-SkDrawing::SkDrawing() {
- fMatrix.reset();
- fParent = fFirstChild = fNextSibling = fPrevSibling = NULL;
-}
-
-SkDrawing::~SkDrawing() {
- this->detachAllChildren();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-void SkDrawing::resetMatrix() {
- fMatrix.reset();
-}
-
-void SkDrawing::getMatrix(SkMatrix* matrix) const {
- if (matrix) {
- *matrix = fMatrix;
- }
-}
-
-void SkDrawing::setMatrix(const SkMatrix& matrix) {
- if (fMatrix != matrix) {
- this->inval();
- fMatrix = matrix;
- this->inval();
- }
-}
-
-void SkDrawing::draw(SkCanvas* canvas) {
- SkAutoCanvasRestore ar(canvas, false);
- canvas->save(SkCanvas::kMatrix_SaveFlag);
- canvas->concat(fMatrix);
-
- this->onDraw(canvas);
-
- B2FIter iter(this);
- SkDrawing* child;
- while ((child = iter.next()) != NULL) {
- child->draw(canvas);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-void SkDrawing::detachFromParent() {
- SkDrawing* parent = fParent;
-
- if (NULL == parent) {
- return;
- }
-
- this->inval();
-
- SkDrawing* next = NULL;
-
- if (fNextSibling != this) { // do we have any siblings
- fNextSibling->fPrevSibling = fPrevSibling;
- fPrevSibling->fNextSibling = fNextSibling;
- next = fNextSibling;
- }
-
- if (fParent->fFirstChild == this) {
- fParent->fFirstChild = next;
- }
-
- fParent = fNextSibling = fPrevSibling = NULL;
- this->unref();
-}
-
-SkDrawing* SkDrawing::attachChildToBack(SkDrawing* child) {
- SkASSERT(child != this);
-
- if (child == NULL || fFirstChild == child) {
- return child;
- }
-
- child->ref();
- child->detachFromParent();
-
- if (fFirstChild == NULL) {
- child->fNextSibling = child;
- child->fPrevSibling = child;
- } else {
- child->fNextSibling = fFirstChild;
- child->fPrevSibling = fFirstChild->fPrevSibling;
- fFirstChild->fPrevSibling->fNextSibling = child;
- fFirstChild->fPrevSibling = child;
- }
-
- fFirstChild = child;
- child->fParent = this;
- child->inval();
- return child;
-}
-
-SkDrawing* SkDrawing::attachChildToFront(SkDrawing* child) {
- SkASSERT(child != this);
-
- if (child == NULL || fFirstChild && fFirstChild->fPrevSibling == child) {
- return child;
- }
-
- child->ref();
- child->detachFromParent();
-
- if (fFirstChild == NULL) {
- fFirstChild = child;
- child->fNextSibling = child;
- child->fPrevSibling = child;
- } else {
- child->fNextSibling = fFirstChild;
- child->fPrevSibling = fFirstChild->fPrevSibling;
- fFirstChild->fPrevSibling->fNextSibling = child;
- fFirstChild->fPrevSibling = child;
- }
-
- child->fParent = this;
- child->inval();
- return child;
-}
-
-void SkDrawing::detachAllChildren() {
- while (fFirstChild) {
- fFirstChild->detachFromParent();
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-SkDrawing::B2FIter::B2FIter(const SkDrawing* parent) {
- fFirstChild = parent ? parent->fFirstChild : NULL;
- fChild = fFirstChild;
-}
-
-SkDrawing* SkDrawing::B2FIter::next() {
- SkDrawing* curr = fChild;
-
- if (fChild) {
- SkDrawing* next = fChild->fNextSibling;
- if (next == fFirstChild) {
- next = NULL;
- }
- fChild = next;
- }
- return curr;
-}
-
-
diff --git a/src/core/SkEdge.cpp b/src/core/SkEdge.cpp
index 80ba9e3..aab1c76 100644
--- a/src/core/SkEdge.cpp
+++ b/src/core/SkEdge.cpp
@@ -1,22 +1,15 @@
-/* libs/graphics/sgl/SkEdge.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkEdge.h"
#include "SkFDot6.h"
+#include "SkMath.h"
/*
In setLine, setQuadratic, setCubic, the first thing we do is to convert
diff --git a/src/core/SkEdge.h b/src/core/SkEdge.h
index eb50a42..29a50d1 100644
--- a/src/core/SkEdge.h
+++ b/src/core/SkEdge.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkEdge.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkEdge_DEFINED
#define SkEdge_DEFINED
diff --git a/src/core/SkEdgeBuilder.cpp b/src/core/SkEdgeBuilder.cpp
index 0f88488..01417e4 100644
--- a/src/core/SkEdgeBuilder.cpp
+++ b/src/core/SkEdgeBuilder.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkEdgeBuilder.h"
#include "SkPath.h"
#include "SkEdge.h"
@@ -111,7 +118,7 @@ int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip,
}
break;
default:
- SkASSERT(!"unexpected verb");
+ SkDEBUGFAIL("unexpected verb");
break;
}
}
@@ -143,7 +150,7 @@ int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip,
break;
}
default:
- SkASSERT(!"unexpected verb");
+ SkDEBUGFAIL("unexpected verb");
break;
}
}
diff --git a/src/core/SkEdgeBuilder.h b/src/core/SkEdgeBuilder.h
index 767735f..ae21f05 100644
--- a/src/core/SkEdgeBuilder.h
+++ b/src/core/SkEdgeBuilder.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkEdgeBuilder_DEFINED
#define SkEdgeBuilder_DEFINED
diff --git a/src/core/SkEdgeClipper.cpp b/src/core/SkEdgeClipper.cpp
index a265d9f..d77f6f8 100644
--- a/src/core/SkEdgeClipper.cpp
+++ b/src/core/SkEdgeClipper.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2009 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkEdgeClipper.h"
#include "SkGeometry.h"
@@ -273,20 +266,21 @@ static bool chopMonoCubicAtX(SkPoint pts[4], SkScalar x, SkScalar* t) {
// Modify pts[] in place so that it is clipped in Y to the clip rect
static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) {
- SkScalar t;
- SkPoint tmp[7]; // for SkChopCubicAt
// are we partially above
if (pts[0].fY < clip.fTop) {
+ SkScalar t;
if (chopMonoCubicAtY(pts, clip.fTop, &t)) {
+ SkPoint tmp[7];
SkChopCubicAt(pts, tmp, t);
- // given the imprecision of computing t, we just slam our Y coord
- // to the top of the clip. This also saves us in the bad case where
- // the t was soooo bad that the entire segment could have been
- // below fBottom
+
+ // tmp[3, 4, 5].fY should all be to the below clip.fTop, and
+ // still be monotonic in Y. Since we can't trust the numerics of
+ // the chopper, we force those conditions now
tmp[3].fY = clip.fTop;
- clamp_ge(tmp[4].fY, clip.fTop);
- clamp_ge(tmp[5].fY, clip.fTop);
+ tmp[4].fY = SkMaxScalar(tmp[4].fY, clip.fTop);
+ tmp[5].fY = SkMaxScalar(tmp[5].fY, tmp[4].fY);
+
pts[0] = tmp[3];
pts[1] = tmp[4];
pts[2] = tmp[5];
@@ -301,7 +295,9 @@ static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) {
// are we partially below
if (pts[3].fY > clip.fBottom) {
+ SkScalar t;
if (chopMonoCubicAtY(pts, clip.fBottom, &t)) {
+ SkPoint tmp[7];
SkChopCubicAt(pts, tmp, t);
clamp_le(tmp[1].fY, clip.fBottom);
clamp_le(tmp[2].fY, clip.fBottom);
@@ -348,18 +344,22 @@ void SkEdgeClipper::clipMonoCubic(const SkPoint src[4], const SkRect& clip) {
this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
return;
}
-
- SkScalar t;
- SkPoint tmp[7];
-
+
// are we partially to the left
if (pts[0].fX < clip.fLeft) {
+ SkScalar t;
if (chopMonoCubicAtX(pts, clip.fLeft, &t)) {
+ SkPoint tmp[7];
SkChopCubicAt(pts, tmp, t);
this->appendVLine(clip.fLeft, tmp[0].fY, tmp[3].fY, reverse);
- clamp_ge(tmp[3].fX, clip.fLeft);
- clamp_ge(tmp[4].fX, clip.fLeft);
- clamp_ge(tmp[5].fX, clip.fLeft);
+
+ // tmp[3, 4, 5].fX should all be to the right of clip.fLeft, and
+ // still be monotonic in X. Since we can't trust the numerics of
+ // the chopper, we force those conditions now
+ tmp[3].fX = clip.fLeft;
+ tmp[4].fX = SkMaxScalar(tmp[4].fX, clip.fLeft);
+ tmp[5].fX = SkMaxScalar(tmp[5].fX, tmp[4].fX);
+
pts[0] = tmp[3];
pts[1] = tmp[4];
pts[2] = tmp[5];
@@ -373,7 +373,9 @@ void SkEdgeClipper::clipMonoCubic(const SkPoint src[4], const SkRect& clip) {
// are we partially to the right
if (pts[3].fX > clip.fRight) {
+ SkScalar t;
if (chopMonoCubicAtX(pts, clip.fRight, &t)) {
+ SkPoint tmp[7];
SkChopCubicAt(pts, tmp, t);
clamp_le(tmp[1].fX, clip.fRight);
clamp_le(tmp[2].fX, clip.fRight);
@@ -483,7 +485,7 @@ SkPath::Verb SkEdgeClipper::next(SkPoint pts[]) {
case SkPath::kDone_Verb:
break;
default:
- SkASSERT(!"unexpected verb in quadclippper2 iter");
+ SkDEBUGFAIL("unexpected verb in quadclippper2 iter");
break;
}
return verb;
diff --git a/src/core/SkFP.h b/src/core/SkFP.h
index 3aab411..1d1507a 100644
--- a/src/core/SkFP.h
+++ b/src/core/SkFP.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkFP.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkFP_DEFINED
#define SkFP_DEFINED
diff --git a/src/core/SkFilterProc.cpp b/src/core/SkFilterProc.cpp
index 7f1e7a1..8c24bb6 100644
--- a/src/core/SkFilterProc.cpp
+++ b/src/core/SkFilterProc.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkFilterProc.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkFilterProc.h"
diff --git a/src/core/SkFilterProc.h b/src/core/SkFilterProc.h
index 9af4ed5..2b515e2 100644
--- a/src/core/SkFilterProc.h
+++ b/src/core/SkFilterProc.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006-2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkFilter_DEFINED
#define SkFilter_DEFINED
diff --git a/src/core/SkFlate.cpp b/src/core/SkFlate.cpp
index 99b331e..a5e15d1 100644
--- a/src/core/SkFlate.cpp
+++ b/src/core/SkFlate.cpp
@@ -1,35 +1,27 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2010 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
+#include "SkData.h"
#include "SkFlate.h"
#include "SkStream.h"
#ifndef SK_ZLIB_INCLUDE
bool SkFlate::HaveFlate() { return false; }
-bool SkFlate::Deflate(SkStream*, SkDynamicMemoryWStream*) { return false; }
-bool SkFlate::Inflate(SkStream*, SkDynamicMemoryWStream*) { return false; }
+bool SkFlate::Deflate(SkStream*, SkWStream*) { return false; }
+bool SkFlate::Deflate(const void*, size_t, SkWStream*) { return false; }
+bool SkFlate::Deflate(const SkData*, SkWStream*) { return false; }
+bool SkFlate::Inflate(SkStream*, SkWStream*) { return false; }
#else
// static
bool SkFlate::HaveFlate() {
-#ifdef SK_DEBUG
- return false;
-#else
return true;
-#endif
}
namespace {
@@ -39,7 +31,7 @@ namespace {
// static
const size_t kBufferSize = 1024;
-bool doFlate(bool compress, SkStream* src, SkDynamicMemoryWStream* dst) {
+bool doFlate(bool compress, SkStream* src, SkWStream* dst) {
uint8_t inputBuffer[kBufferSize];
uint8_t outputBuffer[kBufferSize];
z_stream flateData;
@@ -119,12 +111,25 @@ bool doFlate(bool compress, SkStream* src, SkDynamicMemoryWStream* dst) {
}
// static
-bool SkFlate::Deflate(SkStream* src, SkDynamicMemoryWStream* dst) {
+bool SkFlate::Deflate(SkStream* src, SkWStream* dst) {
return doFlate(true, src, dst);
}
+bool SkFlate::Deflate(const void* ptr, size_t len, SkWStream* dst) {
+ SkMemoryStream stream(ptr, len);
+ return doFlate(true, &stream, dst);
+}
+
+bool SkFlate::Deflate(const SkData* data, SkWStream* dst) {
+ if (data) {
+ SkMemoryStream stream(data->data(), data->size());
+ return doFlate(true, &stream, dst);
+ }
+ return false;
+}
+
// static
-bool SkFlate::Inflate(SkStream* src, SkDynamicMemoryWStream* dst) {
+bool SkFlate::Inflate(SkStream* src, SkWStream* dst) {
return doFlate(false, src, dst);
}
diff --git a/src/core/SkFlattenable.cpp b/src/core/SkFlattenable.cpp
index 99dd856..59a262a 100644
--- a/src/core/SkFlattenable.cpp
+++ b/src/core/SkFlattenable.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkFlattenable.h"
#include "SkTypeface.h"
@@ -48,6 +55,7 @@ SkFlattenableReadBuffer::SkFlattenableReadBuffer() {
fTFArray = NULL;
fTFCount = 0;
+ fFactoryTDArray = NULL;
fFactoryArray = NULL;
fFactoryCount = 0;
}
@@ -60,6 +68,7 @@ SkFlattenableReadBuffer::SkFlattenableReadBuffer(const void* data) :
fTFArray = NULL;
fTFCount = 0;
+ fFactoryTDArray = NULL;
fFactoryArray = NULL;
fFactoryCount = 0;
}
@@ -72,6 +81,7 @@ SkFlattenableReadBuffer::SkFlattenableReadBuffer(const void* data, size_t size)
fTFArray = NULL;
fTFCount = 0;
+ fFactoryTDArray = NULL;
fFactoryArray = NULL;
fFactoryCount = 0;
}
@@ -103,26 +113,48 @@ SkFlattenable* SkFlattenableReadBuffer::readFlattenable() {
SkFlattenable::Factory factory = NULL;
if (fFactoryCount > 0) {
- uint32_t index = this->readU32();
- if (index > 0) {
- index -= 1;
- SkASSERT(index < (unsigned)fFactoryCount);
- factory = fFactoryArray[index];
- // if we recorded an index, but failed to get a factory, we need
- // to skip the flattened data in the buffer
- if (NULL == factory) {
- uint32_t size = this->readU32();
- this->skip(size);
- // fall through and return NULL for the object
+ int32_t index = this->readU32();
+ if (0 == index) {
+ return NULL; // writer failed to give us the flattenable
+ }
+ index = -index; // we stored the negative of the index
+ index -= 1; // we stored the index-base-1
+ SkASSERT(index < fFactoryCount);
+ factory = fFactoryArray[index];
+ } else if (fFactoryTDArray) {
+ const int32_t* peek = (const int32_t*)this->peek();
+ if (*peek <= 0) {
+ int32_t index = this->readU32();
+ if (0 == index) {
+ return NULL; // writer failed to give us the flattenable
}
+ index = -index; // we stored the negative of the index
+ index -= 1; // we stored the index-base-1
+ factory = (*fFactoryTDArray)[index];
+ } else {
+ const char* name = this->readString();
+ factory = SkFlattenable::NameToFactory(name);
+ if (factory) {
+ SkASSERT(fFactoryTDArray->find(factory) < 0);
+ *fFactoryTDArray->append() = factory;
+ } else {
+// SkDebugf("can't find factory for [%s]\n", name);
+ }
+ // if we didn't find a factory, that's our failure, not the writer's,
+ // so we fall through, so we can skip the sizeRecorded data.
}
} else {
factory = (SkFlattenable::Factory)readFunctionPtr();
+ if (NULL == factory) {
+ return NULL; // writer failed to give us the flattenable
+ }
}
+ // if we get here, factory may still be null, but if that is the case, the
+ // failure was ours, not the writer.
SkFlattenable* obj = NULL;
+ uint32_t sizeRecorded = this->readU32();
if (factory) {
- uint32_t sizeRecorded = this->readU32();
uint32_t offset = this->offset();
obj = (*factory)(*this);
// check that we read the amount we expected
@@ -131,6 +163,9 @@ SkFlattenable* SkFlattenableReadBuffer::readFlattenable() {
// we could try to fix up the offset...
sk_throw();
}
+ } else {
+ // we must skip the remaining data
+ this->skip(sizeRecorded);
}
return obj;
}
@@ -189,28 +224,78 @@ void SkFlattenableWriteBuffer::writeRefCnt(SkRefCnt* obj) {
}
void SkFlattenableWriteBuffer::writeFlattenable(SkFlattenable* flattenable) {
+ /*
+ * If we have a factoryset, then the first 32bits tell us...
+ * 0: failure to write the flattenable
+ * <0: we store the negative of the (1-based) index
+ * >0: the length of the name
+ * If we don't have a factoryset, then the first "ptr" is either the
+ * factory, or null for failure.
+ *
+ * The distinction is important, since 0-index is 32bits (always), but a
+ * 0-functionptr might be 32 or 64 bits.
+ */
+
SkFlattenable::Factory factory = NULL;
if (flattenable) {
factory = flattenable->getFactory();
}
+ if (NULL == factory) {
+ if (fFactorySet) {
+ this->write32(0);
+ } else {
+ this->writeFunctionPtr(NULL);
+ }
+ return;
+ }
+ /*
+ * We can write 1 of 3 versions of the flattenable:
+ * 1. function-ptr : this is the fastest for the reader, but assumes that
+ * the writer and reader are in the same process.
+ * 2. index into fFactorySet : This is assumes the writer will later
+ * resolve the function-ptrs into strings for its reader. SkPicture
+ * does exactly this, by writing a table of names (matching the indices)
+ * up front in its serialized form.
+ * 3. names : Reuse fFactorySet to store indices, but only after we've
+ * written the name the first time. SkGPipe uses this technique, as it
+ * doesn't require the reader to be told to know the table of names
+ * up front.
+ */
if (fFactorySet) {
- this->write32(fFactorySet->add(factory));
+ if (this->inlineFactoryNames()) {
+ int index = fFactorySet->find(factory);
+ if (index) {
+ // we write the negative of the index, to distinguish it from
+ // the length of a string
+ this->write32(-index);
+ } else {
+ const char* name = SkFlattenable::FactoryToName(factory);
+ if (NULL == name) {
+ this->write32(0);
+ return;
+ }
+ this->writeString(name);
+ index = fFactorySet->add(factory);
+ }
+ } else {
+ // we write the negative of the index, to distinguish it from
+ // the length of a string
+ this->write32(-(int)fFactorySet->add(factory));
+ }
} else {
this->writeFunctionPtr((void*)factory);
}
- if (factory) {
- // make room for the size of the flatttened object
- (void)this->reserve(sizeof(uint32_t));
- // record the current size, so we can subtract after the object writes.
- uint32_t offset = this->size();
- // now flatten the object
- flattenable->flatten(*this);
- uint32_t objSize = this->size() - offset;
- // record the obj's size
- *this->peek32(offset - sizeof(uint32_t)) = objSize;
- }
+ // make room for the size of the flatttened object
+ (void)this->reserve(sizeof(uint32_t));
+ // record the current size, so we can subtract after the object writes.
+ uint32_t offset = this->size();
+ // now flatten the object
+ flattenable->flatten(*this);
+ uint32_t objSize = this->size() - offset;
+ // record the obj's size
+ *this->peek32(offset - sizeof(uint32_t)) = objSize;
}
void SkFlattenableWriteBuffer::writeFunctionPtr(void* proc) {
@@ -263,7 +348,20 @@ void SkFlattenable::Register(const char name[], Factory factory) {
gCount += 1;
}
+#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS && defined(SK_DEBUG)
+static void report_no_entries(const char* functionName) {
+ if (!gCount) {
+ SkDebugf("%s has no registered name/factory pairs."
+ " Call SkGraphics::Init() at process initialization time.",
+ functionName);
+ }
+}
+#endif
+
SkFlattenable::Factory SkFlattenable::NameToFactory(const char name[]) {
+#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS && defined(SK_DEBUG)
+ report_no_entries(__FUNCTION__);
+#endif
const Pair* pairs = gPairs;
for (int i = gCount - 1; i >= 0; --i) {
if (strcmp(pairs[i].fName, name) == 0) {
@@ -274,6 +372,9 @@ SkFlattenable::Factory SkFlattenable::NameToFactory(const char name[]) {
}
const char* SkFlattenable::FactoryToName(Factory fact) {
+#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS && defined(SK_DEBUG)
+ report_no_entries(__FUNCTION__);
+#endif
const Pair* pairs = gPairs;
for (int i = gCount - 1; i >= 0; --i) {
if (pairs[i].fFactory == fact) {
@@ -286,4 +387,3 @@ const char* SkFlattenable::FactoryToName(Factory fact) {
bool SkFlattenable::toDumpString(SkString* str) const {
return false;
}
-
diff --git a/src/core/SkFloat.cpp b/src/core/SkFloat.cpp
index 504c1d3..ffa5d9a 100644
--- a/src/core/SkFloat.cpp
+++ b/src/core/SkFloat.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006-2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkFloat.h"
#include "SkMath.h"
@@ -223,7 +216,7 @@ int32_t SkFloat::Sqrt(int32_t packed)
{
if (packed < 0)
{
- SkASSERT(!"can't sqrt a negative number");
+ SkDEBUGFAIL("can't sqrt a negative number");
return 0;
}
diff --git a/src/core/SkFloat.h b/src/core/SkFloat.h
index 9435dd0..fe41c27 100644
--- a/src/core/SkFloat.h
+++ b/src/core/SkFloat.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006-2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkFloat_DEFINED
#define SkFloat_DEFINED
diff --git a/src/core/SkFloatBits.cpp b/src/core/SkFloatBits.cpp
index e6c2976..fc46005 100644
--- a/src/core/SkFloatBits.cpp
+++ b/src/core/SkFloatBits.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkFloatBits.h"
#include "SkMath.h"
diff --git a/src/core/SkFontHost.cpp b/src/core/SkFontHost.cpp
index 435b5a5..c1836ac 100644
--- a/src/core/SkFontHost.cpp
+++ b/src/core/SkFontHost.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkFontHost.cpp
-**
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2009 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkFontHost.h"
diff --git a/src/core/SkGeometry.cpp b/src/core/SkGeometry.cpp
index 3c9e9f9..5308d56 100644
--- a/src/core/SkGeometry.cpp
+++ b/src/core/SkGeometry.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkGeometry.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkGeometry.h"
#include "Sk64.h"
@@ -448,18 +440,20 @@ int SkChopQuadAtMaxCurvature(const SkPoint src[3], SkPoint dst[5])
}
}
-void SkConvertQuadToCubic(const SkPoint src[3], SkPoint dst[4])
-{
- SkScalar two = SkIntToScalar(2);
- SkScalar one_third = SkScalarDiv(SK_Scalar1, SkIntToScalar(3));
- dst[0].set(src[0].fX, src[0].fY);
- dst[1].set(
- SkScalarMul(SkScalarMulAdd(src[1].fX, two, src[0].fX), one_third),
- SkScalarMul(SkScalarMulAdd(src[1].fY, two, src[0].fY), one_third));
- dst[2].set(
- SkScalarMul(SkScalarMulAdd(src[1].fX, two, src[2].fX), one_third),
- SkScalarMul(SkScalarMulAdd(src[1].fY, two, src[2].fY), one_third));
- dst[3].set(src[2].fX, src[2].fY);
+#ifdef SK_SCALAR_IS_FLOAT
+ #define SK_ScalarTwoThirds (0.666666666f)
+#else
+ #define SK_ScalarTwoThirds ((SkFixed)(43691))
+#endif
+
+void SkConvertQuadToCubic(const SkPoint src[3], SkPoint dst[4]) {
+ const SkScalar scale = SK_ScalarTwoThirds;
+ dst[0] = src[0];
+ dst[1].set(src[0].fX + SkScalarMul(src[1].fX - src[0].fX, scale),
+ src[0].fY + SkScalarMul(src[1].fY - src[0].fY, scale));
+ dst[2].set(src[2].fX + SkScalarMul(src[1].fX - src[2].fX, scale),
+ src[2].fY + SkScalarMul(src[1].fY - src[2].fY, scale));
+ dst[3] = src[2];
}
////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkGlobals.cpp b/src/core/SkGlobals.cpp
deleted file mode 100644
index bc72b97..0000000
--- a/src/core/SkGlobals.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/* libs/graphics/sgl/SkGlobals.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include "SkGlobals.h"
-#include "SkThread.h"
-
-SkGlobals::Rec::~Rec()
-{
-}
-
-SkGlobals::Rec* SkGlobals::Find(uint32_t 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 == NULL) // no create proc, just return not found
- return NULL;
-
- // 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 == NULL && (rec = create_proc()) != NULL)
- {
- 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 = NULL;
- bootstrap.fMutex.release();
-}
-
-
diff --git a/src/core/SkGlyphCache.cpp b/src/core/SkGlyphCache.cpp
index ad790e8..9f0dfba 100644
--- a/src/core/SkGlyphCache.cpp
+++ b/src/core/SkGlyphCache.cpp
@@ -1,22 +1,14 @@
-/* libs/graphics/sgl/SkGlyphCache.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkGlyphCache.h"
-#include "SkFontHost.h"
+#include "SkGraphics.h"
#include "SkPaint.h"
#include "SkTemplates.h"
@@ -24,6 +16,8 @@
//#define USE_CACHE_HASH
//#define RECORD_HASH_EFFICIENCY
+bool gSkSuppressFontCachePurgeSpew;
+
///////////////////////////////////////////////////////////////////////////////
#ifdef RECORD_HASH_EFFICIENCY
@@ -301,6 +295,10 @@ const void* SkGlyphCache::findImage(const SkGlyph& glyph) {
// check that alloc() actually succeeded
if (glyph.fImage) {
fScalerContext->getImage(glyph);
+ // TODO: the scaler may have changed the maskformat during
+ // getImage (e.g. from AA or LCD to BW) which means we may have
+ // overallocated the buffer. Check if the new computedImageSize
+ // is smaller, and if so, strink the alloc size in fImageAlloc.
fMemoryUsed += size;
}
}
@@ -389,11 +387,6 @@ void SkGlyphCache::invokeAndRemoveAuxProcs() {
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
-#include "SkGlobals.h"
-#include "SkThread.h"
-
-#define SkGlyphCache_GlobalsTag SkSetFourByteTag('g', 'l', 'f', 'c')
-
#ifdef USE_CACHE_HASH
#define HASH_BITCOUNT 6
#define HASH_COUNT (1 << HASH_BITCOUNT)
@@ -413,8 +406,18 @@ void SkGlyphCache::invokeAndRemoveAuxProcs() {
}
#endif
-class SkGlyphCache_Globals : public SkGlobals::Rec {
+#include "SkThread.h"
+
+class SkGlyphCache_Globals {
public:
+ SkGlyphCache_Globals() {
+ fHead = NULL;
+ fTotalMemoryUsed = 0;
+#ifdef USE_CACHE_HASH
+ sk_bzero(fHash, sizeof(fHash));
+#endif
+ }
+
SkMutex fMutex;
SkGlyphCache* fHead;
size_t fTotalMemoryUsed;
@@ -429,28 +432,15 @@ public:
#endif
};
-#ifdef SK_USE_RUNTIME_GLOBALS
- static SkGlobals::Rec* create_globals() {
- SkGlyphCache_Globals* rec = SkNEW(SkGlyphCache_Globals);
- rec->fHead = NULL;
- rec->fTotalMemoryUsed = 0;
-#ifdef USE_CACHE_HASH
- memset(rec->fHash, 0, sizeof(rec->fHash));
-#endif
- 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
+static SkGlyphCache_Globals& getGlobals() {
+ // we leak this, so we don't incur any shutdown cost of the destructor
+ static SkGlyphCache_Globals* gGlobals = new SkGlyphCache_Globals;
+ return *gGlobals;
+}
void SkGlyphCache::VisitAllCaches(bool (*proc)(SkGlyphCache*, void*),
void* context) {
- SkGlyphCache_Globals& globals = FIND_GC_GLOBALS();
+ SkGlyphCache_Globals& globals = getGlobals();
SkAutoMutexAcquire ac(globals.fMutex);
SkGlyphCache* cache;
@@ -476,7 +466,7 @@ SkGlyphCache* SkGlyphCache::VisitCache(const SkDescriptor* desc,
void* context) {
SkASSERT(desc);
- SkGlyphCache_Globals& globals = FIND_GC_GLOBALS();
+ SkGlyphCache_Globals& globals = getGlobals();
SkAutoMutexAcquire ac(globals.fMutex);
SkGlyphCache* cache;
bool insideMutex = true;
@@ -538,7 +528,7 @@ void SkGlyphCache::AttachCache(SkGlyphCache* cache) {
SkASSERT(cache);
SkASSERT(cache->fNext == NULL);
- SkGlyphCache_Globals& globals = GET_GC_GLOBALS();
+ SkGlyphCache_Globals& globals = getGlobals();
SkAutoMutexAcquire ac(globals.fMutex);
globals.validate();
@@ -547,9 +537,10 @@ void SkGlyphCache::AttachCache(SkGlyphCache* cache) {
// if we have a fixed budget for our cache, do a purge here
{
size_t allocated = globals.fTotalMemoryUsed + cache->fMemoryUsed;
- size_t amountToFree = SkFontHost::ShouldPurgeFontCache(allocated);
- if (amountToFree)
- (void)InternalFreeCache(&globals, amountToFree);
+ size_t budgeted = SkGraphics::GetFontCacheLimit();
+ if (allocated > budgeted) {
+ (void)InternalFreeCache(&globals, allocated - budgeted);
+ }
}
cache->attachToHead(&globals.fHead);
@@ -565,7 +556,7 @@ void SkGlyphCache::AttachCache(SkGlyphCache* cache) {
}
size_t SkGlyphCache::GetCacheUsed() {
- SkGlyphCache_Globals& globals = FIND_GC_GLOBALS();
+ SkGlyphCache_Globals& globals = getGlobals();
SkAutoMutexAcquire ac(globals.fMutex);
return SkGlyphCache::ComputeMemoryUsed(globals.fHead);
@@ -575,7 +566,7 @@ bool SkGlyphCache::SetCacheUsed(size_t bytesUsed) {
size_t curr = SkGlyphCache::GetCacheUsed();
if (curr > bytesUsed) {
- SkGlyphCache_Globals& globals = FIND_GC_GLOBALS();
+ SkGlyphCache_Globals& globals = getGlobals();
SkAutoMutexAcquire ac(globals.fMutex);
return InternalFreeCache(&globals, curr - bytesUsed) > 0;
@@ -649,7 +640,7 @@ size_t SkGlyphCache::InternalFreeCache(SkGlyphCache_Globals* globals,
globals->validate();
#ifdef SPEW_PURGE_STATUS
- if (count) {
+ if (count && !gSkSuppressFontCachePurgeSpew) {
SkDebugf("purging %dK from font cache [%d entries]\n",
(int)(bytesFreed >> 10), count);
}
diff --git a/src/core/SkGlyphCache.h b/src/core/SkGlyphCache.h
index adf0466..2895c54 100644
--- a/src/core/SkGlyphCache.h
+++ b/src/core/SkGlyphCache.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkGlyphCache.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkGlyphCache_DEFINED
#define SkGlyphCache_DEFINED
@@ -81,6 +73,14 @@ public:
*/
unsigned getGlyphCount();
+#ifdef SK_BUILD_FOR_ANDROID
+ /** Returns the base glyph count for this strike.
+ */
+ unsigned getBaseGlyphCount(SkUnichar charCode) const {
+ return fScalerContext->getBaseGlyphCount(charCode);
+ }
+#endif
+
/** Return the image associated with the glyph. If it has not been generated
this will trigger that.
*/
@@ -102,6 +102,10 @@ public:
return fScalerContext->getMaskFormat();
}
+ bool isSubpixel() const {
+ return fScalerContext->isSubpixel();
+ }
+
/* AuxProc/Data allow a client to associate data with this cache entry.
Multiple clients can use this, as their data is keyed with a function
pointer. In addition to serving as a key, the function pointer is called
@@ -228,7 +232,7 @@ private:
SkPaint::FontMetrics fFontMetricsY;
enum {
- kHashBits = 8,
+ kHashBits = 12,
kHashCount = 1 << kHashBits,
kHashMask = kHashCount - 1
};
diff --git a/src/core/SkGraphics.cpp b/src/core/SkGraphics.cpp
index 8638504..ff38f85 100644
--- a/src/core/SkGraphics.cpp
+++ b/src/core/SkGraphics.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkGraphics.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkGraphics.h"
@@ -22,11 +14,11 @@
#include "SkCanvas.h"
#include "SkFloat.h"
#include "SkGeometry.h"
-#include "SkGlobals.h"
#include "SkMath.h"
#include "SkMatrix.h"
#include "SkPath.h"
#include "SkPathEffect.h"
+#include "SkPixelRef.h"
#include "SkRandom.h"
#include "SkRefCnt.h"
#include "SkScalerContext.h"
@@ -37,6 +29,18 @@
#include "SkUtils.h"
#include "SkXfermode.h"
+void SkGraphics::GetVersion(int32_t* major, int32_t* minor, int32_t* patch) {
+ if (major) {
+ *major = SKIA_VERSION_MAJOR;
+ }
+ if (minor) {
+ *minor = SKIA_VERSION_MINOR;
+ }
+ if (patch) {
+ *patch = SKIA_VERSION_PATCH;
+ }
+}
+
#define typesizeline(type) { #type , sizeof(type) }
#ifdef BUILD_EMBOSS_TABLE
@@ -48,8 +52,10 @@
#endif
void SkGraphics::Init() {
- SkGlobals::Init();
-
+#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+ SkFlattenable::InitializeFlattenables();
+ SkPixelRef::InitializeFlattenables();
+#endif
#ifdef BUILD_EMBOSS_TABLE
SkEmbossMask_BuildTable();
#endif
@@ -109,6 +115,8 @@ void SkGraphics::Init() {
SkDebugf("SkGraphics: sizeof(%s) = %d\n",
gTypeSize[i].fTypeName, gTypeSize[i].fSizeOf);
}
+ SkDebugf("SkGraphics: font cache limit %dK\n",
+ GetFontCacheLimit() >> 10);
#endif
}
@@ -116,29 +124,88 @@ void SkGraphics::Init() {
///////////////////////////////////////////////////////////////////////////////
#include "SkGlyphCache.h"
+#include "SkTypefaceCache.h"
void SkGraphics::Term() {
- SkGraphics::SetFontCacheUsed(0);
- SkGlobals::Term();
+ PurgeFontCache();
}
-size_t SkGraphics::GetFontCacheUsed() {
- return SkGlyphCache::GetCacheUsed();
-}
+#ifndef SK_DEFAULT_FONT_CACHE_LIMIT
+ #define SK_DEFAULT_FONT_CACHE_LIMIT (2 * 1024 * 1024)
+#endif
-bool SkGraphics::SetFontCacheUsed(size_t usageInBytes) {
- return SkGlyphCache::SetCacheUsed(usageInBytes);
+#define SK_MIN_FONT_CACHE_LIMIT (256 * 1024)
+
+static size_t gFontCacheLimit = SK_DEFAULT_FONT_CACHE_LIMIT;
+
+size_t SkGraphics::GetFontCacheLimit() {
+ return gFontCacheLimit;
}
-void SkGraphics::GetVersion(int32_t* major, int32_t* minor, int32_t* patch) {
- if (major) {
- *major = SKIA_VERSION_MAJOR;
+size_t SkGraphics::SetFontCacheLimit(size_t bytes) {
+ size_t prev = gFontCacheLimit;
+
+ if (bytes < SK_MIN_FONT_CACHE_LIMIT) {
+ bytes = SK_MIN_FONT_CACHE_LIMIT;
}
- if (minor) {
- *minor = SKIA_VERSION_MINOR;
- }
- if (patch) {
- *patch = SKIA_VERSION_PATCH;
+ gFontCacheLimit = bytes;
+
+ // trigger a purge if the new size is smaller that our currently used amount
+ if (bytes < SkGlyphCache::GetCacheUsed()) {
+ SkGlyphCache::SetCacheUsed(bytes);
}
+ return prev;
+}
+
+void SkGraphics::PurgeFontCache() {
+ SkGlyphCache::SetCacheUsed(0);
+ SkTypefaceCache::PurgeAll();
}
+///////////////////////////////////////////////////////////////////////////////
+
+static const char kFontCacheLimitStr[] = "font-cache-limit";
+static const size_t kFontCacheLimitLen = sizeof(kFontCacheLimitStr) - 1;
+
+static const struct {
+ const char* fStr;
+ size_t fLen;
+ size_t (*fFunc)(size_t);
+} gFlags[] = {
+ {kFontCacheLimitStr, kFontCacheLimitLen, SkGraphics::SetFontCacheLimit}
+};
+
+/* flags are of the form param; or param=value; */
+void SkGraphics::SetFlags(const char* flags) {
+ if (!flags) {
+ return;
+ }
+ const char* nextSemi;
+ do {
+ size_t len = strlen(flags);
+ const char* paramEnd = flags + len;
+ const char* nextEqual = strchr(flags, '=');
+ if (nextEqual && paramEnd > nextEqual) {
+ paramEnd = nextEqual;
+ }
+ nextSemi = strchr(flags, ';');
+ if (nextSemi && paramEnd > nextSemi) {
+ paramEnd = nextSemi;
+ }
+ size_t paramLen = paramEnd - flags;
+ for (int i = 0; i < (int)SK_ARRAY_COUNT(gFlags); ++i) {
+ if (paramLen != gFlags[i].fLen) {
+ continue;
+ }
+ if (strncmp(flags, gFlags[i].fStr, paramLen) == 0) {
+ size_t val = 0;
+ if (nextEqual) {
+ val = (size_t) atoi(nextEqual + 1);
+ }
+ (gFlags[i].fFunc)(val);
+ break;
+ }
+ }
+ flags = nextSemi + 1;
+ } while (nextSemi);
+}
diff --git a/src/core/SkLineClipper.cpp b/src/core/SkLineClipper.cpp
index ab49773..708d3a9 100644
--- a/src/core/SkLineClipper.cpp
+++ b/src/core/SkLineClipper.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkLineClipper.h"
// return X coordinate of intersection with horizontal line at Y
diff --git a/src/core/SkMMapStream.cpp b/src/core/SkMMapStream.cpp
index 78cb3f3..0aec5e1 100644
--- a/src/core/SkMMapStream.cpp
+++ b/src/core/SkMMapStream.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkMMapStream.h"
#include <unistd.h>
@@ -7,7 +14,7 @@
SkMMAPStream::SkMMAPStream(const char filename[])
{
- fFildes = -1; // initialize to failure case
+ fAddr = NULL; // initialize to failure case
int fildes = open(filename, O_RDONLY);
if (fildes < 0)
@@ -29,16 +36,21 @@ SkMMAPStream::SkMMAPStream(const char filename[])
size_t size = static_cast<size_t>(offset);
void* addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fildes, 0);
+
+ // According to the POSIX documentation of mmap it adds an extra reference
+ // to the file associated with the fildes which is not removed by a
+ // subsequent close() on that fildes. This reference is removed when there
+ // are no more mappings to the file.
+ close(fildes);
+
if (MAP_FAILED == addr)
{
SkDEBUGF(("---- failed to mmap(%s) for mmap stream error=%d\n", filename, errno));
- close(fildes);
return;
}
this->INHERITED::setMemory(addr, size);
- fFildes = fildes;
fAddr = addr;
fSize = size;
}
@@ -56,11 +68,10 @@ void SkMMAPStream::setMemory(const void* data, size_t length, bool copyData)
void SkMMAPStream::closeMMap()
{
- if (fFildes >= 0)
+ if (fAddr)
{
munmap(fAddr, fSize);
- close(fFildes);
- fFildes = -1;
+ fAddr = NULL;
}
}
diff --git a/src/core/SkMallocPixelRef.cpp b/src/core/SkMallocPixelRef.cpp
index 7b97f16..3e22075 100644
--- a/src/core/SkMallocPixelRef.cpp
+++ b/src/core/SkMallocPixelRef.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkMallocPixelRef.h"
#include "SkBitmap.h"
#include "SkFlattenable.h"
@@ -52,6 +59,4 @@ SkMallocPixelRef::SkMallocPixelRef(SkFlattenableReadBuffer& buffer)
}
}
-static SkPixelRef::Registrar reg("SkMallocPixelRef",
- SkMallocPixelRef::Create);
-
+SK_DEFINE_PIXEL_REF_REGISTRAR(SkMallocPixelRef)
diff --git a/src/core/SkMask.cpp b/src/core/SkMask.cpp
index 34f122b..36047fe 100644
--- a/src/core/SkMask.cpp
+++ b/src/core/SkMask.cpp
@@ -1,19 +1,10 @@
-/* libs/graphics/sgl/SkMask.cpp
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+/*
+ * Copyright 2007 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "Sk64.h"
#include "SkMask.h"
@@ -56,3 +47,31 @@ void SkMask::FreeImage(void* image) {
sk_free(image);
}
+///////////////////////////////////////////////////////////////////////////////
+
+static const int gMaskFormatToShift[] = {
+ ~0, // BW -- not supported
+ 0, // A8
+ 0, // 3D
+ 2, // ARGB32
+ 1, // LCD16
+ 2 // LCD32
+};
+
+static int maskFormatToShift(SkMask::Format format) {
+ SkASSERT((unsigned)format < SK_ARRAY_COUNT(gMaskFormatToShift));
+ SkASSERT(SkMask::kBW_Format != format);
+ return gMaskFormatToShift[format];
+}
+
+void* SkMask::getAddr(int x, int y) const {
+ SkASSERT(kBW_Format != fFormat);
+ SkASSERT(fBounds.contains(x, y));
+ SkASSERT(fImage);
+
+ char* addr = (char*)fImage;
+ addr += (y - fBounds.fTop) * fRowBytes;
+ addr += (x - fBounds.fLeft) << maskFormatToShift(fFormat);
+ return addr;
+}
+
diff --git a/src/core/SkMaskFilter.cpp b/src/core/SkMaskFilter.cpp
index 2008c93..36855a4 100644
--- a/src/core/SkMaskFilter.cpp
+++ b/src/core/SkMaskFilter.cpp
@@ -1,26 +1,18 @@
-/* libs/graphics/sgl/SkMaskFilter.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkMaskFilter.h"
#include "SkBlitter.h"
#include "SkBounder.h"
#include "SkBuffer.h"
#include "SkDraw.h"
-#include "SkRegion.h"
+#include "SkRasterClip.h"
bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&,
SkIPoint*) {
@@ -28,7 +20,7 @@ bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&,
}
bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix,
- const SkRegion& clip, SkBounder* bounder,
+ const SkRasterClip& clip, SkBounder* bounder,
SkBlitter* blitter) {
SkMask srcM, dstM;
@@ -36,15 +28,18 @@ bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix,
SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
return false;
}
-
- SkAutoMaskImage autoSrc(&srcM, false);
+ SkAutoMaskFreeImage autoSrc(srcM.fImage);
if (!this->filterMask(&dstM, srcM, matrix, NULL)) {
return false;
}
+ SkAutoMaskFreeImage autoDst(dstM.fImage);
- SkAutoMaskImage autoDst(&dstM, false);
- SkRegion::Cliperator clipper(clip, dstM.fBounds);
+ // if we get here, we need to (possibly) resolve the clip and blitter
+ SkAAClipBlitterWrapper wrapper(clip, blitter);
+ blitter = wrapper.getBlitter();
+
+ SkRegion::Cliperator clipper(wrapper.getRgn(), dstM.fBounds);
if (!clipper.done() && (bounder == NULL || bounder->doIRect(dstM.fBounds))) {
const SkIRect& cr = clipper.rect();
@@ -57,6 +52,10 @@ bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix,
return true;
}
+SkMaskFilter::BlurType SkMaskFilter::asABlur(BlurInfo*) const {
+ return kNone_BlurType;
+}
+
void SkMaskFilter::computeFastBounds(const SkRect& src, SkRect* dst) {
SkMask srcM, dstM;
diff --git a/src/core/SkMath.cpp b/src/core/SkMath.cpp
index 649b518..7b75305 100644
--- a/src/core/SkMath.cpp
+++ b/src/core/SkMath.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006-2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkMath.h"
#include "SkCordic.h"
#include "SkFloatBits.h"
diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp
index da66a68..6e0bf02 100644
--- a/src/core/SkMatrix.cpp
+++ b/src/core/SkMatrix.cpp
@@ -1,19 +1,11 @@
-/* libs/corecg/SkMatrix.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkMatrix.h"
#include "Sk64.h"
@@ -64,6 +56,18 @@ enum {
static const int32_t kPersp1Int = (1 << 30);
#endif
+uint8_t SkMatrix::computePerspectiveTypeMask() const {
+ unsigned mask = kOnlyPerspectiveValid_Mask | kUnknown_Mask;
+
+ if (SkScalarAs2sCompliment(fMat[kMPersp0]) |
+ SkScalarAs2sCompliment(fMat[kMPersp1]) |
+ (SkScalarAs2sCompliment(fMat[kMPersp2]) - kPersp1Int)) {
+ mask |= kPerspective_Mask;
+ }
+
+ return SkToU8(mask);
+}
+
uint8_t SkMatrix::computeTypeMask() const {
unsigned mask = 0;
@@ -173,7 +177,7 @@ bool SkMatrix::preTranslate(SkScalar dx, SkScalar dy) {
fMat[kMTransY] += SkScalarMul(fMat[kMSkewY], dx) +
SkScalarMul(fMat[kMScaleY], dy);
- this->setTypeMask(kUnknown_Mask);
+ this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
}
return true;
}
@@ -188,7 +192,7 @@ bool SkMatrix::postTranslate(SkScalar dx, SkScalar dy) {
if (SkScalarToCompareType(dx) || SkScalarToCompareType(dy)) {
fMat[kMTransX] += dx;
fMat[kMTransY] += dy;
- this->setTypeMask(kUnknown_Mask);
+ this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
}
return true;
}
@@ -196,28 +200,44 @@ bool SkMatrix::postTranslate(SkScalar dx, SkScalar dy) {
///////////////////////////////////////////////////////////////////////////////
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[kMPersp2] = kMatrix22Elem;
+ if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
+ this->reset();
+ } else {
+ fMat[kMScaleX] = sx;
+ fMat[kMScaleY] = sy;
+ fMat[kMTransX] = px - SkScalarMul(sx, px);
+ fMat[kMTransY] = py - SkScalarMul(sy, py);
+ fMat[kMPersp2] = kMatrix22Elem;
- fMat[kMSkewX] = fMat[kMSkewY] =
- fMat[kMPersp0] = fMat[kMPersp1] = 0;
-
- this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask);
+ fMat[kMSkewX] = fMat[kMSkewY] =
+ fMat[kMPersp0] = fMat[kMPersp1] = 0;
+
+ this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask);
+ }
}
void SkMatrix::setScale(SkScalar sx, SkScalar sy) {
- fMat[kMScaleX] = sx;
- fMat[kMScaleY] = sy;
- fMat[kMPersp2] = kMatrix22Elem;
+ if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
+ this->reset();
+ } else {
+ fMat[kMScaleX] = sx;
+ fMat[kMScaleY] = sy;
+ fMat[kMPersp2] = kMatrix22Elem;
- fMat[kMTransX] = fMat[kMTransY] =
- fMat[kMSkewX] = fMat[kMSkewY] =
- fMat[kMPersp0] = fMat[kMPersp1] = 0;
+ fMat[kMTransX] = fMat[kMTransY] =
+ fMat[kMSkewX] = fMat[kMSkewY] =
+ fMat[kMPersp0] = fMat[kMPersp1] = 0;
+
+ this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
+ }
+}
- this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
+bool SkMatrix::setIDiv(int divx, int divy) {
+ if (!divx || !divy) {
+ return false;
+ }
+ this->setScale(SK_Scalar1 / divx, SK_Scalar1 / divy);
+ return true;
}
bool SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
@@ -227,6 +247,10 @@ bool SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
}
bool SkMatrix::preScale(SkScalar sx, SkScalar sy) {
+ if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
+ return true;
+ }
+
#ifdef SK_SCALAR_IS_FIXED
SkMatrix m;
m.setScale(sx, sy);
@@ -251,12 +275,18 @@ bool SkMatrix::preScale(SkScalar sx, SkScalar sy) {
}
bool SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
+ if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
+ return true;
+ }
SkMatrix m;
m.setScale(sx, sy, px, py);
return this->postConcat(m);
}
bool SkMatrix::postScale(SkScalar sx, SkScalar sy) {
+ if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
+ return true;
+ }
SkMatrix m;
m.setScale(sx, sy);
return this->postConcat(m);
@@ -324,7 +354,7 @@ void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV,
fMat[kMPersp0] = fMat[kMPersp1] = 0;
fMat[kMPersp2] = kMatrix22Elem;
- this->setTypeMask(kUnknown_Mask);
+ this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
}
void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
@@ -339,7 +369,7 @@ void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
fMat[kMPersp0] = fMat[kMPersp1] = 0;
fMat[kMPersp2] = kMatrix22Elem;
- this->setTypeMask(kUnknown_Mask);
+ this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
}
void SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) {
@@ -392,7 +422,7 @@ void SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
fMat[kMPersp0] = fMat[kMPersp1] = 0;
fMat[kMPersp2] = kMatrix22Elem;
- this->setTypeMask(kUnknown_Mask);
+ this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
}
void SkMatrix::setSkew(SkScalar sx, SkScalar sy) {
@@ -407,7 +437,7 @@ void SkMatrix::setSkew(SkScalar sx, SkScalar sy) {
fMat[kMPersp0] = fMat[kMPersp1] = 0;
fMat[kMPersp2] = kMatrix22Elem;
- this->setTypeMask(kUnknown_Mask);
+ this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
}
bool SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
@@ -573,12 +603,12 @@ static void normalize_perspective(SkScalar mat[9]) {
}
bool SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) {
- TypeMask aType = a.getType();
- TypeMask bType = b.getType();
+ TypeMask aType = a.getPerspectiveTypeMaskOnly();
+ TypeMask bType = b.getPerspectiveTypeMaskOnly();
- if (0 == aType) {
+ if (a.isTriviallyIdentity()) {
*this = b;
- } else if (0 == bType) {
+ } else if (b.isTriviallyIdentity()) {
*this = a;
} else {
SkMatrix tmp;
@@ -615,6 +645,7 @@ bool SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) {
}
normalize_perspective(tmp.fMat);
+ tmp.setTypeMask(kUnknown_Mask);
} else { // not perspective
if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMScaleX],
a.fMat[kMSkewX], b.fMat[kMSkewY], &tmp.fMat[kMScaleX])) {
@@ -652,10 +683,12 @@ bool SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) {
tmp.fMat[kMPersp0] = tmp.fMat[kMPersp1] = 0;
tmp.fMat[kMPersp2] = kMatrix22Elem;
+ //SkDebugf("Concat mat non-persp type: %d\n", tmp.getType());
+ //SkASSERT(!(tmp.getType() & kPerspective_Mask));
+ tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
}
*this = tmp;
}
- this->setTypeMask(kUnknown_Mask);
return true;
}
@@ -760,21 +793,27 @@ bool SkMatrix::postConcat(const SkMatrix& mat) {
}
#endif
-bool SkMatrix::pdfTransform(SkScalar transform[6]) const {
- SkMatrix identity;
- const SkMatrix* use = this;
- bool ret = true;
+void SkMatrix::SetAffineIdentity(SkScalar affine[6]) {
+ affine[kAScaleX] = SK_Scalar1;
+ affine[kASkewY] = 0;
+ affine[kASkewX] = 0;
+ affine[kAScaleY] = SK_Scalar1;
+ affine[kATransX] = 0;
+ affine[kATransY] = 0;
+}
+
+bool SkMatrix::asAffine(SkScalar affine[6]) const {
if (this->hasPerspective()) {
- identity.reset();
- use = &identity;
- ret = false;
- }
- transform[0] = use->fMat[kMScaleX];
- transform[1] = use->fMat[kMSkewY];
- transform[2] = use->fMat[kMSkewX];
- transform[3] = use->fMat[kMScaleY];
- transform[4] = use->fMat[kMTransX];
- transform[5] = use->fMat[kMTransY];
+ return false;
+ }
+ if (affine) {
+ affine[kAScaleX] = this->fMat[kMScaleX];
+ affine[kASkewY] = this->fMat[kMSkewY];
+ affine[kASkewX] = this->fMat[kMSkewX];
+ affine[kAScaleY] = this->fMat[kMScaleY];
+ affine[kATransX] = this->fMat[kMTransX];
+ affine[kATransY] = this->fMat[kMTransY];
+ }
return true;
}
@@ -789,8 +828,10 @@ bool SkMatrix::invert(SkMatrix* inv) const {
if (inv) {
SkMatrix tmp;
- if (inv == this)
+ if (inv == this) {
inv = &tmp;
+ }
+ inv->setTypeMask(kUnknown_Mask);
if (isPersp) {
shift = 61 - shift;
@@ -821,6 +862,7 @@ bool SkMatrix::invert(SkMatrix* inv) const {
}
inv->fMat[kMPersp2] = SkFixedToFract(inv->fMat[kMPersp2]);
#endif
+ inv->setTypeMask(kUnknown_Mask);
} else { // not perspective
#ifdef SK_SCALAR_IS_FIXED
Sk64 tx, ty;
@@ -869,12 +911,12 @@ bool SkMatrix::invert(SkMatrix* inv) const {
inv->fMat[kMPersp0] = 0;
inv->fMat[kMPersp1] = 0;
inv->fMat[kMPersp2] = kMatrix22Elem;
+ inv->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
}
if (inv == &tmp) {
*(SkMatrix*)this = tmp;
}
- inv->setTypeMask(kUnknown_Mask);
}
return true;
}
@@ -1632,65 +1674,42 @@ bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[],
SkScalar SkMatrix::getMaxStretch() const {
TypeMask mask = this->getType();
- if (mask & kPerspective_Mask) {
+ if (this->hasPerspective()) {
return -SK_Scalar1;
}
-
- SkScalar stretch;
-
if (this->isIdentity()) {
- stretch = SK_Scalar1;
- } else if (!(mask & kAffine_Mask)) {
- stretch = SkMaxScalar(SkScalarAbs(fMat[kMScaleX]), SkScalarAbs(fMat[kMScaleY]));
-#if 0 // don't have this bit
- } else if (mask & kZeroScale_TypeBit) {
- stretch = SkMaxScalar(SkScalarAbs(fM[kSkewX]), SkScalarAbs(fM[kSkewY]));
-#endif
+ return SK_Scalar1;
+ }
+ if (!(mask & kAffine_Mask)) {
+ return SkMaxScalar(SkScalarAbs(fMat[kMScaleX]),
+ SkScalarAbs(fMat[kMScaleY]));
+ }
+ // ignore the translation part of the matrix, just look at 2x2 portion.
+ // compute singular values, take largest abs value.
+ // [a b; b c] = A^T*A
+ SkScalar a = SkScalarMul(fMat[kMScaleX], fMat[kMScaleX]) +
+ SkScalarMul(fMat[kMSkewY], fMat[kMSkewY]);
+ SkScalar b = SkScalarMul(fMat[kMScaleX], fMat[kMSkewX]) +
+ SkScalarMul(fMat[kMScaleY], fMat[kMSkewY]);
+ SkScalar c = SkScalarMul(fMat[kMSkewX], fMat[kMSkewX]) +
+ SkScalarMul(fMat[kMScaleY], fMat[kMScaleY]);
+ // eigenvalues of A^T*A are the squared singular values of A.
+ // characteristic equation is det((A^T*A) - l*I) = 0
+ // l^2 - (a + c)l + (ac-b^2)
+ // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
+ // and roots are guaraunteed to be pos and real).
+ SkScalar largerRoot;
+ SkScalar bSqd = SkScalarMul(b,b);
+ // if upper left 2x2 is orthogonal save some math
+ if (bSqd <= SK_ScalarNearlyZero) {
+ largerRoot = SkMaxScalar(a, c);
} else {
- // ignore the translation part of the matrix, just look at 2x2 portion.
- // compute singular values, take largest abs value.
- // [a b; b c] = A^T*A
- SkScalar a = SkScalarMul(fMat[kMScaleX], fMat[kMScaleX]) + SkScalarMul(fMat[kMSkewY], fMat[kMSkewY]);
- SkScalar b = SkScalarMul(fMat[kMScaleX], fMat[kMSkewX]) + SkScalarMul(fMat[kMScaleY], fMat[kMSkewY]);
- SkScalar c = SkScalarMul(fMat[kMSkewX], fMat[kMSkewX]) + SkScalarMul(fMat[kMScaleY], fMat[kMScaleY]);
- // eigenvalues of A^T*A are the squared singular values of A.
- // characteristic equation is det((A^T*A) - l*I) = 0
- // l^2 - (a + c)l + (ac-b^2)
- // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
- // and roots are guaraunteed to be pos and real).
- SkScalar largerRoot;
- SkScalar bSqd = SkScalarMul(b,b);
- if (bSqd <= SkFloatToScalar(1e-10)) { // will be true if upper left 2x2 is orthogonal, which is common, so save some math
- largerRoot = SkMaxScalar(a, c);
- } else {
- SkScalar aminusc = a - c;
- SkScalar apluscdiv2 = (a + c) / 2;
- SkScalar x = SkScalarSqrt(SkScalarMul(aminusc, aminusc) + 4 * bSqd) / 2;
- largerRoot = apluscdiv2 + x;
- }
-
- stretch = SkScalarSqrt(largerRoot);
+ SkScalar aminusc = a - c;
+ SkScalar apluscdiv2 = SkScalarHalf(a + c);
+ SkScalar x = SkScalarHalf(SkScalarSqrt(SkScalarMul(aminusc, aminusc) + 4 * bSqd));
+ largerRoot = apluscdiv2 + x;
}
-#if defined(SK_DEBUG) && 0
- // test a bunch of vectors. None should be scaled by more than stretch
- // (modulo some error) and we should find a vector that is scaled by almost
- // stretch.
- SkPoint pt;
- SkScalar max = 0;
- for (int i = 0; i < 1000; ++i) {
- SkScalar x = (float)rand() / RAND_MAX;
- SkScalar y = sqrtf(1 - (x*x));
- pt.fX = fMat[kMScaleX]*x + fMat[kMSkewX]*y;
- pt.fY = fMat[kMSkewY]*x + fMat[kMScaleY]*y;
- SkScalar d = pt.distanceToOrigin();
- SkASSERT(d <= (1.0001 * stretch));
- if (max < pt.distanceToOrigin()) {
- max = pt.distanceToOrigin();
- }
- }
- SkASSERT((stretch - max) < .05*stretch);
-#endif
- return stretch;
+ return SkScalarSqrt(largerRoot);
}
const SkMatrix& SkMatrix::I() {
diff --git a/src/core/SkMemory_stdlib.cpp b/src/core/SkMemory_stdlib.cpp
index 9aea795..df87359 100644
--- a/src/core/SkMemory_stdlib.cpp
+++ b/src/core/SkMemory_stdlib.cpp
@@ -1,19 +1,11 @@
-/* libs/corecg/SkMemory_stdlib.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTypes.h"
#include <stdio.h>
@@ -167,19 +159,13 @@ void ValidateHeap() {}
void sk_throw()
{
-#ifdef ANDROID
- fprintf(stderr, "throwing...\n");
-#endif
- SkASSERT(!"sk_throw");
+ SkDEBUGFAIL("sk_throw");
abort();
}
void sk_out_of_memory(void)
{
-#ifdef ANDROID
- fprintf(stderr,"- out of memory in SGL -\n");
-#endif
- SkASSERT(!"sk_out_of_memory");
+ SkDEBUGFAIL("sk_out_of_memory");
abort();
}
diff --git a/src/core/SkMetaData.cpp b/src/core/SkMetaData.cpp
index b1901dc..338ec5e 100644
--- a/src/core/SkMetaData.cpp
+++ b/src/core/SkMetaData.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/views/SkMetaData.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkMetaData.h"
#include "SkRefCnt.h"
diff --git a/src/core/SkPackBits.cpp b/src/core/SkPackBits.cpp
index 3e92841..8edd4c0 100644
--- a/src/core/SkPackBits.cpp
+++ b/src/core/SkPackBits.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkPackBits.h"
#define GATHER_STATSx
@@ -151,8 +158,8 @@ static uint8_t* flush_same8(uint8_t dst[], uint8_t value, int count) {
return dst;
}
-static uint8_t* flush_diff16(uint8_t SK_RESTRICT dst[],
- const uint16_t SK_RESTRICT src[], int count) {
+static uint8_t* flush_diff16(uint8_t* SK_RESTRICT dst,
+ const uint16_t* SK_RESTRICT src, int count) {
while (count > 0) {
int n = count;
if (n > 128) {
@@ -167,8 +174,8 @@ static uint8_t* flush_diff16(uint8_t SK_RESTRICT dst[],
return dst;
}
-static uint8_t* flush_diff8(uint8_t SK_RESTRICT dst[],
- const uint8_t SK_RESTRICT src[], int count) {
+static uint8_t* flush_diff8(uint8_t* SK_RESTRICT dst,
+ const uint8_t* SK_RESTRICT src, int count) {
while (count > 0) {
int n = count;
if (n > 128) {
@@ -183,8 +190,8 @@ static uint8_t* flush_diff8(uint8_t SK_RESTRICT dst[],
return dst;
}
-size_t SkPackBits::Pack16(const uint16_t SK_RESTRICT src[], int count,
- uint8_t SK_RESTRICT dst[]) {
+size_t SkPackBits::Pack16(const uint16_t* SK_RESTRICT src, int count,
+ uint8_t* SK_RESTRICT dst) {
uint8_t* origDst = dst;
const uint16_t* stop = src + count;
@@ -226,8 +233,8 @@ size_t SkPackBits::Pack16(const uint16_t SK_RESTRICT src[], int count,
}
}
-size_t SkPackBits::Pack8(const uint8_t SK_RESTRICT src[], int count,
- uint8_t SK_RESTRICT dst[]) {
+size_t SkPackBits::Pack8(const uint8_t* SK_RESTRICT src, int count,
+ uint8_t* SK_RESTRICT dst) {
uint8_t* origDst = dst;
const uint8_t* stop = src + count;
@@ -272,8 +279,8 @@ size_t SkPackBits::Pack8(const uint8_t SK_RESTRICT src[], int count,
#include "SkUtils.h"
-int SkPackBits::Unpack16(const uint8_t SK_RESTRICT src[], size_t srcSize,
- uint16_t SK_RESTRICT dst[]) {
+int SkPackBits::Unpack16(const uint8_t* SK_RESTRICT src, size_t srcSize,
+ uint16_t* SK_RESTRICT dst) {
uint16_t* origDst = dst;
const uint8_t* stop = src + srcSize;
@@ -294,8 +301,8 @@ int SkPackBits::Unpack16(const uint8_t SK_RESTRICT src[], size_t srcSize,
return dst - origDst;
}
-int SkPackBits::Unpack8(const uint8_t SK_RESTRICT src[], size_t srcSize,
- uint8_t SK_RESTRICT dst[]) {
+int SkPackBits::Unpack8(const uint8_t* SK_RESTRICT src, size_t srcSize,
+ uint8_t* SK_RESTRICT dst) {
uint8_t* origDst = dst;
const uint8_t* stop = src + srcSize;
@@ -321,8 +328,8 @@ enum UnpackState {
COPY_SRC_STATE
};
-void SkPackBits::Unpack8(uint8_t SK_RESTRICT dst[], size_t dstSkip,
- size_t dstWrite, const uint8_t SK_RESTRICT src[]) {
+void SkPackBits::Unpack8(uint8_t* SK_RESTRICT dst, size_t dstSkip,
+ size_t dstWrite, const uint8_t* SK_RESTRICT src) {
if (dstWrite == 0) {
return;
}
@@ -402,6 +409,3 @@ void SkPackBits::Unpack8(uint8_t SK_RESTRICT dst[], size_t dstSkip,
}
SkASSERT(0 == dstWrite);
}
-
-
-
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 21bd078..a6d30c9 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -1,23 +1,16 @@
-/* libs/graphics/sgl/SkPaint.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkPaint.h"
#include "SkColorFilter.h"
#include "SkFontHost.h"
+#include "SkImageFilter.h"
#include "SkMaskFilter.h"
#include "SkPathEffect.h"
#include "SkRasterizer.h"
@@ -29,12 +22,17 @@
#include "SkTypeface.h"
#include "SkXfermode.h"
#include "SkAutoKern.h"
+#include "SkGlyphCache.h"
+
+// define this to get a printf for out-of-range parameter in setters
+// e.g. setTextSize(-1)
+//#define SK_REPORT_API_RANGE_CHECK
#define SK_DefaultTextSize SkIntToScalar(12)
#define SK_DefaultFlags 0 //(kNativeHintsText_Flag)
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
#define GEN_ID_INC fGenerationID++
#define GEN_ID_INC_EVAL(expression) if (expression) { fGenerationID++; }
#else
@@ -58,6 +56,7 @@ SkPaint::SkPaint() {
fColorFilter = NULL;
fRasterizer = NULL;
fLooper = NULL;
+ fImageFilter = NULL;
fWidth = 0;
#endif
@@ -72,7 +71,7 @@ SkPaint::SkPaint() {
fStyle = kFill_Style;
fTextEncoding = kUTF8_TextEncoding;
fHinting = kNormal_Hinting;
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
fGenerationID = 0;
#endif
}
@@ -88,6 +87,7 @@ SkPaint::SkPaint(const SkPaint& src) {
SkSafeRef(fColorFilter);
SkSafeRef(fRasterizer);
SkSafeRef(fLooper);
+ SkSafeRef(fImageFilter);
}
SkPaint::~SkPaint() {
@@ -99,6 +99,7 @@ SkPaint::~SkPaint() {
SkSafeUnref(fColorFilter);
SkSafeUnref(fRasterizer);
SkSafeUnref(fLooper);
+ SkSafeUnref(fImageFilter);
}
SkPaint& SkPaint::operator=(const SkPaint& src) {
@@ -112,6 +113,7 @@ SkPaint& SkPaint::operator=(const SkPaint& src) {
SkSafeRef(src.fColorFilter);
SkSafeRef(src.fRasterizer);
SkSafeRef(src.fLooper);
+ SkSafeRef(src.fImageFilter);
SkSafeUnref(fTypeface);
SkSafeUnref(fPathEffect);
@@ -121,40 +123,54 @@ SkPaint& SkPaint::operator=(const SkPaint& src) {
SkSafeUnref(fColorFilter);
SkSafeUnref(fRasterizer);
SkSafeUnref(fLooper);
+ SkSafeUnref(fImageFilter);
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
uint32_t oldGenerationID = fGenerationID;
#endif
memcpy(this, &src, sizeof(src));
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
fGenerationID = oldGenerationID + 1;
#endif
return *this;
}
-int operator==(const SkPaint& a, const SkPaint& b) {
- return memcmp(&a, &b, sizeof(a)) == 0;
+bool operator==(const SkPaint& a, const SkPaint& b) {
+#ifdef SK_BUILD_FOR_ANDROID
+ //assumes that fGenerationID is the last field in the struct
+ return !memcmp(&a, &b, SK_OFFSETOF(SkPaint, fGenerationID));
+#else
+ return !memcmp(&a, &b, sizeof(a));
+#endif
}
void SkPaint::reset() {
SkPaint init;
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
uint32_t oldGenerationID = fGenerationID;
#endif
*this = init;
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
fGenerationID = oldGenerationID + 1;
#endif
}
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
uint32_t SkPaint::getGenerationID() const {
return fGenerationID;
}
#endif
+#ifdef SK_BUILD_FOR_ANDROID
+unsigned SkPaint::getBaseGlyphCount(SkUnichar text) const {
+ SkAutoGlyphCache autoCache(*this, NULL);
+ SkGlyphCache* cache = autoCache.getCache();
+ return cache->getBaseGlyphCount(text);
+}
+#endif
+
void SkPaint::setHinting(Hinting hintingLevel) {
GEN_ID_INC_EVAL((unsigned) hintingLevel != fHinting);
fHinting = hintingLevel;
@@ -200,6 +216,11 @@ void SkPaint::setLinearText(bool doLinearText) {
this->setFlags(SkSetClearMask(fFlags, doLinearText, kLinearText_Flag));
}
+void SkPaint::setVerticalText(bool doVertical) {
+ GEN_ID_INC_EVAL(doVertical != isVerticalText());
+ this->setFlags(SkSetClearMask(fFlags, doVertical, kVerticalText_Flag));
+}
+
void SkPaint::setUnderlineText(bool doUnderline) {
GEN_ID_INC_EVAL(doUnderline != isUnderlineText());
this->setFlags(SkSetClearMask(fFlags, doUnderline, kUnderlineText_Flag));
@@ -230,7 +251,9 @@ void SkPaint::setStyle(Style style) {
GEN_ID_INC_EVAL((unsigned)style != fStyle);
fStyle = style;
} else {
- SkDEBUGCODE(SkDebugf("SkPaint::setStyle(%d) out of range\n", style);)
+#ifdef SK_REPORT_API_RANGE_CHECK
+ SkDebugf("SkPaint::setStyle(%d) out of range\n", style);
+#endif
}
}
@@ -253,7 +276,9 @@ void SkPaint::setStrokeWidth(SkScalar width) {
GEN_ID_INC_EVAL(width != fWidth);
fWidth = width;
} else {
- SkDEBUGCODE(SkDebugf("SkPaint::setStrokeWidth() called with negative value\n");)
+#ifdef SK_REPORT_API_RANGE_CHECK
+ SkDebugf("SkPaint::setStrokeWidth() called with negative value\n");
+#endif
}
}
@@ -262,7 +287,9 @@ void SkPaint::setStrokeMiter(SkScalar limit) {
GEN_ID_INC_EVAL(limit != fMiterLimit);
fMiterLimit = limit;
} else {
- SkDEBUGCODE(SkDebugf("SkPaint::setStrokeMiter() called with negative value\n");)
+#ifdef SK_REPORT_API_RANGE_CHECK
+ SkDebugf("SkPaint::setStrokeMiter() called with negative value\n");
+#endif
}
}
@@ -271,7 +298,9 @@ void SkPaint::setStrokeCap(Cap ct) {
GEN_ID_INC_EVAL((unsigned)ct != fCapType);
fCapType = SkToU8(ct);
} else {
- SkDEBUGCODE(SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct);)
+#ifdef SK_REPORT_API_RANGE_CHECK
+ SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct);
+#endif
}
}
@@ -280,7 +309,9 @@ void SkPaint::setStrokeJoin(Join jt) {
GEN_ID_INC_EVAL((unsigned)jt != fJoinType);
fJoinType = SkToU8(jt);
} else {
- SkDEBUGCODE(SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt);)
+#ifdef SK_REPORT_API_RANGE_CHECK
+ SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt);
+#endif
}
}
@@ -291,16 +322,20 @@ void SkPaint::setTextAlign(Align align) {
GEN_ID_INC_EVAL((unsigned)align != fTextAlign);
fTextAlign = SkToU8(align);
} else {
- SkDEBUGCODE(SkDebugf("SkPaint::setTextAlign(%d) out of range\n", align);)
+#ifdef SK_REPORT_API_RANGE_CHECK
+ SkDebugf("SkPaint::setTextAlign(%d) out of range\n", align);
+#endif
}
}
void SkPaint::setTextSize(SkScalar ts) {
- if (ts > 0) {
+ if (ts >= 0) {
GEN_ID_INC_EVAL(ts != fTextSize);
fTextSize = ts;
} else {
- SkDEBUGCODE(SkDebugf("SkPaint::setTextSize() called with negative value\n");)
+#ifdef SK_REPORT_API_RANGE_CHECK
+ SkDebugf("SkPaint::setTextSize() called with negative value\n");
+#endif
}
}
@@ -319,7 +354,9 @@ void SkPaint::setTextEncoding(TextEncoding encoding) {
GEN_ID_INC_EVAL((unsigned)encoding != fTextEncoding);
fTextEncoding = encoding;
} else {
- SkDEBUGCODE(SkDebugf("SkPaint::setTextEncoding(%d) out of range\n", encoding);)
+#ifdef SK_REPORT_API_RANGE_CHECK
+ SkDebugf("SkPaint::setTextEncoding(%d) out of range\n", encoding);
+#endif
}
}
@@ -343,6 +380,12 @@ SkDrawLooper* SkPaint::setLooper(SkDrawLooper* looper) {
return looper;
}
+SkImageFilter* SkPaint::setImageFilter(SkImageFilter* imageFilter) {
+ SkRefCnt_SafeAssign(fImageFilter, imageFilter);
+ GEN_ID_INC;
+ return imageFilter;
+}
+
///////////////////////////////////////////////////////////////////////////////
#include "SkGlyphCache.h"
@@ -352,7 +395,7 @@ static void DetachDescProc(const SkDescriptor* desc, void* context) {
*((SkGlyphCache**)context) = SkGlyphCache::DetachCache(desc);
}
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
const SkGlyph& SkPaint::getUnicharMetrics(SkUnichar text) {
SkGlyphCache* cache;
descriptorProc(NULL, DetachDescProc, &cache, true);
@@ -403,7 +446,7 @@ int SkPaint::textToGlyphs(const void* textData, size_t byteLength,
case kGlyphID_TextEncoding:
return byteLength >> 1;
default:
- SkASSERT(!"unknown text encoding");
+ SkDEBUGFAIL("unknown text encoding");
}
return 0;
}
@@ -439,7 +482,7 @@ int SkPaint::textToGlyphs(const void* textData, size_t byteLength,
break;
}
default:
- SkASSERT(!"unknown text encoding");
+ SkDEBUGFAIL("unknown text encoding");
}
return gptr - glyphs;
}
@@ -488,7 +531,7 @@ bool SkPaint::containsText(const void* textData, size_t byteLength) const {
break;
}
default:
- SkASSERT(!"unknown text encoding");
+ SkDEBUGFAIL("unknown text encoding");
return false;
}
return true;
@@ -781,7 +824,7 @@ typedef int64_t Sk48Dot16;
}
#endif
-static void join_bounds(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dx) {
+static void join_bounds_x(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dx) {
SkScalar sx = Sk48Dot16ToScalar(dx);
bounds->join(SkIntToScalar(g.fLeft) + sx,
SkIntToScalar(g.fTop),
@@ -789,6 +832,22 @@ static void join_bounds(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dx) {
SkIntToScalar(g.fTop + g.fHeight));
}
+static void join_bounds_y(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dy) {
+ SkScalar sy = Sk48Dot16ToScalar(dy);
+ bounds->join(SkIntToScalar(g.fLeft),
+ SkIntToScalar(g.fTop) + sy,
+ SkIntToScalar(g.fLeft + g.fWidth),
+ SkIntToScalar(g.fTop + g.fHeight) + sy);
+}
+
+typedef void (*JoinBoundsProc)(const SkGlyph&, SkRect*, Sk48Dot16);
+
+// xyIndex is 0 for fAdvanceX or 1 for fAdvanceY
+static SkFixed advance(const SkGlyph& glyph, int xyIndex) {
+ SkASSERT(0 == xyIndex || 1 == xyIndex);
+ return (&glyph.fAdvanceX)[xyIndex];
+}
+
SkScalar SkPaint::measure_text(SkGlyphCache* cache,
const char* text, size_t byteLength,
int* count, SkRect* bounds) const {
@@ -805,13 +864,23 @@ SkScalar SkPaint::measure_text(SkGlyphCache* cache,
glyphCacheProc = this->getMeasureCacheProc(kForward_TextBufferDirection,
NULL != bounds);
+ int xyIndex;
+ JoinBoundsProc joinBoundsProc;
+ if (this->isVerticalText()) {
+ xyIndex = 1;
+ joinBoundsProc = join_bounds_y;
+ } else {
+ xyIndex = 0;
+ joinBoundsProc = join_bounds_x;
+ }
+
int n = 1;
const char* stop = (const char*)text + byteLength;
const SkGlyph* g = &glyphCacheProc(cache, &text);
// our accumulated fixed-point advances might overflow 16.16, so we use
// a 48.16 (64bit) accumulator, and then convert that to scalar at the
// very end.
- Sk48Dot16 x = g->fAdvanceX;
+ Sk48Dot16 x = advance(*g, xyIndex);
SkAutoKern autokern;
@@ -821,11 +890,11 @@ SkScalar SkPaint::measure_text(SkGlyphCache* cache,
for (; text < stop; n++) {
rsb = g->fRsbDelta;
g = &glyphCacheProc(cache, &text);
- x += SkAutoKern_AdjustF(rsb, g->fLsbDelta) + g->fAdvanceX;
+ x += SkAutoKern_AdjustF(rsb, g->fLsbDelta) + advance(*g, xyIndex);
}
} else {
for (; text < stop; n++) {
- x += glyphCacheProc(cache, &text).fAdvanceX;
+ x += advance(glyphCacheProc(cache, &text), xyIndex);
}
}
} else {
@@ -836,14 +905,14 @@ SkScalar SkPaint::measure_text(SkGlyphCache* cache,
rsb = g->fRsbDelta;
g = &glyphCacheProc(cache, &text);
x += SkAutoKern_AdjustF(rsb, g->fLsbDelta);
- join_bounds(*g, bounds, x);
- x += g->fAdvanceX;
+ joinBoundsProc(*g, bounds, x);
+ x += advance(*g, xyIndex);
}
} else {
for (; text < stop; n++) {
g = &glyphCacheProc(cache, &text);
- join_bounds(*g, bounds, x);
- x += g->fAdvanceX;
+ joinBoundsProc(*g, bounds, x);
+ x += advance(*g, xyIndex);
}
}
}
@@ -929,6 +998,13 @@ size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth,
return 0;
}
+ if (0 == fTextSize) {
+ if (measuredWidth) {
+ *measuredWidth = 0;
+ }
+ return length;
+ }
+
SkASSERT(textD != NULL);
const char* text = (const char*)textD;
@@ -948,6 +1024,7 @@ size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth,
SkMeasureCacheProc glyphCacheProc = this->getMeasureCacheProc(tbd, false);
const char* stop;
SkTextBufferPred pred = chooseTextBufferPred(tbd, &text, length, &stop);
+ const int xyIndex = this->isVerticalText() ? 1 : 0;
// use 64bits for our accumulator, to avoid overflowing 16.16
Sk48Dot16 max = SkScalarToFixed(maxWidth);
Sk48Dot16 width = 0;
@@ -959,7 +1036,7 @@ size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth,
while (pred(text, stop)) {
const char* curr = text;
const SkGlyph& g = glyphCacheProc(cache, &text);
- SkFixed x = SkAutoKern_AdjustF(rsb, g.fLsbDelta) + g.fAdvanceX;
+ SkFixed x = SkAutoKern_AdjustF(rsb, g.fLsbDelta) + advance(g, xyIndex);
if ((width += x) > max) {
width -= x;
text = curr;
@@ -970,7 +1047,7 @@ size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth,
} else {
while (pred(text, stop)) {
const char* curr = text;
- SkFixed x = glyphCacheProc(cache, &text).fAdvanceX;
+ SkFixed x = advance(glyphCacheProc(cache, &text), xyIndex);
if ((width += x) > max) {
width -= x;
text = curr;
@@ -1029,7 +1106,7 @@ SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const {
metrics = &storage;
}
- this->descriptorProc(zoomPtr, FontMetricsDescProc, metrics);
+ this->descriptorProc(zoomPtr, FontMetricsDescProc, metrics, true);
if (scale) {
metrics->fTop = SkScalarMul(metrics->fTop, scale);
@@ -1080,6 +1157,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength,
const char* text = (const char*)textData;
const char* stop = text + byteLength;
int count = 0;
+ const int xyIndex = this->isVerticalText() ? 1 : 0;
if (this->isDevKernText()) {
// we adjust the widths returned here through auto-kerning
@@ -1096,7 +1174,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength,
SkScalar w = SkFixedToScalar(prevWidth + adjust);
*widths++ = SkScalarMul(w, scale);
}
- prevWidth = g.fAdvanceX;
+ prevWidth = advance(g, xyIndex);
}
if (bounds) {
set_bounds(g, bounds++, scale);
@@ -1115,7 +1193,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength,
if (count > 0) {
*widths++ = SkFixedToScalar(prevWidth + adjust);
}
- prevWidth = g.fAdvanceX;
+ prevWidth = advance(g, xyIndex);
}
if (bounds) {
set_bounds(g, bounds++);
@@ -1131,7 +1209,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength,
while (text < stop) {
const SkGlyph& g = glyphCacheProc(cache, &text);
if (widths) {
- *widths++ = SkScalarMul(SkFixedToScalar(g.fAdvanceX),
+ *widths++ = SkScalarMul(SkFixedToScalar(advance(g, xyIndex)),
scale);
}
if (bounds) {
@@ -1143,7 +1221,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength,
while (text < stop) {
const SkGlyph& g = glyphCacheProc(cache, &text);
if (widths) {
- *widths++ = SkFixedToScalar(g.fAdvanceX);
+ *widths++ = SkFixedToScalar(advance(g, xyIndex));
}
if (bounds) {
set_bounds(g, bounds++);
@@ -1192,6 +1270,7 @@ static void add_flattenable(SkDescriptor* desc, uint32_t tag,
buffer->flatten(desc->addEntry(tag, buffer->size(), NULL));
}
+// SkFontHost can override this choice in FilterRec()
static SkMask::Format computeMaskFormat(const SkPaint& paint) {
uint32_t flags = paint.getFlags();
@@ -1200,16 +1279,9 @@ static SkMask::Format computeMaskFormat(const SkPaint& paint) {
return SkMask::kBW_Format;
}
-#if defined(SK_SUPPORT_LCDTEXT)
- if (flags & SkPaint::kLCDRenderText_Flag) {
- return SkFontHost::GetSubpixelOrientation() == SkFontHost::kHorizontal_LCDOrientation ?
- SkMask::kHorizontalLCD_Format : SkMask::kVerticalLCD_Format;
- }
-#else
if (flags & SkPaint::kLCDRenderText_Flag) {
return SkMask::kLCD16_Format;
}
-#endif
return SkMask::kA8_Format;
}
@@ -1224,6 +1296,59 @@ static SkPaint::Hinting computeHinting(const SkPaint& paint) {
return h;
}
+// return true if the paint is just a single color (i.e. not a shader). If its
+// a shader, then we can't compute a const luminance for it :(
+static bool justAColor(const SkPaint& paint, SkColor* color) {
+ if (paint.getShader()) {
+ return false;
+ }
+ SkColor c = paint.getColor();
+ if (paint.getColorFilter()) {
+ c = paint.getColorFilter()->filterColor(c);
+ }
+ if (color) {
+ *color = c;
+ }
+ return true;
+}
+
+// returns 0..kLuminance_Max
+static unsigned computeLuminance(const SkPaint& paint) {
+ SkColor c;
+ if (justAColor(paint, &c)) {
+ int r = SkColorGetR(c);
+ int g = SkColorGetG(c);
+ int b = SkColorGetB(c);
+ // compute luminance
+ // R=0.2126 G=0.7152 B=0.0722
+ // scaling by 127 yields 27, 92, 9
+#if 1
+ int luminance = r * 27 + g * 92 + b * 9;
+ luminance >>= 15 - SkScalerContext::kLuminance_Bits;
+#else
+ int luminance = r * 2 + g * 5 + b * 1;
+ luminance >>= 11 - SkScalerContext::kLuminance_Bits;
+#endif
+ SkASSERT(luminance <= SkScalerContext::kLuminance_Max);
+ return luminance;
+ }
+ // if we're not a single color, return the middle of the luminance range
+ return SkScalerContext::kLuminance_Max >> 1;
+}
+
+// Beyond this size, LCD doesn't appreciably improve quality, but it always
+// cost more RAM and draws slower, so we set a cap.
+#ifndef SK_MAX_SIZE_FOR_LCDTEXT
+ #define SK_MAX_SIZE_FOR_LCDTEXT 48
+#endif
+
+static bool tooBigForLCD(const SkScalerContext::Rec& rec) {
+ SkScalar area = SkScalarMul(rec.fPost2x2[0][0], rec.fPost2x2[1][1]) -
+ SkScalarMul(rec.fPost2x2[1][0], rec.fPost2x2[0][1]);
+ SkScalar size = SkScalarMul(area, rec.fTextSize);
+ return SkScalarAbs(size) > SkIntToScalar(SK_MAX_SIZE_FOR_LCDTEXT);
+}
+
/*
* Return the scalar with only limited fractional precision. Used to consolidate matrices
* that vary only slightly when we create our key into the font cache, since the font scaler
@@ -1262,7 +1387,7 @@ void SkScalerContext::MakeRec(const SkPaint& paint,
SkPaint::Style style = paint.getStyle();
SkScalar strokeWidth = paint.getStrokeWidth();
- unsigned flags = SkFontHost::ComputeGammaFlag(paint);
+ unsigned flags = 0;
if (paint.isFakeBoldText()) {
#ifdef SK_USE_FREETYPE_EMBOLDEN
@@ -1303,10 +1428,12 @@ void SkScalerContext::MakeRec(const SkPaint& paint,
rec->fMaskFormat = SkToU8(computeMaskFormat(paint));
- if (SkMask::kLCD16_Format == rec->fMaskFormat) {
+ if (SkMask::kLCD16_Format == rec->fMaskFormat ||
+ SkMask::kLCD32_Format == rec->fMaskFormat)
+ {
SkFontHost::LCDOrder order = SkFontHost::GetSubpixelOrder();
SkFontHost::LCDOrientation orient = SkFontHost::GetSubpixelOrientation();
- if (SkFontHost::kNONE_LCDOrder == order) {
+ if (SkFontHost::kNONE_LCDOrder == order || tooBigForLCD(*rec)) {
// eeek, can't support LCD
rec->fMaskFormat = SkMask::kA8_Format;
} else {
@@ -1328,10 +1455,14 @@ void SkScalerContext::MakeRec(const SkPaint& paint,
if (paint.isAutohinted()) {
flags |= SkScalerContext::kAutohinting_Flag;
}
+ if (paint.isVerticalText()) {
+ flags |= SkScalerContext::kVertical_Flag;
+ }
rec->fFlags = SkToU16(flags);
- // setHinting modifies fFlags, so do this last
+ // these modify fFlags, so do them after assigning fFlags
rec->setHinting(computeHinting(paint));
+ rec->setLuminanceBits(computeLuminance(paint));
/* Allow the fonthost to modify our rec before we use it as a key into the
cache. This way if we're asking for something that they will ignore,
@@ -1339,6 +1470,11 @@ void SkScalerContext::MakeRec(const SkPaint& paint,
entries.
*/
SkFontHost::FilterRec(rec);
+
+ // No need to differentiate gamma if we're BW
+ if (SkMask::kBW_Format == rec->fMaskFormat) {
+ rec->setLuminanceBits(0);
+ }
}
#define MIN_SIZE_FOR_EFFECT_BUFFER 1024
@@ -1347,6 +1483,13 @@ void SkScalerContext::MakeRec(const SkPaint& paint,
#define TEST_DESC
#endif
+/*
+ * ignoreGamma tells us that the caller just wants metrics that are unaffected
+ * by gamma correction, so we jam the luminance field to 0 (most common value
+ * for black text) in hopes that we get a cache hit easier. A better solution
+ * would be for the fontcache lookup to know to ignore the luminance field
+ * entirely, but not sure how to do that and keep it fast.
+ */
void SkPaint::descriptorProc(const SkMatrix* deviceMatrix,
void (*proc)(const SkDescriptor*, void*),
void* context, bool ignoreGamma) const {
@@ -1354,8 +1497,7 @@ void SkPaint::descriptorProc(const SkMatrix* deviceMatrix,
SkScalerContext::MakeRec(*this, deviceMatrix, &rec);
if (ignoreGamma) {
- rec.fFlags &= ~(SkScalerContext::kGammaForBlack_Flag |
- SkScalerContext::kGammaForWhite_Flag);
+ rec.setLuminanceBits(0);
}
size_t descSize = sizeof(rec);
@@ -1521,7 +1663,8 @@ void SkPaint::flatten(SkFlattenableWriteBuffer& buffer) const {
asint(this->getMaskFilter()) |
asint(this->getColorFilter()) |
asint(this->getRasterizer()) |
- asint(this->getLooper())) {
+ asint(this->getLooper()) |
+ asint(this->getImageFilter())) {
flatFlags |= kHasEffects_FlatFlag;
}
@@ -1534,7 +1677,13 @@ void SkPaint::flatten(SkFlattenableWriteBuffer& buffer) const {
ptr = write_scalar(ptr, this->getStrokeWidth());
ptr = write_scalar(ptr, this->getStrokeMiter());
*ptr++ = this->getColor();
- *ptr++ = (this->getFlags() << 16) | (this->getTextAlign() << 8) | flatFlags;
+ // previously flags:16, textAlign:8, flatFlags:8
+ // now flags:16, hinting:4, textAlign:4, flatFlags:8
+ *ptr++ = (this->getFlags() << 16) |
+ // hinting added later. 0 in this nibble means use the default.
+ ((this->getHinting()+1) << 12) |
+ (this->getTextAlign() << 8) |
+ flatFlags;
*ptr++ = pack_4(this->getStrokeCap(), this->getStrokeJoin(),
this->getStyle(), this->getTextEncoding());
@@ -1551,6 +1700,7 @@ void SkPaint::flatten(SkFlattenableWriteBuffer& buffer) const {
buffer.writeFlattenable(this->getColorFilter());
buffer.writeFlattenable(this->getRasterizer());
buffer.writeFlattenable(this->getLooper());
+ buffer.writeFlattenable(this->getImageFilter());
}
}
@@ -1567,9 +1717,17 @@ void SkPaint::unflatten(SkFlattenableReadBuffer& buffer) {
this->setStrokeMiter(read_scalar(pod));
this->setColor(*pod++);
+ // previously flags:16, textAlign:8, flatFlags:8
+ // now flags:16, hinting:4, textAlign:4, flatFlags:8
uint32_t tmp = *pod++;
this->setFlags(tmp >> 16);
- this->setTextAlign(static_cast<Align>((tmp >> 8) & 0xFF));
+
+ // hinting added later. 0 in this nibble means use the default.
+ uint32_t hinting = (tmp >> 12) & 0xF;
+ this->setHinting(0 == hinting ? kNormal_Hinting : static_cast<Hinting>(hinting-1));
+
+ this->setTextAlign(static_cast<Align>((tmp >> 8) & 0xF));
+
uint8_t flatFlags = tmp & 0xFF;
tmp = *pod++;
@@ -1592,6 +1750,7 @@ void SkPaint::unflatten(SkFlattenableReadBuffer& buffer) {
SkSafeUnref(this->setColorFilter((SkColorFilter*) buffer.readFlattenable()));
SkSafeUnref(this->setRasterizer((SkRasterizer*) buffer.readFlattenable()));
SkSafeUnref(this->setLooper((SkDrawLooper*) buffer.readFlattenable()));
+ SkSafeUnref(this->setImageFilter((SkImageFilter*) buffer.readFlattenable()));
} else {
this->setPathEffect(NULL);
this->setShader(NULL);
@@ -1600,6 +1759,7 @@ void SkPaint::unflatten(SkFlattenableReadBuffer& buffer) {
this->setColorFilter(NULL);
this->setRasterizer(NULL);
this->setLooper(NULL);
+ this->setImageFilter(NULL);
}
}
@@ -1662,7 +1822,7 @@ bool SkPaint::getFillPath(const SkPath& src, SkPath* dst) const {
case SkPaint::kStroke_Style:
break;
default:
- SkASSERT(!"unknown paint style");
+ SkDEBUGFAIL("unknown paint style");
}
if (this->getPathEffect()) {
@@ -1803,6 +1963,8 @@ SkTextToPathIter::SkTextToPathIter( const char text[], size_t length,
fText = text;
fStop = text + length;
+
+ fXYIndex = paint.isVerticalText() ? 1 : 0;
}
SkTextToPathIter::~SkTextToPathIter() {
@@ -1814,7 +1976,7 @@ const SkPath* SkTextToPathIter::next(SkScalar* xpos) {
const SkGlyph& glyph = fGlyphCacheProc(fCache, &fText);
fXPos += SkScalarMul(SkFixedToScalar(fPrevAdvance + fAutoKern.adjust(glyph)), fScale);
- fPrevAdvance = glyph.fAdvanceX; // + fPaint.getTextTracking();
+ fPrevAdvance = advance(glyph, fXYIndex); // + fPaint.getTextTracking();
if (glyph.fWidth) {
if (xpos) {
@@ -1828,6 +1990,68 @@ const SkPath* SkTextToPathIter::next(SkScalar* xpos) {
///////////////////////////////////////////////////////////////////////////////
+bool SkPaint::nothingToDraw() const {
+ if (fLooper) {
+ return false;
+ }
+ SkXfermode::Mode mode;
+ if (SkXfermode::AsMode(fXfermode, &mode)) {
+ switch (mode) {
+ case SkXfermode::kSrcOver_Mode:
+ case SkXfermode::kSrcATop_Mode:
+ case SkXfermode::kDstOut_Mode:
+ case SkXfermode::kDstOver_Mode:
+ case SkXfermode::kPlus_Mode:
+ return 0 == this->getAlpha();
+ case SkXfermode::kDst_Mode:
+ return true;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+
+//////////// Move these to their own file soon.
+
+bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
+ const SkMatrix& ctm,
+ SkBitmap* result, SkIPoint* loc) {
+ SkASSERT(proxy);
+ SkASSERT(result);
+ SkASSERT(loc);
+ /*
+ * Give the proxy first shot at the filter. If it returns false, ask
+ * the filter to do it.
+ */
+ return proxy->filterImage(this, src, ctm, result, loc) ||
+ this->onFilterImage(proxy, src, ctm, result, loc);
+}
+
+bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
+ SkIRect* dst) {
+ SkASSERT(&src);
+ SkASSERT(dst);
+ return this->onFilterBounds(src, ctm, dst);
+}
+
+bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&,
+ SkBitmap*, SkIPoint*) {
+ return false;
+}
+
+bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
+ SkIRect* dst) {
+ *dst = src;
+ return true;
+}
+
+bool SkImageFilter::asABlur(SkSize* sigma) const {
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
bool SkDrawLooper::canComputeFastBounds(const SkPaint& paint) {
SkCanvas canvas;
@@ -1870,3 +2094,4 @@ void SkDrawLooper::computeFastBounds(const SkPaint& paint, const SkRect& src,
}
}
}
+
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index b88b20f..c99db4c 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkPath.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkPath.h"
#include "SkReader32.h"
@@ -22,6 +14,18 @@
////////////////////////////////////////////////////////////////////////////
+/**
+ * Path.bounds is defined to be the bounds of all the control points.
+ * If we called bounds.join(r) we would skip r if r was empty, which breaks
+ * our promise. Hence we have a custom joiner that doesn't look at emptiness
+ */
+static void joinNoEmptyChecks(SkRect* dst, const SkRect& src) {
+ dst->fLeft = SkMinScalar(dst->fLeft, src.fLeft);
+ dst->fTop = SkMinScalar(dst->fTop, src.fTop);
+ dst->fRight = SkMaxScalar(dst->fRight, src.fRight);
+ dst->fBottom = SkMaxScalar(dst->fBottom, src.fBottom);
+}
+
/* This guy's constructor/destructor bracket a path editing operation. It is
used when we know the bounds of the amount we are going to add to the path
(usually a new contour, but not required).
@@ -51,7 +55,7 @@ public:
fPath->fBounds = fRect;
fPath->fBoundsIsDirty = false;
} else if (!fDirty) {
- fPath->fBounds.join(fRect);
+ joinNoEmptyChecks(&fPath->fBounds, fRect);
fPath->fBoundsIsDirty = false;
}
}
@@ -85,20 +89,24 @@ static void compute_pt_bounds(SkRect* bounds, const SkTDArray<SkPoint>& pts) {
/*
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 only record "Close" if it was immediately preceeded by Move | 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
+ 1. If we encounter degenerate segments, remove them
+ 2. if we encounter Close, return a cons'd up Line() first (if the curr-pt != start-pt)
+ 3. if we encounter Move without a preceeding Close, and forceClose is true, goto #2
+ 4. if we encounter Line | Quad | Cubic after Close, cons up a Move
*/
////////////////////////////////////////////////////////////////////////////
-SkPath::SkPath() : fBoundsIsDirty(true), fFillType(kWinding_FillType) {
+SkPath::SkPath()
+ : fFillType(kWinding_FillType)
+ , fBoundsIsDirty(true) {
fConvexity = kUnknown_Convexity;
-#ifdef ANDROID
+ fSegmentMask = 0;
+#ifdef SK_BUILD_FOR_ANDROID
fGenerationID = 0;
#endif
}
@@ -106,7 +114,7 @@ SkPath::SkPath() : fBoundsIsDirty(true), fFillType(kWinding_FillType) {
SkPath::SkPath(const SkPath& src) {
SkDEBUGCODE(src.validate();)
*this = src;
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
// the assignment operator above increments the ID so correct for that here
fGenerationID--;
#endif
@@ -126,6 +134,7 @@ SkPath& SkPath::operator=(const SkPath& src) {
fFillType = src.fFillType;
fBoundsIsDirty = src.fBoundsIsDirty;
fConvexity = src.fConvexity;
+ fSegmentMask = src.fSegmentMask;
GEN_ID_INC;
}
SkDEBUGCODE(this->validate();)
@@ -135,8 +144,14 @@ SkPath& SkPath::operator=(const SkPath& src) {
bool operator==(const SkPath& a, const SkPath& b) {
// note: don't need to look at isConvex or bounds, since just comparing the
// raw data is sufficient.
+
+ // We explicitly check fSegmentMask as a quick-reject. We could skip it,
+ // since it is only a cache of info in the fVerbs, but its a fast way to
+ // notice a difference
+
return &a == &b ||
- (a.fFillType == b.fFillType && a.fVerbs == b.fVerbs && a.fPts == b.fPts);
+ (a.fFillType == b.fFillType && a.fSegmentMask == b.fSegmentMask &&
+ a.fVerbs == b.fVerbs && a.fPts == b.fPts);
}
void SkPath::swap(SkPath& other) {
@@ -149,11 +164,12 @@ void SkPath::swap(SkPath& other) {
SkTSwap<uint8_t>(fFillType, other.fFillType);
SkTSwap<uint8_t>(fBoundsIsDirty, other.fBoundsIsDirty);
SkTSwap<uint8_t>(fConvexity, other.fConvexity);
+ SkTSwap<uint8_t>(fSegmentMask, other.fSegmentMask);
GEN_ID_INC;
}
}
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
uint32_t SkPath::getGenerationID() const {
return fGenerationID;
}
@@ -167,6 +183,7 @@ void SkPath::reset() {
GEN_ID_INC;
fBoundsIsDirty = true;
fConvexity = kUnknown_Convexity;
+ fSegmentMask = 0;
}
void SkPath::rewind() {
@@ -175,22 +192,137 @@ void SkPath::rewind() {
fPts.rewind();
fVerbs.rewind();
GEN_ID_INC;
- fBoundsIsDirty = true;
fConvexity = kUnknown_Convexity;
+ fBoundsIsDirty = true;
+ fSegmentMask = 0;
}
bool SkPath::isEmpty() const {
SkDEBUGCODE(this->validate();)
-
+#if SK_OLD_EMPTY_PATH_BEHAVIOR
int count = fVerbs.count();
return count == 0 || (count == 1 && fVerbs[0] == kMove_Verb);
+#else
+ return 0 == fVerbs.count();
+#endif
}
-bool SkPath::isRect(SkRect*) const {
+/*
+ Determines if path is a rect by keeping track of changes in direction
+ and looking for a loop either clockwise or counterclockwise.
+
+ The direction is computed such that:
+ 0: vertical up
+ 1: horizontal right
+ 2: vertical down
+ 3: horizontal left
+
+A rectangle cycles up/right/down/left or up/left/down/right.
+
+The test fails if:
+ The path is closed, and followed by a line.
+ A second move creates a new endpoint.
+ A diagonal line is parsed.
+ There's more than four changes of direction.
+ There's a discontinuity on the line (e.g., a move in the middle)
+ The line reverses direction.
+ The rectangle doesn't complete a cycle.
+ The path contains a quadratic or cubic.
+ The path contains fewer than four points.
+ The final point isn't equal to the first point.
+
+It's OK if the path has:
+ Several colinear line segments composing a rectangle side.
+ Single points on the rectangle side.
+
+The direction takes advantage of the corners found since opposite sides
+must travel in opposite directions.
+
+FIXME: Allow colinear quads and cubics to be treated like lines.
+FIXME: If the API passes fill-only, return true if the filled stroke
+ is a rectangle, though the caller failed to close the path.
+ */
+bool SkPath::isRect(SkRect* rect) const {
SkDEBUGCODE(this->validate();)
- SkASSERT(!"unimplemented");
- return false;
+ int corners = 0;
+ SkPoint first, last;
+ first.set(0, 0);
+ last.set(0, 0);
+ int firstDirection = 0;
+ int lastDirection = 0;
+ int nextDirection = 0;
+ bool closedOrMoved = false;
+ bool autoClose = false;
+ const uint8_t* verbs = fVerbs.begin();
+ const uint8_t* verbStop = fVerbs.end();
+ const SkPoint* pts = fPts.begin();
+ while (verbs != verbStop) {
+ switch (*verbs++) {
+ case kClose_Verb:
+ pts = fPts.begin();
+ autoClose = true;
+ case kLine_Verb: {
+ SkScalar left = last.fX;
+ SkScalar top = last.fY;
+ SkScalar right = pts->fX;
+ SkScalar bottom = pts->fY;
+ ++pts;
+ if (left != right && top != bottom) {
+ return false; // diagonal
+ }
+ if (left == right && top == bottom) {
+ break; // single point on side OK
+ }
+ nextDirection = (left != right) << 0 |
+ (left < right || top < bottom) << 1;
+ if (0 == corners) {
+ firstDirection = nextDirection;
+ first = last;
+ last = pts[-1];
+ corners = 1;
+ closedOrMoved = false;
+ break;
+ }
+ if (closedOrMoved) {
+ return false; // closed followed by a line
+ }
+ closedOrMoved = autoClose;
+ if (lastDirection != nextDirection) {
+ if (++corners > 4) {
+ return false; // too many direction changes
+ }
+ }
+ last = pts[-1];
+ if (lastDirection == nextDirection) {
+ break; // colinear segment
+ }
+ // Possible values for corners are 2, 3, and 4.
+ // When corners == 3, nextDirection opposes firstDirection.
+ // Otherwise, nextDirection at corner 2 opposes corner 4.
+ int turn = firstDirection ^ (corners - 1);
+ int directionCycle = 3 == corners ? 0 : nextDirection ^ turn;
+ if ((directionCycle ^ turn) != nextDirection) {
+ return false; // direction didn't follow cycle
+ }
+ break;
+ }
+ case kQuad_Verb:
+ case kCubic_Verb:
+ return false; // quadratic, cubic not allowed
+ case kMove_Verb:
+ last = *pts++;
+ closedOrMoved = true;
+ break;
+ }
+ lastDirection = nextDirection;
+ }
+ // Success if 4 corners and first point equals last
+ bool result = 4 == corners && first == last;
+ if (result && rect) {
+ *rect = getBounds();
+ }
+ return result;
}
int SkPath::getPoints(SkPoint copy[], int max) const {
@@ -211,17 +343,20 @@ SkPoint SkPath::getPoint(int index) const {
return SkPoint::Make(0, 0);
}
-void SkPath::getLastPt(SkPoint* lastPt) const {
+bool SkPath::getLastPt(SkPoint* lastPt) const {
SkDEBUGCODE(this->validate();)
- if (lastPt) {
- int count = fPts.count();
- if (count == 0) {
- lastPt->set(0, 0);
- } else {
+ int count = fPts.count();
+ if (count > 0) {
+ if (lastPt) {
*lastPt = fPts[count - 1];
}
+ return true;
+ }
+ if (lastPt) {
+ lastPt->set(0, 0);
}
+ return false;
}
void SkPath::setLastPt(SkScalar x, SkScalar y) {
@@ -254,10 +389,10 @@ void SkPath::setConvexity(Convexity c) {
//////////////////////////////////////////////////////////////////////////////
// Construction methods
-#define DIRTY_AFTER_EDIT \
- do { \
- fBoundsIsDirty = true; \
- fConvexity = kUnknown_Convexity;\
+#define DIRTY_AFTER_EDIT \
+ do { \
+ fBoundsIsDirty = true; \
+ fConvexity = kUnknown_Convexity; \
} while (0)
void SkPath::incReserve(U16CPU inc) {
@@ -275,12 +410,17 @@ void SkPath::moveTo(SkScalar x, SkScalar y) {
int vc = fVerbs.count();
SkPoint* pt;
+#ifdef SK_OLD_EMPTY_PATH_BEHAVIOR
if (vc > 0 && fVerbs[vc - 1] == kMove_Verb) {
pt = &fPts[fPts.count() - 1];
} else {
pt = fPts.append();
*fVerbs.append() = kMove_Verb;
}
+#else
+ pt = fPts.append();
+ *fVerbs.append() = kMove_Verb;
+#endif
pt->set(x, y);
GEN_ID_INC;
@@ -302,6 +442,7 @@ void SkPath::lineTo(SkScalar x, SkScalar y) {
}
fPts.append()->set(x, y);
*fVerbs.append() = kLine_Verb;
+ fSegmentMask |= kLine_SegmentMask;
GEN_ID_INC;
DIRTY_AFTER_EDIT;
@@ -325,6 +466,7 @@ void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
pts[0].set(x1, y1);
pts[1].set(x2, y2);
*fVerbs.append() = kQuad_Verb;
+ fSegmentMask |= kQuad_SegmentMask;
GEN_ID_INC;
DIRTY_AFTER_EDIT;
@@ -349,6 +491,7 @@ void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
pts[1].set(x2, y2);
pts[2].set(x3, y3);
*fVerbs.append() = kCubic_Verb;
+ fSegmentMask |= kCubic_SegmentMask;
GEN_ID_INC;
DIRTY_AFTER_EDIT;
@@ -371,11 +514,14 @@ void SkPath::close() {
case kLine_Verb:
case kQuad_Verb:
case kCubic_Verb:
+#ifndef SK_OLD_EMPTY_PATH_BEHAVIOR
+ case kMove_Verb:
+#endif
*fVerbs.append() = kClose_Verb;
GEN_ID_INC;
break;
default:
- // don't add a close if the prev wasn't a primitive
+ // don't add a close if it's the first verb or a repeat
break;
}
}
@@ -512,7 +658,7 @@ static void add_corner_arc(SkPath* path, const SkRect& rect,
break;
case 180: r.offset(rect.fLeft - r.fLeft, rect.fTop - r.fTop); break;
case 270: r.offset(rect.fRight - r.fRight, rect.fTop - r.fTop); break;
- default: SkASSERT(!"unexpected startAngle in add_corner_arc");
+ default: SkDEBUGFAIL("unexpected startAngle in add_corner_arc");
}
SkScalar start = SkIntToScalar(startAngle);
@@ -789,7 +935,7 @@ void SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy) {
void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) {
this->incReserve(path.fPts.count());
- Iter iter(path, false);
+ RawIter iter(path);
SkPoint pts[4];
Verb verb;
@@ -817,7 +963,7 @@ void SkPath::addPath(const SkPath& path, const SkMatrix& matrix) {
this->close();
break;
default:
- SkASSERT(!"unknown verb");
+ SkDEBUGFAIL("unknown verb");
}
}
}
@@ -899,13 +1045,60 @@ void SkPath::reversePathTo(const SkPath& path) {
pts[-3].fX, pts[-3].fY);
break;
default:
- SkASSERT(!"bad verb");
+ SkDEBUGFAIL("bad verb");
break;
}
pts -= gPtsInVerb[verbs[i]];
}
}
+void SkPath::reverseAddPath(const SkPath& src) {
+ this->incReserve(src.fPts.count());
+
+ const SkPoint* startPts = src.fPts.begin();
+ const SkPoint* pts = src.fPts.end();
+ const uint8_t* startVerbs = src.fVerbs.begin();
+ const uint8_t* verbs = src.fVerbs.end();
+
+ bool needMove = true;
+ bool needClose = false;
+ while (verbs > startVerbs) {
+ uint8_t v = *--verbs;
+ int n = gPtsInVerb[v];
+
+ if (needMove) {
+ --pts;
+ this->moveTo(pts->fX, pts->fY);
+ needMove = false;
+ }
+ pts -= n;
+ switch (v) {
+ case kMove_Verb:
+ if (needClose) {
+ this->close();
+ needClose = false;
+ }
+ needMove = true;
+ pts += 1; // so we see the point in "if (needMove)" above
+ break;
+ case kLine_Verb:
+ this->lineTo(pts[0]);
+ break;
+ case kQuad_Verb:
+ this->quadTo(pts[1], pts[0]);
+ break;
+ case kCubic_Verb:
+ this->cubicTo(pts[2], pts[1], pts[0]);
+ break;
+ case kClose_Verb:
+ needClose = true;
+ break;
+ default:
+ SkASSERT(!"unexpected verb");
+ }
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
void SkPath::offset(SkScalar dx, SkScalar dy, SkPath* dst) const {
@@ -975,7 +1168,7 @@ void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const {
tmp.close();
break;
default:
- SkASSERT(!"unknown verb");
+ SkDEBUGFAIL("unknown verb");
break;
}
}
@@ -998,6 +1191,8 @@ void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const {
dst->fVerbs = fVerbs;
dst->fPts.setCount(fPts.count());
dst->fFillType = fFillType;
+ dst->fSegmentMask = fSegmentMask;
+ dst->fConvexity = fConvexity;
}
matrix.mapPoints(dst->fPts.begin(), fPts.begin(), fPts.count());
SkDEBUGCODE(dst->validate();)
@@ -1007,17 +1202,20 @@ void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const {
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
-enum NeedMoveToState {
- kAfterClose_NeedMoveToState,
- kAfterCons_NeedMoveToState,
- kAfterPrefix_NeedMoveToState
+enum SegmentState {
+ kAfterClose_SegmentState, // We will need a move next, but we have a
+ // previous close pt to use for the new move.
+ kAfterMove_SegmentState, // We have seen a move, but nothing else.
+ kAfterPrimitive_SegmentState // We have seen a primitive but not yet
+ // closed the path. Also the initial state.
};
SkPath::Iter::Iter() {
#ifdef SK_DEBUG
fPts = NULL;
fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0;
- fForceClose = fNeedMoveTo = fCloseLine = false;
+ fForceClose = fCloseLine = false;
+ fSegmentState = kAfterPrimitive_SegmentState;
#endif
// need to init enough to make next() harmlessly return kDone_Verb
fVerbs = NULL;
@@ -1033,9 +1231,11 @@ void SkPath::Iter::setPath(const SkPath& path, bool forceClose) {
fPts = path.fPts.begin();
fVerbs = path.fVerbs.begin();
fVerbStop = path.fVerbs.end();
+ fLastPt.fX = fLastPt.fY = 0;
+ fMoveTo.fX = fMoveTo.fY = 0;
fForceClose = SkToU8(forceClose);
fNeedClose = false;
- fNeedMoveTo = kAfterPrefix_NeedMoveToState;
+ fSegmentState = kAfterClose_SegmentState;
}
bool SkPath::Iter::isClosedContour() const {
@@ -1082,28 +1282,34 @@ SkPath::Verb SkPath::Iter::autoClose(SkPoint pts[2]) {
fLastPt = fMoveTo;
fCloseLine = true;
return kLine_Verb;
+ } else {
+ pts[0] = fMoveTo;
+ return kClose_Verb;
}
- return kClose_Verb;
}
bool SkPath::Iter::cons_moveTo(SkPoint pts[1]) {
- if (fNeedMoveTo == kAfterClose_NeedMoveToState) {
+ if (fSegmentState == kAfterClose_SegmentState) {
+ // We have closed a curve and have a primitive, so we need a move.
+ // Set the first return pt to the most recent move pt
if (pts) {
*pts = fMoveTo;
}
fNeedClose = fForceClose;
- fNeedMoveTo = kAfterCons_NeedMoveToState;
- fVerbs -= 1;
+ fSegmentState = kAfterMove_SegmentState;
+ fVerbs -= 1; // Step back to see the primitive again
return true;
}
- if (fNeedMoveTo == kAfterCons_NeedMoveToState) {
+ if (fSegmentState == kAfterMove_SegmentState) {
+ // Set the first return pt to the move pt
if (pts) {
*pts = fMoveTo;
}
- fNeedMoveTo = kAfterPrefix_NeedMoveToState;
+ fSegmentState = kAfterPrimitive_SegmentState;
} else {
- SkASSERT(fNeedMoveTo == kAfterPrefix_NeedMoveToState);
+ SkASSERT(fSegmentState == kAfterPrimitive_SegmentState);
+ // Set the first return pt to the last pt of the previous primitive.
if (pts) {
*pts = fPts[-1];
}
@@ -1111,9 +1317,93 @@ bool SkPath::Iter::cons_moveTo(SkPoint pts[1]) {
return false;
}
+void SkPath::Iter::consumeDegenerateSegments() {
+ // We need to step over anything that will not move the current draw point
+ // forward before the next move is seen
+ const uint8_t* lastMoveVerb = 0;
+ const SkPoint* lastMovePt = 0;
+ SkPoint lastPt = fLastPt;
+ while (fVerbs != fVerbStop) {
+ unsigned verb = *fVerbs;
+ switch (verb) {
+ case kMove_Verb:
+ // Keep a record of this most recent move
+ lastMoveVerb = fVerbs;
+ lastMovePt = fPts;
+ lastPt = fPts[0];
+ fVerbs++;
+ fPts++;
+ break;
+
+ case kClose_Verb:
+ // A close when we are in a segment is always valid
+ if (fSegmentState == kAfterPrimitive_SegmentState) {
+ return;
+ }
+ // A close at any other time must be ignored
+ fVerbs++;
+ break;
+
+ case kLine_Verb:
+ if (!IsLineDegenerate(lastPt, fPts[0])) {
+ if (lastMoveVerb) {
+ fVerbs = lastMoveVerb;
+ fPts = lastMovePt;
+ return;
+ }
+ return;
+ }
+ // Ignore this line and continue
+ fVerbs++;
+ fPts++;
+ break;
+
+ case kQuad_Verb:
+ if (!IsQuadDegenerate(lastPt, fPts[0], fPts[1])) {
+ if (lastMoveVerb) {
+ fVerbs = lastMoveVerb;
+ fPts = lastMovePt;
+ return;
+ }
+ return;
+ }
+ // Ignore this line and continue
+ fVerbs++;
+ fPts += 2;
+ break;
+
+ case kCubic_Verb:
+ if (!IsCubicDegenerate(lastPt, fPts[0], fPts[1], fPts[2])) {
+ if (lastMoveVerb) {
+ fVerbs = lastMoveVerb;
+ fPts = lastMovePt;
+ return;
+ }
+ return;
+ }
+ // Ignore this line and continue
+ fVerbs++;
+ fPts += 3;
+ break;
+
+ default:
+ SkDEBUGFAIL("Should never see kDone_Verb");
+ }
+ }
+}
+
SkPath::Verb SkPath::Iter::next(SkPoint pts[4]) {
+#ifndef SK_OLD_EMPTY_PATH_BEHAVIOR
+ this->consumeDegenerateSegments();
+#endif
+
if (fVerbs == fVerbStop) {
+ // Close the curve if requested and if there is some curve to close
+#ifdef SK_OLD_EMPTY_PATH_BEHAVIOR
if (fNeedClose) {
+#else
+ if (fNeedClose && fSegmentState == kAfterPrimitive_SegmentState) {
+#endif
if (kLine_Verb == this->autoClose(pts)) {
return kLine_Verb;
}
@@ -1144,7 +1434,10 @@ SkPath::Verb SkPath::Iter::next(SkPoint pts[4]) {
pts[0] = *srcPts;
}
srcPts += 1;
- fNeedMoveTo = kAfterCons_NeedMoveToState;
+ fSegmentState = kAfterMove_SegmentState;
+#ifndef SK_OLD_EMPTY_PATH_BEHAVIOR
+ fLastPt = fMoveTo;
+#endif
fNeedClose = fForceClose;
break;
case kLine_Verb:
@@ -1184,8 +1477,15 @@ SkPath::Verb SkPath::Iter::next(SkPoint pts[4]) {
fVerbs -= 1;
} else {
fNeedClose = false;
+#ifndef SK_OLD_EMPTY_PATH_BEHAVIOR
+ fSegmentState = kAfterClose_SegmentState;
+#endif
}
- fNeedMoveTo = kAfterClose_NeedMoveToState;
+#ifdef SK_OLD_EMPTY_PATH_BEHAVIOR
+ fSegmentState = kAfterClose_SegmentState;
+#else
+ fLastPt = fMoveTo;
+#endif
break;
}
fPts = srcPts;
@@ -1194,89 +1494,82 @@ SkPath::Verb SkPath::Iter::next(SkPoint pts[4]) {
///////////////////////////////////////////////////////////////////////////////
-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;
+SkPath::RawIter::RawIter() {
+#ifdef SK_DEBUG
+ fPts = NULL;
+ fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0;
+#endif
+ // need to init enough to make next() harmlessly return kDone_Verb
+ fVerbs = NULL;
+ fVerbStop = NULL;
}
-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]);
- }
+SkPath::RawIter::RawIter(const SkPath& path) {
+ this->setPath(path);
}
-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::RawIter::setPath(const SkPath& path) {
+ fPts = path.fPts.begin();
+ fVerbs = path.fVerbs.begin();
+ fVerbStop = path.fVerbs.end();
+ fMoveTo.fX = fMoveTo.fY = 0;
+ fLastPt.fX = fLastPt.fY = 0;
}
-void SkPath::subdivide(SkScalar dist, bool bendLines, SkPath* dst) const {
- SkPath tmpPath;
- if (NULL == dst || this == dst) {
- dst = &tmpPath;
+SkPath::Verb SkPath::RawIter::next(SkPoint pts[4]) {
+ if (fVerbs == fVerbStop) {
+ return kDone_Verb;
}
- SkPath::Iter iter(*this, false);
- SkPoint pts[4];
+ unsigned verb = *fVerbs++;
+ const SkPoint* srcPts = fPts;
- 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);
+ switch (verb) {
+ case kMove_Verb:
+ if (pts) {
+ pts[0] = *srcPts;
+ }
+ fMoveTo = srcPts[0];
+ fLastPt = fMoveTo;
+ srcPts += 1;
+ break;
+ case kLine_Verb:
+ if (pts) {
+ pts[0] = fLastPt;
+ pts[1] = srcPts[0];
+ }
+ fLastPt = srcPts[0];
+ srcPts += 1;
+ break;
+ case kQuad_Verb:
+ if (pts) {
+ pts[0] = fLastPt;
+ memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint));
+ }
+ fLastPt = srcPts[1];
+ srcPts += 2;
+ break;
+ case kCubic_Verb:
+ if (pts) {
+ pts[0] = fLastPt;
+ memcpy(&pts[1], srcPts, 3 * sizeof(SkPoint));
+ }
+ fLastPt = srcPts[2];
+ srcPts += 3;
+ break;
+ case kClose_Verb:
+ fLastPt = fMoveTo;
+ if (pts) {
+ pts[0] = fMoveTo;
+ }
+ break;
}
+ fPts = srcPts;
+ return (Verb)verb;
}
-///////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
/*
Format in flattened buffer: [ptCount, verbCount, pts[], verbs[]]
*/
@@ -1286,7 +1579,7 @@ void SkPath::flatten(SkWriter32& buffer) const {
buffer.write32(fPts.count());
buffer.write32(fVerbs.count());
- buffer.write32(fFillType);
+ buffer.write32((fFillType << 8) | fSegmentMask);
buffer.writeMul4(fPts.begin(), sizeof(SkPoint) * fPts.count());
buffer.writePad(fVerbs.begin(), fVerbs.count());
}
@@ -1294,7 +1587,9 @@ void SkPath::flatten(SkWriter32& buffer) const {
void SkPath::unflatten(SkReader32& buffer) {
fPts.setCount(buffer.readS32());
fVerbs.setCount(buffer.readS32());
- fFillType = buffer.readS32();
+ uint32_t packed = buffer.readS32();
+ fFillType = packed >> 8;
+ fSegmentMask = packed & 0xFF;
buffer.read(fPts.begin(), sizeof(SkPoint) * fPts.count());
buffer.read(fVerbs.begin(), fVerbs.count());
@@ -1305,7 +1600,6 @@ void SkPath::unflatten(SkReader32& buffer) {
}
///////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
void SkPath::dump(bool forceClose, const char title[]) const {
Iter iter(*this, forceClose);
@@ -1389,29 +1683,40 @@ void SkPath::validate() const {
SkASSERT(bounds.isEmpty());
SkASSERT(fBounds.isEmpty());
} else {
- fBounds.contains(bounds);
+ if (bounds.isEmpty()) {
+ SkASSERT(fBounds.isEmpty());
+ } else {
+ if (!fBounds.isEmpty()) {
+ SkASSERT(fBounds.contains(bounds));
+ }
+ }
+ }
+ }
+
+ uint32_t mask = 0;
+ for (int i = 0; i < fVerbs.count(); i++) {
+ switch (fVerbs[i]) {
+ case kLine_Verb:
+ mask |= kLine_SegmentMask;
+ break;
+ case kQuad_Verb:
+ mask |= kQuad_SegmentMask;
+ break;
+ case kCubic_Verb:
+ mask |= kCubic_SegmentMask;
}
}
+ SkASSERT(mask == fSegmentMask);
}
#endif
///////////////////////////////////////////////////////////////////////////////
-/**
- * Returns -1 || 0 || 1 depending on the sign of value:
- * -1 if value < 0
- * 0 if vlaue == 0
- * 1 if value > 0
- */
-static int SkScalarSign(SkScalar value) {
- return value < 0 ? -1 : (value > 0);
-}
-
static int sign(SkScalar x) { return x < 0; }
#define kValueNeverReturnedBySign 2
static int CrossProductSign(const SkVector& a, const SkVector& b) {
- return SkScalarSign(SkPoint::CrossProduct(a, b));
+ return SkScalarSignAsInt(SkPoint::CrossProduct(a, b));
}
// only valid for a single contour
@@ -1518,7 +1823,7 @@ SkPath::Convexity SkPath::ComputeConvexity(const SkPath& path) {
count = 0;
break;
default:
- SkASSERT(!"bad verb");
+ SkDEBUGFAIL("bad verb");
return kConcave_Convexity;
}
@@ -1532,3 +1837,160 @@ SkPath::Convexity SkPath::ComputeConvexity(const SkPath& path) {
}
return state.getConvexity();
}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class ContourIter {
+public:
+ ContourIter(const SkTDArray<uint8_t>& verbs, const SkTDArray<SkPoint>& pts);
+
+ bool done() const { return fDone; }
+ // if !done() then these may be called
+ int count() const { return fCurrPtCount; }
+ const SkPoint* pts() const { return fCurrPt; }
+ void next();
+
+private:
+ int fCurrPtCount;
+ const SkPoint* fCurrPt;
+ const uint8_t* fCurrVerb;
+ const uint8_t* fStopVerbs;
+ bool fDone;
+ SkDEBUGCODE(int fContourCounter;)
+};
+
+ContourIter::ContourIter(const SkTDArray<uint8_t>& verbs,
+ const SkTDArray<SkPoint>& pts) {
+ fStopVerbs = verbs.begin() + verbs.count();
+
+ fDone = false;
+ fCurrPt = pts.begin();
+ fCurrVerb = verbs.begin();
+ fCurrPtCount = 0;
+ SkDEBUGCODE(fContourCounter = 0;)
+ this->next();
+}
+
+void ContourIter::next() {
+ if (fCurrVerb >= fStopVerbs) {
+ fDone = true;
+ }
+ if (fDone) {
+ return;
+ }
+
+ // skip pts of prev contour
+ fCurrPt += fCurrPtCount;
+
+ SkASSERT(SkPath::kMove_Verb == fCurrVerb[0]);
+ int ptCount = 1; // moveTo
+ const uint8_t* verbs = fCurrVerb;
+
+ for (++verbs; verbs < fStopVerbs; ++verbs) {
+ switch (*verbs) {
+ case SkPath::kMove_Verb:
+ goto CONTOUR_END;
+ case SkPath::kLine_Verb:
+ ptCount += 1;
+ break;
+ case SkPath::kQuad_Verb:
+ ptCount += 2;
+ break;
+ case SkPath::kCubic_Verb:
+ ptCount += 3;
+ break;
+ default: // kClose_Verb, just keep going
+ break;
+ }
+ }
+CONTOUR_END:
+ fCurrPtCount = ptCount;
+ fCurrVerb = verbs;
+ SkDEBUGCODE(++fContourCounter;)
+}
+
+static SkScalar cross_prod(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
+ return SkPoint::CrossProduct(p1 - p0, p2 - p0);
+}
+
+static int find_max_y(const SkPoint pts[], int count) {
+ SkASSERT(count > 0);
+ SkScalar max = pts[0].fY;
+ int maxIndex = 0;
+ for (int i = 1; i < count; ++i) {
+ if (pts[i].fY > max) {
+ max = pts[i].fY;
+ maxIndex = i;
+ }
+ }
+ return maxIndex;
+}
+
+static int find_diff_pt(const SkPoint pts[], int index, int n, int inc) {
+ int i = index;
+ for (;;) {
+ i = (i + inc) % n;
+ if (i == index) { // we wrapped around, so abort
+ break;
+ }
+ if (pts[index] != pts[i]) { // found a different point, success!
+ break;
+ }
+ }
+ return i;
+}
+
+bool SkPath::cheapComputeDirection(Direction* dir) const {
+ // don't want to pay the cost for computing this if it
+ // is unknown, so we don't call isConvex()
+ const Convexity conv = this->getConvexityOrUnknown();
+
+ ContourIter iter(fVerbs, fPts);
+
+ for (; !iter.done(); iter.next()) {
+ int n = iter.count();
+ if (n < 3) {
+ continue;
+ }
+
+ const SkPoint* pts = iter.pts();
+ SkScalar cross = 0;
+ if (kConvex_Convexity == conv) {
+ // we loop, skipping over degenerate or flat segments that will
+ // return 0 for the cross-product
+ for (int i = 0; i < n - 2; ++i) {
+ cross = cross_prod(pts[i], pts[i + 1], pts[i + 2]);
+ if (cross) {
+ break;
+ }
+ }
+ } else {
+ int index = find_max_y(pts, n);
+ // Find a next and prev index to use for the cross-product test,
+ // but we try to find pts that form non-zero vectors from pts[index]
+ //
+ // Its possible that we can't find two non-degenerate vectors, so
+ // we have to guard our search (e.g. all the pts could be in the
+ // same place).
+
+ // we pass n - 1 instead of -1 so we don't foul up % operator by
+ // passing it a negative LH argument.
+ int prev = find_diff_pt(pts, index, n, n - 1);
+ if (prev == index) {
+ // completely degenerate, skip to next contour
+ continue;
+ }
+ int next = find_diff_pt(pts, index, n, 1);
+ SkASSERT(next != index);
+ cross = cross_prod(pts[prev], pts[index], pts[next]);
+ }
+ if (cross) {
+ if (dir) {
+ *dir = cross > 0 ? kCW_Direction : kCCW_Direction;
+ }
+ return true;
+ }
+ }
+ return false; // unknown
+}
+
diff --git a/src/core/SkPathEffect.cpp b/src/core/SkPathEffect.cpp
index c3a24fc..3e017e2 100644
--- a/src/core/SkPathEffect.cpp
+++ b/src/core/SkPathEffect.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkPathEffect.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkPathEffect.h"
#include "SkPath.h"
@@ -30,8 +22,8 @@ SkPairPathEffect::SkPairPathEffect(SkPathEffect* pe0, SkPathEffect* pe1)
}
SkPairPathEffect::~SkPairPathEffect() {
- fPE0->unref();
- fPE1->unref();
+ SkSafeUnref(fPE0);
+ SkSafeUnref(fPE1);
}
/*
@@ -45,12 +37,18 @@ void SkPairPathEffect::flatten(SkFlattenableWriteBuffer& buffer) {
SkPairPathEffect::SkPairPathEffect(SkFlattenableReadBuffer& buffer) {
fPE0 = (SkPathEffect*)buffer.readFlattenable();
fPE1 = (SkPathEffect*)buffer.readFlattenable();
+ // either of these may fail, so we have to check for nulls later on
}
///////////////////////////////////////////////////////////////////////////////
bool SkComposePathEffect::filterPath(SkPath* dst, const SkPath& src,
SkScalar* width) {
+ // we may have failed to unflatten these, so we have to check
+ if (!fPE0 || !fPE1) {
+ return false;
+ }
+
SkPath tmp;
const SkPath* ptr = &src;
@@ -134,3 +132,11 @@ SkStrokePathEffect::SkStrokePathEffect(SkFlattenableReadBuffer& buffer) {
fCap = buffer.readU8();
}
+///////////////////////////////////////////////////////////////////////////////
+
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkPathEffect)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposePathEffect)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkStrokePathEffect)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSumPathEffect)
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
+
diff --git a/src/core/SkPathHeap.cpp b/src/core/SkPathHeap.cpp
index f6dae5d..9bf77c1 100644
--- a/src/core/SkPathHeap.cpp
+++ b/src/core/SkPathHeap.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkPathHeap.h"
#include "SkPath.h"
#include "SkStream.h"
diff --git a/src/core/SkPathHeap.h b/src/core/SkPathHeap.h
index 1a0023c..99c2626 100644
--- a/src/core/SkPathHeap.h
+++ b/src/core/SkPathHeap.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkPathHeap_DEFINED
#define SkPathHeap_DEFINED
diff --git a/src/core/SkPathMeasure.cpp b/src/core/SkPathMeasure.cpp
index 99bdece..3158925 100644
--- a/src/core/SkPathMeasure.cpp
+++ b/src/core/SkPathMeasure.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006-2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkPathMeasure.h"
#include "SkGeometry.h"
#include "SkPath.h"
@@ -277,7 +270,7 @@ static void compute_pos_tan(const SkPath& path, int firstPtIndex, int ptIndex,
}
break;
default:
- SkASSERT(!"unknown segType");
+ SkDEBUGFAIL("unknown segType");
}
}
@@ -348,7 +341,7 @@ static void seg_to(const SkPath& src, int firstPtIndex, int ptIndex,
}
break;
default:
- SkASSERT(!"unknown segType");
+ SkDEBUGFAIL("unknown segType");
sk_throw();
}
}
diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp
index c199cae..a3b7396 100644
--- a/src/core/SkPicture.cpp
+++ b/src/core/SkPicture.cpp
@@ -1,19 +1,11 @@
+
/*
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+ * Copyright 2007 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkPictureFlat.h"
#include "SkPicturePlayback.h"
diff --git a/src/core/SkPictureFlat.cpp b/src/core/SkPictureFlat.cpp
index 105df3c..1058526 100644
--- a/src/core/SkPictureFlat.cpp
+++ b/src/core/SkPictureFlat.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkPictureFlat.h"
#include "SkColorFilter.h"
diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h
index 4db61f7..983bfc5 100644
--- a/src/core/SkPictureFlat.h
+++ b/src/core/SkPictureFlat.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkPictureFlat_DEFINED
#define SkPictureFlat_DEFINED
@@ -17,6 +24,7 @@ enum DrawType {
CONCAT,
DRAW_BITMAP,
DRAW_BITMAP_MATRIX,
+ DRAW_BITMAP_NINE,
DRAW_BITMAP_RECT,
DRAW_CLEAR,
DRAW_DATA,
@@ -29,7 +37,6 @@ enum DrawType {
DRAW_POS_TEXT_H,
DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H
DRAW_RECT,
- DRAW_SHAPE,
DRAW_SPRITE,
DRAW_TEXT,
DRAW_TEXT_ON_PATH,
@@ -51,6 +58,25 @@ enum DrawVertexFlags {
DRAW_VERTICES_HAS_INDICES = 0x04
};
+///////////////////////////////////////////////////////////////////////////////
+// clipparams are packed in 5 bits
+// doAA:1 | regionOp:4
+
+static inline uint32_t ClipParams_pack(SkRegion::Op op, bool doAA) {
+ unsigned doAABit = doAA ? 1 : 0;
+ return (doAABit << 4) | op;
+}
+
+static inline SkRegion::Op ClipParams_unpackRegionOp(uint32_t packed) {
+ return (SkRegion::Op)(packed & 0xF);
+}
+
+static inline bool ClipParams_unpackDoAA(uint32_t packed) {
+ return SkToBool((packed >> 4) & 1);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
class SkRefCntPlayback {
public:
SkRefCntPlayback();
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index 5a856ef..c2082c7 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkPicturePlayback.h"
#include "SkPictureRecord.h"
#include "SkTypeface.h"
@@ -120,17 +127,6 @@ SkPicturePlayback::SkPicturePlayback(const SkPictureRecord& record) {
}
}
- const SkTDArray<SkShape* >& shapes = record.getShapes();
- fShapeCount = shapes.count();
- if (fShapeCount > 0) {
- fShapes = SkNEW_ARRAY(SkShape*, fShapeCount);
- for (int i = 0; i < fShapeCount; i++) {
- SkShape* s = shapes[i];
- SkSafeRef(s);
- fShapes[i] = s;
- }
- }
-
const SkTDArray<const SkFlatRegion* >& regions = record.getRegions();
fRegionCount = regions.count();
if (fRegionCount > 0) {
@@ -203,14 +199,6 @@ SkPicturePlayback::SkPicturePlayback(const SkPicturePlayback& src) {
fPictureRefs[i]->ref();
}
- fShapeCount = src.fShapeCount;
- fShapes = SkNEW_ARRAY(SkShape*, fShapeCount);
- for (int i = 0; i < fShapeCount; i++) {
- SkShape* s = src.fShapes[i];
- SkSafeRef(s);
- fShapes[i] = s;
- }
-
fRegionCount = src.fRegionCount;
fRegions = SkNEW_ARRAY(SkRegion, fRegionCount);
for (i = 0; i < fRegionCount; i++) {
@@ -224,10 +212,9 @@ void SkPicturePlayback::init() {
fPaints = NULL;
fPathHeap = NULL;
fPictureRefs = NULL;
- fShapes = NULL;
fRegions = NULL;
fBitmapCount = fMatrixCount = fPaintCount = fPictureCount =
- fRegionCount = fShapeCount = 0;
+ fRegionCount = 0;
fFactoryPlayback = NULL;
}
@@ -247,11 +234,6 @@ SkPicturePlayback::~SkPicturePlayback() {
}
SkDELETE_ARRAY(fPictureRefs);
- for (int i = 0; i < fShapeCount; i++) {
- SkSafeUnref(fShapes[i]);
- }
- SkDELETE_ARRAY(fShapes);
-
SkDELETE(fFactoryPlayback);
}
@@ -281,7 +263,6 @@ void SkPicturePlayback::dumpSize() const {
#define PICT_PAINT_TAG SkSetFourByteTag('p', 'n', 't', ' ')
#define PICT_PATH_TAG SkSetFourByteTag('p', 't', 'h', ' ')
#define PICT_REGION_TAG SkSetFourByteTag('r', 'g', 'n', ' ')
-#define PICT_SHAPE_TAG SkSetFourByteTag('s', 'h', 'p', ' ')
#include "SkStream.h"
@@ -378,11 +359,6 @@ void SkPicturePlayback::serialize(SkWStream* stream) const {
buffer.writePad(storage.get(), size);
}
- writeTagSize(buffer, PICT_SHAPE_TAG, fShapeCount);
- for (i = 0; i < fShapeCount; i++) {
- buffer.writeFlattenable(fShapes[i]);
- }
-
// now we can write to the stream again
writeFactories(stream, factSet);
@@ -491,12 +467,6 @@ SkPicturePlayback::SkPicturePlayback(SkStream* stream) {
SkDEBUGCODE(uint32_t bytes =) fRegions[i].unflatten(buffer.skip(size));
SkASSERT(size == bytes);
}
-
- fShapeCount = readTagSize(buffer, PICT_SHAPE_TAG);
- fShapes = SkNEW_ARRAY(SkShape*, fShapeCount);
- for (i = 0; i < fShapeCount; i++) {
- fShapes[i] = reinterpret_cast<SkShape*>(buffer.readFlattenable());
- }
}
///////////////////////////////////////////////////////////////////////////////
@@ -528,7 +498,7 @@ void SkPicturePlayback::draw(SkCanvas& canvas) {
SkipClipRec skipRect, skipRegion, skipPath;
#endif
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
SkAutoMutexAcquire autoMutex(fDrawMutex);
#endif
@@ -539,10 +509,11 @@ void SkPicturePlayback::draw(SkCanvas& canvas) {
switch (fReader.readInt()) {
case CLIP_PATH: {
const SkPath& path = getPath();
- SkRegion::Op op = (SkRegion::Op) getInt();
+ uint32_t packed = getInt();
+ SkRegion::Op op = ClipParams_unpackRegionOp(packed);
+ bool doAA = ClipParams_unpackDoAA(packed);
size_t offsetToRestore = getInt();
- // HACK (false) until I can handle op==kReplace
- if (!canvas.clipPath(path, op)) {
+ if (!canvas.clipPath(path, op, doAA) && offsetToRestore) {
#ifdef SPEW_CLIP_SKIPPING
skipPath.recordSkip(offsetToRestore - fReader.offset());
#endif
@@ -551,9 +522,10 @@ void SkPicturePlayback::draw(SkCanvas& canvas) {
} break;
case CLIP_REGION: {
const SkRegion& region = getRegion();
- SkRegion::Op op = (SkRegion::Op) getInt();
+ uint32_t packed = getInt();
+ SkRegion::Op op = ClipParams_unpackRegionOp(packed);
size_t offsetToRestore = getInt();
- if (!canvas.clipRegion(region, op)) {
+ if (!canvas.clipRegion(region, op) && offsetToRestore) {
#ifdef SPEW_CLIP_SKIPPING
skipRegion.recordSkip(offsetToRestore - fReader.offset());
#endif
@@ -561,10 +533,12 @@ void SkPicturePlayback::draw(SkCanvas& canvas) {
}
} break;
case CLIP_RECT: {
- const SkRect* rect = fReader.skipRect();
- SkRegion::Op op = (SkRegion::Op) getInt();
+ const SkRect& rect = fReader.skipT<SkRect>();
+ uint32_t packed = getInt();
+ SkRegion::Op op = ClipParams_unpackRegionOp(packed);
+ bool doAA = ClipParams_unpackDoAA(packed);
size_t offsetToRestore = getInt();
- if (!canvas.clipRect(*rect, op)) {
+ if (!canvas.clipRect(rect, op, doAA) && offsetToRestore) {
#ifdef SPEW_CLIP_SKIPPING
skipRect.recordSkip(offsetToRestore - fReader.offset());
#endif
@@ -577,15 +551,15 @@ void SkPicturePlayback::draw(SkCanvas& canvas) {
case DRAW_BITMAP: {
const SkPaint* paint = getPaint();
const SkBitmap& bitmap = getBitmap();
- const SkPoint* loc = fReader.skipPoint();
- canvas.drawBitmap(bitmap, loc->fX, loc->fY, paint);
+ const SkPoint& loc = fReader.skipT<SkPoint>();
+ canvas.drawBitmap(bitmap, loc.fX, loc.fY, paint);
} break;
case DRAW_BITMAP_RECT: {
const SkPaint* paint = getPaint();
const SkBitmap& bitmap = getBitmap();
const SkIRect* src = this->getIRectPtr(); // may be null
- const SkRect* dst = fReader.skipRect(); // required
- canvas.drawBitmapRect(bitmap, src, *dst, paint);
+ const SkRect& dst = fReader.skipT<SkRect>(); // required
+ canvas.drawBitmapRect(bitmap, src, dst, paint);
} break;
case DRAW_BITMAP_MATRIX: {
const SkPaint* paint = getPaint();
@@ -593,6 +567,13 @@ void SkPicturePlayback::draw(SkCanvas& canvas) {
const SkMatrix* matrix = getMatrix();
canvas.drawBitmapMatrix(bitmap, *matrix, paint);
} break;
+ case DRAW_BITMAP_NINE: {
+ const SkPaint* paint = getPaint();
+ const SkBitmap& bitmap = getBitmap();
+ const SkIRect& src = fReader.skipT<SkIRect>();
+ const SkRect& dst = fReader.skipT<SkRect>();
+ canvas.drawBitmapNine(bitmap, src, dst, paint);
+ } break;
case DRAW_CLEAR:
canvas.clear(getInt());
break;
@@ -660,13 +641,7 @@ void SkPicturePlayback::draw(SkCanvas& canvas) {
} break;
case DRAW_RECT: {
const SkPaint& paint = *getPaint();
- canvas.drawRect(*fReader.skipRect(), paint);
- } break;
- case DRAW_SHAPE: {
- SkShape* shape = getShape();
- if (shape) {
- canvas.drawShape(shape);
- }
+ canvas.drawRect(fReader.skipT<SkRect>(), paint);
} break;
case DRAW_SPRITE: {
const SkPaint* paint = getPaint();
diff --git a/src/core/SkPicturePlayback.h b/src/core/SkPicturePlayback.h
index 350df78..88f86e2 100644
--- a/src/core/SkPicturePlayback.h
+++ b/src/core/SkPicturePlayback.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkPicturePlayback_DEFINED
#define SkPicturePlayback_DEFINED
@@ -11,9 +18,8 @@
#include "SkPathHeap.h"
#include "SkRegion.h"
#include "SkPictureFlat.h"
-#include "SkShape.h"
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
#include "SkThread.h"
#endif
@@ -78,12 +84,6 @@ private:
return *fPictureRefs[index - 1];
}
- SkShape* getShape() {
- int index = getInt();
- SkASSERT(index > 0 && index <= fShapeCount);
- return fShapes[index - 1];
- }
-
const SkPaint* getPaint() {
int index = getInt();
if (index == 0) {
@@ -95,7 +95,7 @@ private:
const SkRect* getRectPtr() {
if (fReader.readBool()) {
- return fReader.skipRect();
+ return &fReader.skipT<SkRect>();
} else {
return NULL;
}
@@ -103,7 +103,7 @@ private:
const SkIRect* getIRectPtr() {
if (fReader.readBool()) {
- return (const SkIRect*)fReader.skip(sizeof(SkIRect));
+ return &fReader.skipT<SkIRect>();
} else {
return NULL;
}
@@ -170,13 +170,11 @@ private:
SkPicture** fPictureRefs;
int fPictureCount;
- SkShape** fShapes;
- int fShapeCount;
SkRefCntPlayback fRCPlayback;
SkTypefacePlayback fTFPlayback;
SkFactoryPlayback* fFactoryPlayback;
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
SkMutex fDrawMutex;
#endif
};
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index 5810051..fd403cf 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -1,5 +1,11 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkPictureRecord.h"
-#include "SkShape.h"
#include "SkTSearch.h"
#define MIN_WRITER_SIZE 16384
@@ -122,45 +128,74 @@ void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
this->INHERITED::setMatrix(matrix);
}
-bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op) {
- addDraw(CLIP_RECT);
- addRect(rect);
- addInt(op);
+static bool regionOpExpands(SkRegion::Op op) {
+ switch (op) {
+ case SkRegion::kUnion_Op:
+ case SkRegion::kXOR_Op:
+ case SkRegion::kReverseDifference_Op:
+ case SkRegion::kReplace_Op:
+ return true;
+ case SkRegion::kIntersect_Op:
+ case SkRegion::kDifference_Op:
+ return false;
+ default:
+ SkDEBUGFAIL("unknown region op");
+ return false;
+ }
+}
+void SkPictureRecord::recordOffsetForRestore(SkRegion::Op op) {
+ if (regionOpExpands(op)) {
+ // Run back through any previous clip ops, and mark their offset to
+ // be 0, disabling their ability to trigger a jump-to-restore, otherwise
+ // they could hide this clips ability to expand the clip (i.e. go from
+ // empty to non-empty).
+ uint32_t offset = fRestoreOffsetStack.top();
+ while (offset) {
+ uint32_t* peek = fWriter.peek32(offset);
+ offset = *peek;
+ *peek = 0;
+ }
+ }
+
size_t offset = fWriter.size();
addInt(fRestoreOffsetStack.top());
fRestoreOffsetStack.top() = offset;
+}
+
+bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
+ addDraw(CLIP_RECT);
+ addRect(rect);
+ addInt(ClipParams_pack(op, doAA));
+
+ this->recordOffsetForRestore(op);
validate();
- return this->INHERITED::clipRect(rect, op);
+ return this->INHERITED::clipRect(rect, op, doAA);
}
-bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op) {
+bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
addDraw(CLIP_PATH);
addPath(path);
- addInt(op);
+ addInt(ClipParams_pack(op, doAA));
- size_t offset = fWriter.size();
- addInt(fRestoreOffsetStack.top());
- fRestoreOffsetStack.top() = offset;
+ this->recordOffsetForRestore(op);
validate();
if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
- return this->INHERITED::clipRect(path.getBounds(), op);
+ return this->INHERITED::clipRect(path.getBounds(), op, doAA);
} else {
- return this->INHERITED::clipPath(path, op);
+ return this->INHERITED::clipPath(path, op, doAA);
}
}
bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
addDraw(CLIP_REGION);
addRegion(region);
- addInt(op);
+ addInt(ClipParams_pack(op, false));
- size_t offset = fWriter.size();
- addInt(fRestoreOffsetStack.top());
- fRestoreOffsetStack.top() = offset;
+ this->recordOffsetForRestore(op);
validate();
return this->INHERITED::clipRegion(region, op);
@@ -223,7 +258,7 @@ void SkPictureRecord::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
}
void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
- const SkPaint* paint) {
+ const SkPaint* paint) {
addDraw(DRAW_BITMAP_MATRIX);
addPaintPtr(paint);
addBitmap(bitmap);
@@ -231,6 +266,16 @@ void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m
validate();
}
+void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
+ const SkRect& dst, const SkPaint* paint) {
+ addDraw(DRAW_BITMAP_NINE);
+ addPaintPtr(paint);
+ addBitmap(bitmap);
+ addIRect(center);
+ addRect(dst);
+ validate();
+}
+
void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
const SkPaint* paint = NULL) {
addDraw(DRAW_SPRITE);
@@ -382,20 +427,6 @@ void SkPictureRecord::drawPicture(SkPicture& picture) {
validate();
}
-void SkPictureRecord::drawShape(SkShape* shape) {
- addDraw(DRAW_SHAPE);
-
- int index = fShapes.find(shape);
- if (index < 0) { // not found
- index = fShapes.count();
- *fShapes.append() = shape;
- shape->ref();
- }
- // follow the convention of recording a 1-based index
- addInt(index + 1);
- validate();
-}
-
void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
const SkPoint vertices[], const SkPoint texs[],
const SkColor colors[], SkXfermode*,
@@ -447,7 +478,6 @@ void SkPictureRecord::reset() {
fPaints.reset();
fPictureRefs.unrefAll();
fRegions.reset();
- fShapes.safeUnrefAll();
fWriter.reset();
fHeap.reset();
@@ -532,6 +562,10 @@ void SkPictureRecord::addRectPtr(const SkRect* rect) {
}
}
+void SkPictureRecord::addIRect(const SkIRect& rect) {
+ fWriter.write(&rect, sizeof(rect));
+}
+
void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
if (fWriter.writeBool(rect != NULL)) {
*(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index 5a400cb..3c85b9b 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkPictureRecord_DEFINED
#define SkPictureRecord_DEFINED
@@ -14,50 +21,50 @@ public:
SkPictureRecord(uint32_t recordFlags);
virtual ~SkPictureRecord();
- // overrides from SkCanvas
- virtual int save(SaveFlags);
- virtual int saveLayer(const SkRect* bounds, const SkPaint*, SaveFlags);
- virtual void restore();
- virtual bool translate(SkScalar dx, SkScalar dy);
- virtual bool scale(SkScalar sx, SkScalar sy);
- virtual bool rotate(SkScalar degrees);
- virtual bool skew(SkScalar sx, SkScalar sy);
- virtual bool concat(const SkMatrix& matrix);
- virtual void setMatrix(const SkMatrix& matrix);
- virtual bool clipRect(const SkRect& rect, SkRegion::Op op);
- virtual bool clipPath(const SkPath& path, SkRegion::Op op);
- virtual bool clipRegion(const SkRegion& region, SkRegion::Op op);
- virtual void clear(SkColor);
- virtual void drawPaint(const SkPaint& paint);
+ virtual int save(SaveFlags) SK_OVERRIDE;
+ virtual int saveLayer(const SkRect* bounds, const SkPaint*, SaveFlags) SK_OVERRIDE;
+ virtual void restore() SK_OVERRIDE;
+ virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE;
+ virtual bool scale(SkScalar sx, SkScalar sy) SK_OVERRIDE;
+ virtual bool rotate(SkScalar degrees) SK_OVERRIDE;
+ virtual bool skew(SkScalar sx, SkScalar sy) SK_OVERRIDE;
+ virtual bool concat(const SkMatrix& matrix) SK_OVERRIDE;
+ virtual void setMatrix(const SkMatrix& matrix) SK_OVERRIDE;
+ virtual bool clipRect(const SkRect&, SkRegion::Op, bool) SK_OVERRIDE;
+ virtual bool clipPath(const SkPath&, SkRegion::Op, bool) SK_OVERRIDE;
+ virtual bool clipRegion(const SkRegion& region, SkRegion::Op op) SK_OVERRIDE;
+ virtual void clear(SkColor) SK_OVERRIDE;
+ virtual void drawPaint(const SkPaint& paint) SK_OVERRIDE;
virtual void drawPoints(PointMode, size_t count, const SkPoint pts[],
- const SkPaint&);
- virtual void drawRect(const SkRect& rect, const SkPaint&);
- virtual void drawPath(const SkPath& path, const SkPaint&);
+ const SkPaint&) SK_OVERRIDE;
+ virtual void drawRect(const SkRect& rect, const SkPaint&) SK_OVERRIDE;
+ virtual void drawPath(const SkPath& path, const SkPaint&) SK_OVERRIDE;
virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
- const SkPaint*);
+ const SkPaint*) SK_OVERRIDE;
virtual void drawBitmapRect(const SkBitmap&, const SkIRect* src,
- const SkRect& dst, const SkPaint*);
+ const SkRect& dst, const SkPaint*) SK_OVERRIDE;
virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&,
- const SkPaint*);
+ const SkPaint*) SK_OVERRIDE;
+ virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
+ const SkRect& dst, const SkPaint*) SK_OVERRIDE;
virtual void drawSprite(const SkBitmap&, int left, int top,
- const SkPaint*);
+ const SkPaint*) SK_OVERRIDE;
virtual void drawText(const void* text, size_t byteLength, SkScalar x,
- SkScalar y, const SkPaint&);
+ SkScalar y, const SkPaint&) SK_OVERRIDE;
virtual void drawPosText(const void* text, size_t byteLength,
- const SkPoint pos[], const SkPaint&);
+ const SkPoint pos[], const SkPaint&) SK_OVERRIDE;
virtual void drawPosTextH(const void* text, size_t byteLength,
- const SkScalar xpos[], SkScalar constY, const SkPaint&);
+ const SkScalar xpos[], SkScalar constY, const SkPaint&) SK_OVERRIDE;
virtual void drawTextOnPath(const void* text, size_t byteLength,
const SkPath& path, const SkMatrix* matrix,
- const SkPaint&);
- virtual void drawPicture(SkPicture& picture);
- virtual void drawShape(SkShape*);
+ const SkPaint&) SK_OVERRIDE;
+ virtual void drawPicture(SkPicture& picture) SK_OVERRIDE;
virtual void drawVertices(VertexMode, int vertexCount,
const SkPoint vertices[], const SkPoint texs[],
const SkColor colors[], SkXfermode*,
const uint16_t indices[], int indexCount,
- const SkPaint&);
- virtual void drawData(const void*, size_t);
+ const SkPaint&) SK_OVERRIDE;
+ virtual void drawData(const void*, size_t) SK_OVERRIDE;
void addFontMetricsTopBottom(const SkPaint& paint, SkScalar minY, SkScalar maxY);
@@ -73,9 +80,6 @@ public:
const SkTDArray<SkPicture* >& getPictureRefs() const {
return fPictureRefs;
}
- const SkTDArray<SkShape* >& getShapes() const {
- return fShapes;
- }
const SkTDArray<const SkFlatRegion* >& getRegions() const {
return fRegions;
}
@@ -113,6 +117,7 @@ private:
void addPoints(const SkPoint pts[], int count);
void addRect(const SkRect& rect);
void addRectPtr(const SkRect* rect);
+ void addIRect(const SkIRect& rect);
void addIRectPtr(const SkIRect* rect);
void addRegion(const SkRegion& region);
void addText(const void* text, size_t byteLength);
@@ -173,13 +178,15 @@ private:
// we ref each item in these arrays
SkTDArray<SkPicture*> fPictureRefs;
- SkTDArray<SkShape*> fShapes;
SkRefCntSet fRCSet;
SkRefCntSet fTFSet;
uint32_t fRecordFlags;
+ // helper function to handle save/restore culling offsets
+ void recordOffsetForRestore(SkRegion::Op op);
+
friend class SkPicturePlayback;
typedef SkCanvas INHERITED;
diff --git a/src/core/SkPixelRef.cpp b/src/core/SkPixelRef.cpp
index 967a872..1f28ae7 100644
--- a/src/core/SkPixelRef.cpp
+++ b/src/core/SkPixelRef.cpp
@@ -1,10 +1,18 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkPixelRef.h"
#include "SkFlattenable.h"
#include "SkThread.h"
static SkMutex gPixelRefMutex;
-extern int32_t SkNextPixelRefGenerationID() {
+extern int32_t SkNextPixelRefGenerationID();
+int32_t SkNextPixelRefGenerationID() {
static int32_t gPixelRefGenerationID;
// do a loop in case our global wraps around, as we never want to
// return a 0
@@ -63,6 +71,14 @@ void SkPixelRef::unlockPixels() {
}
}
+bool SkPixelRef::lockPixelsAreWritable() const {
+ return this->onLockPixelsAreWritable();
+}
+
+bool SkPixelRef::onLockPixelsAreWritable() const {
+ return true;
+}
+
uint32_t SkPixelRef::getGenerationID() const {
if (0 == fGenerationID) {
fGenerationID = SkNextPixelRefGenerationID();
@@ -121,7 +137,20 @@ void SkPixelRef::Register(const char name[], Factory factory) {
gCount += 1;
}
+#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS && defined(SK_DEBUG)
+static void report_no_entries(const char* functionName) {
+ if (!gCount) {
+ SkDebugf("%s has no registered name/factory pairs."
+ " Call SkGraphics::Init() at process initialization time.",
+ functionName);
+ }
+}
+#endif
+
SkPixelRef::Factory SkPixelRef::NameToFactory(const char name[]) {
+#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS && defined(SK_DEBUG)
+ report_no_entries(__FUNCTION__);
+#endif
const Pair* pairs = gPairs;
for (int i = gCount - 1; i >= 0; --i) {
if (strcmp(pairs[i].fName, name) == 0) {
@@ -132,6 +161,9 @@ SkPixelRef::Factory SkPixelRef::NameToFactory(const char name[]) {
}
const char* SkPixelRef::FactoryToName(Factory fact) {
+#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS && defined(SK_DEBUG)
+ report_no_entries(__FUNCTION__);
+#endif
const Pair* pairs = gPairs;
for (int i = gCount - 1; i >= 0; --i) {
if (pairs[i].fFactory == fact) {
@@ -143,7 +175,7 @@ const char* SkPixelRef::FactoryToName(Factory fact) {
///////////////////////////////////////////////////////////////////////////////
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
void SkPixelRef::globalRef(void* data) {
this->ref();
}
diff --git a/src/core/SkPoint.cpp b/src/core/SkPoint.cpp
index b5941d5..5747504 100644
--- a/src/core/SkPoint.cpp
+++ b/src/core/SkPoint.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006-2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2008 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkPoint.h"
void SkIPoint::rotateCW(SkIPoint* dst) const {
@@ -82,8 +75,6 @@ void SkPoint::scale(SkScalar scale, SkPoint* dst) const {
dst->set(SkScalarMul(fX, scale), SkScalarMul(fY, scale));
}
-#define kNearlyZero (SK_Scalar1 / 8092)
-
bool SkPoint::normalize() {
return this->setLength(fX, fY, SK_Scalar1);
}
@@ -96,29 +87,34 @@ 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);
-}
-
SkScalar SkPoint::Normalize(SkPoint* pt) {
- float mag = SkPoint::Length(pt->fX, pt->fY);
- if (mag > kNearlyZero) {
- float scale = 1 / mag;
- pt->fX *= scale;
- pt->fY *= scale;
+ SkScalar mag = SkPoint::Length(pt->fX, pt->fY);
+ if (mag > SK_ScalarNearlyZero) {
+ SkScalar scale = SkScalarInvert(mag);
+ pt->fX = SkScalarMul(pt->fX, scale);
+ pt->fY = SkScalarMul(pt->fY, scale);
return mag;
}
return 0;
}
+#ifdef SK_SCALAR_IS_FLOAT
+
+bool SkPoint::CanNormalize(SkScalar dx, SkScalar dy) {
+ float mag2 = dx * dx + dy * dy;
+ return mag2 > SK_ScalarNearlyZero * SK_ScalarNearlyZero;
+}
+
+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;
+ float mag2 = x * x + y * y;
+ if (mag2 > SK_ScalarNearlyZero * SK_ScalarNearlyZero) {
+ float scale = length / sk_float_sqrt(mag2);
+ fX = x * scale;
+ fY = y * scale;
return true;
}
return false;
@@ -128,6 +124,23 @@ bool SkPoint::setLength(float x, float y, float length) {
#include "Sk64.h"
+bool SkPoint::CanNormalize(SkScalar dx, SkScalar dy) {
+ Sk64 tmp1, tmp2, tolSqr;
+
+ tmp1.setMul(dx, dx);
+ tmp2.setMul(dy, dy);
+ tmp1.add(tmp2);
+
+ // we want nearlyzero^2, but to compute it fast we want to just do a
+ // 32bit multiply, so we require that it not exceed 31bits. That is true
+ // if nearlyzero is <= 0xB504, which should be trivial, since usually
+ // nearlyzero is a very small fixed-point value.
+ SkASSERT(SK_ScalarNearlyZero <= 0xB504);
+
+ tolSqr.set(0, SK_ScalarNearlyZero * SK_ScalarNearlyZero);
+ return tmp1 > tolSqr;
+}
+
SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) {
Sk64 tmp1, tmp2;
@@ -368,7 +381,25 @@ bool SkPoint::setLength(SkFixed ox, SkFixed oy, SkFixed length) {
///////////////////////////////////////////////////////////////////////////////
-SkScalar SkPoint::distanceToLineSegmentBetweenSqd(const SkPoint& a,
+SkScalar SkPoint::distanceToLineBetweenSqd(const SkPoint& a,
+ const SkPoint& b,
+ Side* side) const {
+
+ SkVector u = b - a;
+ SkVector v = *this - a;
+
+ SkScalar uLengthSqd = u.lengthSqd();
+ SkScalar det = u.cross(v);
+ if (NULL != side) {
+ SkASSERT(-1 == SkPoint::kLeft_Side &&
+ 0 == SkPoint::kOn_Side &&
+ 1 == kRight_Side);
+ *side = (Side) SkScalarSignAsInt(det);
+ }
+ return SkScalarMulDiv(det, det, uLengthSqd);
+}
+
+SkScalar SkPoint::distanceToLineSegmentBetweenSqd(const SkPoint& a,
const SkPoint& b) const {
// See comments to distanceToLineBetweenSqd. If the projection of c onto
// u is between a and b then this returns the same result as that
@@ -401,4 +432,3 @@ SkScalar SkPoint::distanceToLineSegmentBetweenSqd(const SkPoint& a,
return SkScalarMulDiv(det, det, uLengthSqd);
}
}
-
diff --git a/src/core/SkProcSpriteBlitter.cpp b/src/core/SkProcSpriteBlitter.cpp
index f727581..a481920 100644
--- a/src/core/SkProcSpriteBlitter.cpp
+++ b/src/core/SkProcSpriteBlitter.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkProcSpriteBlitter.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#if 0 // experimental
diff --git a/src/core/SkPtrRecorder.cpp b/src/core/SkPtrRecorder.cpp
index 6d5d95d..e3a9eee 100644
--- a/src/core/SkPtrRecorder.cpp
+++ b/src/core/SkPtrRecorder.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkPtrRecorder.h"
#include "SkTSearch.h"
diff --git a/src/core/SkQuadClipper.cpp b/src/core/SkQuadClipper.cpp
index dff1833..b79d5a2 100644
--- a/src/core/SkQuadClipper.cpp
+++ b/src/core/SkQuadClipper.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2009 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkQuadClipper.h"
#include "SkGeometry.h"
diff --git a/src/core/SkQuadClipper.h b/src/core/SkQuadClipper.h
index 1e5c935..be0cea0 100644
--- a/src/core/SkQuadClipper.h
+++ b/src/core/SkQuadClipper.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2009 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkQuadClipper_DEFINED
#define SkQuadClipper_DEFINED
diff --git a/src/core/SkRasterClip.cpp b/src/core/SkRasterClip.cpp
new file mode 100644
index 0000000..9bf39fa
--- /dev/null
+++ b/src/core/SkRasterClip.cpp
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRasterClip.h"
+
+
+SkRasterClip::SkRasterClip() {
+ fIsBW = true;
+}
+
+SkRasterClip::SkRasterClip(const SkRasterClip& src) {
+ AUTO_RASTERCLIP_VALIDATE(src);
+
+ fIsBW = src.fIsBW;
+ if (fIsBW) {
+ fBW = src.fBW;
+ } else {
+ fAA = src.fAA;
+ }
+}
+
+SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) {
+ fIsBW = true;
+}
+
+SkRasterClip::~SkRasterClip() {
+ AUTO_RASTERCLIP_VALIDATE(*this);
+}
+
+bool SkRasterClip::isEmpty() const {
+ return fIsBW ? fBW.isEmpty() : fAA.isEmpty();
+}
+
+bool SkRasterClip::isRect() const {
+ return fIsBW ? fBW.isRect() : false;
+}
+
+bool SkRasterClip::isComplex() const {
+ return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
+}
+
+const SkIRect& SkRasterClip::getBounds() const {
+ return fIsBW ? fBW.getBounds() : fAA.getBounds();
+}
+
+bool SkRasterClip::setEmpty() {
+ AUTO_RASTERCLIP_VALIDATE(*this);
+
+ fIsBW = true;
+ fBW.setEmpty();
+ fAA.setEmpty();
+ return false;
+}
+
+bool SkRasterClip::setRect(const SkIRect& rect) {
+ AUTO_RASTERCLIP_VALIDATE(*this);
+
+ fIsBW = true;
+ fAA.setEmpty();
+ return fBW.setRect(rect);
+}
+
+bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
+ AUTO_RASTERCLIP_VALIDATE(*this);
+
+ if (this->isBW() && !doAA) {
+ return fBW.setPath(path, clip);
+ } else {
+ if (this->isBW()) {
+ this->convertToAA();
+ }
+ return fAA.setPath(path, &clip, doAA);
+ }
+}
+
+bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) {
+ SkRegion tmp;
+ tmp.setRect(clip);
+ return this->setPath(path, tmp, doAA);
+}
+
+bool SkRasterClip::setPath(const SkPath& path, const SkRasterClip& clip,
+ bool doAA) {
+ if (clip.isBW()) {
+ return this->setPath(path, clip.bwRgn(), doAA);
+ } else {
+ SkRegion tmp;
+ tmp.setRect(clip.getBounds());
+ if (!this->setPath(path, clip, doAA)) {
+ return false;
+ }
+ return this->op(clip, SkRegion::kIntersect_Op);
+ }
+}
+
+bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
+ AUTO_RASTERCLIP_VALIDATE(*this);
+
+ return fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
+}
+
+bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
+ AUTO_RASTERCLIP_VALIDATE(*this);
+
+ if (fIsBW) {
+ return fBW.op(rgn, op);
+ } else {
+ SkAAClip tmp;
+ tmp.setRegion(rgn);
+ return fAA.op(tmp, op);
+ }
+}
+
+bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
+ AUTO_RASTERCLIP_VALIDATE(*this);
+ clip.validate();
+
+ if (this->isBW() && clip.isBW()) {
+ return fBW.op(clip.fBW, op);
+ } else {
+ SkAAClip tmp;
+ const SkAAClip* other;
+
+ if (this->isBW()) {
+ this->convertToAA();
+ }
+ if (clip.isBW()) {
+ tmp.setRegion(clip.bwRgn());
+ other = &tmp;
+ } else {
+ other = &clip.aaRgn();
+ }
+ return fAA.op(*other, op);
+ }
+}
+
+// return true if x is nearly integral (within 1/16) since that is the highest
+// precision our aa code can have.
+static bool is_integral(SkScalar x) {
+ int ix = SkScalarRoundToInt(x);
+ SkScalar sx = SkIntToScalar(ix);
+ return SkScalarAbs(sx - x) < (SK_Scalar1 / 16);
+}
+
+bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
+ AUTO_RASTERCLIP_VALIDATE(*this);
+
+ if (doAA) {
+ // check that the rect really needs aa
+ if (is_integral(r.fLeft) && is_integral(r.fTop) &&
+ is_integral(r.fRight) && is_integral(r.fBottom)) {
+ doAA = false;
+ }
+ }
+
+ if (fIsBW && !doAA) {
+ SkIRect ir;
+ r.round(&ir);
+ return fBW.op(ir, op);
+ } else {
+ if (fIsBW) {
+ this->convertToAA();
+ }
+ return fAA.op(r, op, doAA);
+ }
+}
+
+void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
+ if (NULL == dst) {
+ return;
+ }
+
+ AUTO_RASTERCLIP_VALIDATE(*this);
+
+ if (this->isEmpty()) {
+ dst->setEmpty();
+ return;
+ }
+ if (0 == (dx | dy)) {
+ *dst = *this;
+ return;
+ }
+
+ dst->fIsBW = fIsBW;
+ if (fIsBW) {
+ fBW.translate(dx, dy, &dst->fBW);
+ dst->fAA.setEmpty();
+ } else {
+ fAA.translate(dx, dy, &dst->fAA);
+ dst->fBW.setEmpty();
+ }
+}
+
+bool SkRasterClip::quickContains(const SkIRect& ir) const {
+ return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+const SkRegion& SkRasterClip::forceGetBW() {
+ AUTO_RASTERCLIP_VALIDATE(*this);
+
+ if (!fIsBW) {
+ fBW.setRect(fAA.getBounds());
+ }
+ return fBW;
+}
+
+void SkRasterClip::convertToAA() {
+ AUTO_RASTERCLIP_VALIDATE(*this);
+
+ SkASSERT(fIsBW);
+ fAA.setRegion(fBW);
+ fIsBW = false;
+}
+
+#ifdef SK_DEBUG
+void SkRasterClip::validate() const {
+ // can't ever assert that fBW is empty, since we may have called forceGetBW
+ if (fIsBW) {
+ SkASSERT(fAA.isEmpty());
+ }
+
+ fBW.validate();
+ fAA.validate();
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
+ SkDEBUGCODE(fClipRgn = NULL;)
+ SkDEBUGCODE(fBlitter = NULL;)
+}
+
+SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
+ SkBlitter* blitter) {
+ this->init(clip, blitter);
+}
+
+SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
+ SkBlitter* blitter) {
+ SkASSERT(blitter);
+ SkASSERT(aaclip);
+ fBWRgn.setRect(aaclip->getBounds());
+ fAABlitter.init(blitter, aaclip);
+ // now our return values
+ fClipRgn = &fBWRgn;
+ fBlitter = &fAABlitter;
+}
+
+void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
+ SkASSERT(blitter);
+ if (clip.isBW()) {
+ fClipRgn = &clip.bwRgn();
+ fBlitter = blitter;
+ } else {
+ const SkAAClip& aaclip = clip.aaRgn();
+ fBWRgn.setRect(aaclip.getBounds());
+ fAABlitter.init(blitter, &aaclip);
+ // now our return values
+ fClipRgn = &fBWRgn;
+ fBlitter = &fAABlitter;
+ }
+}
+
diff --git a/src/core/SkRasterClip.h b/src/core/SkRasterClip.h
new file mode 100644
index 0000000..8f18270
--- /dev/null
+++ b/src/core/SkRasterClip.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkRasterClip_DEFINED
+#define SkRasterClip_DEFINED
+
+#include "SkRegion.h"
+#include "SkAAClip.h"
+
+class SkRasterClip {
+public:
+ SkRasterClip();
+ SkRasterClip(const SkIRect&);
+ SkRasterClip(const SkRasterClip&);
+ ~SkRasterClip();
+
+ bool isBW() const { return fIsBW; }
+ bool isAA() const { return !fIsBW; }
+ const SkRegion& bwRgn() const { SkASSERT(fIsBW); return fBW; }
+ const SkAAClip& aaRgn() const { SkASSERT(!fIsBW); return fAA; }
+
+ bool isEmpty() const;
+ bool isRect() const;
+ bool isComplex() const;
+ const SkIRect& getBounds() const;
+
+ bool setEmpty();
+ bool setRect(const SkIRect&);
+
+ bool setPath(const SkPath& path, const SkRegion& clip, bool doAA);
+ bool setPath(const SkPath& path, const SkIRect& clip, bool doAA);
+ bool setPath(const SkPath& path, const SkRasterClip&, bool doAA);
+
+ bool op(const SkIRect&, SkRegion::Op);
+ bool op(const SkRegion&, SkRegion::Op);
+ bool op(const SkRasterClip&, SkRegion::Op);
+ bool op(const SkRect&, SkRegion::Op, bool doAA);
+
+ void translate(int dx, int dy, SkRasterClip* dst) const;
+ void translate(int dx, int dy) {
+ this->translate(dx, dy, this);
+ }
+
+ bool quickContains(const SkIRect& rect) const;
+ bool quickContains(int left, int top, int right, int bottom) const {
+ return quickContains(SkIRect::MakeLTRB(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 SkIRect& rect) const {
+ return this->isEmpty() || rect.isEmpty() ||
+ !SkIRect::Intersects(this->getBounds(), rect);
+ }
+
+ // hack for SkCanvas::getTotalClip
+ const SkRegion& forceGetBW();
+
+#ifdef SK_DEBUG
+ void validate() const;
+#else
+ void validate() const {}
+#endif
+
+private:
+ SkRegion fBW;
+ SkAAClip fAA;
+ bool fIsBW;
+
+ void convertToAA();
+};
+
+class SkAutoRasterClipValidate : SkNoncopyable {
+public:
+ SkAutoRasterClipValidate(const SkRasterClip& rc) : fRC(rc) {
+ fRC.validate();
+ }
+ ~SkAutoRasterClipValidate() {
+ fRC.validate();
+ }
+private:
+ const SkRasterClip& fRC;
+};
+
+#ifdef SK_DEBUG
+ #define AUTO_RASTERCLIP_VALIDATE(rc) SkAutoRasterClipValidate arcv(rc)
+#else
+ #define AUTO_RASTERCLIP_VALIDATE(rc)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Encapsulates the logic of deciding if we need to change/wrap the blitter
+ * for aaclipping. If so, getRgn and getBlitter return modified values. If
+ * not, they return the raw blitter and (bw) clip region.
+ *
+ * We need to keep the constructor/destructor cost as small as possible, so we
+ * can freely put this guy on the stack, and not pay too much for the case when
+ * we're really BW anyways.
+ */
+class SkAAClipBlitterWrapper {
+public:
+ SkAAClipBlitterWrapper();
+ SkAAClipBlitterWrapper(const SkRasterClip&, SkBlitter*);
+ SkAAClipBlitterWrapper(const SkAAClip*, SkBlitter*);
+
+ void init(const SkRasterClip&, SkBlitter*);
+
+ const SkIRect& getBounds() const {
+ SkASSERT(fClipRgn);
+ return fClipRgn->getBounds();
+ }
+ const SkRegion& getRgn() const {
+ SkASSERT(fClipRgn);
+ return *fClipRgn;
+ }
+ SkBlitter* getBlitter() {
+ SkASSERT(fBlitter);
+ return fBlitter;
+ }
+
+private:
+ const SkAAClip* fAAClip;
+ SkRegion fBWRgn;
+ SkAAClipBlitter fAABlitter;
+ // what we return
+ const SkRegion* fClipRgn;
+ SkBlitter* fBlitter;
+};
+
+#endif
diff --git a/src/core/SkRasterizer.cpp b/src/core/SkRasterizer.cpp
index 7701df5..7ccced8 100644
--- a/src/core/SkRasterizer.cpp
+++ b/src/core/SkRasterizer.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkRasterizer.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkRasterizer.h"
#include "SkDraw.h"
diff --git a/src/core/SkRect.cpp b/src/core/SkRect.cpp
index 2c6d188..5e3d93c 100644
--- a/src/core/SkRect.cpp
+++ b/src/core/SkRect.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2006 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkRect.h"
void SkIRect::join(int32_t left, int32_t top, int32_t right, int32_t bottom) {
@@ -44,13 +37,6 @@ void SkIRect::sort() {
/////////////////////////////////////////////////////////////////////////////
-bool SkRect::hasValidCoordinates() const {
- return SkScalarIsFinite(fLeft) &&
- SkScalarIsFinite(fTop) &&
- SkScalarIsFinite(fRight) &&
- SkScalarIsFinite(fBottom);
-}
-
void SkRect::sort() {
if (fLeft > fRight) {
SkTSwap<SkScalar>(fLeft, fRight);
@@ -69,6 +55,12 @@ void SkRect::toQuad(SkPoint quad[4]) const {
quad[3].set(fLeft, fBottom);
}
+#ifdef SK_SCALAR_IS_FLOAT
+ #define SkFLOATCODE(code) code
+#else
+ #define SkFLOATCODE(code)
+#endif
+
void SkRect::set(const SkPoint pts[], int count) {
SkASSERT((pts && count > 0) || count == 0);
@@ -94,17 +86,26 @@ void SkRect::set(const SkPoint pts[], int count) {
Sk2sComplimentAsScalar(b));
#else
SkScalar l, t, r, b;
+ SkFLOATCODE(int isNaN;)
l = r = pts[0].fX;
t = b = pts[0].fY;
+ SkFLOATCODE(isNaN = (l != l) | (t != t);)
for (int i = 1; i < count; i++) {
SkScalar x = pts[i].fX;
SkScalar y = pts[i].fY;
+ SkFLOATCODE(isNaN |= (x != x) | (y != y);)
if (x < l) l = x; else if (x > r) r = x;
if (y < t) t = y; else if (y > b) b = y;
}
+
+#ifdef SK_SCALAR_IS_FLOAT
+ if (isNaN) {
+ l = t = r = b = 0;
+ }
+#endif
this->set(l, t, r, b);
#endif
}
@@ -129,6 +130,21 @@ bool SkRect::intersect(const SkRect& r) {
return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom);
}
+bool SkRect::intersect(const SkRect& a, const SkRect& b) {
+ SkASSERT(&a && &b);
+
+ if (!a.isEmpty() && !b.isEmpty() &&
+ a.fLeft < b.fRight && b.fLeft < a.fRight &&
+ a.fTop < b.fBottom && b.fTop < a.fBottom) {
+ fLeft = SkMaxScalar(a.fLeft, b.fLeft);
+ fTop = SkMaxScalar(a.fTop, b.fTop);
+ fRight = SkMinScalar(a.fRight, b.fRight);
+ fBottom = SkMinScalar(a.fBottom, b.fBottom);
+ return true;
+ }
+ return false;
+}
+
void SkRect::join(SkScalar left, SkScalar top, SkScalar right,
SkScalar bottom) {
// do nothing if the params are empty
diff --git a/src/core/SkRefDict.cpp b/src/core/SkRefDict.cpp
index 6f1e7ca..53b099b 100644
--- a/src/core/SkRefDict.cpp
+++ b/src/core/SkRefDict.cpp
@@ -1,19 +1,12 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkRefDict.h"
#include "SkString.h"
diff --git a/src/core/SkRegion.cpp b/src/core/SkRegion.cpp
index e08d2f8..0a8ab65 100644
--- a/src/core/SkRegion.cpp
+++ b/src/core/SkRegion.cpp
@@ -1,28 +1,16 @@
-/* libs/corecg/SkRegion.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkRegionPriv.h"
#include "SkTemplates.h"
#include "SkThread.h"
-#ifdef ANDROID
-#include <stdio.h>
-#endif
-
SkDEBUGCODE(int32_t gRgnAllocCounter;)
/////////////////////////////////////////////////////////////////////////////////////////////////
@@ -179,7 +167,7 @@ bool SkRegion::op(const SkRegion& rgn, const SkIRect& rect, Op op) {
///////////////////////////////////////////////////////////////////////////////
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
char* SkRegion::toString()
{
Iterator iter(*this);
@@ -785,11 +773,10 @@ private:
SkRegion::RunType fTop;
};
-static int operate( const SkRegion::RunType a_runs[],
- const SkRegion::RunType b_runs[],
- SkRegion::RunType dst[],
- SkRegion::Op op)
-{
+static int operate(const SkRegion::RunType a_runs[],
+ const SkRegion::RunType b_runs[],
+ SkRegion::RunType dst[],
+ SkRegion::Op op) {
const SkRegion::RunType gSentinel[] = {
SkRegion::kRunTypeSentinel,
// just need a 2nd value, since spanRec.init() reads 2 values, even
@@ -813,83 +800,67 @@ static int operate( const SkRegion::RunType a_runs[],
bool firstInterval = true;
int prevBot = SkRegion::kRunTypeSentinel; // so we fail the first test
- while (a_bot < SkRegion::kRunTypeSentinel || b_bot < SkRegion::kRunTypeSentinel)
- {
- int top, bot SK_INIT_TO_AVOID_WARNING;
+ while (a_bot < SkRegion::kRunTypeSentinel ||
+ b_bot < SkRegion::kRunTypeSentinel) {
+ int top, bot SK_INIT_TO_AVOID_WARNING;
const SkRegion::RunType* run0 = gSentinel;
const SkRegion::RunType* run1 = gSentinel;
- bool a_flush = false;
- bool b_flush = false;
- int inside;
+ bool a_flush = false;
+ bool b_flush = false;
- if (a_top < b_top)
- {
- inside = 1;
+ if (a_top < b_top) {
top = a_top;
run0 = a_runs;
- if (a_bot <= b_top) // [...] <...>
- {
+ if (a_bot <= b_top) { // [...] <...>
bot = a_bot;
a_flush = true;
- }
- else // [...<..]...> or [...<...>...]
+ } else { // [...<..]...> or [...<...>...]
bot = a_top = b_top;
- }
- else if (b_top < a_top)
- {
- inside = 2;
+ }
+ } else if (b_top < a_top) {
top = b_top;
run1 = b_runs;
- if (b_bot <= a_top) // [...] <...>
- {
+ if (b_bot <= a_top) { // [...] <...>
bot = b_bot;
b_flush = true;
- }
- else // [...<..]...> or [...<...>...]
+ } else { // [...<..]...> or [...<...>...]
bot = b_top = a_top;
- }
- else // a_top == b_top
- {
- inside = 3;
+ }
+ } else { // a_top == b_top
top = a_top; // or b_top
run0 = a_runs;
run1 = b_runs;
- if (a_bot <= b_bot)
- {
+ if (a_bot <= b_bot) {
bot = b_top = a_bot;
a_flush = true;
}
- if (b_bot <= a_bot)
- {
+ if (b_bot <= a_bot) {
bot = a_top = b_bot;
b_flush = true;
}
}
- if (top > prevBot)
+ if (top > prevBot) {
oper.addSpan(top, gSentinel, gSentinel);
-
-// if ((unsigned)(inside - oper.fMin) <= (unsigned)(oper.fMax - oper.fMin))
- {
- oper.addSpan(bot, run0, run1);
- firstInterval = false;
}
+ oper.addSpan(bot, run0, run1);
+ firstInterval = false;
- if (a_flush)
- {
+ if (a_flush) {
a_runs = skip_scanline(a_runs);
a_top = a_bot;
a_bot = *a_runs++;
- if (a_bot == SkRegion::kRunTypeSentinel)
+ if (a_bot == SkRegion::kRunTypeSentinel) {
a_top = a_bot;
+ }
}
- if (b_flush)
- {
+ if (b_flush) {
b_runs = skip_scanline(b_runs);
b_top = b_bot;
b_bot = *b_runs++;
- if (b_bot == SkRegion::kRunTypeSentinel)
+ if (b_bot == SkRegion::kRunTypeSentinel) {
b_top = b_bot;
+ }
}
prevBot = bot;
@@ -995,7 +966,7 @@ bool SkRegion::op(const SkRegion& rgnaOrig, const SkRegion& rgnbOrig, Op op)
return this->setRegion(*rgna);
break;
default:
- SkASSERT(!"unknown region op");
+ SkDEBUGFAIL("unknown region op");
return !this->isEmpty();
}
diff --git a/src/core/SkRegionPriv.h b/src/core/SkRegionPriv.h
index 70f8828..648643f 100644
--- a/src/core/SkRegionPriv.h
+++ b/src/core/SkRegionPriv.h
@@ -1,19 +1,11 @@
-/* libs/corecg/SkRegionPriv.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkRegionPriv_DEFINED
#define SkRegionPriv_DEFINED
diff --git a/src/core/SkRegion_path.cpp b/src/core/SkRegion_path.cpp
index d00baf9..345ecf8 100644
--- a/src/core/SkRegion_path.cpp
+++ b/src/core/SkRegion_path.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkRegion_path.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkRegionPriv.h"
#include "SkBlitter.h"
@@ -430,6 +422,10 @@ static int EdgeProc(const Edge* a, const Edge* b) {
}
bool SkRegion::getBoundaryPath(SkPath* path) const {
+ // path could safely be NULL if we're empty, but the caller shouldn't
+ // *know* that
+ SkASSERT(path);
+
if (this->isEmpty()) {
return false;
}
@@ -451,7 +447,8 @@ bool SkRegion::getBoundaryPath(SkPath* path) const {
edge[0].set(r.fLeft, r.fBottom, r.fTop);
edge[1].set(r.fRight, r.fTop, r.fBottom);
}
- SkQSort(edges.begin(), edges.count(), sizeof(Edge), (SkQSortCompareProc)EdgeProc);
+ SkQSort(edges.begin(), edges.count(), sizeof(Edge),
+ (SkQSortCompareProc)EdgeProc);
int count = edges.count();
Edge* start = edges.begin();
diff --git a/src/core/SkRegion_rects.cpp b/src/core/SkRegion_rects.cpp
index 0e77b1a..1777a1e 100644
--- a/src/core/SkRegion_rects.cpp
+++ b/src/core/SkRegion_rects.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkRegion.h"
#include "SkChunkAlloc.h"
#include "SkTDArray.h"
diff --git a/src/core/SkScalar.cpp b/src/core/SkScalar.cpp
index c6755d1..c48d389 100644
--- a/src/core/SkScalar.cpp
+++ b/src/core/SkScalar.cpp
@@ -1,19 +1,13 @@
+
/*
- * Copyright 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2010 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkMath.h"
#include "SkScalar.h"
SkScalar SkScalarInterpFunc(SkScalar searchKey, const SkScalar keys[],
diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp
index 05439f1..2921b1e 100644
--- a/src/core/SkScalerContext.cpp
+++ b/src/core/SkScalerContext.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkScalerContext.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkScalerContext.h"
#include "SkColorPriv.h"
@@ -23,15 +15,12 @@
#include "SkMaskFilter.h"
#include "SkPathEffect.h"
#include "SkRasterizer.h"
-#include "SkRegion.h"
+#include "SkRasterClip.h"
#include "SkStroke.h"
#include "SkThread.h"
#define ComputeBWRowBytes(width) (((unsigned)(width) + 7) >> 3)
-static const uint8_t* gBlackGammaTable;
-static const uint8_t* gWhiteGammaTable;
-
void SkGlyph::toMask(SkMask* mask) const {
SkASSERT(mask);
@@ -45,10 +34,6 @@ size_t SkGlyph::computeImageSize() const {
const size_t size = this->rowBytes() * fHeight;
switch (fMaskFormat) {
- case SkMask::kHorizontalLCD_Format:
- return SkAlign4(size) + sizeof(uint32_t) * ((fWidth + 2) * fHeight);
- case SkMask::kVerticalLCD_Format:
- return SkAlign4(size) + sizeof(uint32_t) * (fWidth * (fHeight + 2));
case SkMask::k3D_Format:
return 3 * size;
default:
@@ -67,48 +52,6 @@ void SkGlyph::zeroMetrics() {
fLsbDelta = 0;
}
-void SkGlyph::expandA8ToLCD() const {
- SkASSERT(fMaskFormat == SkMask::kHorizontalLCD_Format ||
- fMaskFormat == SkMask::kVerticalLCD_Format);
-
-#if defined(SK_SUPPORT_LCDTEXT)
- uint8_t* input = reinterpret_cast<uint8_t*>(fImage);
- uint32_t* output = reinterpret_cast<uint32_t*>(input + SkAlign4(rowBytes() * fHeight));
-
- if (fMaskFormat == SkMask::kHorizontalLCD_Format) {
- for (unsigned y = 0; y < fHeight; ++y) {
- const uint8_t* inputRow = input;
- *output++ = 0; // make the extra column on the left clear
- for (unsigned x = 0; x < fWidth; ++x) {
- const uint8_t alpha = *inputRow++;
- *output++ = SkPackARGB32(alpha, alpha, alpha, alpha);
- }
- *output++ = 0;
-
- input += rowBytes();
- }
- } else {
- const unsigned outputRowBytes = sizeof(uint32_t) * fWidth;
- memset(output, 0, outputRowBytes);
- output += fWidth;
-
- for (unsigned y = 0; y < fHeight; ++y) {
- const uint8_t* inputRow = input;
- for (unsigned x = 0; x < fWidth; ++x) {
- const uint8_t alpha = *inputRow++;
- *output++ = SkPackARGB32(alpha, alpha, alpha, alpha);
- }
-
- input += rowBytes();
- }
-
- memset(output, 0, outputRowBytes);
- output += fWidth;
- }
-#else
-#endif
-}
-
///////////////////////////////////////////////////////////////////////////////
#ifdef SK_DEBUG
@@ -131,15 +74,6 @@ static SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag) {
SkScalerContext::SkScalerContext(const SkDescriptor* desc)
: fPathEffect(NULL), fMaskFilter(NULL)
{
- static bool gHaveGammaTables;
- if (!gHaveGammaTables) {
- const uint8_t* tables[2];
- SkFontHost::GetGammaTables(tables);
- gBlackGammaTable = tables[0];
- gWhiteGammaTable = tables[1];
- gHaveGammaTables = true;
- }
-
fBaseGlyphCount = 0;
fNextContext = NULL;
@@ -166,6 +100,10 @@ SkScalerContext::SkScalerContext(const SkDescriptor* desc)
fPathEffect = (SkPathEffect*)load_flattenable(desc, kPathEffect_SkDescriptorTag);
fMaskFilter = (SkMaskFilter*)load_flattenable(desc, kMaskFilter_SkDescriptorTag);
fRasterizer = (SkRasterizer*)load_flattenable(desc, kRasterizer_SkDescriptorTag);
+
+ // initialize based on our settings. subclasses can also force this
+ fGenerateImageFromPath = fRec.fFrameWidth > 0 || fPathEffect != NULL ||
+ fRasterizer != NULL;
}
SkScalerContext::~SkScalerContext() {
@@ -237,6 +175,32 @@ SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) {
return ctx;
}
+#ifdef SK_BUILD_FOR_ANDROID
+/* This loops through all available fallback contexts (if needed) until it
+ finds some context that can handle the unichar and return it.
+
+ As this is somewhat expensive operation, it should only be done on the first
+ char of a run.
+ */
+unsigned SkScalerContext::getBaseGlyphCount(SkUnichar uni) {
+ SkScalerContext* ctx = this;
+ unsigned glyphID;
+ for (;;) {
+ glyphID = ctx->generateCharToGlyph(uni);
+ if (glyphID) {
+ break; // found it
+ }
+ ctx = ctx->getNextContext();
+ if (NULL == ctx) {
+ SkDebugf("--- no context for char %x\n", uni);
+ // just return the original context (this)
+ return this->fBaseGlyphCount;
+ }
+ }
+ return ctx->fBaseGlyphCount;
+}
+#endif
+
/* This loops through all available fallback contexts (if needed) until it
finds some context that can handle the unichar. If all fail, returns 0
*/
@@ -308,7 +272,7 @@ void SkScalerContext::getMetrics(SkGlyph* glyph) {
return;
}
- if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) {
+ if (fGenerateImageFromPath) {
SkPath devPath, fillPath;
SkMatrix fillToDevMatrix;
@@ -376,6 +340,164 @@ SK_ERROR:
glyph->fMaskFormat = fRec.fMaskFormat;
}
+static bool isLCD(const SkScalerContext::Rec& rec) {
+ return SkMask::kLCD16_Format == rec.fMaskFormat ||
+ SkMask::kLCD32_Format == rec.fMaskFormat;
+}
+
+static uint16_t a8_to_rgb565(unsigned a8) {
+ return SkPackRGB16(a8 >> 3, a8 >> 2, a8 >> 3);
+}
+
+static void copyToLCD16(const SkBitmap& src, const SkMask& dst) {
+ SkASSERT(SkBitmap::kA8_Config == src.config());
+ SkASSERT(SkMask::kLCD16_Format == dst.fFormat);
+
+ const int width = dst.fBounds.width();
+ const int height = dst.fBounds.height();
+ const uint8_t* srcP = src.getAddr8(0, 0);
+ size_t srcRB = src.rowBytes();
+ uint16_t* dstP = (uint16_t*)dst.fImage;
+ size_t dstRB = dst.fRowBytes;
+ for (int y = 0; y < height; ++y) {
+ for (int x = 0; x < width; ++x) {
+ dstP[x] = a8_to_rgb565(srcP[x]);
+ }
+ srcP += srcRB;
+ dstP = (uint16_t*)((char*)dstP + dstRB);
+ }
+}
+
+#define SK_FREETYPE_LCD_LERP 160
+
+static int lerp(int start, int end) {
+ SkASSERT((unsigned)SK_FREETYPE_LCD_LERP <= 256);
+ return start + ((end - start) * (SK_FREETYPE_LCD_LERP) >> 8);
+}
+
+static uint16_t packLCD16(unsigned r, unsigned g, unsigned b) {
+ if (SK_FREETYPE_LCD_LERP) {
+ // want (a+b+c)/3, but we approx to avoid the divide
+ unsigned ave = (5 * (r + g + b) + g) >> 4;
+ r = lerp(r, ave);
+ g = lerp(g, ave);
+ b = lerp(b, ave);
+ }
+ return SkPackRGB16(r >> 3, g >> 2, b >> 3);
+}
+
+static void pack3xHToLCD16(const SkBitmap& src, const SkMask& dst) {
+ SkASSERT(SkBitmap::kA8_Config == src.config());
+ SkASSERT(SkMask::kLCD16_Format == dst.fFormat);
+
+ const int width = dst.fBounds.width();
+ const int height = dst.fBounds.height();
+ uint16_t* dstP = (uint16_t*)dst.fImage;
+ size_t dstRB = dst.fRowBytes;
+ for (int y = 0; y < height; ++y) {
+ const uint8_t* srcP = src.getAddr8(0, y);
+ for (int x = 0; x < width; ++x) {
+ unsigned r = *srcP++;
+ unsigned g = *srcP++;
+ unsigned b = *srcP++;
+ dstP[x] = packLCD16(r, g, b);
+ }
+ dstP = (uint16_t*)((char*)dstP + dstRB);
+ }
+}
+
+static void pack3xHToLCD32(const SkBitmap& src, const SkMask& dst) {
+ SkASSERT(SkBitmap::kA8_Config == src.config());
+ SkASSERT(SkMask::kLCD32_Format == dst.fFormat);
+
+ const int width = dst.fBounds.width();
+ const int height = dst.fBounds.height();
+ SkPMColor* dstP = (SkPMColor*)dst.fImage;
+ size_t dstRB = dst.fRowBytes;
+ for (int y = 0; y < height; ++y) {
+ const uint8_t* srcP = src.getAddr8(0, y);
+ for (int x = 0; x < width; ++x) {
+ unsigned r = *srcP++;
+ unsigned g = *srcP++;
+ unsigned b = *srcP++;
+ unsigned a = SkMax32(SkMax32(r, g), b);
+ dstP[x] = SkPackARGB32(a, r, g, b);
+ }
+ dstP = (SkPMColor*)((char*)dstP + dstRB);
+ }
+}
+
+static void generateMask(const SkMask& mask, const SkPath& path) {
+ SkBitmap::Config config;
+ SkPaint paint;
+
+ int srcW = mask.fBounds.width();
+ int srcH = mask.fBounds.height();
+ int dstW = srcW;
+ int dstH = srcH;
+ int dstRB = mask.fRowBytes;
+
+ SkMatrix matrix;
+ matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
+ -SkIntToScalar(mask.fBounds.fTop));
+
+ if (SkMask::kBW_Format == mask.fFormat) {
+ config = SkBitmap::kA1_Config;
+ paint.setAntiAlias(false);
+ } else {
+ config = SkBitmap::kA8_Config;
+ paint.setAntiAlias(true);
+ switch (mask.fFormat) {
+ case SkMask::kA8_Format:
+ break;
+ case SkMask::kLCD16_Format:
+ case SkMask::kLCD32_Format:
+ // TODO: trigger off LCD orientation
+ dstW *= 3;
+ matrix.postScale(SkIntToScalar(3), SK_Scalar1);
+ dstRB = 0; // signals we need a copy
+ break;
+ default:
+ SkDEBUGFAIL("unexpected mask format");
+ }
+ }
+
+ SkRasterClip clip;
+ clip.setRect(SkIRect::MakeWH(dstW, dstH));
+
+ SkBitmap bm;
+ bm.setConfig(config, dstW, dstH, dstRB);
+
+ if (0 == dstRB) {
+ bm.allocPixels();
+ bm.lockPixels();
+ } else {
+ bm.setPixels(mask.fImage);
+ }
+ sk_bzero(bm.getPixels(), bm.getSafeSize());
+
+ SkDraw draw;
+ sk_bzero(&draw, sizeof(draw));
+ draw.fRC = &clip;
+ draw.fClip = &clip.bwRgn();
+ draw.fMatrix = &matrix;
+ draw.fBitmap = &bm;
+ draw.drawPath(path, paint);
+
+ if (0 == dstRB) {
+ switch (mask.fFormat) {
+ case SkMask::kLCD16_Format:
+ pack3xHToLCD16(bm, mask);
+ break;
+ case SkMask::kLCD32_Format:
+ pack3xHToLCD32(bm, mask);
+ break;
+ default:
+ SkDEBUGFAIL("bad format for copyback");
+ }
+ }
+}
+
void SkScalerContext::getImage(const SkGlyph& origGlyph) {
const SkGlyph* glyph = &origGlyph;
SkGlyph tmpGlyph;
@@ -397,19 +519,15 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
glyph = &tmpGlyph;
}
- if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) {
+ if (fGenerateImageFromPath) {
SkPath devPath, fillPath;
SkMatrix fillToDevMatrix;
+ SkMask mask;
this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
-
- const bool lcdMode = fRec.fMaskFormat == SkMask::kHorizontalLCD_Format ||
- fRec.fMaskFormat == SkMask::kVerticalLCD_Format;
+ glyph->toMask(&mask);
if (fRasterizer) {
- SkMask mask;
-
- glyph->toMask(&mask);
mask.fFormat = SkMask::kA8_Format;
sk_bzero(glyph->fImage, mask.computeImageSize());
@@ -419,39 +537,7 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
return;
}
} else {
- SkBitmap bm;
- SkBitmap::Config config;
- SkMatrix matrix;
- SkRegion clip;
- SkPaint paint;
- SkDraw draw;
-
- if (SkMask::kA8_Format == fRec.fMaskFormat || lcdMode) {
- config = SkBitmap::kA8_Config;
- paint.setAntiAlias(true);
- } else {
- SkASSERT(SkMask::kBW_Format == fRec.fMaskFormat);
- config = SkBitmap::kA1_Config;
- paint.setAntiAlias(false);
- }
-
- clip.setRect(0, 0, glyph->fWidth, glyph->fHeight);
- matrix.setTranslate(-SkIntToScalar(glyph->fLeft),
- -SkIntToScalar(glyph->fTop));
- bm.setConfig(config, glyph->fWidth, glyph->fHeight,
- glyph->rowBytes());
- bm.setPixels(glyph->fImage);
- sk_bzero(glyph->fImage, bm.height() * bm.rowBytes());
-
- draw.fClip = &clip;
- draw.fMatrix = &matrix;
- draw.fBitmap = &bm;
- draw.fBounder = NULL;
- draw.drawPath(devPath, paint);
- }
-
- if (lcdMode) {
- glyph->expandA8ToLCD();
+ generateMask(mask, devPath);
}
} else {
this->getGlyphContext(*glyph)->generateImage(*glyph);
@@ -491,27 +577,6 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
SkMask::FreeImage(dstM.fImage);
}
}
-
- // check to see if we should filter the alpha channel
-
- if (NULL == fMaskFilter &&
- fRec.fMaskFormat != SkMask::kBW_Format &&
- fRec.fMaskFormat != SkMask::kLCD16_Format &&
- (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0)
- {
- const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable;
- if (NULL != table) {
- uint8_t* dst = (uint8_t*)origGlyph.fImage;
- unsigned rowBytes = origGlyph.rowBytes();
-
- for (int y = origGlyph.fHeight - 1; y >= 0; --y) {
- for (int x = origGlyph.fWidth - 1; x >= 0; --x) {
- dst[x] = table[dst[x]];
- }
- dst += rowBytes;
- }
- }
- }
}
void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) {
@@ -535,6 +600,14 @@ void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
this->getGlyphContext(glyph)->generatePath(glyph, &path);
+ if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
+ SkFixed dx = glyph.getSubXFixed();
+ SkFixed dy = glyph.getSubYFixed();
+ if (dx | dy) {
+ path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy));
+ }
+ }
+
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
@@ -630,6 +703,18 @@ void SkScalerContext::Rec::getSingleMatrix(SkMatrix* m) const {
m->postConcat(deviceMatrix);
}
+SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix) {
+ SkASSERT(!matrix.hasPerspective());
+
+ if (0 == matrix[SkMatrix::kMSkewY]) {
+ return kX_SkAxisAlignment;
+ }
+ if (0 == matrix[SkMatrix::kMScaleX]) {
+ return kY_SkAxisAlignment;
+ }
+ return kNone_SkAxisAlignment;
+}
+
///////////////////////////////////////////////////////////////////////////////
#include "SkFontHost.h"
diff --git a/src/core/SkScan.cpp b/src/core/SkScan.cpp
index 013b0ea..cee328f 100644
--- a/src/core/SkScan.cpp
+++ b/src/core/SkScan.cpp
@@ -1,23 +1,15 @@
-/* libs/graphics/sgl/SkScan.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkScan.h"
#include "SkBlitter.h"
-#include "SkRegion.h"
+#include "SkRasterClip.h"
static inline void blitrect(SkBlitter* blitter, const SkIRect& r) {
blitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
@@ -73,3 +65,54 @@ void SkScan::FillRect(const SkRect& r, const SkRegion* clip,
#endif
+///////////////////////////////////////////////////////////////////////////////
+
+void SkScan::FillIRect(const SkIRect& r, const SkRasterClip& clip,
+ SkBlitter* blitter) {
+ if (clip.isEmpty() || r.isEmpty()) {
+ return;
+ }
+
+ if (clip.isBW()) {
+ FillIRect(r, &clip.bwRgn(), blitter);
+ return;
+ }
+
+ SkAAClipBlitterWrapper wrapper(clip, blitter);
+ FillIRect(r, &wrapper.getRgn(), wrapper.getBlitter());
+}
+
+void SkScan::FillXRect(const SkXRect& xr, const SkRasterClip& clip,
+ SkBlitter* blitter) {
+ if (clip.isEmpty() || xr.isEmpty()) {
+ return;
+ }
+
+ if (clip.isBW()) {
+ FillXRect(xr, &clip.bwRgn(), blitter);
+ return;
+ }
+
+ SkAAClipBlitterWrapper wrapper(clip, blitter);
+ FillXRect(xr, &wrapper.getRgn(), wrapper.getBlitter());
+}
+
+#ifdef SK_SCALAR_IS_FLOAT
+
+void SkScan::FillRect(const SkRect& r, const SkRasterClip& clip,
+ SkBlitter* blitter) {
+ if (clip.isEmpty() || r.isEmpty()) {
+ return;
+ }
+
+ if (clip.isBW()) {
+ FillRect(r, &clip.bwRgn(), blitter);
+ return;
+ }
+
+ SkAAClipBlitterWrapper wrapper(clip, blitter);
+ FillRect(r, &wrapper.getRgn(), wrapper.getBlitter());
+}
+
+#endif
+
diff --git a/src/core/SkScanPriv.h b/src/core/SkScanPriv.h
index e78feed..96ed5ab 100644
--- a/src/core/SkScanPriv.h
+++ b/src/core/SkScanPriv.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkScanPriv.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkScanPriv_DEFINED
#define SkScanPriv_DEFINED
diff --git a/src/core/SkScan_AntiPath.cpp b/src/core/SkScan_AntiPath.cpp
index 4dc2cd3..97843ef 100644
--- a/src/core/SkScan_AntiPath.cpp
+++ b/src/core/SkScan_AntiPath.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkScan_AntiPath.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkScanPriv.h"
#include "SkPath.h"
@@ -26,13 +18,18 @@
#define SCALE (1 << SHIFT)
#define MASK (SCALE - 1)
-/*
+/** @file
We have two techniques for capturing the output of the supersampler:
- SUPERMASK, which records a large mask-bitmap
this is often faster for small, complex objects
- RLE, which records a rle-encoded scanline
this is often faster for large objects with big spans
+ These blitters use two coordinate systems:
+ - destination coordinates, scale equal to the output - often
+ abbreviated with 'i' or 'I' in variable names
+ - supersampled coordinates, scale equal to the output * SCALE
+
NEW_AA is a set of code-changes to try to make both paths produce identical
results. Its not quite there yet, though the remaining differences may be
in the subsequent blits, and not in the different masks/runs...
@@ -43,29 +40,38 @@
///////////////////////////////////////////////////////////////////////////////
+/// Base class for a single-pass supersampled blitter.
class BaseSuperBlitter : public SkBlitter {
public:
BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
const SkRegion& clip);
+ /// Must be explicitly defined on subclasses.
virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
- const int16_t runs[]) {
- SkASSERT(!"How did I get here?");
- }
- virtual void blitV(int x, int y, int height, SkAlpha alpha) {
- SkASSERT(!"How did I get here?");
+ const int16_t runs[]) SK_OVERRIDE {
+ SkDEBUGFAIL("How did I get here?");
}
- virtual void blitRect(int x, int y, int width, int height) {
- SkASSERT(!"How did I get here?");
+ /// May not be called on BaseSuperBlitter because it blits out of order.
+ virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE {
+ SkDEBUGFAIL("How did I get here?");
}
protected:
SkBlitter* fRealBlitter;
+ /// Current y coordinate, in destination coordinates.
int fCurrIY;
- int fWidth, fLeft, fSuperLeft;
+ /// Widest row of region to be blitted, in destination coordinates.
+ int fWidth;
+ /// Leftmost x coordinate in any row, in destination coordinates.
+ int fLeft;
+ /// Leftmost x coordinate in any row, in supersampled coordinates.
+ int fSuperLeft;
SkDEBUGCODE(int fCurrX;)
+ /// Current y coordinate in supersampled coordinates.
int fCurrY;
+ /// Initial y coordinate (top of bounds).
+ int fTop;
};
BaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
@@ -80,11 +86,18 @@ BaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
fLeft = left;
fSuperLeft = left << SHIFT;
fWidth = right - left;
+#if 0
fCurrIY = -1;
fCurrY = -1;
+#else
+ fTop = ir.fTop;
+ fCurrIY = ir.fTop - 1;
+ fCurrY = (ir.fTop << SHIFT) - 1;
+#endif
SkDEBUGCODE(fCurrX = -1;)
}
+/// Run-length-encoded supersampling antialiased blitter.
class SuperBlitter : public BaseSuperBlitter {
public:
SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
@@ -95,10 +108,16 @@ public:
sk_free(fRuns.fRuns);
}
+ /// Once fRuns contains a complete supersampled row, flush() blits
+ /// it out through the wrapped blitter.
void flush();
- virtual void blitH(int x, int y, int width);
- virtual void blitRect(int x, int y, int width, int height);
+ /// Blits a row of pixels, with location and width specified
+ /// in supersampled coordinates.
+ virtual void blitH(int x, int y, int width) SK_OVERRIDE;
+ /// Blits a rectangle of pixels, with location and size specified
+ /// in supersampled coordinates.
+ virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE;
private:
SkAlphaRuns fRuns;
@@ -119,14 +138,14 @@ SuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
}
void SuperBlitter::flush() {
- if (fCurrIY >= 0) {
+ if (fCurrIY >= fTop) {
if (!fRuns.empty()) {
// SkDEBUGCODE(fRuns.dump();)
fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns);
fRuns.reset(fWidth);
fOffsetX = 0;
}
- fCurrIY = -1;
+ fCurrIY = fTop - 1;
SkDEBUGCODE(fCurrX = -1;)
}
}
@@ -137,9 +156,15 @@ static inline int coverage_to_alpha(int aa) {
return aa;
}
-#define SUPER_Mask ((1 << SHIFT) - 1)
+static inline int coverage_to_exact_alpha(int aa) {
+ int alpha = (256 >> SHIFT) * aa;
+ // clamp 256->255
+ return alpha - (alpha >> 8);
+}
void SuperBlitter::blitH(int x, int y, int width) {
+ SkASSERT(width > 0);
+
int iy = y >> SHIFT;
SkASSERT(iy >= fCurrIY);
@@ -164,16 +189,13 @@ void SuperBlitter::blitH(int x, int y, int width) {
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);
-
int start = x;
int stop = x + width;
SkASSERT(start >= 0 && stop > start);
- int fb = start & SUPER_Mask;
- int fe = stop & SUPER_Mask;
+ // integer-pixel-aligned ends of blit, rounded out
+ int fb = start & MASK;
+ int fe = stop & MASK;
int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
if (n < 0) {
@@ -184,11 +206,13 @@ void SuperBlitter::blitH(int x, int y, int width) {
if (fb == 0) {
n += 1;
} else {
- fb = (1 << SHIFT) - fb;
+ fb = SCALE - fb;
}
}
- fOffsetX = fRuns.add(x >> SHIFT, coverage_to_alpha(fb), n, coverage_to_alpha(fe),
+ // TODO - should this be using coverage_to_exact_alpha?
+ fOffsetX = fRuns.add(x >> SHIFT, coverage_to_alpha(fb),
+ n, coverage_to_alpha(fe),
(1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT),
fOffsetX);
@@ -198,16 +222,141 @@ void SuperBlitter::blitH(int x, int y, int width) {
#endif
}
+static void set_left_rite_runs(SkAlphaRuns& runs, int ileft, U8CPU leftA,
+ int n, U8CPU riteA) {
+ SkASSERT(leftA <= 0xFF);
+ SkASSERT(riteA <= 0xFF);
+
+ int16_t* run = runs.fRuns;
+ uint8_t* aa = runs.fAlpha;
+
+ if (ileft > 0) {
+ run[0] = ileft;
+ aa[0] = 0;
+ run += ileft;
+ aa += ileft;
+ }
+
+ SkASSERT(leftA < 0xFF);
+ if (leftA > 0) {
+ *run++ = 1;
+ *aa++ = leftA;
+ }
+
+ if (n > 0) {
+ run[0] = n;
+ aa[0] = 0xFF;
+ run += n;
+ aa += n;
+ }
+
+ SkASSERT(riteA < 0xFF);
+ if (riteA > 0) {
+ *run++ = 1;
+ *aa++ = riteA;
+ }
+ run[0] = 0;
+}
+
void SuperBlitter::blitRect(int x, int y, int width, int height) {
- for (int i = 0; i < height; ++i) {
- blitH(x, y + i, width);
+ SkASSERT(width > 0);
+ SkASSERT(height > 0);
+
+ // blit leading rows
+ while ((y & MASK)) {
+ this->blitH(x, y++, width);
+ if (--height <= 0) {
+ return;
+ }
+ }
+ SkASSERT(height > 0);
+
+ // Since this is a rect, instead of blitting supersampled rows one at a
+ // time and then resolving to the destination canvas, we can blit
+ // directly to the destintion canvas one row per SCALE supersampled rows.
+ int start_y = y >> SHIFT;
+ int stop_y = (y + height) >> SHIFT;
+ int count = stop_y - start_y;
+ if (count > 0) {
+ y += count << SHIFT;
+ height -= count << SHIFT;
+
+ // save original X for our tail blitH() loop at the bottom
+ int origX = x;
+
+ x -= fSuperLeft;
+ // hack, until I figure out why my cubics (I think) go beyond the bounds
+ if (x < 0) {
+ width += x;
+ x = 0;
+ }
+
+ // There is always a left column, a middle, and a right column.
+ // ileft is the destination x of the first pixel of the entire rect.
+ // xleft is (SCALE - # of covered supersampled pixels) in that
+ // destination pixel.
+ int ileft = x >> SHIFT;
+ int xleft = x & MASK;
+ // irite is the destination x of the last pixel of the OPAQUE section.
+ // xrite is the number of supersampled pixels extending beyond irite;
+ // xrite/SCALE should give us alpha.
+ int irite = (x + width) >> SHIFT;
+ int xrite = (x + width) & MASK;
+ if (!xrite) {
+ xrite = SCALE;
+ irite--;
+ }
+
+ // Need to call flush() to clean up pending draws before we
+ // even consider blitV(), since otherwise it can look nonmonotonic.
+ SkASSERT(start_y > fCurrIY);
+ this->flush();
+
+ int n = irite - ileft - 1;
+ if (n < 0) {
+ // If n < 0, we'll only have a single partially-transparent column
+ // of pixels to render.
+ xleft = xrite - xleft;
+ SkASSERT(xleft <= SCALE);
+ SkASSERT(xleft > 0);
+ xrite = 0;
+ fRealBlitter->blitV(ileft + fLeft, start_y, count,
+ coverage_to_exact_alpha(xleft));
+ } else {
+ // With n = 0, we have two possibly-transparent columns of pixels
+ // to render; with n > 0, we have opaque columns between them.
+
+ xleft = SCALE - xleft;
+
+ // Using coverage_to_exact_alpha is not consistent with blitH()
+ const int coverageL = coverage_to_exact_alpha(xleft);
+ const int coverageR = coverage_to_exact_alpha(xrite);
+
+ SkASSERT(coverageL > 0 || n > 0 || coverageR > 0);
+ SkASSERT((coverageL != 0) + n + (coverageR != 0) <= fWidth);
+
+ fRealBlitter->blitAntiRect(ileft + fLeft, start_y, n, count,
+ coverageL, coverageR);
+ }
+
+ // preamble for our next call to blitH()
+ fCurrIY = stop_y - 1;
+ fOffsetX = 0;
+ fCurrY = y - 1;
+ fRuns.reset(fWidth);
+ x = origX;
}
- flush();
+ // catch any remaining few rows
+ SkASSERT(height <= MASK);
+ while (--height >= 0) {
+ this->blitH(x, y++, width);
+ }
}
///////////////////////////////////////////////////////////////////////////////
+/// Masked supersampling antialiased blitter.
class MaskSuperBlitter : public BaseSuperBlitter {
public:
MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
@@ -216,7 +365,7 @@ public:
fRealBlitter->blitMask(fMask, fClipRect);
}
- virtual void blitH(int x, int y, int width);
+ virtual void blitH(int x, int y, int width) SK_OVERRIDE;
static bool CanHandleRect(const SkIRect& bounds) {
#ifdef FORCE_RLE
@@ -365,18 +514,14 @@ void MaskSuperBlitter::blitH(int x, int y, int width) {
x = 0;
}
- // 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);
-
uint8_t* row = fMask.fImage + iy * fMask.fRowBytes + (x >> SHIFT);
int start = x;
int stop = x + width;
SkASSERT(start >= 0 && stop > start);
- int fb = start & SUPER_Mask;
- int fe = stop & SUPER_Mask;
+ int fb = start & MASK;
+ int fe = stop & MASK;
int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
@@ -389,10 +534,10 @@ void MaskSuperBlitter::blitH(int x, int y, int width) {
if (0 == fb) {
n += 1;
} else {
- fb = (1 << SHIFT) - fb;
+ fb = SCALE - fb;
}
#else
- fb = (1 << SHIFT) - fb;
+ fb = SCALE - fb;
#endif
SkASSERT(row >= fMask.fImage);
SkASSERT(row + n + 1 < fMask.fImage + kMAX_STORAGE + 1);
@@ -417,7 +562,7 @@ static int overflows_short_shift(int value, int shift) {
}
void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip,
- SkBlitter* blitter) {
+ SkBlitter* blitter, bool forceRLE) {
if (clip.isEmpty()) {
return;
}
@@ -425,6 +570,9 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip,
SkIRect ir;
path.getBounds().roundOut(&ir);
if (ir.isEmpty()) {
+ if (path.isInverseFillType()) {
+ blitter->blitRegion(clip);
+ }
return;
}
@@ -468,7 +616,7 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip,
// MaskSuperBlitter can't handle drawing outside of ir, so we can't use it
// if we're an inverse filltype
- if (!path.isInverseFillType() && MaskSuperBlitter::CanHandleRect(ir)) {
+ if (!path.isInverseFillType() && MaskSuperBlitter::CanHandleRect(ir) && !forceRLE) {
MaskSuperBlitter superBlit(blitter, ir, clip);
SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop);
sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, clip);
@@ -481,3 +629,44 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip,
sk_blit_below(blitter, ir, clip);
}
}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkRasterClip.h"
+
+void SkScan::FillPath(const SkPath& path, const SkRasterClip& clip,
+ SkBlitter* blitter) {
+ if (clip.isEmpty()) {
+ return;
+ }
+
+ if (clip.isBW()) {
+ FillPath(path, clip.bwRgn(), blitter);
+ } else {
+ SkRegion tmp;
+ SkAAClipBlitter aaBlitter;
+
+ tmp.setRect(clip.getBounds());
+ aaBlitter.init(blitter, &clip.aaRgn());
+ SkScan::FillPath(path, tmp, &aaBlitter);
+ }
+}
+
+void SkScan::AntiFillPath(const SkPath& path, const SkRasterClip& clip,
+ SkBlitter* blitter) {
+ if (clip.isEmpty()) {
+ return;
+ }
+
+ if (clip.isBW()) {
+ AntiFillPath(path, clip.bwRgn(), blitter);
+ } else {
+ SkRegion tmp;
+ SkAAClipBlitter aaBlitter;
+
+ tmp.setRect(clip.getBounds());
+ aaBlitter.init(blitter, &clip.aaRgn());
+ SkScan::AntiFillPath(path, tmp, &aaBlitter, true);
+ }
+}
+
diff --git a/src/core/SkScan_Antihair.cpp b/src/core/SkScan_Antihair.cpp
index 52f2a32..3b28634 100644
--- a/src/core/SkScan_Antihair.cpp
+++ b/src/core/SkScan_Antihair.cpp
@@ -1,25 +1,17 @@
-/* libs/graphics/sgl/SkScan_Antihair.cpp
-**
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkScan.h"
#include "SkBlitter.h"
#include "SkColorPriv.h"
#include "SkLineClipper.h"
-#include "SkRegion.h"
+#include "SkRasterClip.h"
#include "SkFDot6.h"
/* Our attempt to compute the worst case "bounds" for the horizontal and
@@ -395,8 +387,8 @@ static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1,
}
}
-void SkScan::AntiHairLine(const SkPoint& pt0, const SkPoint& pt1,
- const SkRegion* clip, SkBlitter* blitter) {
+void SkScan::AntiHairLineRgn(const SkPoint& pt0, const SkPoint& pt1,
+ const SkRegion* clip, SkBlitter* blitter) {
if (clip && clip->isEmpty()) {
return;
}
@@ -463,7 +455,7 @@ void SkScan::AntiHairLine(const SkPoint& pt0, const SkPoint& pt1,
do_anti_hairline(x0, y0, x1, y1, NULL, blitter);
}
-void SkScan::AntiHairRect(const SkRect& rect, const SkRegion* clip,
+void SkScan::AntiHairRect(const SkRect& rect, const SkRasterClip& clip,
SkBlitter* blitter) {
SkPoint p0, p1;
@@ -566,7 +558,9 @@ static void antifillrect(const SkXRect& xr, SkBlitter* blitter) {
void SkScan::AntiFillXRect(const SkXRect& xr, const SkRegion* clip,
SkBlitter* blitter) {
- if (clip) {
+ if (NULL == clip) {
+ antifillrect(xr, blitter);
+ } else {
SkIRect outerBounds;
XRect_roundOut(xr, &outerBounds);
@@ -598,8 +592,25 @@ void SkScan::AntiFillXRect(const SkXRect& xr, const SkRegion* clip,
clipper.next();
}
}
+ }
+}
+
+void SkScan::AntiFillXRect(const SkXRect& xr, const SkRasterClip& clip,
+ SkBlitter* blitter) {
+ if (clip.isBW()) {
+ AntiFillXRect(xr, &clip.bwRgn(), blitter);
} else {
- antifillrect(xr, blitter);
+ SkIRect outerBounds;
+ XRect_roundOut(xr, &outerBounds);
+
+ if (clip.quickContains(outerBounds)) {
+ AntiFillXRect(xr, NULL, blitter);
+ } else {
+ SkAAClipBlitterWrapper wrapper(clip, blitter);
+ blitter = wrapper.getBlitter();
+
+ AntiFillXRect(xr, &wrapper.getRgn(), wrapper.getBlitter());
+ }
}
}
@@ -653,6 +664,16 @@ void SkScan::AntiFillRect(const SkRect& origR, const SkRegion* clip,
}
}
+void SkScan::AntiFillRect(const SkRect& r, const SkRasterClip& clip,
+ SkBlitter* blitter) {
+ if (clip.isBW()) {
+ AntiFillRect(r, &clip.bwRgn(), blitter);
+ } else {
+ SkAAClipBlitterWrapper wrap(clip, blitter);
+ AntiFillRect(r, &wrap.getRgn(), wrap.getBlitter());
+ }
+}
+
#endif // SK_SCALAR_IS_FLOAT
///////////////////////////////////////////////////////////////////////////////
@@ -813,3 +834,14 @@ void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
innerstrokedot8(L, T, R, B, blitter);
}
}
+
+void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
+ const SkRasterClip& clip, SkBlitter* blitter) {
+ if (clip.isBW()) {
+ AntiFrameRect(r, strokeSize, &clip.bwRgn(), blitter);
+ } else {
+ SkAAClipBlitterWrapper wrap(clip, blitter);
+ AntiFrameRect(r, strokeSize, &wrap.getRgn(), wrap.getBlitter());
+ }
+}
+
diff --git a/src/core/SkScan_Hairline.cpp b/src/core/SkScan_Hairline.cpp
index a0325fe..412ec03 100644
--- a/src/core/SkScan_Hairline.cpp
+++ b/src/core/SkScan_Hairline.cpp
@@ -1,23 +1,15 @@
-/* libs/graphics/sgl/SkScan_Hairline.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkScan.h"
#include "SkBlitter.h"
-#include "SkRegion.h"
+#include "SkRasterClip.h"
#include "SkFDot6.h"
#include "SkLineClipper.h"
@@ -41,8 +33,8 @@ static void vertline(int y, int stopy, SkFixed fx, SkFixed dx,
} while (++y < stopy);
}
-void SkScan::HairLine(const SkPoint& pt0, const SkPoint& pt1,
- const SkRegion* clip, SkBlitter* blitter) {
+void SkScan::HairLineRgn(const SkPoint& pt0, const SkPoint& pt1,
+ const SkRegion* clip, SkBlitter* blitter) {
SkBlitterClipper clipper;
SkRect r;
SkIRect clipR, ptsR;
@@ -128,8 +120,9 @@ void SkScan::HairLine(const SkPoint& pt0, const SkPoint& pt1,
// we don't just draw 4 lines, 'cause that can leave a gap in the bottom-right
// and double-hit the top-left.
// TODO: handle huge coordinates on rect (before calling SkScalarToFixed)
-void SkScan::HairRect(const SkRect& rect, const SkRegion* clip,
+void SkScan::HairRect(const SkRect& rect, const SkRasterClip& clip,
SkBlitter* blitter) {
+ SkAAClipBlitterWrapper wrapper;
SkBlitterClipper clipper;
SkIRect r;
@@ -138,13 +131,19 @@ void SkScan::HairRect(const SkRect& rect, const SkRegion* clip,
(SkScalarToFixed(rect.fRight) >> 16) + 1,
(SkScalarToFixed(rect.fBottom) >> 16) + 1);
- if (clip) {
- if (clip->quickReject(r)) {
- return;
- }
- if (!clip->quickContains(r)) {
- blitter = clipper.apply(blitter, clip);
+ if (clip.quickReject(r)) {
+ return;
+ }
+ if (!clip.quickContains(r)) {
+ const SkRegion* clipRgn;
+ if (clip.isBW()) {
+ clipRgn = &clip.bwRgn();
+ } else {
+ wrapper.init(clip, blitter);
+ clipRgn = &wrapper.getRgn();
+ blitter = wrapper.getBlitter();
}
+ blitter = clipper.apply(blitter, clipRgn);
}
int width = r.width();
@@ -246,27 +245,34 @@ static void haircubic(const SkPoint pts[4], const SkRegion* clip, SkBlitter* bli
#define kMaxCubicSubdivideLevel 6
#define kMaxQuadSubdivideLevel 5
-static void hair_path(const SkPath& path, const SkRegion* clip, SkBlitter* blitter,
+static void hair_path(const SkPath& path, const SkRasterClip& rclip, SkBlitter* blitter,
void (*lineproc)(const SkPoint&, const SkPoint&, const SkRegion*, SkBlitter*))
{
if (path.isEmpty()) {
return;
}
+ SkAAClipBlitterWrapper wrap;
const SkIRect* clipR = NULL;
+ const SkRegion* clip = NULL;
- if (clip) {
+ {
SkIRect ibounds;
path.getBounds().roundOut(&ibounds);
ibounds.inset(-1, -1);
- if (clip->quickReject(ibounds)) {
+ if (rclip.quickReject(ibounds)) {
return;
}
- if (clip->quickContains(ibounds)) {
- clip = NULL;
- } else {
- clipR = &clip->getBounds();
+ if (!rclip.quickContains(ibounds)) {
+ clipR = &rclip.getBounds();
+ if (rclip.isBW()) {
+ clip = &rclip.bwRgn();
+ } else {
+ wrap.init(rclip, blitter);
+ blitter = wrap.getBlitter();
+ clip = &wrap.getRgn();
+ }
}
}
@@ -304,20 +310,20 @@ static void hair_path(const SkPath& path, const SkRegion* clip, SkBlitter* blitt
}
}
-void SkScan::HairPath(const SkPath& path, const SkRegion* clip,
+void SkScan::HairPath(const SkPath& path, const SkRasterClip& clip,
SkBlitter* blitter) {
- hair_path(path, clip, blitter, SkScan::HairLine);
+ hair_path(path, clip, blitter, SkScan::HairLineRgn);
}
-void SkScan::AntiHairPath(const SkPath& path, const SkRegion* clip,
+void SkScan::AntiHairPath(const SkPath& path, const SkRasterClip& clip,
SkBlitter* blitter) {
- hair_path(path, clip, blitter, SkScan::AntiHairLine);
+ hair_path(path, clip, blitter, SkScan::AntiHairLineRgn);
}
///////////////////////////////////////////////////////////////////////////////
void SkScan::FrameRect(const SkRect& r, const SkPoint& strokeSize,
- const SkRegion* clip, SkBlitter* blitter) {
+ const SkRasterClip& clip, SkBlitter* blitter) {
SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0);
if (strokeSize.fX < 0 || strokeSize.fY < 0) {
@@ -351,3 +357,48 @@ void SkScan::FrameRect(const SkRect& r, const SkPoint& strokeSize,
SkScan::FillRect(tmp, clip, blitter);
}
+void SkScan::HairLine(const SkPoint& p0, const SkPoint& p1,
+ const SkRasterClip& clip, SkBlitter* blitter) {
+ if (clip.isBW()) {
+ HairLineRgn(p0, p1, &clip.bwRgn(), blitter);
+ } else {
+ const SkRegion* clipRgn = NULL;
+ SkRect r;
+ SkIRect ir;
+ r.set(p0.fX, p0.fY, p1.fX, p1.fY);
+ r.sort();
+ r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
+ r.roundOut(&ir);
+
+ SkAAClipBlitterWrapper wrap;
+ if (!clip.quickContains(ir)) {
+ wrap.init(clip, blitter);
+ blitter = wrap.getBlitter();
+ clipRgn = &wrap.getRgn();
+ }
+ HairLineRgn(p0, p1, clipRgn, blitter);
+ }
+}
+
+void SkScan::AntiHairLine(const SkPoint& p0, const SkPoint& p1,
+ const SkRasterClip& clip, SkBlitter* blitter) {
+ if (clip.isBW()) {
+ AntiHairLineRgn(p0, p1, &clip.bwRgn(), blitter);
+ } else {
+ const SkRegion* clipRgn = NULL;
+ SkRect r;
+ SkIRect ir;
+ r.set(p0.fX, p0.fY, p1.fX, p1.fY);
+ r.sort();
+ r.roundOut(&ir);
+ ir.inset(-1, -1);
+
+ SkAAClipBlitterWrapper wrap;
+ if (!clip.quickContains(ir)) {
+ wrap.init(clip, blitter);
+ blitter = wrap.getBlitter();
+ clipRgn = &wrap.getRgn();
+ }
+ AntiHairLineRgn(p0, p1, clipRgn, blitter);
+ }
+}
diff --git a/src/core/SkScan_Path.cpp b/src/core/SkScan_Path.cpp
index 8f5f99f..7a8aa75 100644
--- a/src/core/SkScan_Path.cpp
+++ b/src/core/SkScan_Path.cpp
@@ -1,31 +1,21 @@
-/* libs/graphics/sgl/SkScan_Path.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkScanPriv.h"
#include "SkBlitter.h"
#include "SkEdge.h"
+#include "SkEdgeBuilder.h"
#include "SkGeometry.h"
#include "SkPath.h"
#include "SkQuadClipper.h"
+#include "SkRasterClip.h"
#include "SkRegion.h"
#include "SkTemplates.h"
-#define USE_NEW_BUILDER
-
#define kEDGE_HEAD_Y SK_MinS32
#define kEDGE_TAIL_Y SK_MaxS32
@@ -201,6 +191,122 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
}
}
+// return true if we're done with this edge
+static bool update_edge(SkEdge* edge, int last_y) {
+ SkASSERT(edge->fLastY >= last_y);
+ if (last_y == edge->fLastY) {
+ if (edge->fCurveCount < 0) {
+ if (((SkCubicEdge*)edge)->updateCubic()) {
+ SkASSERT(edge->fFirstY == last_y + 1);
+ return false;
+ }
+ } else if (edge->fCurveCount > 0) {
+ if (((SkQuadraticEdge*)edge)->updateQuadratic()) {
+ SkASSERT(edge->fFirstY == last_y + 1);
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+static void walk_convex_edges(SkEdge* prevHead, SkPath::FillType,
+ SkBlitter* blitter, int start_y, int stop_y,
+ PrePostProc proc) {
+ static int gCalls;
+ gCalls++;
+
+ validate_sort(prevHead->fNext);
+
+ SkEdge* leftE = prevHead->fNext;
+ SkEdge* riteE = leftE->fNext;
+ SkEdge* currE = riteE->fNext;
+
+#if 0
+ int local_top = leftE->fFirstY;
+ SkASSERT(local_top == riteE->fFirstY);
+#else
+ // our edge choppers for curves can result in the initial edges
+ // not lining up, so we take the max.
+ int local_top = SkMax32(leftE->fFirstY, riteE->fFirstY);
+#endif
+ SkASSERT(local_top >= start_y);
+
+ int gLoops = 0;
+ for (;;) {
+ gLoops++;
+
+ SkASSERT(leftE->fFirstY <= stop_y);
+ SkASSERT(riteE->fFirstY <= stop_y);
+
+ if (leftE->fX > riteE->fX || (leftE->fX == riteE->fX &&
+ leftE->fDX > riteE->fDX)) {
+ SkTSwap(leftE, riteE);
+ }
+
+ int local_bot = SkMin32(leftE->fLastY, riteE->fLastY);
+ local_bot = SkMin32(local_bot, stop_y - 1);
+ SkASSERT(local_top <= local_bot);
+
+ SkFixed left = leftE->fX;
+ SkFixed dLeft = leftE->fDX;
+ SkFixed rite = riteE->fX;
+ SkFixed dRite = riteE->fDX;
+ int count = local_bot - local_top;
+ SkASSERT(count >= 0);
+ if (0 == (dLeft | dRite)) {
+ int L = (left + SK_Fixed1/2) >> 16;
+ int R = (rite + SK_Fixed1/2) >> 16;
+ if (L < R) {
+ count += 1;
+ blitter->blitRect(L, local_top, R - L, count);
+ left += count * dLeft;
+ rite += count * dRite;
+ }
+ local_top = local_bot + 1;
+ } else {
+ do {
+ int L = (left + SK_Fixed1/2) >> 16;
+ int R = (rite + SK_Fixed1/2) >> 16;
+ if (L < R) {
+ blitter->blitH(L, local_top, R - L);
+ }
+ left += dLeft;
+ rite += dRite;
+ local_top += 1;
+ } while (--count >= 0);
+ }
+
+ leftE->fX = left;
+ riteE->fX = rite;
+
+ if (update_edge(leftE, local_bot)) {
+ if (currE->fFirstY >= stop_y) {
+ break;
+ }
+ leftE = currE;
+ currE = currE->fNext;
+ }
+ if (update_edge(riteE, local_bot)) {
+ if (currE->fFirstY >= stop_y) {
+ break;
+ }
+ riteE = currE;
+ currE = currE->fNext;
+ }
+
+ SkASSERT(leftE);
+ SkASSERT(riteE);
+
+ // check our bottom clip
+ SkASSERT(local_top == local_bot + 1);
+ if (local_top >= stop_y) {
+ break;
+ }
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
// this guy overrides blitH, and will call its proxy blitter with the inverse
@@ -237,19 +343,19 @@ public:
// we do not expect to get called with these entrypoints
virtual void blitAntiH(int, int, const SkAlpha[], const int16_t runs[]) {
- SkASSERT(!"blitAntiH unexpected");
+ SkDEBUGFAIL("blitAntiH unexpected");
}
virtual void blitV(int x, int y, int height, SkAlpha alpha) {
- SkASSERT(!"blitV unexpected");
+ SkDEBUGFAIL("blitV unexpected");
}
virtual void blitRect(int x, int y, int width, int height) {
- SkASSERT(!"blitRect unexpected");
+ SkDEBUGFAIL("blitRect unexpected");
}
virtual void blitMask(const SkMask&, const SkIRect& clip) {
- SkASSERT(!"blitMask unexpected");
+ SkDEBUGFAIL("blitMask unexpected");
}
virtual const SkBitmap* justAnOpaqueColor(uint32_t* value) {
- SkASSERT(!"justAnOpaqueColor unexpected");
+ SkDEBUGFAIL("justAnOpaqueColor unexpected");
return NULL;
}
@@ -268,138 +374,6 @@ static void PrePostInverseBlitterProc(SkBlitter* blitter, int y, bool isStart) {
#pragma warning ( pop )
#endif
-#ifdef USE_NEW_BUILDER
-#include "SkEdgeBuilder.h"
-#else
-static int build_edges(SkEdge edge[], const SkPath& path,
- const SkIRect* clipRect, SkEdge* list[], int shiftUp) {
- SkEdge** start = list;
- SkPath::Iter iter(path, true);
- SkPoint pts[4];
- SkPath::Verb verb;
-
- SkQuadClipper qclipper;
- if (clipRect) {
- SkIRect r;
- r.set(clipRect->fLeft >> shiftUp, clipRect->fTop >> shiftUp,
- clipRect->fRight >> shiftUp, clipRect->fBottom >> shiftUp);
- qclipper.setClip(r);
- }
-
- while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
- switch (verb) {
- case SkPath::kLine_Verb:
- if (edge->setLine(pts[0], pts[1], clipRect, shiftUp)) {
- *list++ = edge;
- edge = (SkEdge*)((char*)edge + sizeof(SkEdge));
- }
- break;
- case SkPath::kQuad_Verb: {
- SkPoint tmp[5], clippedPts[3];
- SkPoint* p = tmp;
- int count = SkChopQuadAtYExtrema(pts, tmp);
-
- do {
- const SkPoint* qpts = p;
- if (clipRect) {
- if (!qclipper.clipQuad(p, clippedPts)) {
- goto NEXT_CHOPPED_QUAD;
- }
- qpts = clippedPts;
- }
- if (((SkQuadraticEdge*)edge)->setQuadratic(qpts, shiftUp)) {
- *list++ = edge;
- edge = (SkEdge*)((char*)edge + sizeof(SkQuadraticEdge));
- }
- NEXT_CHOPPED_QUAD:
- 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);
-}
-
-#ifdef SK_DEBUG
-/* 'quick' computation of the max sized needed to allocated for
- our edgelist.
-*/
-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(NULL)) != 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;
-}
-#endif
-
-/* Much faster than worst_case_edge_count, but over estimates even more
-*/
-static int cheap_worst_case_edge_count(const SkPath& path, size_t* storage) {
- int ptCount = path.getPoints(NULL, 0);
- // worst case is curve, close, curve, close, as that is
- // 2 lines per pt, or : pts * 2
- // 2 quads + 1 line per 2 pts, or : pts * 3 / 2
- // 3 cubics + 1 line per 3 pts : pts * 4 / 3
- int edgeCount = ptCount << 1;
- // worst storage, due to relative size of different edge types, is
- // quads * 3 / 2
- size_t quadSize = (ptCount * 3 >> 1) * sizeof(SkQuadraticEdge);
-#if 0
- size_t lineSize = (ptCount << 1) * sizeof(SkEdge);
- size_t cubicSize = (ptCount * 3 / 4) * sizeof(SkCubicEdge);
- SkASSERT(lineSize <= quadSize);
- SkASSERT(cubicSize <= quadSize);
-#endif
- *storage = quadSize;
- return edgeCount;
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-
extern "C" {
static int edge_compare(const void* a, const void* b) {
const SkEdge* edgea = *(const SkEdge**)a;
@@ -443,31 +417,10 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
const SkRegion& clipRgn) {
SkASSERT(&path && blitter);
-#ifdef USE_NEW_BUILDER
SkEdgeBuilder builder;
int count = builder.build(path, clipRect, shiftEdgesUp);
SkEdge** list = builder.edgeList();
-#else
- size_t size;
- int maxCount = cheap_worst_case_edge_count(path, &size);
-
-#ifdef SK_DEBUG
- {
- size_t size2;
- int maxCount2 = worst_case_edge_count(path, &size2);
-
- SkASSERT(maxCount >= maxCount2 && size >= size2);
- }
-#endif
-
- SkAutoMalloc memory(maxCount * sizeof(SkEdge*) + size);
- SkEdge** list = (SkEdge**)memory.get();
- SkEdge* initialEdge = (SkEdge*)(list + maxCount);
- int count = build_edges(initialEdge, path, clipRect, list,
- shiftEdgesUp);
- SkASSERT(count <= maxCount);
-#endif
if (count < 2) {
if (path.isInverseFillType()) {
@@ -516,7 +469,11 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
proc = PrePostInverseBlitterProc;
}
- walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc);
+ if (path.isConvex() && (NULL == proc)) {
+ walk_convex_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, NULL);
+ } else {
+ walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc);
+ }
}
void sk_blit_above(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) {
@@ -636,6 +593,12 @@ void SkScan::FillPath(const SkPath& path, const SkRegion& origClip,
}
}
+void SkScan::FillPath(const SkPath& path, const SkIRect& ir,
+ SkBlitter* blitter) {
+ SkRegion rgn(ir);
+ FillPath(path, rgn, blitter);
+}
+
///////////////////////////////////////////////////////////////////////////////
static int build_tri_edges(SkEdge edge[], const SkPoint pts[],
@@ -694,12 +657,13 @@ static void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect,
if (clipRect && start_y < clipRect->fTop) {
start_y = clipRect->fTop;
}
- walk_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, NULL);
+ walk_convex_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, NULL);
+// walk_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, NULL);
}
-void SkScan::FillTriangle(const SkPoint pts[], const SkRegion* clip,
+void SkScan::FillTriangle(const SkPoint pts[], const SkRasterClip& clip,
SkBlitter* blitter) {
- if (clip && clip->isEmpty()) {
+ if (clip.isEmpty()) {
return;
}
@@ -707,12 +671,21 @@ void SkScan::FillTriangle(const SkPoint pts[], const SkRegion* clip,
SkIRect ir;
r.set(pts, 3);
r.round(&ir);
- if (ir.isEmpty()) {
+ if (ir.isEmpty() || !SkIRect::Intersects(ir, clip.getBounds())) {
return;
}
- SkScanClipper clipper(blitter, clip, ir);
+ SkAAClipBlitterWrapper wrap;
+ const SkRegion* clipRgn;
+ if (clip.isBW()) {
+ clipRgn = &clip.bwRgn();
+ } else {
+ wrap.init(clip, blitter);
+ clipRgn = &wrap.getRgn();
+ blitter = wrap.getBlitter();
+ }
+ SkScanClipper clipper(blitter, clipRgn, ir);
blitter = clipper.getBlitter();
if (NULL != blitter) {
sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir);
diff --git a/src/core/SkShader.cpp b/src/core/SkShader.cpp
index b51705e..ce7ff9e 100644
--- a/src/core/SkShader.cpp
+++ b/src/core/SkShader.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkShader.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkScalar.h"
#include "SkShader.h"
@@ -116,7 +108,7 @@ void SkShader::shadeSpan16(int x, int y, uint16_t span16[], int count) {
SkASSERT(this->canCallShadeSpan16());
// basically, if we get here, the subclass screwed up
- SkASSERT(!"kHasSpan16 flag is set, but shadeSpan16() not implemented");
+ SkDEBUGFAIL("kHasSpan16 flag is set, but shadeSpan16() not implemented");
}
#define kTempColorQuadCount 6 // balance between speed (larger) and saving stack-space
@@ -219,23 +211,25 @@ SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
SkColorShader::SkColorShader() {
fFlags = 0;
fInheritColor = true;
- fAsABitmapPixelRef = NULL;
}
SkColorShader::SkColorShader(SkColor c) {
fFlags = 0;
fColor = c;
fInheritColor = false;
- fAsABitmapPixelRef = NULL;
}
-SkColorShader::~SkColorShader() {
- SkSafeUnref(fAsABitmapPixelRef);
+SkColorShader::~SkColorShader() {}
+
+bool SkColorShader::isOpaque() const {
+ if (fInheritColor) {
+ return true; // using paint's alpha
+ }
+ return SkColorGetA(fColor) == 255;
}
SkColorShader::SkColorShader(SkFlattenableReadBuffer& b) : INHERITED(b) {
fFlags = 0; // computed in setContext
- fAsABitmapPixelRef = NULL;
fInheritColor = b.readU8();
if (fInheritColor) {
@@ -253,6 +247,18 @@ void SkColorShader::flatten(SkFlattenableWriteBuffer& buffer) {
buffer.write32(fColor);
}
+SkFlattenable* SkColorShader::CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkColorShader, (buffer));
+}
+
+SkFlattenable::Factory SkColorShader::getFactory() {
+ return CreateProc;
+}
+
+uint32_t SkColorShader::getFlags() {
+ return fFlags;
+}
+
uint8_t SkColorShader::getSpan16Alpha() const {
return SkGetPackedA32(fPMColor);
}
@@ -313,25 +319,7 @@ void SkColorShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
SkShader::BitmapType SkColorShader::asABitmap(SkBitmap* bitmap, SkMatrix* matrix,
TileMode modes[],
SkScalar* twoPointRadialParams) const {
- // we cache the pixelref, since its generateID is used in the texture cache
- if (NULL == fAsABitmapPixelRef) {
- SkPMColor* storage = (SkPMColor*)sk_malloc_throw(sizeof(SkPMColor));
- *storage = fPMColor;
- fAsABitmapPixelRef = new SkMallocPixelRef(storage, sizeof(SkPMColor),
- NULL);
- }
-
- if (bitmap) {
- bitmap->setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
- bitmap->setPixelRef(fAsABitmapPixelRef);
- }
- if (matrix) {
- matrix->reset();
- }
- if (modes) {
- modes[0] = modes[1] = SkShader::kRepeat_TileMode;
- }
- return kDefault_BitmapType;
+ return kNone_BitmapType;
}
SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const {
@@ -344,3 +332,34 @@ SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const {
}
return kColor_GradientType;
}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkEmptyShader.h"
+
+SkEmptyShader::SkEmptyShader(SkFlattenableReadBuffer& b) : INHERITED(b) {}
+
+uint32_t SkEmptyShader::getFlags() { return 0; }
+uint8_t SkEmptyShader::getSpan16Alpha() const { return 0; }
+
+bool SkEmptyShader::setContext(const SkBitmap&, const SkPaint&,
+ const SkMatrix&) { return false; }
+
+void SkEmptyShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
+ SkDEBUGFAIL("should never get called, since setContext() returned false");
+}
+
+void SkEmptyShader::shadeSpan16(int x, int y, uint16_t span[], int count) {
+ SkDEBUGFAIL("should never get called, since setContext() returned false");
+}
+
+void SkEmptyShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
+ SkDEBUGFAIL("should never get called, since setContext() returned false");
+}
+
+SkFlattenable::Factory SkEmptyShader::getFactory() { return NULL; }
+
+void SkEmptyShader::flatten(SkFlattenableWriteBuffer& buffer) {
+ this->INHERITED::flatten(buffer);
+}
+
diff --git a/src/core/SkShape.cpp b/src/core/SkShape.cpp
index cd405db..339601a 100644
--- a/src/core/SkShape.cpp
+++ b/src/core/SkShape.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkCanvas.h"
#include "SkShape.h"
#include "SkMatrix.h"
@@ -67,4 +74,4 @@ void SkShape::flatten(SkFlattenableWriteBuffer& buffer) {
void SkShape::onDraw(SkCanvas*) {}
-static SkFlattenable::Registrar gReg("SkShape", SkShape::CreateProc);
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkShape)
diff --git a/src/core/SkSinTable.h b/src/core/SkSinTable.h
index 9b4477d..ac26b9e 100644
--- a/src/core/SkSinTable.h
+++ b/src/core/SkSinTable.h
@@ -1,19 +1,11 @@
-/* libs/corecg/SkSinTable.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSinTable_DEFINED
#define SkSinTable_DEFINED
diff --git a/src/core/SkSpriteBlitter.h b/src/core/SkSpriteBlitter.h
index 9f7764d..c1dbfa2 100644
--- a/src/core/SkSpriteBlitter.h
+++ b/src/core/SkSpriteBlitter.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkSpriteBlitter.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSpriteBlitter_DEFINED
#define SkSpriteBlitter_DEFINED
diff --git a/src/core/SkSpriteBlitterTemplate.h b/src/core/SkSpriteBlitterTemplate.h
index 2ab2b3a..c43e582 100644
--- a/src/core/SkSpriteBlitterTemplate.h
+++ b/src/core/SkSpriteBlitterTemplate.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkSpriteBlitterTemplate.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
class SkSPRITE_CLASSNAME : public SkSpriteBlitter {
@@ -27,8 +19,8 @@ public:
SkASSERT(width > 0 && height > 0);
int srcX = x - fLeft;
int srcY = y - fTop;
- SK_RESTRICT SkSPRITE_DST_TYPE* dst =fDevice->SkSPRITE_DST_GETADDR(x, y);
- const SK_RESTRICT SkSPRITE_SRC_TYPE* src =
+ SkSPRITE_DST_TYPE* SK_RESTRICT dst =fDevice->SkSPRITE_DST_GETADDR(x, y);
+ const SkSPRITE_SRC_TYPE* SK_RESTRICT src =
fSource->SkSPRITE_SRC_GETADDR(srcX, srcY);
unsigned dstRB = fDevice->rowBytes();
unsigned srcRB = fSource->rowBytes();
@@ -55,8 +47,8 @@ public:
d += 1;
} while (--w != 0);
#endif
- dst = (SK_RESTRICT SkSPRITE_DST_TYPE*)((char*)dst + dstRB);
- src = (const SK_RESTRICT SkSPRITE_SRC_TYPE*)
+ dst = (SkSPRITE_DST_TYPE* SK_RESTRICT)((char*)dst + dstRB);
+ src = (const SkSPRITE_SRC_TYPE* SK_RESTRICT)
((const char*)src + srcRB);
SkSPRITE_NEXT_ROW
#ifdef SkSPRITE_ROW_PROC
@@ -88,4 +80,3 @@ private:
#ifdef SkSPRITE_ROW_PROC
#undef SkSPRITE_ROW_PROC
#endif
-
diff --git a/src/core/SkSpriteBlitter_ARGB32.cpp b/src/core/SkSpriteBlitter_ARGB32.cpp
index df9e2a1..80d3225 100644
--- a/src/core/SkSpriteBlitter_ARGB32.cpp
+++ b/src/core/SkSpriteBlitter_ARGB32.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkSpriteBlitter_ARGB32.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSpriteBlitter.h"
#include "SkBlitRow.h"
@@ -44,8 +36,8 @@ public:
virtual void blitRect(int x, int y, int width, int height) {
SkASSERT(width > 0 && height > 0);
- SK_RESTRICT uint32_t* dst = fDevice->getAddr32(x, y);
- const SK_RESTRICT uint32_t* src = fSource->getAddr32(x - fLeft,
+ uint32_t* SK_RESTRICT dst = fDevice->getAddr32(x, y);
+ const uint32_t* SK_RESTRICT src = fSource->getAddr32(x - fLeft,
y - fTop);
size_t dstRB = fDevice->rowBytes();
size_t srcRB = fSource->rowBytes();
@@ -54,8 +46,8 @@ public:
do {
proc(dst, src, width, alpha);
- dst = (SK_RESTRICT uint32_t*)((char*)dst + dstRB);
- src = (const SK_RESTRICT uint32_t*)((const char*)src + srcRB);
+ dst = (uint32_t* SK_RESTRICT)((char*)dst + dstRB);
+ src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB);
} while (--height != 0);
}
@@ -132,8 +124,8 @@ public:
virtual void blitRect(int x, int y, int width, int height) {
SkASSERT(width > 0 && height > 0);
- SK_RESTRICT uint32_t* dst = fDevice->getAddr32(x, y);
- const SK_RESTRICT uint32_t* src = fSource->getAddr32(x - fLeft,
+ uint32_t* SK_RESTRICT dst = fDevice->getAddr32(x, y);
+ const uint32_t* SK_RESTRICT src = fSource->getAddr32(x - fLeft,
y - fTop);
unsigned dstRB = fDevice->rowBytes();
unsigned srcRB = fSource->rowBytes();
@@ -154,8 +146,8 @@ public:
fProc32(dst, tmp, width, fAlpha);
}
- dst = (SK_RESTRICT uint32_t*)((char*)dst + dstRB);
- src = (const SK_RESTRICT uint32_t*)((const char*)src + srcRB);
+ dst = (uint32_t* SK_RESTRICT)((char*)dst + dstRB);
+ src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB);
} while (--height != 0);
}
@@ -163,8 +155,8 @@ private:
typedef Sprite_D32_XferFilter INHERITED;
};
-static void fillbuffer(SK_RESTRICT SkPMColor dst[],
- const SK_RESTRICT SkPMColor16 src[], int count) {
+static void fillbuffer(SkPMColor* SK_RESTRICT dst,
+ const SkPMColor16* SK_RESTRICT src, int count) {
SkASSERT(count > 0);
do {
@@ -179,12 +171,12 @@ public:
virtual void blitRect(int x, int y, int width, int height) {
SkASSERT(width > 0 && height > 0);
- SK_RESTRICT SkPMColor* dst = fDevice->getAddr32(x, y);
- const SK_RESTRICT SkPMColor16* src = fSource->getAddr16(x - fLeft,
+ SkPMColor* SK_RESTRICT dst = fDevice->getAddr32(x, y);
+ const SkPMColor16* SK_RESTRICT src = fSource->getAddr16(x - fLeft,
y - fTop);
unsigned dstRB = fDevice->rowBytes();
unsigned srcRB = fSource->rowBytes();
- SK_RESTRICT SkPMColor* buffer = fBuffer;
+ SkPMColor* SK_RESTRICT buffer = fBuffer;
SkColorFilter* colorFilter = fColorFilter;
SkXfermode* xfermode = fXfermode;
@@ -200,8 +192,8 @@ public:
fProc32(dst, buffer, width, fAlpha);
}
- dst = (SK_RESTRICT SkPMColor*)((char*)dst + dstRB);
- src = (const SK_RESTRICT SkPMColor16*)((const char*)src + srcRB);
+ dst = (SkPMColor* SK_RESTRICT)((char*)dst + dstRB);
+ src = (const SkPMColor16* SK_RESTRICT)((const char*)src + srcRB);
} while (--height != 0);
}
@@ -211,8 +203,8 @@ private:
///////////////////////////////////////////////////////////////////////////////
-static void src_row(SK_RESTRICT SkPMColor dst[],
- const SK_RESTRICT SkPMColor16 src[], int count) {
+static void src_row(SkPMColor* SK_RESTRICT dst,
+ const SkPMColor16* SK_RESTRICT src, int count) {
do {
*dst = SkPixel4444ToPixel32(*src);
src += 1;
@@ -226,22 +218,22 @@ public:
virtual void blitRect(int x, int y, int width, int height) {
SkASSERT(width > 0 && height > 0);
- SK_RESTRICT SkPMColor* dst = fDevice->getAddr32(x, y);
- const SK_RESTRICT SkPMColor16* src = fSource->getAddr16(x - fLeft,
+ SkPMColor* SK_RESTRICT dst = fDevice->getAddr32(x, y);
+ const SkPMColor16* SK_RESTRICT src = fSource->getAddr16(x - fLeft,
y - fTop);
unsigned dstRB = fDevice->rowBytes();
unsigned srcRB = fSource->rowBytes();
do {
src_row(dst, src, width);
- dst = (SK_RESTRICT SkPMColor*)((char*)dst + dstRB);
- src = (const SK_RESTRICT SkPMColor16*)((const char*)src + srcRB);
+ dst = (SkPMColor* SK_RESTRICT)((char*)dst + dstRB);
+ src = (const SkPMColor16* SK_RESTRICT)((const char*)src + srcRB);
} while (--height != 0);
}
};
-static void srcover_row(SK_RESTRICT SkPMColor dst[],
- const SK_RESTRICT SkPMColor16 src[], int count) {
+static void srcover_row(SkPMColor* SK_RESTRICT dst,
+ const SkPMColor16* SK_RESTRICT src, int count) {
do {
*dst = SkPMSrcOver(SkPixel4444ToPixel32(*src), *dst);
src += 1;
@@ -255,16 +247,16 @@ public:
virtual void blitRect(int x, int y, int width, int height) {
SkASSERT(width > 0 && height > 0);
- SK_RESTRICT SkPMColor* dst = fDevice->getAddr32(x, y);
- const SK_RESTRICT SkPMColor16* src = fSource->getAddr16(x - fLeft,
+ SkPMColor* SK_RESTRICT dst = fDevice->getAddr32(x, y);
+ const SkPMColor16* SK_RESTRICT src = fSource->getAddr16(x - fLeft,
y - fTop);
unsigned dstRB = fDevice->rowBytes();
unsigned srcRB = fSource->rowBytes();
do {
srcover_row(dst, src, width);
- dst = (SK_RESTRICT SkPMColor*)((char*)dst + dstRB);
- src = (const SK_RESTRICT SkPMColor16*)((const char*)src + srcRB);
+ dst = (SkPMColor* SK_RESTRICT)((char*)dst + dstRB);
+ src = (const SkPMColor16* SK_RESTRICT)((const char*)src + srcRB);
} while (--height != 0);
}
};
@@ -319,4 +311,3 @@ SkSpriteBlitter* SkSpriteBlitter::ChooseD32(const SkBitmap& source,
}
return blitter;
}
-
diff --git a/src/core/SkSpriteBlitter_RGB16.cpp b/src/core/SkSpriteBlitter_RGB16.cpp
index 4dcd73d..2c38f71 100644
--- a/src/core/SkSpriteBlitter_RGB16.cpp
+++ b/src/core/SkSpriteBlitter_RGB16.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkSpriteBlitter_RGB16.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSpriteBlitter.h"
#include "SkBlitRow.h"
@@ -63,8 +55,8 @@ public:
// overrides
virtual void blitRect(int x, int y, int width, int height) {
- SK_RESTRICT uint16_t* dst = fDevice->getAddr16(x, y);
- const SK_RESTRICT uint16_t* src = fSource->getAddr16(x - fLeft,
+ uint16_t* SK_RESTRICT dst = fDevice->getAddr16(x, y);
+ const uint16_t* SK_RESTRICT src = fSource->getAddr16(x - fLeft,
y - fTop);
unsigned dstRB = fDevice->rowBytes();
unsigned srcRB = fSource->rowBytes();
@@ -176,9 +168,9 @@ static intptr_t asint(const void* ptr) {
return reinterpret_cast<const char*>(ptr) - (const char*)0;
}
-static void blitrow_d16_si8(SK_RESTRICT uint16_t* dst,
- SK_RESTRICT const uint8_t* src, int count,
- SK_RESTRICT const uint16_t* ctable) {
+static void blitrow_d16_si8(uint16_t* SK_RESTRICT dst,
+ const uint8_t* SK_RESTRICT src, int count,
+ const uint16_t* SK_RESTRICT ctable) {
if (count <= 8) {
do {
*dst++ = ctable[*src++];
@@ -290,8 +282,8 @@ public:
}
virtual void blitRect(int x, int y, int width, int height) {
- SK_RESTRICT uint16_t* dst = fDevice->getAddr16(x, y);
- const SK_RESTRICT SkPMColor* src = fSource->getAddr32(x - fLeft,
+ uint16_t* SK_RESTRICT dst = fDevice->getAddr16(x, y);
+ const SkPMColor* SK_RESTRICT src = fSource->getAddr32(x - fLeft,
y - fTop);
unsigned dstRB = fDevice->rowBytes();
unsigned srcRB = fSource->rowBytes();
@@ -301,8 +293,8 @@ public:
while (--height >= 0) {
proc(dst, src, width, alpha, x, y);
y += 1;
- dst = (SK_RESTRICT uint16_t*)((char*)dst + dstRB);
- src = (const SK_RESTRICT SkPMColor*)((const char*)src + srcRB);
+ dst = (uint16_t* SK_RESTRICT)((char*)dst + dstRB);
+ src = (const SkPMColor* SK_RESTRICT)((const char*)src + srcRB);
}
}
@@ -383,4 +375,3 @@ SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkBitmap& source,
}
return blitter;
}
-
diff --git a/src/core/SkStream.cpp b/src/core/SkStream.cpp
index 21ee05e..8b71244 100644
--- a/src/core/SkStream.cpp
+++ b/src/core/SkStream.cpp
@@ -1,21 +1,14 @@
-/* libs/graphics/images/SkStream.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkStream.h"
+#include "SkData.h"
#include "SkFixed.h"
#include "SkString.h"
#include "SkOSFile.h"
@@ -71,28 +64,22 @@ SkScalar SkStream::readScalar() {
return value;
}
+#define SK_MAX_BYTE_FOR_U8 0xFD
+#define SK_BYTE_SENTINEL_FOR_U16 0xFE
+#define SK_BYTE_SENTINEL_FOR_U32 0xFF
+
size_t SkStream::readPackedUInt() {
uint8_t byte;
if (!this->read(&byte, 1)) {
return 0;
}
- if (byte != 0xFF) {
+ if (SK_BYTE_SENTINEL_FOR_U16 == byte) {
+ return this->readU16();
+ } else if (SK_BYTE_SENTINEL_FOR_U32 == byte) {
+ return this->readU32();
+ } else {
return byte;
}
-
- uint16_t word;
- if (!this->read(&word, 2)) {
- return 0;
- }
- if (word != 0xFFFF) {
- return word;
- }
-
- uint32_t quad;
- if (!this->read(&quad, 4)) {
- return 0;
- }
- return quad;
}
//////////////////////////////////////////////////////////////////////////////////////
@@ -163,13 +150,23 @@ bool SkWStream::writeScalar(SkScalar value) {
}
bool SkWStream::writePackedUInt(size_t value) {
- if (value < 0xFF) {
- return this->write8(value);
- } else if (value < 0xFFFF) {
- return this->write8(0xFF) && this->write16(value);
+ uint8_t data[5];
+ size_t len = 1;
+ if (value <= SK_MAX_BYTE_FOR_U8) {
+ data[0] = value;
+ len = 1;
+ } else if (value <= 0xFFFF) {
+ uint16_t value16 = value;
+ data[0] = SK_BYTE_SENTINEL_FOR_U16;
+ memcpy(&data[1], &value16, 2);
+ len = 3;
} else {
- return this->write16(0xFFFF) && this->write32(value);
+ uint32_t value32 = value;
+ data[0] = SK_BYTE_SENTINEL_FOR_U32;
+ memcpy(&data[1], &value32, 4);
+ len = 5;
}
+ return this->write(data, len);
}
bool SkWStream::writeStream(SkStream* stream, size_t length) {
@@ -190,7 +187,14 @@ bool SkWStream::writeStream(SkStream* stream, size_t length) {
return true;
}
-////////////////////////////////////////////////////////////////////////////
+bool SkWStream::writeData(const SkData* data) {
+ if (data) {
+ this->write(data->data(), data->size());
+ }
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
SkFILEStream::SkFILEStream(const char file[]) : fName(file)
{
@@ -245,112 +249,105 @@ size_t SkFILEStream::read(void* buffer, size_t size)
return 0;
}
-////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
-SkMemoryStream::SkMemoryStream()
-{
- fWeOwnTheData = false;
- this->setMemory(NULL, 0);
+static SkData* newFromParams(const void* src, size_t size, bool copyData) {
+ if (copyData) {
+ return SkData::NewWithCopy(src, size);
+ } else {
+ return SkData::NewWithProc(src, size, NULL, NULL);
+ }
}
-SkMemoryStream::SkMemoryStream(size_t size) {
- fWeOwnTheData = true;
+SkMemoryStream::SkMemoryStream() {
+ fData = SkData::NewEmpty();
fOffset = 0;
- fSize = size;
- fSrc = sk_malloc_throw(size);
}
-SkMemoryStream::SkMemoryStream(const void* src, size_t size, bool copyData)
-{
- fWeOwnTheData = false;
- this->setMemory(src, size, copyData);
+SkMemoryStream::SkMemoryStream(size_t size) {
+ fData = SkData::NewFromMalloc(sk_malloc_throw(size), size);
+ fOffset = 0;
}
-SkMemoryStream::~SkMemoryStream()
-{
- if (fWeOwnTheData)
- sk_free((void*)fSrc);
+SkMemoryStream::SkMemoryStream(const void* src, size_t size, bool copyData) {
+ fData = newFromParams(src, size, copyData);
+ fOffset = 0;
}
-void SkMemoryStream::setMemoryOwned(const void* src, size_t size)
-{
- if (fWeOwnTheData)
- sk_free((void*)fSrc);
+SkMemoryStream::~SkMemoryStream() {
+ fData->unref();
+}
- fSize = size;
+void SkMemoryStream::setMemoryOwned(const void* src, size_t size) {
+ fData->unref();
+ fData = SkData::NewFromMalloc(src, size);
fOffset = 0;
- fWeOwnTheData = true;
-
- fSrc = src;
}
-void SkMemoryStream::setMemory(const void* src, size_t size, bool copyData)
-{
- if (fWeOwnTheData)
- sk_free((void*)fSrc);
-
- fSize = size;
+void SkMemoryStream::setMemory(const void* src, size_t size, bool copyData) {
+ fData->unref();
+ fData = newFromParams(src, size, copyData);
fOffset = 0;
- fWeOwnTheData = copyData;
+}
- if (copyData)
- {
- void* copy = sk_malloc_throw(size);
- memcpy(copy, src, size);
- src = copy;
- }
- fSrc = src;
+SkData* SkMemoryStream::copyToData() const {
+ fData->ref();
+ return fData;
}
-void SkMemoryStream::skipToAlign4()
-{
+SkData* SkMemoryStream::setData(SkData* data) {
+ SkRefCnt_SafeAssign(fData, data);
+ return data;
+}
+
+void SkMemoryStream::skipToAlign4() {
// cast to remove unary-minus warning
fOffset += -(int)fOffset & 0x03;
}
-bool SkMemoryStream::rewind()
-{
+bool SkMemoryStream::rewind() {
fOffset = 0;
return true;
}
-size_t SkMemoryStream::read(void* buffer, size_t size)
-{
+size_t SkMemoryStream::read(void* buffer, size_t size) {
+ size_t dataSize = fData->size();
+
if (buffer == NULL && size == 0) // special signature, they want the total size
- return fSize;
+ return dataSize;
// if buffer is NULL, seek ahead by size
- if (size == 0)
+ if (size == 0) {
return 0;
- if (size > fSize - fOffset)
- size = fSize - fOffset;
+ }
+ if (size > dataSize - fOffset) {
+ size = dataSize - fOffset;
+ }
if (buffer) {
- memcpy(buffer, (const char*)fSrc + fOffset, size);
+ memcpy(buffer, fData->bytes() + fOffset, size);
}
fOffset += size;
return size;
}
-const void* SkMemoryStream::getMemoryBase()
-{
- return fSrc;
+const void* SkMemoryStream::getMemoryBase() {
+ return fData->data();
}
-const void* SkMemoryStream::getAtPos()
-{
- return (const char*)fSrc + fOffset;
+const void* SkMemoryStream::getAtPos() {
+ return fData->bytes() + fOffset;
}
-size_t SkMemoryStream::seek(size_t offset)
-{
- if (offset > fSize)
- offset = fSize;
+size_t SkMemoryStream::seek(size_t offset) {
+ if (offset > fData->size()) {
+ offset = fData->size();
+ }
fOffset = offset;
return offset;
}
-/////////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
SkBufferStream::SkBufferStream(SkStream* proxy, size_t bufferSize)
: fProxy(proxy)
@@ -585,7 +582,8 @@ struct SkDynamicMemoryWStream::Block {
}
};
-SkDynamicMemoryWStream::SkDynamicMemoryWStream() : fHead(NULL), fTail(NULL), fBytesWritten(0), fCopyToCache(NULL)
+SkDynamicMemoryWStream::SkDynamicMemoryWStream()
+ : fHead(NULL), fTail(NULL), fBytesWritten(0), fCopy(NULL)
{
}
@@ -594,16 +592,10 @@ SkDynamicMemoryWStream::~SkDynamicMemoryWStream()
reset();
}
-const char* SkDynamicMemoryWStream::detach()
-{
- const char* result = getStream();
- fCopyToCache = NULL;
- return result;
-}
-
void SkDynamicMemoryWStream::reset()
{
- sk_free(fCopyToCache);
+ this->invalidateCopy();
+
Block* block = fHead;
while (block != NULL) {
@@ -613,17 +605,13 @@ void SkDynamicMemoryWStream::reset()
}
fHead = fTail = NULL;
fBytesWritten = 0;
- fCopyToCache = NULL;
}
bool SkDynamicMemoryWStream::write(const void* buffer, size_t count)
{
if (count > 0) {
+ this->invalidateCopy();
- if (fCopyToCache) {
- sk_free(fCopyToCache);
- fCopyToCache = NULL;
- }
fBytesWritten += count;
size_t size;
@@ -653,8 +641,12 @@ bool SkDynamicMemoryWStream::write(const void* buffer, size_t count)
bool SkDynamicMemoryWStream::write(const void* buffer, size_t offset, size_t count)
{
- if (offset + count > fBytesWritten)
+ if (offset + count > fBytesWritten) {
return false; // test does not partially modify
+ }
+
+ this->invalidateCopy();
+
Block* block = fHead;
while (block != NULL) {
size_t size = block->written();
@@ -695,23 +687,18 @@ bool SkDynamicMemoryWStream::read(void* buffer, size_t offset, size_t count)
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);
+ if (fCopy) {
+ memcpy(dst, fCopy->data(), fBytesWritten);
+ } else {
+ Block* block = fHead;
+
+ while (block != NULL) {
+ size_t size = block->written();
+ memcpy(dst, block->start(), size);
+ dst = (void*)((char*)dst + size);
+ block = block->fNext;
+ }
}
- return fCopyToCache;
}
void SkDynamicMemoryWStream::padToAlign4()
@@ -724,7 +711,24 @@ void SkDynamicMemoryWStream::padToAlign4()
write(&zero, padBytes);
}
-/////////////////////////////////////////////////////////////////////////////////////////////////////////
+SkData* SkDynamicMemoryWStream::copyToData() const {
+ if (NULL == fCopy) {
+ void* buffer = sk_malloc_throw(fBytesWritten);
+ this->copyTo(buffer);
+ fCopy = SkData::NewFromMalloc(buffer, fBytesWritten);
+ }
+ fCopy->ref();
+ return fCopy;
+}
+
+void SkDynamicMemoryWStream::invalidateCopy() {
+ if (fCopy) {
+ fCopy->unref();
+ fCopy = NULL;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
void SkDebugWStream::newline()
{
diff --git a/src/core/SkString.cpp b/src/core/SkString.cpp
index f461a7a..4658ff8 100644
--- a/src/core/SkString.cpp
+++ b/src/core/SkString.cpp
@@ -1,22 +1,15 @@
-/* libs/graphics/sgl/SkString.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkString.h"
#include "SkFixed.h"
+#include "SkThread.h"
#include "SkUtils.h"
#include <stdarg.h>
#include <stdio.h>
@@ -25,7 +18,8 @@
static const size_t kBufferSize = 256;
#ifdef SK_BUILD_FOR_WIN
- #define VSNPRINTF _vsnprintf
+ #define VSNPRINTF(buffer, size, format, args) \
+ _vsnprintf_s(buffer, size, _TRUNCATE, format, args)
#define SNPRINTF _snprintf
#else
#define VSNPRINTF vsnprintf
@@ -188,22 +182,20 @@ char* SkStrAppendFixed(char string[], SkFixed x) {
///////////////////////////////////////////////////////////////////////////////
-#define kMaxRefCnt_SkString SK_MaxU16
-
// the 3 values are [length] [refcnt] [terminating zero data]
const SkString::Rec SkString::gEmptyRec = { 0, 0, 0 };
#define SizeOfRec() (gEmptyRec.data() - (const char*)&gEmptyRec)
-SkString::Rec* SkString::AllocRec(const char text[], U16CPU len) {
+SkString::Rec* SkString::AllocRec(const char text[], size_t len) {
Rec* rec;
- if (len == 0) {
+ if (0 == len) {
rec = const_cast<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(SizeOfRec() + SkAlign4(len + 1));
- rec->fLength = SkToU16(len);
+ rec->fLength = len;
rec->fRefCnt = 1;
if (text) {
memcpy(rec->data(), text, len);
@@ -215,11 +207,7 @@ SkString::Rec* SkString::AllocRec(const char text[], U16CPU len) {
SkString::Rec* SkString::RefRec(Rec* src) {
if (src != &gEmptyRec) {
- if (src->fRefCnt == kMaxRefCnt_SkString) {
- src = AllocRec(src->data(), src->fLength);
- } else {
- src->fRefCnt += 1;
- }
+ sk_atomic_inc(&src->fRefCnt);
}
return src;
}
@@ -227,14 +215,14 @@ SkString::Rec* SkString::RefRec(Rec* src) {
#ifdef SK_DEBUG
void SkString::validate() const {
// make sure know one has written over our global
- SkASSERT(gEmptyRec.fLength == 0);
- SkASSERT(gEmptyRec.fRefCnt == 0);
- SkASSERT(gEmptyRec.data()[0] == 0);
+ SkASSERT(0 == gEmptyRec.fLength);
+ SkASSERT(0 == gEmptyRec.fRefCnt);
+ SkASSERT(0 == gEmptyRec.data()[0]);
if (fRec != &gEmptyRec) {
SkASSERT(fRec->fLength > 0);
SkASSERT(fRec->fRefCnt > 0);
- SkASSERT(fRec->data()[fRec->fLength] == 0);
+ SkASSERT(0 == fRec->data()[fRec->fLength]);
}
SkASSERT(fStr == c_str());
}
@@ -287,7 +275,7 @@ SkString::~SkString() {
if (fRec->fLength) {
SkASSERT(fRec->fRefCnt > 0);
- if (--fRec->fRefCnt == 0) {
+ if (sk_atomic_dec(&fRec->fRefCnt) == 1) {
sk_free(fRec);
}
}
@@ -331,7 +319,7 @@ void SkString::reset() {
if (fRec->fLength) {
SkASSERT(fRec->fRefCnt > 0);
- if (--fRec->fRefCnt == 0) {
+ if (sk_atomic_dec(&fRec->fRefCnt) == 1) {
sk_free(fRec);
}
}
@@ -347,8 +335,14 @@ char* SkString::writable_str() {
if (fRec->fLength) {
if (fRec->fRefCnt > 1) {
- fRec->fRefCnt -= 1;
- fRec = AllocRec(fRec->data(), fRec->fLength);
+ Rec* rec = AllocRec(fRec->data(), fRec->fLength);
+ if (sk_atomic_dec(&fRec->fRefCnt) == 1) {
+ // In this case after our check of fRecCnt > 1, we suddenly
+ // did become the only owner, so now we have two copies of the
+ // data (fRec and rec), so we need to delete one of them.
+ sk_free(fRec);
+ }
+ fRec = rec;
#ifdef SK_DEBUG
fStr = fRec->data();
#endif
@@ -362,9 +356,9 @@ void SkString::set(const char text[]) {
}
void SkString::set(const char text[], size_t len) {
- if (len == 0) {
+ if (0 == len) {
this->reset();
- } else if (fRec->fRefCnt == 1 && len <= fRec->fLength) {
+ } else if (1 == fRec->fRefCnt && 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();
@@ -372,15 +366,15 @@ void SkString::set(const char text[], size_t len) {
memcpy(p, text, len);
}
p[len] = 0;
- fRec->fLength = SkToU16(len);
- } else if (fRec->fRefCnt == 1 && ((unsigned)fRec->fLength >> 2) == (len >> 2)) {
+ fRec->fLength = len;
+ } else if (1 == fRec->fRefCnt && (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);
+ fRec->fLength = len;
} else {
SkString tmp(text, len);
this->swap(tmp);
@@ -397,7 +391,7 @@ void SkString::setUTF16(const uint16_t src[]) {
}
void SkString::setUTF16(const uint16_t src[], size_t count) {
- if (count == 0) {
+ if (0 == count) {
this->reset();
} else if (count <= fRec->fLength) {
// should we resize if len <<<< fLength, to save RAM? (e.g. len < (fLength>>1))
@@ -441,7 +435,7 @@ void SkString::insert(size_t offset, const char text[], size_t len) {
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)) {
+ if (1 == fRec->fRefCnt && (length >> 2) == ((length + len) >> 2)) {
char* dst = this->writable_str();
if (offset < length) {
@@ -450,7 +444,7 @@ void SkString::insert(size_t offset, const char text[], size_t len) {
memcpy(dst + offset, text, len);
dst[length + len] = 0;
- fRec->fLength = SkToU16(length + len);
+ fRec->fLength = 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.
@@ -542,8 +536,6 @@ void SkString::prependf(const char format[], ...) {
this->prepend(buffer, strlen(buffer));
}
-#undef VSNPRINTF
-
///////////////////////////////////////////////////////////////////////////////
void SkString::remove(size_t offset, size_t length) {
@@ -605,3 +597,17 @@ SkAutoUCS2::SkAutoUCS2(const char utf8[]) {
SkAutoUCS2::~SkAutoUCS2() {
sk_free(fUCS2);
}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkString SkStringPrintf(const char* format, ...) {
+ SkString formattedOutput;
+ char buffer[kBufferSize];
+ ARGS_TO_BUFFER(format, buffer, kBufferSize);
+ formattedOutput.set(buffer);
+ return formattedOutput;
+}
+
+#undef VSNPRINTF
+#undef SNPRINTF
+
diff --git a/src/core/SkStroke.cpp b/src/core/SkStroke.cpp
index c35400b..8816de5 100644
--- a/src/core/SkStroke.cpp
+++ b/src/core/SkStroke.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006-2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2008 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkStrokerPriv.h"
#include "SkGeometry.h"
#include "SkPath.h"
@@ -22,13 +15,7 @@
#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);
+ return !SkPoint::CanNormalize(v.fX, v.fY);
}
static inline bool normals_too_curvy(const SkVector& norm0, SkVector& norm1) {
@@ -226,7 +213,7 @@ void SkPathStroker::line_to(const SkPoint& currPt, const SkVector& normal) {
}
void SkPathStroker::lineTo(const SkPoint& currPt) {
- if (degenerate_line(fPrevPt, currPt)) {
+ if (SkPath::IsLineDegenerate(fPrevPt, currPt)) {
return;
}
SkVector normal, unitNormal;
@@ -357,8 +344,8 @@ DRAW_LINE:
}
void SkPathStroker::quadTo(const SkPoint& pt1, const SkPoint& pt2) {
- bool degenerateAB = degenerate_line(fPrevPt, pt1);
- bool degenerateBC = degenerate_line(pt1, pt2);
+ bool degenerateAB = SkPath::IsLineDegenerate(fPrevPt, pt1);
+ bool degenerateBC = SkPath::IsLineDegenerate(pt1, pt2);
if (degenerateAB | degenerateBC) {
if (degenerateAB ^ degenerateBC) {
@@ -413,9 +400,9 @@ void SkPathStroker::quadTo(const SkPoint& pt1, const SkPoint& pt2) {
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);
+ bool degenerateAB = SkPath::IsLineDegenerate(fPrevPt, pt1);
+ bool degenerateBC = SkPath::IsLineDegenerate(pt1, pt2);
+ bool degenerateCD = SkPath::IsLineDegenerate(pt2, pt3);
if (degenerateAB + degenerateBC + degenerateCD >= 2) {
this->lineTo(pt3);
@@ -632,11 +619,37 @@ void SkStroke::strokePath(const SkPath& src, SkPath* dst) const {
#endif
if (fDoFill) {
- dst->addPath(src);
+ if (src.cheapIsDirection(SkPath::kCCW_Direction)) {
+ dst->reverseAddPath(src);
+ } else {
+ dst->addPath(src);
+ }
} else {
- if (src.countPoints() == 2) {
+ // Seems like we can assume that a 2-point src would always result in
+ // a convex stroke, but testing has proved otherwise.
+ // TODO: fix the stroker to make this assumption true (without making
+ // it slower that the work that will be done in computeConvexity())
+#if 0
+ // this test results in a non-convex stroke :(
+ static void test(SkCanvas* canvas) {
+ SkPoint pts[] = { 146.333328, 192.333328, 300.333344, 293.333344 };
+ SkPaint paint;
+ paint.setStrokeWidth(7);
+ paint.setStrokeCap(SkPaint::kRound_Cap);
+ canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
+ }
+#endif
+#if 0
+ if (2 == src.countPoints()) {
dst->setIsConvex(true);
}
+#endif
+ }
+
+ // our answer should preserve the inverseness of the src
+ if (src.isInverseFillType()) {
+ SkASSERT(!dst->isInverseFillType());
+ dst->toggleInverseFillType();
}
}
diff --git a/src/core/SkStrokerPriv.cpp b/src/core/SkStrokerPriv.cpp
index 07833ca..85aae02 100644
--- a/src/core/SkStrokerPriv.cpp
+++ b/src/core/SkStrokerPriv.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkStrokerPriv.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkStrokerPriv.h"
#include "SkGeometry.h"
diff --git a/src/core/SkStrokerPriv.h b/src/core/SkStrokerPriv.h
index ecb9bde..e67d677 100644
--- a/src/core/SkStrokerPriv.h
+++ b/src/core/SkStrokerPriv.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkStrokerPriv.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkStrokerPriv_DEFINED
#define SkStrokerPriv_DEFINED
diff --git a/src/core/SkTSearch.cpp b/src/core/SkTSearch.cpp
index 6d9ff81..ccdcecb 100644
--- a/src/core/SkTSearch.cpp
+++ b/src/core/SkTSearch.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkTSearch.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTSearch.h"
#include <ctype.h>
diff --git a/src/core/SkTSort.h b/src/core/SkTSort.h
index d9544d7..38f8f22 100644
--- a/src/core/SkTSort.h
+++ b/src/core/SkTSort.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkTSort.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkTSort_DEFINED
#define SkTSort_DEFINED
diff --git a/src/core/SkTemplatesPriv.h b/src/core/SkTemplatesPriv.h
index b0a95a0..79ae609 100644
--- a/src/core/SkTemplatesPriv.h
+++ b/src/core/SkTemplatesPriv.h
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkTemplatesPriv.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkTemplatesPriv_DEFINED
#define SkTemplatesPriv_DEFINED
diff --git a/src/core/SkTextFormatParams.h b/src/core/SkTextFormatParams.h
index 3306270..c2767f9 100644
--- a/src/core/SkTextFormatParams.h
+++ b/src/core/SkTextFormatParams.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2010 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTextFormatParams_DEFINES
#define SkTextFormatParams_DEFINES
diff --git a/src/core/SkTypeface.cpp b/src/core/SkTypeface.cpp
index ca88d7c..e3b49e6 100644
--- a/src/core/SkTypeface.cpp
+++ b/src/core/SkTypeface.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2011 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkAdvancedTypefaceMetrics.h"
#include "SkTypeface.h"
#include "SkFontHost.h"
@@ -41,25 +34,25 @@ SkTypeface::~SkTypeface() {
///////////////////////////////////////////////////////////////////////////////
-uint32_t SkTypeface::UniqueID(const SkTypeface* face) {
- if (face) {
- return face->uniqueID();
+static SkTypeface* get_default_typeface() {
+ // we keep a reference to this guy for all time, since if we return its
+ // fontID, the font cache may later on ask to resolve that back into a
+ // typeface object.
+ static SkTypeface* gDefaultTypeface;
+
+ if (NULL == gDefaultTypeface) {
+ gDefaultTypeface =
+ SkFontHost::CreateTypeface(NULL, NULL, NULL, 0,
+ SkTypeface::kNormal);
}
+ return gDefaultTypeface;
+}
- // We cache the default fontID, assuming it will not change during a boot
- // The initial value of 0 is fine, since a typeface's uniqueID should not
- // be zero.
- static uint32_t gDefaultFontID;
-
- if (0 == gDefaultFontID) {
- SkTypeface* defaultFace =
- SkFontHost::CreateTypeface(NULL, NULL, NULL, 0,
- SkTypeface::kNormal);
- SkASSERT(defaultFace);
- gDefaultFontID = defaultFace->uniqueID();
- defaultFace->unref();
+uint32_t SkTypeface::UniqueID(const SkTypeface* face) {
+ if (NULL == face) {
+ face = get_default_typeface();
}
- return gDefaultFontID;
+ return face->uniqueID();
}
bool SkTypeface::Equal(const SkTypeface* facea, const SkTypeface* faceb) {
@@ -100,6 +93,11 @@ SkTypeface* SkTypeface::Deserialize(SkStream* stream) {
}
SkAdvancedTypefaceMetrics* SkTypeface::getAdvancedTypefaceMetrics(
- SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo) const {
- return SkFontHost::GetAdvancedTypefaceMetrics(fUniqueID, perGlyphInfo);
+ SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
+ const uint32_t* glyphIDs,
+ uint32_t glyphIDsCount) const {
+ return SkFontHost::GetAdvancedTypefaceMetrics(fUniqueID,
+ perGlyphInfo,
+ glyphIDs,
+ glyphIDsCount);
}
diff --git a/src/core/SkTypefaceCache.cpp b/src/core/SkTypefaceCache.cpp
index 4db6bfb..5a0b36c 100644
--- a/src/core/SkTypefaceCache.cpp
+++ b/src/core/SkTypefaceCache.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkTypefaceCache.h"
#include "SkThread.h"
@@ -73,6 +66,10 @@ void SkTypefaceCache::purge(int numToPurge) {
}
}
+void SkTypefaceCache::purgeAll() {
+ this->purge(fArray.count());
+}
+
///////////////////////////////////////////////////////////////////////////////
SkTypefaceCache& SkTypefaceCache::Get() {
@@ -102,6 +99,10 @@ SkTypeface* SkTypefaceCache::FindByProc(FindProc proc, void* ctx) {
return Get().findByProc(proc, ctx);
}
+void SkTypefaceCache::PurgeAll() {
+ Get().purgeAll();
+}
+
///////////////////////////////////////////////////////////////////////////////
#ifdef SK_DEBUG
diff --git a/src/core/SkTypefaceCache.h b/src/core/SkTypefaceCache.h
index 91411a4..b788d21 100644
--- a/src/core/SkTypefaceCache.h
+++ b/src/core/SkTypefaceCache.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkTypefaceCache_DEFINED
#define SkTypefaceCache_DEFINED
@@ -60,6 +53,13 @@ public:
static SkTypeface* FindByProc(FindProc proc, void* ctx);
/**
+ * This will unref all of the typefaces in the cache. Normally this is
+ * handled automatically as needed. This function is exposed for clients
+ * that explicitly want to purge the entire cache (e.g. to look for leaks).
+ */
+ static void PurgeAll();
+
+ /**
* Debugging only: dumps the status of the typefaces in the cache
*/
static void Dump();
@@ -71,6 +71,7 @@ private:
SkTypeface* findByID(SkFontID findID) const;
SkTypeface* findByProc(FindProc proc, void* ctx) const;
void purge(int count);
+ void purgeAll();
struct Rec {
SkTypeface* fFace;
diff --git a/src/core/SkUnPreMultiply.cpp b/src/core/SkUnPreMultiply.cpp
index 371af32..5f32da6 100644
--- a/src/core/SkUnPreMultiply.cpp
+++ b/src/core/SkUnPreMultiply.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkUnPreMultiply.h"
#include "SkColorPriv.h"
diff --git a/src/core/SkUtils.cpp b/src/core/SkUtils.cpp
index 6aa57ee..3f1c65e 100644
--- a/src/core/SkUtils.cpp
+++ b/src/core/SkUtils.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/sgl/SkUtils.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkUtils.h"
@@ -116,7 +108,6 @@ void sk_memset32_portable(uint32_t dst[], uint32_t value, int count) {
}
}
-#if !defined(ANDROID) || defined(SK_BUILD_FOR_ANDROID_NDK)
static void sk_memset16_stub(uint16_t dst[], uint16_t value, int count) {
SkMemset16Proc proc = SkMemset16GetPlatformProc();
sk_memset16 = proc ? proc : sk_memset16_portable;
@@ -133,8 +124,6 @@ static void sk_memset32_stub(uint32_t dst[], uint32_t value, int count) {
SkMemset32Proc sk_memset32 = sk_memset32_stub;
-#endif
-
///////////////////////////////////////////////////////////////////////////////
/* 0xxxxxxx 1 total
@@ -251,7 +240,7 @@ SkUnichar SkUTF8_PrevUnichar(const char** ptr) {
size_t SkUTF8_FromUnichar(SkUnichar uni, char utf8[]) {
if ((uint32_t)uni > 0x10FFFF) {
- SkASSERT(!"bad unichar");
+ SkDEBUGFAIL("bad unichar");
return 0;
}
diff --git a/src/core/SkWriter32.cpp b/src/core/SkWriter32.cpp
index 9a60b8e..dfa18a0 100644
--- a/src/core/SkWriter32.cpp
+++ b/src/core/SkWriter32.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkWriter32.h"
struct SkWriter32::Block {
@@ -188,23 +195,18 @@ bool SkWriter32::writeToStream(SkWStream* stream) {
///////////////////////////////////////////////////////////////////////////////
#include "SkReader32.h"
+#include "SkString.h"
+
+/*
+ * Strings are stored as: length[4-bytes] + string_data + '\0' + pad_to_mul_4
+ */
const char* SkReader32::readString(size_t* outLen) {
- // we need to read at least 1-4 bytes
- SkASSERT(this->isAvailable(4));
- const uint8_t* base = (const uint8_t*)this->peek();
- const uint8_t* ptr = base;
-
- size_t len = *ptr++;
- if (0xFF == len) {
- len = (ptr[0] << 8) | ptr[1];
- ptr += 2;
- SkASSERT(len < 0xFFFF);
- }
-
- // skip what we've read, and 0..3 pad bytes
- // add 1 for the terminating 0 that writeString() included
- size_t alignedSize = SkAlign4(len + (ptr - base) + 1);
+ size_t len = this->readInt();
+ const void* ptr = this->peek();
+
+ // skip over teh string + '\0' and then pad to a multiple of 4
+ size_t alignedSize = SkAlign4(len + 1);
this->skip(alignedSize);
if (outLen) {
@@ -213,26 +215,24 @@ const char* SkReader32::readString(size_t* outLen) {
return (const char*)ptr;
}
+size_t SkReader32::readIntoString(SkString* copy) {
+ size_t len;
+ const char* ptr = this->readString(&len);
+ if (copy) {
+ copy->set(ptr, len);
+ }
+ return len;
+}
+
void SkWriter32::writeString(const char str[], size_t len) {
if ((long)len < 0) {
SkASSERT(str);
len = strlen(str);
}
- size_t lenBytes = 1;
- if (len >= 0xFF) {
- lenBytes = 3;
- SkASSERT(len < 0xFFFF);
- }
+ this->write32(len);
// add 1 since we also write a terminating 0
- size_t alignedLen = SkAlign4(lenBytes + len + 1);
- uint8_t* ptr = (uint8_t*)this->reserve(alignedLen);
- if (1 == lenBytes) {
- *ptr++ = SkToU8(len);
- } else {
- *ptr++ = 0xFF;
- *ptr++ = SkToU8(len >> 8);
- *ptr++ = len & 0xFF;
- }
+ size_t alignedLen = SkAlign4(len + 1);
+ char* ptr = (char*)this->reserve(alignedLen);
memcpy(ptr, str, len);
ptr[len] = 0;
// we may have left 0,1,2,3 bytes uninitialized, since we reserved align4
@@ -244,11 +244,7 @@ size_t SkWriter32::WriteStringSize(const char* str, size_t len) {
SkASSERT(str);
len = strlen(str);
}
- size_t lenBytes = 1;
- if (len >= 0xFF) {
- lenBytes = 3;
- SkASSERT(len < 0xFFFF);
- }
+ const size_t lenBytes = 4; // we use 4 bytes to record the length
// add 1 since we also write a terminating 0
return SkAlign4(lenBytes + len + 1);
}
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
index 90cf13a..fdf1798 100644
--- a/src/core/SkXfermode.cpp
+++ b/src/core/SkXfermode.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkXfermode.h"
#include "SkColorPriv.h"
@@ -477,9 +470,9 @@ SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) {
return dst;
}
-void SkXfermode::xfer32(SK_RESTRICT SkPMColor dst[],
- const SK_RESTRICT SkPMColor src[], int count,
- const SK_RESTRICT SkAlpha aa[]) {
+void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT src, int count,
+ const SkAlpha* SK_RESTRICT aa) {
SkASSERT(dst && src && count >= 0);
if (NULL == aa) {
@@ -501,9 +494,9 @@ void SkXfermode::xfer32(SK_RESTRICT SkPMColor dst[],
}
}
-void SkXfermode::xfer16(SK_RESTRICT uint16_t dst[],
- const SK_RESTRICT SkPMColor src[], int count,
- const SK_RESTRICT SkAlpha aa[]) {
+void SkXfermode::xfer16(uint16_t* dst,
+ const SkPMColor* SK_RESTRICT src, int count,
+ const SkAlpha* SK_RESTRICT aa) {
SkASSERT(dst && src && count >= 0);
if (NULL == aa) {
@@ -526,9 +519,9 @@ void SkXfermode::xfer16(SK_RESTRICT uint16_t dst[],
}
}
-void SkXfermode::xfer4444(SK_RESTRICT SkPMColor16 dst[],
- const SK_RESTRICT SkPMColor src[], int count,
- const SK_RESTRICT SkAlpha aa[])
+void SkXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT src, int count,
+ const SkAlpha* SK_RESTRICT aa)
{
SkASSERT(dst && src && count >= 0);
@@ -552,9 +545,9 @@ void SkXfermode::xfer4444(SK_RESTRICT SkPMColor16 dst[],
}
}
-void SkXfermode::xferA8(SK_RESTRICT SkAlpha dst[],
+void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
const SkPMColor src[], int count,
- const SK_RESTRICT SkAlpha aa[])
+ const SkAlpha* SK_RESTRICT aa)
{
SkASSERT(dst && src && count >= 0);
@@ -581,9 +574,9 @@ void SkXfermode::xferA8(SK_RESTRICT SkAlpha dst[],
///////////////////////////////////////////////////////////////////////////////
-void SkProcXfermode::xfer32(SK_RESTRICT SkPMColor dst[],
- const SK_RESTRICT SkPMColor src[], int count,
- const SK_RESTRICT SkAlpha aa[]) {
+void SkProcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT src, int count,
+ const SkAlpha* SK_RESTRICT aa) {
SkASSERT(dst && src && count >= 0);
SkXfermodeProc proc = fProc;
@@ -609,9 +602,9 @@ void SkProcXfermode::xfer32(SK_RESTRICT SkPMColor dst[],
}
}
-void SkProcXfermode::xfer16(SK_RESTRICT uint16_t dst[],
- const SK_RESTRICT SkPMColor src[], int count,
- const SK_RESTRICT SkAlpha aa[]) {
+void SkProcXfermode::xfer16(uint16_t* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT src, int count,
+ const SkAlpha* SK_RESTRICT aa) {
SkASSERT(dst && src && count >= 0);
SkXfermodeProc proc = fProc;
@@ -638,9 +631,9 @@ void SkProcXfermode::xfer16(SK_RESTRICT uint16_t dst[],
}
}
-void SkProcXfermode::xfer4444(SK_RESTRICT SkPMColor16 dst[],
- const SK_RESTRICT SkPMColor src[], int count,
- const SK_RESTRICT SkAlpha aa[]) {
+void SkProcXfermode::xfer4444(SkPMColor16* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT src, int count,
+ const SkAlpha* SK_RESTRICT aa) {
SkASSERT(dst && src && count >= 0);
SkXfermodeProc proc = fProc;
@@ -667,9 +660,9 @@ void SkProcXfermode::xfer4444(SK_RESTRICT SkPMColor16 dst[],
}
}
-void SkProcXfermode::xferA8(SK_RESTRICT SkAlpha dst[],
- const SK_RESTRICT SkPMColor src[], int count,
- const SK_RESTRICT SkAlpha aa[]) {
+void SkProcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT src, int count,
+ const SkAlpha* SK_RESTRICT aa) {
SkASSERT(dst && src && count >= 0);
SkXfermodeProc proc = fProc;
@@ -699,11 +692,18 @@ void SkProcXfermode::xferA8(SK_RESTRICT SkAlpha dst[],
SkProcXfermode::SkProcXfermode(SkFlattenableReadBuffer& buffer)
: SkXfermode(buffer) {
+ // Might be a NULL if the Xfermode is recorded using the CrossProcess flag
fProc = (SkXfermodeProc)buffer.readFunctionPtr();
}
void SkProcXfermode::flatten(SkFlattenableWriteBuffer& buffer) {
- buffer.writeFunctionPtr((void*)fProc);
+ if (buffer.isCrossProcess()) {
+ // function pointer is only valid in the current process. Write a NULL
+ // so it can't be accidentally used
+ buffer.writeFunctionPtr(NULL);
+ } else {
+ buffer.writeFunctionPtr((void*)fProc);
+ }
}
///////////////////////////////////////////////////////////////////////////////
@@ -744,8 +744,6 @@ public:
virtual void flatten(SkFlattenableWriteBuffer& buffer) {
this->INHERITED::flatten(buffer);
buffer.write32(fMode);
- buffer.write32(fSrcCoeff);
- buffer.write32(fDstCoeff);
}
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
@@ -756,8 +754,13 @@ protected:
SkProcCoeffXfermode(SkFlattenableReadBuffer& buffer)
: INHERITED(buffer) {
fMode = (SkXfermode::Mode)buffer.readU32();
- fSrcCoeff = (Coeff)buffer.readU32();
- fDstCoeff = (Coeff)buffer.readU32();
+
+ const ProcCoeff& rec = gProcCoeffs[fMode];
+ // these may be valid, or may be CANNOT_USE_COEFF
+ fSrcCoeff = rec.fSC;
+ fDstCoeff = rec.fDC;
+ // now update our function-ptr in the super class
+ this->INHERITED::setProc(rec.fProc);
}
private:
@@ -774,44 +777,9 @@ class SkClearXfermode : public SkProcCoeffXfermode {
public:
SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
- virtual void xfer32(SK_RESTRICT SkPMColor dst[],
- const SK_RESTRICT SkPMColor[], int count,
- const SK_RESTRICT 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 (0xFF == a) {
- dst[i] = 0;
- } else if (a != 0) {
- dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
- }
- }
- }
- }
- virtual void xferA8(SK_RESTRICT SkAlpha dst[],
- const SK_RESTRICT SkPMColor[], int count,
- const SK_RESTRICT 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 (0xFF == a) {
- dst[i] = 0;
- } else if (0 != a) {
- dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
- }
- }
- }
- }
-
- virtual Factory getFactory() { return CreateProc; }
+ virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
+ virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
+ virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkClearXfermode, (buffer));
@@ -823,56 +791,52 @@ private:
};
-///////////////////////////////////////////////////////////////////////////////
-
-class SkSrcXfermode : public SkProcCoeffXfermode {
-public:
- SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
-
- virtual void xfer32(SK_RESTRICT SkPMColor dst[],
- const SK_RESTRICT SkPMColor src[], int count,
- const SK_RESTRICT SkAlpha aa[]) {
- SkASSERT(dst && src && count >= 0);
+void SkClearXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT, int count,
+ const SkAlpha* SK_RESTRICT aa) {
+ SkASSERT(dst && 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);
- }
+ if (NULL == aa) {
+ memset(dst, 0, count << 2);
+ } else {
+ for (int i = count - 1; i >= 0; --i) {
+ unsigned a = aa[i];
+ if (0xFF == a) {
+ dst[i] = 0;
+ } else if (a != 0) {
+ dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
}
}
}
+}
+void SkClearXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT, int count,
+ const SkAlpha* SK_RESTRICT aa) {
+ SkASSERT(dst && count >= 0);
- virtual void xferA8(SK_RESTRICT SkAlpha dst[],
- const SK_RESTRICT SkPMColor src[], int count,
- const SK_RESTRICT 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 (0 != a) {
- unsigned srcA = SkGetPackedA32(src[i]);
- if (a == 0xFF) {
- dst[i] = SkToU8(srcA);
- } else {
- dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
- }
- }
+ if (NULL == aa) {
+ memset(dst, 0, count);
+ } else {
+ for (int i = count - 1; i >= 0; --i) {
+ unsigned a = aa[i];
+ if (0xFF == a) {
+ dst[i] = 0;
+ } else if (0 != a) {
+ dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
}
}
}
+}
- virtual Factory getFactory() { return CreateProc; }
+///////////////////////////////////////////////////////////////////////////////
+
+class SkSrcXfermode : public SkProcCoeffXfermode {
+public:
+ SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
+
+ virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
+ virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
+ virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkSrcXfermode, (buffer));
@@ -884,31 +848,57 @@ private:
};
-class SkDstInXfermode : public SkProcCoeffXfermode {
-public:
- SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
+void SkSrcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT src, int count,
+ const SkAlpha* SK_RESTRICT 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 xfer32(SK_RESTRICT SkPMColor dst[],
- const SK_RESTRICT SkPMColor src[], int count,
- const SK_RESTRICT SkAlpha aa[]) {
- SkASSERT(dst && src);
+void SkSrcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT src, int count,
+ const SkAlpha* SK_RESTRICT aa) {
+ SkASSERT(dst && src && count >= 0);
- if (count <= 0) {
- return;
+ if (NULL == aa) {
+ for (int i = count - 1; i >= 0; --i) {
+ dst[i] = SkToU8(SkGetPackedA32(src[i]));
}
- if (NULL != aa) {
- return this->INHERITED::xfer32(dst, src, count, aa);
+ } else {
+ for (int i = count - 1; i >= 0; --i) {
+ unsigned a = aa[i];
+ if (0 != a) {
+ unsigned srcA = SkGetPackedA32(src[i]);
+ if (a == 0xFF) {
+ dst[i] = SkToU8(srcA);
+ } else {
+ dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
+ }
+ }
}
-
- do {
- unsigned a = SkGetPackedA32(*src);
- *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
- dst++;
- src++;
- } while (--count != 0);
}
+}
- virtual Factory getFactory() { return CreateProc; }
+////////////////////////////////////////////////////////////////////////////////////
+
+class SkDstInXfermode : public SkProcCoeffXfermode {
+public:
+ SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
+
+ virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
+ virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkDstInXfermode, (buffer));
@@ -920,31 +910,34 @@ private:
typedef SkProcCoeffXfermode INHERITED;
};
-class SkDstOutXfermode : public SkProcCoeffXfermode {
-public:
- SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
+void SkDstInXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT src, int count,
+ const SkAlpha* SK_RESTRICT aa) {
+ SkASSERT(dst && src);
- virtual void xfer32(SK_RESTRICT SkPMColor dst[],
- const SK_RESTRICT SkPMColor src[], int count,
- const SK_RESTRICT SkAlpha aa[]) {
- SkASSERT(dst && src);
+ if (count <= 0) {
+ return;
+ }
+ if (NULL != aa) {
+ return this->INHERITED::xfer32(dst, src, count, aa);
+ }
- if (count <= 0) {
- return;
- }
- if (NULL != aa) {
- return this->INHERITED::xfer32(dst, src, count, aa);
- }
+ do {
+ unsigned a = SkGetPackedA32(*src);
+ *dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
+ dst++;
+ src++;
+ } while (--count != 0);
+}
- do {
- unsigned a = SkGetPackedA32(*src);
- *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
- dst++;
- src++;
- } while (--count != 0);
- }
+/////////////////////////////////////////////////////////////////////////////////////////
- virtual Factory getFactory() { return CreateProc; }
+class SkDstOutXfermode : public SkProcCoeffXfermode {
+public:
+ SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
+
+ virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) SK_OVERRIDE;
+ virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkDstOutXfermode, (buffer));
@@ -957,6 +950,26 @@ private:
typedef SkProcCoeffXfermode INHERITED;
};
+void SkDstOutXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
+ const SkPMColor* SK_RESTRICT src, int count,
+ const SkAlpha* SK_RESTRICT aa) {
+ SkASSERT(dst && src);
+
+ if (count <= 0) {
+ return;
+ }
+ if (NULL != aa) {
+ return this->INHERITED::xfer32(dst, src, count, aa);
+ }
+
+ do {
+ unsigned a = SkGetPackedA32(*src);
+ *dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
+ dst++;
+ src++;
+ } while (--count != 0);
+}
+
///////////////////////////////////////////////////////////////////////////////
SkXfermode* SkXfermode::Create(Mode mode) {
@@ -1030,6 +1043,15 @@ bool SkXfermode::AsCoeff(SkXfermode* xfer, Coeff* src, Coeff* dst) {
return xfer->asCoeff(src, dst);
}
+bool SkXfermode::IsMode(SkXfermode* xfer, Mode mode) {
+ // if xfer==null then the mode is srcover
+ Mode m = kSrcOver_Mode;
+ if (xfer && !xfer->asMode(&m)) {
+ return false;
+ }
+ return mode == m;
+}
+
///////////////////////////////////////////////////////////////////////////////
//////////// 16bit xfermode procs
@@ -1198,18 +1220,10 @@ SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
return proc16;
}
-static SkFlattenable::Registrar
- gSkProcCoeffXfermodeReg("SkProcCoeffXfermode",
- SkProcCoeffXfermode::CreateProc);
-
-static SkFlattenable::Registrar
- gSkClearXfermodeReg("SkClearXfermode", SkClearXfermode::CreateProc);
-
-static SkFlattenable::Registrar
- gSkSrcXfermodeReg("SkSrcXfermode", SkSrcXfermode::CreateProc);
-
-static SkFlattenable::Registrar
- gSkDstInXfermodeReg("SkDstInXfermode", SkDstInXfermode::CreateProc);
-
-static SkFlattenable::Registrar
- gSkDstOutXfermodeReg("SkDstOutXfermode", SkDstOutXfermode::CreateProc);
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkClearXfermode)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSrcXfermode)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstInXfermode)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstOutXfermode)
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
diff --git a/src/core/core_files.mk b/src/core/core_files.mk
deleted file mode 100644
index 984f4e2..0000000
--- a/src/core/core_files.mk
+++ /dev/null
@@ -1,102 +0,0 @@
-SOURCE := \
- Sk64.cpp \
- SkAdvancedTypefaceMetrics.cpp \
- SkAlphaRuns.cpp \
- SkBitmap.cpp \
- SkBitmapProcShader.cpp \
- SkBitmapProcState.cpp \
- SkBitmapProcState_matrixProcs.cpp \
- SkBitmapSampler.cpp \
- SkBitmap_scroll.cpp \
- SkBlitRow_D16.cpp \
- SkBlitRow_D32.cpp \
- SkBlitRow_D4444.cpp \
- SkBlitter.cpp \
- SkBlitter_4444.cpp \
- SkBlitter_A1.cpp \
- SkBlitter_A8.cpp \
- SkBlitter_ARGB32.cpp \
- SkBlitter_ARGB32_Subpixel.cpp \
- SkBlitter_RGB16.cpp \
- SkBlitter_Sprite.cpp \
- SkBuffer.cpp \
- SkCanvas.cpp \
- SkChunkAlloc.cpp \
- SkClampRange.cpp \
- SkClipStack.cpp \
- SkColor.cpp \
- SkColorFilter.cpp \
- SkColorTable.cpp \
- SkConcaveToTriangles.cpp \
- SkComposeShader.cpp \
- SkCordic.cpp \
- SkCubicClipper.cpp \
- SkDebug.cpp \
- SkDeque.cpp \
- SkDevice.cpp \
- SkDither.cpp \
- SkDraw.cpp \
- SkEdge.cpp \
- SkEdgeBuilder.cpp \
- SkEdgeClipper.cpp \
- SkFilterProc.cpp \
- SkFlate.cpp \
- SkFlattenable.cpp \
- SkFloat.cpp \
- SkFloatBits.cpp \
- SkFontHost.cpp \
- SkGeometry.cpp \
- SkGlobals.cpp \
- SkGlyphCache.cpp \
- SkGraphics.cpp \
- SkLineClipper.cpp \
- SkMMapStream.cpp \
- SkMallocPixelRef.cpp \
- SkMask.cpp \
- SkMaskFilter.cpp \
- SkMath.cpp \
- SkMatrix.cpp \
- SkMemory_stdlib.cpp \
- SkMetaData.cpp \
- SkPackBits.cpp \
- SkPaint.cpp \
- SkPath.cpp \
- SkPathEffect.cpp \
- SkPathHeap.cpp \
- SkPathMeasure.cpp \
- SkPicture.cpp \
- SkPictureFlat.cpp \
- SkPicturePlayback.cpp \
- SkPictureRecord.cpp \
- SkPixelRef.cpp \
- SkPoint.cpp \
- SkPtrRecorder.cpp \
- SkQuadClipper.cpp \
- SkRasterizer.cpp \
- SkRect.cpp \
- SkRefDict.cpp \
- SkRegion.cpp \
- SkRegion_rects.cpp \
- SkRegion_path.cpp \
- SkScalar.cpp \
- SkScalerContext.cpp \
- SkScan.cpp \
- SkScan_AntiPath.cpp \
- SkScan_Antihair.cpp \
- SkScan_Hairline.cpp \
- SkScan_Path.cpp \
- SkShader.cpp \
- SkShape.cpp \
- SkSpriteBlitter_ARGB32.cpp \
- SkSpriteBlitter_RGB16.cpp \
- SkStream.cpp \
- SkString.cpp \
- SkStroke.cpp \
- SkStrokerPriv.cpp \
- SkTSearch.cpp \
- SkTypeface.cpp \
- SkTypefaceCache.cpp \
- SkUnPreMultiply.cpp \
- SkUtils.cpp \
- SkWriter32.cpp \
- SkXfermode.cpp
diff --git a/src/effects/Sk1DPathEffect.cpp b/src/effects/Sk1DPathEffect.cpp
index fe299c9..9ccc453 100644
--- a/src/effects/Sk1DPathEffect.cpp
+++ b/src/effects/Sk1DPathEffect.cpp
@@ -1,69 +1,57 @@
-/* libs/graphics/effects/Sk1DPathEffect.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "Sk1DPathEffect.h"
#include "SkPathMeasure.h"
-bool Sk1DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
-{
+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)
- {
+ while (distance < length) {
SkScalar delta = this->next(dst, distance, meas);
- if (delta <= 0)
+ if (delta <= 0) {
break;
+ }
distance += delta;
}
} while (meas.nextContour());
return true;
}
-///////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
SkPath1DPathEffect::SkPath1DPathEffect(const SkPath& path, SkScalar advance,
SkScalar phase, Style style) : fPath(path)
{
- if (advance <= 0 || path.isEmpty())
- {
+ if (advance <= 0 || path.isEmpty()) {
SkDEBUGF(("SkPath1DPathEffect can't use advance <= 0\n"));
fAdvance = 0; // signals we can't draw anything
- }
- else
- {
+ } else {
// cleanup their phase parameter, inverting it so that it becomes an
// offset along the path (to match the interpretation in PostScript)
- if (phase < 0)
- {
+ if (phase < 0) {
phase = -phase;
- if (phase > advance)
+ if (phase > advance) {
phase = SkScalarMod(phase, advance);
- }
- else
- {
- if (phase > advance)
+ }
+ } else {
+ if (phase > advance) {
phase = SkScalarMod(phase, advance);
+ }
phase = advance - phase;
}
// now catch the edge case where phase == advance (within epsilon)
- if (phase >= advance)
+ if (phase >= advance) {
phase = 0;
+ }
SkASSERT(phase >= 0);
fAdvance = advance;
@@ -76,10 +64,9 @@ SkPath1DPathEffect::SkPath1DPathEffect(const SkPath& path, SkScalar advance,
}
}
-bool SkPath1DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
-{
- if (fAdvance > 0)
- {
+bool SkPath1DPathEffect::filterPath(SkPath* dst, const SkPath& src,
+ SkScalar* width) {
+ if (fAdvance > 0) {
*width = -1;
return this->INHERITED::filterPath(dst, src, width);
}
@@ -87,10 +74,8 @@ bool SkPath1DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* wi
}
static void morphpoints(SkPoint dst[], const SkPoint src[], int count,
- SkPathMeasure& meas, SkScalar dist)
-{
- for (int i = 0; i < count; i++)
- {
+ SkPathMeasure& meas, SkScalar dist) {
+ for (int i = 0; i < count; i++) {
SkPoint pos;
SkVector tangent;
@@ -116,14 +101,13 @@ Need differentially more subdivisions when the follow-path is curvy. Not sure ho
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)
-{
+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)
- {
+
+ while ((verb = iter.next(srcP)) != SkPath::kDone_Verb) {
switch (verb) {
case SkPath::kMove_Verb:
morphpoints(dstP, srcP, 1, meas, dist);
@@ -146,14 +130,13 @@ static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas, SkSca
dst->close();
break;
default:
- SkASSERT(!"unknown verb");
+ SkDEBUGFAIL("unknown verb");
break;
}
}
}
-SkPath1DPathEffect::SkPath1DPathEffect(SkFlattenableReadBuffer& buffer)
-{
+SkPath1DPathEffect::SkPath1DPathEffect(SkFlattenableReadBuffer& buffer) {
fAdvance = buffer.readScalar();
if (fAdvance > 0) {
fPath.unflatten(buffer);
@@ -162,13 +145,11 @@ SkPath1DPathEffect::SkPath1DPathEffect(SkFlattenableReadBuffer& buffer)
}
}
-SkScalar SkPath1DPathEffect::begin(SkScalar contourLength)
-{
+SkScalar SkPath1DPathEffect::begin(SkScalar contourLength) {
return fInitialOffset;
}
-void SkPath1DPathEffect::flatten(SkFlattenableWriteBuffer& buffer)
-{
+void SkPath1DPathEffect::flatten(SkFlattenableWriteBuffer& buffer) {
buffer.writeScalar(fAdvance);
if (fAdvance > 0) {
fPath.flatten(buffer);
@@ -177,30 +158,30 @@ void SkPath1DPathEffect::flatten(SkFlattenableWriteBuffer& buffer)
}
}
-SkScalar SkPath1DPathEffect::next(SkPath* dst, SkScalar distance, SkPathMeasure& meas)
-{
+SkScalar SkPath1DPathEffect::next(SkPath* dst, SkScalar distance,
+ SkPathMeasure& meas) {
switch (fStyle) {
- case kTranslate_Style:
- {
+ case kTranslate_Style: {
SkPoint pos;
meas.getPosTan(distance, &pos, NULL);
dst->addPath(fPath, pos.fX, pos.fY);
- }
- break;
- case kRotate_Style:
- {
+ } break;
+ case kRotate_Style: {
SkMatrix matrix;
meas.getMatrix(distance, &matrix);
dst->addPath(fPath, matrix);
- }
- break;
+ } break;
case kMorph_Style:
morphpath(dst, fPath, meas, distance);
break;
default:
- SkASSERT(!"unknown Style enum");
+ SkDEBUGFAIL("unknown Style enum");
break;
}
return fAdvance;
}
+///////////////////////////////////////////////////////////////////////////////
+
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkPath1DPathEffect)
+
diff --git a/src/effects/Sk2DPathEffect.cpp b/src/effects/Sk2DPathEffect.cpp
index 1dfc24d..3729610 100644
--- a/src/effects/Sk2DPathEffect.cpp
+++ b/src/effects/Sk2DPathEffect.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/effects/Sk2DPathEffect.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "Sk2DPathEffect.h"
#include "SkBlitter.h"
@@ -23,10 +15,9 @@
class Sk2DPathEffectBlitter : public SkBlitter {
public:
Sk2DPathEffectBlitter(Sk2DPathEffect* pe, SkPath* dst)
- : fPE(pe), fDst(dst)
- {}
- virtual void blitH(int x, int y, int count)
- {
+ : fPE(pe), fDst(dst) {}
+
+ virtual void blitH(int x, int y, int count) {
fPE->nextSpan(x, y, count, fDst);
}
private:
@@ -34,15 +25,13 @@ private:
SkPath* fDst;
};
-////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
-Sk2DPathEffect::Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat)
-{
+Sk2DPathEffect::Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat) {
mat.invert(&fInverse);
}
-bool Sk2DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
-{
+bool Sk2DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width) {
Sk2DPathEffectBlitter blitter(this, dst);
SkPath tmp;
SkIRect ir;
@@ -50,19 +39,14 @@ bool Sk2DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
src.transform(fInverse, &tmp);
tmp.getBounds().round(&ir);
if (!ir.isEmpty()) {
- // need to pass a clip to fillpath, required for inverse filltypes,
- // even though those do not make sense for this patheffect
- SkRegion clip(ir);
-
this->begin(ir, dst);
- SkScan::FillPath(tmp, clip, &blitter);
+ SkScan::FillPath(tmp, ir, &blitter);
this->end(dst);
}
return true;
}
-void Sk2DPathEffect::nextSpan(int x, int y, int count, SkPath* path)
-{
+void Sk2DPathEffect::nextSpan(int x, int y, int count, SkPath* path) {
const SkMatrix& mat = this->getMatrix();
SkPoint src, dst;
@@ -78,18 +62,16 @@ void Sk2DPathEffect::begin(const SkIRect& uvBounds, SkPath* dst) {}
void Sk2DPathEffect::next(const SkPoint& loc, int u, int v, SkPath* dst) {}
void Sk2DPathEffect::end(SkPath* dst) {}
-////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
-void Sk2DPathEffect::flatten(SkFlattenableWriteBuffer& buffer)
-{
+void Sk2DPathEffect::flatten(SkFlattenableWriteBuffer& buffer) {
char storage[SkMatrix::kMaxFlattenSize];
uint32_t size = fMatrix.flatten(storage);
buffer.write32(size);
buffer.write(storage, size);
}
-Sk2DPathEffect::Sk2DPathEffect(SkFlattenableReadBuffer& buffer)
-{
+Sk2DPathEffect::Sk2DPathEffect(SkFlattenableReadBuffer& buffer) {
char storage[SkMatrix::kMaxFlattenSize];
uint32_t size = buffer.readS32();
SkASSERT(size <= sizeof(storage));
@@ -98,15 +80,42 @@ Sk2DPathEffect::Sk2DPathEffect(SkFlattenableReadBuffer& buffer)
fMatrix.invert(&fInverse);
}
-SkFlattenable::Factory Sk2DPathEffect::getFactory()
-{
+SkFlattenable::Factory Sk2DPathEffect::getFactory() {
return CreateProc;
}
-SkFlattenable* Sk2DPathEffect::CreateProc(SkFlattenableReadBuffer& buffer)
-{
+SkFlattenable* Sk2DPathEffect::CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(Sk2DPathEffect, (buffer));
}
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+SkPath2DPathEffect::SkPath2DPathEffect(const SkMatrix& m, const SkPath& p)
+ : INHERITED(m), fPath(p) {
+}
+
+SkPath2DPathEffect::SkPath2DPathEffect(SkFlattenableReadBuffer& buffer)
+ : INHERITED(buffer) {
+ fPath.unflatten(buffer);
+}
+
+SkFlattenable* SkPath2DPathEffect::CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkPath2DPathEffect, (buffer));
+}
+
+void SkPath2DPathEffect::flatten(SkFlattenableWriteBuffer& buffer) {
+ this->INHERITED::flatten(buffer);
+ fPath.flatten(buffer);
+}
+
+SkFlattenable::Factory SkPath2DPathEffect::getFactory() {
+ return CreateProc;
+}
+
+void SkPath2DPathEffect::next(const SkPoint& loc, int u, int v, SkPath* dst) {
+ dst->addPath(fPath, loc.fX, loc.fY);
+}
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkPath2DPathEffect)
diff --git a/src/effects/SkArithmeticMode.cpp b/src/effects/SkArithmeticMode.cpp
new file mode 100644
index 0000000..8190b39
--- /dev/null
+++ b/src/effects/SkArithmeticMode.cpp
@@ -0,0 +1,177 @@
+#include "SkArithmeticMode.h"
+#include "SkColorPriv.h"
+#include "SkUnPreMultiply.h"
+
+class SkArithmeticMode_scalar : public SkXfermode {
+public:
+ SkArithmeticMode_scalar(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4) {
+ fK[0] = k1;
+ fK[1] = k2;
+ fK[2] = k3;
+ fK[3] = k4;
+ }
+
+ virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
+ const SkAlpha aa[]) SK_OVERRIDE;
+ virtual Factory getFactory() SK_OVERRIDE;
+
+ static SkFlattenable* Create(SkFlattenableReadBuffer& buffer) {
+ return NULL;
+ }
+
+private:
+ SkScalar fK[4];
+};
+
+SkFlattenable::Factory SkArithmeticMode_scalar::getFactory() {
+ return Create;
+}
+
+static int pinToByte(int value) {
+ if (value < 0) {
+ value = 0;
+ } else if (value > 255) {
+ value = 255;
+ }
+ return value;
+}
+
+static int arith(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4,
+ int src, int dst) {
+ SkScalar result = SkScalarMul(k1, src * dst) +
+ SkScalarMul(k2, src) +
+ SkScalarMul(k3, dst) +
+ k4;
+ int res = SkScalarRoundToInt(result);
+ return pinToByte(res);
+}
+
+static int blend(int src, int dst, int scale) {
+ return dst + ((src - dst) * scale >> 8);
+}
+
+static bool needsUnpremul(int alpha) {
+ return 0 != alpha && 0xFF != alpha;
+}
+
+void SkArithmeticMode_scalar::xfer32(SkPMColor dst[], const SkPMColor src[],
+ int count, const SkAlpha aaCoverage[]) {
+ SkScalar k1 = fK[0] / 255;
+ SkScalar k2 = fK[1];
+ SkScalar k3 = fK[2];
+ SkScalar k4 = fK[3] * 255;
+
+ for (int i = 0; i < count; ++i) {
+ if ((NULL == aaCoverage) || aaCoverage[i]) {
+ SkPMColor sc = src[i];
+ SkPMColor dc = dst[i];
+ int sa = SkGetPackedA32(sc);
+ int da = SkGetPackedA32(dc);
+
+ int srcNeedsUnpremul = needsUnpremul(sa);
+ int dstNeedsUnpremul = needsUnpremul(sa);
+
+ int a, r, g, b;
+
+ if (!srcNeedsUnpremul && !srcNeedsUnpremul) {
+ a = arith(k1, k2, k3, k4, sa, sa);
+ r = arith(k1, k2, k3, k4, SkGetPackedR32(sc), SkGetPackedR32(dc));
+ g = arith(k1, k2, k3, k4, SkGetPackedG32(sc), SkGetPackedG32(dc));
+ b = arith(k1, k2, k3, k4, SkGetPackedB32(sc), SkGetPackedB32(dc));
+ } else {
+ int sr = SkGetPackedR32(sc);
+ int sg = SkGetPackedG32(sc);
+ int sb = SkGetPackedB32(sc);
+ if (srcNeedsUnpremul) {
+ SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(sa);
+ sr = SkUnPreMultiply::ApplyScale(scale, sr);
+ sg = SkUnPreMultiply::ApplyScale(scale, sg);
+ sb = SkUnPreMultiply::ApplyScale(scale, sb);
+ }
+
+ int dr = SkGetPackedR32(dc);
+ int dg = SkGetPackedG32(dc);
+ int db = SkGetPackedB32(dc);
+ if (dstNeedsUnpremul) {
+ SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(da);
+ dr = SkUnPreMultiply::ApplyScale(scale, dr);
+ dg = SkUnPreMultiply::ApplyScale(scale, dg);
+ db = SkUnPreMultiply::ApplyScale(scale, db);
+ }
+
+ a = arith(k1, k2, k3, k4, sa, sa);
+ r = arith(k1, k2, k3, k4, sr, dr);
+ g = arith(k1, k2, k3, k4, sg, dg);
+ b = arith(k1, k2, k3, k4, sb, db);
+ }
+
+ // apply antialias coverage if necessary
+ if (aaCoverage && 0xFF != aaCoverage[i]) {
+ int scale = aaCoverage[i] + (aaCoverage[i] >> 7);
+ a = blend(a, SkGetPackedA32(sc), scale);
+ r = blend(r, SkGetPackedR32(sc), scale);
+ g = blend(g, SkGetPackedG32(sc), scale);
+ b = blend(b, SkGetPackedB32(sc), scale);
+ }
+
+ // turn the result back into premul
+ if (0xFF != a) {
+ int scale = a + (a >> 7);
+ r = SkAlphaMul(r, scale);
+ g = SkAlphaMul(g, scale);
+ b = SkAlphaMul(b, scale);
+ }
+ dst[i] = SkPackARGB32(a, r, g, b);
+ }
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+static bool fitsInBits(SkScalar x, int bits) {
+#ifdef SK_SCALAR_IS_FIXED
+ x = SkAbs32(x);
+ x += 1 << 7;
+ x >>= 8;
+ return x < (1 << (bits - 1));
+#else
+ return SkScalarAbs(x) < (1 << (bits - 1));
+#endif
+}
+
+static int32_t toDot8(SkScalar x) {
+#ifdef SK_SCALAR_IS_FIXED
+ x += 1 << 7;
+ x >>= 8;
+ return x;
+#else
+ return (int32_t)(x * 256);
+#endif
+}
+
+SkXfermode* SkArithmeticMode::Create(SkScalar k1, SkScalar k2,
+ SkScalar k3, SkScalar k4) {
+ if (fitsInBits(k1, 8) && fitsInBits(k2, 16) &&
+ fitsInBits(k2, 16) && fitsInBits(k2, 24)) {
+
+ int32_t i1 = toDot8(k1);
+ int32_t i2 = toDot8(k2);
+ int32_t i3 = toDot8(k3);
+ int32_t i4 = toDot8(k4);
+#if 0
+ if (i1) {
+ return SkNEW_ARGS(SkArithmeticMode_quad, (i1, i2, i3, i4));
+ }
+ if (0 == i2) {
+ return SkNEW_ARGS(SkArithmeticMode_dst, (i3, i4));
+ }
+ if (0 == i3) {
+ return SkNEW_ARGS(SkArithmeticMode_src, (i2, i4));
+ }
+ return SkNEW_ARGS(SkArithmeticMode_linear, (i2, i3, i4));
+#endif
+ }
+ return SkNEW_ARGS(SkArithmeticMode_scalar, (k1, k2, k3, k4));
+}
+
diff --git a/src/effects/SkAvoidXfermode.cpp b/src/effects/SkAvoidXfermode.cpp
index de3fe28..d2cd49b 100644
--- a/src/effects/SkAvoidXfermode.cpp
+++ b/src/effects/SkAvoidXfermode.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/effects/SkAvoidXfermode.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkAvoidXfermode.h"
#include "SkColorPriv.h"
@@ -258,5 +250,4 @@ void SkAvoidXfermode::xferA8(SkAlpha dst[], const SkPMColor src[], int count, co
// override in subclass
}
-static SkFlattenable::Registrar
- gSkAvoidXfermodeReg("SkAvoidXfermode", SkAvoidXfermode::CreateProc);
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkAvoidXfermode)
diff --git a/src/effects/SkBitmapCache.cpp b/src/effects/SkBitmapCache.cpp
index 2a3f87a..f4b7b91 100644
--- a/src/effects/SkBitmapCache.cpp
+++ b/src/effects/SkBitmapCache.cpp
@@ -1,19 +1,12 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkBitmapCache.h"
struct SkBitmapCache::Entry {
@@ -24,7 +17,10 @@ struct SkBitmapCache::Entry {
size_t fSize;
SkBitmap fBitmap;
- Entry(const void* buffer, size_t size, const SkBitmap& bm) : fBitmap(bm) {
+ Entry(const void* buffer, size_t size, const SkBitmap& bm)
+ : fPrev(NULL),
+ fNext(NULL),
+ fBitmap(bm) {
fBuffer = sk_malloc_throw(size);
fSize = size;
memcpy(fBuffer, buffer, size);
diff --git a/src/effects/SkBitmapCache.h b/src/effects/SkBitmapCache.h
index 2c8b0c2..ea9cf91 100644
--- a/src/effects/SkBitmapCache.h
+++ b/src/effects/SkBitmapCache.h
@@ -1,19 +1,12 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkBitmapCache_DEFINED
#define SkBitmapCache_DEFINED
diff --git a/src/effects/SkBlurDrawLooper.cpp b/src/effects/SkBlurDrawLooper.cpp
index bde04ed..a44f081 100644
--- a/src/effects/SkBlurDrawLooper.cpp
+++ b/src/effects/SkBlurDrawLooper.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBlurDrawLooper.h"
#include "SkBlurMaskFilter.h"
#include "SkCanvas.h"
@@ -38,7 +45,9 @@ SkBlurDrawLooper::SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy,
}
}
-SkBlurDrawLooper::SkBlurDrawLooper(SkFlattenableReadBuffer& buffer) {
+SkBlurDrawLooper::SkBlurDrawLooper(SkFlattenableReadBuffer& buffer)
+: INHERITED(buffer) {
+
fDx = buffer.readScalar();
fDy = buffer.readScalar();
fBlurColor = buffer.readU32();
@@ -73,7 +82,7 @@ bool SkBlurDrawLooper::next(SkCanvas* canvas, SkPaint* paint) {
fState = kDone;
return false;
}
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
SkColor blurColor;
blurColor = fBlurColor;
if (SkColorGetA(blurColor) == 255) {
@@ -107,6 +116,5 @@ bool SkBlurDrawLooper::next(SkCanvas* canvas, SkPaint* paint) {
///////////////////////////////////////////////////////////////////////////////
-static SkFlattenable::Registrar gReg("SkBlurDrawLooper",
- SkBlurDrawLooper::CreateProc);
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkBlurDrawLooper)
diff --git a/src/effects/SkBlurImageFilter.cpp b/src/effects/SkBlurImageFilter.cpp
new file mode 100644
index 0000000..1446e92
--- /dev/null
+++ b/src/effects/SkBlurImageFilter.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBlurImageFilter.h"
+#include "SkColorPriv.h"
+
+SkBlurImageFilter::SkBlurImageFilter(SkFlattenableReadBuffer& buffer)
+ : INHERITED(buffer) {
+ fSigma.fWidth = buffer.readScalar();
+ fSigma.fHeight = buffer.readScalar();
+}
+
+SkBlurImageFilter::SkBlurImageFilter(SkScalar sigmaX, SkScalar sigmaY)
+ : fSigma(SkSize::Make(sigmaX, sigmaY)) {
+ SkASSERT(sigmaX >= 0 && sigmaY >= 0);
+}
+
+bool SkBlurImageFilter::asABlur(SkSize* sigma) const {
+ *sigma = fSigma;
+ return true;
+}
+
+void SkBlurImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
+ this->INHERITED::flatten(buffer);
+ buffer.writeScalar(fSigma.fWidth);
+ buffer.writeScalar(fSigma.fHeight);
+}
+
+static void boxBlurX(const SkBitmap& src, SkBitmap* dst, int kernelSize,
+ int leftOffset, int rightOffset)
+{
+ int width = src.width(), height = src.height();
+ int rightBorder = SkMin32(rightOffset + 1, width);
+ for (int y = 0; y < height; ++y) {
+ int sumA = 0, sumR = 0, sumG = 0, sumB = 0;
+ SkPMColor* p = src.getAddr32(0, y);
+ for (int i = 0; i < rightBorder; ++i) {
+ sumA += SkGetPackedA32(*p);
+ sumR += SkGetPackedR32(*p);
+ sumG += SkGetPackedG32(*p);
+ sumB += SkGetPackedB32(*p);
+ p++;
+ }
+
+ const SkColor* sptr = src.getAddr32(0, y);
+ SkColor* dptr = dst->getAddr32(0, y);
+ for (int x = 0; x < width; ++x) {
+ *dptr = SkPackARGB32(sumA / kernelSize,
+ sumR / kernelSize,
+ sumG / kernelSize,
+ sumB / kernelSize);
+ if (x >= leftOffset) {
+ SkColor l = *(sptr - leftOffset);
+ sumA -= SkGetPackedA32(l);
+ sumR -= SkGetPackedR32(l);
+ sumG -= SkGetPackedG32(l);
+ sumB -= SkGetPackedB32(l);
+ }
+ if (x + rightOffset + 1 < width) {
+ SkColor r = *(sptr + rightOffset + 1);
+ sumA += SkGetPackedA32(r);
+ sumR += SkGetPackedR32(r);
+ sumG += SkGetPackedG32(r);
+ sumB += SkGetPackedB32(r);
+ }
+ sptr++;
+ dptr++;
+ }
+ }
+}
+
+static void boxBlurY(const SkBitmap& src, SkBitmap* dst, int kernelSize,
+ int topOffset, int bottomOffset)
+{
+ int width = src.width(), height = src.height();
+ int bottomBorder = SkMin32(bottomOffset + 1, height);
+ int srcStride = src.rowBytesAsPixels();
+ int dstStride = dst->rowBytesAsPixels();
+ for (int x = 0; x < width; ++x) {
+ int sumA = 0, sumR = 0, sumG = 0, sumB = 0;
+ SkColor* p = src.getAddr32(x, 0);
+ for (int i = 0; i < bottomBorder; ++i) {
+ sumA += SkGetPackedA32(*p);
+ sumR += SkGetPackedR32(*p);
+ sumG += SkGetPackedG32(*p);
+ sumB += SkGetPackedB32(*p);
+ p += srcStride;
+ }
+
+ const SkColor* sptr = src.getAddr32(x, 0);
+ SkColor* dptr = dst->getAddr32(x, 0);
+ for (int y = 0; y < height; ++y) {
+ *dptr = SkPackARGB32(sumA / kernelSize,
+ sumR / kernelSize,
+ sumG / kernelSize,
+ sumB / kernelSize);
+ if (y >= topOffset) {
+ SkColor l = *(sptr - topOffset * srcStride);
+ sumA -= SkGetPackedA32(l);
+ sumR -= SkGetPackedR32(l);
+ sumG -= SkGetPackedG32(l);
+ sumB -= SkGetPackedB32(l);
+ }
+ if (y + bottomOffset + 1 < height) {
+ SkColor r = *(sptr + (bottomOffset + 1) * srcStride);
+ sumA += SkGetPackedA32(r);
+ sumR += SkGetPackedR32(r);
+ sumG += SkGetPackedG32(r);
+ sumB += SkGetPackedB32(r);
+ }
+ sptr += srcStride;
+ dptr += dstStride;
+ }
+ }
+}
+
+static void getBox3Params(SkScalar s, int *kernelSize, int* kernelSize3, int *lowOffset, int *highOffset)
+{
+ float pi = SkScalarToFloat(SK_ScalarPI);
+ int d = static_cast<int>(floorf(SkScalarToFloat(s) * 3.0f * sqrtf(2.0f * pi) / 4.0f + 0.5f));
+ *kernelSize = d;
+ if (d % 2 == 1) {
+ *lowOffset = *highOffset = (d - 1) / 2;
+ *kernelSize3 = d;
+ } else {
+ *highOffset = d / 2;
+ *lowOffset = *highOffset - 1;
+ *kernelSize3 = d + 1;
+ }
+}
+
+bool SkBlurImageFilter::onFilterImage(Proxy*,
+ const SkBitmap& src, const SkMatrix&,
+ SkBitmap* dst, SkIPoint*) {
+ if (src.config() != SkBitmap::kARGB_8888_Config) {
+ return false;
+ }
+
+ SkAutoLockPixels alp(src);
+ if (!src.getPixels()) {
+ return false;
+ }
+
+ dst->setConfig(src.config(), src.width(), src.height());
+ dst->allocPixels();
+ int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX;
+ int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY;
+ getBox3Params(fSigma.width(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffsetX);
+ getBox3Params(fSigma.height(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffsetY);
+
+ if (kernelSizeX < 0 || kernelSizeY < 0) {
+ return false;
+ }
+
+ if (kernelSizeX == 0 && kernelSizeY == 0) {
+ src.copyTo(dst, dst->config());
+ return true;
+ }
+
+ SkBitmap temp;
+ temp.setConfig(dst->config(), dst->width(), dst->height());
+ if (!temp.allocPixels()) {
+ return false;
+ }
+
+ if (kernelSizeX > 0 && kernelSizeY > 0) {
+ boxBlurX(src, &temp, kernelSizeX, lowOffsetX, highOffsetX);
+ boxBlurY(temp, dst, kernelSizeY, lowOffsetY, highOffsetY);
+ boxBlurX(*dst, &temp, kernelSizeX, highOffsetX, lowOffsetX);
+ boxBlurY(temp, dst, kernelSizeY, highOffsetY, lowOffsetY);
+ boxBlurX(*dst, &temp, kernelSizeX3, highOffsetX, highOffsetX);
+ boxBlurY(temp, dst, kernelSizeY3, highOffsetY, highOffsetY);
+ } else if (kernelSizeX > 0) {
+ boxBlurX(src, dst, kernelSizeX, lowOffsetX, highOffsetX);
+ boxBlurX(*dst, &temp, kernelSizeX, highOffsetX, lowOffsetX);
+ boxBlurX(temp, dst, kernelSizeX3, highOffsetX, highOffsetX);
+ } else if (kernelSizeY > 0) {
+ boxBlurY(src, dst, kernelSizeY, lowOffsetY, highOffsetY);
+ boxBlurY(*dst, &temp, kernelSizeY, highOffsetY, lowOffsetY);
+ boxBlurY(temp, dst, kernelSizeY3, highOffsetY, highOffsetY);
+ }
+ return true;
+}
+
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkBlurImageFilter)
diff --git a/src/effects/SkBlurMask.cpp b/src/effects/SkBlurMask.cpp
index f57a177..95a1e6b 100644
--- a/src/effects/SkBlurMask.cpp
+++ b/src/effects/SkBlurMask.cpp
@@ -1,36 +1,23 @@
-/* libs/graphics/effects/SkBlurMask.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkBlurMask.h"
+#include "SkMath.h"
#include "SkTemplates.h"
-
-#if 0
-static void dump_sum_buffer(const uint32_t sum[], const int w, const int h) {
- printf("---- sum buffer\n");
- for (int y = 0; y <= h; y++) {
- for (int x = 0; x <= w; x++) {
- printf(" %5d", sum[x]);
- }
- printf("\n");
- sum += w+1;
- }
-}
-#else
-#define dump_sum_buffer(sum, w, h)
+#include "SkEndian.h"
+
+// Unrolling the integer blur kernel seems to give us a ~15% speedup on Windows,
+// breakeven on Mac, and ~15% slowdown on Linux.
+// Reading a word at a time when bulding the sum buffer seems to give
+// us no appreciable speedup on Windows or Mac, and 2% slowdown on Linux.
+#if defined(SK_BUILD_FOR_WIN32)
+#define UNROLL_KERNEL_LOOP 1
#endif
/** The sum buffer is an array of u32 to hold the accumulated sum of all of the
@@ -43,7 +30,8 @@ static void dump_sum_buffer(const uint32_t sum[], const int w, const int h) {
We assume that the sum buffer's stride == its width
*/
-static void build_sum_buffer(uint32_t sum[], int srcW, int srcH, const uint8_t src[], int srcRB) {
+static void build_sum_buffer(uint32_t sum[], int srcW, int srcH,
+ const uint8_t src[], int srcRB) {
int sumW = srcW + 1;
SkASSERT(srcRB >= srcW);
@@ -59,21 +47,50 @@ static void build_sum_buffer(uint32_t sum[], int srcW, int srcH, const uint8_t s
// special case first row
uint32_t X = 0;
*sum++ = 0; // initialze the first column to 0
- for (x = srcW - 1; x >= 0; --x)
- {
+ for (x = srcW - 1; x >= 0; --x) {
X = *src++ + X;
*sum++ = X;
}
src += srcRB;
// now do the rest of the rows
- for (y = srcH - 1; y > 0; --y)
- {
+ for (y = srcH - 1; y > 0; --y) {
uint32_t L = 0;
uint32_t C = 0;
*sum++ = 0; // initialze the first column to 0
- for (x = srcW - 1; x >= 0; --x)
- {
+
+ for (x = srcW - 1; !SkIsAlign4((intptr_t) src) && x >= 0; x--) {
+ uint32_t T = sum[-sumW];
+ X = *src++ + L + T - C;
+ *sum++ = X;
+ L = X;
+ C = T;
+ }
+
+ for (; x >= 4; x-=4) {
+ uint32_t T = sum[-sumW];
+ X = *src++ + L + T - C;
+ *sum++ = X;
+ L = X;
+ C = T;
+ T = sum[-sumW];
+ X = *src++ + L + T - C;
+ *sum++ = X;
+ L = X;
+ C = T;
+ T = sum[-sumW];
+ X = *src++ + L + T - C;
+ *sum++ = X;
+ L = X;
+ C = T;
+ T = sum[-sumW];
+ X = *src++ + L + T - C;
+ *sum++ = X;
+ L = X;
+ C = T;
+ }
+
+ for (; x >= 0; --x) {
uint32_t T = sum[-sumW];
X = *src++ + L + T - C;
*sum++ = X;
@@ -84,13 +101,14 @@ static void build_sum_buffer(uint32_t sum[], int srcW, int srcH, const uint8_t s
}
}
-/* sw and sh are the width and height of the src. Since the sum buffer
- matches that, but has an extra row and col at the beginning (with zeros),
- we can just use sw and sh as our "max" values for pinning coordinates
- when sampling into sum[][]
+/**
+ * This is the path for apply_kernel() to be taken when the kernel
+ * is wider than the source image.
*/
-static void apply_kernel(uint8_t dst[], int rx, int ry, const uint32_t sum[],
- int sw, int sh) {
+static void kernel_clamped(uint8_t dst[], int rx, int ry, const uint32_t sum[],
+ int sw, int sh) {
+ SkASSERT(2*rx > sw);
+
uint32_t scale = (1 << 24) / ((2*rx + 1)*(2*ry + 1));
int sumStride = sw + 1;
@@ -118,20 +136,138 @@ static void apply_kernel(uint8_t dst[], int rx, int ry, const uint32_t sum[],
prev_x += 1;
next_x += 1;
}
+
+ prev_y += 1;
+ next_y += 1;
+ }
+}
+/**
+ * sw and sh are the width and height of the src. Since the sum buffer
+ * matches that, but has an extra row and col at the beginning (with zeros),
+ * we can just use sw and sh as our "max" values for pinning coordinates
+ * when sampling into sum[][]
+ *
+ * The inner loop is conceptually simple; we break it into several sections
+ * to improve performance. Here's the original version:
+ for (int x = 0; x < dw; x++) {
+ int px = SkClampPos(prev_x);
+ int nx = SkFastMin32(next_x, sw);
+
+ uint32_t tmp = sum[px+py] + sum[nx+ny] - sum[nx+py] - sum[px+ny];
+ *dst++ = SkToU8(tmp * scale >> 24);
+
+ prev_x += 1;
+ next_x += 1;
+ }
+ * The sections are:
+ * left-hand section, where prev_x is clamped to 0
+ * center section, where neither prev_x nor next_x is clamped
+ * right-hand section, where next_x is clamped to sw
+ * On some operating systems, the center section is unrolled for additional
+ * speedup.
+*/
+static void apply_kernel(uint8_t dst[], int rx, int ry, const uint32_t sum[],
+ int sw, int sh) {
+ if (2*rx > sw) {
+ kernel_clamped(dst, rx, ry, sum, sw, sh);
+ return;
+ }
+
+ uint32_t scale = (1 << 24) / ((2*rx + 1)*(2*ry + 1));
+
+ int sumStride = sw + 1;
+
+ int dw = sw + 2*rx;
+ int dh = sh + 2*ry;
+
+ int prev_y = -2*ry;
+ int next_y = 1;
+
+ SkASSERT(2*rx <= dw - 2*rx);
+
+ for (int y = 0; y < dh; y++) {
+ int py = SkClampPos(prev_y) * sumStride;
+ int ny = SkFastMin32(next_y, sh) * sumStride;
+
+ int prev_x = -2*rx;
+ int next_x = 1;
+ int x = 0;
+
+ for (; x < 2*rx; x++) {
+ SkASSERT(prev_x <= 0);
+ SkASSERT(next_x <= sw);
+
+ int px = 0;
+ int nx = next_x;
+
+ uint32_t tmp = sum[px+py] + sum[nx+ny] - sum[nx+py] - sum[px+ny];
+ *dst++ = SkToU8(tmp * scale >> 24);
+
+ prev_x += 1;
+ next_x += 1;
+ }
+
+ int i0 = prev_x + py;
+ int i1 = next_x + ny;
+ int i2 = next_x + py;
+ int i3 = prev_x + ny;
+
+#if UNROLL_KERNEL_LOOP
+ for (; x < dw - 2*rx - 4; x += 4) {
+ SkASSERT(prev_x >= 0);
+ SkASSERT(next_x <= sw);
+
+ uint32_t tmp = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
+ *dst++ = SkToU8(tmp * scale >> 24);
+ tmp = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
+ *dst++ = SkToU8(tmp * scale >> 24);
+ tmp = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
+ *dst++ = SkToU8(tmp * scale >> 24);
+ tmp = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
+ *dst++ = SkToU8(tmp * scale >> 24);
+
+ prev_x += 4;
+ next_x += 4;
+ }
+#endif
+
+ for (; x < dw - 2*rx; x++) {
+ SkASSERT(prev_x >= 0);
+ SkASSERT(next_x <= sw);
+
+ uint32_t tmp = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
+ *dst++ = SkToU8(tmp * scale >> 24);
+
+ prev_x += 1;
+ next_x += 1;
+ }
+
+ for (; x < dw; x++) {
+ SkASSERT(prev_x >= 0);
+ SkASSERT(next_x > sw);
+
+ int px = prev_x;
+ int nx = sw;
+
+ uint32_t tmp = sum[px+py] + sum[nx+ny] - sum[nx+py] - sum[px+ny];
+ *dst++ = SkToU8(tmp * scale >> 24);
+
+ prev_x += 1;
+ next_x += 1;
+ }
+
prev_y += 1;
next_y += 1;
}
}
-/* sw and sh are the width and height of the src. Since the sum buffer
- matches that, but has an extra row and col at the beginning (with zeros),
- we can just use sw and sh as our "max" values for pinning coordinates
- when sampling into sum[][]
+/**
+ * This is the path for apply_kernel_interp() to be taken when the kernel
+ * is wider than the source image.
*/
-static void apply_kernel_interp(uint8_t dst[], int rx, int ry,
+static void kernel_interp_clamped(uint8_t dst[], int rx, int ry,
const uint32_t sum[], int sw, int sh, U8CPU outer_weight) {
- SkASSERT(rx > 0 && ry > 0);
- SkASSERT(outer_weight <= 255);
+ SkASSERT(2*rx > sw);
int inner_weight = 255 - outer_weight;
@@ -167,13 +303,184 @@ static void apply_kernel_interp(uint8_t dst[], int rx, int ry,
int ipx = SkClampPos(prev_x + 1);
int inx = SkClampMax(next_x - 1, sw);
- uint32_t outer_sum = sum[px+py] + sum[nx+ny] - sum[nx+py] - sum[px+ny];
- uint32_t inner_sum = sum[ipx+ipy] + sum[inx+iny] - sum[inx+ipy] - sum[ipx+iny];
- *dst++ = SkToU8((outer_sum * outer_scale + inner_sum * inner_scale) >> 24);
+ uint32_t outer_sum = sum[px+py] + sum[nx+ny]
+ - sum[nx+py] - sum[px+ny];
+ uint32_t inner_sum = sum[ipx+ipy] + sum[inx+iny]
+ - sum[inx+ipy] - sum[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;
+ }
+}
+
+/**
+ * sw and sh are the width and height of the src. Since the sum buffer
+ * matches that, but has an extra row and col at the beginning (with zeros),
+ * we can just use sw and sh as our "max" values for pinning coordinates
+ * when sampling into sum[][]
+ *
+ * The inner loop is conceptually simple; we break it into several variants
+ * to improve performance. Here's the original version:
+ 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 = sum[px+py] + sum[nx+ny]
+ - sum[nx+py] - sum[px+ny];
+ uint32_t inner_sum = sum[ipx+ipy] + sum[inx+iny]
+ - sum[inx+ipy] - sum[ipx+iny];
+ *dst++ = SkToU8((outer_sum * outer_scale
+ + inner_sum * inner_scale) >> 24);
+
+ prev_x += 1;
+ next_x += 1;
+ }
+ * The sections are:
+ * left-hand section, where prev_x is clamped to 0
+ * center section, where neither prev_x nor next_x is clamped
+ * right-hand section, where next_x is clamped to sw
+ * On some operating systems, the center section is unrolled for additional
+ * speedup.
+*/
+static void apply_kernel_interp(uint8_t dst[], int rx, int ry,
+ const uint32_t sum[], int sw, int sh, U8CPU outer_weight) {
+ SkASSERT(rx > 0 && ry > 0);
+ SkASSERT(outer_weight <= 255);
+
+ if (2*rx > sw) {
+ kernel_interp_clamped(dst, rx, ry, sum, sw, sh, outer_weight);
+ return;
+ }
+
+ 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 sumStride = sw + 1;
+
+ int dw = sw + 2*rx;
+ int dh = sh + 2*ry;
+
+ int prev_y = -2*ry;
+ int next_y = 1;
+
+ SkASSERT(2*rx <= dw - 2*rx);
+
+ for (int y = 0; y < dh; y++) {
+ int py = SkClampPos(prev_y) * sumStride;
+ int ny = SkFastMin32(next_y, sh) * sumStride;
+
+ int ipy = SkClampPos(prev_y + 1) * sumStride;
+ int iny = SkClampMax(next_y - 1, sh) * sumStride;
+
+ int prev_x = -2*rx;
+ int next_x = 1;
+ int x = 0;
+
+ for (; x < 2*rx; x++) {
+ SkASSERT(prev_x < 0);
+ SkASSERT(next_x <= sw);
+
+ int px = 0;
+ int nx = next_x;
+
+ int ipx = 0;
+ int inx = next_x - 1;
+
+ uint32_t outer_sum = sum[px+py] + sum[nx+ny]
+ - sum[nx+py] - sum[px+ny];
+ uint32_t inner_sum = sum[ipx+ipy] + sum[inx+iny]
+ - sum[inx+ipy] - sum[ipx+iny];
+ *dst++ = SkToU8((outer_sum * outer_scale
+ + inner_sum * inner_scale) >> 24);
+
+ prev_x += 1;
+ next_x += 1;
+ }
+
+ int i0 = prev_x + py;
+ int i1 = next_x + ny;
+ int i2 = next_x + py;
+ int i3 = prev_x + ny;
+ int i4 = prev_x + 1 + ipy;
+ int i5 = next_x - 1 + iny;
+ int i6 = next_x - 1 + ipy;
+ int i7 = prev_x + 1 + iny;
+
+#if UNROLL_KERNEL_LOOP
+ for (; x < dw - 2*rx - 4; x += 4) {
+ SkASSERT(prev_x >= 0);
+ SkASSERT(next_x <= sw);
+
+ uint32_t outer_sum = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
+ uint32_t inner_sum = sum[i4++] + sum[i5++] - sum[i6++] - sum[i7++];
+ *dst++ = SkToU8((outer_sum * outer_scale
+ + inner_sum * inner_scale) >> 24);
+ outer_sum = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
+ inner_sum = sum[i4++] + sum[i5++] - sum[i6++] - sum[i7++];
+ *dst++ = SkToU8((outer_sum * outer_scale
+ + inner_sum * inner_scale) >> 24);
+ outer_sum = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
+ inner_sum = sum[i4++] + sum[i5++] - sum[i6++] - sum[i7++];
+ *dst++ = SkToU8((outer_sum * outer_scale
+ + inner_sum * inner_scale) >> 24);
+ outer_sum = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
+ inner_sum = sum[i4++] + sum[i5++] - sum[i6++] - sum[i7++];
+ *dst++ = SkToU8((outer_sum * outer_scale
+ + inner_sum * inner_scale) >> 24);
+
+ prev_x += 4;
+ next_x += 4;
+ }
+#endif
+
+ for (; x < dw - 2*rx; x++) {
+ SkASSERT(prev_x >= 0);
+ SkASSERT(next_x <= sw);
+
+ uint32_t outer_sum = sum[i0++] + sum[i1++] - sum[i2++] - sum[i3++];
+ uint32_t inner_sum = sum[i4++] + sum[i5++] - sum[i6++] - sum[i7++];
+ *dst++ = SkToU8((outer_sum * outer_scale
+ + inner_sum * inner_scale) >> 24);
prev_x += 1;
next_x += 1;
}
+
+ for (; x < dw; x++) {
+ SkASSERT(prev_x >= 0);
+ SkASSERT(next_x > sw);
+
+ int px = prev_x;
+ int nx = sw;
+
+ int ipx = prev_x + 1;
+ int inx = sw;
+
+ uint32_t outer_sum = sum[px+py] + sum[nx+ny]
+ - sum[nx+py] - sum[px+ny];
+ uint32_t inner_sum = sum[ipx+ipy] + sum[inx+iny]
+ - sum[inx+ipy] - sum[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;
}
@@ -227,7 +534,7 @@ static void clamp_with_orig(uint8_t dst[], int dstRowBytes,
}
break;
default:
- SkASSERT(!"Unexpected blur style here");
+ SkDEBUGFAIL("Unexpected blur style here");
break;
}
dst += dstRowBytes - sw;
@@ -235,21 +542,22 @@ static void clamp_with_orig(uint8_t dst[], int dstRowBytes,
}
}
-////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
// 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)
-{
+void SkMask_FreeImage(uint8_t* image) {
SkMask::FreeImage(image);
}
bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
- SkScalar radius, Style style, Quality quality)
+ SkScalar radius, Style style, Quality quality,
+ SkIPoint* margin)
{
- if (src.fFormat != SkMask::kA8_Format)
+ if (src.fFormat != SkMask::kA8_Format) {
return false;
+ }
// Force high quality off for small radii (performance)
if (radius < SkIntToScalar(3)) quality = kLow_Quality;
@@ -271,6 +579,9 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
int padx = passCount * rx;
int pady = passCount * ry;
+ if (margin) {
+ margin->set(padx, pady);
+ }
dst->fBounds.set(src.fBounds.fLeft - padx, src.fBounds.fTop - pady,
src.fBounds.fRight + padx, src.fBounds.fBottom + pady);
dst->fRowBytes = dst->fBounds.width();
@@ -292,19 +603,20 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
// build the blurry destination
{
- SkAutoTMalloc<uint32_t> storage((sw + 2 * (passCount - 1) * rx + 1) * (sh + 2 * (passCount - 1) * ry + 1));
+ const size_t storageW = sw + 2 * (passCount - 1) * rx + 1;
+ const size_t storageH = sh + 2 * (passCount - 1) * ry + 1;
+ SkAutoTMalloc<uint32_t> storage(storageW * storageH);
uint32_t* sumBuffer = storage.get();
//pass1: sp is source, dp is destination
build_sum_buffer(sumBuffer, sw, sh, sp, src.fRowBytes);
- dump_sum_buffer(sumBuffer, sw, sh);
- if (outer_weight == 255)
+ if (outer_weight == 255) {
apply_kernel(dp, rx, ry, sumBuffer, sw, sh);
- else
+ } else {
apply_kernel_interp(dp, rx, ry, sumBuffer, sw, sh, outer_weight);
+ }
- if (quality == kHigh_Quality)
- {
+ if (quality == kHigh_Quality) {
//pass2: dp is source, tmpBuffer is destination
int tmp_sw = sw + 2 * rx;
int tmp_sh = sh + 2 * ry;
@@ -313,7 +625,8 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
if (outer_weight == 255)
apply_kernel(tmpBuffer.get(), rx, ry, sumBuffer, tmp_sw, tmp_sh);
else
- apply_kernel_interp(tmpBuffer.get(), rx, ry, sumBuffer, tmp_sw, tmp_sh, outer_weight);
+ apply_kernel_interp(tmpBuffer.get(), rx, ry, sumBuffer,
+ tmp_sw, tmp_sh, outer_weight);
//pass3: tmpBuffer is source, dp is destination
tmp_sw += 2 * rx;
@@ -322,7 +635,8 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
if (outer_weight == 255)
apply_kernel(dp, rx, ry, sumBuffer, tmp_sw, tmp_sh);
else
- apply_kernel_interp(dp, rx, ry, sumBuffer, tmp_sw, tmp_sh, outer_weight);
+ apply_kernel_interp(dp, rx, ry, sumBuffer, tmp_sw, tmp_sh,
+ outer_weight);
}
}
@@ -338,13 +652,12 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
dst->fImage = SkMask::AllocImage(srcSize);
merge_src_with_blur(dst->fImage, src.fRowBytes,
sp, src.fRowBytes,
- dp + passCount * (rx + ry * dst->fRowBytes), dst->fRowBytes,
- sw, sh);
+ dp + passCount * (rx + ry * dst->fRowBytes),
+ dst->fRowBytes, sw, sh);
SkMask::FreeImage(dp);
} else if (style != kNormal_Style) {
- clamp_with_orig(dp + passCount * (rx + ry * dst->fRowBytes), dst->fRowBytes,
- sp, src.fRowBytes, sw, sh,
- style);
+ clamp_with_orig(dp + passCount * (rx + ry * dst->fRowBytes),
+ dst->fRowBytes, sp, src.fRowBytes, sw, sh, style);
}
(void)autoCall.detach();
}
@@ -354,53 +667,6 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
dst->fRowBytes = src.fRowBytes;
}
-#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/src/effects/SkBlurMask.h b/src/effects/SkBlurMask.h
index 560ef48..3709dee 100644
--- a/src/effects/SkBlurMask.h
+++ b/src/effects/SkBlurMask.h
@@ -1,19 +1,11 @@
-/* libs/graphics/effects/SkBlurMask.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkBlurMask_DEFINED
#define SkBlurMask_DEFINED
@@ -36,7 +28,9 @@ public:
kHigh_Quality //!< three pass box blur (similar to gaussian)
};
- static bool Blur(SkMask* dst, const SkMask& src, SkScalar radius, Style, Quality quality);
+ static bool Blur(SkMask* dst, const SkMask& src,
+ SkScalar radius, Style style, Quality quality,
+ SkIPoint* margin = NULL);
};
#endif
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index ad00d17..fe428d9 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/effects/SkBlurMaskFilter.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkBlurMaskFilter.h"
#include "SkBlurMask.h"
@@ -22,18 +14,19 @@
class SkBlurMaskFilterImpl : public SkMaskFilter {
public:
- SkBlurMaskFilterImpl(SkScalar radius, SkBlurMaskFilter::BlurStyle style, uint32_t flags);
+ SkBlurMaskFilterImpl(SkScalar radius, SkBlurMaskFilter::BlurStyle,
+ uint32_t flags);
// overrides from SkMaskFilter
- virtual SkMask::Format getFormat();
- virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkIPoint* margin);
- virtual void computeFastBounds(const SkRect& src, SkRect* dst);
+ virtual SkMask::Format getFormat() SK_OVERRIDE;
+ virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
+ SkIPoint* margin) SK_OVERRIDE;
+ virtual BlurType asABlur(BlurInfo*) const SK_OVERRIDE;
+ virtual void computeFastBounds(const SkRect& src, SkRect* dst) SK_OVERRIDE;
// overrides from SkFlattenable
- // This method is not exported to java.
- virtual Factory getFactory();
- // This method is not exported to java.
- virtual void flatten(SkFlattenableWriteBuffer&);
+ virtual Factory getFactory() SK_OVERRIDE;
+ virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);
@@ -47,26 +40,27 @@ private:
typedef SkMaskFilter INHERITED;
};
-SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius, SkBlurMaskFilter::BlurStyle style,
- uint32_t flags)
-{
- if (radius <= 0 || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount
- || flags > SkBlurMaskFilter::kAll_BlurFlag)
+SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius,
+ SkBlurMaskFilter::BlurStyle style,
+ uint32_t flags) {
+ // use !(radius > 0) instead of radius <= 0 to reject NaN values
+ if (!(radius > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount
+ || flags > SkBlurMaskFilter::kAll_BlurFlag) {
return NULL;
+ }
return SkNEW_ARGS(SkBlurMaskFilterImpl, (radius, style, flags));
}
-/////////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
-SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar radius, SkBlurMaskFilter::BlurStyle style,
+SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar radius,
+ SkBlurMaskFilter::BlurStyle style,
uint32_t flags)
- : fRadius(radius), fBlurStyle(style), fBlurFlags(flags)
-{
+ : fRadius(radius), fBlurStyle(style), fBlurFlags(flags) {
#if 0
fGamma = NULL;
- if (gammaScale)
- {
+ if (gammaScale) {
fGamma = new U8[256];
if (gammaScale > 0)
SkBlurMask::BuildSqrGamma(fGamma, gammaScale);
@@ -79,37 +73,30 @@ SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar radius, SkBlurMaskFilter::Bl
SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag);
}
-SkMask::Format SkBlurMaskFilterImpl::getFormat()
-{
+SkMask::Format SkBlurMaskFilterImpl::getFormat() {
return SkMask::kA8_Format;
}
-bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkIPoint* margin)
-{
+bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
+ const SkMatrix& matrix, SkIPoint* margin) {
SkScalar radius;
- if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag)
+ if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
radius = fRadius;
- else
+ } else {
radius = matrix.mapRadius(fRadius);
+ }
// To avoid unseemly allocation requests (esp. for finite platforms like
// handset) we limit the radius so something manageable. (as opposed to
// a request like 10,000)
static const SkScalar MAX_RADIUS = SkIntToScalar(128);
radius = SkMinScalar(radius, MAX_RADIUS);
- SkBlurMask::Quality blurQuality = (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
- SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality;
-
- if (SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle, blurQuality))
- {
- if (margin) {
- // we need to integralize radius for our margin, so take the ceil
- // just to be safe.
- margin->set(SkScalarCeil(radius), SkScalarCeil(radius));
- }
- return true;
- }
- return false;
+ SkBlurMask::Quality blurQuality =
+ (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
+ SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality;
+
+ return SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle,
+ blurQuality, margin);
}
void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src, SkRect* dst) {
@@ -117,18 +104,16 @@ void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src, SkRect* dst) {
src.fRight + fRadius, src.fBottom + fRadius);
}
-SkFlattenable* SkBlurMaskFilterImpl::CreateProc(SkFlattenableReadBuffer& buffer)
-{
+SkFlattenable* SkBlurMaskFilterImpl::CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkBlurMaskFilterImpl, (buffer));
}
-SkFlattenable::Factory SkBlurMaskFilterImpl::getFactory()
-{
+SkFlattenable::Factory SkBlurMaskFilterImpl::getFactory() {
return CreateProc;
}
-SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkFlattenableReadBuffer& buffer) : SkMaskFilter(buffer)
-{
+SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkFlattenableReadBuffer& buffer)
+ : SkMaskFilter(buffer) {
fRadius = buffer.readScalar();
fBlurStyle = (SkBlurMaskFilter::BlurStyle)buffer.readS32();
fBlurFlags = buffer.readU32() & SkBlurMaskFilter::kAll_BlurFlag;
@@ -136,16 +121,29 @@ SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkFlattenableReadBuffer& buffer) : Sk
SkASSERT((unsigned)fBlurStyle < SkBlurMaskFilter::kBlurStyleCount);
}
-void SkBlurMaskFilterImpl::flatten(SkFlattenableWriteBuffer& buffer)
-{
+void SkBlurMaskFilterImpl::flatten(SkFlattenableWriteBuffer& buffer) {
this->INHERITED::flatten(buffer);
buffer.writeScalar(fRadius);
buffer.write32(fBlurStyle);
buffer.write32(fBlurFlags);
}
-///////////////////////////////////////////////////////////////////////////////
+static const SkMaskFilter::BlurType gBlurStyle2BlurType[] = {
+ SkMaskFilter::kNormal_BlurType,
+ SkMaskFilter::kSolid_BlurType,
+ SkMaskFilter::kOuter_BlurType,
+ SkMaskFilter::kInner_BlurType,
+};
-static SkFlattenable::Registrar gReg("SkBlurMaskFilter",
- SkBlurMaskFilterImpl::CreateProc);
+SkMaskFilter::BlurType SkBlurMaskFilterImpl::asABlur(BlurInfo* info) const {
+ if (info) {
+ info->fRadius = fRadius;
+ info->fIgnoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
+ info->fHighQuality = SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag);
+ }
+ return gBlurStyle2BlurType[fBlurStyle];
+}
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
diff --git a/src/effects/SkColorFilters.cpp b/src/effects/SkColorFilters.cpp
index 0f8e227..e6262c1 100644
--- a/src/effects/SkColorFilters.cpp
+++ b/src/effects/SkColorFilters.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2006 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkBlitRow.h"
#include "SkColorFilter.h"
#include "SkColorPriv.h"
@@ -330,6 +323,10 @@ public:
}
}
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkLightingColorFilter, (buffer));
+ }
+
protected:
virtual void flatten(SkFlattenableWriteBuffer& buffer) {
this->INHERITED::flatten(buffer);
@@ -349,10 +346,6 @@ protected:
SkColor fMul, fAdd;
private:
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
- return SkNEW_ARGS(SkLightingColorFilter, (buffer));
- }
-
typedef SkColorFilter INHERITED;
};
@@ -381,6 +374,10 @@ public:
}
}
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkLightingColorFilter_JustAdd, (buffer));
+ }
+
protected:
virtual Factory getFactory() { return CreateProc; }
@@ -388,10 +385,6 @@ protected:
: INHERITED(buffer) {}
private:
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
- return SkNEW_ARGS(SkLightingColorFilter_JustAdd, (buffer));
- }
-
typedef SkLightingColorFilter INHERITED;
};
@@ -419,6 +412,10 @@ public:
}
}
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkLightingColorFilter_JustMul, (buffer));
+ }
+
protected:
virtual Factory getFactory() { return CreateProc; }
@@ -426,10 +423,6 @@ protected:
: INHERITED(buffer) {}
private:
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
- return SkNEW_ARGS(SkLightingColorFilter_JustMul, (buffer));
- }
-
typedef SkLightingColorFilter INHERITED;
};
@@ -460,6 +453,10 @@ public:
}
}
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkLightingColorFilter_SingleMul, (buffer));
+ }
+
protected:
virtual Factory getFactory() { return CreateProc; }
@@ -467,10 +464,6 @@ protected:
: INHERITED(buffer) {}
private:
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
- return SkNEW_ARGS(SkLightingColorFilter_SingleMul, (buffer));
- }
-
typedef SkLightingColorFilter INHERITED;
};
@@ -503,6 +496,10 @@ public:
}
}
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkLightingColorFilter_NoPin, (buffer));
+ }
+
protected:
virtual Factory getFactory() { return CreateProc; }
@@ -510,16 +507,17 @@ protected:
: INHERITED(buffer) {}
private:
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
- return SkNEW_ARGS(SkLightingColorFilter_NoPin, (buffer));
- }
-
typedef SkLightingColorFilter INHERITED;
};
///////////////////////////////////////////////////////////////////////////////
class SkSimpleColorFilter : public SkColorFilter {
+public:
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW(SkSimpleColorFilter);
+ }
+
protected:
void filterSpan(const SkPMColor src[], int count, SkPMColor result[]) {
if (result != src) {
@@ -533,9 +531,6 @@ protected:
return CreateProc;
}
- static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
- return SkNEW(SkSimpleColorFilter);
- }
};
SkColorFilter* SkColorFilter::CreateLightingFilter(SkColor mul, SkColor add) {
@@ -568,14 +563,15 @@ SkColorFilter* SkColorFilter::CreateLightingFilter(SkColor mul, SkColor add) {
return SkNEW_ARGS(SkLightingColorFilter, (mul, add));
}
-static SkFlattenable::Registrar
- gSrcColorFilterReg("Src_SkModeColorFilterReg",
- Src_SkModeColorFilter::CreateProc);
-
-static SkFlattenable::Registrar
- gSrcOverColorFilterReg("SrcOver_SkModeColorFilterReg",
- SrcOver_SkModeColorFilter::CreateProc);
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkColorFilter)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Src_SkModeColorFilter)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SrcOver_SkModeColorFilter)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Proc_SkModeColorFilter)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingColorFilter)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingColorFilter_JustAdd)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingColorFilter_JustMul)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingColorFilter_SingleMul)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingColorFilter_NoPin)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSimpleColorFilter)
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
-static SkFlattenable::Registrar
- gProcColorFilterReg("Proc_SkModeColorFilterReg",
- Proc_SkModeColorFilter::CreateProc);
diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp
index 9270052..79fbea5 100644
--- a/src/effects/SkColorMatrixFilter.cpp
+++ b/src/effects/SkColorMatrixFilter.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkColorMatrixFilter.h"
#include "SkColorMatrix.h"
#include "SkColorPriv.h"
@@ -110,7 +117,9 @@ static void Add16(SkColorMatrixFilter::State* state,
#define kNO_ALPHA_FLAGS (SkColorFilter::kAlphaUnchanged_Flag | \
SkColorFilter::kHasFilter16_Flag)
-void SkColorMatrixFilter::setup(const SkScalar SK_RESTRICT src[20]) {
+// src is [20] but some compilers won't accept __restrict__ on anything
+// but an raw pointer or reference
+void SkColorMatrixFilter::setup(const SkScalar* SK_RESTRICT src) {
if (NULL == src) {
fProc = NULL; // signals identity
fFlags = kNO_ALPHA_FLAGS;
@@ -118,7 +127,7 @@ void SkColorMatrixFilter::setup(const SkScalar SK_RESTRICT src[20]) {
return;
}
- int32_t* SK_RESTRICT array = fState.fArray;
+ int32_t* array = fState.fArray;
int i;
SkFixed max = 0;
@@ -223,7 +232,7 @@ void SkColorMatrixFilter::filterSpan(const SkPMColor src[], int count,
SkPMColor dst[]) {
Proc proc = fProc;
State* state = &fState;
- int32_t* SK_RESTRICT result = state->fResult;
+ int32_t* result = state->fResult;
if (NULL == proc) {
if (src != dst) {
@@ -261,13 +270,7 @@ void SkColorMatrixFilter::filterSpan(const SkPMColor src[], int count,
b = pin(result[2], SK_B32_MASK);
a = pin(result[3], SK_A32_MASK);
// re-prepremultiply if needed
- if (255 != a) {
- int scale = SkAlpha255To256(a);
- r = SkAlphaMul(r, scale);
- g = SkAlphaMul(g, scale);
- b = SkAlphaMul(b, scale);
- }
- dst[i] = SkPackARGB32(a, r, g, b);
+ dst[i] = SkPremultiplyARGBInline(a, r, g, b);
}
}
@@ -277,7 +280,7 @@ void SkColorMatrixFilter::filterSpan16(const uint16_t src[], int count,
Proc proc = fProc;
State* state = &fState;
- int32_t* SK_RESTRICT result = state->fResult;
+ int32_t* result = state->fResult;
if (NULL == proc) {
if (src != dst) {
@@ -324,10 +327,33 @@ SkColorMatrixFilter::SkColorMatrixFilter(SkFlattenableReadBuffer& buffer)
fFlags = buffer.readU32();
}
+bool SkColorMatrixFilter::asColorMatrix(SkScalar matrix[20]) {
+ int32_t* array = fState.fArray;
+ int unshift = 16 - fState.fShift;
+ for (int i = 0; i < 20; i++) {
+ matrix[i] = SkFixedToScalar(array[i] << unshift);
+ }
+ if (NULL != fProc) {
+ // Undo the offset applied to the constant column in setup().
+ SkFixed offset = 1 << (fState.fShift - 1);
+ matrix[4] = SkFixedToScalar((array[4] - offset) << unshift);
+ matrix[9] = SkFixedToScalar((array[9] - offset) << unshift);
+ matrix[14] = SkFixedToScalar((array[14] - offset) << unshift);
+ matrix[19] = SkFixedToScalar((array[19] - offset) << unshift);
+ }
+ return true;
+}
+
SkFlattenable* SkColorMatrixFilter::CreateProc(SkFlattenableReadBuffer& buf) {
return SkNEW_ARGS(SkColorMatrixFilter, (buf));
}
-static SkFlattenable::Registrar
- gSkColorMatrixFilterReg("SkColorMatrixFilter",
- SkColorMatrixFilter::CreateProc);
+void SkColorMatrixFilter::setMatrix(const SkColorMatrix& matrix) {
+ setup(matrix.fMat);
+}
+
+void SkColorMatrixFilter::setArray(const SkScalar array[20]) {
+ setup(array);
+}
+
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkColorMatrixFilter)
diff --git a/src/effects/SkCornerPathEffect.cpp b/src/effects/SkCornerPathEffect.cpp
index 158cefa..4da31ab 100644
--- a/src/effects/SkCornerPathEffect.cpp
+++ b/src/effects/SkCornerPathEffect.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/effects/SkCornerPathEffect.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkCornerPathEffect.h"
#include "SkPath.h"
@@ -153,3 +145,5 @@ SkCornerPathEffect::SkCornerPathEffect(SkFlattenableReadBuffer& buffer) {
fRadius = buffer.readScalar();
}
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkCornerPathEffect)
+
diff --git a/src/effects/SkDashPathEffect.cpp b/src/effects/SkDashPathEffect.cpp
index f6b9dba..7950d64 100644
--- a/src/effects/SkDashPathEffect.cpp
+++ b/src/effects/SkDashPathEffect.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/effects/SkDashPathEffect.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDashPathEffect.h"
#include "SkBuffer.h"
@@ -174,4 +166,6 @@ SkDashPathEffect::SkDashPathEffect(SkFlattenableReadBuffer& buffer) {
buffer.read(fIntervals, fCount * sizeof(fIntervals[0]));
}
+///////////////////////////////////////////////////////////////////////////////
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkDashPathEffect)
diff --git a/src/effects/SkDiscretePathEffect.cpp b/src/effects/SkDiscretePathEffect.cpp
index 3b8d48e..a438859 100644
--- a/src/effects/SkDiscretePathEffect.cpp
+++ b/src/effects/SkDiscretePathEffect.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/effects/SkDiscretePathEffect.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDiscretePathEffect.h"
#include "SkBuffer.h"
@@ -93,3 +85,7 @@ SkDiscretePathEffect::SkDiscretePathEffect(SkFlattenableReadBuffer& buffer) {
fPerterb = buffer.readScalar();
}
+///////////////////////////////////////////////////////////////////////////////
+
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkDiscretePathEffect)
+
diff --git a/src/effects/SkEffects.cpp b/src/effects/SkEffects.cpp
new file mode 100644
index 0000000..d4ccac0
--- /dev/null
+++ b/src/effects/SkEffects.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTypes.h"
+
+#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+
+#include "Sk1DPathEffect.h"
+#include "Sk2DPathEffect.h"
+#include "SkAvoidXfermode.h"
+#include "SkBlurDrawLooper.h"
+#include "SkBlurImageFilter.h"
+#include "SkBlurMaskFilter.h"
+#include "SkColorFilter.h"
+#include "SkColorMatrixFilter.h"
+#include "SkCornerPathEffect.h"
+#include "SkDashPathEffect.h"
+#include "SkDiscretePathEffect.h"
+#include "SkEffects.h"
+#include "SkFlattenable.h"
+#include "SkGradientShader.h"
+#include "SkGroupShape.h"
+#include "SkLayerDrawLooper.h"
+#include "SkLayerRasterizer.h"
+#include "SkPathEffect.h"
+#include "SkPixelXorXfermode.h"
+#include "SkRectShape.h"
+
+void SkEffects::Init() {
+ SkAvoidXfermode::Init();
+ SkBlurDrawLooper::Init();
+ SkBlurImageFilter::Init();
+ SkBlurMaskFilter::Init();
+ SkColorFilter::Init();
+ SkColorMatrixFilter::Init();
+ SkCornerPathEffect::Init();
+ SkDashPathEffect::Init();
+ SkDiscretePathEffect::Init();
+ SkGradientShader::Init();
+ SkGroupShape::Init();
+ SkLayerDrawLooper::Init();
+ SkLayerRasterizer::Init();
+ SkPath1DPathEffect::Init();
+ SkPath2DPathEffect::Init();
+ SkPixelXorXfermode::Init();
+ SkRectShape::Init();
+}
+
+#endif
diff --git a/src/effects/SkEffects_none.cpp b/src/effects/SkEffects_none.cpp
new file mode 100644
index 0000000..519fcf7
--- /dev/null
+++ b/src/effects/SkEffects_none.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTypes.h"
+
+#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+
+#include "../../include/effects/SkEffects.h"
+
+void SkEffects::Init() {
+}
+
+#endif
diff --git a/src/effects/SkEmbossMask.cpp b/src/effects/SkEmbossMask.cpp
index 742ccd2..300494b 100644
--- a/src/effects/SkEmbossMask.cpp
+++ b/src/effects/SkEmbossMask.cpp
@@ -1,21 +1,14 @@
-/* libs/graphics/effects/SkEmbossMask.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkEmbossMask.h"
+#include "SkMath.h"
static inline int nonzero_to_one(int x) {
#if 0
diff --git a/src/effects/SkEmbossMask.h b/src/effects/SkEmbossMask.h
index 8e56d6f..15e2474 100644
--- a/src/effects/SkEmbossMask.h
+++ b/src/effects/SkEmbossMask.h
@@ -1,19 +1,11 @@
-/* libs/graphics/effects/SkEmbossMask.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkEmbossMask_DEFINED
#define SkEmbossMask_DEFINED
diff --git a/src/effects/SkEmbossMaskFilter.cpp b/src/effects/SkEmbossMaskFilter.cpp
index 51c19b2..ce37718 100644
--- a/src/effects/SkEmbossMaskFilter.cpp
+++ b/src/effects/SkEmbossMaskFilter.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/effects/SkEmbossMaskFilter.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkEmbossMaskFilter.h"
#include "SkBlurMaskFilter.h"
diff --git a/src/effects/SkEmbossMask_Table.h b/src/effects/SkEmbossMask_Table.h
index 775fe25..fc29a15 100644
--- a/src/effects/SkEmbossMask_Table.h
+++ b/src/effects/SkEmbossMask_Table.h
@@ -1,19 +1,11 @@
-/* libs/graphics/effects/SkEmbossMask_Table.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTypes.h"
diff --git a/src/effects/SkGradientShader.cpp b/src/effects/SkGradientShader.cpp
index cfe444e..a907d04 100644
--- a/src/effects/SkGradientShader.cpp
+++ b/src/effects/SkGradientShader.cpp
@@ -1,21 +1,14 @@
-/* libs/graphics/effects/SkGradientShader.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkGradientShader.h"
+#include "SkClampRange.h"
#include "SkColorPriv.h"
#include "SkMallocPixelRef.h"
#include "SkUnitMapper.h"
@@ -23,13 +16,14 @@
#include "SkTemplates.h"
#include "SkBitmapCache.h"
+#if defined(SK_SCALAR_IS_FLOAT) && !defined(SK_DONT_USE_FLOAT_SQRT)
+ #define SK_USE_FLOAT_SQRT
+#endif
+
#ifndef SK_DISABLE_DITHER_32BIT_GRADIENT
#define USE_DITHER_32BIT_GRADIENT
#endif
-#define SK_ENABLE_FAST_LINEAR_GRADIENTS
-
-#ifdef SK_ENABLE_FAST_LINEAR_GRADIENTS
static void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
int count) {
if (count > 0) {
@@ -47,7 +41,6 @@ static void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
}
}
}
-#endif
///////////////////////////////////////////////////////////////////////////////
// Can't use a two-argument function with side effects like this in a
@@ -125,8 +118,30 @@ public:
virtual ~Gradient_Shader();
// overrides
- virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&);
- virtual uint32_t getFlags() { return fFlags; }
+ virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
+ virtual uint32_t getFlags() SK_OVERRIDE { return fFlags; }
+ virtual bool isOpaque() const SK_OVERRIDE;
+
+ enum {
+ kCache16Bits = 8, // seems like enough for visual accuracy
+ kCache16Count = 1 << kCache16Bits,
+ kCache16Mask = kCache16Count - 1,
+ kCache16Shift = 16 - kCache16Bits,
+ kSqrt16Shift = 8 - kCache16Bits,
+
+ kCache32Bits = 8, // pretty much should always be 8
+ kCache32Count = 1 << kCache32Bits,
+ kCache32Mask = kCache32Count - 1,
+ kCache32Shift = 16 - kCache32Bits,
+ kSqrt32Shift = 8 - kCache32Bits,
+#ifdef USE_DITHER_32BIT_GRADIENT
+ kToggleMask32 = kCache32Count,
+#else
+ kToggleMask32 = 0,
+#endif
+ kToggleMask16 = kCache16Count
+ };
+
protected:
Gradient_Shader(SkFlattenableReadBuffer& );
@@ -146,15 +161,6 @@ protected:
};
Rec* fRecs;
- enum {
- kCache16Bits = 8, // seems like enough for visual accuracy
- kCache16Count = 1 << kCache16Bits,
- kCache16Mask = kCache16Count - 1,
- kCache16Shift = 16 - kCache16Bits,
-
- kCache32Bits = 8, // pretty much should always be 8
- kCache32Count = 1 << kCache32Bits
- };
virtual void flatten(SkFlattenableWriteBuffer& );
const uint16_t* getCache16() const;
const SkPMColor* getCache32() const;
@@ -169,18 +175,21 @@ private:
kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(Rec))
};
SkColor fStorage[(kStorageSize + 3) >> 2];
- SkColor* fOrigColors;
+ SkColor* fOrigColors; // original colors, before modulation by paint in setContext
+ bool fColorsAreOpaque;
mutable uint16_t* fCache16; // working ptr. If this is NULL, we need to recompute the cache values
mutable SkPMColor* fCache32; // working ptr. If this is NULL, we need to recompute the cache values
mutable uint16_t* fCache16Storage; // storage for fCache16, allocated on demand
mutable SkMallocPixelRef* fCache32PixelRef;
- unsigned fCacheAlpha; // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value
+ mutable unsigned fCacheAlpha; // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value
static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count);
static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
U8CPU alpha);
+ void setCacheAlpha(U8CPU alpha) const;
+ void initCommon();
typedef SkShader INHERITED;
};
@@ -309,7 +318,7 @@ Gradient_Shader::Gradient_Shader(const SkColor colors[], const SkScalar pos[],
}
}
}
- fFlags = 0;
+ this->initCommon();
}
Gradient_Shader::Gradient_Shader(SkFlattenableReadBuffer& buffer) :
@@ -343,7 +352,7 @@ Gradient_Shader::Gradient_Shader(SkFlattenableReadBuffer& buffer) :
}
}
SkReadMatrix(&buffer, &fPtsToUnit);
- fFlags = 0;
+ this->initCommon();
}
Gradient_Shader::~Gradient_Shader() {
@@ -357,6 +366,15 @@ Gradient_Shader::~Gradient_Shader() {
SkSafeUnref(fMapper);
}
+void Gradient_Shader::initCommon() {
+ fFlags = 0;
+ unsigned colorAlpha = 0xFF;
+ for (int i = 0; i < fColorCount; i++) {
+ colorAlpha &= SkColorGetA(fOrigColors[i]);
+ }
+ fColorsAreOpaque = colorAlpha == 0xFF;
+}
+
void Gradient_Shader::flatten(SkFlattenableWriteBuffer& buffer) {
this->INHERITED::flatten(buffer);
buffer.writeFlattenable(fMapper);
@@ -373,6 +391,10 @@ void Gradient_Shader::flatten(SkFlattenableWriteBuffer& buffer) {
SkWriteMatrix(&buffer, fPtsToUnit);
}
+bool Gradient_Shader::isOpaque() const {
+ return fColorsAreOpaque;
+}
+
bool Gradient_Shader::setContext(const SkBitmap& device,
const SkPaint& paint,
const SkMatrix& matrix) {
@@ -391,39 +413,34 @@ bool Gradient_Shader::setContext(const SkBitmap& device,
// now convert our colors in to PMColors
unsigned paintAlpha = this->getPaintAlpha();
- unsigned colorAlpha = 0xFF;
-
- // FIXME: record colorAlpha in constructor, since this is not affected
- // by setContext()
- for (int i = 0; i < fColorCount; i++) {
- SkColor src = fOrigColors[i];
- unsigned sa = SkColorGetA(src);
- colorAlpha &= sa;
- }
fFlags = this->INHERITED::getFlags();
- if ((colorAlpha & paintAlpha) == 0xFF) {
+ if (fColorsAreOpaque && paintAlpha == 0xFF) {
fFlags |= kOpaqueAlpha_Flag;
}
// we can do span16 as long as our individual colors are opaque,
// regardless of the paint's alpha
- if (0xFF == colorAlpha) {
+ if (fColorsAreOpaque) {
fFlags |= kHasSpan16_Flag;
}
+ this->setCacheAlpha(paintAlpha);
+ return true;
+}
+
+void Gradient_Shader::setCacheAlpha(U8CPU alpha) const {
// 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 NULL
- if (fCacheAlpha != paintAlpha) {
- fCache16 = NULL; // inval the cache
- fCache32 = NULL; // inval the cache
- fCacheAlpha = paintAlpha; // record the new alpha
+ if (fCacheAlpha != alpha) {
+ fCache16 = NULL; // inval the cache
+ fCache32 = NULL; // inval the cache
+ fCacheAlpha = alpha; // record the new alpha
// inform our subclasses
if (fCache32PixelRef) {
fCache32PixelRef->notifyPixelsChanged();
}
}
- return true;
}
static inline int blend8(int a, int b, int scale) {
@@ -538,11 +555,11 @@ void Gradient_Shader::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1,
b = SkIntToFixed(b) + 0x8000;
do {
- cache[0] = SkPreMultiplyARGB(a >> 16, r >> 16, g >> 16, b >> 16);
- cache[kCache32Count] = SkPreMultiplyARGB(dither_ceil_fixed_to_8(a),
- dither_fixed_to_8(r),
- dither_fixed_to_8(g),
- dither_fixed_to_8(b));
+ cache[0] = SkPremultiplyARGBInline(a >> 16, r >> 16, g >> 16, b >> 16);
+ cache[kCache32Count] = SkPremultiplyARGBInline(dither_ceil_fixed_to_8(a),
+ dither_fixed_to_8(r),
+ dither_fixed_to_8(g),
+ dither_fixed_to_8(b));
cache += 1;
a += da;
r += dr;
@@ -629,7 +646,7 @@ const SkPMColor* Gradient_Shader::getCache32() const {
Rec* rec = fRecs;
int prevIndex = 0;
for (int i = 1; i < fColorCount; i++) {
- int nextIndex = SkFixedToFFFF(rec[i].fPos) >> (16 - kCache32Bits);
+ int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift;
SkASSERT(nextIndex < kCache32Count);
if (nextIndex > prevIndex)
@@ -669,6 +686,10 @@ const SkPMColor* Gradient_Shader::getCache32() const {
* is present, we skip the cache for now.
*/
void Gradient_Shader::commonAsABitmap(SkBitmap* bitmap) const {
+ // our caller assumes no external alpha, so we ensure that our cache is
+ // built with 0xFF
+ this->setCacheAlpha(0xFF);
+
// don't have a way to put the mapper into our cache-key yet
if (fMapper) {
// force our cahce32pixelref to be built
@@ -769,18 +790,18 @@ public:
pts_to_unit_matrix(pts, &fPtsToUnit);
}
- virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&);
- virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count);
- virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count);
- virtual BitmapType asABitmap(SkBitmap*, SkMatrix*,
- TileMode*, SkScalar* twoPointRadialParams) const;
- virtual GradientType asAGradient(GradientInfo* info) const;
+ virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
+ virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
+ virtual BitmapType asABitmap(SkBitmap*, SkMatrix*, TileMode*,
+ SkScalar* twoPointRadialParams) const SK_OVERRIDE;
+ virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE;
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(Linear_Gradient, (buffer));
}
- virtual void flatten(SkFlattenableWriteBuffer& buffer) {
+ virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE {
this->INHERITED::flatten(buffer);
buffer.writeScalar(fStart.fX);
buffer.writeScalar(fStart.fY);
@@ -788,13 +809,15 @@ public:
buffer.writeScalar(fEnd.fY);
}
+ SK_DECLARE_FLATTENABLE_REGISTRAR()
+
protected:
Linear_Gradient(SkFlattenableReadBuffer& buffer)
: Gradient_Shader(buffer),
fStart(unflatten_point(buffer)),
fEnd(unflatten_point(buffer)) {
}
- virtual Factory getFactory() { return CreateProc; }
+ virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
private:
typedef Gradient_Shader INHERITED;
@@ -821,37 +844,111 @@ bool Linear_Gradient::setContext(const SkBitmap& device, const SkPaint& paint,
return true;
}
-// Return true if fx, fx+dx, fx+2*dx, ... is always in range
-static inline bool no_need_for_clamp(int fx, int dx, int count) {
- SkASSERT(count > 0);
- return (unsigned)((fx | (fx + (count - 1) * dx)) >> 8) <= 0xFF;
-}
-
-#include "SkClampRange.h"
-
#define NO_CHECK_ITER \
do { \
- unsigned fi = fx >> 8; \
+ unsigned fi = fx >> Gradient_Shader::kCache32Shift; \
SkASSERT(fi <= 0xFF); \
fx += dx; \
*dstC++ = cache[toggle + fi]; \
- toggle ^= TOGGLE_MASK; \
+ toggle ^= Gradient_Shader::kToggleMask32; \
} while (0)
+namespace {
+
+typedef void (*LinearShadeProc)(TileProc proc, SkFixed dx, SkFixed fx,
+ SkPMColor* SK_RESTRICT dstC,
+ const SkPMColor* SK_RESTRICT cache,
+ int toggle, int count);
+
+void shadeSpan_linear_vertical(TileProc proc, SkFixed dx, SkFixed fx,
+ SkPMColor* SK_RESTRICT dstC,
+ const SkPMColor* SK_RESTRICT cache,
+ int toggle, int count) {
+ // we're a vertical gradient, so no change in a span
+ unsigned fi = proc(fx) >> Gradient_Shader::kCache32Shift;
+ sk_memset32_dither(dstC, cache[toggle + fi],
+ cache[(toggle ^ Gradient_Shader::kToggleMask32) + fi], count);
+
+}
+
+void shadeSpan_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
+ SkPMColor* SK_RESTRICT dstC,
+ const SkPMColor* SK_RESTRICT cache,
+ int toggle, int count) {
+ SkClampRange range;
+ range.init(fx, dx, count, 0, 0xFF);
+
+ if ((count = range.fCount0) > 0) {
+ sk_memset32_dither(dstC,
+ cache[toggle + range.fV0],
+ cache[(toggle ^ Gradient_Shader::kToggleMask32) + range.fV0],
+ count);
+ dstC += count;
+ }
+ if ((count = range.fCount1) > 0) {
+ int unroll = count >> 3;
+ fx = range.fFx1;
+ for (int i = 0; i < unroll; i++) {
+ NO_CHECK_ITER; NO_CHECK_ITER;
+ NO_CHECK_ITER; NO_CHECK_ITER;
+ NO_CHECK_ITER; NO_CHECK_ITER;
+ NO_CHECK_ITER; NO_CHECK_ITER;
+ }
+ if ((count &= 7) > 0) {
+ do {
+ NO_CHECK_ITER;
+ } while (--count != 0);
+ }
+ }
+ if ((count = range.fCount2) > 0) {
+ sk_memset32_dither(dstC,
+ cache[toggle + range.fV1],
+ cache[(toggle ^ Gradient_Shader::kToggleMask32) + range.fV1],
+ count);
+ }
+}
+
+// TODO: we could merge mirror and repeat if we passed in a pointer to the
+// *_8bits proc, but that'd lose inlining, which might be significant here.
+void shadeSpan_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
+ SkPMColor* SK_RESTRICT dstC,
+ const SkPMColor* SK_RESTRICT cache,
+ int toggle, int count) {
+ do {
+ unsigned fi = mirror_8bits(fx >> 8);
+ SkASSERT(fi <= 0xFF);
+ fx += dx;
+ *dstC++ = cache[toggle + fi];
+ toggle ^= Gradient_Shader::kToggleMask32;
+ } while (--count != 0);
+}
-void Linear_Gradient::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
+void shadeSpan_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx,
+ SkPMColor* SK_RESTRICT dstC,
+ const SkPMColor* SK_RESTRICT cache,
+ int toggle, int count) {
+ do {
+ unsigned fi = repeat_8bits(fx >> 8);
+ SkASSERT(fi <= 0xFF);
+ fx += dx;
+ *dstC++ = cache[toggle + fi];
+ toggle ^= Gradient_Shader::kToggleMask32;
+ } while (--count != 0);
+}
+}
+
+void Linear_Gradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
+ int count) {
SkASSERT(count > 0);
SkPoint srcPt;
SkMatrix::MapXYProc dstProc = fDstToIndexProc;
TileProc proc = fTileProc;
- const SkPMColor* cache = this->getCache32();
+ const SkPMColor* SK_RESTRICT cache = this->getCache32();
#ifdef USE_DITHER_32BIT_GRADIENT
int toggle = ((x ^ y) & 1) << kCache32Bits;
- const int TOGGLE_MASK = (1 << kCache32Bits);
#else
int toggle = 0;
- const int TOGGLE_MASK = 0;
#endif
if (fDstToIndexClass != kPerspective_MatrixClass) {
@@ -868,72 +965,17 @@ void Linear_Gradient::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
dx = SkScalarToFixed(fDstToIndex.getScaleX());
}
+ LinearShadeProc shadeProc = shadeSpan_linear_repeat;
if (SkFixedNearlyZero(dx)) {
- // we're a vertical gradient, so no change in a span
- unsigned fi = proc(fx);
- SkASSERT(fi <= 0xFFFF);
- // TODO: dither version
- sk_memset32(dstC, cache[fi >> (16 - kCache32Bits)], count);
+ shadeProc = shadeSpan_linear_vertical;
} else if (proc == clamp_tileproc) {
-#ifdef SK_ENABLE_FAST_LINEAR_GRADIENTS
- SkClampRange range;
- range.init(fx, dx, count, 0, 0xFF);
-
- if ((count = range.fCount0) > 0) {
- sk_memset32_dither(dstC,
- cache[toggle + range.fV0],
- cache[(toggle ^ TOGGLE_MASK) + range.fV0],
- count);
- dstC += count;
- }
- if ((count = range.fCount1) > 0) {
- int unroll = count >> 3;
- fx = range.fFx1;
- for (int i = 0; i < unroll; i++) {
- NO_CHECK_ITER; NO_CHECK_ITER;
- NO_CHECK_ITER; NO_CHECK_ITER;
- NO_CHECK_ITER; NO_CHECK_ITER;
- NO_CHECK_ITER; NO_CHECK_ITER;
- }
- if ((count &= 7) > 0) {
- do {
- NO_CHECK_ITER;
- } while (--count != 0);
- }
- }
- if ((count = range.fCount2) > 0) {
- sk_memset32_dither(dstC,
- cache[toggle + range.fV1],
- cache[(toggle ^ TOGGLE_MASK) + range.fV1],
- count);
- }
-#else
- do {
- unsigned fi = SkClampMax(fx >> 8, 0xFF);
- SkASSERT(fi <= 0xFF);
- fx += dx;
- *dstC++ = cache[toggle + fi];
- toggle ^= TOGGLE_MASK;
- } while (--count != 0);
-#endif
+ shadeProc = shadeSpan_linear_clamp;
} else if (proc == mirror_tileproc) {
- do {
- unsigned fi = mirror_8bits(fx >> 8);
- SkASSERT(fi <= 0xFF);
- fx += dx;
- *dstC++ = cache[toggle + fi];
- toggle ^= TOGGLE_MASK;
- } while (--count != 0);
+ shadeProc = shadeSpan_linear_mirror;
} else {
SkASSERT(proc == repeat_tileproc);
- do {
- unsigned fi = repeat_8bits(fx >> 8);
- SkASSERT(fi <= 0xFF);
- fx += dx;
- *dstC++ = cache[toggle + fi];
- toggle ^= TOGGLE_MASK;
- } while (--count != 0);
}
+ (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count);
} else {
SkScalar dstX = SkIntToScalar(x);
SkScalar dstY = SkIntToScalar(y);
@@ -941,8 +983,8 @@ void Linear_Gradient::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
dstProc(fDstToIndex, dstX, dstY, &srcPt);
unsigned fi = proc(SkScalarToFixed(srcPt.fX));
SkASSERT(fi <= 0xFFFF);
- *dstC++ = cache[toggle + (fi >> (16 - kCache32Bits))];
- toggle ^= TOGGLE_MASK;
+ *dstC++ = cache[toggle + (fi >> kCache32Shift)];
+ toggle ^= Gradient_Shader::kToggleMask32;
dstX += SK_Scalar1;
} while (--count != 0);
}
@@ -992,23 +1034,108 @@ static void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other,
#define NO_CHECK_ITER_16 \
do { \
- unsigned fi = fx >> kCache16Shift; \
- SkASSERT(fi <= kCache16Mask); \
+ unsigned fi = fx >> Gradient_Shader::kCache16Shift; \
+ SkASSERT(fi <= Gradient_Shader::kCache16Mask); \
fx += dx; \
*dstC++ = cache[toggle + fi]; \
- toggle ^= TOGGLE_MASK; \
+ toggle ^= Gradient_Shader::kToggleMask16; \
} while (0)
+namespace {
+
+typedef void (*LinearShade16Proc)(TileProc proc, SkFixed dx, SkFixed fx,
+ uint16_t* SK_RESTRICT dstC,
+ const uint16_t* SK_RESTRICT cache,
+ int toggle, int count);
+
+void shadeSpan16_linear_vertical(TileProc proc, SkFixed dx, SkFixed fx,
+ uint16_t* SK_RESTRICT dstC,
+ const uint16_t* SK_RESTRICT cache,
+ int toggle, int count) {
+ // we're a vertical gradient, so no change in a span
+ unsigned fi = proc(fx) >> Gradient_Shader::kCache16Shift;
+ SkASSERT(fi <= Gradient_Shader::kCache16Mask);
+ dither_memset16(dstC, cache[toggle + fi],
+ cache[(toggle ^ Gradient_Shader::kToggleMask16) + fi], count);
+
+}
+
+void shadeSpan16_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
+ uint16_t* SK_RESTRICT dstC,
+ const uint16_t* SK_RESTRICT cache,
+ int toggle, int count) {
+ SkClampRange range;
+ range.init(fx, dx, count, 0, Gradient_Shader::kCache16Mask);
+
+ if ((count = range.fCount0) > 0) {
+ dither_memset16(dstC,
+ cache[toggle + range.fV0],
+ cache[(toggle ^ Gradient_Shader::kToggleMask16) + range.fV0],
+ count);
+ dstC += count;
+ }
+ if ((count = range.fCount1) > 0) {
+ int unroll = count >> 3;
+ fx = range.fFx1;
+ for (int i = 0; i < unroll; i++) {
+ NO_CHECK_ITER_16; NO_CHECK_ITER_16;
+ NO_CHECK_ITER_16; NO_CHECK_ITER_16;
+ NO_CHECK_ITER_16; NO_CHECK_ITER_16;
+ NO_CHECK_ITER_16; NO_CHECK_ITER_16;
+ }
+ if ((count &= 7) > 0) {
+ do {
+ NO_CHECK_ITER_16;
+ } while (--count != 0);
+ }
+ }
+ if ((count = range.fCount2) > 0) {
+ dither_memset16(dstC,
+ cache[toggle + range.fV1],
+ cache[(toggle ^ Gradient_Shader::kToggleMask16) + range.fV1],
+ count);
+ }
+}
+
+void shadeSpan16_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
+ uint16_t* SK_RESTRICT dstC,
+ const uint16_t* SK_RESTRICT cache,
+ int toggle, int count) {
+ do {
+ unsigned fi = mirror_bits(fx >> Gradient_Shader::kCache16Shift,
+ Gradient_Shader::kCache16Bits);
+ SkASSERT(fi <= Gradient_Shader::kCache16Mask);
+ fx += dx;
+ *dstC++ = cache[toggle + fi];
+ toggle ^= Gradient_Shader::kToggleMask16;
+ } while (--count != 0);
+}
+
+void shadeSpan16_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx,
+ uint16_t* SK_RESTRICT dstC,
+ const uint16_t* SK_RESTRICT cache,
+ int toggle, int count) {
+ SkASSERT(proc == repeat_tileproc);
+ do {
+ unsigned fi = repeat_bits(fx >> Gradient_Shader::kCache16Shift,
+ Gradient_Shader::kCache16Bits);
+ SkASSERT(fi <= Gradient_Shader::kCache16Mask);
+ fx += dx;
+ *dstC++ = cache[toggle + fi];
+ toggle ^= Gradient_Shader::kToggleMask16;
+ } while (--count != 0);
+}
+}
-void Linear_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
+void Linear_Gradient::shadeSpan16(int x, int y,
+ uint16_t* SK_RESTRICT dstC, int count) {
SkASSERT(count > 0);
SkPoint srcPt;
SkMatrix::MapXYProc dstProc = fDstToIndexProc;
TileProc proc = fTileProc;
- const uint16_t* cache = this->getCache16();
+ const uint16_t* SK_RESTRICT cache = this->getCache16();
int toggle = ((x ^ y) & 1) << kCache16Bits;
- const int TOGGLE_MASK = (1 << kCache32Bits);
if (fDstToIndexClass != kPerspective_MatrixClass) {
dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
@@ -1024,72 +1151,17 @@ void Linear_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
dx = SkScalarToFixed(fDstToIndex.getScaleX());
}
+ LinearShade16Proc shadeProc = shadeSpan16_linear_repeat;
if (SkFixedNearlyZero(dx)) {
- // we're a vertical gradient, so no change in a span
- unsigned fi = proc(fx) >> kCache16Shift;
- SkASSERT(fi <= kCache16Mask);
- dither_memset16(dstC, cache[toggle + fi],
- cache[(toggle ^ TOGGLE_MASK) + fi], count);
+ shadeProc = shadeSpan16_linear_vertical;
} else if (proc == clamp_tileproc) {
-#ifdef SK_ENABLE_FAST_LINEAR_GRADIENTS
- SkClampRange range;
- range.init(fx, dx, count, 0, kCache16Mask);
-
- if ((count = range.fCount0) > 0) {
- dither_memset16(dstC,
- cache[toggle + range.fV0],
- cache[(toggle ^ TOGGLE_MASK) + range.fV0],
- count);
- dstC += count;
- }
- if ((count = range.fCount1) > 0) {
- int unroll = count >> 3;
- fx = range.fFx1;
- for (int i = 0; i < unroll; i++) {
- NO_CHECK_ITER_16; NO_CHECK_ITER_16;
- NO_CHECK_ITER_16; NO_CHECK_ITER_16;
- NO_CHECK_ITER_16; NO_CHECK_ITER_16;
- NO_CHECK_ITER_16; NO_CHECK_ITER_16;
- }
- if ((count &= 7) > 0) {
- do {
- NO_CHECK_ITER_16;
- } while (--count != 0);
- }
- }
- if ((count = range.fCount2) > 0) {
- dither_memset16(dstC,
- cache[toggle + range.fV1],
- cache[(toggle ^ TOGGLE_MASK) + range.fV1],
- count);
- }
-#else
- do {
- unsigned fi = SkClampMax(fx >> kCache16Shift, kCache16Mask);
- SkASSERT(fi <= kCache16Mask);
- fx += dx;
- *dstC++ = cache[toggle + fi];
- toggle ^= TOGGLE_MASK;
- } while (--count != 0);
-#endif
+ shadeProc = shadeSpan16_linear_clamp;
} else if (proc == mirror_tileproc) {
- do {
- unsigned fi = mirror_bits(fx >> kCache16Shift, kCache16Bits);
- SkASSERT(fi <= kCache16Mask);
- fx += dx;
- *dstC++ = cache[toggle + fi];
- toggle ^= TOGGLE_MASK;
- } while (--count != 0);
+ shadeProc = shadeSpan16_linear_mirror;
} else {
SkASSERT(proc == repeat_tileproc);
- do {
- unsigned fi = repeat_bits(fx >> kCache16Shift, kCache16Bits);
- SkASSERT(fi <= kCache16Mask);
- fx += dx;
- *dstC++ = cache[toggle + fi];
- toggle ^= TOGGLE_MASK;
- } while (--count != 0);
}
+ (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count);
} else {
SkScalar dstX = SkIntToScalar(x);
SkScalar dstY = SkIntToScalar(y);
@@ -1100,7 +1172,7 @@ void Linear_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
int index = fi >> kCache16Shift;
*dstC++ = cache[toggle + index];
- toggle ^= TOGGLE_MASK;
+ toggle ^= Gradient_Shader::kToggleMask16;
dstX += SK_Scalar1;
} while (--count != 0);
@@ -1155,6 +1227,90 @@ static void rad_to_unit_matrix(const SkPoint& center, SkScalar radius,
matrix->postScale(inv, inv);
}
+
+namespace {
+
+typedef void (* RadialShade16Proc)(SkFixed fx, SkFixed dx,
+ SkFixed fy, SkFixed dy,
+ uint16_t* dstC, const uint16_t* SK_RESTRICT cache,
+ int toggle, int count);
+
+void shadeSpan16_radial_clamp(SkFixed fx, SkFixed dx,
+ SkFixed fy, SkFixed dy,
+ uint16_t* dstC, const uint16_t* SK_RESTRICT cache,
+ int toggle, int count) {
+ const uint8_t* SK_RESTRICT 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;
+ // might perform this check for the other modes,
+ // but the win will be a smaller % of the total
+ if (dy == 0) {
+ 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;
+ *dstC++ = cache[toggle +
+ (sqrt_table[fi] >> Gradient_Shader::kSqrt16Shift)];
+ toggle ^= Gradient_Shader::kToggleMask16;
+ } 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;
+ *dstC++ = cache[toggle +
+ (sqrt_table[fi] >> Gradient_Shader::kSqrt16Shift)];
+ toggle ^= Gradient_Shader::kToggleMask16;
+ } while (--count != 0);
+ }
+}
+
+void shadeSpan16_radial_mirror(SkFixed fx, SkFixed dx, SkFixed fy, SkFixed dy,
+ uint16_t* dstC, const uint16_t* SK_RESTRICT cache,
+ int toggle, int count) {
+ do {
+ SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
+ unsigned fi = mirror_tileproc(dist);
+ SkASSERT(fi <= 0xFFFF);
+ fx += dx;
+ fy += dy;
+ *dstC++ = cache[toggle + (fi >> Gradient_Shader::kCache16Shift)];
+ toggle ^= Gradient_Shader::kToggleMask16;
+ } while (--count != 0);
+}
+
+void shadeSpan16_radial_repeat(SkFixed fx, SkFixed dx, SkFixed fy, SkFixed dy,
+ uint16_t* dstC, const uint16_t* SK_RESTRICT cache,
+ int toggle, int count) {
+ do {
+ SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
+ unsigned fi = repeat_tileproc(dist);
+ SkASSERT(fi <= 0xFFFF);
+ fx += dx;
+ fy += dy;
+ *dstC++ = cache[toggle + (fi >> Gradient_Shader::kCache16Shift)];
+ toggle ^= Gradient_Shader::kToggleMask16;
+ } while (--count != 0);
+}
+
+}
+
class Radial_Gradient : public Gradient_Shader {
public:
Radial_Gradient(const SkPoint& center, SkScalar radius,
@@ -1170,92 +1326,14 @@ public:
rad_to_unit_matrix(center, radius, &fPtsToUnit);
}
- virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) {
- SkASSERT(count > 0);
-
- SkPoint srcPt;
- SkMatrix::MapXYProc dstProc = fDstToIndexProc;
- TileProc proc = fTileProc;
- const SkPMColor* cache = this->getCache32();
-
- if (fDstToIndexClass != kPerspective_MatrixClass) {
- dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
- SkIntToScalar(y) + SK_ScalarHalf, &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 uint8_t* 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 magnitudeSquared = SkFixedSquare(fx) + SkFixedSquare(fy);
- if (magnitudeSquared < 0) // Overflow.
- magnitudeSquared = SK_FixedMax;
- SkFixed dist = SkFixedSqrt(magnitudeSquared);
- 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 magnitudeSquared = SkFixedSquare(fx) + SkFixedSquare(fy);
- if (magnitudeSquared < 0) // Overflow.
- magnitudeSquared = SK_FixedMax;
- SkFixed dist = SkFixedSqrt(magnitudeSquared);
- 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 shadeSpan16(int x, int y, uint16_t dstC[], int count) {
+ virtual void shadeSpan(int x, int y, SkPMColor* dstC, int count) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC, int count) SK_OVERRIDE {
SkASSERT(count > 0);
SkPoint srcPt;
SkMatrix::MapXYProc dstProc = fDstToIndexProc;
TileProc proc = fTileProc;
- const uint16_t* cache = this->getCache16();
+ const uint16_t* SK_RESTRICT cache = this->getCache16();
int toggle = ((x ^ y) & 1) << kCache16Bits;
if (fDstToIndexClass != kPerspective_MatrixClass) {
@@ -1275,64 +1353,15 @@ public:
dy = SkScalarToFixed(fDstToIndex.getSkewY());
}
+ RadialShade16Proc shadeProc = shadeSpan16_radial_repeat;
if (proc == clamp_tileproc) {
- const uint8_t* 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;
- *dstC++ = cache[toggle + (sqrt_table[fi] >> (8 - kCache16Bits))];
- toggle ^= (1 << kCache16Bits);
- } 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;
- *dstC++ = cache[toggle + (sqrt_table[fi] >> (8 - kCache16Bits))];
- toggle ^= (1 << kCache16Bits);
- } while (--count != 0);
- }
+ shadeProc = shadeSpan16_radial_clamp;
} 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;
- *dstC++ = cache[toggle + (fi >> (16 - kCache16Bits))];
- toggle ^= (1 << kCache16Bits);
- } while (--count != 0);
+ shadeProc = shadeSpan16_radial_mirror;
} 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;
- *dstC++ = cache[toggle + (fi >> (16 - kCache16Bits))];
- toggle ^= (1 << kCache16Bits);
- } while (--count != 0);
}
+ (*shadeProc)(fx, dx, fy, dy, dstC, cache, toggle, count);
} else { // perspective case
SkScalar dstX = SkIntToScalar(x);
SkScalar dstY = SkIntToScalar(y);
@@ -1353,12 +1382,14 @@ public:
virtual BitmapType asABitmap(SkBitmap* bitmap,
SkMatrix* matrix,
TileMode* xy,
- SkScalar* twoPointRadialParams) const {
+ SkScalar* twoPointRadialParams)
+ const SK_OVERRIDE {
if (bitmap) {
this->commonAsABitmap(bitmap);
}
if (matrix) {
- matrix->setScale(SkIntToScalar(kCache32Count), SkIntToScalar(kCache32Count));
+ matrix->setScale(SkIntToScalar(kCache32Count),
+ SkIntToScalar(kCache32Count));
matrix->preConcat(fPtsToUnit);
}
if (xy) {
@@ -1367,7 +1398,7 @@ public:
}
return kRadial_BitmapType;
}
- virtual GradientType asAGradient(GradientInfo* info) const {
+ virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE {
if (info) {
commonAsAGradient(info);
info->fPoint[0] = fCenter;
@@ -1380,7 +1411,7 @@ public:
return SkNEW_ARGS(Radial_Gradient, (buffer));
}
- virtual void flatten(SkFlattenableWriteBuffer& buffer) {
+ virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE {
this->INHERITED::flatten(buffer);
buffer.writeScalar(fCenter.fX);
buffer.writeScalar(fCenter.fY);
@@ -1393,7 +1424,7 @@ protected:
fCenter(unflatten_point(buffer)),
fRadius(buffer.readScalar()) {
}
- virtual Factory getFactory() { return CreateProc; }
+ virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
private:
typedef Gradient_Shader INHERITED;
@@ -1401,6 +1432,194 @@ private:
const SkScalar fRadius;
};
+namespace {
+
+inline bool radial_completely_pinned(int fx, int dx, int fy, int dy) {
+ // fast, overly-conservative test: checks unit square instead
+ // of unit circle
+ bool xClamped = (fx >= SK_FixedHalf && dx >= 0) ||
+ (fx <= -SK_FixedHalf && dx <= 0);
+ bool yClamped = (fy >= SK_FixedHalf && dy >= 0) ||
+ (fy <= -SK_FixedHalf && dy <= 0);
+
+ return xClamped || yClamped;
+}
+
+// Return true if (fx * fy) is always inside the unit circle
+// SkPin32 is expensive, but so are all the SkFixedMul in this test,
+// so it shouldn't be run if count is small.
+inline bool no_need_for_radial_pin(int fx, int dx,
+ int fy, int dy, int count) {
+ SkASSERT(count > 0);
+ if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) {
+ return false;
+ }
+ if (fx*fx + fy*fy > 0x7FFF*0x7FFF) {
+ return false;
+ }
+ fx += (count - 1) * dx;
+ fy += (count - 1) * dy;
+ if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) {
+ return false;
+ }
+ return fx*fx + fy*fy <= 0x7FFF*0x7FFF;
+}
+
+#define UNPINNED_RADIAL_STEP \
+ fi = (fx * fx + fy * fy) >> (14 + 16 - kSQRT_TABLE_BITS); \
+ *dstC++ = cache[sqrt_table[fi] >> Gradient_Shader::kSqrt32Shift]; \
+ fx += dx; \
+ fy += dy;
+
+typedef void (* RadialShadeProc)(SkFixed fx, SkFixed dx, SkFixed fy, SkFixed dy,
+ SkPMColor* dstC, const SkPMColor* SK_RESTRICT cache,
+ int count, SkPoint& srcPt, float fdx, float fdy);
+
+// On Linux, this is faster with SkPMColor[] params than SkPMColor* SK_RESTRICT
+void shadeSpan_radial_clamp(SkFixed fx, SkFixed dx, SkFixed fy, SkFixed dy,
+ SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
+ int count, SkPoint& srcPt, float fdx, float fdy) {
+ // Floating point seems to be slower than fixed point,
+ // even when we have float hardware.
+ const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table;
+ fx >>= 1;
+ dx >>= 1;
+ fy >>= 1;
+ dy >>= 1;
+ if ((count > 4) && radial_completely_pinned(fx, dx, fy, dy)) {
+ sk_memset32(dstC, cache[Gradient_Shader::kCache32Count - 1], count);
+ } else if ((count > 4) &&
+ no_need_for_radial_pin(fx, dx, fy, dy, count)) {
+ unsigned fi;
+ // 4x unroll appears to be no faster than 2x unroll on Linux
+ while (count > 1) {
+ UNPINNED_RADIAL_STEP;
+ UNPINNED_RADIAL_STEP;
+ count -= 2;
+ }
+ if (count) {
+ UNPINNED_RADIAL_STEP;
+ }
+ }
+ 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));
+ *dstC++ = cache[sqrt_table[fi] >> Gradient_Shader::kSqrt32Shift];
+ fx += dx;
+ fy += dy;
+ } while (--count != 0);
+ }
+}
+
+void shadeSpan_radial_mirror(SkFixed fx, SkFixed dx, SkFixed fy, SkFixed dy,
+ SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
+ int count, SkPoint& srcPt, float fdx, float fdy) {
+#ifdef SK_USE_FLOAT_SQRT
+ float ffx = srcPt.fX;
+ float ffy = srcPt.fY;
+ do {
+ float fdist = sk_float_sqrt(ffx*ffx + ffy*ffy);
+ unsigned fi = mirror_tileproc(SkFloatToFixed(fdist));
+ SkASSERT(fi <= 0xFFFF);
+ *dstC++ = cache[fi >> Gradient_Shader::kCache32Shift];
+ ffx += fdx;
+ ffy += fdy;
+ } while (--count != 0);
+#else
+ do {
+ SkFixed magnitudeSquared = SkFixedSquare(fx) +
+ SkFixedSquare(fy);
+ if (magnitudeSquared < 0) // Overflow.
+ magnitudeSquared = SK_FixedMax;
+ SkFixed dist = SkFixedSqrt(magnitudeSquared);
+ unsigned fi = mirror_tileproc(dist);
+ SkASSERT(fi <= 0xFFFF);
+ *dstC++ = cache[fi >> Gradient_Shader::kCache32Shift];
+ fx += dx;
+ fy += dy;
+ } while (--count != 0);
+#endif
+}
+
+void shadeSpan_radial_repeat(SkFixed fx, SkFixed dx, SkFixed fy, SkFixed dy,
+ SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
+ int count, SkPoint& srcPt, float fdx, float fdy) {
+ do {
+ SkFixed magnitudeSquared = SkFixedSquare(fx) +
+ SkFixedSquare(fy);
+ if (magnitudeSquared < 0) // Overflow.
+ magnitudeSquared = SK_FixedMax;
+ SkFixed dist = SkFixedSqrt(magnitudeSquared);
+ unsigned fi = repeat_tileproc(dist);
+ SkASSERT(fi <= 0xFFFF);
+ *dstC++ = cache[fi >> Gradient_Shader::kCache32Shift];
+ fx += dx;
+ fy += dy;
+ } while (--count != 0);
+}
+}
+
+void Radial_Gradient::shadeSpan(int x, int y,
+ SkPMColor* SK_RESTRICT dstC, int count) {
+ SkASSERT(count > 0);
+
+ SkPoint srcPt;
+ SkMatrix::MapXYProc dstProc = fDstToIndexProc;
+ TileProc proc = fTileProc;
+ const SkPMColor* SK_RESTRICT cache = this->getCache32();
+
+ if (fDstToIndexClass != kPerspective_MatrixClass) {
+ dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
+ SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
+ SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
+ SkFixed dy, fy = SkScalarToFixed(srcPt.fY);
+ float fdx = 0;
+ float fdy = 0;
+
+ if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
+ SkFixed storage[2];
+ (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &storage[0], &storage[1]);
+ dx = storage[0];
+ dy = storage[1];
+#ifdef SK_USE_FLOAT_SQRT
+ fdx = SkFixedToFloat(storage[0]);
+ fdy = SkFixedToFloat(storage[1]);
+#endif
+ } else {
+ SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
+ dx = SkScalarToFixed(fDstToIndex.getScaleX());
+ dy = SkScalarToFixed(fDstToIndex.getSkewY());
+#ifdef SK_USE_FLOAT_SQRT
+ fdx = fDstToIndex.getScaleX();
+ fdy = fDstToIndex.getSkewY();
+#endif
+ }
+
+ RadialShadeProc shadeProc = shadeSpan_radial_repeat;
+ if (proc == clamp_tileproc) {
+ shadeProc = shadeSpan_radial_clamp;
+ } else if (proc == mirror_tileproc) {
+ shadeProc = shadeSpan_radial_mirror;
+ } else {
+ SkASSERT(proc == repeat_tileproc);
+ }
+ (*shadeProc)(fx, dx, fy, dy, dstC, cache, count, srcPt, fdx, fdy);
+ } 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 >> Gradient_Shader::kCache32Shift];
+ dstX += SK_Scalar1;
+ } while (--count != 0);
+ }
+}
+
/* Two-point radial gradients are specified by two circles, each with a center
point and radius. The gradient can be considered to be a series of
concentric circles, with the color interpolated from the start circle
@@ -1473,25 +1692,16 @@ private:
*/
-#ifdef SK_USE_SLOW_2POINT_RADIAL_GRADIENT
-static inline SkFixed two_point_radial(SkFixed b, SkFixed fx, SkFixed fy, SkFixed sr2d2, SkFixed foura, SkFixed oneOverTwoA, bool posRoot) {
- SkFixed c = SkFixedSquare(fx) + SkFixedSquare(fy) - sr2d2;
- SkFixed discrim = SkFixedSquare(b) - SkFixedMul(foura, c);
- if (discrim < 0) {
- discrim = -discrim;
- }
- SkFixed rootDiscrim = SkFixedSqrt(discrim);
- if (posRoot) {
- return SkFixedMul(-b + rootDiscrim, oneOverTwoA);
- } else {
- return SkFixedMul(-b - rootDiscrim, oneOverTwoA);
- }
-}
-#else
-static inline SkFixed two_point_radial(SkScalar b, SkScalar fx, SkScalar fy,
- SkScalar sr2d2, SkScalar foura,
- SkScalar oneOverTwoA, bool posRoot) {
+namespace {
+
+inline SkFixed two_point_radial(SkScalar b, SkScalar fx, SkScalar fy,
+ SkScalar sr2d2, SkScalar foura,
+ SkScalar oneOverTwoA, bool posRoot) {
SkScalar c = SkScalarSquare(fx) + SkScalarSquare(fy) - sr2d2;
+ if (0 == foura) {
+ return SkScalarToFixed(SkScalarDiv(-c, b));
+ }
+
SkScalar discrim = SkScalarSquare(b) - SkScalarMul(foura, c);
if (discrim < 0) {
discrim = -discrim;
@@ -1505,7 +1715,70 @@ static inline SkFixed two_point_radial(SkScalar b, SkScalar fx, SkScalar fy,
}
return SkScalarToFixed(result);
}
-#endif
+
+typedef void (* TwoPointRadialShadeProc)(SkScalar fx, SkScalar dx,
+ SkScalar fy, SkScalar dy,
+ SkScalar b, SkScalar db,
+ SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
+ SkPMColor* dstC, const SkPMColor* SK_RESTRICT cache,
+ int count);
+
+void shadeSpan_twopoint_clamp(SkScalar fx, SkScalar dx,
+ SkScalar fy, SkScalar dy,
+ SkScalar b, SkScalar db,
+ SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
+ SkPMColor* dstC, const SkPMColor* SK_RESTRICT cache,
+ int count) {
+ for (; count > 0; --count) {
+ SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
+ fOneOverTwoA, posRoot);
+ SkFixed index = SkClampMax(t, 0xFFFF);
+ SkASSERT(index <= 0xFFFF);
+ *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
+ fx += dx;
+ fy += dy;
+ b += db;
+ }
+}
+void shadeSpan_twopoint_mirror(SkScalar fx, SkScalar dx,
+ SkScalar fy, SkScalar dy,
+ SkScalar b, SkScalar db,
+ SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
+ SkPMColor* dstC, const SkPMColor* SK_RESTRICT cache,
+ int count) {
+ for (; count > 0; --count) {
+ SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
+ fOneOverTwoA, posRoot);
+ SkFixed index = mirror_tileproc(t);
+ SkASSERT(index <= 0xFFFF);
+ *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
+ fx += dx;
+ fy += dy;
+ b += db;
+ }
+}
+
+void shadeSpan_twopoint_repeat(SkScalar fx, SkScalar dx,
+ SkScalar fy, SkScalar dy,
+ SkScalar b, SkScalar db,
+ SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
+ SkPMColor* dstC, const SkPMColor* SK_RESTRICT cache,
+ int count) {
+ for (; count > 0; --count) {
+ SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
+ fOneOverTwoA, posRoot);
+ SkFixed index = repeat_tileproc(t);
+ SkASSERT(index <= 0xFFFF);
+ *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
+ fx += dx;
+ fy += dy;
+ b += db;
+ }
+}
+
+
+
+}
class Two_Point_Radial_Gradient : public Gradient_Shader {
public:
@@ -1556,7 +1829,7 @@ public:
return kTwoPointRadial_BitmapType;
}
- virtual GradientType asAGradient(GradientInfo* info) const {
+ virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE {
if (info) {
commonAsAGradient(info);
info->fPoint[0] = fCenter1;
@@ -1567,107 +1840,8 @@ public:
return kRadial2_GradientType;
}
-#ifdef SK_USE_SLOW_2POINT_RADIAL_GRADIENT
- virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count)
- {
- SkASSERT(count > 0);
-
- // Zero difference between radii: fill with transparent black.
- if (fDiffRadius == 0) {
- sk_bzero(dstC, count * sizeof(*dstC));
- return;
- }
- SkMatrix::MapXYProc dstProc = fDstToIndexProc;
- TileProc proc = fTileProc;
- const SkPMColor* cache = this->getCache32();
- SkFixed diffx = SkScalarToFixed(fDiff.fX);
- SkFixed diffy = SkScalarToFixed(fDiff.fY);
- SkFixed foura = SkScalarToFixed(SkScalarMul(fA, 4));
- SkFixed startRadius = SkScalarToFixed(fStartRadius);
- SkFixed sr2D2 = SkScalarToFixed(fSr2D2);
- SkFixed oneOverTwoA = SkScalarToFixed(fOneOverTwoA);
- bool posRoot = fDiffRadius < 0;
- if (fDstToIndexClass != kPerspective_MatrixClass)
- {
- SkPoint srcPt;
- dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
- SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
- SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
- SkFixed dy, fy = SkScalarToFixed(srcPt.fY);
-
- if (fDstToIndexClass == kFixedStepInX_MatrixClass)
- {
- (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &dx, &dy);
- }
- else
- {
- SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
- dx = SkScalarToFixed(fDstToIndex.getScaleX());
- dy = SkScalarToFixed(fDstToIndex.getSkewY());
- }
- SkFixed b = (SkFixedMul(diffx, fx) +
- SkFixedMul(diffy, fy) - startRadius) << 1;
- SkFixed db = (SkFixedMul(diffx, dx) +
- SkFixedMul(diffy, dy)) << 1;
- if (proc == clamp_tileproc)
- {
- for (; count > 0; --count) {
- SkFixed t = two_point_radial(b, fx, fy, sr2D2, foura, oneOverTwoA, posRoot);
- SkFixed index = SkClampMax(t, 0xFFFF);
- SkASSERT(index <= 0xFFFF);
- *dstC++ = cache[index >> (16 - kCache32Bits)];
- fx += dx;
- fy += dy;
- b += db;
- }
- }
- else if (proc == mirror_tileproc)
- {
- for (; count > 0; --count) {
- SkFixed t = two_point_radial(b, fx, fy, sr2D2, foura, oneOverTwoA, posRoot);
- SkFixed index = mirror_tileproc(t);
- SkASSERT(index <= 0xFFFF);
- *dstC++ = cache[index >> (16 - kCache32Bits)];
- fx += dx;
- fy += dy;
- b += db;
- }
- }
- else
- {
- SkASSERT(proc == repeat_tileproc);
- for (; count > 0; --count) {
- SkFixed t = two_point_radial(b, fx, fy, sr2D2, foura, oneOverTwoA, posRoot);
- SkFixed index = repeat_tileproc(t);
- SkASSERT(index <= 0xFFFF);
- *dstC++ = cache[index >> (16 - kCache32Bits)];
- fx += dx;
- fy += dy;
- b += db;
- }
- }
- }
- else // perspective case
- {
- SkScalar dstX = SkIntToScalar(x);
- SkScalar dstY = SkIntToScalar(y);
- for (; count > 0; --count) {
- SkPoint srcPt;
- dstProc(fDstToIndex, dstX, dstY, &srcPt);
- SkFixed fx = SkScalarToFixed(srcPt.fX);
- SkFixed fy = SkScalarToFixed(srcPt.fY);
- SkFixed b = (SkFixedMul(diffx, fx) +
- SkFixedMul(diffy, fy) - startRadius) << 1;
- SkFixed t = two_point_radial(b, fx, fy, sr2D2, foura, oneOverTwoA, posRoot);
- SkFixed index = proc(t);
- SkASSERT(index <= 0xFFFF);
- *dstC++ = cache[index >> (16 - kCache32Bits)];
- dstX += SK_Scalar1;
- }
- }
- }
-#else
- virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) {
+ virtual void shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
+ int count) SK_OVERRIDE {
SkASSERT(count > 0);
// Zero difference between radii: fill with transparent black.
@@ -1677,7 +1851,7 @@ public:
}
SkMatrix::MapXYProc dstProc = fDstToIndexProc;
TileProc proc = fTileProc;
- const SkPMColor* cache = this->getCache32();
+ const SkPMColor* SK_RESTRICT cache = this->getCache32();
SkScalar foura = fA * 4;
bool posRoot = fDiffRadius < 0;
@@ -1702,38 +1876,18 @@ public:
SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
SkScalar db = (SkScalarMul(fDiff.fX, dx) +
SkScalarMul(fDiff.fY, dy)) * 2;
+
+ TwoPointRadialShadeProc shadeProc = shadeSpan_twopoint_repeat;
if (proc == clamp_tileproc) {
- for (; count > 0; --count) {
- SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot);
- SkFixed index = SkClampMax(t, 0xFFFF);
- SkASSERT(index <= 0xFFFF);
- *dstC++ = cache[index >> (16 - kCache32Bits)];
- fx += dx;
- fy += dy;
- b += db;
- }
+ shadeProc = shadeSpan_twopoint_clamp;
} else if (proc == mirror_tileproc) {
- for (; count > 0; --count) {
- SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot);
- SkFixed index = mirror_tileproc(t);
- SkASSERT(index <= 0xFFFF);
- *dstC++ = cache[index >> (16 - kCache32Bits)];
- fx += dx;
- fy += dy;
- b += db;
- }
+ shadeProc = shadeSpan_twopoint_mirror;
} else {
SkASSERT(proc == repeat_tileproc);
- for (; count > 0; --count) {
- SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot);
- SkFixed index = repeat_tileproc(t);
- SkASSERT(index <= 0xFFFF);
- *dstC++ = cache[index >> (16 - kCache32Bits)];
- fx += dx;
- fy += dy;
- b += db;
- }
}
+ (*shadeProc)(fx, dx, fy, dy, b, db,
+ fSr2D2, foura, fOneOverTwoA, posRoot,
+ dstC, cache, count);
} else { // perspective case
SkScalar dstX = SkIntToScalar(x);
SkScalar dstY = SkIntToScalar(y);
@@ -1744,19 +1898,19 @@ public:
SkScalar fy = srcPt.fY;
SkScalar b = (SkScalarMul(fDiff.fX, fx) +
SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
- SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot);
+ SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
+ fOneOverTwoA, posRoot);
SkFixed index = proc(t);
SkASSERT(index <= 0xFFFF);
- *dstC++ = cache[index >> (16 - kCache32Bits)];
+ *dstC++ = cache[index >> Gradient_Shader::kCache32Shift];
dstX += SK_Scalar1;
}
}
}
-#endif
virtual bool setContext(const SkBitmap& device,
const SkPaint& paint,
- const SkMatrix& matrix) {
+ const SkMatrix& matrix) SK_OVERRIDE {
if (!this->INHERITED::setContext(device, paint, matrix)) {
return false;
}
@@ -1770,7 +1924,7 @@ public:
return SkNEW_ARGS(Two_Point_Radial_Gradient, (buffer));
}
- virtual void flatten(SkFlattenableWriteBuffer& buffer) {
+ virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE {
this->INHERITED::flatten(buffer);
buffer.writeScalar(fCenter1.fX);
buffer.writeScalar(fCenter1.fY);
@@ -1789,7 +1943,7 @@ protected:
fRadius2(buffer.readScalar()) {
init();
};
- virtual Factory getFactory() { return CreateProc; }
+ virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
private:
typedef Gradient_Shader INHERITED;
@@ -1809,7 +1963,7 @@ private:
fStartRadius = SkScalarMul(fRadius1, inv);
fSr2D2 = SkScalarSquare(fStartRadius);
fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
- fOneOverTwoA = SkScalarInvert(fA * 2);
+ fOneOverTwoA = fA ? SkScalarInvert(fA * 2) : 0;
fPtsToUnit.setTranslate(-fCenter1.fX, -fCenter1.fY);
fPtsToUnit.postScale(inv, inv);
@@ -1827,13 +1981,13 @@ public:
{
fPtsToUnit.setTranslate(-cx, -cy);
}
- virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count);
- virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count);
+ virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
virtual BitmapType asABitmap(SkBitmap* bitmap,
SkMatrix* matrix,
TileMode* xy,
- SkScalar* twoPointRadialParams) const {
+ SkScalar* twoPointRadialParams) const SK_OVERRIDE {
if (bitmap) {
this->commonAsABitmap(bitmap);
}
@@ -1847,7 +2001,7 @@ public:
return kSweep_BitmapType;
}
- virtual GradientType asAGradient(GradientInfo* info) const {
+ virtual GradientType asAGradient(GradientInfo* info) const SK_OVERRIDE {
if (info) {
commonAsAGradient(info);
info->fPoint[0] = fCenter;
@@ -1859,7 +2013,7 @@ public:
return SkNEW_ARGS(Sweep_Gradient, (buffer));
}
- virtual void flatten(SkFlattenableWriteBuffer& buffer) {
+ virtual void flatten(SkFlattenableWriteBuffer& buffer) SK_OVERRIDE {
this->INHERITED::flatten(buffer);
buffer.writeScalar(fCenter.fX);
buffer.writeScalar(fCenter.fY);
@@ -1871,7 +2025,7 @@ protected:
fCenter(unflatten_point(buffer)) {
}
- virtual Factory getFactory() { return CreateProc; }
+ virtual Factory getFactory() SK_OVERRIDE { return CreateProc; }
private:
typedef Gradient_Shader INHERITED;
@@ -2043,6 +2197,23 @@ static unsigned atan_0_90(SkFixed y, SkFixed x) {
}
// returns angle in a circle [0..2PI) -> [0..255]
+#ifdef SK_SCALAR_IS_FLOAT
+static unsigned SkATan2_255(float y, float x) {
+ // static const float g255Over2PI = 255 / (2 * SK_ScalarPI);
+ static const float g255Over2PI = 40.584510488433314f;
+
+ float result = sk_float_atan2(y, x);
+ if (result < 0) {
+ result += 2 * SK_ScalarPI;
+ }
+ SkASSERT(result >= 0);
+ // since our value is always >= 0, we can cast to int, which is faster than
+ // calling floorf()
+ int ir = (int)(result * g255Over2PI);
+ SkASSERT(ir >= 0 && ir <= 255);
+ return ir;
+}
+#else
static unsigned SkATan2_255(SkFixed y, SkFixed x) {
if (x == 0) {
if (y == 0) {
@@ -2081,7 +2252,7 @@ static unsigned SkATan2_255(SkFixed y, SkFixed x) {
else if (192 == add)
SkASSERT(x > 0 && y < 0);
else
- SkASSERT(!"bad value for add");
+ SkDEBUGFAIL("bad value for add");
#endif
/* This ^ trick makes x, y positive, and the swap<> handles quadrants
@@ -2097,29 +2268,30 @@ static unsigned SkATan2_255(SkFixed y, SkFixed x) {
SkASSERT(result < 256);
return result;
}
+#endif
-void Sweep_Gradient::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
+void Sweep_Gradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, int count) {
SkMatrix::MapXYProc proc = fDstToIndexProc;
const SkMatrix& matrix = fDstToIndex;
- const SkPMColor* cache = this->getCache32();
+ const SkPMColor* SK_RESTRICT cache = this->getCache32();
SkPoint srcPt;
if (fDstToIndexClass != kPerspective_MatrixClass) {
proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
- SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
- SkFixed dy, fy = SkScalarToFixed(srcPt.fY);
+ SkScalar dx, fx = srcPt.fX;
+ SkScalar dy, fy = srcPt.fY;
if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
SkFixed storage[2];
(void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
&storage[0], &storage[1]);
- dx = storage[0];
- dy = storage[1];
+ dx = SkFixedToScalar(storage[0]);
+ dy = SkFixedToScalar(storage[1]);
} else {
SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
- dx = SkScalarToFixed(matrix.getScaleX());
- dy = SkScalarToFixed(matrix.getSkewY());
+ dx = matrix.getScaleX();
+ dy = matrix.getSkewY();
}
for (; count > 0; --count) {
@@ -2130,38 +2302,35 @@ void Sweep_Gradient::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
} else { // perspective case
for (int stop = x + count; x < stop; x++) {
proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
- SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
-
- int index = SkATan2_255(SkScalarToFixed(srcPt.fY),
- SkScalarToFixed(srcPt.fX));
- *dstC++ = cache[index];
+ SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
+ *dstC++ = cache[SkATan2_255(srcPt.fY, srcPt.fX)];
}
}
}
-void Sweep_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
+void Sweep_Gradient::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC, int count) {
SkMatrix::MapXYProc proc = fDstToIndexProc;
const SkMatrix& matrix = fDstToIndex;
- const uint16_t* cache = this->getCache16();
+ const uint16_t* SK_RESTRICT cache = this->getCache16();
int toggle = ((x ^ y) & 1) << kCache16Bits;
SkPoint srcPt;
if (fDstToIndexClass != kPerspective_MatrixClass) {
proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
- SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
- SkFixed dy, fy = SkScalarToFixed(srcPt.fY);
+ SkScalar dx, fx = srcPt.fX;
+ SkScalar dy, fy = srcPt.fY;
if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
SkFixed storage[2];
(void)matrix.fixedStepInX(SkIntToScalar(y) + SK_ScalarHalf,
&storage[0], &storage[1]);
- dx = storage[0];
- dy = storage[1];
+ dx = SkFixedToScalar(storage[0]);
+ dy = SkFixedToScalar(storage[1]);
} else {
SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
- dx = SkScalarToFixed(matrix.getScaleX());
- dy = SkScalarToFixed(matrix.getSkewY());
+ dx = matrix.getScaleX();
+ dy = matrix.getSkewY();
}
for (; count > 0; --count) {
@@ -2176,8 +2345,7 @@ void Sweep_Gradient::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
- int index = SkATan2_255(SkScalarToFixed(srcPt.fY),
- SkScalarToFixed(srcPt.fX));
+ int index = SkATan2_255(srcPt.fY, srcPt.fX);
index >>= (8 - kCache16Bits);
*dstC++ = cache[toggle + index];
toggle ^= (1 << kCache16Bits);
@@ -2259,15 +2427,11 @@ SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
return SkNEW_ARGS(Sweep_Gradient, (cx, cy, colors, pos, count, mapper));
}
-static SkFlattenable::Registrar gLinearGradientReg("Linear_Gradient",
- Linear_Gradient::CreateProc);
-
-static SkFlattenable::Registrar gRadialGradientReg("Radial_Gradient",
- Radial_Gradient::CreateProc);
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Linear_Gradient)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Radial_Gradient)
-static SkFlattenable::Registrar gSweepGradientReg("Sweep_Gradient",
- Sweep_Gradient::CreateProc);
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Sweep_Gradient)
-static SkFlattenable::Registrar
- gTwoPointRadialGradientReg("Two_Point_Radial_Gradient",
- Two_Point_Radial_Gradient::CreateProc);
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Two_Point_Radial_Gradient)
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
diff --git a/src/effects/SkGroupShape.cpp b/src/effects/SkGroupShape.cpp
index b8edc82..fd741ee 100644
--- a/src/effects/SkGroupShape.cpp
+++ b/src/effects/SkGroupShape.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkGroupShape.h"
SkGroupShape::SkGroupShape() {}
@@ -124,5 +131,5 @@ SkFlattenable* SkGroupShape::CreateProc(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkGroupShape, (buffer));
}
-static SkFlattenable::Registrar gReg("SkGroupShape", SkGroupShape::CreateProc);
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkGroupShape)
diff --git a/src/effects/SkKernel33MaskFilter.cpp b/src/effects/SkKernel33MaskFilter.cpp
index 5051f71..852168c 100644
--- a/src/effects/SkKernel33MaskFilter.cpp
+++ b/src/effects/SkKernel33MaskFilter.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkKernel33MaskFilter.h"
#include "SkColorPriv.h"
diff --git a/src/effects/SkLayerDrawLooper.cpp b/src/effects/SkLayerDrawLooper.cpp
index 74cc624..acb3e88 100644
--- a/src/effects/SkLayerDrawLooper.cpp
+++ b/src/effects/SkLayerDrawLooper.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkCanvas.h"
#include "SkColor.h"
#include "SkLayerDrawLooper.h"
@@ -12,9 +19,10 @@ SkLayerDrawLooper::LayerInfo::LayerInfo() {
fPostTranslate = false;
}
-SkLayerDrawLooper::SkLayerDrawLooper() {
- fRecs = NULL;
- fCount = 0;
+SkLayerDrawLooper::SkLayerDrawLooper()
+ : fRecs(NULL),
+ fCount(0),
+ fCurrRec(NULL) {
}
SkLayerDrawLooper::~SkLayerDrawLooper() {
@@ -119,13 +127,11 @@ void SkLayerDrawLooper::ApplyInfo(SkPaint* dst, const SkPaint& src,
dst->setXfermode(src.getXfermode());
}
- // we never copy these
+ // we don't override these
#if 0
- dst->setFlags(src.getFlags());
dst->setTypeface(src.getTypeface());
dst->setTextSize(src.getTextSize());
dst->setTextScaleX(src.getTextScaleX());
- dst->setTextSkewX(src.getTextSkewX());
dst->setRasterizer(src.getRasterizer());
dst->setLooper(src.getLooper());
dst->setTextEncoding(src.getTextEncoding());
@@ -193,7 +199,6 @@ void SkLayerDrawLooper::flatten(SkFlattenableWriteBuffer& buffer) {
Rec* rec = fRecs;
for (int i = 0; i < fCount; i++) {
- buffer.writeInt(rec->fInfo.fFlagsMask);
buffer.writeInt(rec->fInfo.fPaintBits);
buffer.writeInt(rec->fInfo.fColorMode);
buffer.writeScalar(rec->fInfo.fOffset.fX);
@@ -205,15 +210,14 @@ void SkLayerDrawLooper::flatten(SkFlattenableWriteBuffer& buffer) {
}
SkLayerDrawLooper::SkLayerDrawLooper(SkFlattenableReadBuffer& buffer)
- : INHERITED(buffer) {
- fRecs = NULL;
- fCount = 0;
-
+ : INHERITED(buffer),
+ fRecs(NULL),
+ fCount(0),
+ fCurrRec(NULL) {
int count = buffer.readInt();
for (int i = 0; i < count; i++) {
LayerInfo info;
- info.fFlagsMask = buffer.readInt();
info.fPaintBits = buffer.readInt();
info.fColorMode = (SkXfermode::Mode)buffer.readInt();
info.fOffset.fX = buffer.readScalar();
@@ -241,5 +245,4 @@ SkLayerDrawLooper::SkLayerDrawLooper(SkFlattenableReadBuffer& buffer)
///////////////////////////////////////////////////////////////////////////////
-static SkFlattenable::Registrar gReg("SkLayerDrawLooper",
- SkLayerDrawLooper::CreateProc);
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkLayerDrawLooper)
diff --git a/src/effects/SkLayerRasterizer.cpp b/src/effects/SkLayerRasterizer.cpp
index 27683ef..9b29550 100644
--- a/src/effects/SkLayerRasterizer.cpp
+++ b/src/effects/SkLayerRasterizer.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/effects/SkLayerRasterizer.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkLayerRasterizer.h"
#include "SkBuffer.h"
@@ -22,7 +14,7 @@
#include "SkMaskFilter.h"
#include "SkPaint.h"
#include "SkPath.h"
-#include "SkRegion.h"
+#include "../core/SkRasterClip.h"
#include "SkXfermode.h"
#include <new>
@@ -115,13 +107,13 @@ bool SkLayerRasterizer::onRasterize(const SkPath& path, const SkMatrix& matrix,
}
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;
+ SkBitmap device;
+ SkRasterClip rectClip;
+ SkDraw draw;
+ SkMatrix translatedMatrix; // this translates us to our local pixels
+ SkMatrix drawMatrix; // this translates the path by each layer's offset
- rectClip.setRect(0, 0, mask->fBounds.width(), mask->fBounds.height());
+ rectClip.setRect(SkIRect::MakeWH(mask->fBounds.width(), mask->fBounds.height()));
translatedMatrix = matrix;
translatedMatrix.postTranslate(-SkIntToScalar(mask->fBounds.fLeft),
@@ -132,7 +124,8 @@ bool SkLayerRasterizer::onRasterize(const SkPath& path, const SkMatrix& matrix,
draw.fBitmap = &device;
draw.fMatrix = &drawMatrix;
- draw.fClip = &rectClip;
+ draw.fRC = &rectClip;
+ draw.fClip = &rectClip.bwRgn();
// we set the matrixproc in the loop, as the matrix changes each time (potentially)
draw.fBounder = NULL;
@@ -231,3 +224,5 @@ SkFlattenable::Factory SkLayerRasterizer::getFactory() {
return CreateProc;
}
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkLayerRasterizer)
+
diff --git a/src/effects/SkPaintFlagsDrawFilter.cpp b/src/effects/SkPaintFlagsDrawFilter.cpp
index 9b7cff1..1fe4402 100644
--- a/src/effects/SkPaintFlagsDrawFilter.cpp
+++ b/src/effects/SkPaintFlagsDrawFilter.cpp
@@ -1,19 +1,12 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkPaintFlagsDrawFilter.h"
#include "SkPaint.h"
diff --git a/src/effects/SkPixelXorXfermode.cpp b/src/effects/SkPixelXorXfermode.cpp
index f4a74ee..935a475 100644
--- a/src/effects/SkPixelXorXfermode.cpp
+++ b/src/effects/SkPixelXorXfermode.cpp
@@ -1,19 +1,12 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkPixelXorXfermode.h"
#include "SkColorPriv.h"
@@ -43,6 +36,4 @@ SkFlattenable* SkPixelXorXfermode::Create(SkFlattenableReadBuffer& rb) {
return SkNEW_ARGS(SkPixelXorXfermode, (rb));
}
-static SkFlattenable::Registrar
- gSkPixelXorXfermodeReg("SkPixelXorXfermode",
- SkPixelXorXfermode::CreateProc);
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkPixelXorXfermode)
diff --git a/src/effects/SkPorterDuff.cpp b/src/effects/SkPorterDuff.cpp
index fd3e1c0..8acb345 100644
--- a/src/effects/SkPorterDuff.cpp
+++ b/src/effects/SkPorterDuff.cpp
@@ -1,19 +1,12 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkPorterDuff.h"
#include "SkXfermode.h"
@@ -46,7 +39,7 @@ static const struct Pair {
MAKE_PAIR(Multiply),
MAKE_PAIR(Screen),
{ SkPorterDuff::kAdd_Mode, SkXfermode::kPlus_Mode },
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
MAKE_PAIR(Overlay),
#endif
};
diff --git a/src/effects/SkRadialGradient_Table.h b/src/effects/SkRadialGradient_Table.h
index 2336237..7db23df 100644
--- a/src/effects/SkRadialGradient_Table.h
+++ b/src/effects/SkRadialGradient_Table.h
@@ -1,19 +1,11 @@
-/* libs/graphics/effects/SkRadialGradient_Table.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
static const uint8_t gSqrt8Table[] = {
0x00, 0x05, 0x08, 0x09, 0x0B, 0x0C, 0x0D, 0x0E, 0x10, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x15,
diff --git a/src/effects/SkRectShape.cpp b/src/effects/SkRectShape.cpp
index 47520f0..3e37072 100644
--- a/src/effects/SkRectShape.cpp
+++ b/src/effects/SkRectShape.cpp
@@ -1,19 +1,12 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkRectShape.h"
#include "SkCanvas.h"
@@ -99,5 +92,5 @@ SkPaintShape::SkPaintShape(SkFlattenableReadBuffer& buffer) : INHERITED(buffer)
fPaint.unflatten(buffer);
}
-static SkFlattenable::Registrar gReg("SkRectShape", SkRectShape::CreateProc);
+SK_DEFINE_FLATTENABLE_REGISTRAR(SkRectShape)
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
new file mode 100644
index 0000000..800d4a9
--- /dev/null
+++ b/src/effects/SkTableColorFilter.cpp
@@ -0,0 +1,220 @@
+#include "SkColorPriv.h"
+#include "SkTableColorFilter.h"
+#include "SkUnPreMultiply.h"
+
+class SkTable_ColorFilter : public SkColorFilter {
+public:
+ SkTable_ColorFilter(const uint8_t tableA[], const uint8_t tableR[],
+ const uint8_t tableG[], const uint8_t tableB[]) {
+ fBitmap = NULL;
+ fFlags = 0;
+
+ uint8_t* dst = fStorage;
+ if (tableA) {
+ memcpy(dst, tableA, 256);
+ dst += 256;
+ fFlags |= kA_Flag;
+ }
+ if (tableR) {
+ memcpy(dst, tableR, 256);
+ dst += 256;
+ fFlags |= kR_Flag;
+ }
+ if (tableG) {
+ memcpy(dst, tableG, 256);
+ dst += 256;
+ fFlags |= kG_Flag;
+ }
+ if (tableB) {
+ memcpy(dst, tableB, 256);
+ fFlags |= kB_Flag;
+ }
+ }
+
+ virtual bool asComponentTable(SkBitmap* table) SK_OVERRIDE;
+
+ virtual void filterSpan(const SkPMColor src[], int count,
+ SkPMColor dst[]) SK_OVERRIDE;
+ virtual void flatten(SkFlattenableWriteBuffer&) SK_OVERRIDE;
+ virtual Factory getFactory() SK_OVERRIDE;
+
+ static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
+ return SkNEW_ARGS(SkTable_ColorFilter, (buffer));
+ }
+
+protected:
+ SkTable_ColorFilter(SkFlattenableReadBuffer& buffer);
+
+private:
+ SkBitmap* fBitmap;
+
+ enum {
+ kA_Flag = 1 << 0,
+ kR_Flag = 1 << 1,
+ kG_Flag = 1 << 2,
+ kB_Flag = 1 << 3,
+ };
+ uint8_t fStorage[256 * 4];
+ unsigned fFlags;
+
+ typedef SkColorFilter INHERITED;
+};
+
+static const uint8_t gIdentityTable[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
+ 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+ 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
+ 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
+ 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
+ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+ 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
+};
+
+void SkTable_ColorFilter::filterSpan(const SkPMColor src[], int count,
+ SkPMColor dst[]) {
+ const uint8_t* table = fStorage;
+ const uint8_t* tableA = gIdentityTable;
+ const uint8_t* tableR = gIdentityTable;
+ const uint8_t* tableG = gIdentityTable;
+ const uint8_t* tableB = gIdentityTable;
+ if (fFlags & kA_Flag) {
+ tableA = table; table += 256;
+ }
+ if (fFlags & kR_Flag) {
+ tableR = table; table += 256;
+ }
+ if (fFlags & kG_Flag) {
+ tableG = table; table += 256;
+ }
+ if (fFlags & kB_Flag) {
+ tableB = table;
+ }
+
+ const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
+ for (int i = 0; i < count; ++i) {
+ SkPMColor c = src[i];
+ unsigned a, r, g, b;
+ if (0 == c) {
+ a = r = g = b = 0;
+ } else {
+ a = SkGetPackedA32(c);
+ r = SkGetPackedR32(c);
+ g = SkGetPackedG32(c);
+ b = SkGetPackedB32(c);
+
+ if (a < 255) {
+ SkUnPreMultiply::Scale scale = scaleTable[a];
+ r = SkUnPreMultiply::ApplyScale(scale, r);
+ g = SkUnPreMultiply::ApplyScale(scale, g);
+ b = SkUnPreMultiply::ApplyScale(scale, b);
+ }
+ }
+ dst[i] = SkPremultiplyARGBInline(tableA[a], tableR[r],
+ tableG[g], tableB[b]);
+ }
+}
+
+SkFlattenable::Factory SkTable_ColorFilter::getFactory() {
+ return CreateProc;
+}
+
+static const uint8_t gCountNibBits[] = {
+ 0, 1, 1, 2,
+ 1, 2, 2, 3,
+ 1, 2, 2, 3,
+ 2, 3, 3, 4
+};
+
+#include "SkPackBits.h"
+
+void SkTable_ColorFilter::flatten(SkFlattenableWriteBuffer& buffer) {
+ this->INHERITED::flatten(buffer);
+
+ uint8_t storage[5*256];
+ int count = gCountNibBits[fFlags & 0xF];
+ size_t size = SkPackBits::Pack8(fStorage, count * 256, storage);
+ SkASSERT(size <= sizeof(storage));
+
+// SkDebugf("raw %d packed %d\n", count * 256, size);
+
+ buffer.writeInt(fFlags);
+ buffer.writeInt(size);
+ buffer.write(storage, size);
+}
+
+SkTable_ColorFilter::SkTable_ColorFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
+ fBitmap = NULL;
+
+ uint8_t storage[5*256];
+
+ fFlags = buffer.readInt();
+ size_t size = buffer.readInt();
+ buffer.read(storage, size);
+
+ size_t raw = SkPackBits::Unpack8(storage, size, fStorage);
+
+ SkASSERT(raw <= sizeof(fStorage));
+ size_t count = gCountNibBits[fFlags & 0xF];
+ SkASSERT(raw == count * 256);
+}
+
+bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) {
+ if (table) {
+ if (NULL == fBitmap) {
+ fBitmap = new SkBitmap;
+ fBitmap->setConfig(SkBitmap::kA8_Config, 256, 4, 256);
+ fBitmap->allocPixels();
+ memcpy(fBitmap->getAddr8(0, 0), fStorage, 256 * 4);
+ }
+ *table = *fBitmap;
+ }
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef SK_CPU_BENDIAN
+#else
+ #define SK_A32_INDEX (3 - (SK_A32_SHIFT >> 3))
+ #define SK_R32_INDEX (3 - (SK_R32_SHIFT >> 3))
+ #define SK_G32_INDEX (3 - (SK_G32_SHIFT >> 3))
+ #define SK_B32_INDEX (3 - (SK_B32_SHIFT >> 3))
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
+ return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
+}
+
+SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
+ const uint8_t tableR[256],
+ const uint8_t tableG[256],
+ const uint8_t tableB[256]) {
+ return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
+}
diff --git a/src/effects/SkTableMaskFilter.cpp b/src/effects/SkTableMaskFilter.cpp
index 8edbf7e..5842e4b 100644
--- a/src/effects/SkTableMaskFilter.cpp
+++ b/src/effects/SkTableMaskFilter.cpp
@@ -1,19 +1,12 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkTableMaskFilter.h"
SkTableMaskFilter::SkTableMaskFilter() {
diff --git a/src/effects/SkTestImageFilters.cpp b/src/effects/SkTestImageFilters.cpp
new file mode 100755
index 0000000..a772f64
--- /dev/null
+++ b/src/effects/SkTestImageFilters.cpp
@@ -0,0 +1,401 @@
+#include "SkTestImageFilters.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+
+class OwnDeviceCanvas : public SkCanvas {
+public:
+ OwnDeviceCanvas(SkDevice* device) : SkCanvas(device) {
+ SkSafeUnref(device);
+ }
+};
+
+bool SkOffsetImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
+ const SkMatrix& matrix,
+ SkBitmap* result,
+ SkIPoint* loc) {
+ SkVector vec;
+ matrix.mapVectors(&vec, &fOffset, 1);
+
+ loc->fX += SkScalarRoundToInt(vec.fX);
+ loc->fY += SkScalarRoundToInt(vec.fY);
+ *result = src;
+ return true;
+}
+
+bool SkOffsetImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
+ SkIRect* dst) {
+ SkVector vec;
+ ctm.mapVectors(&vec, &fOffset, 1);
+
+ *dst = src;
+ dst->offset(SkScalarRoundToInt(vec.fX), SkScalarRoundToInt(vec.fY));
+ return true;
+}
+
+void SkOffsetImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
+ this->INHERITED::flatten(buffer);
+ buffer.writeScalar(fOffset.x());
+ buffer.writeScalar(fOffset.y());
+}
+
+SkOffsetImageFilter::SkOffsetImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
+ fOffset.fX = buffer.readScalar();
+ fOffset.fY = buffer.readScalar();
+}
+
+SkFlattenable::Factory SkOffsetImageFilter::getFactory() {
+ return CreateProc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkComposeImageFilter::~SkComposeImageFilter() {
+ SkSafeUnref(fInner);
+ SkSafeUnref(fOuter);
+}
+
+bool SkComposeImageFilter::onFilterImage(Proxy* proxy,
+ const SkBitmap& src,
+ const SkMatrix& ctm,
+ SkBitmap* result,
+ SkIPoint* loc) {
+ if (!fOuter && !fInner) {
+ return false;
+ }
+
+ if (!fOuter || !fInner) {
+ return (fOuter ? fOuter : fInner)->filterImage(proxy, src, ctm, result, loc);
+ }
+
+ SkBitmap tmp;
+ return fInner->filterImage(proxy, src, ctm, &tmp, loc) &&
+ fOuter->filterImage(proxy, tmp, ctm, result, loc);
+}
+
+bool SkComposeImageFilter::onFilterBounds(const SkIRect& src,
+ const SkMatrix& ctm,
+ SkIRect* dst) {
+ if (!fOuter && !fInner) {
+ return false;
+ }
+
+ if (!fOuter || !fInner) {
+ return (fOuter ? fOuter : fInner)->filterBounds(src, ctm, dst);
+ }
+
+ SkIRect tmp;
+ return fInner->filterBounds(src, ctm, &tmp) &&
+ fOuter->filterBounds(tmp, ctm, dst);
+}
+
+void SkComposeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
+ this->INHERITED::flatten(buffer);
+
+ buffer.writeFlattenable(fOuter);
+ buffer.writeFlattenable(fInner);
+}
+
+SkComposeImageFilter::SkComposeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
+ fOuter = (SkImageFilter*)buffer.readFlattenable();
+ fInner = (SkImageFilter*)buffer.readFlattenable();
+}
+
+SkFlattenable::Factory SkComposeImageFilter::getFactory() {
+ return CreateProc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+template <typename T> T* SkSafeRefReturn(T* obj) {
+ SkSafeRef(obj);
+ return obj;
+}
+
+void SkMergeImageFilter::initAlloc(int count, bool hasModes) {
+ if (count < 1) {
+ fFilters = NULL;
+ fModes = NULL;
+ fCount = 0;
+ } else {
+ int modeCount = hasModes ? count : 0;
+ size_t size = sizeof(SkImageFilter*) * count + sizeof(uint8_t) * modeCount;
+ if (size <= sizeof(fStorage)) {
+ fFilters = SkTCast<SkImageFilter**>(fStorage);
+ } else {
+ fFilters = SkTCast<SkImageFilter**>(sk_malloc_throw(size));
+ }
+ fModes = hasModes ? SkTCast<uint8_t*>(fFilters + count) : NULL;
+ fCount = count;
+ }
+}
+
+void SkMergeImageFilter::init(SkImageFilter* const filters[], int count,
+ const SkXfermode::Mode modes[]) {
+ this->initAlloc(count, !!modes);
+ for (int i = 0; i < count; ++i) {
+ fFilters[i] = SkSafeRefReturn(filters[i]);
+ if (modes) {
+ fModes[i] = SkToU8(modes[i]);
+ }
+ }
+}
+
+SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* first, SkImageFilter* second,
+ SkXfermode::Mode mode) {
+ SkImageFilter* filters[] = { first, second };
+ SkXfermode::Mode modes[] = { mode, mode };
+ this->init(filters, 2, SkXfermode::kSrcOver_Mode == mode ? NULL : modes);
+}
+
+SkMergeImageFilter::SkMergeImageFilter(SkImageFilter* const filters[], int count,
+ const SkXfermode::Mode modes[]) {
+ this->init(filters, count, modes);
+}
+
+SkMergeImageFilter::~SkMergeImageFilter() {
+ for (int i = 0; i < fCount; ++i) {
+ SkSafeUnref(fFilters[i]);
+ }
+
+ if (fFilters != SkTCast<SkImageFilter**>(fStorage)) {
+ sk_free(fFilters);
+ // fModes is allocated in the same block as fFilters, so no need to
+ // separately free it.
+ }
+}
+
+bool SkMergeImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
+ SkIRect* dst) {
+ if (fCount < 1) {
+ return false;
+ }
+
+ SkIRect totalBounds;
+
+ for (int i = 0; i < fCount; ++i) {
+ SkImageFilter* filter = fFilters[i];
+ SkIRect r;
+ if (filter) {
+ if (!filter->filterBounds(src, ctm, &r)) {
+ return false;
+ }
+ } else {
+ r = src;
+ }
+ if (0 == i) {
+ totalBounds = r;
+ } else {
+ totalBounds.join(r);
+ }
+ }
+
+ // don't modify dst until now, so we don't accidentally change it in the
+ // loop, but then return false on the next filter.
+ *dst = totalBounds;
+ return true;
+}
+
+bool SkMergeImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
+ const SkMatrix& ctm,
+ SkBitmap* result, SkIPoint* loc) {
+ if (fCount < 1) {
+ return false;
+ }
+
+ const SkIRect srcBounds = SkIRect::MakeXYWH(loc->x(), loc->y(),
+ src.width(), src.height());
+ SkIRect bounds;
+ if (!this->filterBounds(srcBounds, ctm, &bounds)) {
+ return false;
+ }
+
+ const int x0 = bounds.left();
+ const int y0 = bounds.top();
+
+ SkDevice* dst = proxy->createDevice(bounds.width(), bounds.height());
+ if (NULL == dst) {
+ return false;
+ }
+ OwnDeviceCanvas canvas(dst);
+ SkPaint paint;
+
+ for (int i = 0; i < fCount; ++i) {
+ SkBitmap tmp;
+ const SkBitmap* srcPtr;
+ SkIPoint pos = *loc;
+ SkImageFilter* filter = fFilters[i];
+ if (filter) {
+ if (!filter->filterImage(proxy, src, ctm, &tmp, &pos)) {
+ return false;
+ }
+ srcPtr = &tmp;
+ } else {
+ srcPtr = &src;
+ }
+
+ if (fModes) {
+ paint.setXfermodeMode((SkXfermode::Mode)fModes[i]);
+ } else {
+ paint.setXfermode(NULL);
+ }
+ canvas.drawSprite(*srcPtr, pos.x() - x0, pos.y() - y0, &paint);
+ }
+
+ loc->set(bounds.left(), bounds.top());
+ *result = dst->accessBitmap(false);
+ return true;
+}
+
+void SkMergeImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
+ this->INHERITED::flatten(buffer);
+
+ int storedCount = fCount;
+ if (fModes) {
+ // negative count signals we have modes
+ storedCount = -storedCount;
+ }
+ buffer.write32(storedCount);
+
+ if (fCount) {
+ for (int i = 0; i < fCount; ++i) {
+ buffer.writeFlattenable(fFilters[i]);
+ }
+ if (fModes) {
+ buffer.write(fModes, fCount * sizeof(fModes[0]));
+ }
+ }
+}
+
+SkMergeImageFilter::SkMergeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
+ int storedCount = buffer.readS32();
+ this->initAlloc(SkAbs32(storedCount), storedCount < 0);
+
+ for (int i = 0; i < fCount; ++i) {
+ fFilters[i] = (SkImageFilter*)buffer.readFlattenable();
+ }
+
+ if (fModes) {
+ SkASSERT(storedCount < 0);
+ buffer.read(fModes, fCount * sizeof(fModes[0]));
+ } else {
+ SkASSERT(storedCount >= 0);
+ }
+}
+
+SkFlattenable::Factory SkMergeImageFilter::getFactory() {
+ return CreateProc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkColorFilter.h"
+
+SkColorFilterImageFilter::~SkColorFilterImageFilter() {
+ SkSafeUnref(fColorFilter);
+}
+
+bool SkColorFilterImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
+ const SkMatrix& matrix,
+ SkBitmap* result,
+ SkIPoint* loc) {
+ SkColorFilter* cf = fColorFilter;
+ if (NULL == cf) {
+ *result = src;
+ return true;
+ }
+
+ SkDevice* dev = proxy->createDevice(src.width(), src.height());
+ if (NULL == dev) {
+ return false;
+ }
+ OwnDeviceCanvas canvas(dev);
+ SkPaint paint;
+
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ paint.setColorFilter(fColorFilter);
+ canvas.drawSprite(src, 0, 0, &paint);
+
+ *result = dev->accessBitmap(false);
+ return true;
+}
+
+void SkColorFilterImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
+ this->INHERITED::flatten(buffer);
+
+ buffer.writeFlattenable(fColorFilter);
+}
+
+SkColorFilterImageFilter::SkColorFilterImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
+ fColorFilter = (SkColorFilter*)buffer.readFlattenable();
+}
+
+SkFlattenable::Factory SkColorFilterImageFilter::getFactory() {
+ return CreateProc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool SkDownSampleImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
+ const SkMatrix& matrix,
+ SkBitmap* result, SkIPoint*) {
+ SkScalar scale = fScale;
+ if (scale > SK_Scalar1 || scale <= 0) {
+ return false;
+ }
+
+ int dstW = SkScalarRoundToInt(src.width() * scale);
+ int dstH = SkScalarRoundToInt(src.height() * scale);
+ if (dstW < 1) {
+ dstW = 1;
+ }
+ if (dstH < 1) {
+ dstH = 1;
+ }
+
+ SkBitmap tmp;
+
+ // downsample
+ {
+ SkDevice* dev = proxy->createDevice(dstW, dstH);
+ if (NULL == dev) {
+ return false;
+ }
+ OwnDeviceCanvas canvas(dev);
+ SkPaint paint;
+
+ paint.setFilterBitmap(true);
+ canvas.scale(scale, scale);
+ canvas.drawBitmap(src, 0, 0, &paint);
+ tmp = dev->accessBitmap(false);
+ }
+
+ // upscale
+ {
+ SkDevice* dev = proxy->createDevice(src.width(), src.height());
+ if (NULL == dev) {
+ return false;
+ }
+ OwnDeviceCanvas canvas(dev);
+
+ SkRect r = SkRect::MakeWH(SkIntToScalar(src.width()),
+ SkIntToScalar(src.height()));
+ canvas.drawBitmapRect(tmp, NULL, r, NULL);
+ *result = dev->accessBitmap(false);
+ }
+ return true;
+}
+
+void SkDownSampleImageFilter::flatten(SkFlattenableWriteBuffer& buffer) {
+ this->INHERITED::flatten(buffer);
+
+ buffer.writeScalar(fScale);
+}
+
+SkDownSampleImageFilter::SkDownSampleImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
+ fScale = buffer.readScalar();
+}
+
+SkFlattenable::Factory SkDownSampleImageFilter::getFactory() {
+ return CreateProc;
+}
+
diff --git a/src/effects/SkTransparentShader.cpp b/src/effects/SkTransparentShader.cpp
index 6e68b5e..486fc89 100644
--- a/src/effects/SkTransparentShader.cpp
+++ b/src/effects/SkTransparentShader.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/effects/SkTransparentShader.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTransparentShader.h"
#include "SkColorPriv.h"
@@ -102,7 +94,7 @@ void SkTransparentShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
break;
}
case SkBitmap::kIndex8_Config:
- SkASSERT(!"index8 not supported as a destination device");
+ SkDEBUGFAIL("index8 not supported as a destination device");
break;
case SkBitmap::kA8_Config: {
const uint8_t* src = fDevice->getAddr8(x, y);
@@ -118,7 +110,7 @@ void SkTransparentShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
break;
}
case SkBitmap::kA1_Config:
- SkASSERT(!"kA1_Config umimplemented at this time");
+ SkDEBUGFAIL("kA1_Config umimplemented at this time");
break;
default: // to avoid warnings
break;
@@ -134,3 +126,11 @@ void SkTransparentShader::shadeSpan16(int x, int y, uint16_t span[], int count)
}
}
+SkFlattenable::Factory SkTransparentShader::getFactory() {
+ return Create;
+}
+
+void SkTransparentShader::flatten(SkFlattenableWriteBuffer& buffer) {
+ this->INHERITED::flatten(buffer);
+}
+
diff --git a/src/effects/effects_files.mk b/src/effects/effects_files.mk
deleted file mode 100644
index 00d9e7d..0000000
--- a/src/effects/effects_files.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-SOURCE := \
- Sk1DPathEffect.cpp \
- Sk2DPathEffect.cpp \
- SkBitmapCache.cpp \
- SkTransparentShader.cpp \
- SkAvoidXfermode.cpp \
- SkBlurDrawLooper.cpp \
- SkBlurMask.cpp \
- SkBlurMaskFilter.cpp \
- SkColorFilters.cpp \
- SkColorMatrixFilter.cpp \
- SkCornerPathEffect.cpp \
- SkDashPathEffect.cpp \
- SkDiscretePathEffect.cpp \
- SkEmbossMask.cpp \
- SkEmbossMaskFilter.cpp \
- SkGradientShader.cpp \
- SkGroupShape.cpp \
- SkKernel33MaskFilter.cpp \
- SkLayerDrawLooper.cpp \
- SkLayerRasterizer.cpp \
- SkPaintFlagsDrawFilter.cpp \
- SkPixelXorXfermode.cpp \
- SkPorterDuff.cpp \
- SkRectShape.cpp
diff --git a/gpu/src/FlingState.cpp b/src/gpu/FlingState.cpp
index cb634cc..050a810 100644
--- a/gpu/src/FlingState.cpp
+++ b/src/gpu/FlingState.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "FlingState.h"
#include "SkMatrix.h"
#include "SkTime.h"
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
new file mode 100644
index 0000000..29db9aa
--- /dev/null
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp
@@ -0,0 +1,730 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrAAHairLinePathRenderer.h"
+
+#include "GrContext.h"
+#include "GrDrawState.h"
+#include "GrGpu.h"
+#include "GrIndexBuffer.h"
+#include "GrPathUtils.h"
+#include "SkGeometry.h"
+#include "SkTemplates.h"
+
+namespace {
+// quadratics are rendered as 5-sided polys in order to bound the
+// AA stroke around the center-curve. See comments in push_quad_index_buffer and
+// bloat_quad.
+static const int kVertsPerQuad = 5;
+static const int kIdxsPerQuad = 9;
+
+static const int kVertsPerLineSeg = 4;
+static const int kIdxsPerLineSeg = 6;
+
+static const int kNumQuadsInIdxBuffer = 256;
+static const size_t kQuadIdxSBufize = kIdxsPerQuad *
+ sizeof(uint16_t) *
+ kNumQuadsInIdxBuffer;
+
+bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) {
+ uint16_t* data = (uint16_t*) qIdxBuffer->lock();
+ bool tempData = NULL == data;
+ if (tempData) {
+ data = new uint16_t[kNumQuadsInIdxBuffer * kIdxsPerQuad];
+ }
+ for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) {
+
+ // Each quadratic is rendered as a five sided polygon. This poly bounds
+ // the quadratic's bounding triangle but has been expanded so that the
+ // 1-pixel wide area around the curve is inside the poly.
+ // If a,b,c are the original control points then the poly a0,b0,c0,c1,a1
+ // that is rendered would look like this:
+ // b0
+ // b
+ //
+ // a0 c0
+ // a c
+ // a1 c1
+ // Each is drawn as three triagnles specified by these 9 indices:
+ int baseIdx = i * kIdxsPerQuad;
+ uint16_t baseVert = (uint16_t)(i * kVertsPerQuad);
+ data[0 + baseIdx] = baseVert + 0; // a0
+ data[1 + baseIdx] = baseVert + 1; // a1
+ data[2 + baseIdx] = baseVert + 2; // b0
+ data[3 + baseIdx] = baseVert + 2; // b0
+ data[4 + baseIdx] = baseVert + 4; // c1
+ data[5 + baseIdx] = baseVert + 3; // c0
+ data[6 + baseIdx] = baseVert + 1; // a1
+ data[7 + baseIdx] = baseVert + 4; // c1
+ data[8 + baseIdx] = baseVert + 2; // b0
+ }
+ if (tempData) {
+ bool ret = qIdxBuffer->updateData(data, kQuadIdxSBufize);
+ delete[] data;
+ return ret;
+ } else {
+ qIdxBuffer->unlock();
+ return true;
+ }
+}
+}
+
+GrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* context) {
+ const GrIndexBuffer* lIdxBuffer = context->getQuadIndexBuffer();
+ if (NULL == lIdxBuffer) {
+ return NULL;
+ }
+ GrGpu* gpu = context->getGpu();
+ GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false);
+ SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf);
+ if (NULL == qIdxBuf ||
+ !push_quad_index_data(qIdxBuf)) {
+ return NULL;
+ }
+ return new GrAAHairLinePathRenderer(context,
+ lIdxBuffer,
+ qIdxBuf);
+}
+
+GrAAHairLinePathRenderer::GrAAHairLinePathRenderer(
+ const GrContext* context,
+ const GrIndexBuffer* linesIndexBuffer,
+ const GrIndexBuffer* quadsIndexBuffer) {
+ fLinesIndexBuffer = linesIndexBuffer;
+ linesIndexBuffer->ref();
+ fQuadsIndexBuffer = quadsIndexBuffer;
+ quadsIndexBuffer->ref();
+ this->resetGeom();
+}
+
+GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() {
+ fLinesIndexBuffer->unref();
+ fQuadsIndexBuffer->unref();
+}
+
+bool GrAAHairLinePathRenderer::canDrawPath(const GrDrawTarget::Caps& targetCaps,
+ const SkPath& path,
+ GrPathFill fill,
+ bool antiAlias) const {
+ static const uint32_t gReqDerivMask = SkPath::kCubic_SegmentMask |
+ SkPath::kQuad_SegmentMask;
+ return (kHairLine_PathFill == fill &&
+ antiAlias &&
+ (targetCaps.fShaderDerivativeSupport ||
+ !(gReqDerivMask & path.getSegmentMasks())));
+}
+
+void GrAAHairLinePathRenderer::pathWillClear() {
+ this->resetGeom();
+}
+
+void GrAAHairLinePathRenderer::resetGeom() {
+ fPreviousStages = ~0;
+ fPreviousRTHeight = ~0;
+ fPreviousViewMatrix = GrMatrix::InvalidMatrix();
+ fLineSegmentCnt = 0;
+ fQuadCnt = 0;
+ if ((fQuadCnt || fLineSegmentCnt) && NULL != fTarget) {
+ fTarget->resetVertexSource();
+ }
+}
+
+namespace {
+
+typedef SkTArray<SkPoint, true> PtArray;
+#define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true>
+typedef SkTArray<int, true> IntArray;
+
+/**
+ * We convert cubics to quadratics (for now).
+ */
+void convert_noninflect_cubic_to_quads(const SkPoint p[4],
+ SkScalar tolScale,
+ PtArray* quads,
+ int sublevel = 0) {
+ SkVector ab = p[1];
+ ab -= p[0];
+ SkVector dc = p[2];
+ dc -= p[3];
+
+ static const SkScalar gLengthScale = 3 * SK_Scalar1 / 2;
+ // base tolerance is 2 pixels in dev coords.
+ const SkScalar distanceSqdTol = SkScalarMul(tolScale, 2 * SK_Scalar1);
+ static const int kMaxSubdivs = 10;
+
+ ab.scale(gLengthScale);
+ dc.scale(gLengthScale);
+
+ SkVector c0 = p[0];
+ c0 += ab;
+ SkVector c1 = p[3];
+ c1 += dc;
+
+ SkScalar dSqd = c0.distanceToSqd(c1);
+ if (sublevel > kMaxSubdivs || dSqd <= distanceSqdTol) {
+ SkPoint cAvg = c0;
+ cAvg += c1;
+ cAvg.scale(SK_ScalarHalf);
+
+ SkPoint* pts = quads->push_back_n(3);
+ pts[0] = p[0];
+ pts[1] = cAvg;
+ pts[2] = p[3];
+
+ return;
+ } else {
+ SkPoint choppedPts[7];
+ SkChopCubicAtHalf(p, choppedPts);
+ convert_noninflect_cubic_to_quads(choppedPts + 0, tolScale,
+ quads, sublevel + 1);
+ convert_noninflect_cubic_to_quads(choppedPts + 3, tolScale,
+ quads, sublevel + 1);
+ }
+}
+
+void convert_cubic_to_quads(const SkPoint p[4],
+ SkScalar tolScale,
+ PtArray* quads) {
+ SkPoint chopped[13];
+ int count = SkChopCubicAtInflections(p, chopped);
+
+ for (int i = 0; i < count; ++i) {
+ SkPoint* cubic = chopped + 3*i;
+ convert_noninflect_cubic_to_quads(cubic, tolScale, quads);
+ }
+}
+
+// Takes 178th time of logf on Z600 / VC2010
+int get_float_exp(float x) {
+ GR_STATIC_ASSERT(sizeof(int) == sizeof(float));
+#if GR_DEBUG
+ static bool tested;
+ if (!tested) {
+ tested = true;
+ GrAssert(get_float_exp(0.25f) == -2);
+ GrAssert(get_float_exp(0.3f) == -2);
+ GrAssert(get_float_exp(0.5f) == -1);
+ GrAssert(get_float_exp(1.f) == 0);
+ GrAssert(get_float_exp(2.f) == 1);
+ GrAssert(get_float_exp(2.5f) == 1);
+ GrAssert(get_float_exp(8.f) == 3);
+ GrAssert(get_float_exp(100.f) == 6);
+ GrAssert(get_float_exp(1000.f) == 9);
+ GrAssert(get_float_exp(1024.f) == 10);
+ GrAssert(get_float_exp(3000000.f) == 21);
+ }
+#endif
+ const int* iptr = (const int*)&x;
+ return (((*iptr) & 0x7f800000) >> 23) - 127;
+}
+
+// we subdivide the quads to avoid huge overfill
+// if it returns -1 then should be drawn as lines
+int num_quad_subdivs(const SkPoint p[3]) {
+ static const SkScalar gDegenerateToLineTol = SK_Scalar1;
+ static const SkScalar gDegenerateToLineTolSqd =
+ SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol);
+
+ if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd ||
+ p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) {
+ return -1;
+ }
+
+ GrScalar dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]);
+ if (dsqd < gDegenerateToLineTolSqd) {
+ return -1;
+ }
+
+ if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) {
+ return -1;
+ }
+
+ static const int kMaxSub = 4;
+ // tolerance of triangle height in pixels
+ // tuned on windows Quadro FX 380 / Z600
+ // trade off of fill vs cpu time on verts
+ // maybe different when do this using gpu (geo or tess shaders)
+ static const SkScalar gSubdivTol = 175 * SK_Scalar1;
+
+ if (dsqd <= gSubdivTol*gSubdivTol) {
+ return 0;
+ } else {
+ // subdividing the quad reduces d by 4. so we want x = log4(d/tol)
+ // = log4(d*d/tol*tol)/2
+ // = log2(d*d/tol*tol)
+
+#ifdef SK_SCALAR_IS_FLOAT
+ // +1 since we're ignoring the mantissa contribution.
+ int log = get_float_exp(dsqd/(gSubdivTol*gSubdivTol)) + 1;
+ log = GrMin(GrMax(0, log), kMaxSub);
+ return log;
+#else
+ SkScalar log = SkScalarLog(SkScalarDiv(dsqd,gSubdivTol*gSubdivTol));
+ static const SkScalar conv = SkScalarInvert(SkScalarLog(2));
+ log = SkScalarMul(log, conv);
+ return GrMin(GrMax(0, SkScalarCeilToInt(log)),kMaxSub);
+#endif
+ }
+}
+
+/**
+ * Generates the lines and quads to be rendered. Lines are always recorded in
+ * device space. We will do a device space bloat to account for the 1pixel
+ * thickness.
+ * Quads are recorded in device space unless m contains
+ * perspective, then in they are in src space. We do this because we will
+ * subdivide large quads to reduce over-fill. This subdivision has to be
+ * performed before applying the perspective matrix.
+ */
+int generate_lines_and_quads(const SkPath& path,
+ const SkMatrix& m,
+ const SkVector& translate,
+ GrIRect clip,
+ PtArray* lines,
+ PtArray* quads,
+ IntArray* quadSubdivCnts) {
+ SkPath::Iter iter(path, false);
+
+ int totalQuadCount = 0;
+ GrRect bounds;
+ GrIRect ibounds;
+
+ bool persp = m.hasPerspective();
+
+ for (;;) {
+ GrPoint pts[4];
+ GrPoint devPts[4];
+ GrPathCmd cmd = (GrPathCmd)iter.next(pts);
+ switch (cmd) {
+ case kMove_PathCmd:
+ break;
+ case kLine_PathCmd:
+ SkPoint::Offset(pts, 2, translate);
+ m.mapPoints(devPts, pts, 2);
+ bounds.setBounds(devPts, 2);
+ bounds.outset(SK_Scalar1, SK_Scalar1);
+ bounds.roundOut(&ibounds);
+ if (SkIRect::Intersects(clip, ibounds)) {
+ SkPoint* pts = lines->push_back_n(2);
+ pts[0] = devPts[0];
+ pts[1] = devPts[1];
+ }
+ break;
+ case kQuadratic_PathCmd:
+ SkPoint::Offset(pts, 3, translate);
+ m.mapPoints(devPts, pts, 3);
+ bounds.setBounds(devPts, 3);
+ bounds.outset(SK_Scalar1, SK_Scalar1);
+ bounds.roundOut(&ibounds);
+ if (SkIRect::Intersects(clip, ibounds)) {
+ int subdiv = num_quad_subdivs(devPts);
+ GrAssert(subdiv >= -1);
+ if (-1 == subdiv) {
+ SkPoint* pts = lines->push_back_n(4);
+ pts[0] = devPts[0];
+ pts[1] = devPts[1];
+ pts[2] = devPts[1];
+ pts[3] = devPts[2];
+ } else {
+ // when in perspective keep quads in src space
+ SkPoint* qPts = persp ? pts : devPts;
+ SkPoint* pts = quads->push_back_n(3);
+ pts[0] = qPts[0];
+ pts[1] = qPts[1];
+ pts[2] = qPts[2];
+ quadSubdivCnts->push_back() = subdiv;
+ totalQuadCount += 1 << subdiv;
+ }
+ }
+ break;
+ case kCubic_PathCmd:
+ SkPoint::Offset(pts, 4, translate);
+ m.mapPoints(devPts, pts, 4);
+ bounds.setBounds(devPts, 4);
+ bounds.outset(SK_Scalar1, SK_Scalar1);
+ bounds.roundOut(&ibounds);
+ if (SkIRect::Intersects(clip, ibounds)) {
+ PREALLOC_PTARRAY(32) q;
+ // in perspective have to do conversion in src space
+ if (persp) {
+ SkScalar tolScale =
+ GrPathUtils::scaleToleranceToSrc(SK_Scalar1, m,
+ path.getBounds());
+ convert_cubic_to_quads(pts, tolScale, &q);
+ } else {
+ convert_cubic_to_quads(devPts, SK_Scalar1, &q);
+ }
+ for (int i = 0; i < q.count(); i += 3) {
+ SkPoint* qInDevSpace;
+ // bounds has to be calculated in device space, but q is
+ // in src space when there is perspective.
+ if (persp) {
+ m.mapPoints(devPts, &q[i], 3);
+ bounds.setBounds(devPts, 3);
+ qInDevSpace = devPts;
+ } else {
+ bounds.setBounds(&q[i], 3);
+ qInDevSpace = &q[i];
+ }
+ bounds.outset(SK_Scalar1, SK_Scalar1);
+ bounds.roundOut(&ibounds);
+ if (SkIRect::Intersects(clip, ibounds)) {
+ int subdiv = num_quad_subdivs(qInDevSpace);
+ GrAssert(subdiv >= -1);
+ if (-1 == subdiv) {
+ SkPoint* pts = lines->push_back_n(4);
+ // lines should always be in device coords
+ pts[0] = qInDevSpace[0];
+ pts[1] = qInDevSpace[1];
+ pts[2] = qInDevSpace[1];
+ pts[3] = qInDevSpace[2];
+ } else {
+ SkPoint* pts = quads->push_back_n(3);
+ // q is already in src space when there is no
+ // perspective and dev coords otherwise.
+ pts[0] = q[0 + i];
+ pts[1] = q[1 + i];
+ pts[2] = q[2 + i];
+ quadSubdivCnts->push_back() = subdiv;
+ totalQuadCount += 1 << subdiv;
+ }
+ }
+ }
+ }
+ break;
+ case kClose_PathCmd:
+ break;
+ case kEnd_PathCmd:
+ return totalQuadCount;
+ }
+ }
+}
+
+struct Vertex {
+ GrPoint fPos;
+ union {
+ struct {
+ GrScalar fA;
+ GrScalar fB;
+ GrScalar fC;
+ } fLine;
+ GrVec fQuadCoord;
+ struct {
+ GrScalar fBogus[4];
+ };
+ };
+};
+GR_STATIC_ASSERT(sizeof(Vertex) == 3 * sizeof(GrPoint));
+
+void intersect_lines(const SkPoint& ptA, const SkVector& normA,
+ const SkPoint& ptB, const SkVector& normB,
+ SkPoint* result) {
+
+ SkScalar lineAW = -normA.dot(ptA);
+ SkScalar lineBW = -normB.dot(ptB);
+
+ SkScalar wInv = SkScalarMul(normA.fX, normB.fY) -
+ SkScalarMul(normA.fY, normB.fX);
+ wInv = SkScalarInvert(wInv);
+
+ result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY);
+ result->fX = SkScalarMul(result->fX, wInv);
+
+ result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW);
+ result->fY = SkScalarMul(result->fY, wInv);
+}
+
+void bloat_quad(const SkPoint qpts[3], const GrMatrix* toDevice,
+ const GrMatrix* toSrc, Vertex verts[kVertsPerQuad]) {
+ GrAssert(!toDevice == !toSrc);
+ // original quad is specified by tri a,b,c
+ SkPoint a = qpts[0];
+ SkPoint b = qpts[1];
+ SkPoint c = qpts[2];
+
+ // compute a matrix that goes from device coords to U,V quad params
+ // this should be in the src space, not dev coords, when we have perspective
+ SkMatrix DevToUV;
+ DevToUV.setAll(a.fX, b.fX, c.fX,
+ a.fY, b.fY, c.fY,
+ SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ DevToUV.invert(&DevToUV);
+ // can't make this static, no cons :(
+ SkMatrix UVpts;
+ UVpts.setAll(0, SK_ScalarHalf, SK_Scalar1,
+ 0, 0, SK_Scalar1,
+ SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ DevToUV.postConcat(UVpts);
+
+ // We really want to avoid perspective matrix muls.
+ // These may wind up really close to zero
+ DevToUV.setPerspX(0);
+ DevToUV.setPerspY(0);
+
+ if (toDevice) {
+ toDevice->mapPoints(&a, 1);
+ toDevice->mapPoints(&b, 1);
+ toDevice->mapPoints(&c, 1);
+ }
+ // make a new poly where we replace a and c by a 1-pixel wide edges orthog
+ // to edges ab and bc:
+ //
+ // before | after
+ // | b0
+ // b |
+ // |
+ // | a0 c0
+ // a c | a1 c1
+ //
+ // edges a0->b0 and b0->c0 are parallel to original edges a->b and b->c,
+ // respectively.
+ Vertex& a0 = verts[0];
+ Vertex& a1 = verts[1];
+ Vertex& b0 = verts[2];
+ Vertex& c0 = verts[3];
+ Vertex& c1 = verts[4];
+
+ SkVector ab = b;
+ ab -= a;
+ SkVector ac = c;
+ ac -= a;
+ SkVector cb = b;
+ cb -= c;
+
+ // We should have already handled degenerates
+ GrAssert(ab.length() > 0 && cb.length() > 0);
+
+ ab.normalize();
+ SkVector abN;
+ abN.setOrthog(ab, SkVector::kLeft_Side);
+ if (abN.dot(ac) > 0) {
+ abN.negate();
+ }
+
+ cb.normalize();
+ SkVector cbN;
+ cbN.setOrthog(cb, SkVector::kLeft_Side);
+ if (cbN.dot(ac) < 0) {
+ cbN.negate();
+ }
+
+ a0.fPos = a;
+ a0.fPos += abN;
+ a1.fPos = a;
+ a1.fPos -= abN;
+
+ c0.fPos = c;
+ c0.fPos += cbN;
+ c1.fPos = c;
+ c1.fPos -= cbN;
+
+ intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos);
+
+ if (toSrc) {
+ toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad);
+ }
+ DevToUV.mapPointsWithStride(&verts[0].fQuadCoord,
+ &verts[0].fPos, sizeof(Vertex), kVertsPerQuad);
+}
+
+void add_quads(const SkPoint p[3],
+ int subdiv,
+ const GrMatrix* toDevice,
+ const GrMatrix* toSrc,
+ Vertex** vert) {
+ GrAssert(subdiv >= 0);
+ if (subdiv) {
+ SkPoint newP[5];
+ SkChopQuadAtHalf(p, newP);
+ add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert);
+ add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert);
+ } else {
+ bloat_quad(p, toDevice, toSrc, *vert);
+ *vert += kVertsPerQuad;
+ }
+}
+
+void add_line(const SkPoint p[2],
+ int rtHeight,
+ const SkMatrix* toSrc,
+ Vertex** vert) {
+ const SkPoint& a = p[0];
+ const SkPoint& b = p[1];
+
+ SkVector orthVec = b;
+ orthVec -= a;
+
+ if (orthVec.setLength(SK_Scalar1)) {
+ orthVec.setOrthog(orthVec);
+
+ // the values we pass down to the frag shader
+ // have to be in y-points-up space;
+ SkVector normal;
+ normal.fX = orthVec.fX;
+ normal.fY = -orthVec.fY;
+ SkPoint aYDown;
+ aYDown.fX = a.fX;
+ aYDown.fY = rtHeight - a.fY;
+
+ SkScalar lineC = -(aYDown.dot(normal));
+ for (int i = 0; i < kVertsPerLineSeg; ++i) {
+ (*vert)[i].fPos = (i < 2) ? a : b;
+ if (0 == i || 3 == i) {
+ (*vert)[i].fPos -= orthVec;
+ } else {
+ (*vert)[i].fPos += orthVec;
+ }
+ (*vert)[i].fLine.fA = normal.fX;
+ (*vert)[i].fLine.fB = normal.fY;
+ (*vert)[i].fLine.fC = lineC;
+ }
+ if (NULL != toSrc) {
+ toSrc->mapPointsWithStride(&(*vert)->fPos,
+ sizeof(Vertex),
+ kVertsPerLineSeg);
+ }
+ } else {
+ // just make it degenerate and likely offscreen
+ (*vert)[0].fPos.set(SK_ScalarMax, SK_ScalarMax);
+ (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax);
+ (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax);
+ (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax);
+ }
+
+ *vert += kVertsPerLineSeg;
+}
+
+}
+
+bool GrAAHairLinePathRenderer::createGeom(GrDrawState::StageMask stageMask) {
+ const GrDrawState& drawState = fTarget->getDrawState();
+ int rtHeight = drawState.getRenderTarget()->height();
+
+ GrIRect clip;
+ if (fTarget->getClip().hasConservativeBounds()) {
+ GrRect clipRect = fTarget->getClip().getConservativeBounds();
+ clipRect.roundOut(&clip);
+ } else {
+ clip.setLargest();
+ }
+
+ // If none of the inputs that affect generation of path geometry have
+ // have changed since last previous path draw then we can reuse the
+ // previous geoemtry.
+ if (stageMask == fPreviousStages &&
+ fPreviousViewMatrix == drawState.getViewMatrix() &&
+ fPreviousTranslate == fTranslate &&
+ rtHeight == fPreviousRTHeight &&
+ fClipRect == clip) {
+ return true;
+ }
+
+ GrVertexLayout layout = GrDrawTarget::kEdge_VertexLayoutBit;
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ if ((1 << s) & stageMask) {
+ layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
+ }
+ }
+
+ GrMatrix viewM = drawState.getViewMatrix();
+
+ PREALLOC_PTARRAY(128) lines;
+ PREALLOC_PTARRAY(128) quads;
+ IntArray qSubdivs;
+ fQuadCnt = generate_lines_and_quads(*fPath, viewM, fTranslate, clip,
+ &lines, &quads, &qSubdivs);
+
+ fLineSegmentCnt = lines.count() / 2;
+ int vertCnt = kVertsPerLineSeg * fLineSegmentCnt + kVertsPerQuad * fQuadCnt;
+
+ GrAssert(sizeof(Vertex) == GrDrawTarget::VertexSize(layout));
+
+ Vertex* verts;
+ if (!fTarget->reserveVertexSpace(layout, vertCnt, (void**)&verts)) {
+ return false;
+ }
+ Vertex* base = verts;
+
+ const GrMatrix* toDevice = NULL;
+ const GrMatrix* toSrc = NULL;
+ GrMatrix ivm;
+
+ if (viewM.hasPerspective()) {
+ if (viewM.invert(&ivm)) {
+ toDevice = &viewM;
+ toSrc = &ivm;
+ }
+ }
+
+ for (int i = 0; i < fLineSegmentCnt; ++i) {
+ add_line(&lines[2*i], rtHeight, toSrc, &verts);
+ }
+
+ int unsubdivQuadCnt = quads.count() / 3;
+ for (int i = 0; i < unsubdivQuadCnt; ++i) {
+ GrAssert(qSubdivs[i] >= 0);
+ add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts);
+ }
+
+ fPreviousStages = stageMask;
+ fPreviousViewMatrix = drawState.getViewMatrix();
+ fPreviousRTHeight = rtHeight;
+ fClipRect = clip;
+ fPreviousTranslate = fTranslate;
+ return true;
+}
+
+void GrAAHairLinePathRenderer::drawPath(GrDrawState::StageMask stageMask) {
+
+ if (!this->createGeom(stageMask)) {
+ return;
+ }
+
+ GrDrawState* drawState = fTarget->drawState();
+
+ GrDrawTarget::AutoStateRestore asr;
+ if (!drawState->getViewMatrix().hasPerspective()) {
+ asr.set(fTarget);
+ GrMatrix ivm;
+ if (drawState->getViewInverse(&ivm)) {
+ drawState->preConcatSamplerMatrices(stageMask, ivm);
+ }
+ drawState->setViewMatrix(GrMatrix::I());
+ }
+
+ // TODO: See whether rendering lines as degenerate quads improves perf
+ // when we have a mix
+ fTarget->setIndexSourceToBuffer(fLinesIndexBuffer);
+ int lines = 0;
+ int nBufLines = fLinesIndexBuffer->maxQuads();
+ while (lines < fLineSegmentCnt) {
+ int n = GrMin(fLineSegmentCnt-lines, nBufLines);
+ drawState->setVertexEdgeType(GrDrawState::kHairLine_EdgeType);
+ fTarget->drawIndexed(kTriangles_PrimitiveType,
+ kVertsPerLineSeg*lines, // startV
+ 0, // startI
+ kVertsPerLineSeg*n, // vCount
+ kIdxsPerLineSeg*n); // iCount
+ lines += n;
+ }
+
+ fTarget->setIndexSourceToBuffer(fQuadsIndexBuffer);
+ int quads = 0;
+ while (quads < fQuadCnt) {
+ int n = GrMin(fQuadCnt-quads, kNumQuadsInIdxBuffer);
+ drawState->setVertexEdgeType(GrDrawState::kHairQuad_EdgeType);
+ fTarget->drawIndexed(kTriangles_PrimitiveType,
+ 4*fLineSegmentCnt + kVertsPerQuad*quads, // startV
+ 0, // startI
+ kVertsPerQuad*n, // vCount
+ kIdxsPerQuad*n); // iCount
+ quads += n;
+ }
+
+}
+
diff --git a/src/gpu/GrAAHairLinePathRenderer.h b/src/gpu/GrAAHairLinePathRenderer.h
new file mode 100644
index 0000000..3b29919
--- /dev/null
+++ b/src/gpu/GrAAHairLinePathRenderer.h
@@ -0,0 +1,59 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrAAHairLinePathRenderer_DEFINED
+#define GrAAHairLinePathRenderer_DEFINED
+
+#include "GrPathRenderer.h"
+
+class GrAAHairLinePathRenderer : public GrPathRenderer {
+public:
+ virtual ~GrAAHairLinePathRenderer();
+
+ static GrPathRenderer* Create(GrContext* context);
+ // GrPathRenderer overrides
+ virtual bool canDrawPath(const GrDrawTarget::Caps& targetCaps,
+ const SkPath& path,
+ GrPathFill fill,
+ bool antiAlias) const SK_OVERRIDE;
+ virtual void drawPath(GrDrawState::StageMask stages) SK_OVERRIDE;
+
+protected:
+
+ // GrPathRenderer overrides
+ virtual void pathWillClear() SK_OVERRIDE;
+
+private:
+ void resetGeom();
+
+ GrAAHairLinePathRenderer(const GrContext* context,
+ const GrIndexBuffer* fLinesIndexBuffer,
+ const GrIndexBuffer* fQuadsIndexBuffer);
+
+ bool createGeom(GrDrawState::StageMask stages);
+
+ const GrIndexBuffer* fLinesIndexBuffer;
+ const GrIndexBuffer* fQuadsIndexBuffer;
+
+ // have to recreate geometry if stages in use changes :(
+ GrDrawState::StageMask fPreviousStages;
+ int fPreviousRTHeight;
+ SkVector fPreviousTranslate;
+ GrIRect fClipRect;
+
+ // this path renderer draws everything in device coordinates
+ GrMatrix fPreviousViewMatrix;
+ int fLineSegmentCnt;
+ int fQuadCnt;
+
+ typedef GrPathRenderer INHERITED;
+};
+
+
+#endif
+
diff --git a/src/gpu/GrAddPathRenderers_aahairline.cpp b/src/gpu/GrAddPathRenderers_aahairline.cpp
new file mode 100644
index 0000000..a7df66e
--- /dev/null
+++ b/src/gpu/GrAddPathRenderers_aahairline.cpp
@@ -0,0 +1,20 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrAAHairLinePathRenderer.h"
+
+void GrPathRenderer::AddPathRenderers(GrContext* ctx,
+ GrPathRendererChain::UsageFlags flags,
+ GrPathRendererChain* chain) {
+ if (!(GrPathRendererChain::kNonAAOnly_UsageFlag & flags)) {
+ if (GrPathRenderer* pr = GrAAHairLinePathRenderer::Create(ctx)) {
+ chain->addPathRenderer(pr)->unref();
+ }
+ }
+}
diff --git a/src/gpu/GrAddPathRenderers_none.cpp b/src/gpu/GrAddPathRenderers_none.cpp
new file mode 100644
index 0000000..46855db
--- /dev/null
+++ b/src/gpu/GrAddPathRenderers_none.cpp
@@ -0,0 +1,15 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrPathRenderer.h"
+
+
+void GrPathRenderer::AddPathRenderers(GrContext*,
+ GrPathRendererChain::UsageFlags,
+ GrPathRendererChain*) {}
diff --git a/src/gpu/GrAddPathRenderers_tesselated.cpp b/src/gpu/GrAddPathRenderers_tesselated.cpp
new file mode 100644
index 0000000..a1cde13
--- /dev/null
+++ b/src/gpu/GrAddPathRenderers_tesselated.cpp
@@ -0,0 +1,17 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrTesselatedPathRenderer.h"
+
+
+void GrPathRenderer::AddPathRenderers(GrContext*,
+ GrPathRendererChain::UsageFlags flags,
+ GrPathRendererChain* chain) {
+ chain->addPathRenderer(new GrTesselatedPathRenderer())->unref();
+}
diff --git a/gpu/src/GrAllocPool.cpp b/src/gpu/GrAllocPool.cpp
index f133f97..ecd2acf 100644
--- a/gpu/src/GrAllocPool.cpp
+++ b/src/gpu/GrAllocPool.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "GrAllocPool.h"
#define GrAllocPool_MIN_BLOCK_SIZE ((size_t)128)
diff --git a/gpu/include/GrAllocPool.h b/src/gpu/GrAllocPool.h
index 251c0b4..3ecc4aa 100644
--- a/gpu/include/GrAllocPool.h
+++ b/src/gpu/GrAllocPool.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrAllocPool_DEFINED
#define GrAllocPool_DEFINED
diff --git a/gpu/include/GrAllocator.h b/src/gpu/GrAllocator.h
index deed2dc..555e56f 100755
--- a/gpu/include/GrAllocator.h
+++ b/src/gpu/GrAllocator.h
@@ -1,29 +1,22 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrAllocator_DEFINED
#define GrAllocator_DEFINED
#include "GrConfig.h"
-#include "GrTArray.h"
+#include "SkTArray.h"
-class GrAllocator {
+class GrAllocator : GrNoncopyable {
public:
- virtual ~GrAllocator() {
+ ~GrAllocator() {
reset();
}
@@ -37,7 +30,6 @@ public:
* Caller is responsible for freeing this memory.
*/
GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock) :
- fBlocks(fBlockInitialStorage, NUM_INIT_BLOCK_PTRS),
fItemSize(itemSize),
fItemsPerBlock(itemsPerBlock),
fOwnFirstBlock(NULL == initialBlock),
@@ -53,7 +45,7 @@ public:
*
* @return pointer to the added item.
*/
- void* push_back() {
+ void* push_back() {
int indexInBlock = fCount % fItemsPerBlock;
// we always have at least one block
if (0 == indexInBlock) {
@@ -135,22 +127,21 @@ public:
private:
static const int NUM_INIT_BLOCK_PTRS = 8;
- GrTArray<void*> fBlocks;
- size_t fBlockSize;
- char fBlockInitialStorage[NUM_INIT_BLOCK_PTRS*sizeof(void*)];
- size_t fItemSize;
- int fItemsPerBlock;
- bool fOwnFirstBlock;
- int fCount;
+ SkSTArray<NUM_INIT_BLOCK_PTRS, void*> fBlocks;
+ size_t fBlockSize;
+ size_t fItemSize;
+ int fItemsPerBlock;
+ bool fOwnFirstBlock;
+ int fCount;
+
+ typedef GrNoncopyable INHERITED;
};
template <typename T>
-class GrTAllocator {
-private:
- GrAllocator fAllocator;
-
+class GrTAllocator : GrNoncopyable {
+
public:
- virtual ~GrTAllocator() {};
+ virtual ~GrTAllocator() { this->reset(); };
/**
* Create an allocator
@@ -160,20 +151,10 @@ public:
* Must be at least size(T)*itemsPerBlock sized.
* Caller is responsible for freeing this memory.
*/
- GrTAllocator(int itemsPerBlock, void* initialBlock)
- : fAllocator(sizeof(T), itemsPerBlock, initialBlock) {}
+ explicit GrTAllocator(int itemsPerBlock)
+ : fAllocator(sizeof(T), itemsPerBlock, NULL) {}
/**
- * Create an allocator using a GrAlignedTAlloc as the initial block.
- *
- * @param initialBlock specifies the storage for the initial block
- * and the size of subsequent blocks.
- */
- template <int N>
- GrTAllocator(GrAlignedSTStorage<N,T>* initialBlock)
- : fAllocator(sizeof(T), N, initialBlock->get()) {}
-
- /**
* Adds an item and returns it.
*
* @return the added item.
@@ -184,7 +165,14 @@ public:
new (item) T;
return *(T*)item;
}
-
+
+ T& push_back(const T& t) {
+ void* item = fAllocator.push_back();
+ GrAssert(NULL != item);
+ new (item) T(t);
+ return *(T*)item;
+ }
+
/**
* removes all added items
*/
@@ -234,7 +222,28 @@ public:
*/
const T& operator[] (int i) const {
return *(const T*)(fAllocator[i]);
- }
+ }
+
+protected:
+ GrTAllocator(int itemsPerBlock, void* initialBlock)
+ : fAllocator(sizeof(T), itemsPerBlock, initialBlock) {
+ }
+
+private:
+ GrAllocator fAllocator;
+ typedef GrNoncopyable INHERITED;
+};
+
+template <int N, typename T> class GrSTAllocator : public GrTAllocator<T> {
+private:
+ typedef GrTAllocator<T> INHERITED;
+
+public:
+ GrSTAllocator() : INHERITED(N, fStorage.get()) {
+ }
+
+private:
+ SkAlignedSTStorage<N, T> fStorage;
};
#endif
diff --git a/gpu/src/GrAtlas.cpp b/src/gpu/GrAtlas.cpp
index e577beb..17464ba 100644
--- a/gpu/src/GrAtlas.cpp
+++ b/src/gpu/GrAtlas.cpp
@@ -1,23 +1,16 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "GrAtlas.h"
+#include "GrContext.h"
#include "GrGpu.h"
-#include "GrMemory.h"
#include "GrRectanizer.h"
#include "GrPlotMgr.h"
@@ -63,7 +56,7 @@ GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY, GrMaskFormat format) {
fMaskFormat = format;
#if GR_DEBUG
- GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter);
+// GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter);
gCounter += 1;
#endif
}
@@ -75,7 +68,7 @@ GrAtlas::~GrAtlas() {
#if GR_DEBUG
--gCounter;
- GrPrintf("~GrAtlas %p [%d %d] %d\n", this, fPlot.fX, fPlot.fY, gCounter);
+// GrPrintf("~GrAtlas %p [%d %d] %d\n", this, fPlot.fX, fPlot.fY, gCounter);
#endif
}
@@ -97,13 +90,13 @@ bool GrAtlas::addSubImage(int width, int height, const void* image,
return false;
}
- GrAutoSMalloc<1024> storage;
+ SkAutoSMalloc<1024> storage;
int dstW = width + 2*BORDER;
int dstH = height + 2*BORDER;
if (BORDER) {
const int bpp = GrMaskFormatBytesPerPixel(fMaskFormat);
const size_t dstRB = dstW * bpp;
- uint8_t* dst = (uint8_t*)storage.realloc(dstH * dstRB);
+ uint8_t* dst = (uint8_t*)storage.reset(dstH * dstRB);
Gr_bzero(dst, dstRB); // zero top row
dst += dstRB;
for (int y = 0; y < height; y++) {
@@ -117,7 +110,14 @@ bool GrAtlas::addSubImage(int width, int height, const void* image,
image = storage.get();
}
adjustForPlot(loc, fPlot);
- fTexture->uploadTextureData(loc->fX, loc->fY, dstW, dstH, image);
+ GrContext* context = fTexture->getContext();
+ // We call the internal version so that we don't force a flush. We assume
+ // our caller is smart and hasn't referenced the part of the texture we're
+ // about to update since the last flush.
+ context->internalWriteTexturePixels(fTexture, loc->fX, loc->fY,
+ dstW, dstH, fTexture->config(),
+ image, 0,
+ GrContext::kDontFlush_PixelOpsFlag);
// now tell the caller to skip the top/left BORDER
loc->fX += BORDER;
@@ -148,6 +148,8 @@ static GrPixelConfig maskformat2pixelconfig(GrMaskFormat format) {
return kAlpha_8_GrPixelConfig;
case kA565_GrMaskFormat:
return kRGB_565_GrPixelConfig;
+ case kA888_GrMaskFormat:
+ return kSkia8888_PM_GrPixelConfig;
default:
GrAssert(!"unknown maskformat");
}
diff --git a/gpu/include/GrAtlas.h b/src/gpu/GrAtlas.h
index 406b45c..f0114e3 100644
--- a/gpu/include/GrAtlas.h
+++ b/src/gpu/GrAtlas.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrAtlas_DEFINED
#define GrAtlas_DEFINED
diff --git a/src/gpu/GrBinHashKey.h b/src/gpu/GrBinHashKey.h
new file mode 100644
index 0000000..028bb91
--- /dev/null
+++ b/src/gpu/GrBinHashKey.h
@@ -0,0 +1,95 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrBinHashKey_DEFINED
+#define GrBinHashKey_DEFINED
+
+#include "GrTypes.h"
+
+/**
+ * Hash function class that can take a data chunk of any predetermined
+ * length. The hash function used is the One-at-a-Time Hash
+ * (http://burtleburtle.net/bob/hash/doobs.html).
+ */
+template<typename Entry, size_t KeySize>
+class GrBinHashKey {
+public:
+ GrBinHashKey()
+ : fHash(0)
+#if GR_DEBUG
+ , fIsValid(false)
+#endif
+ {}
+
+ GrBinHashKey(const GrBinHashKey<Entry, KeySize>& other) {
+ *this = other;
+ }
+ GrBinHashKey<Entry, KeySize>& operator=(const GrBinHashKey<Entry,
+ KeySize>& other) {
+ memcpy(this, &other, sizeof(*this));
+ return *this;
+ }
+
+ ~GrBinHashKey() {
+ }
+
+ void setKeyData(const uint32_t* SK_RESTRICT data) {
+ GrAssert(GrIsALIGN4(KeySize));
+ memcpy(&fData, data, KeySize);
+
+ uint32_t hash = 0;
+ size_t len = KeySize;
+ while (len >= 4) {
+ hash += *data++;
+ hash += (fHash << 10);
+ hash ^= (hash >> 6);
+ len -= 4;
+ }
+ hash += (fHash << 3);
+ hash ^= (fHash >> 11);
+ hash += (fHash << 15);
+#if GR_DEBUG
+ fIsValid = true;
+#endif
+ fHash = hash;
+ }
+
+ int compare(const GrBinHashKey<Entry, KeySize>& key) const {
+ GrAssert(fIsValid && key.fIsValid);
+ return memcmp(fData, key.fData, KeySize);
+ }
+
+ static bool
+ EQ(const Entry& entry, const GrBinHashKey<Entry, KeySize>& key) {
+ GrAssert(key.fIsValid);
+ return 0 == entry.compare(key);
+ }
+
+ static bool
+ LT(const Entry& entry, const GrBinHashKey<Entry, KeySize>& key) {
+ GrAssert(key.fIsValid);
+ return entry.compare(key) < 0;
+ }
+
+ uint32_t getHash() const {
+ GrAssert(fIsValid);
+ return fHash;
+ }
+
+private:
+ uint32_t fHash;
+ uint8_t fData[KeySize]; //Buffer for key storage
+
+#if GR_DEBUG
+public:
+ bool fIsValid;
+#endif
+};
+
+#endif
diff --git a/gpu/src/GrBufferAllocPool.cpp b/src/gpu/GrBufferAllocPool.cpp
index d786b02..d029471 100644
--- a/gpu/src/GrBufferAllocPool.cpp
+++ b/src/gpu/GrBufferAllocPool.cpp
@@ -1,19 +1,12 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "GrBufferAllocPool.h"
#include "GrTypes.h"
#include "GrVertexBuffer.h"
@@ -23,9 +16,10 @@
#if GR_DEBUG
#define VALIDATE validate
#else
- #define VALIDATE()
+ static void VALIDATE(bool x = false) {}
#endif
+// page size
#define GrBufferAllocPool_MIN_BLOCK_SIZE ((size_t)1 << 12)
GrBufferAllocPool::GrBufferAllocPool(GrGpu* gpu,
@@ -45,6 +39,8 @@ GrBufferAllocPool::GrBufferAllocPool(GrGpu* gpu,
fBufferPtr = NULL;
fMinBlockSize = GrMax(GrBufferAllocPool_MIN_BLOCK_SIZE, blockSize);
+ fBytesInUse = 0;
+
fPreallocBuffersInUse = 0;
fFirstPreallocBuffer = 0;
for (int i = 0; i < preallocBufferCnt; ++i) {
@@ -80,6 +76,7 @@ void GrBufferAllocPool::releaseGpuRef() {
void GrBufferAllocPool::reset() {
VALIDATE();
+ fBytesInUse = 0;
if (fBlocks.count()) {
GrGeometryBuffer* buffer = fBlocks.back().fBuffer;
if (buffer->isLocked()) {
@@ -94,7 +91,9 @@ void GrBufferAllocPool::reset() {
fFirstPreallocBuffer = (fFirstPreallocBuffer + fPreallocBuffersInUse) %
fPreallocBuffers.count();
}
- fCpuData.realloc(fGpu->supportsBufferLocking() ? 0 : fMinBlockSize);
+ // we may have created a large cpu mirror of a large VB. Reset the size
+ // to match our pre-allocated VBs.
+ fCpuData.reset(fMinBlockSize);
GrAssert(0 == fPreallocBuffersInUse);
VALIDATE();
}
@@ -107,7 +106,7 @@ void GrBufferAllocPool::unlock() {
if (block.fBuffer->isLocked()) {
block.fBuffer->unlock();
} else {
- size_t flushSize = block.fBuffer->size() - block.fBytesFree;
+ size_t flushSize = block.fBuffer->sizeInBytes() - block.fBytesFree;
flushCpuData(fBlocks.back().fBuffer, flushSize);
}
fBufferPtr = NULL;
@@ -116,7 +115,7 @@ void GrBufferAllocPool::unlock() {
}
#if GR_DEBUG
-void GrBufferAllocPool::validate() const {
+void GrBufferAllocPool::validate(bool unusedBlockAllowed) const {
if (NULL != fBufferPtr) {
GrAssert(!fBlocks.empty());
if (fBlocks.back().fBuffer->isLocked()) {
@@ -124,14 +123,27 @@ void GrBufferAllocPool::validate() const {
GrAssert(buf->lockPtr() == fBufferPtr);
} else {
GrAssert(fCpuData.get() == fBufferPtr);
- GrAssert(fCpuData.size() == fBlocks.back().fBuffer->size());
}
} else {
GrAssert(fBlocks.empty() || !fBlocks.back().fBuffer->isLocked());
}
+ size_t bytesInUse = 0;
for (int i = 0; i < fBlocks.count() - 1; ++i) {
GrAssert(!fBlocks[i].fBuffer->isLocked());
}
+ for (int i = 0; i < fBlocks.count(); ++i) {
+ size_t bytes = fBlocks[i].fBuffer->sizeInBytes() - fBlocks[i].fBytesFree;
+ bytesInUse += bytes;
+ GrAssert(bytes || unusedBlockAllowed);
+ }
+
+ GrAssert(bytesInUse == fBytesInUse);
+ if (unusedBlockAllowed) {
+ GrAssert((fBytesInUse && !fBlocks.empty()) ||
+ (!fBytesInUse && (fBlocks.count() < 2)));
+ } else {
+ GrAssert((0 == fBytesInUse) == fBlocks.empty());
+ }
}
#endif
@@ -146,7 +158,7 @@ void* GrBufferAllocPool::makeSpace(size_t size,
if (NULL != fBufferPtr) {
BufferBlock& back = fBlocks.back();
- size_t usedBytes = back.fBuffer->size() - back.fBytesFree;
+ size_t usedBytes = back.fBuffer->sizeInBytes() - back.fBytesFree;
size_t pad = GrSizeAlignUpPad(usedBytes,
alignment);
if ((size + pad) <= back.fBytesFree) {
@@ -154,20 +166,30 @@ void* GrBufferAllocPool::makeSpace(size_t size,
*offset = usedBytes;
*buffer = back.fBuffer;
back.fBytesFree -= size + pad;
+ fBytesInUse += size;
return (void*)(reinterpret_cast<intptr_t>(fBufferPtr) + usedBytes);
}
}
+ // We could honor the space request using by a partial update of the current
+ // VB (if there is room). But we don't currently use draw calls to GL that
+ // allow the driver to know that previously issued draws won't read from
+ // the part of the buffer we update. Also, the GL buffer implementation
+ // may be cheating on the actual buffer size by shrinking the buffer on
+ // updateData() if the amount of data passed is less than the full buffer
+ // size.
+
if (!createBlock(size)) {
return NULL;
}
- VALIDATE();
GrAssert(NULL != fBufferPtr);
*offset = 0;
BufferBlock& back = fBlocks.back();
*buffer = back.fBuffer;
back.fBytesFree -= size;
+ fBytesInUse += size;
+ VALIDATE();
return fBufferPtr;
}
@@ -175,7 +197,7 @@ int GrBufferAllocPool::currentBufferItems(size_t itemSize) const {
VALIDATE();
if (NULL != fBufferPtr) {
const BufferBlock& back = fBlocks.back();
- size_t usedBytes = back.fBuffer->size() - back.fBytesFree;
+ size_t usedBytes = back.fBuffer->sizeInBytes() - back.fBytesFree;
size_t pad = GrSizeAlignUpPad(usedBytes, itemSize);
return (back.fBytesFree - pad) / itemSize;
} else if (fPreallocBuffersInUse < fPreallocBuffers.count()) {
@@ -194,29 +216,29 @@ int GrBufferAllocPool::preallocatedBufferCount() const {
void GrBufferAllocPool::putBack(size_t bytes) {
VALIDATE();
- if (NULL != fBufferPtr) {
- BufferBlock& back = fBlocks.back();
- size_t bytesUsed = back.fBuffer->size() - back.fBytesFree;
+
+ while (bytes) {
+ // caller shouldnt try to put back more than they've taken
+ GrAssert(!fBlocks.empty());
+ BufferBlock& block = fBlocks.back();
+ size_t bytesUsed = block.fBuffer->sizeInBytes() - block.fBytesFree;
if (bytes >= bytesUsed) {
- destroyBlock();
bytes -= bytesUsed;
+ fBytesInUse -= bytesUsed;
+ // if we locked a vb to satisfy the make space and we're releasing
+ // beyond it, then unlock it.
+ if (block.fBuffer->isLocked()) {
+ block.fBuffer->unlock();
+ }
+ this->destroyBlock();
} else {
- back.fBytesFree += bytes;
- return;
+ block.fBytesFree += bytes;
+ fBytesInUse -= bytes;
+ bytes = 0;
+ break;
}
}
VALIDATE();
- GrAssert(NULL == fBufferPtr);
- // we don't partially roll-back buffers because our VB semantics say locking
- // a VB discards its previous content.
- // We could honor it by being sure we use updateSubData and not lock
- // we will roll-back fully released buffers, though.
- while (!fBlocks.empty() &&
- bytes >= fBlocks.back().fBuffer->size()) {
- bytes -= fBlocks.back().fBuffer->size();
- destroyBlock();
- }
- VALIDATE();
}
bool GrBufferAllocPool::createBlock(size_t requestSize) {
@@ -252,24 +274,24 @@ bool GrBufferAllocPool::createBlock(size_t requestSize) {
prev.fBuffer->unlock();
} else {
flushCpuData(prev.fBuffer,
- prev.fBuffer->size() - prev.fBytesFree);
+ prev.fBuffer->sizeInBytes() - prev.fBytesFree);
}
fBufferPtr = NULL;
}
GrAssert(NULL == fBufferPtr);
- if (fGpu->supportsBufferLocking() &&
+ if (fGpu->getCaps().fBufferLockSupport &&
size > GR_GEOM_BUFFER_LOCK_THRESHOLD &&
(!fFrequentResetHint || requestSize > GR_GEOM_BUFFER_LOCK_THRESHOLD)) {
fBufferPtr = block.fBuffer->lock();
}
if (NULL == fBufferPtr) {
- fBufferPtr = fCpuData.realloc(size);
+ fBufferPtr = fCpuData.reset(size);
}
- VALIDATE();
+ VALIDATE(true);
return true;
}
@@ -298,17 +320,15 @@ void GrBufferAllocPool::flushCpuData(GrGeometryBuffer* buffer,
GrAssert(NULL != buffer);
GrAssert(!buffer->isLocked());
GrAssert(fCpuData.get() == fBufferPtr);
- GrAssert(fCpuData.size() == buffer->size());
- GrAssert(flushSize <= buffer->size());
+ GrAssert(flushSize <= buffer->sizeInBytes());
- bool updated = false;
- if (fGpu->supportsBufferLocking() &&
+ if (fGpu->getCaps().fBufferLockSupport &&
flushSize > GR_GEOM_BUFFER_LOCK_THRESHOLD) {
void* data = buffer->lock();
if (NULL != data) {
memcpy(data, fBufferPtr, flushSize);
buffer->unlock();
- updated = true;
+ return;
}
}
buffer->updateData(fBufferPtr, flushSize);
diff --git a/gpu/src/GrBufferAllocPool.h b/src/gpu/GrBufferAllocPool.h
index 7d70ebb..acf0289 100644
--- a/gpu/src/GrBufferAllocPool.h
+++ b/src/gpu/GrBufferAllocPool.h
@@ -1,27 +1,20 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrBufferAllocPool_DEFINED
#define GrBufferAllocPool_DEFINED
#include "GrNoncopyable.h"
#include "GrTDArray.h"
-#include "GrTArray.h"
-#include "GrMemory.h"
+
+#include "SkTArray.h"
class GrGeometryBuffer;
class GrGpu;
@@ -169,8 +162,10 @@ private:
void destroyBlock();
void flushCpuData(GrGeometryBuffer* buffer, size_t flushSize);
#if GR_DEBUG
- void validate() const;
+ void validate(bool unusedBlockAllowed = false) const;
#endif
+
+ size_t fBytesInUse;
GrGpu* fGpu;
bool fGpuIsReffed;
@@ -179,11 +174,11 @@ private:
size_t fMinBlockSize;
BufferType fBufferType;
- GrTArray<BufferBlock> fBlocks;
+ SkTArray<BufferBlock> fBlocks;
int fPreallocBuffersInUse;
int fFirstPreallocBuffer;
- GrAutoMalloc fCpuData;
- void* fBufferPtr;
+ SkAutoMalloc fCpuData;
+ void* fBufferPtr;
};
class GrVertexBuffer;
diff --git a/gpu/src/GrClip.cpp b/src/gpu/GrClip.cpp
index c2613bb..a02d9f4 100644
--- a/gpu/src/GrClip.cpp
+++ b/src/gpu/GrClip.cpp
@@ -1,46 +1,34 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "GrClip.h"
-GrClip::GrClip()
- : fList(&fListStorage) {
+GrClip::GrClip() {
fConservativeBounds.setEmpty();
fConservativeBoundsValid = true;
}
-GrClip::GrClip(const GrClip& src)
- : fList(&fListStorage) {
+GrClip::GrClip(const GrClip& src) {
*this = src;
}
-GrClip::GrClip(const GrIRect& rect)
- : fList(&fListStorage) {
+GrClip::GrClip(const GrIRect& rect) {
this->setFromIRect(rect);
}
-GrClip::GrClip(const GrRect& rect)
- : fList(&fListStorage) {
+GrClip::GrClip(const GrRect& rect) {
this->setFromRect(rect);
}
GrClip::GrClip(GrClipIterator* iter, GrScalar tx, GrScalar ty,
- const GrRect* bounds)
- : fList(&fListStorage) {
+ const GrRect* bounds) {
this->setFromIterator(iter, tx, ty, bounds);
}
@@ -68,6 +56,7 @@ void GrClip::setFromRect(const GrRect& r) {
fList.push_back();
fList.back().fRect = r;
fList.back().fType = kRect_ClipType;
+ fList.back().fOp = kReplace_SetOp;
fConservativeBounds = r;
fConservativeBoundsValid = true;
}
@@ -82,6 +71,7 @@ void GrClip::setFromIRect(const GrIRect& r) {
fList.push_back();
fList.back().fRect.set(r);
fList.back().fType = kRect_ClipType;
+ fList.back().fOp = kReplace_SetOp;
fConservativeBounds.set(r);
fConservativeBoundsValid = true;
}
@@ -117,7 +107,7 @@ void GrClip::setFromIterator(GrClipIterator* iter, GrScalar tx, GrScalar ty,
}
++rectCount;
if (isectRectValid) {
- if (1 == rectCount || kIntersect_SetOp == e.fOp) {
+ if (kIntersect_SetOp == e.fOp) {
GrAssert(fList.count() <= 2);
if (fList.count() > 1) {
GrAssert(2 == rectCount);
@@ -145,13 +135,9 @@ void GrClip::setFromIterator(GrClipIterator* iter, GrScalar tx, GrScalar ty,
}
}
fConservativeBoundsValid = false;
- if (isectRectValid) {
+ if (isectRectValid && rectCount) {
+ fConservativeBounds = fList[0].fRect;
fConservativeBoundsValid = true;
- if (rectCount > 0) {
- fConservativeBounds = fList[0].fRect;
- } else {
- fConservativeBounds.setEmpty();
- }
} else if (NULL != conservativeBounds) {
fConservativeBounds = *conservativeBounds;
fConservativeBoundsValid = true;
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
new file mode 100644
index 0000000..1767f06
--- /dev/null
+++ b/src/gpu/GrContext.cpp
@@ -0,0 +1,2120 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrContext.h"
+
+#include "GrBufferAllocPool.h"
+#include "GrClipIterator.h"
+#include "GrGpu.h"
+#include "GrIndexBuffer.h"
+#include "GrInOrderDrawBuffer.h"
+#include "GrPathRenderer.h"
+#include "GrPathUtils.h"
+#include "GrResourceCache.h"
+#include "GrStencilBuffer.h"
+#include "GrTextStrike.h"
+#include "SkTLazy.h"
+#include "SkTrace.h"
+
+// Using MSAA seems to be slower for some yet unknown reason.
+#define PREFER_MSAA_OFFSCREEN_AA 0
+#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
+
+#define DEFER_TEXT_RENDERING 1
+
+#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
+
+// When we're using coverage AA but the blend is incompatible (given gpu
+// limitations) should we disable AA or draw wrong?
+#define DISABLE_COVERAGE_AA_FOR_BLEND 1
+
+static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
+static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
+
+static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
+static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
+
+// We are currently only batching Text and drawRectToRect, both
+// of which use the quad index buffer.
+static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
+static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
+
+#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
+
+GrContext* GrContext::Create(GrEngine engine,
+ GrPlatform3DContext context3D) {
+ GrContext* ctx = NULL;
+ GrGpu* fGpu = GrGpu::Create(engine, context3D);
+ if (NULL != fGpu) {
+ ctx = new GrContext(fGpu);
+ fGpu->unref();
+ }
+ return ctx;
+}
+
+GrContext::~GrContext() {
+ this->flush();
+ delete fTextureCache;
+ delete fFontCache;
+ delete fDrawBuffer;
+ delete fDrawBufferVBAllocPool;
+ delete fDrawBufferIBAllocPool;
+
+ GrSafeUnref(fAAFillRectIndexBuffer);
+ GrSafeUnref(fAAStrokeRectIndexBuffer);
+ fGpu->unref();
+ GrSafeUnref(fPathRendererChain);
+}
+
+void GrContext::contextLost() {
+ contextDestroyed();
+ this->setupDrawBuffer();
+}
+
+void GrContext::contextDestroyed() {
+ // abandon first to so destructors
+ // don't try to free the resources in the API.
+ fGpu->abandonResources();
+
+ // a path renderer may be holding onto resources that
+ // are now unusable
+ GrSafeSetNull(fPathRendererChain);
+
+ delete fDrawBuffer;
+ fDrawBuffer = NULL;
+
+ delete fDrawBufferVBAllocPool;
+ fDrawBufferVBAllocPool = NULL;
+
+ delete fDrawBufferIBAllocPool;
+ fDrawBufferIBAllocPool = NULL;
+
+ GrSafeSetNull(fAAFillRectIndexBuffer);
+ GrSafeSetNull(fAAStrokeRectIndexBuffer);
+
+ fTextureCache->removeAll();
+ fFontCache->freeAll();
+ fGpu->markContextDirty();
+}
+
+void GrContext::resetContext() {
+ fGpu->markContextDirty();
+}
+
+void GrContext::freeGpuResources() {
+ this->flush();
+ fTextureCache->removeAll();
+ fFontCache->freeAll();
+ // a path renderer may be holding onto resources
+ GrSafeSetNull(fPathRendererChain);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+int GrContext::PaintStageVertexLayoutBits(
+ const GrPaint& paint,
+ const bool hasTexCoords[GrPaint::kTotalStages]) {
+ int stageMask = paint.getActiveStageMask();
+ int layout = 0;
+ for (int i = 0; i < GrPaint::kTotalStages; ++i) {
+ if ((1 << i) & stageMask) {
+ if (NULL != hasTexCoords && hasTexCoords[i]) {
+ layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
+ } else {
+ layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
+ }
+ }
+ }
+ return layout;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+enum {
+ // flags for textures
+ kNPOTBit = 0x1,
+ kFilterBit = 0x2,
+ kScratchBit = 0x4,
+
+ // resource type
+ kTextureBit = 0x8,
+ kStencilBufferBit = 0x10
+};
+
+GrTexture* GrContext::TextureCacheEntry::texture() const {
+ if (NULL == fEntry) {
+ return NULL;
+ } else {
+ return (GrTexture*) fEntry->resource();
+ }
+}
+
+namespace {
+// returns true if this is a "special" texture because of gpu NPOT limitations
+bool gen_texture_key_values(const GrGpu* gpu,
+ const GrSamplerState* sampler,
+ GrContext::TextureKey clientKey,
+ int width,
+ int height,
+ bool scratch,
+ uint32_t v[4]) {
+ GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
+ // we assume we only need 16 bits of width and height
+ // assert that texture creation will fail anyway if this assumption
+ // would cause key collisions.
+ GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
+ v[0] = clientKey & 0xffffffffUL;
+ v[1] = (clientKey >> 32) & 0xffffffffUL;
+ v[2] = width | (height << 16);
+
+ v[3] = 0;
+ if (!gpu->getCaps().fNPOTTextureTileSupport) {
+ bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
+
+ bool tiled = NULL != sampler &&
+ ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
+ (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
+
+ if (tiled && !isPow2) {
+ v[3] |= kNPOTBit;
+ if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
+ v[3] |= kFilterBit;
+ }
+ }
+ }
+
+ if (scratch) {
+ v[3] |= kScratchBit;
+ }
+
+ v[3] |= kTextureBit;
+
+ return v[3] & kNPOTBit;
+}
+
+// we should never have more than one stencil buffer with same combo of
+// (width,height,samplecount)
+void gen_stencil_key_values(int width, int height,
+ int sampleCnt, uint32_t v[4]) {
+ v[0] = width;
+ v[1] = height;
+ v[2] = sampleCnt;
+ v[3] = kStencilBufferBit;
+}
+
+void gen_stencil_key_values(const GrStencilBuffer* sb,
+ uint32_t v[4]) {
+ gen_stencil_key_values(sb->width(), sb->height(),
+ sb->numSamples(), v);
+}
+
+// This should be subsumed by a future version of GrDrawState
+// It does not reset stage textures/samplers or per-vertex-edge-aa state since
+// they aren't used unless the vertex layout references them.
+// It also doesn't set the render target.
+void reset_draw_state(GrDrawState* drawState){
+
+ drawState->setViewMatrix(GrMatrix::I());
+ drawState->setColorFilter(0, SkXfermode::kDst_Mode);
+ drawState->resetStateFlags();
+ drawState->setEdgeAAData(NULL, 0);
+ drawState->disableStencil();
+ drawState->setAlpha(0xFF);
+ drawState->setBlendFunc(kOne_BlendCoeff,
+ kZero_BlendCoeff);
+ drawState->setFirstCoverageStage(GrDrawState::kNumStages);
+ drawState->setDrawFace(GrDrawState::kBoth_DrawFace);
+}
+}
+
+GrContext::TextureCacheEntry GrContext::findAndLockTexture(
+ TextureKey key,
+ int width,
+ int height,
+ const GrSamplerState* sampler) {
+ uint32_t v[4];
+ gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
+ GrResourceKey resourceKey(v);
+ return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
+ GrResourceCache::kNested_LockType));
+}
+
+bool GrContext::isTextureInCache(TextureKey key,
+ int width,
+ int height,
+ const GrSamplerState* sampler) const {
+ uint32_t v[4];
+ gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
+ GrResourceKey resourceKey(v);
+ return fTextureCache->hasKey(resourceKey);
+}
+
+GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
+ ASSERT_OWNED_RESOURCE(sb);
+ uint32_t v[4];
+ gen_stencil_key_values(sb, v);
+ GrResourceKey resourceKey(v);
+ return fTextureCache->createAndLock(resourceKey, sb);
+}
+
+GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
+ int sampleCnt) {
+ uint32_t v[4];
+ gen_stencil_key_values(width, height, sampleCnt, v);
+ GrResourceKey resourceKey(v);
+ GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
+ GrResourceCache::kSingle_LockType);
+ if (NULL != entry) {
+ GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
+ return sb;
+ } else {
+ return NULL;
+ }
+}
+
+void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
+ ASSERT_OWNED_RESOURCE(sbEntry->resource());
+ fTextureCache->unlock(sbEntry);
+}
+
+static void stretchImage(void* dst,
+ int dstW,
+ int dstH,
+ void* src,
+ int srcW,
+ int srcH,
+ int bpp) {
+ GrFixed dx = (srcW << 16) / dstW;
+ GrFixed dy = (srcH << 16) / dstH;
+
+ GrFixed y = dy >> 1;
+
+ int dstXLimit = dstW*bpp;
+ for (int j = 0; j < dstH; ++j) {
+ GrFixed x = dx >> 1;
+ void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
+ void* dstRow = (uint8_t*)dst + j*dstW*bpp;
+ for (int i = 0; i < dstXLimit; i += bpp) {
+ memcpy((uint8_t*) dstRow + i,
+ (uint8_t*) srcRow + (x>>16)*bpp,
+ bpp);
+ x += dx;
+ }
+ y += dy;
+ }
+}
+
+GrContext::TextureCacheEntry GrContext::createAndLockTexture(
+ TextureKey key,
+ const GrSamplerState* sampler,
+ const GrTextureDesc& desc,
+ void* srcData,
+ size_t rowBytes) {
+ SK_TRACE_EVENT0("GrContext::createAndLockTexture");
+
+#if GR_DUMP_TEXTURE_UPLOAD
+ GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
+#endif
+
+ TextureCacheEntry entry;
+ uint32_t v[4];
+ bool special = gen_texture_key_values(fGpu, sampler, key,
+ desc.fWidth, desc.fHeight, false, v);
+ GrResourceKey resourceKey(v);
+
+ if (special) {
+ GrAssert(NULL != sampler);
+ TextureCacheEntry clampEntry = this->findAndLockTexture(key,
+ desc.fWidth,
+ desc.fHeight,
+ NULL);
+
+ if (NULL == clampEntry.texture()) {
+ clampEntry = this->createAndLockTexture(key, NULL, desc,
+ srcData, rowBytes);
+ GrAssert(NULL != clampEntry.texture());
+ if (NULL == clampEntry.texture()) {
+ return entry;
+ }
+ }
+ GrTextureDesc rtDesc = desc;
+ rtDesc.fFlags = rtDesc.fFlags |
+ kRenderTarget_GrTextureFlagBit |
+ kNoStencil_GrTextureFlagBit;
+ rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
+ rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
+
+ GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
+
+ if (NULL != texture) {
+ GrDrawTarget::AutoStateRestore asr(fGpu);
+ GrDrawState* drawState = fGpu->drawState();
+ reset_draw_state(drawState);
+ drawState->setRenderTarget(texture->asRenderTarget());
+ drawState->setTexture(0, clampEntry.texture());
+
+ GrSamplerState::Filter filter;
+ // if filtering is not desired then we want to ensure all
+ // texels in the resampled image are copies of texels from
+ // the original.
+ if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
+ filter = GrSamplerState::kNearest_Filter;
+ } else {
+ filter = GrSamplerState::kBilinear_Filter;
+ }
+ drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
+ filter);
+
+ static const GrVertexLayout layout =
+ GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
+ GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
+
+ if (arg.succeeded()) {
+ GrPoint* verts = (GrPoint*) arg.vertices();
+ verts[0].setIRectFan(0, 0,
+ texture->width(),
+ texture->height(),
+ 2*sizeof(GrPoint));
+ verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
+ fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
+ 0, 4);
+ entry.set(fTextureCache->createAndLock(resourceKey, texture));
+ }
+ texture->releaseRenderTarget();
+ } else {
+ // TODO: Our CPU stretch doesn't filter. But we create separate
+ // stretched textures when the sampler state is either filtered or
+ // not. Either implement filtered stretch blit on CPU or just create
+ // one when FBO case fails.
+
+ rtDesc.fFlags = kNone_GrTextureFlags;
+ // no longer need to clamp at min RT size.
+ rtDesc.fWidth = GrNextPow2(desc.fWidth);
+ rtDesc.fHeight = GrNextPow2(desc.fHeight);
+ int bpp = GrBytesPerPixel(desc.fConfig);
+ SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
+ rtDesc.fWidth *
+ rtDesc.fHeight);
+ stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
+ srcData, desc.fWidth, desc.fHeight, bpp);
+
+ size_t stretchedRowBytes = rtDesc.fWidth * bpp;
+
+ GrTexture* texture = fGpu->createTexture(rtDesc,
+ stretchedPixels.get(),
+ stretchedRowBytes);
+ GrAssert(NULL != texture);
+ entry.set(fTextureCache->createAndLock(resourceKey, texture));
+ }
+ fTextureCache->unlock(clampEntry.cacheEntry());
+
+ } else {
+ GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
+ if (NULL != texture) {
+ entry.set(fTextureCache->createAndLock(resourceKey, texture));
+ }
+ }
+ return entry;
+}
+
+namespace {
+inline void gen_scratch_tex_key_values(const GrGpu* gpu,
+ const GrTextureDesc& desc,
+ uint32_t v[4]) {
+ // Instead of a client-provided key of the texture contents
+ // we create a key of from the descriptor.
+ GrContext::TextureKey descKey = desc.fAALevel |
+ (desc.fFlags << 8) |
+ ((uint64_t) desc.fConfig << 32);
+ // this code path isn't friendly to tiling with NPOT restricitons
+ // We just pass ClampNoFilter()
+ gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
+ desc.fHeight, true, v);
+}
+}
+
+GrContext::TextureCacheEntry GrContext::lockScratchTexture(
+ const GrTextureDesc& inDesc,
+ ScratchTexMatch match) {
+
+ GrTextureDesc desc = inDesc;
+ if (kExact_ScratchTexMatch != match) {
+ // bin by pow2 with a reasonable min
+ static const int MIN_SIZE = 256;
+ desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
+ desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
+ }
+
+ uint32_t p0 = desc.fConfig;
+ uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
+
+ GrResourceEntry* entry;
+ int origWidth = desc.fWidth;
+ int origHeight = desc.fHeight;
+ bool doubledW = false;
+ bool doubledH = false;
+
+ do {
+ uint32_t v[4];
+ gen_scratch_tex_key_values(fGpu, desc, v);
+ GrResourceKey key(v);
+ entry = fTextureCache->findAndLock(key,
+ GrResourceCache::kNested_LockType);
+ // if we miss, relax the fit of the flags...
+ // then try doubling width... then height.
+ if (NULL != entry || kExact_ScratchTexMatch == match) {
+ break;
+ }
+ if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
+ desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
+ } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
+ desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
+ } else if (!doubledW) {
+ desc.fFlags = inDesc.fFlags;
+ desc.fWidth *= 2;
+ doubledW = true;
+ } else if (!doubledH) {
+ desc.fFlags = inDesc.fFlags;
+ desc.fWidth = origWidth;
+ desc.fHeight *= 2;
+ doubledH = true;
+ } else {
+ break;
+ }
+
+ } while (true);
+
+ if (NULL == entry) {
+ desc.fFlags = inDesc.fFlags;
+ desc.fWidth = origWidth;
+ desc.fHeight = origHeight;
+ GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
+ if (NULL != texture) {
+ uint32_t v[4];
+ gen_scratch_tex_key_values(fGpu, desc, v);
+ GrResourceKey key(v);
+ entry = fTextureCache->createAndLock(key, texture);
+ }
+ }
+
+ // If the caller gives us the same desc/sampler twice we don't want
+ // to return the same texture the second time (unless it was previously
+ // released). So we detach the entry from the cache and reattach at release.
+ if (NULL != entry) {
+ fTextureCache->detach(entry);
+ }
+ return TextureCacheEntry(entry);
+}
+
+void GrContext::unlockTexture(TextureCacheEntry entry) {
+ ASSERT_OWNED_RESOURCE(entry.texture());
+ // If this is a scratch texture we detached it from the cache
+ // while it was locked (to avoid two callers simultaneously getting
+ // the same texture).
+ if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
+ fTextureCache->reattachAndUnlock(entry.cacheEntry());
+ } else {
+ fTextureCache->unlock(entry.cacheEntry());
+ }
+}
+
+GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
+ void* srcData,
+ size_t rowBytes) {
+ return fGpu->createTexture(desc, srcData, rowBytes);
+}
+
+void GrContext::getTextureCacheLimits(int* maxTextures,
+ size_t* maxTextureBytes) const {
+ fTextureCache->getLimits(maxTextures, maxTextureBytes);
+}
+
+void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
+ fTextureCache->setLimits(maxTextures, maxTextureBytes);
+}
+
+int GrContext::getMaxTextureSize() const {
+ return fGpu->getCaps().fMaxTextureSize;
+}
+
+int GrContext::getMaxRenderTargetSize() const {
+ return fGpu->getCaps().fMaxRenderTargetSize;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
+ return fGpu->createPlatformTexture(desc);
+}
+
+GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
+ return fGpu->createPlatformRenderTarget(desc);
+}
+
+GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
+ // validate flags here so that GrGpu subclasses don't have to check
+ if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
+ 0 != desc.fRenderTargetFlags) {
+ return NULL;
+ }
+ if (desc.fSampleCnt &&
+ (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
+ return NULL;
+ }
+ if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
+ desc.fSampleCnt &&
+ !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
+ return NULL;
+ }
+ return fGpu->createPlatformSurface(desc);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
+ int width, int height) const {
+ const GrDrawTarget::Caps& caps = fGpu->getCaps();
+ if (!caps.f8BitPaletteSupport) {
+ return false;
+ }
+
+ bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
+
+ if (!isPow2) {
+ bool tiled = NULL != sampler &&
+ (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
+ sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
+ if (tiled && !caps.fNPOTTextureTileSupport) {
+ return false;
+ }
+ }
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
+
+void GrContext::setClip(const GrClip& clip) {
+ fGpu->setClip(clip);
+ fGpu->drawState()->enableState(GrDrawState::kClip_StateBit);
+}
+
+void GrContext::setClip(const GrIRect& rect) {
+ GrClip clip;
+ clip.setFromIRect(rect);
+ fGpu->setClip(clip);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrContext::clear(const GrIRect* rect, const GrColor color) {
+ this->flush();
+ fGpu->clear(rect, color);
+}
+
+void GrContext::drawPaint(const GrPaint& paint) {
+ // set rect to be big enough to fill the space, but not super-huge, so we
+ // don't overflow fixed-point implementations
+ GrRect r;
+ r.setLTRB(0, 0,
+ GrIntToScalar(getRenderTarget()->width()),
+ GrIntToScalar(getRenderTarget()->height()));
+ GrMatrix inverse;
+ SkTLazy<GrPaint> tmpPaint;
+ const GrPaint* p = &paint;
+ GrDrawState* drawState = fGpu->drawState();
+ GrAutoMatrix am;
+
+ // We attempt to map r by the inverse matrix and draw that. mapRect will
+ // map the four corners and bound them with a new rect. This will not
+ // produce a correct result for some perspective matrices.
+ if (!this->getMatrix().hasPerspective()) {
+ if (!drawState->getViewInverse(&inverse)) {
+ GrPrintf("Could not invert matrix");
+ return;
+ }
+ inverse.mapRect(&r);
+ } else {
+ if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
+ if (!drawState->getViewInverse(&inverse)) {
+ GrPrintf("Could not invert matrix");
+ return;
+ }
+ tmpPaint.set(paint);
+ tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
+ p = tmpPaint.get();
+ }
+ am.set(this, GrMatrix::I());
+ }
+ // by definition this fills the entire clip, no need for AA
+ if (paint.fAntiAlias) {
+ if (!tmpPaint.isValid()) {
+ tmpPaint.set(paint);
+ p = tmpPaint.get();
+ }
+ GrAssert(p == tmpPaint.get());
+ tmpPaint.get()->fAntiAlias = false;
+ }
+ this->drawRect(*p, r);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace {
+inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
+ return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
+}
+}
+
+struct GrContext::OffscreenRecord {
+ enum Downsample {
+ k4x4SinglePass_Downsample,
+ kFSAA_Downsample
+ } fDownsample;
+ int fTileSizeX;
+ int fTileSizeY;
+ int fTileCountX;
+ int fTileCountY;
+ int fScale;
+ GrAutoScratchTexture fOffscreen;
+ GrDrawTarget::SavedDrawState fSavedState;
+ GrClip fClip;
+};
+
+bool GrContext::doOffscreenAA(GrDrawTarget* target,
+ bool isHairLines) const {
+#if !GR_USE_OFFSCREEN_AA
+ return false;
+#else
+ // Line primitves are always rasterized as 1 pixel wide.
+ // Super-sampling would make them too thin but MSAA would be OK.
+ if (isHairLines &&
+ (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
+ return false;
+ }
+ if (target->getDrawState().getRenderTarget()->isMultisampled()) {
+ return false;
+ }
+ if (disable_coverage_aa_for_blend(target)) {
+#if GR_DEBUG
+ //GrPrintf("Turning off AA to correctly apply blend.\n");
+#endif
+ return false;
+ }
+ return true;
+#endif
+}
+
+bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
+ bool requireStencil,
+ const GrIRect& boundRect,
+ GrPathRenderer* pr,
+ OffscreenRecord* record) {
+
+ GrAssert(GR_USE_OFFSCREEN_AA);
+
+ GrAssert(NULL == record->fOffscreen.texture());
+ GrAssert(!boundRect.isEmpty());
+
+ int boundW = boundRect.width();
+ int boundH = boundRect.height();
+
+ GrTextureDesc desc;
+
+ desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
+ desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
+
+ if (requireStencil) {
+ desc.fFlags = kRenderTarget_GrTextureFlagBit;
+ } else {
+ desc.fFlags = kRenderTarget_GrTextureFlagBit |
+ kNoStencil_GrTextureFlagBit;
+ }
+
+ desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
+
+ if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
+ record->fDownsample = OffscreenRecord::kFSAA_Downsample;
+ record->fScale = 1;
+ desc.fAALevel = kMed_GrAALevel;
+ } else {
+ record->fDownsample = OffscreenRecord::k4x4SinglePass_Downsample;
+ record->fScale = OFFSCREEN_SSAA_SCALE;
+ // both downsample paths assume this
+ GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
+ desc.fAALevel = kNone_GrAALevel;
+ }
+
+ desc.fWidth *= record->fScale;
+ desc.fHeight *= record->fScale;
+ record->fOffscreen.set(this, desc);
+ if (NULL == record->fOffscreen.texture()) {
+ return false;
+ }
+ // the approximate lookup might have given us some slop space, might as well
+ // use it when computing the tiles size.
+ // these are scale values, will adjust after considering
+ // the possible second offscreen.
+ record->fTileSizeX = record->fOffscreen.texture()->width();
+ record->fTileSizeY = record->fOffscreen.texture()->height();
+
+ record->fTileSizeX /= record->fScale;
+ record->fTileSizeY /= record->fScale;
+
+ record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
+ record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
+
+ record->fClip = target->getClip();
+
+ target->saveCurrentDrawState(&record->fSavedState);
+ return true;
+}
+
+void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
+ const GrIRect& boundRect,
+ int tileX, int tileY,
+ OffscreenRecord* record) {
+
+ GrRenderTarget* offRT = record->fOffscreen.texture()->asRenderTarget();
+ GrAssert(NULL != offRT);
+
+ GrPaint tempPaint;
+ tempPaint.reset();
+ this->setPaint(tempPaint, target);
+ GrDrawState* drawState = target->drawState();
+ drawState->setRenderTarget(offRT);
+#if PREFER_MSAA_OFFSCREEN_AA
+ drawState->enableState(GrDrawState::kHWAntialias_StateBit);
+#endif
+
+ GrMatrix transM;
+ int left = boundRect.fLeft + tileX * record->fTileSizeX;
+ int top = boundRect.fTop + tileY * record->fTileSizeY;
+ transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
+ drawState->viewMatrix()->postConcat(transM);
+ GrMatrix scaleM;
+ scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
+ drawState->viewMatrix()->postConcat(scaleM);
+
+ int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
+ record->fTileSizeX;
+ int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
+ record->fTileSizeY;
+ GrIRect clear = SkIRect::MakeWH(record->fScale * w,
+ record->fScale * h);
+ target->setClip(GrClip(clear));
+#if 0
+ // visualize tile boundaries by setting edges of offscreen to white
+ // and interior to tranparent. black.
+ target->clear(&clear, 0xffffffff);
+
+ static const int gOffset = 2;
+ GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
+ record->fScale * w - gOffset,
+ record->fScale * h - gOffset);
+ target->clear(&clear2, 0x0);
+#else
+ target->clear(&clear, 0x0);
+#endif
+}
+
+void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
+ const GrPaint& paint,
+ const GrIRect& boundRect,
+ int tileX, int tileY,
+ OffscreenRecord* record) {
+ SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
+ GrAssert(NULL != record->fOffscreen.texture());
+ GrDrawTarget::AutoGeometryPush agp(target);
+ GrIRect tileRect;
+ tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
+ tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
+ tileRect.fRight = (tileX == record->fTileCountX-1) ?
+ boundRect.fRight :
+ tileRect.fLeft + record->fTileSizeX;
+ tileRect.fBottom = (tileY == record->fTileCountY-1) ?
+ boundRect.fBottom :
+ tileRect.fTop + record->fTileSizeY;
+
+ GrSamplerState::Filter filter;
+ if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
+ filter = GrSamplerState::k4x4Downsample_Filter;
+ } else {
+ filter = GrSamplerState::kBilinear_Filter;
+ }
+
+ GrTexture* src = record->fOffscreen.texture();
+ int scale;
+
+ enum {
+ kOffscreenStage = GrPaint::kTotalStages,
+ };
+
+ GrDrawState* drawState = target->drawState();
+
+ if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
+ scale = 1;
+ GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
+ src->asRenderTarget()->overrideResolveRect(rect);
+ } else {
+ GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
+ record->fDownsample);
+ scale = 4;
+ }
+
+ // setup for draw back to main RT, we use the original
+ // draw state setup by the caller plus an additional coverage
+ // stage to handle the AA resolve. Also, we use an identity
+ // view matrix and so pre-concat sampler matrices with view inv.
+ int stageMask = paint.getActiveStageMask();
+
+ target->restoreDrawState(record->fSavedState);
+ target->setClip(record->fClip);
+
+ if (stageMask) {
+ GrMatrix invVM;
+ if (drawState->getViewInverse(&invVM)) {
+ drawState->preConcatSamplerMatrices(stageMask, invVM);
+ }
+ }
+ // This is important when tiling, otherwise second tile's
+ // pass 1 view matrix will be incorrect.
+ GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I());
+
+ drawState->setTexture(kOffscreenStage, src);
+ GrSamplerState* sampler = drawState->sampler(kOffscreenStage);
+ sampler->reset(GrSamplerState::kClamp_WrapMode, filter);
+ sampler->matrix()->setScale(scale * GR_Scalar1 / src->width(),
+ scale * GR_Scalar1 / src->height());
+ sampler->matrix()->preTranslate(SkIntToScalar(-tileRect.fLeft),
+ SkIntToScalar(-tileRect.fTop));
+
+ GrRect dstRect;
+ int stages = (1 << kOffscreenStage) | stageMask;
+ dstRect.set(tileRect);
+ target->drawSimpleRect(dstRect, NULL, stages);
+}
+
+void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
+ GrPathRenderer* pr,
+ OffscreenRecord* record) {
+ target->restoreDrawState(record->fSavedState);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+/* create a triangle strip that strokes the specified triangle. There are 8
+ unique vertices, but we repreat the last 2 to close up. Alternatively we
+ could use an indices array, and then only send 8 verts, but not sure that
+ would be faster.
+ */
+static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
+ GrScalar width) {
+ const GrScalar rad = GrScalarHalf(width);
+ rect.sort();
+
+ verts[0].set(rect.fLeft + rad, rect.fTop + rad);
+ verts[1].set(rect.fLeft - rad, rect.fTop - rad);
+ verts[2].set(rect.fRight - rad, rect.fTop + rad);
+ verts[3].set(rect.fRight + rad, rect.fTop - rad);
+ verts[4].set(rect.fRight - rad, rect.fBottom - rad);
+ verts[5].set(rect.fRight + rad, rect.fBottom + rad);
+ verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
+ verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
+ verts[8] = verts[0];
+ verts[9] = verts[1];
+}
+
+static void setInsetFan(GrPoint* pts, size_t stride,
+ const GrRect& r, GrScalar dx, GrScalar dy) {
+ pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
+}
+
+static const uint16_t gFillAARectIdx[] = {
+ 0, 1, 5, 5, 4, 0,
+ 1, 2, 6, 6, 5, 1,
+ 2, 3, 7, 7, 6, 2,
+ 3, 0, 4, 4, 7, 3,
+ 4, 5, 6, 6, 7, 4,
+};
+
+int GrContext::aaFillRectIndexCount() const {
+ return GR_ARRAY_COUNT(gFillAARectIdx);
+}
+
+GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
+ if (NULL == fAAFillRectIndexBuffer) {
+ fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
+ false);
+ if (NULL != fAAFillRectIndexBuffer) {
+ #if GR_DEBUG
+ bool updated =
+ #endif
+ fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
+ sizeof(gFillAARectIdx));
+ GR_DEBUGASSERT(updated);
+ }
+ }
+ return fAAFillRectIndexBuffer;
+}
+
+static const uint16_t gStrokeAARectIdx[] = {
+ 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
+ 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
+ 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
+ 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
+
+ 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
+ 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
+ 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
+ 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
+
+ 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
+ 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
+ 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
+ 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
+};
+
+int GrContext::aaStrokeRectIndexCount() const {
+ return GR_ARRAY_COUNT(gStrokeAARectIdx);
+}
+
+GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
+ if (NULL == fAAStrokeRectIndexBuffer) {
+ fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
+ false);
+ if (NULL != fAAStrokeRectIndexBuffer) {
+ #if GR_DEBUG
+ bool updated =
+ #endif
+ fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
+ sizeof(gStrokeAARectIdx));
+ GR_DEBUGASSERT(updated);
+ }
+ }
+ return fAAStrokeRectIndexBuffer;
+}
+
+static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
+ bool useCoverage) {
+ GrVertexLayout layout = 0;
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ if (NULL != target->getDrawState().getTexture(s)) {
+ layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
+ }
+ }
+ if (useCoverage) {
+ layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
+ } else {
+ layout |= GrDrawTarget::kColor_VertexLayoutBit;
+ }
+ return layout;
+}
+
+void GrContext::fillAARect(GrDrawTarget* target,
+ const GrRect& devRect,
+ bool useVertexCoverage) {
+ GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
+
+ size_t vsize = GrDrawTarget::VertexSize(layout);
+
+ GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
+ if (!geo.succeeded()) {
+ GrPrintf("Failed to get space for vertices!\n");
+ return;
+ }
+ GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
+ if (NULL == indexBuffer) {
+ GrPrintf("Failed to create index buffer!\n");
+ return;
+ }
+
+ intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
+
+ GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
+ GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
+
+ setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
+ setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
+
+ verts += sizeof(GrPoint);
+ for (int i = 0; i < 4; ++i) {
+ *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
+ }
+
+ GrColor innerColor;
+ if (useVertexCoverage) {
+ innerColor = 0xffffffff;
+ } else {
+ innerColor = target->getDrawState().getColor();
+ }
+
+ verts += 4 * vsize;
+ for (int i = 0; i < 4; ++i) {
+ *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
+ }
+
+ target->setIndexSourceToBuffer(indexBuffer);
+
+ target->drawIndexed(kTriangles_PrimitiveType, 0,
+ 0, 8, this->aaFillRectIndexCount());
+}
+
+void GrContext::strokeAARect(GrDrawTarget* target,
+ const GrRect& devRect,
+ const GrVec& devStrokeSize,
+ bool useVertexCoverage) {
+ const GrScalar& dx = devStrokeSize.fX;
+ const GrScalar& dy = devStrokeSize.fY;
+ const GrScalar rx = GrMul(dx, GR_ScalarHalf);
+ const GrScalar ry = GrMul(dy, GR_ScalarHalf);
+
+ GrScalar spare;
+ {
+ GrScalar w = devRect.width() - dx;
+ GrScalar h = devRect.height() - dy;
+ spare = GrMin(w, h);
+ }
+
+ if (spare <= 0) {
+ GrRect r(devRect);
+ r.inset(-rx, -ry);
+ fillAARect(target, r, useVertexCoverage);
+ return;
+ }
+ GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
+ size_t vsize = GrDrawTarget::VertexSize(layout);
+
+ GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
+ if (!geo.succeeded()) {
+ GrPrintf("Failed to get space for vertices!\n");
+ return;
+ }
+ GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
+ if (NULL == indexBuffer) {
+ GrPrintf("Failed to create index buffer!\n");
+ return;
+ }
+
+ intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
+
+ GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
+ GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
+ GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
+ GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
+
+ setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
+ setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
+ setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
+ setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
+
+ verts += sizeof(GrPoint);
+ for (int i = 0; i < 4; ++i) {
+ *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
+ }
+
+ GrColor innerColor;
+ if (useVertexCoverage) {
+ innerColor = 0xffffffff;
+ } else {
+ innerColor = target->getDrawState().getColor();
+ }
+ verts += 4 * vsize;
+ for (int i = 0; i < 8; ++i) {
+ *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
+ }
+
+ verts += 8 * vsize;
+ for (int i = 0; i < 8; ++i) {
+ *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
+ }
+
+ target->setIndexSourceToBuffer(indexBuffer);
+ target->drawIndexed(kTriangles_PrimitiveType,
+ 0, 0, 16, aaStrokeRectIndexCount());
+}
+
+/**
+ * Returns true if the rects edges are integer-aligned.
+ */
+static bool isIRect(const GrRect& r) {
+ return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
+ GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
+}
+
+static bool apply_aa_to_rect(GrDrawTarget* target,
+ const GrRect& rect,
+ GrScalar width,
+ const GrMatrix* matrix,
+ GrMatrix* combinedMatrix,
+ GrRect* devRect,
+ bool* useVertexCoverage) {
+ // we use a simple alpha ramp to do aa on axis-aligned rects
+ // do AA with alpha ramp if the caller requested AA, the rect
+ // will be axis-aligned, and the rect won't land on integer coords.
+
+ // we are keeping around the "tweak the alpha" trick because
+ // it is our only hope for the fixed-pipe implementation.
+ // In a shader implementation we can give a separate coverage input
+ // TODO: remove this ugliness when we drop the fixed-pipe impl
+ *useVertexCoverage = false;
+ if (!target->canTweakAlphaForCoverage()) {
+ if (target->getCaps().fSupportPerVertexCoverage) {
+ if (disable_coverage_aa_for_blend(target)) {
+#if GR_DEBUG
+ //GrPrintf("Turning off AA to correctly apply blend.\n");
+#endif
+ return false;
+ } else {
+ *useVertexCoverage = true;
+ }
+ } else {
+ GrPrintf("Rect AA dropped because no support for coverage.\n");
+ return false;
+ }
+ }
+ const GrDrawState& drawState = target->getDrawState();
+ if (drawState.getRenderTarget()->isMultisampled()) {
+ return false;
+ }
+
+ if (0 == width && target->willUseHWAALines()) {
+ return false;
+ }
+
+ if (!drawState.getViewMatrix().preservesAxisAlignment()) {
+ return false;
+ }
+
+ if (NULL != matrix &&
+ !matrix->preservesAxisAlignment()) {
+ return false;
+ }
+
+ *combinedMatrix = drawState.getViewMatrix();
+ if (NULL != matrix) {
+ combinedMatrix->preConcat(*matrix);
+ GrAssert(combinedMatrix->preservesAxisAlignment());
+ }
+
+ combinedMatrix->mapRect(devRect, rect);
+ devRect->sort();
+
+ if (width < 0) {
+ return !isIRect(*devRect);
+ } else {
+ return true;
+ }
+}
+
+void GrContext::drawRect(const GrPaint& paint,
+ const GrRect& rect,
+ GrScalar width,
+ const GrMatrix* matrix) {
+ SK_TRACE_EVENT0("GrContext::drawRect");
+
+ GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
+ int stageMask = paint.getActiveStageMask();
+
+ GrRect devRect = rect;
+ GrMatrix combinedMatrix;
+ bool useVertexCoverage;
+ bool needAA = paint.fAntiAlias &&
+ !this->getRenderTarget()->isMultisampled();
+ bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
+ &combinedMatrix, &devRect,
+ &useVertexCoverage);
+
+ if (doAA) {
+ GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
+ if (width >= 0) {
+ GrVec strokeSize;;
+ if (width > 0) {
+ strokeSize.set(width, width);
+ combinedMatrix.mapVectors(&strokeSize, 1);
+ strokeSize.setAbs(strokeSize);
+ } else {
+ strokeSize.set(GR_Scalar1, GR_Scalar1);
+ }
+ strokeAARect(target, devRect, strokeSize, useVertexCoverage);
+ } else {
+ fillAARect(target, devRect, useVertexCoverage);
+ }
+ return;
+ }
+
+ if (width >= 0) {
+ // TODO: consider making static vertex buffers for these cases.
+ // Hairline could be done by just adding closing vertex to
+ // unitSquareVertexBuffer()
+ GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
+
+ static const int worstCaseVertCount = 10;
+ GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
+
+ if (!geo.succeeded()) {
+ GrPrintf("Failed to get space for vertices!\n");
+ return;
+ }
+
+ GrPrimitiveType primType;
+ int vertCount;
+ GrPoint* vertex = geo.positions();
+
+ if (width > 0) {
+ vertCount = 10;
+ primType = kTriangleStrip_PrimitiveType;
+ setStrokeRectStrip(vertex, rect, width);
+ } else {
+ // hairline
+ vertCount = 5;
+ primType = kLineStrip_PrimitiveType;
+ vertex[0].set(rect.fLeft, rect.fTop);
+ vertex[1].set(rect.fRight, rect.fTop);
+ vertex[2].set(rect.fRight, rect.fBottom);
+ vertex[3].set(rect.fLeft, rect.fBottom);
+ vertex[4].set(rect.fLeft, rect.fTop);
+ }
+
+ GrDrawState::AutoViewMatrixRestore avmr;
+ if (NULL != matrix) {
+ GrDrawState* drawState = target->drawState();
+ avmr.set(drawState);
+ drawState->preConcatViewMatrix(*matrix);
+ drawState->preConcatSamplerMatrices(stageMask, *matrix);
+ }
+
+ target->drawNonIndexed(primType, 0, vertCount);
+ } else {
+#if GR_STATIC_RECT_VB
+ GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
+ const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
+ if (NULL == sqVB) {
+ GrPrintf("Failed to create static rect vb.\n");
+ return;
+ }
+ target->setVertexSourceToBuffer(layout, sqVB);
+ GrDrawState* drawState = target->drawState();
+ GrDrawState::AutoViewMatrixRestore avmr(drawState);
+ GrMatrix m;
+ m.setAll(rect.width(), 0, rect.fLeft,
+ 0, rect.height(), rect.fTop,
+ 0, 0, GrMatrix::I()[8]);
+
+ if (NULL != matrix) {
+ m.postConcat(*matrix);
+ }
+ drawState->preConcatViewMatrix(m);
+ drawState->preConcatSamplerMatrices(stageMask, m);
+
+ target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
+#else
+ target->drawSimpleRect(rect, matrix, stageMask);
+#endif
+ }
+}
+
+void GrContext::drawRectToRect(const GrPaint& paint,
+ const GrRect& dstRect,
+ const GrRect& srcRect,
+ const GrMatrix* dstMatrix,
+ const GrMatrix* srcMatrix) {
+ SK_TRACE_EVENT0("GrContext::drawRectToRect");
+
+ // srcRect refers to paint's first texture
+ if (NULL == paint.getTexture(0)) {
+ drawRect(paint, dstRect, -1, dstMatrix);
+ return;
+ }
+
+ GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
+
+#if GR_STATIC_RECT_VB
+ GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
+ GrDrawState* drawState = target->drawState();
+ GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
+ GrDrawState::AutoViewMatrixRestore avmr(drawState);
+
+ GrMatrix m;
+
+ m.setAll(dstRect.width(), 0, dstRect.fLeft,
+ 0, dstRect.height(), dstRect.fTop,
+ 0, 0, GrMatrix::I()[8]);
+ if (NULL != dstMatrix) {
+ m.postConcat(*dstMatrix);
+ }
+ drawState->preConcatViewMatrix(m);
+
+ // srcRect refers to first stage
+ int otherStageMask = paint.getActiveStageMask() &
+ (~(1 << GrPaint::kFirstTextureStage));
+ if (otherStageMask) {
+ drawState->preConcatSamplerMatrices(otherStageMask, m);
+ }
+
+ m.setAll(srcRect.width(), 0, srcRect.fLeft,
+ 0, srcRect.height(), srcRect.fTop,
+ 0, 0, GrMatrix::I()[8]);
+ if (NULL != srcMatrix) {
+ m.postConcat(*srcMatrix);
+ }
+ drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
+
+ const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
+ if (NULL == sqVB) {
+ GrPrintf("Failed to create static rect vb.\n");
+ return;
+ }
+ target->setVertexSourceToBuffer(layout, sqVB);
+ target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
+#else
+
+ GrDrawTarget* target;
+#if BATCH_RECT_TO_RECT
+ target = this->prepareToDraw(paint, kBuffered_DrawCategory);
+#else
+ target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
+#endif
+
+ const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
+ const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
+ srcRects[0] = &srcRect;
+ srcMatrices[0] = srcMatrix;
+
+ target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
+#endif
+}
+
+void GrContext::drawVertices(const GrPaint& paint,
+ GrPrimitiveType primitiveType,
+ int vertexCount,
+ const GrPoint positions[],
+ const GrPoint texCoords[],
+ const GrColor colors[],
+ const uint16_t indices[],
+ int indexCount) {
+ SK_TRACE_EVENT0("GrContext::drawVertices");
+
+ GrDrawTarget::AutoReleaseGeometry geo;
+
+ GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
+
+ bool hasTexCoords[GrPaint::kTotalStages] = {
+ NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
+ 0 // remaining stages use positions
+ };
+
+ GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
+
+ if (NULL != colors) {
+ layout |= GrDrawTarget::kColor_VertexLayoutBit;
+ }
+ int vertexSize = GrDrawTarget::VertexSize(layout);
+
+ if (sizeof(GrPoint) != vertexSize) {
+ if (!geo.set(target, layout, vertexCount, 0)) {
+ GrPrintf("Failed to get space for vertices!\n");
+ return;
+ }
+ int texOffsets[GrDrawState::kMaxTexCoords];
+ int colorOffset;
+ GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
+ texOffsets,
+ &colorOffset,
+ NULL,
+ NULL);
+ void* curVertex = geo.vertices();
+
+ for (int i = 0; i < vertexCount; ++i) {
+ *((GrPoint*)curVertex) = positions[i];
+
+ if (texOffsets[0] > 0) {
+ *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
+ }
+ if (colorOffset > 0) {
+ *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
+ }
+ curVertex = (void*)((intptr_t)curVertex + vertexSize);
+ }
+ } else {
+ target->setVertexSourceToArray(layout, positions, vertexCount);
+ }
+
+ // we don't currently apply offscreen AA to this path. Need improved
+ // management of GrDrawTarget's geometry to avoid copying points per-tile.
+
+ if (NULL != indices) {
+ target->setIndexSourceToArray(indices, indexCount);
+ target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
+ } else {
+ target->drawNonIndexed(primitiveType, 0, vertexCount);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
+ GrPathFill fill, const GrPoint* translate) {
+
+ if (path.isEmpty()) {
+ if (GrIsFillInverted(fill)) {
+ this->drawPaint(paint);
+ }
+ return;
+ }
+
+ GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
+
+ bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
+
+ // An Assumption here is that path renderer would use some form of tweaking
+ // the src color (either the input alpha or in the frag shader) to implement
+ // aa. If we have some future driver-mojo path AA that can do the right
+ // thing WRT to the blend then we'll need some query on the PR.
+ if (disable_coverage_aa_for_blend(target)) {
+#if GR_DEBUG
+ //GrPrintf("Turning off AA to correctly apply blend.\n");
+#endif
+ prAA = false;
+ }
+
+ bool doOSAA = false;
+ GrPathRenderer* pr = NULL;
+ if (prAA) {
+ pr = this->getPathRenderer(path, fill, true);
+ if (NULL == pr) {
+ prAA = false;
+ doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
+ pr = this->getPathRenderer(path, fill, false);
+ }
+ } else {
+ pr = this->getPathRenderer(path, fill, false);
+ }
+
+ if (NULL == pr) {
+#if GR_DEBUG
+ GrPrintf("Unable to find path renderer compatible with path.\n");
+#endif
+ return;
+ }
+
+ GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
+ GrDrawState::StageMask stageMask = paint.getActiveStageMask();
+
+ if (doOSAA) {
+ bool needsStencil = pr->requiresStencilPass(target, path, fill);
+ const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
+ // compute bounds as intersection of rt size, clip, and path
+ GrIRect bound = SkIRect::MakeWH(rt->width(), rt->height());
+ GrIRect clipIBounds;
+ if (target->getClip().hasConservativeBounds()) {
+ target->getClip().getConservativeBounds().roundOut(&clipIBounds);
+ if (!bound.intersect(clipIBounds)) {
+ return;
+ }
+ }
+ GrRect pathBounds = path.getBounds();
+ if (!pathBounds.isEmpty()) {
+ if (NULL != translate) {
+ pathBounds.offset(*translate);
+ }
+ target->getDrawState().getViewMatrix().mapRect(&pathBounds,
+ pathBounds);
+ GrIRect pathIBounds;
+ pathBounds.roundOut(&pathIBounds);
+ if (!bound.intersect(pathIBounds)) {
+ return;
+ }
+ }
+ OffscreenRecord record;
+ if (this->prepareForOffscreenAA(target, needsStencil, bound,
+ pr, &record)) {
+ for (int tx = 0; tx < record.fTileCountX; ++tx) {
+ for (int ty = 0; ty < record.fTileCountY; ++ty) {
+ this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
+ pr->drawPath(0);
+ this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
+ }
+ }
+ this->cleanupOffscreenAA(target, pr, &record);
+ if (GrIsFillInverted(fill) && bound != clipIBounds) {
+ GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
+ GrRect rect;
+ if (clipIBounds.fTop < bound.fTop) {
+ rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
+ clipIBounds.fRight, bound.fTop);
+ target->drawSimpleRect(rect, NULL, stageMask);
+ }
+ if (clipIBounds.fLeft < bound.fLeft) {
+ rect.iset(clipIBounds.fLeft, bound.fTop,
+ bound.fLeft, bound.fBottom);
+ target->drawSimpleRect(rect, NULL, stageMask);
+ }
+ if (clipIBounds.fRight > bound.fRight) {
+ rect.iset(bound.fRight, bound.fTop,
+ clipIBounds.fRight, bound.fBottom);
+ target->drawSimpleRect(rect, NULL, stageMask);
+ }
+ if (clipIBounds.fBottom > bound.fBottom) {
+ rect.iset(clipIBounds.fLeft, bound.fBottom,
+ clipIBounds.fRight, clipIBounds.fBottom);
+ target->drawSimpleRect(rect, NULL, stageMask);
+ }
+ }
+ return;
+ }
+ }
+ pr->drawPath(stageMask);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrContext::flush(int flagsBitfield) {
+ if (kDiscard_FlushBit & flagsBitfield) {
+ fDrawBuffer->reset();
+ } else {
+ this->flushDrawBuffer();
+ }
+ if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
+ fGpu->forceRenderTargetFlush();
+ }
+}
+
+void GrContext::flushText() {
+ if (kText_DrawCategory == fLastDrawCategory) {
+ flushDrawBuffer();
+ }
+}
+
+void GrContext::flushDrawBuffer() {
+#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
+ if (fDrawBuffer) {
+ fDrawBuffer->playback(fGpu);
+ fDrawBuffer->reset();
+ }
+#endif
+}
+
+void GrContext::internalWriteTexturePixels(GrTexture* texture,
+ int left, int top,
+ int width, int height,
+ GrPixelConfig config,
+ const void* buffer,
+ size_t rowBytes,
+ uint32_t flags) {
+ SK_TRACE_EVENT0("GrContext::writeTexturePixels");
+ ASSERT_OWNED_RESOURCE(texture);
+
+ if (!(kDontFlush_PixelOpsFlag & flags)) {
+ this->flush();
+ }
+ // TODO: use scratch texture to perform conversion
+ if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
+ GrPixelConfigIsUnpremultiplied(config)) {
+ return;
+ }
+
+ fGpu->writeTexturePixels(texture, left, top, width, height,
+ config, buffer, rowBytes);
+}
+
+bool GrContext::internalReadTexturePixels(GrTexture* texture,
+ int left, int top,
+ int width, int height,
+ GrPixelConfig config,
+ void* buffer,
+ size_t rowBytes,
+ uint32_t flags) {
+ SK_TRACE_EVENT0("GrContext::readTexturePixels");
+ ASSERT_OWNED_RESOURCE(texture);
+
+ // TODO: code read pixels for textures that aren't also rendertargets
+ GrRenderTarget* target = texture->asRenderTarget();
+ if (NULL != target) {
+ return this->internalReadRenderTargetPixels(target,
+ left, top, width, height,
+ config, buffer, rowBytes,
+ flags);
+ } else {
+ return false;
+ }
+}
+
+bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
+ int left, int top,
+ int width, int height,
+ GrPixelConfig config,
+ void* buffer,
+ size_t rowBytes,
+ uint32_t flags) {
+ SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
+ ASSERT_OWNED_RESOURCE(target);
+
+ if (NULL == target) {
+ target = fGpu->drawState()->getRenderTarget();
+ if (NULL == target) {
+ return false;
+ }
+ }
+
+ // PM <-> UPM conversion requires a draw. Currently we only support drawing
+ // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
+ // not supported at this time.
+ if (GrPixelConfigIsUnpremultiplied(target->config()) &&
+ !GrPixelConfigIsUnpremultiplied(config)) {
+ return false;
+ }
+
+ if (!(kDontFlush_PixelOpsFlag & flags)) {
+ this->flush();
+ }
+
+ GrTexture* src = target->asTexture();
+ bool swapRAndB = NULL != src &&
+ fGpu->preferredReadPixelsConfig(config) ==
+ GrPixelConfigSwapRAndB(config);
+
+ bool flipY = NULL != src &&
+ fGpu->readPixelsWillPayForYFlip(target, left, top,
+ width, height, config,
+ rowBytes);
+ bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
+ GrPixelConfigIsUnpremultiplied(config));
+
+ if (NULL == src && alphaConversion) {
+ // we should fallback to cpu conversion here. This could happen when
+ // we were given an external render target by the client that is not
+ // also a texture (e.g. FBO 0 in GL)
+ return false;
+ }
+ // we draw to a scratch texture if any of these conversion are applied
+ GrAutoScratchTexture ast;
+ if (flipY || swapRAndB || alphaConversion) {
+ GrAssert(NULL != src);
+ if (swapRAndB) {
+ config = GrPixelConfigSwapRAndB(config);
+ GrAssert(kUnknown_GrPixelConfig != config);
+ }
+ // Make the scratch a render target because we don't have a robust
+ // readTexturePixels as of yet (it calls this function).
+ const GrTextureDesc desc = {
+ kRenderTarget_GrTextureFlagBit,
+ kNone_GrAALevel,
+ width, height,
+ config
+ };
+
+ // When a full readback is faster than a partial we could always make
+ // the scratch exactly match the passed rect. However, if we see many
+ // different size rectangles we will trash our texture cache and pay the
+ // cost of creating and destroying many textures. So, we only request
+ // an exact match when the caller is reading an entire RT.
+ ScratchTexMatch match = kApprox_ScratchTexMatch;
+ if (0 == left &&
+ 0 == top &&
+ target->width() == width &&
+ target->height() == height &&
+ fGpu->fullReadPixelsIsFasterThanPartial()) {
+ match = kExact_ScratchTexMatch;
+ }
+ ast.set(this, desc, match);
+ GrTexture* texture = ast.texture();
+ if (!texture) {
+ return false;
+ }
+ target = texture->asRenderTarget();
+ GrAssert(NULL != target);
+
+ GrDrawTarget::AutoStateRestore asr(fGpu);
+ GrDrawState* drawState = fGpu->drawState();
+ reset_draw_state(drawState);
+ drawState->setRenderTarget(target);
+
+ GrMatrix matrix;
+ if (flipY) {
+ matrix.setTranslate(SK_Scalar1 * left,
+ SK_Scalar1 * (top + height));
+ matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
+ } else {
+ matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
+ }
+ matrix.postIDiv(src->width(), src->height());
+ drawState->sampler(0)->reset(matrix);
+ drawState->sampler(0)->setRAndBSwap(swapRAndB);
+ drawState->setTexture(0, src);
+ GrRect rect;
+ rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
+ fGpu->drawSimpleRect(rect, NULL, 0x1);
+ left = 0;
+ top = 0;
+ }
+ return fGpu->readPixels(target,
+ left, top, width, height,
+ config, buffer, rowBytes, flipY);
+}
+
+void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
+ if (NULL == src || NULL == dst) {
+ return;
+ }
+ ASSERT_OWNED_RESOURCE(src);
+
+ GrDrawTarget::AutoStateRestore asr(fGpu);
+ GrDrawState* drawState = fGpu->drawState();
+ reset_draw_state(drawState);
+ drawState->setRenderTarget(dst);
+ GrMatrix sampleM;
+ sampleM.setIDiv(src->width(), src->height());
+ drawState->setTexture(0, src);
+ drawState->sampler(0)->reset(sampleM);
+ SkRect rect = SkRect::MakeXYWH(0, 0, src->width(), src->height());
+ fGpu->drawSimpleRect(rect, NULL, 1 << 0);
+}
+
+void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
+ int left, int top,
+ int width, int height,
+ GrPixelConfig config,
+ const void* buffer,
+ size_t rowBytes,
+ uint32_t flags) {
+ SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
+ ASSERT_OWNED_RESOURCE(target);
+
+ if (NULL == target) {
+ target = fGpu->drawState()->getRenderTarget();
+ if (NULL == target) {
+ return;
+ }
+ }
+
+ // TODO: when underlying api has a direct way to do this we should use it
+ // (e.g. glDrawPixels on desktop GL).
+
+ // If the RT is also a texture and we don't have to do PM/UPM conversion
+ // then take the texture path, which we expect to be at least as fast or
+ // faster since it doesn't use an intermediate texture as we do below.
+
+#if !GR_MAC_BUILD
+ // At least some drivers on the Mac get confused when glTexImage2D is called
+ // on a texture attached to an FBO. The FBO still sees the old image. TODO:
+ // determine what OS versions and/or HW is affected.
+ if (NULL != target->asTexture() &&
+ GrPixelConfigIsUnpremultiplied(target->config()) ==
+ GrPixelConfigIsUnpremultiplied(config)) {
+
+ this->internalWriteTexturePixels(target->asTexture(),
+ left, top, width, height,
+ config, buffer, rowBytes, flags);
+ return;
+ }
+#endif
+
+ bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
+ GrPixelConfigSwapRAndB(config);
+ if (swapRAndB) {
+ config = GrPixelConfigSwapRAndB(config);
+ }
+
+ const GrTextureDesc desc = {
+ kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
+ };
+ GrAutoScratchTexture ast(this, desc);
+ GrTexture* texture = ast.texture();
+ if (NULL == texture) {
+ return;
+ }
+ this->internalWriteTexturePixels(texture, 0, 0, width, height,
+ config, buffer, rowBytes, flags);
+
+ GrDrawTarget::AutoStateRestore asr(fGpu);
+ GrDrawState* drawState = fGpu->drawState();
+ reset_draw_state(drawState);
+
+ GrMatrix matrix;
+ matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
+ drawState->setViewMatrix(matrix);
+ drawState->setRenderTarget(target);
+ drawState->setTexture(0, texture);
+
+ matrix.setIDiv(texture->width(), texture->height());
+ drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
+ GrSamplerState::kNearest_Filter,
+ matrix);
+ drawState->sampler(0)->setRAndBSwap(swapRAndB);
+
+ GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
+ static const int VCOUNT = 4;
+ // TODO: Use GrGpu::drawRect here
+ GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
+ if (!geo.succeeded()) {
+ GrPrintf("Failed to get space for vertices!\n");
+ return;
+ }
+ ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
+ fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
+}
+////////////////////////////////////////////////////////////////////////////////
+
+void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
+ GrDrawState* drawState = target->drawState();
+
+ for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
+ int s = i + GrPaint::kFirstTextureStage;
+ drawState->setTexture(s, paint.getTexture(i));
+ ASSERT_OWNED_RESOURCE(paint.getTexture(i));
+ if (paint.getTexture(i)) {
+ *drawState->sampler(s) = paint.getTextureSampler(i);
+ }
+ }
+
+ drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
+
+ for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
+ int s = i + GrPaint::kFirstMaskStage;
+ drawState->setTexture(s, paint.getMask(i));
+ ASSERT_OWNED_RESOURCE(paint.getMask(i));
+ if (paint.getMask(i)) {
+ *drawState->sampler(s) = paint.getMaskSampler(i);
+ }
+ }
+
+ drawState->setColor(paint.fColor);
+
+ if (paint.fDither) {
+ drawState->enableState(GrDrawState::kDither_StateBit);
+ } else {
+ drawState->disableState(GrDrawState::kDither_StateBit);
+ }
+ if (paint.fAntiAlias) {
+ drawState->enableState(GrDrawState::kHWAntialias_StateBit);
+ } else {
+ drawState->disableState(GrDrawState::kHWAntialias_StateBit);
+ }
+ if (paint.fColorMatrixEnabled) {
+ drawState->enableState(GrDrawState::kColorMatrix_StateBit);
+ } else {
+ drawState->disableState(GrDrawState::kColorMatrix_StateBit);
+ }
+ drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
+ drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
+ drawState->setColorMatrix(paint.fColorMatrix);
+
+ if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
+ GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
+ }
+}
+
+GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
+ DrawCategory category) {
+ if (category != fLastDrawCategory) {
+ flushDrawBuffer();
+ fLastDrawCategory = category;
+ }
+ this->setPaint(paint, fGpu);
+ GrDrawTarget* target = fGpu;
+ switch (category) {
+ case kText_DrawCategory:
+#if DEFER_TEXT_RENDERING
+ target = fDrawBuffer;
+ fDrawBuffer->initializeDrawStateAndClip(*fGpu);
+#else
+ target = fGpu;
+#endif
+ break;
+ case kUnbuffered_DrawCategory:
+ target = fGpu;
+ break;
+ case kBuffered_DrawCategory:
+ target = fDrawBuffer;
+ fDrawBuffer->initializeDrawStateAndClip(*fGpu);
+ break;
+ }
+ return target;
+}
+
+GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
+ GrPathFill fill,
+ bool antiAlias) {
+ if (NULL == fPathRendererChain) {
+ fPathRendererChain =
+ new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
+ }
+ return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
+ fill, antiAlias);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrContext::setRenderTarget(GrRenderTarget* target) {
+ ASSERT_OWNED_RESOURCE(target);
+ this->flush(false);
+ fGpu->drawState()->setRenderTarget(target);
+}
+
+GrRenderTarget* GrContext::getRenderTarget() {
+ return fGpu->drawState()->getRenderTarget();
+}
+
+const GrRenderTarget* GrContext::getRenderTarget() const {
+ return fGpu->getDrawState().getRenderTarget();
+}
+
+const GrMatrix& GrContext::getMatrix() const {
+ return fGpu->getDrawState().getViewMatrix();
+}
+
+void GrContext::setMatrix(const GrMatrix& m) {
+ fGpu->drawState()->setViewMatrix(m);
+}
+
+void GrContext::concatMatrix(const GrMatrix& m) const {
+ fGpu->drawState()->preConcatViewMatrix(m);
+}
+
+static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
+ intptr_t mask = 1 << shift;
+ if (pred) {
+ bits |= mask;
+ } else {
+ bits &= ~mask;
+ }
+ return bits;
+}
+
+void GrContext::resetStats() {
+ fGpu->resetStats();
+}
+
+const GrGpuStats& GrContext::getStats() const {
+ return fGpu->getStats();
+}
+
+void GrContext::printStats() const {
+ fGpu->printStats();
+}
+
+GrContext::GrContext(GrGpu* gpu) {
+ fGpu = gpu;
+ fGpu->ref();
+ fGpu->setContext(this);
+
+ fPathRendererChain = NULL;
+
+ fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
+ MAX_TEXTURE_CACHE_BYTES);
+ fFontCache = new GrFontCache(fGpu);
+
+ fLastDrawCategory = kUnbuffered_DrawCategory;
+
+ fDrawBuffer = NULL;
+ fDrawBufferVBAllocPool = NULL;
+ fDrawBufferIBAllocPool = NULL;
+
+ fAAFillRectIndexBuffer = NULL;
+ fAAStrokeRectIndexBuffer = NULL;
+
+ int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
+ if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
+ gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
+ }
+ fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
+
+ this->setupDrawBuffer();
+}
+
+void GrContext::setupDrawBuffer() {
+
+ GrAssert(NULL == fDrawBuffer);
+ GrAssert(NULL == fDrawBufferVBAllocPool);
+ GrAssert(NULL == fDrawBufferIBAllocPool);
+
+#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
+ fDrawBufferVBAllocPool =
+ new GrVertexBufferAllocPool(fGpu, false,
+ DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
+ DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
+ fDrawBufferIBAllocPool =
+ new GrIndexBufferAllocPool(fGpu, false,
+ DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
+ DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
+
+ fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
+ fDrawBufferVBAllocPool,
+ fDrawBufferIBAllocPool);
+#endif
+
+#if BATCH_RECT_TO_RECT
+ fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
+#endif
+}
+
+GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
+ GrDrawTarget* target;
+#if DEFER_TEXT_RENDERING
+ target = prepareToDraw(paint, kText_DrawCategory);
+#else
+ target = prepareToDraw(paint, kUnbuffered_DrawCategory);
+#endif
+ this->setPaint(paint, target);
+ return target;
+}
+
+const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
+ return fGpu->getQuadIndexBuffer();
+}
+
+void GrContext::convolveInX(GrTexture* texture,
+ const SkRect& rect,
+ const float* kernel,
+ int kernelWidth) {
+ ASSERT_OWNED_RESOURCE(texture);
+
+ float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
+ convolve(texture, rect, imageIncrement, kernel, kernelWidth);
+}
+
+void GrContext::convolveInY(GrTexture* texture,
+ const SkRect& rect,
+ const float* kernel,
+ int kernelWidth) {
+ ASSERT_OWNED_RESOURCE(texture);
+
+ float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
+ convolve(texture, rect, imageIncrement, kernel, kernelWidth);
+}
+
+void GrContext::convolve(GrTexture* texture,
+ const SkRect& rect,
+ float imageIncrement[2],
+ const float* kernel,
+ int kernelWidth) {
+ ASSERT_OWNED_RESOURCE(texture);
+
+ GrDrawTarget::AutoStateRestore asr(fGpu);
+ GrDrawState* drawState = fGpu->drawState();
+ GrMatrix sampleM;
+ sampleM.setIDiv(texture->width(), texture->height());
+ drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
+ GrSamplerState::kConvolution_Filter,
+ sampleM);
+ drawState->sampler(0)->setConvolutionParams(kernelWidth,
+ kernel,
+ imageIncrement);
+
+ drawState->setViewMatrix(GrMatrix::I());
+ drawState->setTexture(0, texture);
+ drawState->setAlpha(0xFF);
+ drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
+ fGpu->drawSimpleRect(rect, NULL, 1 << 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrDefaultPathRenderer.cpp b/src/gpu/GrDefaultPathRenderer.cpp
new file mode 100644
index 0000000..6ea0459
--- /dev/null
+++ b/src/gpu/GrDefaultPathRenderer.cpp
@@ -0,0 +1,566 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrDefaultPathRenderer.h"
+
+#include "GrContext.h"
+#include "GrDrawState.h"
+#include "GrPathUtils.h"
+#include "SkString.h"
+#include "SkTrace.h"
+
+
+GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
+ bool stencilWrapOpsSupport)
+ : fSeparateStencil(separateStencilSupport)
+ , fStencilWrapOps(stencilWrapOpsSupport)
+ , fSubpathCount(0)
+ , fSubpathVertCount(0)
+ , fPreviousSrcTol(-GR_Scalar1)
+ , fPreviousStages(-1) {
+ fTarget = NULL;
+}
+
+bool GrDefaultPathRenderer::canDrawPath(const GrDrawTarget::Caps& targetCaps,
+ const SkPath& path,
+ GrPathFill fill,
+ bool antiAlias) const {
+ // this class can draw any path with any fill but doesn't do any
+ // anti-aliasing.
+ return !antiAlias;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Stencil rules for paths
+
+////// Even/Odd
+
+GR_STATIC_CONST_SAME_STENCIL(gEOStencilPass,
+ kInvert_StencilOp,
+ kKeep_StencilOp,
+ kAlwaysIfInClip_StencilFunc,
+ 0xffff,
+ 0xffff,
+ 0xffff);
+
+// ok not to check clip b/c stencil pass only wrote inside clip
+GR_STATIC_CONST_SAME_STENCIL(gEOColorPass,
+ kZero_StencilOp,
+ kZero_StencilOp,
+ kNotEqual_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
+
+// have to check clip b/c outside clip will always be zero.
+GR_STATIC_CONST_SAME_STENCIL(gInvEOColorPass,
+ kZero_StencilOp,
+ kZero_StencilOp,
+ kEqualIfInClip_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
+
+////// Winding
+
+// when we have separate stencil we increment front faces / decrement back faces
+// when we don't have wrap incr and decr we use the stencil test to simulate
+// them.
+
+GR_STATIC_CONST_STENCIL(gWindStencilSeparateWithWrap,
+ kIncWrap_StencilOp, kDecWrap_StencilOp,
+ kKeep_StencilOp, kKeep_StencilOp,
+ kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
+ 0xffff, 0xffff,
+ 0xffff, 0xffff,
+ 0xffff, 0xffff);
+
+// if inc'ing the max value, invert to make 0
+// if dec'ing zero invert to make all ones.
+// we can't avoid touching the stencil on both passing and
+// failing, so we can't resctrict ourselves to the clip.
+GR_STATIC_CONST_STENCIL(gWindStencilSeparateNoWrap,
+ kInvert_StencilOp, kInvert_StencilOp,
+ kIncClamp_StencilOp, kDecClamp_StencilOp,
+ kEqual_StencilFunc, kEqual_StencilFunc,
+ 0xffff, 0xffff,
+ 0xffff, 0x0000,
+ 0xffff, 0xffff);
+
+// When there are no separate faces we do two passes to setup the winding rule
+// stencil. First we draw the front faces and inc, then we draw the back faces
+// and dec. These are same as the above two split into the incrementing and
+// decrementing passes.
+GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapInc,
+ kIncWrap_StencilOp,
+ kKeep_StencilOp,
+ kAlwaysIfInClip_StencilFunc,
+ 0xffff,
+ 0xffff,
+ 0xffff);
+
+GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilWithWrapDec,
+ kDecWrap_StencilOp,
+ kKeep_StencilOp,
+ kAlwaysIfInClip_StencilFunc,
+ 0xffff,
+ 0xffff,
+ 0xffff);
+
+GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapInc,
+ kInvert_StencilOp,
+ kIncClamp_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff,
+ 0xffff,
+ 0xffff);
+
+GR_STATIC_CONST_SAME_STENCIL(gWindSingleStencilNoWrapDec,
+ kInvert_StencilOp,
+ kDecClamp_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
+
+// Color passes are the same whether we use the two-sided stencil or two passes
+
+GR_STATIC_CONST_SAME_STENCIL(gWindColorPass,
+ kZero_StencilOp,
+ kZero_StencilOp,
+ kNonZeroIfInClip_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
+
+GR_STATIC_CONST_SAME_STENCIL(gInvWindColorPass,
+ kZero_StencilOp,
+ kZero_StencilOp,
+ kEqualIfInClip_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
+
+////// Normal render to stencil
+
+// Sometimes the default path renderer can draw a path directly to the stencil
+// buffer without having to first resolve the interior / exterior.
+GR_STATIC_CONST_SAME_STENCIL(gDirectToStencil,
+ kZero_StencilOp,
+ kIncClamp_StencilOp,
+ kAlwaysIfInClip_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
+
+////////////////////////////////////////////////////////////////////////////////
+// Helpers for drawPath
+
+static GrConvexHint getConvexHint(const SkPath& path) {
+ return path.isConvex() ? kConvex_ConvexHint : kConcave_ConvexHint;
+}
+
+#define STENCIL_OFF 0 // Always disable stencil (even when needed)
+
+static inline bool single_pass_path(const GrDrawTarget& target,
+ const GrPath& path,
+ GrPathFill fill) {
+#if STENCIL_OFF
+ return true;
+#else
+ if (kEvenOdd_PathFill == fill) {
+ GrConvexHint hint = getConvexHint(path);
+ return hint == kConvex_ConvexHint ||
+ hint == kNonOverlappingConvexPieces_ConvexHint;
+ } else if (kWinding_PathFill == fill) {
+ GrConvexHint hint = getConvexHint(path);
+ return hint == kConvex_ConvexHint ||
+ hint == kNonOverlappingConvexPieces_ConvexHint ||
+ (hint == kSameWindingConvexPieces_ConvexHint &&
+ !target.drawWillReadDst() &&
+ !target.getDrawState().isDitherState());
+
+ }
+ return false;
+#endif
+}
+
+bool GrDefaultPathRenderer::requiresStencilPass(const GrDrawTarget* target,
+ const GrPath& path,
+ GrPathFill fill) const {
+ return !single_pass_path(*target, path, fill);
+}
+
+void GrDefaultPathRenderer::pathWillClear() {
+ fSubpathVertCount.reset(0);
+ fTarget->resetVertexSource();
+ if (fUseIndexedDraw) {
+ fTarget->resetIndexSource();
+ }
+ fPreviousSrcTol = -GR_Scalar1;
+ fPreviousStages = -1;
+}
+
+static inline void append_countour_edge_indices(GrPathFill fillType,
+ uint16_t fanCenterIdx,
+ uint16_t edgeV0Idx,
+ uint16_t** indices) {
+ // when drawing lines we're appending line segments along
+ // the contour. When applying the other fill rules we're
+ // drawing triangle fans around fanCenterIdx.
+ if (kHairLine_PathFill != fillType) {
+ *((*indices)++) = fanCenterIdx;
+ }
+ *((*indices)++) = edgeV0Idx;
+ *((*indices)++) = edgeV0Idx + 1;
+}
+
+bool GrDefaultPathRenderer::createGeom(GrScalar srcSpaceTol,
+ GrDrawState::StageMask stageMask) {
+ {
+ SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
+
+ GrScalar srcSpaceTolSqd = GrMul(srcSpaceTol, srcSpaceTol);
+ int maxPts = GrPathUtils::worstCasePointCount(*fPath, &fSubpathCount,
+ srcSpaceTol);
+
+ if (maxPts <= 0) {
+ return false;
+ }
+ if (maxPts > ((int)SK_MaxU16 + 1)) {
+ GrPrintf("Path not rendered, too many verts (%d)\n", maxPts);
+ return false;
+ }
+
+ GrVertexLayout layout = 0;
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ if ((1 << s) & stageMask) {
+ layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
+ }
+ }
+
+ fUseIndexedDraw = fSubpathCount > 1;
+
+ int maxIdxs = 0;
+ if (kHairLine_PathFill == fFill) {
+ if (fUseIndexedDraw) {
+ maxIdxs = 2 * maxPts;
+ fPrimitiveType = kLines_PrimitiveType;
+ } else {
+ fPrimitiveType = kLineStrip_PrimitiveType;
+ }
+ } else {
+ if (fUseIndexedDraw) {
+ maxIdxs = 3 * maxPts;
+ fPrimitiveType = kTriangles_PrimitiveType;
+ } else {
+ fPrimitiveType = kTriangleFan_PrimitiveType;
+ }
+ }
+
+ GrPoint* base;
+ if (!fTarget->reserveVertexSpace(layout, maxPts, (void**)&base)) {
+ return false;
+ }
+ GrAssert(NULL != base);
+ GrPoint* vert = base;
+
+ uint16_t* idxBase = NULL;
+ uint16_t* idx = NULL;
+ uint16_t subpathIdxStart = 0;
+ if (fUseIndexedDraw) {
+ if (!fTarget->reserveIndexSpace(maxIdxs, (void**)&idxBase)) {
+ fTarget->resetVertexSource();
+ return false;
+ }
+ GrAssert(NULL != idxBase);
+ idx = idxBase;
+ }
+
+ fSubpathVertCount.reset(fSubpathCount);
+
+ GrPoint pts[4];
+
+ bool first = true;
+ int subpath = 0;
+
+ SkPath::Iter iter(*fPath, false);
+
+ for (;;) {
+ GrPathCmd cmd = (GrPathCmd)iter.next(pts);
+ switch (cmd) {
+ case kMove_PathCmd:
+ if (!first) {
+ uint16_t currIdx = (uint16_t) (vert - base);
+ fSubpathVertCount[subpath] = currIdx - subpathIdxStart;
+ subpathIdxStart = currIdx;
+ ++subpath;
+ }
+ *vert = pts[0];
+ vert++;
+ break;
+ case kLine_PathCmd:
+ if (fUseIndexedDraw) {
+ uint16_t prevIdx = (uint16_t)(vert - base) - 1;
+ append_countour_edge_indices(fFill, subpathIdxStart,
+ prevIdx, &idx);
+ }
+ *(vert++) = pts[1];
+ break;
+ case kQuadratic_PathCmd: {
+ // first pt of quad is the pt we ended on in previous step
+ uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
+ uint16_t numPts = (uint16_t)
+ GrPathUtils::generateQuadraticPoints(
+ pts[0], pts[1], pts[2],
+ srcSpaceTolSqd, &vert,
+ GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
+ if (fUseIndexedDraw) {
+ for (uint16_t i = 0; i < numPts; ++i) {
+ append_countour_edge_indices(fFill, subpathIdxStart,
+ firstQPtIdx + i, &idx);
+ }
+ }
+ break;
+ }
+ case kCubic_PathCmd: {
+ // first pt of cubic is the pt we ended on in previous step
+ uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
+ uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
+ pts[0], pts[1], pts[2], pts[3],
+ srcSpaceTolSqd, &vert,
+ GrPathUtils::cubicPointCount(pts, srcSpaceTol));
+ if (fUseIndexedDraw) {
+ for (uint16_t i = 0; i < numPts; ++i) {
+ append_countour_edge_indices(fFill, subpathIdxStart,
+ firstCPtIdx + i, &idx);
+ }
+ }
+ break;
+ }
+ case kClose_PathCmd:
+ break;
+ case kEnd_PathCmd:
+ uint16_t currIdx = (uint16_t) (vert - base);
+ fSubpathVertCount[subpath] = currIdx - subpathIdxStart;
+ goto FINISHED;
+ }
+ first = false;
+ }
+FINISHED:
+ GrAssert((vert - base) <= maxPts);
+ GrAssert((idx - idxBase) <= maxIdxs);
+
+ fVertexCnt = vert - base;
+ fIndexCnt = idx - idxBase;
+
+ if (fTranslate.fX || fTranslate.fY) {
+ int count = vert - base;
+ for (int i = 0; i < count; i++) {
+ base[i].offset(fTranslate.fX, fTranslate.fY);
+ }
+ }
+ }
+ // set these at the end so if we failed on first drawPath inside a
+ // setPath/clearPath block we won't assume geom was created on a subsequent
+ // drawPath in the same block.
+ fPreviousSrcTol = srcSpaceTol;
+ fPreviousStages = stageMask;
+ return true;
+}
+
+void GrDefaultPathRenderer::onDrawPath(GrDrawState::StageMask stageMask,
+ bool stencilOnly) {
+
+ GrMatrix viewM = fTarget->getDrawState().getViewMatrix();
+ GrScalar tol = GR_Scalar1;
+ tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, fPath->getBounds());
+ GrDrawState* drawState = fTarget->drawState();
+
+ // FIXME: It's really dumb that we recreate the verts for a new vertex
+ // layout. We only do that because the GrDrawTarget API doesn't allow
+ // us to change the vertex layout after reserveVertexSpace(). We won't
+ // actually change the vertex data when the layout changes since all the
+ // stages reference the positions (rather than having separate tex coords)
+ // and we don't ever have per-vert colors. In practice our call sites
+ // won't change the stages in use inside a setPath / removePath pair. But
+ // it is a silly limitation of the GrDrawTarget design that should be fixed.
+ if (tol != fPreviousSrcTol ||
+ stageMask != fPreviousStages) {
+ if (!this->createGeom(tol, stageMask)) {
+ return;
+ }
+ }
+
+ GrAssert(NULL != fTarget);
+ GrDrawTarget::AutoStateRestore asr(fTarget);
+ bool colorWritesWereDisabled = drawState->isColorWriteDisabled();
+ // face culling doesn't make sense here
+ GrAssert(GrDrawState::kBoth_DrawFace == drawState->getDrawFace());
+
+ int passCount = 0;
+ const GrStencilSettings* passes[3];
+ GrDrawState::DrawFace drawFace[3];
+ bool reverse = false;
+ bool lastPassIsBounds;
+
+ if (kHairLine_PathFill == fFill) {
+ passCount = 1;
+ if (stencilOnly) {
+ passes[0] = &gDirectToStencil;
+ } else {
+ passes[0] = NULL;
+ }
+ lastPassIsBounds = false;
+ drawFace[0] = GrDrawState::kBoth_DrawFace;
+ } else {
+ if (single_pass_path(*fTarget, *fPath, fFill)) {
+ passCount = 1;
+ if (stencilOnly) {
+ passes[0] = &gDirectToStencil;
+ } else {
+ passes[0] = NULL;
+ }
+ drawFace[0] = GrDrawState::kBoth_DrawFace;
+ lastPassIsBounds = false;
+ } else {
+ switch (fFill) {
+ case kInverseEvenOdd_PathFill:
+ reverse = true;
+ // fallthrough
+ case kEvenOdd_PathFill:
+ passes[0] = &gEOStencilPass;
+ if (stencilOnly) {
+ passCount = 1;
+ lastPassIsBounds = false;
+ } else {
+ passCount = 2;
+ lastPassIsBounds = true;
+ if (reverse) {
+ passes[1] = &gInvEOColorPass;
+ } else {
+ passes[1] = &gEOColorPass;
+ }
+ }
+ drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace;
+ break;
+
+ case kInverseWinding_PathFill:
+ reverse = true;
+ // fallthrough
+ case kWinding_PathFill:
+ if (fSeparateStencil) {
+ if (fStencilWrapOps) {
+ passes[0] = &gWindStencilSeparateWithWrap;
+ } else {
+ passes[0] = &gWindStencilSeparateNoWrap;
+ }
+ passCount = 2;
+ drawFace[0] = GrDrawState::kBoth_DrawFace;
+ } else {
+ if (fStencilWrapOps) {
+ passes[0] = &gWindSingleStencilWithWrapInc;
+ passes[1] = &gWindSingleStencilWithWrapDec;
+ } else {
+ passes[0] = &gWindSingleStencilNoWrapInc;
+ passes[1] = &gWindSingleStencilNoWrapDec;
+ }
+ // which is cw and which is ccw is arbitrary.
+ drawFace[0] = GrDrawState::kCW_DrawFace;
+ drawFace[1] = GrDrawState::kCCW_DrawFace;
+ passCount = 3;
+ }
+ if (stencilOnly) {
+ lastPassIsBounds = false;
+ --passCount;
+ } else {
+ lastPassIsBounds = true;
+ drawFace[passCount-1] = GrDrawState::kBoth_DrawFace;
+ if (reverse) {
+ passes[passCount-1] = &gInvWindColorPass;
+ } else {
+ passes[passCount-1] = &gWindColorPass;
+ }
+ }
+ break;
+ default:
+ GrAssert(!"Unknown path fFill!");
+ return;
+ }
+ }
+ }
+
+ {
+ for (int p = 0; p < passCount; ++p) {
+ drawState->setDrawFace(drawFace[p]);
+ if (NULL != passes[p]) {
+ *drawState->stencil() = *passes[p];
+ }
+
+ if (lastPassIsBounds && (p == passCount-1)) {
+ if (!colorWritesWereDisabled) {
+ drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
+ }
+ GrRect bounds;
+ if (reverse) {
+ GrAssert(NULL != drawState->getRenderTarget());
+ // draw over the whole world.
+ bounds.setLTRB(0, 0,
+ GrIntToScalar(drawState->getRenderTarget()->width()),
+ GrIntToScalar(drawState->getRenderTarget()->height()));
+ GrMatrix vmi;
+ // mapRect through persp matrix may not be correct
+ if (!drawState->getViewMatrix().hasPerspective() &&
+ drawState->getViewInverse(&vmi)) {
+ vmi.mapRect(&bounds);
+ } else {
+ if (stageMask) {
+ if (!drawState->getViewInverse(&vmi)) {
+ GrPrintf("Could not invert matrix.");
+ return;
+ }
+ drawState->preConcatSamplerMatrices(stageMask, vmi);
+ }
+ drawState->setViewMatrix(GrMatrix::I());
+ }
+ } else {
+ bounds = fPath->getBounds();
+ bounds.offset(fTranslate);
+ }
+ GrDrawTarget::AutoGeometryPush agp(fTarget);
+ fTarget->drawSimpleRect(bounds, NULL, stageMask);
+ } else {
+ if (passCount > 1) {
+ drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
+ }
+ if (fUseIndexedDraw) {
+ fTarget->drawIndexed(fPrimitiveType, 0, 0,
+ fVertexCnt, fIndexCnt);
+ } else {
+ int baseVertex = 0;
+ for (int sp = 0; sp < fSubpathCount; ++sp) {
+ fTarget->drawNonIndexed(fPrimitiveType, baseVertex,
+ fSubpathVertCount[sp]);
+ baseVertex += fSubpathVertCount[sp];
+ }
+ }
+ }
+ }
+ }
+}
+
+void GrDefaultPathRenderer::drawPath(GrDrawState::StageMask stageMask) {
+ this->onDrawPath(stageMask, false);
+}
+
+void GrDefaultPathRenderer::drawPathToStencil() {
+ GrAssert(kInverseEvenOdd_PathFill != fFill);
+ GrAssert(kInverseWinding_PathFill != fFill);
+ this->onDrawPath(0, true);
+}
diff --git a/src/gpu/GrDefaultPathRenderer.h b/src/gpu/GrDefaultPathRenderer.h
new file mode 100644
index 0000000..adfe7d2
--- /dev/null
+++ b/src/gpu/GrDefaultPathRenderer.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrDefaultPathRenderer_DEFINED
+#define GrDefaultPathRenderer_DEFINED
+
+#include "GrPathRenderer.h"
+#include "SkTemplates.h"
+
+/**
+ * Subclass that renders the path using the stencil buffer to resolve fill
+ * rules (e.g. winding, even-odd)
+ */
+class GR_API GrDefaultPathRenderer : public GrPathRenderer {
+public:
+ GrDefaultPathRenderer(bool separateStencilSupport,
+ bool stencilWrapOpsSupport);
+
+ virtual bool canDrawPath(const GrDrawTarget::Caps& targetCaps,
+ const SkPath& path,
+ GrPathFill fill,
+ bool antiAlias) const SK_OVERRIDE;
+
+ virtual bool requiresStencilPass(const GrDrawTarget* target,
+ const SkPath& path,
+ GrPathFill fill) const SK_OVERRIDE;
+
+ virtual void drawPath(GrDrawState::StageMask stageMask) SK_OVERRIDE;
+ virtual void drawPathToStencil() SK_OVERRIDE;
+
+protected:
+ virtual void pathWillClear();
+
+private:
+
+ void onDrawPath(GrDrawState::StageMask stages, bool stencilOnly);
+
+ bool createGeom(GrScalar srcSpaceTol,
+ GrDrawState::StageMask stages);
+
+ bool fSeparateStencil;
+ bool fStencilWrapOps;
+
+ int fSubpathCount;
+ SkAutoSTMalloc<8, uint16_t> fSubpathVertCount;
+ int fIndexCnt;
+ int fVertexCnt;
+ GrScalar fPreviousSrcTol;
+ GrDrawState::StageMask fPreviousStages;
+ GrPrimitiveType fPrimitiveType;
+ bool fUseIndexedDraw;
+
+ typedef GrPathRenderer INHERITED;
+};
+
+#endif
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
new file mode 100644
index 0000000..4191c4a
--- /dev/null
+++ b/src/gpu/GrDrawState.h
@@ -0,0 +1,754 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrDrawState_DEFINED
+#define GrDrawState_DEFINED
+
+#include "GrColor.h"
+#include "GrMatrix.h"
+#include "GrNoncopyable.h"
+#include "GrSamplerState.h"
+#include "GrStencil.h"
+
+#include "SkXfermode.h"
+
+class GrRenderTarget;
+class GrTexture;
+
+struct GrDrawState {
+
+ /**
+ * Number of texture stages. Each stage takes as input a color and
+ * 2D texture coordinates. The color input to the first enabled stage is the
+ * per-vertex color or the constant color (setColor/setAlpha) if there are
+ * no per-vertex colors. For subsequent stages the input color is the output
+ * color from the previous enabled stage. The output color of each stage is
+ * the input color modulated with the result of a texture lookup. Texture
+ * lookups are specified by a texture a sampler (setSamplerState). Texture
+ * coordinates for each stage come from the vertices based on a
+ * GrVertexLayout bitfield. The output fragment color is the output color of
+ * the last enabled stage. The presence or absence of texture coordinates
+ * for each stage in the vertex layout indicates whether a stage is enabled
+ * or not.
+ */
+ enum {
+ kNumStages = 3,
+ kMaxTexCoords = kNumStages
+ };
+
+ /**
+ * Bitfield used to indicate a set of stages.
+ */
+ typedef uint32_t StageMask;
+ GR_STATIC_ASSERT(sizeof(StageMask)*8 >= GrDrawState::kNumStages);
+
+ GrDrawState() {
+ // make sure any pad is zero for memcmp
+ // all GrDrawState members should default to something
+ // valid by the memset
+ memset(this, 0, sizeof(GrDrawState));
+
+ // memset exceptions
+ fColorFilterMode = SkXfermode::kDstIn_Mode;
+ fFirstCoverageStage = kNumStages;
+
+ // pedantic assertion that our ptrs will
+ // be NULL (0 ptr is mem addr 0)
+ GrAssert((intptr_t)(void*)NULL == 0LL);
+
+ GrAssert(fStencilSettings.isDisabled());
+ fFirstCoverageStage = kNumStages;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Color
+ ////
+
+ /**
+ * Sets color for next draw to a premultiplied-alpha color.
+ *
+ * @param color the color to set.
+ */
+ void setColor(GrColor color) { fColor = color; }
+
+ GrColor getColor() const { return fColor; }
+
+ /**
+ * Sets the color to be used for the next draw to be
+ * (r,g,b,a) = (alpha, alpha, alpha, alpha).
+ *
+ * @param alpha The alpha value to set as the color.
+ */
+ void setAlpha(uint8_t a) {
+ this->setColor((a << 24) | (a << 16) | (a << 8) | a);
+ }
+
+ /**
+ * Add a color filter that can be represented by a color and a mode. Applied
+ * after color-computing texture stages.
+ */
+ void setColorFilter(GrColor c, SkXfermode::Mode mode) {
+ fColorFilterColor = c;
+ fColorFilterMode = mode;
+ }
+
+ GrColor getColorFilterColor() const { return fColorFilterColor; }
+ SkXfermode::Mode getColorFilterMode() const { return fColorFilterMode; }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Textures
+ ////
+
+ /**
+ * Sets the texture used at the next drawing call
+ *
+ * @param stage The texture stage for which the texture will be set
+ *
+ * @param texture The texture to set. Can be NULL though there is no
+ * advantage to settings a NULL texture if doing non-textured drawing
+ */
+ void setTexture(int stage, GrTexture* texture) {
+ GrAssert((unsigned)stage < kNumStages);
+ fTextures[stage] = texture;
+ }
+
+ /**
+ * Retrieves the currently set texture.
+ *
+ * @return The currently set texture. The return value will be NULL if no
+ * texture has been set, NULL was most recently passed to
+ * setTexture, or the last setTexture was destroyed.
+ */
+ const GrTexture* getTexture(int stage) const {
+ GrAssert((unsigned)stage < kNumStages);
+ return fTextures[stage];
+ }
+ GrTexture* getTexture(int stage) {
+ GrAssert((unsigned)stage < kNumStages);
+ return fTextures[stage];
+ }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Samplers
+ ////
+
+ /**
+ * Returns the current sampler for a stage.
+ */
+ const GrSamplerState& getSampler(int stage) const {
+ GrAssert((unsigned)stage < kNumStages);
+ return fSamplerStates[stage];
+ }
+
+ /**
+ * Writable pointer to a stage's sampler.
+ */
+ GrSamplerState* sampler(int stage) {
+ GrAssert((unsigned)stage < kNumStages);
+ return fSamplerStates + stage;
+ }
+
+ /**
+ * Preconcats the matrix of all samplers in the mask with the same matrix.
+ */
+ void preConcatSamplerMatrices(StageMask stageMask, const GrMatrix& matrix) {
+ GrAssert(!(stageMask & kIllegalStageMaskBits));
+ for (int i = 0; i < kNumStages; ++i) {
+ if ((1 << i) & stageMask) {
+ fSamplerStates[i].preConcatMatrix(matrix);
+ }
+ }
+ }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Coverage / Color Stages
+ ////
+
+ /**
+ * A common pattern is to compute a color with the initial stages and then
+ * modulate that color by a coverage value in later stage(s) (AA, mask-
+ * filters, glyph mask, etc). Color-filters, xfermodes, etc should be
+ * computed based on the pre-coverage-modulated color. The division of
+ * stages between color-computing and coverage-computing is specified by
+ * this method. Initially this is kNumStages (all stages
+ * are color-computing).
+ */
+ void setFirstCoverageStage(int firstCoverageStage) {
+ GrAssert((unsigned)firstCoverageStage <= kNumStages);
+ fFirstCoverageStage = firstCoverageStage;
+ }
+
+ /**
+ * Gets the index of the first coverage-computing stage.
+ */
+ int getFirstCoverageStage() const {
+ return fFirstCoverageStage;
+ }
+
+ ///@}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Blending
+ ////
+
+ /**
+ * Sets the blending function coeffecients.
+ *
+ * The blend function will be:
+ * D' = sat(S*srcCoef + D*dstCoef)
+ *
+ * where D is the existing destination color, S is the incoming source
+ * color, and D' is the new destination color that will be written. sat()
+ * is the saturation function.
+ *
+ * @param srcCoef coeffecient applied to the src color.
+ * @param dstCoef coeffecient applied to the dst color.
+ */
+ void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
+ fSrcBlend = srcCoeff;
+ fDstBlend = dstCoeff;
+ #if GR_DEBUG
+ switch (dstCoeff) {
+ case kDC_BlendCoeff:
+ case kIDC_BlendCoeff:
+ case kDA_BlendCoeff:
+ case kIDA_BlendCoeff:
+ GrPrintf("Unexpected dst blend coeff. Won't work correctly with"
+ "coverage stages.\n");
+ break;
+ default:
+ break;
+ }
+ switch (srcCoeff) {
+ case kSC_BlendCoeff:
+ case kISC_BlendCoeff:
+ case kSA_BlendCoeff:
+ case kISA_BlendCoeff:
+ GrPrintf("Unexpected src blend coeff. Won't work correctly with"
+ "coverage stages.\n");
+ break;
+ default:
+ break;
+ }
+ #endif
+ }
+
+ GrBlendCoeff getSrcBlendCoeff() const { return fSrcBlend; }
+ GrBlendCoeff getDstBlendCoeff() const { return fDstBlend; }
+
+ void getDstBlendCoeff(GrBlendCoeff* srcBlendCoeff,
+ GrBlendCoeff* dstBlendCoeff) const {
+ *srcBlendCoeff = fSrcBlend;
+ *dstBlendCoeff = fDstBlend;
+ }
+
+ /**
+ * Sets the blending function constant referenced by the following blending
+ * coeffecients:
+ * kConstC_BlendCoeff
+ * kIConstC_BlendCoeff
+ * kConstA_BlendCoeff
+ * kIConstA_BlendCoeff
+ *
+ * @param constant the constant to set
+ */
+ void setBlendConstant(GrColor constant) { fBlendConstant = constant; }
+
+ /**
+ * Retrieves the last value set by setBlendConstant()
+ * @return the blending constant value
+ */
+ GrColor getBlendConstant() const { return fBlendConstant; }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name View Matrix
+ ////
+
+ /**
+ * Sets the matrix applied to veretx positions.
+ *
+ * In the post-view-matrix space the rectangle [0,w]x[0,h]
+ * fully covers the render target. (w and h are the width and height of the
+ * the rendertarget.)
+ */
+ void setViewMatrix(const GrMatrix& m) { fViewMatrix = m; }
+
+ /**
+ * Gets a writable pointer to the view matrix.
+ */
+ GrMatrix* viewMatrix() { return &fViewMatrix; }
+
+ /**
+ * Multiplies the current view matrix by a matrix
+ *
+ * After this call V' = V*m where V is the old view matrix,
+ * m is the parameter to this function, and V' is the new view matrix.
+ * (We consider positions to be column vectors so position vector p is
+ * transformed by matrix X as p' = X*p.)
+ *
+ * @param m the matrix used to modify the view matrix.
+ */
+ void preConcatViewMatrix(const GrMatrix& m) { fViewMatrix.preConcat(m); }
+
+ /**
+ * Multiplies the current view matrix by a matrix
+ *
+ * After this call V' = m*V where V is the old view matrix,
+ * m is the parameter to this function, and V' is the new view matrix.
+ * (We consider positions to be column vectors so position vector p is
+ * transformed by matrix X as p' = X*p.)
+ *
+ * @param m the matrix used to modify the view matrix.
+ */
+ void postConcatViewMatrix(const GrMatrix& m) { fViewMatrix.postConcat(m); }
+
+ /**
+ * Retrieves the current view matrix
+ * @return the current view matrix.
+ */
+ const GrMatrix& getViewMatrix() const { return fViewMatrix; }
+
+ /**
+ * Retrieves the inverse of the current view matrix.
+ *
+ * If the current view matrix is invertible, return true, and if matrix
+ * is non-null, copy the inverse into it. If the current view matrix is
+ * non-invertible, return false and ignore the matrix parameter.
+ *
+ * @param matrix if not null, will receive a copy of the current inverse.
+ */
+ bool getViewInverse(GrMatrix* matrix) const {
+ // TODO: determine whether we really need to leave matrix unmodified
+ // at call sites when inversion fails.
+ GrMatrix inverse;
+ if (fViewMatrix.invert(&inverse)) {
+ if (matrix) {
+ *matrix = inverse;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ class AutoViewMatrixRestore : public ::GrNoncopyable {
+ public:
+ AutoViewMatrixRestore() : fDrawState(NULL) {}
+ AutoViewMatrixRestore(GrDrawState* ds, const GrMatrix& newMatrix) {
+ fDrawState = NULL;
+ this->set(ds, newMatrix);
+ }
+ AutoViewMatrixRestore(GrDrawState* ds) {
+ fDrawState = NULL;
+ this->set(ds);
+ }
+ ~AutoViewMatrixRestore() {
+ this->set(NULL, GrMatrix::I());
+ }
+ void set(GrDrawState* ds, const GrMatrix& newMatrix) {
+ if (NULL != fDrawState) {
+ fDrawState->setViewMatrix(fSavedMatrix);
+ }
+ if (NULL != ds) {
+ fSavedMatrix = ds->getViewMatrix();
+ ds->setViewMatrix(newMatrix);
+ }
+ fDrawState = ds;
+ }
+ void set(GrDrawState* ds) {
+ if (NULL != fDrawState) {
+ fDrawState->setViewMatrix(fSavedMatrix);
+ }
+ if (NULL != ds) {
+ fSavedMatrix = ds->getViewMatrix();
+ }
+ fDrawState = ds;
+ }
+ private:
+ GrDrawState* fDrawState;
+ GrMatrix fSavedMatrix;
+ };
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Render Target
+ ////
+
+ /**
+ * Sets the rendertarget used at the next drawing call
+ *
+ * @param target The render target to set.
+ */
+ void setRenderTarget(GrRenderTarget* target) { fRenderTarget = target; }
+
+ /**
+ * Retrieves the currently set rendertarget.
+ *
+ * @return The currently set render target.
+ */
+ const GrRenderTarget* getRenderTarget() const { return fRenderTarget; }
+ GrRenderTarget* getRenderTarget() { return fRenderTarget; }
+
+ class AutoRenderTargetRestore : public ::GrNoncopyable {
+ public:
+ AutoRenderTargetRestore() : fDrawState(NULL), fSavedTarget(NULL) {}
+ AutoRenderTargetRestore(GrDrawState* ds, GrRenderTarget* newTarget) {
+ fDrawState = NULL;
+ this->set(ds, newTarget);
+ }
+ ~AutoRenderTargetRestore() { this->set(NULL, NULL); }
+ void set(GrDrawState* ds, GrRenderTarget* newTarget) {
+ if (NULL != fDrawState) {
+ fDrawState->setRenderTarget(fSavedTarget);
+ }
+ if (NULL != ds) {
+ fSavedTarget = ds->getRenderTarget();
+ ds->setRenderTarget(newTarget);
+ }
+ fDrawState = ds;
+ }
+ private:
+ GrDrawState* fDrawState;
+ GrRenderTarget* fSavedTarget;
+ };
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Stencil
+ ////
+
+ /**
+ * Sets the stencil settings to use for the next draw.
+ * Changing the clip has the side-effect of possibly zeroing
+ * out the client settable stencil bits. So multipass algorithms
+ * using stencil should not change the clip between passes.
+ * @param settings the stencil settings to use.
+ */
+ void setStencil(const GrStencilSettings& settings) {
+ fStencilSettings = settings;
+ }
+
+ /**
+ * Shortcut to disable stencil testing and ops.
+ */
+ void disableStencil() {
+ fStencilSettings.setDisabled();
+ }
+
+ const GrStencilSettings& getStencil() const { return fStencilSettings; }
+
+ GrStencilSettings* stencil() { return &fStencilSettings; }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Color Matrix
+ ////
+
+ /**
+ * Sets the color matrix to use for the next draw.
+ * @param matrix the 5x4 matrix to apply to the incoming color
+ */
+ void setColorMatrix(const float matrix[20]) {
+ memcpy(fColorMatrix, matrix, sizeof(fColorMatrix));
+ }
+
+ const float* getColorMatrix() const { return fColorMatrix; }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ // @name Edge AA
+ // There are two ways to perform antialiasing using edge equations. One
+ // is to specify an (linear or quadratic) edge eq per-vertex. This requires
+ // splitting vertices shared by primitives.
+ //
+ // The other is via setEdgeAAData which sets a set of edges and each
+ // is tested against all the edges.
+ ////
+
+ /**
+ * When specifying edges as vertex data this enum specifies what type of
+ * edges are in use. The edges are always 4 GrScalars in memory, even when
+ * the edge type requires fewer than 4.
+ */
+ enum VertexEdgeType {
+ /* 1-pixel wide line
+ 2D implicit line eq (a*x + b*y +c = 0). 4th component unused */
+ kHairLine_EdgeType,
+ /* 1-pixel wide quadratic
+ u^2-v canonical coords (only 2 components used) */
+ kHairQuad_EdgeType
+ };
+
+ /**
+ * Determines the interpretation per-vertex edge data when the
+ * kEdge_VertexLayoutBit is set (see GrDrawTarget). When per-vertex edges
+ * are not specified the value of this setting has no effect.
+ */
+ void setVertexEdgeType(VertexEdgeType type) {
+ fVertexEdgeType = type;
+ }
+
+ VertexEdgeType getVertexEdgeType() const {
+ return fVertexEdgeType;
+ }
+
+ /**
+ * The absolute maximum number of edges that may be specified for
+ * a single draw call when performing edge antialiasing. This is used for
+ * the size of several static buffers, so implementations of getMaxEdges()
+ * (below) should clamp to this value.
+ */
+ enum {
+ // TODO: this should be 32 when GrTesselatedPathRenderer is used
+ // Visual Studio 2010 does not permit a member array of size 0.
+ kMaxEdges = 1
+ };
+
+ class Edge {
+ public:
+ Edge() {}
+ Edge(float x, float y, float z) : fX(x), fY(y), fZ(z) {}
+ GrPoint intersect(const Edge& other) {
+ return GrPoint::Make(
+ SkFloatToScalar((fY * other.fZ - other.fY * fZ) /
+ (fX * other.fY - other.fX * fY)),
+ SkFloatToScalar((fX * other.fZ - other.fX * fZ) /
+ (other.fX * fY - fX * other.fY)));
+ }
+ float fX, fY, fZ;
+ };
+
+ /**
+ * Sets the edge data required for edge antialiasing.
+ *
+ * @param edges 3 * numEdges float values, representing the edge
+ * equations in Ax + By + C form
+ */
+ void setEdgeAAData(const Edge* edges, int numEdges) {
+ GrAssert(numEdges <= GrDrawState::kMaxEdges);
+ memcpy(fEdgeAAEdges, edges, numEdges * sizeof(GrDrawState::Edge));
+ fEdgeAANumEdges = numEdges;
+ }
+
+ int getNumAAEdges() const { return fEdgeAANumEdges; }
+
+ const Edge* getAAEdges() const { return fEdgeAAEdges; }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name State Flags
+ ////
+
+ /**
+ * Flags that affect rendering. Controlled using enable/disableState(). All
+ * default to disabled.
+ */
+ enum StateBits {
+ /**
+ * Perform dithering. TODO: Re-evaluate whether we need this bit
+ */
+ kDither_StateBit = 0x01,
+ /**
+ * Perform HW anti-aliasing. This means either HW FSAA, if supported
+ * by the render target, or smooth-line rendering if a line primitive
+ * is drawn and line smoothing is supported by the 3D API.
+ */
+ kHWAntialias_StateBit = 0x02,
+ /**
+ * Draws will respect the clip, otherwise the clip is ignored.
+ */
+ kClip_StateBit = 0x04,
+ /**
+ * Disables writing to the color buffer. Useful when performing stencil
+ * operations.
+ */
+ kNoColorWrites_StateBit = 0x08,
+ /**
+ * Modifies the behavior of edge AA specified by setEdgeAA. If set,
+ * will test edge pairs for convexity when rasterizing. Set this if the
+ * source polygon is non-convex.
+ */
+ kEdgeAAConcave_StateBit = 0x10,
+ /**
+ * Draws will apply the color matrix, otherwise the color matrix is
+ * ignored.
+ */
+ kColorMatrix_StateBit = 0x20,
+
+ // Users of the class may add additional bits to the vector
+ kDummyStateBit,
+ kLastPublicStateBit = kDummyStateBit-1,
+ };
+
+ void resetStateFlags() {
+ fFlagBits = 0;
+ }
+
+ /**
+ * Enable render state settings.
+ *
+ * @param flags bitfield of StateBits specifing the states to enable
+ */
+ void enableState(uint32_t stateBits) {
+ fFlagBits |= stateBits;
+ }
+
+ /**
+ * Disable render state settings.
+ *
+ * @param flags bitfield of StateBits specifing the states to disable
+ */
+ void disableState(uint32_t stateBits) {
+ fFlagBits &= ~(stateBits);
+ }
+
+ bool isDitherState() const {
+ return 0 != (fFlagBits & kDither_StateBit);
+ }
+
+ bool isHWAntialiasState() const {
+ return 0 != (fFlagBits & kHWAntialias_StateBit);
+ }
+
+ bool isClipState() const {
+ return 0 != (fFlagBits & kClip_StateBit);
+ }
+
+ bool isColorWriteDisabled() const {
+ return 0 != (fFlagBits & kNoColorWrites_StateBit);
+ }
+
+ bool isConcaveEdgeAAState() const {
+ return 0 != (fFlagBits & kEdgeAAConcave_StateBit);
+ }
+
+ bool isStateFlagEnabled(uint32_t stateBit) const {
+ return 0 != (stateBit & fFlagBits);
+ }
+
+ void copyStateFlags(const GrDrawState& ds) {
+ fFlagBits = ds.fFlagBits;
+ }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+ /// @name Face Culling
+ ////
+
+ enum DrawFace {
+ kBoth_DrawFace,
+ kCCW_DrawFace,
+ kCW_DrawFace,
+ };
+
+ /**
+ * Controls whether clockwise, counterclockwise, or both faces are drawn.
+ * @param face the face(s) to draw.
+ */
+ void setDrawFace(DrawFace face) {
+ fDrawFace = face;
+ }
+
+ /**
+ * Gets whether the target is drawing clockwise, counterclockwise,
+ * or both faces.
+ * @return the current draw face(s).
+ */
+ DrawFace getDrawFace() const {
+ return fDrawFace;
+ }
+
+ /// @}
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ // Most stages are usually not used, so conditionals here
+ // reduce the expected number of bytes touched by 50%.
+ bool operator ==(const GrDrawState& s) const {
+ if (memcmp(this, &s, this->leadingBytes())) return false;
+
+ for (int i = 0; i < kNumStages; i++) {
+ if (fTextures[i] &&
+ memcmp(&this->fSamplerStates[i], &s.fSamplerStates[i],
+ sizeof(GrSamplerState))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ bool operator !=(const GrDrawState& s) const { return !(*this == s); }
+
+ // Most stages are usually not used, so conditionals here
+ // reduce the expected number of bytes touched by 50%.
+ GrDrawState& operator =(const GrDrawState& s) {
+ memcpy(this, &s, this->leadingBytes());
+
+ for (int i = 0; i < kNumStages; i++) {
+ if (s.fTextures[i]) {
+ memcpy(&this->fSamplerStates[i], &s.fSamplerStates[i],
+ sizeof(GrSamplerState));
+ }
+ }
+
+ return *this;
+ }
+
+private:
+ static const StageMask kIllegalStageMaskBits = ~((1 << kNumStages)-1);
+ uint8_t fFlagBits;
+ GrBlendCoeff fSrcBlend : 8;
+ GrBlendCoeff fDstBlend : 8;
+ DrawFace fDrawFace : 8;
+ uint8_t fFirstCoverageStage;
+ SkXfermode::Mode fColorFilterMode : 8;
+ GrColor fBlendConstant;
+ GrTexture* fTextures[kNumStages];
+ GrRenderTarget* fRenderTarget;
+ GrColor fColor;
+ GrColor fColorFilterColor;
+ float fColorMatrix[20];
+ GrStencilSettings fStencilSettings;
+ GrMatrix fViewMatrix;
+ // @{ Data for GrTesselatedPathRenderer
+ // TODO: currently ignored in copying & comparison for performance.
+ // Must be considered if GrTesselatedPathRenderer is being used.
+
+ VertexEdgeType fVertexEdgeType;
+ int fEdgeAANumEdges;
+ Edge fEdgeAAEdges[kMaxEdges];
+
+ // @}
+ // This field must be last; it will not be copied or compared
+ // if the corresponding fTexture[] is NULL.
+ GrSamplerState fSamplerStates[kNumStages];
+
+ size_t leadingBytes() const {
+ // Can't use offsetof() with non-POD types, so stuck with pointer math.
+ // TODO: ignores GrTesselatedPathRenderer data structures. We don't
+ // have a compile-time flag that lets us know if it's being used, and
+ // checking at runtime seems to cost 5% performance.
+ return (size_t) ((unsigned char*)&fEdgeAANumEdges -
+ (unsigned char*)&fFlagBits);
+ }
+
+};
+
+#endif
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
new file mode 100644
index 0000000..be6bd0a
--- /dev/null
+++ b/src/gpu/GrDrawTarget.cpp
@@ -0,0 +1,1215 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#include "GrDrawTarget.h"
+#include "GrGpuVertex.h"
+#include "GrIndexBuffer.h"
+#include "GrRenderTarget.h"
+#include "GrTexture.h"
+#include "GrVertexBuffer.h"
+
+namespace {
+
+/**
+ * This function generates some masks that we like to have known at compile
+ * time. When the number of stages or tex coords is bumped or the way bits
+ * are defined in GrDrawTarget.h changes this funcion should be rerun to
+ * generate the new masks. (We attempted to force the compiler to generate the
+ * masks using recursive templates but always wound up with static initializers
+ * under gcc, even if they were just a series of immediate->memory moves.)
+ *
+ */
+void gen_mask_arrays(GrVertexLayout* stageTexCoordMasks,
+ GrVertexLayout* stageMasks,
+ GrVertexLayout* texCoordMasks) {
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ stageTexCoordMasks[s] = 0;
+ for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
+ stageTexCoordMasks[s] |= GrDrawTarget::StageTexCoordVertexLayoutBit(s, t);
+ }
+ stageMasks[s] = stageTexCoordMasks[s] | GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
+ }
+ for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
+ texCoordMasks[t] = 0;
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ texCoordMasks[t] |= GrDrawTarget::StageTexCoordVertexLayoutBit(s, t);
+ }
+ }
+}
+
+/**
+ * Run this function to generate the code that declares the global masks.
+ */
+void gen_globals() {
+ GrVertexLayout stageTexCoordMasks[GrDrawState::kNumStages];
+ GrVertexLayout stageMasks[GrDrawState::kNumStages];
+ GrVertexLayout texCoordMasks[GrDrawState::kMaxTexCoords];
+ gen_mask_arrays(stageTexCoordMasks, stageMasks, texCoordMasks);
+
+ GrPrintf("const GrVertexLayout gStageTexCoordMasks[] = {\n");
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ GrPrintf(" 0x%x,\n", stageTexCoordMasks[s]);
+ }
+ GrPrintf("};\n");
+ GrPrintf("GR_STATIC_ASSERT(GrDrawState::kNumStages == GR_ARRAY_COUNT(gStageTexCoordMasks));\n\n");
+ GrPrintf("const GrVertexLayout gStageMasks[] = {\n");
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ GrPrintf(" 0x%x,\n", stageMasks[s]);
+ }
+ GrPrintf("};\n");
+ GrPrintf("GR_STATIC_ASSERT(GrDrawState::kNumStages == GR_ARRAY_COUNT(gStageMasks));\n\n");
+ GrPrintf("const GrVertexLayout gTexCoordMasks[] = {\n");
+ for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
+ GrPrintf(" 0x%x,\n", texCoordMasks[t]);
+ }
+ GrPrintf("};\n");
+ GrPrintf("GR_STATIC_ASSERT(GrDrawState::kMaxTexCoords == GR_ARRAY_COUNT(gTexCoordMasks));\n");
+}
+
+/* These values were generated by the above function */
+const GrVertexLayout gStageTexCoordMasks[] = {
+ 0x49,
+ 0x92,
+ 0x124
+};
+
+GR_STATIC_ASSERT(GrDrawState::kNumStages == GR_ARRAY_COUNT(gStageTexCoordMasks));
+const GrVertexLayout gStageMasks[] = {
+ 0x249,
+ 0x492,
+ 0x924
+};
+
+GR_STATIC_ASSERT(GrDrawState::kNumStages == GR_ARRAY_COUNT(gStageMasks));
+const GrVertexLayout gTexCoordMasks[] = {
+ 0x7,
+ 0x38,
+ 0x1c0,
+};
+GR_STATIC_ASSERT(GrDrawState::kMaxTexCoords == GR_ARRAY_COUNT(gTexCoordMasks));
+
+bool check_layout(GrVertexLayout layout) {
+ // can only have 1 or 0 bits set for each stage.
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ int stageBits = layout & gStageMasks[s];
+ if (stageBits && !GrIsPow2(stageBits)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+int num_tex_coords(GrVertexLayout layout) {
+ int cnt = 0;
+ // figure out how many tex coordinates are present
+ for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
+ if (gTexCoordMasks[t] & layout) {
+ ++cnt;
+ }
+ }
+ return cnt;
+}
+
+} //unnamed namespace
+
+size_t GrDrawTarget::VertexSize(GrVertexLayout vertexLayout) {
+ GrAssert(check_layout(vertexLayout));
+
+ size_t vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
+ sizeof(GrGpuTextVertex) :
+ sizeof(GrPoint);
+
+ size_t size = vecSize; // position
+ size += num_tex_coords(vertexLayout) * vecSize;
+ if (vertexLayout & kColor_VertexLayoutBit) {
+ size += sizeof(GrColor);
+ }
+ if (vertexLayout & kCoverage_VertexLayoutBit) {
+ size += sizeof(GrColor);
+ }
+ if (vertexLayout & kEdge_VertexLayoutBit) {
+ size += 4 * sizeof(GrScalar);
+ }
+ return size;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Functions for computing offsets of various components from the layout
+ * bitfield.
+ *
+ * Order of vertex components:
+ * Position
+ * Tex Coord 0
+ * ...
+ * Tex Coord GrDrawState::kMaxTexCoords-1
+ * Color
+ * Coverage
+ */
+
+int GrDrawTarget::VertexStageCoordOffset(int stage, GrVertexLayout vertexLayout) {
+ GrAssert(check_layout(vertexLayout));
+ if (StagePosAsTexCoordVertexLayoutBit(stage) & vertexLayout) {
+ return 0;
+ }
+ int tcIdx = VertexTexCoordsForStage(stage, vertexLayout);
+ if (tcIdx >= 0) {
+
+ int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
+ sizeof(GrGpuTextVertex) :
+ sizeof(GrPoint);
+ int offset = vecSize; // position
+ // figure out how many tex coordinates are present and precede this one.
+ for (int t = 0; t < tcIdx; ++t) {
+ if (gTexCoordMasks[t] & vertexLayout) {
+ offset += vecSize;
+ }
+ }
+ return offset;
+ }
+
+ return -1;
+}
+
+int GrDrawTarget::VertexColorOffset(GrVertexLayout vertexLayout) {
+ GrAssert(check_layout(vertexLayout));
+
+ if (vertexLayout & kColor_VertexLayoutBit) {
+ int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
+ sizeof(GrGpuTextVertex) :
+ sizeof(GrPoint);
+ return vecSize * (num_tex_coords(vertexLayout) + 1); //+1 for pos
+ }
+ return -1;
+}
+
+int GrDrawTarget::VertexCoverageOffset(GrVertexLayout vertexLayout) {
+ GrAssert(check_layout(vertexLayout));
+
+ if (vertexLayout & kCoverage_VertexLayoutBit) {
+ int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
+ sizeof(GrGpuTextVertex) :
+ sizeof(GrPoint);
+
+ int offset = vecSize * (num_tex_coords(vertexLayout) + 1);
+ if (vertexLayout & kColor_VertexLayoutBit) {
+ offset += sizeof(GrColor);
+ }
+ return offset;
+ }
+ return -1;
+}
+
+int GrDrawTarget::VertexEdgeOffset(GrVertexLayout vertexLayout) {
+ GrAssert(check_layout(vertexLayout));
+
+ // edge pts are after the pos, tex coords, and color
+ if (vertexLayout & kEdge_VertexLayoutBit) {
+ int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
+ sizeof(GrGpuTextVertex) :
+ sizeof(GrPoint);
+ int offset = vecSize * (num_tex_coords(vertexLayout) + 1); //+1 for pos
+ if (vertexLayout & kColor_VertexLayoutBit) {
+ offset += sizeof(GrColor);
+ }
+ if (vertexLayout & kCoverage_VertexLayoutBit) {
+ offset += sizeof(GrColor);
+ }
+ return offset;
+ }
+ return -1;
+}
+
+int GrDrawTarget::VertexSizeAndOffsetsByIdx(
+ GrVertexLayout vertexLayout,
+ int texCoordOffsetsByIdx[GrDrawState::kMaxTexCoords],
+ int* colorOffset,
+ int* coverageOffset,
+ int* edgeOffset) {
+ GrAssert(check_layout(vertexLayout));
+
+ int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ?
+ sizeof(GrGpuTextVertex) :
+ sizeof(GrPoint);
+ int size = vecSize; // position
+
+ for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
+ if (gTexCoordMasks[t] & vertexLayout) {
+ if (NULL != texCoordOffsetsByIdx) {
+ texCoordOffsetsByIdx[t] = size;
+ }
+ size += vecSize;
+ } else {
+ if (NULL != texCoordOffsetsByIdx) {
+ texCoordOffsetsByIdx[t] = -1;
+ }
+ }
+ }
+ if (kColor_VertexLayoutBit & vertexLayout) {
+ if (NULL != colorOffset) {
+ *colorOffset = size;
+ }
+ size += sizeof(GrColor);
+ } else {
+ if (NULL != colorOffset) {
+ *colorOffset = -1;
+ }
+ }
+ if (kCoverage_VertexLayoutBit & vertexLayout) {
+ if (NULL != coverageOffset) {
+ *coverageOffset = size;
+ }
+ size += sizeof(GrColor);
+ } else {
+ if (NULL != coverageOffset) {
+ *coverageOffset = -1;
+ }
+ }
+ if (kEdge_VertexLayoutBit & vertexLayout) {
+ if (NULL != edgeOffset) {
+ *edgeOffset = size;
+ }
+ size += 4 * sizeof(GrScalar);
+ } else {
+ if (NULL != edgeOffset) {
+ *edgeOffset = -1;
+ }
+ }
+ return size;
+}
+
+int GrDrawTarget::VertexSizeAndOffsetsByStage(
+ GrVertexLayout vertexLayout,
+ int texCoordOffsetsByStage[GrDrawState::kNumStages],
+ int* colorOffset,
+ int* coverageOffset,
+ int* edgeOffset) {
+ GrAssert(check_layout(vertexLayout));
+
+ int texCoordOffsetsByIdx[GrDrawState::kMaxTexCoords];
+ int size = VertexSizeAndOffsetsByIdx(vertexLayout,
+ (NULL == texCoordOffsetsByStage) ?
+ NULL :
+ texCoordOffsetsByIdx,
+ colorOffset,
+ coverageOffset,
+ edgeOffset);
+ if (NULL != texCoordOffsetsByStage) {
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ int tcIdx;
+ if (StagePosAsTexCoordVertexLayoutBit(s) & vertexLayout) {
+ texCoordOffsetsByStage[s] = 0;
+ } else if ((tcIdx = VertexTexCoordsForStage(s, vertexLayout)) >= 0) {
+ texCoordOffsetsByStage[s] = texCoordOffsetsByIdx[tcIdx];
+ } else {
+ texCoordOffsetsByStage[s] = -1;
+ }
+ }
+ }
+ return size;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool GrDrawTarget::VertexUsesStage(int stage, GrVertexLayout vertexLayout) {
+ GrAssert(stage < GrDrawState::kNumStages);
+ GrAssert(check_layout(vertexLayout));
+ return !!(gStageMasks[stage] & vertexLayout);
+}
+
+bool GrDrawTarget::VertexUsesTexCoordIdx(int coordIndex,
+ GrVertexLayout vertexLayout) {
+ GrAssert(coordIndex < GrDrawState::kMaxTexCoords);
+ GrAssert(check_layout(vertexLayout));
+ return !!(gTexCoordMasks[coordIndex] & vertexLayout);
+}
+
+int GrDrawTarget::VertexTexCoordsForStage(int stage,
+ GrVertexLayout vertexLayout) {
+ GrAssert(stage < GrDrawState::kNumStages);
+ GrAssert(check_layout(vertexLayout));
+ int bit = vertexLayout & gStageTexCoordMasks[stage];
+ if (bit) {
+ // figure out which set of texture coordates is used
+ // bits are ordered T0S0, T0S1, T0S2, ..., T1S0, T1S1, ...
+ // and start at bit 0.
+ GR_STATIC_ASSERT(sizeof(GrVertexLayout) <= sizeof(uint32_t));
+ return (32 - Gr_clz(bit) - 1) / GrDrawState::kNumStages;
+ }
+ return -1;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrDrawTarget::VertexLayoutUnitTest() {
+ // Ensure that our globals mask arrays are correct
+ GrVertexLayout stageTexCoordMasks[GrDrawState::kNumStages];
+ GrVertexLayout stageMasks[GrDrawState::kNumStages];
+ GrVertexLayout texCoordMasks[GrDrawState::kMaxTexCoords];
+ gen_mask_arrays(stageTexCoordMasks, stageMasks, texCoordMasks);
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ GrAssert(stageTexCoordMasks[s] == gStageTexCoordMasks[s]);
+ GrAssert(stageMasks[s] == gStageMasks[s]);
+ }
+ for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
+ GrAssert(texCoordMasks[t] == gTexCoordMasks[t]);
+ }
+
+ // not necessarily exhaustive
+ static bool run;
+ if (!run) {
+ run = true;
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+
+ GrAssert(!VertexUsesStage(s, 0));
+ GrAssert(-1 == VertexStageCoordOffset(s, 0));
+ GrVertexLayout stageMask = 0;
+ for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
+ stageMask |= StageTexCoordVertexLayoutBit(s,t);
+ }
+ GrAssert(1 == GrDrawState::kMaxTexCoords ||
+ !check_layout(stageMask));
+ GrAssert(gStageTexCoordMasks[s] == stageMask);
+ stageMask |= StagePosAsTexCoordVertexLayoutBit(s);
+ GrAssert(gStageMasks[s] == stageMask);
+ GrAssert(!check_layout(stageMask));
+ }
+ for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
+ GrVertexLayout tcMask = 0;
+ GrAssert(!VertexUsesTexCoordIdx(t, 0));
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ tcMask |= StageTexCoordVertexLayoutBit(s,t);
+ GrAssert(VertexUsesStage(s, tcMask));
+ GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask));
+ GrAssert(VertexUsesTexCoordIdx(t, tcMask));
+ GrAssert(2*sizeof(GrPoint) == VertexSize(tcMask));
+ GrAssert(t == VertexTexCoordsForStage(s, tcMask));
+ for (int s2 = s + 1; s2 < GrDrawState::kNumStages; ++s2) {
+ GrAssert(-1 == VertexStageCoordOffset(s2, tcMask));
+ GrAssert(!VertexUsesStage(s2, tcMask));
+ GrAssert(-1 == VertexTexCoordsForStage(s2, tcMask));
+
+ #if GR_DEBUG
+ GrVertexLayout posAsTex = tcMask | StagePosAsTexCoordVertexLayoutBit(s2);
+ #endif
+ GrAssert(0 == VertexStageCoordOffset(s2, posAsTex));
+ GrAssert(VertexUsesStage(s2, posAsTex));
+ GrAssert(2*sizeof(GrPoint) == VertexSize(posAsTex));
+ GrAssert(-1 == VertexTexCoordsForStage(s2, posAsTex));
+ GrAssert(-1 == VertexEdgeOffset(posAsTex));
+ }
+ GrAssert(-1 == VertexEdgeOffset(tcMask));
+ GrAssert(-1 == VertexColorOffset(tcMask));
+ GrAssert(-1 == VertexCoverageOffset(tcMask));
+ #if GR_DEBUG
+ GrVertexLayout withColor = tcMask | kColor_VertexLayoutBit;
+ #endif
+ GrAssert(-1 == VertexCoverageOffset(withColor));
+ GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColor));
+ GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColor));
+ #if GR_DEBUG
+ GrVertexLayout withEdge = tcMask | kEdge_VertexLayoutBit;
+ #endif
+ GrAssert(-1 == VertexColorOffset(withEdge));
+ GrAssert(2*sizeof(GrPoint) == VertexEdgeOffset(withEdge));
+ GrAssert(4*sizeof(GrPoint) == VertexSize(withEdge));
+ #if GR_DEBUG
+ GrVertexLayout withColorAndEdge = withColor | kEdge_VertexLayoutBit;
+ #endif
+ GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColorAndEdge));
+ GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexEdgeOffset(withColorAndEdge));
+ GrAssert(4*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColorAndEdge));
+ #if GR_DEBUG
+ GrVertexLayout withCoverage = tcMask | kCoverage_VertexLayoutBit;
+ #endif
+ GrAssert(-1 == VertexColorOffset(withCoverage));
+ GrAssert(2*sizeof(GrPoint) == VertexCoverageOffset(withCoverage));
+ GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withCoverage));
+ #if GR_DEBUG
+ GrVertexLayout withCoverageAndColor = tcMask | kCoverage_VertexLayoutBit |
+ kColor_VertexLayoutBit;
+ #endif
+ GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withCoverageAndColor));
+ GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexCoverageOffset(withCoverageAndColor));
+ GrAssert(2*sizeof(GrPoint) + 2 * sizeof(GrColor) == VertexSize(withCoverageAndColor));
+ }
+ GrAssert(gTexCoordMasks[t] == tcMask);
+ GrAssert(check_layout(tcMask));
+
+ int stageOffsets[GrDrawState::kNumStages];
+ int colorOffset;
+ int edgeOffset;
+ int coverageOffset;
+ int size;
+ size = VertexSizeAndOffsetsByStage(tcMask,
+ stageOffsets, &colorOffset,
+ &coverageOffset, &edgeOffset);
+ GrAssert(2*sizeof(GrPoint) == size);
+ GrAssert(-1 == colorOffset);
+ GrAssert(-1 == coverageOffset);
+ GrAssert(-1 == edgeOffset);
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ GrAssert(VertexUsesStage(s, tcMask));
+ GrAssert(sizeof(GrPoint) == stageOffsets[s]);
+ GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask));
+ }
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define DEBUG_INVAL_BUFFER 0xdeadcafe
+#define DEBUG_INVAL_START_IDX -1
+
+GrDrawTarget::GrDrawTarget() {
+#if GR_DEBUG
+ VertexLayoutUnitTest();
+#endif
+ GeometrySrcState& geoSrc = fGeoSrcStateStack.push_back();
+#if GR_DEBUG
+ geoSrc.fVertexCount = DEBUG_INVAL_START_IDX;
+ geoSrc.fVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
+ geoSrc.fIndexCount = DEBUG_INVAL_START_IDX;
+ geoSrc.fIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
+#endif
+ geoSrc.fVertexSrc = kNone_GeometrySrcType;
+ geoSrc.fIndexSrc = kNone_GeometrySrcType;
+}
+
+GrDrawTarget::~GrDrawTarget() {
+ GrAssert(1 == fGeoSrcStateStack.count());
+ GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+ GrAssert(kNone_GeometrySrcType == geoSrc.fIndexSrc);
+ GrAssert(kNone_GeometrySrcType == geoSrc.fVertexSrc);
+}
+
+void GrDrawTarget::releaseGeometry() {
+ int popCnt = fGeoSrcStateStack.count() - 1;
+ while (popCnt) {
+ this->popGeometrySource();
+ --popCnt;
+ }
+ this->resetVertexSource();
+ this->resetIndexSource();
+}
+
+void GrDrawTarget::setClip(const GrClip& clip) {
+ clipWillBeSet(clip);
+ fClip = clip;
+}
+
+const GrClip& GrDrawTarget::getClip() const {
+ return fClip;
+}
+
+void GrDrawTarget::saveCurrentDrawState(SavedDrawState* state) const {
+ state->fState = fCurrDrawState;
+}
+
+void GrDrawTarget::restoreDrawState(const SavedDrawState& state) {
+ fCurrDrawState = state.fState;
+}
+
+void GrDrawTarget::copyDrawState(const GrDrawTarget& srcTarget) {
+ fCurrDrawState = srcTarget.fCurrDrawState;
+}
+
+bool GrDrawTarget::reserveVertexSpace(GrVertexLayout vertexLayout,
+ int vertexCount,
+ void** vertices) {
+ GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+ bool acquired = false;
+ if (vertexCount > 0) {
+ GrAssert(NULL != vertices);
+ this->releasePreviousVertexSource();
+ geoSrc.fVertexSrc = kNone_GeometrySrcType;
+
+ acquired = this->onReserveVertexSpace(vertexLayout,
+ vertexCount,
+ vertices);
+ }
+ if (acquired) {
+ geoSrc.fVertexSrc = kReserved_GeometrySrcType;
+ geoSrc.fVertexCount = vertexCount;
+ geoSrc.fVertexLayout = vertexLayout;
+ } else if (NULL != vertices) {
+ *vertices = NULL;
+ }
+ return acquired;
+}
+
+bool GrDrawTarget::reserveIndexSpace(int indexCount,
+ void** indices) {
+ GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+ bool acquired = false;
+ if (indexCount > 0) {
+ GrAssert(NULL != indices);
+ this->releasePreviousIndexSource();
+ geoSrc.fIndexSrc = kNone_GeometrySrcType;
+
+ acquired = this->onReserveIndexSpace(indexCount, indices);
+ }
+ if (acquired) {
+ geoSrc.fIndexSrc = kReserved_GeometrySrcType;
+ geoSrc.fIndexCount = indexCount;
+ } else if (NULL != indices) {
+ *indices = NULL;
+ }
+ return acquired;
+
+}
+
+bool GrDrawTarget::geometryHints(GrVertexLayout vertexLayout,
+ int32_t* vertexCount,
+ int32_t* indexCount) const {
+ if (NULL != vertexCount) {
+ *vertexCount = -1;
+ }
+ if (NULL != indexCount) {
+ *indexCount = -1;
+ }
+ return false;
+}
+
+void GrDrawTarget::releasePreviousVertexSource() {
+ GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+ switch (geoSrc.fVertexSrc) {
+ case kNone_GeometrySrcType:
+ break;
+ case kArray_GeometrySrcType:
+ this->releaseVertexArray();
+ break;
+ case kReserved_GeometrySrcType:
+ this->releaseReservedVertexSpace();
+ break;
+ case kBuffer_GeometrySrcType:
+ geoSrc.fVertexBuffer->unref();
+#if GR_DEBUG
+ geoSrc.fVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
+#endif
+ break;
+ default:
+ GrCrash("Unknown Vertex Source Type.");
+ break;
+ }
+}
+
+void GrDrawTarget::releasePreviousIndexSource() {
+ GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+ switch (geoSrc.fIndexSrc) {
+ case kNone_GeometrySrcType: // these two don't require
+ break;
+ case kArray_GeometrySrcType:
+ this->releaseIndexArray();
+ break;
+ case kReserved_GeometrySrcType:
+ this->releaseReservedIndexSpace();
+ break;
+ case kBuffer_GeometrySrcType:
+ geoSrc.fIndexBuffer->unref();
+#if GR_DEBUG
+ geoSrc.fIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
+#endif
+ break;
+ default:
+ GrCrash("Unknown Index Source Type.");
+ break;
+ }
+}
+
+void GrDrawTarget::setVertexSourceToArray(GrVertexLayout vertexLayout,
+ const void* vertexArray,
+ int vertexCount) {
+ this->releasePreviousVertexSource();
+ GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+ geoSrc.fVertexSrc = kArray_GeometrySrcType;
+ geoSrc.fVertexLayout = vertexLayout;
+ geoSrc.fVertexCount = vertexCount;
+ this->onSetVertexSourceToArray(vertexArray, vertexCount);
+}
+
+void GrDrawTarget::setIndexSourceToArray(const void* indexArray,
+ int indexCount) {
+ this->releasePreviousIndexSource();
+ GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+ geoSrc.fIndexSrc = kArray_GeometrySrcType;
+ geoSrc.fIndexCount = indexCount;
+ this->onSetIndexSourceToArray(indexArray, indexCount);
+}
+
+void GrDrawTarget::setVertexSourceToBuffer(GrVertexLayout vertexLayout,
+ const GrVertexBuffer* buffer) {
+ this->releasePreviousVertexSource();
+ GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+ geoSrc.fVertexSrc = kBuffer_GeometrySrcType;
+ geoSrc.fVertexBuffer = buffer;
+ buffer->ref();
+ geoSrc.fVertexLayout = vertexLayout;
+}
+
+void GrDrawTarget::setIndexSourceToBuffer(const GrIndexBuffer* buffer) {
+ this->releasePreviousIndexSource();
+ GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+ geoSrc.fIndexSrc = kBuffer_GeometrySrcType;
+ geoSrc.fIndexBuffer = buffer;
+ buffer->ref();
+}
+
+void GrDrawTarget::resetVertexSource() {
+ this->releasePreviousVertexSource();
+ GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+ geoSrc.fVertexSrc = kNone_GeometrySrcType;
+}
+
+void GrDrawTarget::resetIndexSource() {
+ this->releasePreviousIndexSource();
+ GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+ geoSrc.fIndexSrc = kNone_GeometrySrcType;
+}
+
+void GrDrawTarget::pushGeometrySource() {
+ this->geometrySourceWillPush();
+ GeometrySrcState& newState = fGeoSrcStateStack.push_back();
+ newState.fIndexSrc = kNone_GeometrySrcType;
+ newState.fVertexSrc = kNone_GeometrySrcType;
+#if GR_DEBUG
+ newState.fVertexCount = ~0;
+ newState.fVertexBuffer = (GrVertexBuffer*)~0;
+ newState.fIndexCount = ~0;
+ newState.fIndexBuffer = (GrIndexBuffer*)~0;
+#endif
+}
+
+void GrDrawTarget::popGeometrySource() {
+ const GeometrySrcState& geoSrc = this->getGeomSrc();
+ // if popping last element then pops are unbalanced with pushes
+ GrAssert(fGeoSrcStateStack.count() > 1);
+
+ this->geometrySourceWillPop(fGeoSrcStateStack.fromBack(1));
+ this->releasePreviousVertexSource();
+ this->releasePreviousIndexSource();
+ fGeoSrcStateStack.pop_back();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool GrDrawTarget::checkDraw(GrPrimitiveType type, int startVertex,
+ int startIndex, int vertexCount,
+ int indexCount) const {
+#if GR_DEBUG
+ const GeometrySrcState& geoSrc = fGeoSrcStateStack.back();
+ int maxVertex = startVertex + vertexCount;
+ int maxValidVertex;
+ switch (geoSrc.fVertexSrc) {
+ case kNone_GeometrySrcType:
+ GrCrash("Attempting to draw without vertex src.");
+ case kReserved_GeometrySrcType: // fallthrough
+ case kArray_GeometrySrcType:
+ maxValidVertex = geoSrc.fVertexCount;
+ break;
+ case kBuffer_GeometrySrcType:
+ maxValidVertex = geoSrc.fVertexBuffer->sizeInBytes() /
+ VertexSize(geoSrc.fVertexLayout);
+ break;
+ }
+ if (maxVertex > maxValidVertex) {
+ GrCrash("Drawing outside valid vertex range.");
+ }
+ if (indexCount > 0) {
+ int maxIndex = startIndex + indexCount;
+ int maxValidIndex;
+ switch (geoSrc.fIndexSrc) {
+ case kNone_GeometrySrcType:
+ GrCrash("Attempting to draw indexed geom without index src.");
+ case kReserved_GeometrySrcType: // fallthrough
+ case kArray_GeometrySrcType:
+ maxValidIndex = geoSrc.fIndexCount;
+ break;
+ case kBuffer_GeometrySrcType:
+ maxValidIndex = geoSrc.fIndexBuffer->sizeInBytes() / sizeof(uint16_t);
+ break;
+ }
+ if (maxIndex > maxValidIndex) {
+ GrCrash("Index reads outside valid index range.");
+ }
+ }
+#endif
+ const GrDrawState& drawState = this->getDrawState();
+ if (NULL == drawState.getRenderTarget()) {
+ return false;
+ }
+ if (GrPixelConfigIsUnpremultiplied(drawState.getRenderTarget()->config())) {
+ if (kOne_BlendCoeff != drawState.getSrcBlendCoeff() ||
+ kZero_BlendCoeff != drawState.getDstBlendCoeff()) {
+ return false;
+ }
+ }
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ // We don't support using unpremultiplied textures with filters (other
+ // than nearest). Alpha-premulling is not distributive WRT to filtering.
+ // We'd have to filter each texel before filtering. We could do this for
+ // our custom filters but we would also have to disable bilerp and do
+ // a custom bilerp in the shader. Until Skia itself supports unpremul
+ // configs there is no pressure to implement this.
+ if (this->isStageEnabled(s) &&
+ GrPixelConfigIsUnpremultiplied(drawState.getTexture(s)->config()) &&
+ GrSamplerState::kNearest_Filter !=
+ drawState.getSampler(s).getFilter()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void GrDrawTarget::drawIndexed(GrPrimitiveType type, int startVertex,
+ int startIndex, int vertexCount,
+ int indexCount) {
+ if (indexCount > 0 &&
+ this->checkDraw(type, startVertex, startIndex,
+ vertexCount, indexCount)) {
+ this->onDrawIndexed(type, startVertex, startIndex,
+ vertexCount, indexCount);
+ }
+}
+
+void GrDrawTarget::drawNonIndexed(GrPrimitiveType type,
+ int startVertex,
+ int vertexCount) {
+ if (vertexCount > 0 &&
+ this->checkDraw(type, startVertex, -1, vertexCount, -1)) {
+ this->onDrawNonIndexed(type, startVertex, vertexCount);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Some blend modes allow folding a partial coverage value into the color's
+// alpha channel, while others will blend incorrectly.
+bool GrDrawTarget::canTweakAlphaForCoverage() const {
+ /**
+ * The fractional coverage is f
+ * The src and dst coeffs are Cs and Cd
+ * The dst and src colors are S and D
+ * We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D
+ * By tweaking the source color's alpha we're replacing S with S'=fS. It's
+ * obvious that that first term will always be ok. The second term can be
+ * rearranged as [1-(1-Cd)f]D. By substituing in the various possbilities
+ * for Cd we find that only 1, ISA, and ISC produce the correct depth
+ * coeffecient in terms of S' and D.
+ */
+ GrBlendCoeff dstCoeff = this->getDrawState().getDstBlendCoeff();
+ return kOne_BlendCoeff == dstCoeff ||
+ kISA_BlendCoeff == dstCoeff ||
+ kISC_BlendCoeff == dstCoeff;
+}
+
+
+bool GrDrawTarget::srcAlphaWillBeOne() const {
+ const GrVertexLayout& layout = this->getGeomSrc().fVertexLayout;
+ const GrDrawState& drawState = this->getDrawState();
+
+ // Check if per-vertex or constant color may have partial alpha
+ if ((layout & kColor_VertexLayoutBit) ||
+ 0xff != GrColorUnpackA(drawState.getColor())) {
+ return false;
+ }
+ // Check if color filter could introduce an alpha
+ // (TODO: Consider being more aggressive with regards to detecting 0xff
+ // final alpha from color filter).
+ if (SkXfermode::kDst_Mode != drawState.getColorFilterMode()) {
+ return false;
+ }
+ // Check if a color stage could create a partial alpha
+ for (int s = 0; s < drawState.getFirstCoverageStage(); ++s) {
+ if (StageWillBeUsed(s, layout, fCurrDrawState)) {
+ GrAssert(NULL != drawState.getTexture(s));
+ GrPixelConfig config = drawState.getTexture(s)->config();
+ if (!GrPixelConfigIsOpaque(config)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+GrDrawTarget::BlendOptFlags
+GrDrawTarget::getBlendOpts(bool forceCoverage,
+ GrBlendCoeff* srcCoeff,
+ GrBlendCoeff* dstCoeff) const {
+
+ const GrVertexLayout& layout = this->getGeomSrc().fVertexLayout;
+ const GrDrawState& drawState = this->getDrawState();
+
+ GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
+ if (NULL == srcCoeff) {
+ srcCoeff = &bogusSrcCoeff;
+ }
+ *srcCoeff = drawState.getSrcBlendCoeff();
+
+ if (NULL == dstCoeff) {
+ dstCoeff = &bogusDstCoeff;
+ }
+ *dstCoeff = drawState.getDstBlendCoeff();
+
+ // We don't ever expect source coeffecients to reference the source
+ GrAssert(kSA_BlendCoeff != *srcCoeff &&
+ kISA_BlendCoeff != *srcCoeff &&
+ kSC_BlendCoeff != *srcCoeff &&
+ kISC_BlendCoeff != *srcCoeff);
+ // same for dst
+ GrAssert(kDA_BlendCoeff != *dstCoeff &&
+ kIDA_BlendCoeff != *dstCoeff &&
+ kDC_BlendCoeff != *dstCoeff &&
+ kIDC_BlendCoeff != *dstCoeff);
+
+ if (drawState.isColorWriteDisabled()) {
+ *srcCoeff = kZero_BlendCoeff;
+ *dstCoeff = kOne_BlendCoeff;
+ }
+
+ bool srcAIsOne = this->srcAlphaWillBeOne();
+ bool dstCoeffIsOne = kOne_BlendCoeff == *dstCoeff ||
+ (kSA_BlendCoeff == *dstCoeff && srcAIsOne);
+ bool dstCoeffIsZero = kZero_BlendCoeff == *dstCoeff ||
+ (kISA_BlendCoeff == *dstCoeff && srcAIsOne);
+
+
+ // When coeffs are (0,1) there is no reason to draw at all, unless
+ // stenciling is enabled. Having color writes disabled is effectively
+ // (0,1).
+ if ((kZero_BlendCoeff == *srcCoeff && dstCoeffIsOne)) {
+ if (drawState.getStencil().doesWrite()) {
+ return kDisableBlend_BlendOptFlag |
+ kEmitTransBlack_BlendOptFlag;
+ } else {
+ return kSkipDraw_BlendOptFlag;
+ }
+ }
+
+ // check for coverage due to edge aa or coverage texture stage
+ bool hasCoverage = forceCoverage ||
+ drawState.getNumAAEdges() > 0 ||
+ (layout & kCoverage_VertexLayoutBit) ||
+ (layout & kEdge_VertexLayoutBit);
+ for (int s = drawState.getFirstCoverageStage();
+ !hasCoverage && s < GrDrawState::kNumStages;
+ ++s) {
+ if (StageWillBeUsed(s, layout, fCurrDrawState)) {
+ hasCoverage = true;
+ }
+ }
+
+ // if we don't have coverage we can check whether the dst
+ // has to read at all. If not, we'll disable blending.
+ if (!hasCoverage) {
+ if (dstCoeffIsZero) {
+ if (kOne_BlendCoeff == *srcCoeff) {
+ // if there is no coverage and coeffs are (1,0) then we
+ // won't need to read the dst at all, it gets replaced by src
+ return kDisableBlend_BlendOptFlag;
+ } else if (kZero_BlendCoeff == *srcCoeff) {
+ // if the op is "clear" then we don't need to emit a color
+ // or blend, just write transparent black into the dst.
+ *srcCoeff = kOne_BlendCoeff;
+ *dstCoeff = kZero_BlendCoeff;
+ return kDisableBlend_BlendOptFlag |
+ kEmitTransBlack_BlendOptFlag;
+ }
+ }
+ } else {
+ // check whether coverage can be safely rolled into alpha
+ // of if we can skip color computation and just emit coverage
+ if (this->canTweakAlphaForCoverage()) {
+ return kCoverageAsAlpha_BlendOptFlag;
+ }
+ if (dstCoeffIsZero) {
+ if (kZero_BlendCoeff == *srcCoeff) {
+ // the source color is not included in the blend
+ // the dst coeff is effectively zero so blend works out to:
+ // (c)(0)D + (1-c)D = (1-c)D.
+ *dstCoeff = kISA_BlendCoeff;
+ return kEmitCoverage_BlendOptFlag;
+ } else if (srcAIsOne) {
+ // the dst coeff is effectively zero so blend works out to:
+ // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
+ // If Sa is 1 then we can replace Sa with c
+ // and set dst coeff to 1-Sa.
+ *dstCoeff = kISA_BlendCoeff;
+ return kCoverageAsAlpha_BlendOptFlag;
+ }
+ } else if (dstCoeffIsOne) {
+ // the dst coeff is effectively one so blend works out to:
+ // cS + (c)(1)D + (1-c)D = cS + D.
+ *dstCoeff = kOne_BlendCoeff;
+ return kCoverageAsAlpha_BlendOptFlag;
+ }
+ }
+ return kNone_BlendOpt;
+}
+
+bool GrDrawTarget::willUseHWAALines() const {
+ // there is a conflict between using smooth lines and our use of
+ // premultiplied alpha. Smooth lines tweak the incoming alpha value
+ // but not in a premul-alpha way. So we only use them when our alpha
+ // is 0xff and tweaking the color for partial coverage is OK
+ if (!fCaps.fHWAALineSupport ||
+ !this->getDrawState().isHWAntialiasState()) {
+ return false;
+ }
+ BlendOptFlags opts = this->getBlendOpts();
+ return (kDisableBlend_BlendOptFlag & opts) &&
+ (kCoverageAsAlpha_BlendOptFlag & opts);
+}
+
+bool GrDrawTarget::canApplyCoverage() const {
+ // we can correctly apply coverage if a) we have dual source blending
+ // or b) one of our blend optimizations applies.
+ return this->getCaps().fDualSourceBlendingSupport ||
+ kNone_BlendOpt != this->getBlendOpts(true);
+}
+
+bool GrDrawTarget::drawWillReadDst() const {
+ return SkToBool((kDisableBlend_BlendOptFlag | kSkipDraw_BlendOptFlag) &
+ this->getBlendOpts());
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrDrawTarget::drawRect(const GrRect& rect,
+ const GrMatrix* matrix,
+ StageMask stageMask,
+ const GrRect* srcRects[],
+ const GrMatrix* srcMatrices[]) {
+ GrVertexLayout layout = GetRectVertexLayout(stageMask, srcRects);
+
+ AutoReleaseGeometry geo(this, layout, 4, 0);
+ if (!geo.succeeded()) {
+ GrPrintf("Failed to get space for vertices!\n");
+ return;
+ }
+
+ SetRectVertices(rect, matrix, srcRects,
+ srcMatrices, layout, geo.vertices());
+
+ drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
+}
+
+GrVertexLayout GrDrawTarget::GetRectVertexLayout(StageMask stageMask,
+ const GrRect* srcRects[]) {
+ GrVertexLayout layout = 0;
+
+ for (int i = 0; i < GrDrawState::kNumStages; ++i) {
+ int numTC = 0;
+ if (stageMask & (1 << i)) {
+ if (NULL != srcRects && NULL != srcRects[i]) {
+ layout |= StageTexCoordVertexLayoutBit(i, numTC);
+ ++numTC;
+ } else {
+ layout |= StagePosAsTexCoordVertexLayoutBit(i);
+ }
+ }
+ }
+ return layout;
+}
+
+void GrDrawTarget::clipWillBeSet(const GrClip& clip) {
+}
+
+void GrDrawTarget::SetRectVertices(const GrRect& rect,
+ const GrMatrix* matrix,
+ const GrRect* srcRects[],
+ const GrMatrix* srcMatrices[],
+ GrVertexLayout layout,
+ void* vertices) {
+#if GR_DEBUG
+ // check that the layout and srcRects agree
+ for (int i = 0; i < GrDrawState::kNumStages; ++i) {
+ if (VertexTexCoordsForStage(i, layout) >= 0) {
+ GR_DEBUGASSERT(NULL != srcRects && NULL != srcRects[i]);
+ } else {
+ GR_DEBUGASSERT(NULL == srcRects || NULL == srcRects[i]);
+ }
+ }
+#endif
+
+ int stageOffsets[GrDrawState::kNumStages];
+ int vsize = VertexSizeAndOffsetsByStage(layout, stageOffsets,
+ NULL, NULL, NULL);
+
+ GrTCast<GrPoint*>(vertices)->setRectFan(rect.fLeft, rect.fTop,
+ rect.fRight, rect.fBottom,
+ vsize);
+ if (NULL != matrix) {
+ matrix->mapPointsWithStride(GrTCast<GrPoint*>(vertices), vsize, 4);
+ }
+
+ for (int i = 0; i < GrDrawState::kNumStages; ++i) {
+ if (stageOffsets[i] > 0) {
+ GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(vertices) +
+ stageOffsets[i]);
+ coords->setRectFan(srcRects[i]->fLeft, srcRects[i]->fTop,
+ srcRects[i]->fRight, srcRects[i]->fBottom,
+ vsize);
+ if (NULL != srcMatrices && NULL != srcMatrices[i]) {
+ srcMatrices[i]->mapPointsWithStride(coords, vsize, 4);
+ }
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+GrDrawTarget::AutoStateRestore::AutoStateRestore() {
+ fDrawTarget = NULL;
+}
+
+GrDrawTarget::AutoStateRestore::AutoStateRestore(GrDrawTarget* target) {
+ fDrawTarget = target;
+ if (NULL != fDrawTarget) {
+ fDrawTarget->saveCurrentDrawState(&fDrawState);
+ }
+}
+
+GrDrawTarget::AutoStateRestore::~AutoStateRestore() {
+ if (NULL != fDrawTarget) {
+ fDrawTarget->restoreDrawState(fDrawState);
+ }
+}
+
+void GrDrawTarget::AutoStateRestore::set(GrDrawTarget* target) {
+ if (target != fDrawTarget) {
+ if (NULL != fDrawTarget) {
+ fDrawTarget->restoreDrawState(fDrawState);
+ }
+ if (NULL != target) {
+ target->saveCurrentDrawState(&fDrawState);
+ }
+ fDrawTarget = target;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+GrDrawTarget::AutoDeviceCoordDraw::AutoDeviceCoordDraw(
+ GrDrawTarget* target,
+ GrDrawState::StageMask stageMask) {
+ GrAssert(NULL != target);
+ GrDrawState* drawState = target->drawState();
+
+ fDrawTarget = target;
+ fViewMatrix = drawState->getViewMatrix();
+ fStageMask = stageMask;
+ if (fStageMask) {
+ GrMatrix invVM;
+ if (fViewMatrix.invert(&invVM)) {
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ if (fStageMask & (1 << s)) {
+ fSamplerMatrices[s] = drawState->getSampler(s).getMatrix();
+ }
+ }
+ drawState->preConcatSamplerMatrices(fStageMask, invVM);
+ } else {
+ // sad trombone sound
+ fStageMask = 0;
+ }
+ }
+ drawState->setViewMatrix(GrMatrix::I());
+}
+
+GrDrawTarget::AutoDeviceCoordDraw::~AutoDeviceCoordDraw() {
+ GrDrawState* drawState = fDrawTarget->drawState();
+ drawState->setViewMatrix(fViewMatrix);
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ if (fStageMask & (1 << s)) {
+ *drawState->sampler(s)->matrix() = fSamplerMatrices[s];
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+GrDrawTarget::AutoReleaseGeometry::AutoReleaseGeometry(
+ GrDrawTarget* target,
+ GrVertexLayout vertexLayout,
+ int vertexCount,
+ int indexCount) {
+ fTarget = NULL;
+ this->set(target, vertexLayout, vertexCount, indexCount);
+}
+
+GrDrawTarget::AutoReleaseGeometry::AutoReleaseGeometry() {
+ fTarget = NULL;
+}
+
+GrDrawTarget::AutoReleaseGeometry::~AutoReleaseGeometry() {
+ this->reset();
+}
+
+bool GrDrawTarget::AutoReleaseGeometry::set(GrDrawTarget* target,
+ GrVertexLayout vertexLayout,
+ int vertexCount,
+ int indexCount) {
+ this->reset();
+ fTarget = target;
+ bool success = true;
+ if (NULL != fTarget) {
+ fTarget = target;
+ if (vertexCount > 0) {
+ success = target->reserveVertexSpace(vertexLayout,
+ vertexCount,
+ &fVertices);
+ if (!success) {
+ this->reset();
+ }
+ }
+ if (success && indexCount > 0) {
+ success = target->reserveIndexSpace(indexCount, &fIndices);
+ if (!success) {
+ this->reset();
+ }
+ }
+ }
+ GrAssert(success == (NULL != fTarget));
+ return success;
+}
+
+void GrDrawTarget::AutoReleaseGeometry::reset() {
+ if (NULL != fTarget) {
+ if (NULL != fVertices) {
+ fTarget->resetVertexSource();
+ }
+ if (NULL != fIndices) {
+ fTarget->resetIndexSource();
+ }
+ fTarget = NULL;
+ }
+ fVertices = NULL;
+ fIndices = NULL;
+}
+
+void GrDrawTarget::Caps::print() const {
+ static const char* gNY[] = {"NO", "YES"};
+ GrPrintf("8 Bit Palette Support : %s\n", gNY[f8BitPaletteSupport]);
+ GrPrintf("NPOT Texture Tile Support : %s\n", gNY[fNPOTTextureTileSupport]);
+ GrPrintf("Two Sided Stencil Support : %s\n", gNY[fTwoSidedStencilSupport]);
+ GrPrintf("Stencil Wrap Ops Support : %s\n", gNY[fStencilWrapOpsSupport]);
+ GrPrintf("HW AA Lines Support : %s\n", gNY[fHWAALineSupport]);
+ GrPrintf("Shader Derivative Support : %s\n", gNY[fShaderDerivativeSupport]);
+ GrPrintf("Geometry Shader Support : %s\n", gNY[fGeometryShaderSupport]);
+ GrPrintf("FSAA Support : %s\n", gNY[fFSAASupport]);
+ GrPrintf("Dual Source Blending Support: %s\n", gNY[fDualSourceBlendingSupport]);
+ GrPrintf("Buffer Lock Support : %s\n", gNY[fBufferLockSupport]);
+ GrPrintf("Max Texture Size : %d\n", fMaxTextureSize);
+ GrPrintf("Max Render Target Size : %d\n", fMaxRenderTargetSize);
+}
+
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
new file mode 100644
index 0000000..d52565d
--- /dev/null
+++ b/src/gpu/GrDrawTarget.h
@@ -0,0 +1,1016 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrDrawTarget_DEFINED
+#define GrDrawTarget_DEFINED
+
+#include "GrClip.h"
+#include "GrColor.h"
+#include "GrDrawState.h"
+#include "GrMatrix.h"
+#include "GrRefCnt.h"
+#include "GrSamplerState.h"
+#include "GrStencil.h"
+#include "GrTexture.h"
+
+#include "SkXfermode.h"
+
+class GrTexture;
+class GrClipIterator;
+class GrVertexBuffer;
+class GrIndexBuffer;
+
+class GrDrawTarget : public GrRefCnt {
+public:
+ /**
+ * Represents the draw target capabilities.
+ */
+ struct Caps {
+ Caps() { memset(this, 0, sizeof(Caps)); }
+ Caps(const Caps& c) { *this = c; }
+ Caps& operator= (const Caps& c) {
+ memcpy(this, &c, sizeof(Caps));
+ return *this;
+ }
+ void print() const;
+ bool f8BitPaletteSupport : 1;
+ bool fNPOTTextureTileSupport : 1;
+ bool fTwoSidedStencilSupport : 1;
+ bool fStencilWrapOpsSupport : 1;
+ bool fHWAALineSupport : 1;
+ bool fShaderDerivativeSupport : 1;
+ bool fGeometryShaderSupport : 1;
+ bool fFSAASupport : 1;
+ bool fDualSourceBlendingSupport : 1;
+ bool fBufferLockSupport : 1;
+ bool fSupportPerVertexCoverage : 1;
+ int fMaxRenderTargetSize;
+ int fMaxTextureSize;
+ };
+
+ // for convenience
+ typedef GrDrawState::StageMask StageMask;
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ GrDrawTarget();
+ virtual ~GrDrawTarget();
+
+ /**
+ * Gets the capabilities of the draw target.
+ */
+ const Caps& getCaps() const { return fCaps; }
+
+ /**
+ * Sets the current clip to the region specified by clip. All draws will be
+ * clipped against this clip if kClip_StateBit is enabled.
+ *
+ * Setting the clip may (or may not) zero out the client's stencil bits.
+ *
+ * @param description of the clipping region
+ */
+ void setClip(const GrClip& clip);
+
+ /**
+ * Gets the current clip.
+ *
+ * @return the clip.
+ */
+ const GrClip& getClip() const;
+
+ const GrDrawState& getDrawState() const { return fCurrDrawState; }
+ GrDrawState* drawState() { return &fCurrDrawState; }
+
+ /**
+ * Shortcut for drawState()->preConcatSamplerMatrices() on all enabled
+ * stages
+ *
+ * @param matrix the matrix to concat
+ */
+ void preConcatEnabledSamplerMatrices(const GrMatrix& matrix) {
+ StageMask stageMask = this->enabledStages();
+ this->drawState()->preConcatSamplerMatrices(stageMask, matrix);
+ }
+
+ /**
+ * Determines if blending will require a read of a dst given the current
+ * state set on the draw target
+ *
+ * @return true if the dst surface will be read at each pixel hit by the
+ * a draw operation.
+ */
+ bool drawWillReadDst() const;
+
+ /**
+ * Color alpha and coverage are two inputs to the drawing pipeline. For some
+ * blend modes it is safe to fold the coverage into constant or per-vertex
+ * color alpha value. For other blend modes they must be handled separately.
+ * Depending on features available in the underlying 3D API this may or may
+ * not be possible.
+ *
+ * This function looks at the current blend on the draw target and the draw
+ * target's capabilities to determine whether coverage can be handled
+ * correctly.
+ */
+ bool canApplyCoverage() const;
+
+ /**
+ * Determines whether incorporating partial pixel coverage into the constant
+ * color specified by setColor or per-vertex colors will give the right
+ * blending result.
+ */
+ bool canTweakAlphaForCoverage() const;
+
+ /**
+ * Given the current draw state, vertex layout, and hw support, will HW AA
+ * lines be used (if line primitive type is drawn)? (Note that lines are
+ * always 1 pixel wide)
+ */
+ bool willUseHWAALines() const;
+
+ /**
+ * Used to save and restore the GrGpu's drawing state
+ */
+ struct SavedDrawState {
+ private:
+ GrDrawState fState;
+ friend class GrDrawTarget;
+ };
+
+ /**
+ * Saves the current draw state. The state can be restored at a later time
+ * with restoreDrawState.
+ *
+ * See also AutoStateRestore class.
+ *
+ * @param state will hold the state after the function returns.
+ */
+ void saveCurrentDrawState(SavedDrawState* state) const;
+
+ /**
+ * Restores previously saved draw state. The client guarantees that state
+ * was previously passed to saveCurrentDrawState and that the rendertarget
+ * and texture set at save are still valid.
+ *
+ * See also AutoStateRestore class.
+ *
+ * @param state the previously saved state to restore.
+ */
+ void restoreDrawState(const SavedDrawState& state);
+
+ /**
+ * Copies the draw state from another target to this target.
+ *
+ * @param srcTarget draw target used as src of the draw state.
+ */
+ void copyDrawState(const GrDrawTarget& srcTarget);
+
+ /**
+ * The format of vertices is represented as a bitfield of flags.
+ * Flags that indicate the layout of vertex data. Vertices always contain
+ * positions and may also contain up to GrDrawState::kMaxTexCoords sets
+ * of 2D texture * coordinates, per-vertex colors, and per-vertex coverage.
+ * Each stage can
+ * use any of the texture coordinates as its input texture coordinates or it
+ * may use the positions as texture coordinates.
+ *
+ * If no texture coordinates are specified for a stage then the stage is
+ * disabled.
+ *
+ * Only one type of texture coord can be specified per stage. For
+ * example StageTexCoordVertexLayoutBit(0, 2) and
+ * StagePosAsTexCoordVertexLayoutBit(0) cannot both be specified.
+ *
+ * The order in memory is always (position, texture coord 0, ..., color,
+ * coverage) with any unused fields omitted. Note that this means that if
+ * only texture coordinates 1 is referenced then there is no texture
+ * coordinates 0 and the order would be (position, texture coordinate 1
+ * [, color][, coverage]).
+ */
+
+ /**
+ * Generates a bit indicating that a texture stage uses texture coordinates
+ *
+ * @param stage the stage that will use texture coordinates.
+ * @param texCoordIdx the index of the texture coordinates to use
+ *
+ * @return the bit to add to a GrVertexLayout bitfield.
+ */
+ static int StageTexCoordVertexLayoutBit(int stage, int texCoordIdx) {
+ GrAssert(stage < GrDrawState::kNumStages);
+ GrAssert(texCoordIdx < GrDrawState::kMaxTexCoords);
+ return 1 << (stage + (texCoordIdx * GrDrawState::kNumStages));
+ }
+
+private:
+ static const int TEX_COORD_BIT_CNT = GrDrawState::kNumStages *
+ GrDrawState::kMaxTexCoords;
+
+public:
+ /**
+ * Generates a bit indicating that a texture stage uses the position
+ * as its texture coordinate.
+ *
+ * @param stage the stage that will use position as texture
+ * coordinates.
+ *
+ * @return the bit to add to a GrVertexLayout bitfield.
+ */
+ static int StagePosAsTexCoordVertexLayoutBit(int stage) {
+ GrAssert(stage < GrDrawState::kNumStages);
+ return (1 << (TEX_COORD_BIT_CNT + stage));
+ }
+
+private:
+ static const int STAGE_BIT_CNT = TEX_COORD_BIT_CNT +
+ GrDrawState::kNumStages;
+
+public:
+
+ /**
+ * Additional Bits that can be specified in GrVertexLayout.
+ */
+ enum VertexLayoutBits {
+ /* vertices have colors (GrColor) */
+ kColor_VertexLayoutBit = 1 << (STAGE_BIT_CNT + 0),
+ /* vertices have coverage (GrColor where all channels should have the
+ * same value)
+ */
+ kCoverage_VertexLayoutBit = 1 << (STAGE_BIT_CNT + 1),
+ /* Use text vertices. (Pos and tex coords may be a different type for
+ * text [GrGpuTextVertex vs GrPoint].)
+ */
+ kTextFormat_VertexLayoutBit = 1 << (STAGE_BIT_CNT + 2),
+
+ /* Each vertex specificies an edge. Distance to the edge is used to
+ * compute a coverage. See GrDrawState::setVertexEdgeType().
+ */
+ kEdge_VertexLayoutBit = 1 << (STAGE_BIT_CNT + 3),
+ // for below assert
+ kDummyVertexLayoutBit,
+ kHighVertexLayoutBit = kDummyVertexLayoutBit - 1
+ };
+ // make sure we haven't exceeded the number of bits in GrVertexLayout.
+ GR_STATIC_ASSERT(kHighVertexLayoutBit < ((uint64_t)1 << 8*sizeof(GrVertexLayout)));
+
+ /**
+ * There are three methods for specifying geometry (vertices and optionally
+ * indices) to the draw target. When indexed drawing the indices and vertices
+ * can use a different method. Once geometry is specified it can be used for
+ * multiple drawIndexed and drawNonIndexed calls.
+ *
+ * Sometimes it is necessary to perform a draw while upstack code has
+ * already specified geometry that it isn't finished with. There are push
+ * pop methods
+ *
+ * 1. Provide a cpu array (set*SourceToArray). This is useful when the
+ * caller's client has already provided vertex data in a format
+ * the time compatible with a GrVertexLayout. The array must contain the
+ * data at set*SourceToArray is called. The source stays in effect for
+ * drawIndexed & drawNonIndexed calls until set*SourceToArray is called
+ * again or one of the other two paths is chosen.
+ *
+ * 2. Reserve. This is most useful when the caller has data it must
+ * transform before drawing and is not long-lived. The caller requests
+ * that the draw target make room for some amount of vertex and/or index
+ * data. The target provides ptrs to hold the vertex and/or index data.
+ *
+ * The data is writable up until the next drawIndexed, drawNonIndexed,
+ * or pushGeometrySource At this point the data is frozen and the ptrs
+ * are no longer valid.
+ *
+ * 3. Vertex and Index Buffers. This is most useful for geometry that will
+ * is long-lived. SetVertexSourceToBuffer and SetIndexSourceToBuffer are
+ * used to set the buffer and subsequent drawIndexed and drawNonIndexed
+ * calls use this source until another source is set.
+ */
+
+ /**
+ * Reserves space for vertices. Draw target will use reserved vertices at
+ * at the next draw.
+ *
+ * If succeeds:
+ * if vertexCount > 0, *vertices will be the array
+ * of vertices to be filled by caller. The next draw will read
+ * these vertices.
+ *
+ * If a client does not already have a vertex buffer then this is the
+ * preferred way to allocate vertex data. It allows the subclass of
+ * GrDrawTarget to decide whether to put data in buffers, to group vertex
+ * data that uses the same state (e.g. for deferred rendering), etc.
+ *
+ * After the next draw or pushGeometrySource the vertices ptr is no longer
+ * valid and the geometry data cannot be further modified. The contents
+ * that were put in the reserved space can be drawn by multiple draws,
+ * however.
+ *
+ * @param vertexLayout the format of vertices (ignored if vertexCount == 0).
+ * @param vertexCount the number of vertices to reserve space for. Can be 0.
+ * @param vertices will point to reserved vertex space if vertexCount is
+ * non-zero. Illegal to pass NULL if vertexCount > 0.
+ *
+ * @return true if succeeded in allocating space for the vertices and false
+ * if not.
+ */
+ bool reserveVertexSpace(GrVertexLayout vertexLayout,
+ int vertexCount,
+ void** vertices);
+ /**
+ * Reserves space for indices. Draw target will use the reserved indices at
+ * the next indexed draw.
+ *
+ * If succeeds:
+ * if indexCount > 0, *indices will be the array
+ * of indices to be filled by caller. The next draw will read
+ * these indices.
+ *
+ * If a client does not already have a index buffer then this is the
+ * preferred way to allocate index data. It allows the subclass of
+ * GrDrawTarget to decide whether to put data in buffers, to group index
+ * data that uses the same state (e.g. for deferred rendering), etc.
+ *
+ * After the next indexed draw or pushGeometrySource the indices ptr is no
+ * longer valid and the geometry data cannot be further modified. The
+ * contents that were put in the reserved space can be drawn by multiple
+ * draws, however.
+ *
+ * @param indexCount the number of indices to reserve space for. Can be 0.
+ * @param indices will point to reserved index space if indexCount is
+ * non-zero. Illegal to pass NULL if indexCount > 0.
+ */
+
+ bool reserveIndexSpace(int indexCount, void** indices);
+ /**
+ * Provides hints to caller about the number of vertices and indices
+ * that can be allocated cheaply. This can be useful if caller is reserving
+ * space but doesn't know exactly how much geometry is needed.
+ *
+ * Also may hint whether the draw target should be flushed first. This is
+ * useful for deferred targets.
+ *
+ * @param vertexLayout layout of vertices caller would like to reserve
+ * @param vertexCount in: hint about how many vertices the caller would
+ * like to allocate.
+ * out: a hint about the number of vertices that can be
+ * allocated cheaply. Negative means no hint.
+ * Ignored if NULL.
+ * @param indexCount in: hint about how many indices the caller would
+ * like to allocate.
+ * out: a hint about the number of indices that can be
+ * allocated cheaply. Negative means no hint.
+ * Ignored if NULL.
+ *
+ * @return true if target should be flushed based on the input values.
+ */
+ virtual bool geometryHints(GrVertexLayout vertexLayout,
+ int* vertexCount,
+ int* indexCount) const;
+
+ /**
+ * Sets source of vertex data for the next draw. Array must contain
+ * the vertex data when this is called.
+ *
+ * @param array cpu array containing vertex data.
+ * @param size size of the vertex data.
+ * @param vertexCount the number of vertices in the array.
+ */
+ void setVertexSourceToArray(GrVertexLayout vertexLayout,
+ const void* vertexArray,
+ int vertexCount);
+
+ /**
+ * Sets source of index data for the next indexed draw. Array must contain
+ * the indices when this is called.
+ *
+ * @param array cpu array containing index data.
+ * @param indexCount the number of indices in the array.
+ */
+ void setIndexSourceToArray(const void* indexArray, int indexCount);
+
+ /**
+ * Sets source of vertex data for the next draw. Data does not have to be
+ * in the buffer until drawIndexed or drawNonIndexed.
+ *
+ * @param buffer vertex buffer containing vertex data. Must be
+ * unlocked before draw call.
+ * @param vertexLayout layout of the vertex data in the buffer.
+ */
+ void setVertexSourceToBuffer(GrVertexLayout vertexLayout,
+ const GrVertexBuffer* buffer);
+
+ /**
+ * Sets source of index data for the next indexed draw. Data does not have
+ * to be in the buffer until drawIndexed or drawNonIndexed.
+ *
+ * @param buffer index buffer containing indices. Must be unlocked
+ * before indexed draw call.
+ */
+ void setIndexSourceToBuffer(const GrIndexBuffer* buffer);
+
+ /**
+ * Resets vertex source. Drawing from reset vertices is illegal. Set vertex
+ * source to reserved, array, or buffer before next draw. May be able to free
+ * up temporary storage allocated by setVertexSourceToArray or
+ * reserveVertexSpace.
+ */
+ void resetVertexSource();
+
+ /**
+ * Resets index source. Indexed Drawing from reset indices is illegal. Set
+ * index source to reserved, array, or buffer before next indexed draw. May
+ * be able to free up temporary storage allocated by setIndexSourceToArray
+ * or reserveIndexSpace.
+ */
+ void resetIndexSource();
+
+ /**
+ * Pushes and resets the vertex/index sources. Any reserved vertex / index
+ * data is finalized (i.e. cannot be updated after the matching pop but can
+ * be drawn from). Must be balanced by a pop.
+ */
+ void pushGeometrySource();
+
+ /**
+ * Pops the vertex / index sources from the matching push.
+ */
+ void popGeometrySource();
+
+ /**
+ * Draws indexed geometry using the current state and current vertex / index
+ * sources.
+ *
+ * @param type The type of primitives to draw.
+ * @param startVertex the vertex in the vertex array/buffer corresponding
+ * to index 0
+ * @param startIndex first index to read from index src.
+ * @param vertexCount one greater than the max index.
+ * @param indexCount the number of index elements to read. The index count
+ * is effectively trimmed to the last completely
+ * specified primitive.
+ */
+ void drawIndexed(GrPrimitiveType type,
+ int startVertex,
+ int startIndex,
+ int vertexCount,
+ int indexCount);
+
+ /**
+ * Draws non-indexed geometry using the current state and current vertex
+ * sources.
+ *
+ * @param type The type of primitives to draw.
+ * @param startVertex the vertex in the vertex array/buffer corresponding
+ * to index 0
+ * @param vertexCount one greater than the max index.
+ */
+ void drawNonIndexed(GrPrimitiveType type,
+ int startVertex,
+ int vertexCount);
+
+ /**
+ * Helper function for drawing rects. This does not use the current index
+ * and vertex sources. After returning, the vertex and index sources may
+ * have changed. They should be reestablished before the next drawIndexed
+ * or drawNonIndexed. This cannot be called between reserving and releasing
+ * geometry. The GrDrawTarget subclass may be able to perform additional
+ * optimizations if drawRect is used rather than drawIndexed or
+ * drawNonIndexed.
+ * @param rect the rect to draw
+ * @param matrix optional matrix applied to rect (before viewMatrix)
+ * @param stageMask bitmask indicating which stages are enabled.
+ * Bit i indicates whether stage i is enabled.
+ * @param srcRects specifies rects for stages enabled by stageEnableMask.
+ * if stageEnableMask bit i is 1, srcRects is not NULL,
+ * and srcRects[i] is not NULL, then srcRects[i] will be
+ * used as coordinates for stage i. Otherwise, if stage i
+ * is enabled then rect is used as the coordinates.
+ * @param srcMatrices optional matrices applied to srcRects. If
+ * srcRect[i] is non-NULL and srcMatrices[i] is
+ * non-NULL then srcRect[i] will be transformed by
+ * srcMatrix[i]. srcMatrices can be NULL when no
+ * srcMatrices are desired.
+ */
+ virtual void drawRect(const GrRect& rect,
+ const GrMatrix* matrix,
+ StageMask stageMask,
+ const GrRect* srcRects[],
+ const GrMatrix* srcMatrices[]);
+
+ /**
+ * Helper for drawRect when the caller doesn't need separate src rects or
+ * matrices.
+ */
+ void drawSimpleRect(const GrRect& rect,
+ const GrMatrix* matrix,
+ StageMask stageEnableBitfield) {
+ drawRect(rect, matrix, stageEnableBitfield, NULL, NULL);
+ }
+
+ /**
+ * Clear the render target. Ignores the clip and all other draw state
+ * (blend mode, stages, etc). Clears the whole thing if rect is NULL,
+ * otherwise just the rect.
+ */
+ virtual void clear(const GrIRect* rect, GrColor color) = 0;
+
+ /**
+ * Returns the maximum number of edges that may be specified in a single
+ * draw call when performing edge antialiasing. This is usually limited
+ * by the number of fragment uniforms which may be uploaded. Must be a
+ * minimum of six, since a triangle's vertices each belong to two boundary
+ * edges which may be distinct.
+ */
+ virtual int getMaxEdges() const { return 6; }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ class AutoStateRestore : ::GrNoncopyable {
+ public:
+ AutoStateRestore();
+ AutoStateRestore(GrDrawTarget* target);
+ ~AutoStateRestore();
+
+ /**
+ * if this object is already saving state for param target then
+ * this does nothing. Otherise, it restores previously saved state on
+ * previous target (if any) and saves current state on param target.
+ */
+ void set(GrDrawTarget* target);
+
+ private:
+ GrDrawTarget* fDrawTarget;
+ SavedDrawState fDrawState;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Sets the view matrix to I and preconcats all stage matrices enabled in
+ * mask by the view inverse. Destructor undoes these changes.
+ */
+ class AutoDeviceCoordDraw : ::GrNoncopyable {
+ public:
+ AutoDeviceCoordDraw(GrDrawTarget* target, StageMask stageMask);
+ ~AutoDeviceCoordDraw();
+ private:
+ GrDrawTarget* fDrawTarget;
+ GrMatrix fViewMatrix;
+ GrMatrix fSamplerMatrices[GrDrawState::kNumStages];
+ int fStageMask;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ class AutoReleaseGeometry : ::GrNoncopyable {
+ public:
+ AutoReleaseGeometry(GrDrawTarget* target,
+ GrVertexLayout vertexLayout,
+ int vertexCount,
+ int indexCount);
+ AutoReleaseGeometry();
+ ~AutoReleaseGeometry();
+ bool set(GrDrawTarget* target,
+ GrVertexLayout vertexLayout,
+ int vertexCount,
+ int indexCount);
+ bool succeeded() const { return NULL != fTarget; }
+ void* vertices() const { GrAssert(this->succeeded()); return fVertices; }
+ void* indices() const { GrAssert(this->succeeded()); return fIndices; }
+ GrPoint* positions() const {
+ return static_cast<GrPoint*>(this->vertices());
+ }
+
+ private:
+ void reset();
+
+ GrDrawTarget* fTarget;
+ void* fVertices;
+ void* fIndices;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ class AutoClipRestore : ::GrNoncopyable {
+ public:
+ AutoClipRestore(GrDrawTarget* target) {
+ fTarget = target;
+ fClip = fTarget->getClip();
+ }
+
+ ~AutoClipRestore() {
+ fTarget->setClip(fClip);
+ }
+ private:
+ GrDrawTarget* fTarget;
+ GrClip fClip;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ class AutoGeometryPush : ::GrNoncopyable {
+ public:
+ AutoGeometryPush(GrDrawTarget* target) {
+ GrAssert(NULL != target);
+ fTarget = target;
+ target->pushGeometrySource();
+ }
+ ~AutoGeometryPush() {
+ fTarget->popGeometrySource();
+ }
+ private:
+ GrDrawTarget* fTarget;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Helpers for picking apart vertex layouts
+
+ /**
+ * Helper function to compute the size of a vertex from a vertex layout
+ * @return size of a single vertex.
+ */
+ static size_t VertexSize(GrVertexLayout vertexLayout);
+
+ /**
+ * Helper function for determining the index of texture coordinates that
+ * is input for a texture stage. Note that a stage may instead use positions
+ * as texture coordinates, in which case the result of the function is
+ * indistinguishable from the case when the stage is disabled.
+ *
+ * @param stage the stage to query
+ * @param vertexLayout layout to query
+ *
+ * @return the texture coordinate index or -1 if the stage doesn't use
+ * separate (non-position) texture coordinates.
+ */
+ static int VertexTexCoordsForStage(int stage, GrVertexLayout vertexLayout);
+
+ /**
+ * Helper function to compute the offset of texture coordinates in a vertex
+ * @return offset of texture coordinates in vertex layout or -1 if the
+ * layout has no texture coordinates. Will be 0 if positions are
+ * used as texture coordinates for the stage.
+ */
+ static int VertexStageCoordOffset(int stage, GrVertexLayout vertexLayout);
+
+ /**
+ * Helper function to compute the offset of the color in a vertex
+ * @return offset of color in vertex layout or -1 if the
+ * layout has no color.
+ */
+ static int VertexColorOffset(GrVertexLayout vertexLayout);
+
+ /**
+ * Helper function to compute the offset of the coverage in a vertex
+ * @return offset of coverage in vertex layout or -1 if the
+ * layout has no coverage.
+ */
+ static int VertexCoverageOffset(GrVertexLayout vertexLayout);
+
+ /**
+ * Helper function to compute the offset of the edge pts in a vertex
+ * @return offset of edge in vertex layout or -1 if the
+ * layout has no edge.
+ */
+ static int VertexEdgeOffset(GrVertexLayout vertexLayout);
+
+ /**
+ * Helper function to determine if vertex layout contains explicit texture
+ * coordinates of some index.
+ *
+ * @param coordIndex the tex coord index to query
+ * @param vertexLayout layout to query
+ *
+ * @return true if vertex specifies texture coordinates for the index,
+ * false otherwise.
+ */
+ static bool VertexUsesTexCoordIdx(int coordIndex,
+ GrVertexLayout vertexLayout);
+
+ /**
+ * Helper function to determine if vertex layout contains either explicit or
+ * implicit texture coordinates for a stage.
+ *
+ * @param stage the stage to query
+ * @param vertexLayout layout to query
+ *
+ * @return true if vertex specifies texture coordinates for the stage,
+ * false otherwise.
+ */
+ static bool VertexUsesStage(int stage, GrVertexLayout vertexLayout);
+
+ /**
+ * Helper function to compute the size of each vertex and the offsets of
+ * texture coordinates and color. Determines tex coord offsets by tex coord
+ * index rather than by stage. (Each stage can be mapped to any t.c. index
+ * by StageTexCoordVertexLayoutBit.)
+ *
+ * @param vertexLayout the layout to query
+ * @param texCoordOffsetsByIdx after return it is the offset of each
+ * tex coord index in the vertex or -1 if
+ * index isn't used. (optional)
+ * @param colorOffset after return it is the offset of the
+ * color field in each vertex, or -1 if
+ * there aren't per-vertex colors. (optional)
+ * @param coverageOffset after return it is the offset of the
+ * coverage field in each vertex, or -1 if
+ * there aren't per-vertex coeverages.
+ * (optional)
+ * @param edgeOffset after return it is the offset of the
+ * edge eq field in each vertex, or -1 if
+ * there aren't per-vertex edge equations.
+ * (optional)
+ * @return size of a single vertex
+ */
+ static int VertexSizeAndOffsetsByIdx(GrVertexLayout vertexLayout,
+ int texCoordOffsetsByIdx[GrDrawState::kMaxTexCoords],
+ int *colorOffset,
+ int *coverageOffset,
+ int* edgeOffset);
+
+ /**
+ * Helper function to compute the size of each vertex and the offsets of
+ * texture coordinates and color. Determines tex coord offsets by stage
+ * rather than by index. (Each stage can be mapped to any t.c. index
+ * by StageTexCoordVertexLayoutBit.) If a stage uses positions for
+ * tex coords then that stage's offset will be 0 (positions are always at 0).
+ *
+ * @param vertexLayout the layout to query
+ * @param texCoordOffsetsByStage after return it is the offset of each
+ * tex coord index in the vertex or -1 if
+ * index isn't used. (optional)
+ * @param colorOffset after return it is the offset of the
+ * color field in each vertex, or -1 if
+ * there aren't per-vertex colors.
+ * (optional)
+ * @param coverageOffset after return it is the offset of the
+ * coverage field in each vertex, or -1 if
+ * there aren't per-vertex coeverages.
+ * (optional)
+ * @param edgeOffset after return it is the offset of the
+ * edge eq field in each vertex, or -1 if
+ * there aren't per-vertex edge equations.
+ * (optional)
+ * @return size of a single vertex
+ */
+ static int VertexSizeAndOffsetsByStage(GrVertexLayout vertexLayout,
+ int texCoordOffsetsByStage[GrDrawState::kNumStages],
+ int* colorOffset,
+ int* coverageOffset,
+ int* edgeOffset);
+
+ /**
+ * Accessing positions, texture coords, or colors, of a vertex within an
+ * array is a hassle involving casts and simple math. These helpers exist
+ * to keep GrDrawTarget clients' code a bit nicer looking.
+ */
+
+ /**
+ * Gets a pointer to a GrPoint of a vertex's position or texture
+ * coordinate.
+ * @param vertices the vetex array
+ * @param vertexIndex the index of the vertex in the array
+ * @param vertexSize the size of each vertex in the array
+ * @param offset the offset in bytes of the vertex component.
+ * Defaults to zero (corresponding to vertex position)
+ * @return pointer to the vertex component as a GrPoint
+ */
+ static GrPoint* GetVertexPoint(void* vertices,
+ int vertexIndex,
+ int vertexSize,
+ int offset = 0) {
+ intptr_t start = GrTCast<intptr_t>(vertices);
+ return GrTCast<GrPoint*>(start + offset +
+ vertexIndex * vertexSize);
+ }
+ static const GrPoint* GetVertexPoint(const void* vertices,
+ int vertexIndex,
+ int vertexSize,
+ int offset = 0) {
+ intptr_t start = GrTCast<intptr_t>(vertices);
+ return GrTCast<const GrPoint*>(start + offset +
+ vertexIndex * vertexSize);
+ }
+
+ /**
+ * Gets a pointer to a GrColor inside a vertex within a vertex array.
+ * @param vertices the vetex array
+ * @param vertexIndex the index of the vertex in the array
+ * @param vertexSize the size of each vertex in the array
+ * @param offset the offset in bytes of the vertex color
+ * @return pointer to the vertex component as a GrColor
+ */
+ static GrColor* GetVertexColor(void* vertices,
+ int vertexIndex,
+ int vertexSize,
+ int offset) {
+ intptr_t start = GrTCast<intptr_t>(vertices);
+ return GrTCast<GrColor*>(start + offset +
+ vertexIndex * vertexSize);
+ }
+ static const GrColor* GetVertexColor(const void* vertices,
+ int vertexIndex,
+ int vertexSize,
+ int offset) {
+ const intptr_t start = GrTCast<intptr_t>(vertices);
+ return GrTCast<const GrColor*>(start + offset +
+ vertexIndex * vertexSize);
+ }
+
+ static void VertexLayoutUnitTest();
+
+protected:
+
+ /**
+ * Optimizations for blending / coverage to be applied based on the current
+ * state.
+ * Subclasses that actually draw (as opposed to those that just buffer for
+ * playback) must implement the flags that replace the output color.
+ */
+ enum BlendOptFlags {
+ /**
+ * No optimization
+ */
+ kNone_BlendOpt = 0,
+ /**
+ * Don't draw at all
+ */
+ kSkipDraw_BlendOptFlag = 0x2,
+ /**
+ * Emit the src color, disable HW blending (replace dst with src)
+ */
+ kDisableBlend_BlendOptFlag = 0x4,
+ /**
+ * The coverage value does not have to be computed separately from
+ * alpha, the the output color can be the modulation of the two.
+ */
+ kCoverageAsAlpha_BlendOptFlag = 0x1,
+ /**
+ * Instead of emitting a src color, emit coverage in the alpha channel
+ * and r,g,b are "don't cares".
+ */
+ kEmitCoverage_BlendOptFlag = 0x10,
+ /**
+ * Emit transparent black instead of the src color, no need to compute
+ * coverage.
+ */
+ kEmitTransBlack_BlendOptFlag = 0x8,
+ };
+ GR_DECL_BITFIELD_OPS_FRIENDS(BlendOptFlags);
+
+ // Determines what optimizations can be applied based on the blend.
+ // The coeffecients may have to be tweaked in order for the optimization
+ // to work. srcCoeff and dstCoeff are optional params that receive the
+ // tweaked coeffecients.
+ // Normally the function looks at the current state to see if coverage
+ // is enabled. By setting forceCoverage the caller can speculatively
+ // determine the blend optimizations that would be used if there was
+ // partial pixel coverage
+ BlendOptFlags getBlendOpts(bool forceCoverage = false,
+ GrBlendCoeff* srcCoeff = NULL,
+ GrBlendCoeff* dstCoeff = NULL) const;
+
+ // determine if src alpha is guaranteed to be one for all src pixels
+ bool srcAlphaWillBeOne() const;
+
+ enum GeometrySrcType {
+ kNone_GeometrySrcType, //<! src has not been specified
+ kReserved_GeometrySrcType, //<! src was set using reserve*Space
+ kArray_GeometrySrcType, //<! src was set using set*SourceToArray
+ kBuffer_GeometrySrcType //<! src was set using set*SourceToBuffer
+ };
+
+ struct GeometrySrcState {
+ GeometrySrcType fVertexSrc;
+ union {
+ // valid if src type is buffer
+ const GrVertexBuffer* fVertexBuffer;
+ // valid if src type is reserved or array
+ int fVertexCount;
+ };
+
+ GeometrySrcType fIndexSrc;
+ union {
+ // valid if src type is buffer
+ const GrIndexBuffer* fIndexBuffer;
+ // valid if src type is reserved or array
+ int fIndexCount;
+ };
+
+ GrVertexLayout fVertexLayout;
+ };
+
+ // given a vertex layout and a draw state, will a stage be used?
+ static bool StageWillBeUsed(int stage, GrVertexLayout layout,
+ const GrDrawState& state) {
+ return NULL != state.getTexture(stage) &&
+ VertexUsesStage(stage, layout);
+ }
+
+ bool isStageEnabled(int stage) const {
+ return StageWillBeUsed(stage, this->getGeomSrc().fVertexLayout,
+ fCurrDrawState);
+ }
+
+ StageMask enabledStages() const {
+ StageMask mask = 0;
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ mask |= this->isStageEnabled(s) ? 1 : 0;
+ }
+ return mask;
+ }
+
+ // Helpers for GrDrawTarget subclasses that won't have private access to
+ // SavedDrawState but need to peek at the state values.
+ static GrDrawState& accessSavedDrawState(SavedDrawState& sds)
+ { return sds.fState; }
+ static const GrDrawState& accessSavedDrawState(const SavedDrawState& sds)
+ { return sds.fState; }
+
+ // implemented by subclass to allocate space for reserved geom
+ virtual bool onReserveVertexSpace(GrVertexLayout vertexLayout,
+ int vertexCount,
+ void** vertices) = 0;
+ virtual bool onReserveIndexSpace(int indexCount, void** indices) = 0;
+ // implemented by subclass to handle release of reserved geom space
+ virtual void releaseReservedVertexSpace() = 0;
+ virtual void releaseReservedIndexSpace() = 0;
+ // subclass must consume array contents when set
+ virtual void onSetVertexSourceToArray(const void* vertexArray,
+ int vertexCount) = 0;
+ virtual void onSetIndexSourceToArray(const void* indexArray,
+ int indexCount) = 0;
+ // subclass is notified that geom source will be set away from an array
+ virtual void releaseVertexArray() = 0;
+ virtual void releaseIndexArray() = 0;
+ // subclass overrides to be notified just before geo src state
+ // is pushed/popped.
+ virtual void geometrySourceWillPush() = 0;
+ virtual void geometrySourceWillPop(const GeometrySrcState& restoredState) = 0;
+ // subclass called to perform drawing
+ virtual void onDrawIndexed(GrPrimitiveType type,
+ int startVertex,
+ int startIndex,
+ int vertexCount,
+ int indexCount) = 0;
+ virtual void onDrawNonIndexed(GrPrimitiveType type,
+ int startVertex,
+ int vertexCount) = 0;
+ // subclass overrides to be notified when clip is set. Must call
+ // INHERITED::clipwillBeSet
+ virtual void clipWillBeSet(const GrClip& clip);
+
+ // Helpers for drawRect, protected so subclasses that override drawRect
+ // can use them.
+ static GrVertexLayout GetRectVertexLayout(StageMask stageEnableBitfield,
+ const GrRect* srcRects[]);
+
+ static void SetRectVertices(const GrRect& rect,
+ const GrMatrix* matrix,
+ const GrRect* srcRects[],
+ const GrMatrix* srcMatrices[],
+ GrVertexLayout layout,
+ void* vertices);
+
+ // accessor for derived classes
+ const GeometrySrcState& getGeomSrc() const {
+ return fGeoSrcStateStack.back();
+ }
+
+ GrClip fClip;
+
+ GrDrawState fCurrDrawState;
+
+ Caps fCaps;
+
+ // subclasses must call this in their destructors to ensure all vertex
+ // and index sources have been released (including those held by
+ // pushGeometrySource())
+ void releaseGeometry();
+private:
+ // called by drawIndexed and drawNonIndexed. Use a negative indexCount to
+ // indicate non-indexed drawing.
+ bool checkDraw(GrPrimitiveType type, int startVertex,
+ int startIndex, int vertexCount,
+ int indexCount) const;
+ // called when setting a new vert/idx source to unref prev vb/ib
+ void releasePreviousVertexSource();
+ void releasePreviousIndexSource();
+
+ enum {
+ kPreallocGeoSrcStateStackCnt = 4,
+ };
+ SkSTArray<kPreallocGeoSrcStateStackCnt,
+ GeometrySrcState, true> fGeoSrcStateStack;
+
+};
+
+GR_MAKE_BITFIELD_OPS(GrDrawTarget::BlendOptFlags);
+
+#endif
diff --git a/src/gpu/GrGLCreateNativeInterface_none.cpp b/src/gpu/GrGLCreateNativeInterface_none.cpp
new file mode 100644
index 0000000..7de5912
--- /dev/null
+++ b/src/gpu/GrGLCreateNativeInterface_none.cpp
@@ -0,0 +1,13 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrGLInterface.h"
+
+const GrGLInterface* GrGLCreateNativeInterface() {
+ return NULL;
+}
diff --git a/src/gpu/GrGLCreateNullInterface.cpp b/src/gpu/GrGLCreateNullInterface.cpp
new file mode 100644
index 0000000..d4a88c1
--- /dev/null
+++ b/src/gpu/GrGLCreateNullInterface.cpp
@@ -0,0 +1,506 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrGLInterface.h"
+
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLActiveTexture(GrGLenum texture) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLAttachShader(GrGLuint program, GrGLuint shader) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLBeginQuery(GrGLenum target, GrGLuint id) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindAttribLocation(GrGLuint program, GrGLuint index, const char* name) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindTexture(GrGLenum target, GrGLuint texture) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLBlendColor(GrGLclampf red, GrGLclampf green, GrGLclampf blue, GrGLclampf alpha) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindFragDataLocation(GrGLuint program, GrGLuint colorNumber, const GrGLchar* name) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLBlendFunc(GrGLenum sfactor, GrGLenum dfactor) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLBufferData(GrGLenum target, GrGLsizeiptr size, const GrGLvoid* data, GrGLenum usage) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLBufferSubData(GrGLenum target, GrGLintptr offset, GrGLsizeiptr size, const GrGLvoid* data) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLClear(GrGLbitfield mask) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLClearColor(GrGLclampf red, GrGLclampf green, GrGLclampf blue, GrGLclampf alpha) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLClearStencil(GrGLint s) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLColorMask(GrGLboolean red, GrGLboolean green, GrGLboolean blue, GrGLboolean alpha) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLCompileShader(GrGLuint shader) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLCompressedTexImage2D(GrGLenum target, GrGLint level, GrGLenum internalformat, GrGLsizei width, GrGLsizei height, GrGLint border, GrGLsizei imageSize, const GrGLvoid* data) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLCullFace(GrGLenum mode) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLDepthMask(GrGLboolean flag) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLDisable(GrGLenum cap) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLDisableVertexAttribArray(GrGLuint index) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLDrawArrays(GrGLenum mode, GrGLint first, GrGLsizei count) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLDrawBuffer(GrGLenum mode) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLDrawBuffers(GrGLsizei n, const GrGLenum* bufs) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLDrawElements(GrGLenum mode, GrGLsizei count, GrGLenum type, const GrGLvoid* indices) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLEnable(GrGLenum cap) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLEnableVertexAttribArray(GrGLuint index) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLEndQuery(GrGLenum target) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLFinish() {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLFlush() {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLFrontFace(GrGLenum mode) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLLineWidth(GrGLfloat width) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLLinkProgram(GrGLuint program) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLPixelStorei(GrGLenum pname, GrGLint param) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLQueryCounter(GrGLuint id, GrGLenum target) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLReadBuffer(GrGLenum src) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLReadPixels(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, GrGLvoid* pixels) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLScissor(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLShaderSource(GrGLuint shader, GrGLsizei count, const char** str, const GrGLint* length) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLStencilFunc(GrGLenum func, GrGLint ref, GrGLuint mask) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLStencilFuncSeparate(GrGLenum face, GrGLenum func, GrGLint ref, GrGLuint mask) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLStencilMask(GrGLuint mask) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLStencilMaskSeparate(GrGLenum face, GrGLuint mask) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLStencilOp(GrGLenum fail, GrGLenum zfail, GrGLenum zpass) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLStencilOpSeparate(GrGLenum face, GrGLenum fail, GrGLenum zfail, GrGLenum zpass) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLTexImage2D(GrGLenum target, GrGLint level, GrGLint internalformat, GrGLsizei width, GrGLsizei height, GrGLint border, GrGLenum format, GrGLenum type, const GrGLvoid* pixels) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLTexParameteri(GrGLenum target, GrGLenum pname, GrGLint param) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLTexStorage2D(GrGLenum target, GrGLsizei levels, GrGLenum internalformat, GrGLsizei width, GrGLsizei height) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLTexSubImage2D(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, const GrGLvoid* pixels) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform1f(GrGLint location, GrGLfloat v0) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform1i(GrGLint location, GrGLint v0) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform1fv(GrGLint location, GrGLsizei count, const GrGLfloat* v) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform1iv(GrGLint location, GrGLsizei count, const GrGLint* v) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform2f(GrGLint location, GrGLfloat v0, GrGLfloat v1) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform2i(GrGLint location, GrGLint v0, GrGLint v1) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform2fv(GrGLint location, GrGLsizei count, const GrGLfloat* v) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform2iv(GrGLint location, GrGLsizei count, const GrGLint* v) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform3f(GrGLint location, GrGLfloat v0, GrGLfloat v1, GrGLfloat v2) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform3i(GrGLint location, GrGLint v0, GrGLint v1, GrGLint v2) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform3fv(GrGLint location, GrGLsizei count, const GrGLfloat* v) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform3iv(GrGLint location, GrGLsizei count, const GrGLint* v) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform4f(GrGLint location, GrGLfloat v0, GrGLfloat v1, GrGLfloat v2, GrGLfloat v3) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform4i(GrGLint location, GrGLint v0, GrGLint v1, GrGLint v2, GrGLint v3) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform4fv(GrGLint location, GrGLsizei count, const GrGLfloat* v) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniform4iv(GrGLint location, GrGLsizei count, const GrGLint* v) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniformMatrix2fv(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniformMatrix3fv(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUniformMatrix4fv(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLUseProgram(GrGLuint program) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLVertexAttrib4fv(GrGLuint indx, const GrGLfloat* values) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLVertexAttribPointer(GrGLuint indx, GrGLint size, GrGLenum type, GrGLboolean normalized, GrGLsizei stride, const GrGLvoid* ptr) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLViewport(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindFramebuffer(GrGLenum target, GrGLuint framebuffer) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindRenderbuffer(GrGLenum target, GrGLuint renderbuffer) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLDeleteFramebuffers(GrGLsizei n, const GrGLuint *framebuffers) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLDeleteRenderbuffers(GrGLsizei n, const GrGLuint *renderbuffers) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLFramebufferRenderbuffer(GrGLenum target, GrGLenum attachment, GrGLenum renderbuffertarget, GrGLuint renderbuffer) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLFramebufferTexture2D(GrGLenum target, GrGLenum attachment, GrGLenum textarget, GrGLuint texture, GrGLint level) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLGetFramebufferAttachmentParameteriv(GrGLenum target, GrGLenum attachment, GrGLenum pname, GrGLint* params) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLGetRenderbufferParameteriv(GrGLenum target, GrGLenum pname, GrGLint* params) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLRenderbufferStorage(GrGLenum target, GrGLenum internalformat, GrGLsizei width, GrGLsizei height) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLRenderbufferStorageMultisample(GrGLenum target, GrGLsizei samples, GrGLenum internalformat, GrGLsizei width, GrGLsizei height) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLBlitFramebuffer(GrGLint srcX0, GrGLint srcY0, GrGLint srcX1, GrGLint srcY1, GrGLint dstX0, GrGLint dstY0, GrGLint dstX1, GrGLint dstY1, GrGLbitfield mask, GrGLenum filter) {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLResolveMultisampleFramebuffer() {}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindFragDataLocationIndexed(GrGLuint program, GrGLuint colorNumber, GrGLuint index, const GrGLchar * name) {}
+
+GrGLenum GR_GL_FUNCTION_TYPE nullGLCheckFramebufferStatus(GrGLenum target) {
+ return GR_GL_FRAMEBUFFER_COMPLETE;
+}
+
+GrGLuint GR_GL_FUNCTION_TYPE nullGLCreateProgram() {
+ static int gCurrID = 0;
+ return ++gCurrID;
+}
+
+GrGLuint GR_GL_FUNCTION_TYPE nullGLCreateShader(GrGLenum type) {
+ static int gCurrID = 0;
+ return ++gCurrID;
+}
+
+// same delete used for shaders and programs
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLDelete(GrGLuint program) {
+}
+
+// same function used for all glGen*(GLsize i, GLuint*) functions
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLGenIds(GrGLsizei n, GrGLuint* ids) {
+ static int gCurrID = 0;
+ for (int i = 0; i < n; ++i) {
+ ids[i] = ++gCurrID;
+ }
+}
+// same delete function for all glDelete*(GLsize i, const GLuint*) except buffers
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLDeleteIds(GrGLsizei n, const GrGLuint* ids) {}
+
+// In debug builds we do asserts that ensure we agree with GL about when a buffer
+// is mapped.
+#include "GrTDArray.h"
+static GrTDArray<GrGLuint> gMappedBuffers;
+static GrGLuint gCurrArrayBuffer;
+static GrGLuint gCurrElementArrayBuffer;
+
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindBuffer(GrGLenum target, GrGLuint buffer) {
+ switch (target) {
+ case GR_GL_ARRAY_BUFFER:
+ gCurrArrayBuffer = buffer;
+ break;
+ case GR_GL_ELEMENT_ARRAY_BUFFER:
+ gCurrElementArrayBuffer = buffer;
+ break;
+ }
+}
+
+// deleting a bound buffer has the side effect of binding 0
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLDeleteBuffers(GrGLsizei n, const GrGLuint* ids) {
+ for (int i = 0; i < n; ++i) {
+ if (ids[i] == gCurrArrayBuffer) {
+ gCurrArrayBuffer = 0;
+ }
+ if (ids[i] == gCurrElementArrayBuffer) {
+ gCurrElementArrayBuffer = 0;
+ }
+ for (int j = 0; j < gMappedBuffers.count(); ++j) {
+ if (gMappedBuffers[j] == ids[i]) {
+ gMappedBuffers.remove(j);
+ // don't break b/c we didn't check for dupes on insert
+ --j;
+ }
+ }
+ }
+}
+
+GrGLvoid* GR_GL_FUNCTION_TYPE nullGLMapBuffer(GrGLenum target, GrGLenum access) {
+ // We just reserve 32MB of RAM for all locks and hope its big enough
+ static SkAutoMalloc gBufferData(32 * (1 << 20));
+ GrGLuint buf = 0;
+ switch (target) {
+ case GR_GL_ARRAY_BUFFER:
+ buf = gCurrArrayBuffer;
+ break;
+ case GR_GL_ELEMENT_ARRAY_BUFFER:
+ buf = gCurrElementArrayBuffer;
+ break;
+ }
+ if (buf) {
+ *gMappedBuffers.append() = buf;
+ }
+ return gBufferData.get();
+}
+
+GrGLboolean GR_GL_FUNCTION_TYPE nullGLUnmapBuffer(GrGLenum target) {
+ GrGLuint buf = 0;
+ switch (target) {
+ case GR_GL_ARRAY_BUFFER:
+ buf = gCurrArrayBuffer;
+ break;
+ case GR_GL_ELEMENT_ARRAY_BUFFER:
+ buf = gCurrElementArrayBuffer;
+ break;
+ }
+ if (buf) {
+ for (int i = 0; i < gMappedBuffers.count(); ++i) {
+ if (gMappedBuffers[i] == buf) {
+ gMappedBuffers.remove(i);
+ // don't break b/c we didn't check for dupes on insert
+ --i;
+ }
+ }
+ }
+ return GR_GL_TRUE;
+}
+
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLGetBufferParameteriv(GrGLenum target, GrGLenum pname, GrGLint* params) {
+ switch (pname) {
+ case GR_GL_BUFFER_MAPPED: {
+ *params = GR_GL_FALSE;
+ GrGLuint buf = 0;
+ switch (target) {
+ case GR_GL_ARRAY_BUFFER:
+ buf = gCurrArrayBuffer;
+ break;
+ case GR_GL_ELEMENT_ARRAY_BUFFER:
+ buf = gCurrElementArrayBuffer;
+ break;
+ }
+ if (buf) {
+ for (int i = 0; i < gMappedBuffers.count(); ++i) {
+ if (gMappedBuffers[i] == buf) {
+ *params = GR_GL_TRUE;
+ break;
+ }
+ }
+ }
+ break; }
+ default:
+ GrCrash("Unexpected pname to GetBufferParamateriv");
+ break;
+ }
+};
+
+GrGLenum GR_GL_FUNCTION_TYPE nullGLGetError() {
+ return GR_GL_NO_ERROR;
+}
+
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLGetIntegerv(GrGLenum pname, GrGLint* params) {
+ switch (pname) {
+ case GR_GL_STENCIL_BITS:
+ *params = 8;
+ break;
+ case GR_GL_SAMPLES:
+ *params = 1;
+ break;
+ case GR_GL_FRAMEBUFFER_BINDING:
+ *params = 0;
+ break;
+ case GR_GL_VIEWPORT:
+ params[0] = 0;
+ params[1] = 0;
+ params[2] = 800;
+ params[3] = 600;
+ break;
+ case GR_GL_MAX_TEXTURE_IMAGE_UNITS:
+ *params = 8;
+ break;
+ case GR_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
+ *params = 16;
+ break;
+ case GR_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
+ *params = 16 * 4;
+ break;
+ case GR_GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+ *params = 0;
+ break;
+ case GR_GL_COMPRESSED_TEXTURE_FORMATS:
+ break;
+ case GR_GL_MAX_TEXTURE_SIZE:
+ *params = 8192;
+ break;
+ case GR_GL_MAX_RENDERBUFFER_SIZE:
+ *params = 8192;
+ break;
+ case GR_GL_MAX_SAMPLES:
+ *params = 32;
+ break;
+ case GR_GL_MAX_VERTEX_ATTRIBS:
+ *params = 16;
+ break;
+ case GR_GL_MAX_TEXTURE_UNITS:
+ *params = 8;
+ break;
+ default:
+ GrCrash("Unexpected pname to GetIntegerv");
+ }
+}
+// used for both the program and shader info logs
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLGetInfoLog(GrGLuint program, GrGLsizei bufsize, GrGLsizei* length, char* infolog) {
+ if (length) {
+ *length = 0;
+ }
+ if (bufsize > 0) {
+ *infolog = 0;
+ }
+}
+
+// used for both the program and shader params
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLGetShaderOrProgramiv(GrGLuint program, GrGLenum pname, GrGLint* params) {
+ switch (pname) {
+ case GR_GL_LINK_STATUS: // fallthru
+ case GR_GL_COMPILE_STATUS:
+ *params = GR_GL_TRUE;
+ break;
+ case GR_GL_INFO_LOG_LENGTH:
+ *params = 0;
+ break;
+ // we don't expect any other pnames
+ default:
+ GrCrash("Unexpected pname to GetProgramiv");
+ break;
+ }
+}
+
+namespace {
+template <typename T>
+void query_result(GrGLenum GLtarget, GrGLenum pname, T *params) {
+ switch (pname) {
+ case GR_GL_QUERY_RESULT_AVAILABLE:
+ *params = GR_GL_TRUE;
+ break;
+ case GR_GL_QUERY_RESULT:
+ *params = 0;
+ break;
+ default:
+ GrCrash("Unexpected pname passed to GetQueryObject.");
+ break;
+ }
+}
+}
+
+// Queries on the null GL just don't do anything at all. We could potentially make
+// the timers work.
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLGetQueryiv(GrGLenum GLtarget, GrGLenum pname, GrGLint *params) {
+ switch (pname) {
+ case GR_GL_CURRENT_QUERY:
+ *params = 0;
+ break;
+ case GR_GL_QUERY_COUNTER_BITS:
+ *params = 32;
+ break;
+ default:
+ GrCrash("Unexpected pname passed GetQueryiv.");
+ }
+}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLGetQueryObjecti64v(GrGLuint id, GrGLenum pname, GrGLint64 *params) {
+ query_result(id, pname, params);
+}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLGetQueryObjectiv(GrGLuint id, GrGLenum pname, GrGLint *params) {
+ query_result(id, pname, params);
+}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLGetQueryObjectui64v(GrGLuint id, GrGLenum pname, GrGLuint64 *params) {
+ query_result(id, pname, params);
+}
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLGetQueryObjectuiv(GrGLuint id, GrGLenum pname, GrGLuint *params) {
+ query_result(id, pname, params);
+}
+
+const GrGLubyte* GR_GL_FUNCTION_TYPE nullGLGetString(GrGLenum name) {
+ switch (name) {
+ case GR_GL_EXTENSIONS:
+ return (const GrGLubyte*)"GL_ARB_framebuffer_object GL_ARB_blend_func_extended GL_ARB_timer_query GL_ARB_draw_buffers GL_ARB_occlusion_query GL_EXT_blend_color GL_EXT_stencil_wrap";
+ case GR_GL_VERSION:
+ return (const GrGLubyte*)"4.0 Null GL";
+ case GR_GL_SHADING_LANGUAGE_VERSION:
+ return (const GrGLubyte*)"4.20.8 Null GLSL";
+ default:
+ GrCrash("Unexpected name to GetString");
+ return NULL;
+ }
+}
+
+// we used to use this to query stuff about externally created textures, now we just
+// require clients to tell us everything about the texture.
+GrGLvoid GR_GL_FUNCTION_TYPE nullGLGetTexLevelParameteriv(GrGLenum target, GrGLint level, GrGLenum pname, GrGLint* params) {
+ GrCrash("Should never query texture parameters.");
+}
+
+GrGLint GR_GL_FUNCTION_TYPE nullGLGetUniformLocation(GrGLuint program, const char* name) {
+ static int gUniLocation = 0;
+ return ++gUniLocation;
+}
+
+const GrGLInterface* GrGLCreateNullInterface() {
+ // The gl functions are not context-specific so we create one global
+ // interface
+ static SkAutoTUnref<GrGLInterface> glInterface;
+ if (!glInterface.get()) {
+ GrGLInterface* interface = new GrGLInterface;
+ glInterface.reset(interface);
+ interface->fBindingsExported = kDesktop_GrGLBinding;
+ interface->fActiveTexture = nullGLActiveTexture;
+ interface->fAttachShader = nullGLAttachShader;
+ interface->fBeginQuery = nullGLBeginQuery;
+ interface->fBindAttribLocation = nullGLBindAttribLocation;
+ interface->fBindBuffer = nullGLBindBuffer;
+ interface->fBindFragDataLocation = nullGLBindFragDataLocation;
+ interface->fBindTexture = nullGLBindTexture;
+ interface->fBlendColor = nullGLBlendColor;
+ interface->fBlendFunc = nullGLBlendFunc;
+ interface->fBufferData = nullGLBufferData;
+ interface->fBufferSubData = nullGLBufferSubData;
+ interface->fClear = nullGLClear;
+ interface->fClearColor = nullGLClearColor;
+ interface->fClearStencil = nullGLClearStencil;
+ interface->fColorMask = nullGLColorMask;
+ interface->fCompileShader = nullGLCompileShader;
+ interface->fCompressedTexImage2D = nullGLCompressedTexImage2D;
+ interface->fCreateProgram = nullGLCreateProgram;
+ interface->fCreateShader = nullGLCreateShader;
+ interface->fCullFace = nullGLCullFace;
+ interface->fDeleteBuffers = nullGLDeleteBuffers;
+ interface->fDeleteProgram = nullGLDelete;
+ interface->fDeleteQueries = nullGLDeleteIds;
+ interface->fDeleteShader = nullGLDelete;
+ interface->fDeleteTextures = nullGLDeleteIds;
+ interface->fDepthMask = nullGLDepthMask;
+ interface->fDisable = nullGLDisable;
+ interface->fDisableVertexAttribArray = nullGLDisableVertexAttribArray;
+ interface->fDrawArrays = nullGLDrawArrays;
+ interface->fDrawBuffer = nullGLDrawBuffer;
+ interface->fDrawBuffers = nullGLDrawBuffers;
+ interface->fDrawElements = nullGLDrawElements;
+ interface->fEnable = nullGLEnable;
+ interface->fEnableVertexAttribArray = nullGLEnableVertexAttribArray;
+ interface->fEndQuery = nullGLEndQuery;
+ interface->fFinish = nullGLFinish;
+ interface->fFlush = nullGLFlush;
+ interface->fFrontFace = nullGLFrontFace;
+ interface->fGenBuffers = nullGLGenIds;
+ interface->fGenQueries = nullGLGenIds;
+ interface->fGenTextures = nullGLGenIds;
+ interface->fGetBufferParameteriv = nullGLGetBufferParameteriv;
+ interface->fGetError = nullGLGetError;
+ interface->fGetIntegerv = nullGLGetIntegerv;
+ interface->fGetQueryObjecti64v = nullGLGetQueryObjecti64v;
+ interface->fGetQueryObjectiv = nullGLGetQueryObjectiv;
+ interface->fGetQueryObjectui64v = nullGLGetQueryObjectui64v;
+ interface->fGetQueryObjectuiv = nullGLGetQueryObjectuiv;
+ interface->fGetQueryiv = nullGLGetQueryiv;
+ interface->fGetProgramInfoLog = nullGLGetInfoLog;
+ interface->fGetProgramiv = nullGLGetShaderOrProgramiv;
+ interface->fGetShaderInfoLog = nullGLGetInfoLog;
+ interface->fGetShaderiv = nullGLGetShaderOrProgramiv;
+ interface->fGetString = nullGLGetString;
+ interface->fGetTexLevelParameteriv = nullGLGetTexLevelParameteriv;
+ interface->fGetUniformLocation = nullGLGetUniformLocation;
+ interface->fLineWidth = nullGLLineWidth;
+ interface->fLinkProgram = nullGLLinkProgram;
+ interface->fPixelStorei = nullGLPixelStorei;
+ interface->fQueryCounter = nullGLQueryCounter;
+ interface->fReadBuffer = nullGLReadBuffer;
+ interface->fReadPixels = nullGLReadPixels;
+ interface->fScissor = nullGLScissor;
+ interface->fShaderSource = nullGLShaderSource;
+ interface->fStencilFunc = nullGLStencilFunc;
+ interface->fStencilFuncSeparate = nullGLStencilFuncSeparate;
+ interface->fStencilMask = nullGLStencilMask;
+ interface->fStencilMaskSeparate = nullGLStencilMaskSeparate;
+ interface->fStencilOp = nullGLStencilOp;
+ interface->fStencilOpSeparate = nullGLStencilOpSeparate;
+ interface->fTexImage2D = nullGLTexImage2D;
+ interface->fTexParameteri = nullGLTexParameteri;
+ interface->fTexSubImage2D = nullGLTexSubImage2D;
+ interface->fTexStorage2D = nullGLTexStorage2D;
+ interface->fUniform1f = nullGLUniform1f;
+ interface->fUniform1i = nullGLUniform1i;
+ interface->fUniform1fv = nullGLUniform1fv;
+ interface->fUniform1iv = nullGLUniform1iv;
+ interface->fUniform2f = nullGLUniform2f;
+ interface->fUniform2i = nullGLUniform2i;
+ interface->fUniform2fv = nullGLUniform2fv;
+ interface->fUniform2iv = nullGLUniform2iv;
+ interface->fUniform3f = nullGLUniform3f;
+ interface->fUniform3i = nullGLUniform3i;
+ interface->fUniform3fv = nullGLUniform3fv;
+ interface->fUniform3iv = nullGLUniform3iv;
+ interface->fUniform4f = nullGLUniform4f;
+ interface->fUniform4i = nullGLUniform4i;
+ interface->fUniform4fv = nullGLUniform4fv;
+ interface->fUniform4iv = nullGLUniform4iv;
+ interface->fUniformMatrix2fv = nullGLUniformMatrix2fv;
+ interface->fUniformMatrix3fv = nullGLUniformMatrix3fv;
+ interface->fUniformMatrix4fv = nullGLUniformMatrix4fv;
+ interface->fUseProgram = nullGLUseProgram;
+ interface->fVertexAttrib4fv = nullGLVertexAttrib4fv;
+ interface->fVertexAttribPointer = nullGLVertexAttribPointer;
+ interface->fViewport = nullGLViewport;
+ interface->fBindFramebuffer = nullGLBindFramebuffer;
+ interface->fBindRenderbuffer = nullGLBindRenderbuffer;
+ interface->fCheckFramebufferStatus = nullGLCheckFramebufferStatus;
+ interface->fDeleteFramebuffers = nullGLDeleteFramebuffers;
+ interface->fDeleteRenderbuffers = nullGLDeleteRenderbuffers;
+ interface->fFramebufferRenderbuffer = nullGLFramebufferRenderbuffer;
+ interface->fFramebufferTexture2D = nullGLFramebufferTexture2D;
+ interface->fGenFramebuffers = nullGLGenIds;
+ interface->fGenRenderbuffers = nullGLGenIds;
+ interface->fGetFramebufferAttachmentParameteriv = nullGLGetFramebufferAttachmentParameteriv;
+ interface->fGetRenderbufferParameteriv = nullGLGetRenderbufferParameteriv;
+ interface->fRenderbufferStorage = nullGLRenderbufferStorage;
+ interface->fRenderbufferStorageMultisample = nullGLRenderbufferStorageMultisample;
+ interface->fBlitFramebuffer = nullGLBlitFramebuffer;
+ interface->fResolveMultisampleFramebuffer = nullGLResolveMultisampleFramebuffer;
+ interface->fMapBuffer = nullGLMapBuffer;
+ interface->fUnmapBuffer = nullGLUnmapBuffer;
+ interface->fBindFragDataLocationIndexed = nullGLBindFragDataLocationIndexed;
+ }
+ glInterface.get()->ref();
+ return glInterface.get();
+}
diff --git a/src/gpu/GrGLDefaultInterface_native.cpp b/src/gpu/GrGLDefaultInterface_native.cpp
new file mode 100644
index 0000000..7b8b84a
--- /dev/null
+++ b/src/gpu/GrGLDefaultInterface_native.cpp
@@ -0,0 +1,13 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrGLInterface.h"
+
+const GrGLInterface* GrGLDefaultInterface() {
+ return GrGLCreateNativeInterface();
+}
diff --git a/src/gpu/GrGLDefaultInterface_none.cpp b/src/gpu/GrGLDefaultInterface_none.cpp
new file mode 100644
index 0000000..2cca135
--- /dev/null
+++ b/src/gpu/GrGLDefaultInterface_none.cpp
@@ -0,0 +1,13 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrGLInterface.h"
+
+const GrGLInterface* GrGLDefaultInterface() {
+ return NULL;
+}
diff --git a/gpu/include/GrGLIRect.h b/src/gpu/GrGLIRect.h
index ec60029..e94fa21 100644
--- a/gpu/include/GrGLIRect.h
+++ b/src/gpu/GrGLIRect.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrGLIRect_DEFINED
#define GrGLIRect_DEFINED
@@ -30,17 +23,17 @@ struct GrGLIRect {
GrGLsizei fWidth;
GrGLsizei fHeight;
- void pushToGLViewport() const {
- GR_GL(Viewport(fLeft, fBottom, fWidth, fHeight));
+ void pushToGLViewport(const GrGLInterface* gl) const {
+ GR_GL_CALL(gl, Viewport(fLeft, fBottom, fWidth, fHeight));
}
- void pushToGLScissor() const {
- GR_GL(Scissor(fLeft, fBottom, fWidth, fHeight));
+ void pushToGLScissor(const GrGLInterface* gl) const {
+ GR_GL_CALL(gl, Scissor(fLeft, fBottom, fWidth, fHeight));
}
- void setFromGLViewport() {
+ void setFromGLViewport(const GrGLInterface* gl) {
GR_STATIC_ASSERT(sizeof(GrGLIRect) == 4*sizeof(GrGLint));
- GR_GL_GetIntegerv(GR_GL_VIEWPORT, (GrGLint*) this);
+ GR_GL_GetIntegerv(gl, GR_GL_VIEWPORT, (GrGLint*) this);
}
// sometimes we have a GrIRect from the client that we
diff --git a/src/gpu/GrGLIndexBuffer.cpp b/src/gpu/GrGLIndexBuffer.cpp
new file mode 100644
index 0000000..b64668e
--- /dev/null
+++ b/src/gpu/GrGLIndexBuffer.cpp
@@ -0,0 +1,131 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#include "GrGLIndexBuffer.h"
+#include "GrGpuGL.h"
+
+#define GPUGL static_cast<GrGpuGL*>(getGpu())
+
+#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
+
+GrGLIndexBuffer::GrGLIndexBuffer(GrGpuGL* gpu,
+ GrGLuint id,
+ size_t sizeInBytes,
+ bool dynamic)
+ : INHERITED(gpu, sizeInBytes, dynamic)
+ , fBufferID(id)
+ , fLockPtr(NULL) {
+
+}
+
+void GrGLIndexBuffer::onRelease() {
+ // make sure we've not been abandoned
+ if (fBufferID) {
+ GPUGL->notifyIndexBufferDelete(this);
+ GL_CALL(DeleteBuffers(1, &fBufferID));
+ fBufferID = 0;
+ }
+}
+
+void GrGLIndexBuffer::onAbandon() {
+ fBufferID = 0;
+ fLockPtr = NULL;
+}
+
+void GrGLIndexBuffer::bind() const {
+ GL_CALL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, fBufferID));
+ GPUGL->notifyIndexBufferBind(this);
+}
+
+GrGLuint GrGLIndexBuffer::bufferID() const {
+ return fBufferID;
+}
+
+void* GrGLIndexBuffer::lock() {
+ GrAssert(fBufferID);
+ GrAssert(!isLocked());
+ if (this->getGpu()->getCaps().fBufferLockSupport) {
+ this->bind();
+ // Let driver know it can discard the old data
+ GL_CALL(BufferData(GR_GL_ELEMENT_ARRAY_BUFFER,
+ this->sizeInBytes(),
+ NULL,
+ this->dynamic() ? GR_GL_DYNAMIC_DRAW :
+ GR_GL_STATIC_DRAW));
+ GR_GL_CALL_RET(GPUGL->glInterface(),
+ fLockPtr,
+ MapBuffer(GR_GL_ELEMENT_ARRAY_BUFFER,
+ GR_GL_WRITE_ONLY));
+
+ return fLockPtr;
+ }
+ return NULL;
+}
+
+void* GrGLIndexBuffer::lockPtr() const {
+ return fLockPtr;
+}
+
+void GrGLIndexBuffer::unlock() {
+ GrAssert(fBufferID);
+ GrAssert(isLocked());
+ GrAssert(this->getGpu()->getCaps().fBufferLockSupport);
+
+ this->bind();
+ GL_CALL(UnmapBuffer(GR_GL_ELEMENT_ARRAY_BUFFER));
+ fLockPtr = NULL;
+}
+
+bool GrGLIndexBuffer::isLocked() const {
+#if GR_DEBUG
+ if (this->isValid() && this->getGpu()->getCaps().fBufferLockSupport) {
+ this->bind();
+ GrGLint mapped;
+ GL_CALL(GetBufferParameteriv(GR_GL_ELEMENT_ARRAY_BUFFER,
+ GR_GL_BUFFER_MAPPED, &mapped));
+ GrAssert(!!mapped == !!fLockPtr);
+ }
+#endif
+ return NULL != fLockPtr;
+}
+
+bool GrGLIndexBuffer::updateData(const void* src, size_t srcSizeInBytes) {
+ GrAssert(fBufferID);
+ GrAssert(!isLocked());
+ if (srcSizeInBytes > this->sizeInBytes()) {
+ return false;
+ }
+ this->bind();
+ GrGLenum usage = dynamic() ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW;
+#if !GR_GL_USE_BUFFER_DATA_NULL_HINT
+ // Note that we're cheating on the size here. Currently no methods
+ // allow a partial update that preserves contents of non-updated
+ // portions of the buffer (and lock() does a glBufferData(..size, NULL..))
+ GL_CALL(BufferData(GR_GL_ELEMENT_ARRAY_BUFFER, srcSizeInBytes, src, usage));
+#else
+ if (this->sizeInBytes() == srcSizeInBytes) {
+ GL_CALL(BufferData(GR_GL_ELEMENT_ARRAY_BUFFER,
+ srcSizeInBytes, src, usage));
+ } else {
+ // Before we call glBufferSubData we give the driver a hint using
+ // glBufferData with NULL. This makes the old buffer contents
+ // inaccessible to future draws. The GPU may still be processing draws
+ // that reference the old contents. With this hint it can assign a
+ // different allocation for the new contents to avoid flushing the gpu
+ // past draws consuming the old contents.
+ GL_CALL(BufferData(GR_GL_ELEMENT_ARRAY_BUFFER,
+ this->sizeInBytes(), NULL, usage));
+ GL_CALL(BufferSubData(GR_GL_ELEMENT_ARRAY_BUFFER,
+ 0, srcSizeInBytes, src));
+ }
+#endif
+ return true;
+}
+
diff --git a/gpu/include/GrGLIndexBuffer.h b/src/gpu/GrGLIndexBuffer.h
index 3565059..c3e2287 100644
--- a/gpu/include/GrGLIndexBuffer.h
+++ b/src/gpu/GrGLIndexBuffer.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrGLIndexBuffer_DEFINED
#define GrGLIndexBuffer_DEFINED
@@ -37,9 +30,7 @@ public:
virtual void unlock();
virtual bool isLocked() const;
virtual bool updateData(const void* src, size_t srcSizeInBytes);
- virtual bool updateSubData(const void* src,
- size_t srcSizeInBytes,
- size_t offset);
+
protected:
GrGLIndexBuffer(GrGpuGL* gpu,
GrGLuint id,
diff --git a/src/gpu/GrGLInterface.cpp b/src/gpu/GrGLInterface.cpp
new file mode 100644
index 0000000..3ce9ab0
--- /dev/null
+++ b/src/gpu/GrGLInterface.cpp
@@ -0,0 +1,496 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrTypes.h"
+#include "GrGLInterface.h"
+#include "GrGLDefines.h"
+
+#include <stdio.h>
+
+#if GR_GL_PER_GL_FUNC_CALLBACK
+namespace {
+void GrGLDefaultInterfaceCallback(const GrGLInterface*) {}
+}
+#endif
+
+GrGLVersion GrGLGetVersionFromString(const char* versionString) {
+ if (NULL == versionString) {
+ GrAssert(!"NULL GL version string.");
+ return 0;
+ }
+
+ int major, minor;
+
+ int n = sscanf(versionString, "%d.%d", &major, &minor);
+ if (2 == n) {
+ return GR_GL_VER(major, minor);
+ }
+
+ char profile[2];
+ n = sscanf(versionString, "OpenGL ES-%c%c %d.%d", profile, profile+1,
+ &major, &minor);
+ if (4 == n) {
+ return GR_GL_VER(major, minor);
+ }
+
+ n = sscanf(versionString, "OpenGL ES %d.%d", &major, &minor);
+ if (2 == n) {
+ return GR_GL_VER(major, minor);
+ }
+
+ return 0;
+}
+
+GrGLSLVersion GrGLGetGLSLVersionFromString(const char* versionString) {
+ if (NULL == versionString) {
+ GrAssert(!"NULL GLSL version string.");
+ return 0;
+ }
+
+ int major, minor;
+
+ int n = sscanf(versionString, "%d.%d", &major, &minor);
+ if (2 == n) {
+ return GR_GLSL_VER(major, minor);
+ }
+
+ n = sscanf(versionString, "OpenGL ES GLSL ES %d.%d", &major, &minor);
+ if (2 == n) {
+ return GR_GLSL_VER(major, minor);
+ }
+
+ n = sscanf(versionString, "OpenGL ES GLSL %d.%d", &major, &minor);
+ if (2 == n) {
+ return GR_GLSL_VER(major, minor);
+ }
+ return 0;
+}
+
+bool GrGLHasExtensionFromString(const char* ext, const char* extensionString) {
+ int extLength = strlen(ext);
+
+ while (true) {
+ int n = strcspn(extensionString, " ");
+ if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
+ return true;
+ }
+ if (0 == extensionString[n]) {
+ return false;
+ }
+ extensionString += n+1;
+ }
+
+ return false;
+}
+
+bool GrGLHasExtension(const GrGLInterface* gl, const char* ext) {
+ const GrGLubyte* glstr;
+ GR_GL_CALL_RET(gl, glstr, GetString(GR_GL_EXTENSIONS));
+ return GrGLHasExtensionFromString(ext, (const char*) glstr);
+}
+
+GrGLVersion GrGLGetVersion(const GrGLInterface* gl) {
+ const GrGLubyte* v;
+ GR_GL_CALL_RET(gl, v, GetString(GR_GL_VERSION));
+ return GrGLGetVersionFromString((const char*) v);
+}
+
+GrGLSLVersion GrGLGetGLSLVersion(const GrGLInterface* gl) {
+ const GrGLubyte* v;
+ GR_GL_CALL_RET(gl, v, GetString(GR_GL_SHADING_LANGUAGE_VERSION));
+ return GrGLGetGLSLVersionFromString((const char*) v);
+}
+
+GrGLInterface::GrGLInterface() {
+ fBindingsExported = (GrGLBinding)0;
+
+ fActiveTexture = NULL;
+ fAttachShader = NULL;
+ fBeginQuery = NULL;
+ fBindAttribLocation = NULL;
+ fBindBuffer = NULL;
+ fBindFragDataLocation = NULL;
+ fBindTexture = NULL;
+ fBlendColor = NULL;
+ fBlendFunc = NULL;
+ fBufferData = NULL;
+ fBufferSubData = NULL;
+ fClear = NULL;
+ fClearColor = NULL;
+ fClearStencil = NULL;
+ fColorMask = NULL;
+ fColorPointer = NULL;
+ fCompileShader = NULL;
+ fCompressedTexImage2D = NULL;
+ fCreateProgram = NULL;
+ fCreateShader = NULL;
+ fCullFace = NULL;
+ fDeleteBuffers = NULL;
+ fDeleteProgram = NULL;
+ fDeleteQueries = NULL;
+ fDeleteShader = NULL;
+ fDeleteTextures = NULL;
+ fDepthMask = NULL;
+ fDisable = NULL;
+ fDisableVertexAttribArray = NULL;
+ fDrawArrays = NULL;
+ fDrawBuffer = NULL;
+ fDrawBuffers = NULL;
+ fDrawElements = NULL;
+ fEndQuery = NULL;
+ fFinish = NULL;
+ fFlush = NULL;
+ fEnable = NULL;
+ fEnableVertexAttribArray = NULL;
+ fFrontFace = NULL;
+ fGenBuffers = NULL;
+ fGenQueries = NULL;
+ fGenTextures = NULL;
+ fGetBufferParameteriv = NULL;
+ fGetError = NULL;
+ fGetIntegerv = NULL;
+ fGetQueryiv = NULL;
+ fGetQueryObjecti64v = NULL;
+ fGetQueryObjectiv = NULL;
+ fGetQueryObjectui64v = NULL;
+ fGetQueryObjectuiv = NULL;
+ fGetProgramInfoLog = NULL;
+ fGetProgramiv = NULL;
+ fGetShaderInfoLog = NULL;
+ fGetShaderiv = NULL;
+ fGetString = NULL;
+ fGetTexLevelParameteriv = NULL;
+ fGetUniformLocation = NULL;
+ fLineWidth = NULL;
+ fLinkProgram = NULL;
+ fPixelStorei = NULL;
+ fQueryCounter = NULL;
+ fReadBuffer = NULL;
+ fReadPixels = NULL;
+ fScissor = NULL;
+ fShaderSource = NULL;
+ fStencilFunc = NULL;
+ fStencilFuncSeparate = NULL;
+ fStencilMask = NULL;
+ fStencilMaskSeparate = NULL;
+ fStencilOp = NULL;
+ fStencilOpSeparate = NULL;
+ fTexImage2D = NULL;
+ fTexParameteri = NULL;
+ fTexStorage2D = NULL;
+ fTexSubImage2D = NULL;
+ fUniform1f = NULL;
+ fUniform1i = NULL;
+ fUniform1fv = NULL;
+ fUniform1iv = NULL;
+ fUniform2f = NULL;
+ fUniform2i = NULL;
+ fUniform2fv = NULL;
+ fUniform2iv = NULL;
+ fUniform3f = NULL;
+ fUniform3i = NULL;
+ fUniform3fv = NULL;
+ fUniform3iv = NULL;
+ fUniform4f = NULL;
+ fUniform4i = NULL;
+ fUniform4fv = NULL;
+ fUniform4iv = NULL;
+ fUniformMatrix2fv = NULL;
+ fUniformMatrix3fv = NULL;
+ fUniformMatrix4fv = NULL;
+ fUseProgram = NULL;
+ fVertexAttrib4fv = NULL;
+ fVertexAttribPointer = NULL;
+ fViewport = NULL;
+ fBindFramebuffer = NULL;
+ fBindRenderbuffer = NULL;
+ fCheckFramebufferStatus = NULL;
+ fDeleteFramebuffers = NULL;
+ fDeleteRenderbuffers = NULL;
+ fFramebufferRenderbuffer = NULL;
+ fFramebufferTexture2D = NULL;
+ fGenFramebuffers = NULL;
+ fGenRenderbuffers = NULL;
+ fGetFramebufferAttachmentParameteriv = NULL;
+ fGetRenderbufferParameteriv = NULL;
+ fRenderbufferStorage = NULL;
+ fRenderbufferStorageMultisample = NULL;
+ fBlitFramebuffer = NULL;
+ fResolveMultisampleFramebuffer = NULL;
+ fMapBuffer = NULL;
+ fUnmapBuffer = NULL;
+ fBindFragDataLocationIndexed = NULL;
+
+#if GR_GL_PER_GL_FUNC_CALLBACK
+ fCallback = GrGLDefaultInterfaceCallback;
+ fCallbackData = 0;
+#endif
+}
+
+bool GrGLInterface::validate() const {
+
+ bool isDesktop = this->supportsDesktop();
+
+ bool isES2 = this->supportsES2();
+
+ if (isDesktop == isES2) {
+ // must have one, don't support both in same interface
+ return false;
+ }
+
+ // functions that are always required
+ if (NULL == fActiveTexture ||
+ NULL == fAttachShader ||
+ NULL == fBindAttribLocation ||
+ NULL == fBindBuffer ||
+ NULL == fBindTexture ||
+ NULL == fBlendFunc ||
+ NULL == fBufferData ||
+ NULL == fBufferSubData ||
+ NULL == fClear ||
+ NULL == fClearColor ||
+ NULL == fClearStencil ||
+ NULL == fColorMask ||
+ NULL == fCompileShader ||
+ NULL == fCreateProgram ||
+ NULL == fCreateShader ||
+ NULL == fCullFace ||
+ NULL == fDeleteBuffers ||
+ NULL == fDeleteProgram ||
+ NULL == fDeleteShader ||
+ NULL == fDeleteTextures ||
+ NULL == fDepthMask ||
+ NULL == fDisable ||
+ NULL == fDisableVertexAttribArray ||
+ NULL == fDrawArrays ||
+ NULL == fDrawElements ||
+ NULL == fEnable ||
+ NULL == fEnableVertexAttribArray ||
+ NULL == fFrontFace ||
+ NULL == fGenBuffers ||
+ NULL == fGenTextures ||
+ NULL == fGetBufferParameteriv ||
+ NULL == fGetError ||
+ NULL == fGetIntegerv ||
+ NULL == fGetProgramInfoLog ||
+ NULL == fGetProgramiv ||
+ NULL == fGetShaderInfoLog ||
+ NULL == fGetShaderiv ||
+ NULL == fGetString ||
+ NULL == fGetUniformLocation ||
+ NULL == fLinkProgram ||
+ NULL == fPixelStorei ||
+ NULL == fReadPixels ||
+ NULL == fScissor ||
+ NULL == fShaderSource ||
+ NULL == fStencilFunc ||
+ NULL == fStencilMask ||
+ NULL == fStencilOp ||
+ NULL == fTexImage2D ||
+ NULL == fTexParameteri ||
+ NULL == fTexSubImage2D ||
+ NULL == fUniform1f ||
+ NULL == fUniform1i ||
+ NULL == fUniform1fv ||
+ NULL == fUniform1iv ||
+ NULL == fUniform2f ||
+ NULL == fUniform2i ||
+ NULL == fUniform2fv ||
+ NULL == fUniform2iv ||
+ NULL == fUniform3f ||
+ NULL == fUniform3i ||
+ NULL == fUniform3fv ||
+ NULL == fUniform3iv ||
+ NULL == fUniform4f ||
+ NULL == fUniform4i ||
+ NULL == fUniform4fv ||
+ NULL == fUniform4iv ||
+ NULL == fUniformMatrix2fv ||
+ NULL == fUniformMatrix3fv ||
+ NULL == fUniformMatrix4fv ||
+ NULL == fUseProgram ||
+ NULL == fVertexAttrib4fv ||
+ NULL == fVertexAttribPointer ||
+ NULL == fViewport ||
+ NULL == fBindFramebuffer ||
+ NULL == fBindRenderbuffer ||
+ NULL == fCheckFramebufferStatus ||
+ NULL == fDeleteFramebuffers ||
+ NULL == fDeleteRenderbuffers ||
+ NULL == fFinish ||
+ NULL == fFlush ||
+ NULL == fFramebufferRenderbuffer ||
+ NULL == fFramebufferTexture2D ||
+ NULL == fGetFramebufferAttachmentParameteriv ||
+ NULL == fGetRenderbufferParameteriv ||
+ NULL == fGenFramebuffers ||
+ NULL == fGenRenderbuffers ||
+ NULL == fRenderbufferStorage) {
+ return false;
+ }
+
+ const char* ext;
+ GrGLVersion glVer = GrGLGetVersion(this);
+ ext = (const char*)fGetString(GR_GL_EXTENSIONS);
+
+ // Now check that baseline ES/Desktop fns not covered above are present
+ // and that we have fn pointers for any advertised extensions that we will
+ // try to use.
+
+ // these functions are part of ES2, we assume they are available
+ // On the desktop we assume they are available if the extension
+ // is present or GL version is high enough.
+ if ((kES2_GrGLBinding & fBindingsExported)) {
+ if (NULL == fBlendColor ||
+ NULL == fStencilFuncSeparate ||
+ NULL == fStencilMaskSeparate ||
+ NULL == fStencilOpSeparate) {
+ return false;
+ }
+ } else if (kDesktop_GrGLBinding == fBindingsExported) {
+ if (glVer >= GR_GL_VER(2,0)) {
+ if (NULL == fStencilFuncSeparate ||
+ NULL == fStencilMaskSeparate ||
+ NULL == fStencilOpSeparate) {
+ return false;
+ }
+ }
+ if (glVer >= GR_GL_VER(3,0) && NULL == fBindFragDataLocation) {
+ return false;
+ }
+ if (glVer >= GR_GL_VER(2,0) ||
+ GrGLHasExtensionFromString("GL_ARB_draw_buffers", ext)) {
+ if (NULL == fDrawBuffers) {
+ return false;
+ }
+ }
+ if (glVer >= GR_GL_VER(1,4) ||
+ GrGLHasExtensionFromString("GL_EXT_blend_color", ext)) {
+ if (NULL == fBlendColor) {
+ return false;
+ }
+ }
+ if (glVer >= GR_GL_VER(1,5) ||
+ GrGLHasExtensionFromString("GL_ARB_occlusion_query", ext)) {
+ if (NULL == fGenQueries ||
+ NULL == fDeleteQueries ||
+ NULL == fBeginQuery ||
+ NULL == fEndQuery ||
+ NULL == fGetQueryiv ||
+ NULL == fGetQueryObjectiv ||
+ NULL == fGetQueryObjectuiv) {
+ return false;
+ }
+ }
+ if (glVer >= GR_GL_VER(3,3) ||
+ GrGLHasExtensionFromString("GL_ARB_timer_query", ext) ||
+ GrGLHasExtensionFromString("GL_EXT_timer_query", ext)) {
+ if (NULL == fGetQueryObjecti64v ||
+ NULL == fGetQueryObjectui64v) {
+ return false;
+ }
+ }
+ if (glVer >= GR_GL_VER(3,3) ||
+ GrGLHasExtensionFromString("GL_ARB_timer_query", ext)) {
+ if (NULL == fQueryCounter) {
+ return false;
+ }
+ }
+ }
+
+ // optional function on desktop before 1.3
+ if (kDesktop_GrGLBinding != fBindingsExported ||
+ (glVer >= GR_GL_VER(1,3) ||
+ GrGLHasExtensionFromString("GL_ARB_texture_compression", ext))) {
+ if (NULL == fCompressedTexImage2D) {
+ return false;
+ }
+ }
+
+ // part of desktop GL, but not ES
+ if (kDesktop_GrGLBinding == fBindingsExported &&
+ (NULL == fLineWidth ||
+ NULL == fGetTexLevelParameteriv ||
+ NULL == fDrawBuffer ||
+ NULL == fReadBuffer)) {
+ return false;
+ }
+
+ // GL_EXT_texture_storage is part of desktop 4.2
+ // There is a desktop ARB extension and an ES+desktop EXT extension
+ if (kDesktop_GrGLBinding == fBindingsExported) {
+ if (glVer >= GR_GL_VER(4,2) ||
+ GrGLHasExtensionFromString("GL_ARB_texture_storage", ext) ||
+ GrGLHasExtensionFromString("GL_EXT_texture_storage", ext)) {
+ if (NULL == fTexStorage2D) {
+ return false;
+ }
+ }
+ } else if (GrGLHasExtensionFromString("GL_EXT_texture_storage", ext)) {
+ if (NULL == fTexStorage2D) {
+ return false;
+ }
+ }
+
+ // FBO MSAA
+ if (kDesktop_GrGLBinding == fBindingsExported) {
+ // GL 3.0 and the ARB extension have multisample + blit
+ if (glVer >= GR_GL_VER(3,0) || GrGLHasExtensionFromString("GL_ARB_framebuffer_object", ext)) {
+ if (NULL == fRenderbufferStorageMultisample ||
+ NULL == fBlitFramebuffer) {
+ return false;
+ }
+ } else {
+ if (GrGLHasExtensionFromString("GL_EXT_framebuffer_blit", ext) &&
+ NULL == fBlitFramebuffer) {
+ return false;
+ }
+ if (GrGLHasExtensionFromString("GL_EXT_framebuffer_multisample", ext) &&
+ NULL == fRenderbufferStorageMultisample) {
+ return false;
+ }
+ }
+ } else {
+ if (GrGLHasExtensionFromString("GL_CHROMIUM_framebuffer_multisample", ext)) {
+ if (NULL == fRenderbufferStorageMultisample ||
+ NULL == fBlitFramebuffer) {
+ return false;
+ }
+ }
+ if (GrGLHasExtensionFromString("GL_APPLE_framebuffer_multisample", ext)) {
+ if (NULL == fRenderbufferStorageMultisample ||
+ NULL == fResolveMultisampleFramebuffer) {
+ return false;
+ }
+ }
+ }
+
+ // On ES buffer mapping is an extension. On Desktop
+ // buffer mapping was part of original VBO extension
+ // which we require.
+ if (kDesktop_GrGLBinding == fBindingsExported ||
+ GrGLHasExtensionFromString("GL_OES_mapbuffer", ext)) {
+ if (NULL == fMapBuffer ||
+ NULL == fUnmapBuffer) {
+ return false;
+ }
+ }
+
+ // Dual source blending
+ if (kDesktop_GrGLBinding == fBindingsExported &&
+ (glVer >= GR_GL_VER(3,3) ||
+ GrGLHasExtensionFromString("GL_ARB_blend_func_extended", ext))) {
+ if (NULL == fBindFragDataLocationIndexed) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
diff --git a/src/gpu/GrGLProgram.cpp b/src/gpu/GrGLProgram.cpp
new file mode 100644
index 0000000..2e391e3
--- /dev/null
+++ b/src/gpu/GrGLProgram.cpp
@@ -0,0 +1,1871 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrGLProgram.h"
+
+#include "GrAllocator.h"
+#include "GrGLShaderVar.h"
+#include "SkTrace.h"
+#include "SkXfermode.h"
+
+namespace {
+
+enum {
+ /// Used to mark a StageUniLocation field that should be bound
+ /// to a uniform during getUniformLocationsAndInitCache().
+ kUseUniform = 2000
+};
+
+
+const char* GrPrecision(const GrGLInterface* gl) {
+ if (gl->supportsES2()) {
+ return "mediump";
+ } else {
+ return " ";
+ }
+}
+
+const char* GrShaderPrecision(const GrGLInterface* gl) {
+ if (gl->supportsES2()) {
+ return "precision mediump float;\n";
+ } else {
+ return "";
+ }
+}
+
+} // namespace
+
+#define PRINT_SHADERS 0
+
+typedef GrTAllocator<GrGLShaderVar> VarArray;
+
+// number of each input/output type in a single allocation block
+static const int gVarsPerBlock = 8;
+// except FS outputs where we expect 2 at most.
+static const int gMaxFSOutputs = 2;
+
+struct ShaderCodeSegments {
+ ShaderCodeSegments()
+ : fVSUnis(gVarsPerBlock)
+ , fVSAttrs(gVarsPerBlock)
+ , fVSOutputs(gVarsPerBlock)
+ , fGSInputs(gVarsPerBlock)
+ , fGSOutputs(gVarsPerBlock)
+ , fFSInputs(gVarsPerBlock)
+ , fFSUnis(gVarsPerBlock)
+ , fFSOutputs(gMaxFSOutputs)
+ , fUsesGS(false) {}
+ GrStringBuilder fHeader; // VS+FS, GLSL version, etc
+ VarArray fVSUnis;
+ VarArray fVSAttrs;
+ VarArray fVSOutputs;
+ VarArray fGSInputs;
+ VarArray fGSOutputs;
+ VarArray fFSInputs;
+ GrStringBuilder fGSHeader; // layout qualifiers specific to GS
+ VarArray fFSUnis;
+ VarArray fFSOutputs;
+ GrStringBuilder fFSFunctions;
+ GrStringBuilder fVSCode;
+ GrStringBuilder fGSCode;
+ GrStringBuilder fFSCode;
+
+ bool fUsesGS;
+};
+
+typedef GrGLProgram::ProgramDesc::StageDesc StageDesc;
+
+#if GR_GL_ATTRIBUTE_MATRICES
+ #define VIEW_MATRIX_NAME "aViewM"
+#else
+ #define VIEW_MATRIX_NAME "uViewM"
+#endif
+
+#define POS_ATTR_NAME "aPosition"
+#define COL_ATTR_NAME "aColor"
+#define COV_ATTR_NAME "aCoverage"
+#define EDGE_ATTR_NAME "aEdge"
+#define COL_UNI_NAME "uColor"
+#define EDGES_UNI_NAME "uEdges"
+#define COL_FILTER_UNI_NAME "uColorFilter"
+#define COL_MATRIX_UNI_NAME "uColorMatrix"
+#define COL_MATRIX_VEC_UNI_NAME "uColorMatrixVec"
+
+namespace {
+inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
+ *s = "aTexCoord";
+ s->appendS32(coordIdx);
+}
+
+inline GrGLShaderVar::Type float_vector_type(int count) {
+ GR_STATIC_ASSERT(GrGLShaderVar::kFloat_Type == 0);
+ GR_STATIC_ASSERT(GrGLShaderVar::kVec2f_Type == 1);
+ GR_STATIC_ASSERT(GrGLShaderVar::kVec3f_Type == 2);
+ GR_STATIC_ASSERT(GrGLShaderVar::kVec4f_Type == 3);
+ GrAssert(count > 0 && count <= 4);
+ return (GrGLShaderVar::Type)(count - 1);
+}
+
+inline const char* float_vector_type_str(int count) {
+ return GrGLShaderVar::TypeString(float_vector_type(count));
+}
+
+inline const char* vector_homog_coord(int count) {
+ static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
+ GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS));
+ return HOMOGS[count];
+}
+
+inline const char* vector_nonhomog_coords(int count) {
+ static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
+ GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS));
+ return NONHOMOGS[count];
+}
+
+inline const char* vector_all_coords(int count) {
+ static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
+ GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL));
+ return ALL[count];
+}
+
+inline const char* all_ones_vec(int count) {
+ static const char* ONESVEC[] = {"ERROR", "1.0", "vec2(1,1)",
+ "vec3(1,1,1)", "vec4(1,1,1,1)"};
+ GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ONESVEC));
+ return ONESVEC[count];
+}
+
+inline const char* all_zeros_vec(int count) {
+ static const char* ZEROSVEC[] = {"ERROR", "0.0", "vec2(0,0)",
+ "vec3(0,0,0)", "vec4(0,0,0,0)"};
+ GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ZEROSVEC));
+ return ZEROSVEC[count];
+}
+
+inline const char* declared_color_output_name() { return "fsColorOut"; }
+inline const char* dual_source_output_name() { return "dualSourceOut"; }
+
+inline void tex_matrix_name(int stage, GrStringBuilder* s) {
+#if GR_GL_ATTRIBUTE_MATRICES
+ *s = "aTexM";
+#else
+ *s = "uTexM";
+#endif
+ s->appendS32(stage);
+}
+
+inline void normalized_texel_size_name(int stage, GrStringBuilder* s) {
+ *s = "uTexelSize";
+ s->appendS32(stage);
+}
+
+inline void sampler_name(int stage, GrStringBuilder* s) {
+ *s = "uSampler";
+ s->appendS32(stage);
+}
+
+inline void radial2_param_name(int stage, GrStringBuilder* s) {
+ *s = "uRadial2Params";
+ s->appendS32(stage);
+}
+
+inline void convolve_param_names(int stage, GrStringBuilder* k, GrStringBuilder* i) {
+ *k = "uKernel";
+ k->appendS32(stage);
+ *i = "uImageIncrement";
+ i->appendS32(stage);
+}
+
+inline void tex_domain_name(int stage, GrStringBuilder* s) {
+ *s = "uTexDom";
+ s->appendS32(stage);
+}
+}
+
+GrGLProgram::GrGLProgram() {
+}
+
+GrGLProgram::~GrGLProgram() {
+}
+
+void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff,
+ GrBlendCoeff* dstCoeff) const {
+ switch (fProgramDesc.fDualSrcOutput) {
+ case ProgramDesc::kNone_DualSrcOutput:
+ break;
+ // the prog will write a coverage value to the secondary
+ // output and the dst is blended by one minus that value.
+ case ProgramDesc::kCoverage_DualSrcOutput:
+ case ProgramDesc::kCoverageISA_DualSrcOutput:
+ case ProgramDesc::kCoverageISC_DualSrcOutput:
+ *dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_BlendCoeff;
+ break;
+ default:
+ GrCrash("Unexpected dual source blend output");
+ break;
+ }
+}
+
+// assigns modulation of two vars to an output var
+// vars can be vec4s or floats (or one of each)
+// result is always vec4
+// if either var is "" then assign to the other var
+// if both are "" then assign all ones
+static inline void modulate_helper(const char* outputVar,
+ const char* var0,
+ const char* var1,
+ GrStringBuilder* code) {
+ GrAssert(NULL != outputVar);
+ GrAssert(NULL != var0);
+ GrAssert(NULL != var1);
+ GrAssert(NULL != code);
+
+ bool has0 = '\0' != *var0;
+ bool has1 = '\0' != *var1;
+
+ if (!has0 && !has1) {
+ code->appendf("\t%s = %s;\n", outputVar, all_ones_vec(4));
+ } else if (!has0) {
+ code->appendf("\t%s = vec4(%s);\n", outputVar, var1);
+ } else if (!has1) {
+ code->appendf("\t%s = vec4(%s);\n", outputVar, var0);
+ } else {
+ code->appendf("\t%s = vec4(%s * %s);\n", outputVar, var0, var1);
+ }
+}
+
+// assigns addition of two vars to an output var
+// vars can be vec4s or floats (or one of each)
+// result is always vec4
+// if either var is "" then assign to the other var
+// if both are "" then assign all zeros
+static inline void add_helper(const char* outputVar,
+ const char* var0,
+ const char* var1,
+ GrStringBuilder* code) {
+ GrAssert(NULL != outputVar);
+ GrAssert(NULL != var0);
+ GrAssert(NULL != var1);
+ GrAssert(NULL != code);
+
+ bool has0 = '\0' != *var0;
+ bool has1 = '\0' != *var1;
+
+ if (!has0 && !has1) {
+ code->appendf("\t%s = %s;\n", outputVar, all_zeros_vec(4));
+ } else if (!has0) {
+ code->appendf("\t%s = vec4(%s);\n", outputVar, var1);
+ } else if (!has1) {
+ code->appendf("\t%s = vec4(%s);\n", outputVar, var0);
+ } else {
+ code->appendf("\t%s = vec4(%s + %s);\n", outputVar, var0, var1);
+ }
+}
+
+// given two blend coeffecients determine whether the src
+// and/or dst computation can be omitted.
+static inline void needBlendInputs(SkXfermode::Coeff srcCoeff,
+ SkXfermode::Coeff dstCoeff,
+ bool* needSrcValue,
+ bool* needDstValue) {
+ if (SkXfermode::kZero_Coeff == srcCoeff) {
+ switch (dstCoeff) {
+ // these all read the src
+ case SkXfermode::kSC_Coeff:
+ case SkXfermode::kISC_Coeff:
+ case SkXfermode::kSA_Coeff:
+ case SkXfermode::kISA_Coeff:
+ *needSrcValue = true;
+ break;
+ default:
+ *needSrcValue = false;
+ break;
+ }
+ } else {
+ *needSrcValue = true;
+ }
+ if (SkXfermode::kZero_Coeff == dstCoeff) {
+ switch (srcCoeff) {
+ // these all read the dst
+ case SkXfermode::kDC_Coeff:
+ case SkXfermode::kIDC_Coeff:
+ case SkXfermode::kDA_Coeff:
+ case SkXfermode::kIDA_Coeff:
+ *needDstValue = true;
+ break;
+ default:
+ *needDstValue = false;
+ break;
+ }
+ } else {
+ *needDstValue = true;
+ }
+}
+
+/**
+ * Create a blend_coeff * value string to be used in shader code. Sets empty
+ * string if result is trivially zero.
+ */
+static void blendTermString(GrStringBuilder* str, SkXfermode::Coeff coeff,
+ const char* src, const char* dst,
+ const char* value) {
+ switch (coeff) {
+ case SkXfermode::kZero_Coeff: /** 0 */
+ *str = "";
+ break;
+ case SkXfermode::kOne_Coeff: /** 1 */
+ *str = value;
+ break;
+ case SkXfermode::kSC_Coeff:
+ str->printf("(%s * %s)", src, value);
+ break;
+ case SkXfermode::kISC_Coeff:
+ str->printf("((%s - %s) * %s)", all_ones_vec(4), src, value);
+ break;
+ case SkXfermode::kDC_Coeff:
+ str->printf("(%s * %s)", dst, value);
+ break;
+ case SkXfermode::kIDC_Coeff:
+ str->printf("((%s - %s) * %s)", all_ones_vec(4), dst, value);
+ break;
+ case SkXfermode::kSA_Coeff: /** src alpha */
+ str->printf("(%s.a * %s)", src, value);
+ break;
+ case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
+ str->printf("((1.0 - %s.a) * %s)", src, value);
+ break;
+ case SkXfermode::kDA_Coeff: /** dst alpha */
+ str->printf("(%s.a * %s)", dst, value);
+ break;
+ case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
+ str->printf("((1.0 - %s.a) * %s)", dst, value);
+ break;
+ default:
+ GrCrash("Unexpected xfer coeff.");
+ break;
+ }
+}
+/**
+ * Adds a line to the fragment shader code which modifies the color by
+ * the specified color filter.
+ */
+static void addColorFilter(GrStringBuilder* fsCode, const char * outputVar,
+ SkXfermode::Coeff uniformCoeff,
+ SkXfermode::Coeff colorCoeff,
+ const char* inColor) {
+ GrStringBuilder colorStr, constStr;
+ blendTermString(&colorStr, colorCoeff, COL_FILTER_UNI_NAME,
+ inColor, inColor);
+ blendTermString(&constStr, uniformCoeff, COL_FILTER_UNI_NAME,
+ inColor, COL_FILTER_UNI_NAME);
+
+ add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode);
+}
+/**
+ * Adds code to the fragment shader code which modifies the color by
+ * the specified color matrix.
+ */
+static void addColorMatrix(GrStringBuilder* fsCode, const char * outputVar,
+ const char* inColor) {
+ fsCode->appendf("\t%s = %s * vec4(%s.rgb / %s.a, %s.a) + %s;\n", outputVar, COL_MATRIX_UNI_NAME, inColor, inColor, inColor, COL_MATRIX_VEC_UNI_NAME);
+ fsCode->appendf("\t%s.rgb *= %s.a;\n", outputVar, outputVar);
+}
+
+namespace {
+
+const char* glsl_version_string(const GrGLInterface* gl,
+ GrGLSLGeneration v) {
+ switch (v) {
+ case k110_GLSLGeneration:
+ if (gl->supportsES2()) {
+ // ES2s shader language is based on version 1.20 but is version
+ // 1.00 of the ES language.
+ return "#version 100\n";
+ } else {
+ return "#version 110\n";
+ }
+ case k130_GLSLGeneration:
+ GrAssert(!gl->supportsES2());
+ return "#version 130\n";
+ case k150_GLSLGeneration:
+ GrAssert(!gl->supportsES2());
+ return "#version 150\n";
+ default:
+ GrCrash("Unknown GL version.");
+ return ""; // suppress warning
+ }
+}
+
+// Adds a var that is computed in the VS and read in FS.
+// If there is a GS it will just pass it through.
+void append_varying(GrGLShaderVar::Type type,
+ const char* name,
+ ShaderCodeSegments* segments,
+ const char** vsOutName = NULL,
+ const char** fsInName = NULL) {
+ segments->fVSOutputs.push_back();
+ segments->fVSOutputs.back().setType(type);
+ segments->fVSOutputs.back().setTypeModifier(
+ GrGLShaderVar::kOut_TypeModifier);
+ segments->fVSOutputs.back().accessName()->printf("v%s", name);
+ if (vsOutName) {
+ *vsOutName = segments->fVSOutputs.back().getName().c_str();
+ }
+ // input to FS comes either from VS or GS
+ const GrStringBuilder* fsName;
+ if (segments->fUsesGS) {
+ // if we have a GS take each varying in as an array
+ // and output as non-array.
+ segments->fGSInputs.push_back();
+ segments->fGSInputs.back().setType(type);
+ segments->fGSInputs.back().setTypeModifier(
+ GrGLShaderVar::kIn_TypeModifier);
+ segments->fGSInputs.back().setUnsizedArray();
+ *segments->fGSInputs.back().accessName() =
+ segments->fVSOutputs.back().getName();
+ segments->fGSOutputs.push_back();
+ segments->fGSOutputs.back().setType(type);
+ segments->fGSOutputs.back().setTypeModifier(
+ GrGLShaderVar::kOut_TypeModifier);
+ segments->fGSOutputs.back().accessName()->printf("g%s", name);
+ fsName = segments->fGSOutputs.back().accessName();
+ } else {
+ fsName = segments->fVSOutputs.back().accessName();
+ }
+ segments->fFSInputs.push_back();
+ segments->fFSInputs.back().setType(type);
+ segments->fFSInputs.back().setTypeModifier(
+ GrGLShaderVar::kIn_TypeModifier);
+ segments->fFSInputs.back().setName(*fsName);
+ if (fsInName) {
+ *fsInName = fsName->c_str();
+ }
+}
+
+// version of above that adds a stage number to the
+// the var name (for uniqueness)
+void append_varying(GrGLShaderVar::Type type,
+ const char* name,
+ int stageNum,
+ ShaderCodeSegments* segments,
+ const char** vsOutName = NULL,
+ const char** fsInName = NULL) {
+ GrStringBuilder nameWithStage(name);
+ nameWithStage.appendS32(stageNum);
+ append_varying(type, nameWithStage.c_str(), segments, vsOutName, fsInName);
+}
+}
+
+void GrGLProgram::genEdgeCoverage(const GrGLInterface* gl,
+ GrVertexLayout layout,
+ CachedData* programData,
+ GrStringBuilder* coverageVar,
+ ShaderCodeSegments* segments) const {
+ if (fProgramDesc.fEdgeAANumEdges > 0) {
+ segments->fFSUnis.push_back().set(GrGLShaderVar::kVec3f_Type,
+ GrGLShaderVar::kUniform_TypeModifier,
+ EDGES_UNI_NAME,
+ fProgramDesc.fEdgeAANumEdges);
+ programData->fUniLocations.fEdgesUni = kUseUniform;
+ int count = fProgramDesc.fEdgeAANumEdges;
+ segments->fFSCode.append(
+ "\tvec3 pos = vec3(gl_FragCoord.xy, 1);\n");
+ for (int i = 0; i < count; i++) {
+ segments->fFSCode.append("\tfloat a");
+ segments->fFSCode.appendS32(i);
+ segments->fFSCode.append(" = clamp(dot(" EDGES_UNI_NAME "[");
+ segments->fFSCode.appendS32(i);
+ segments->fFSCode.append("], pos), 0.0, 1.0);\n");
+ }
+ if (fProgramDesc.fEdgeAAConcave && (count & 0x01) == 0) {
+ // For concave polys, we consider the edges in pairs.
+ segments->fFSFunctions.append("float cross2(vec2 a, vec2 b) {\n");
+ segments->fFSFunctions.append("\treturn dot(a, vec2(b.y, -b.x));\n");
+ segments->fFSFunctions.append("}\n");
+ for (int i = 0; i < count; i += 2) {
+ segments->fFSCode.appendf("\tfloat eb%d;\n", i / 2);
+ segments->fFSCode.appendf("\tif (cross2(" EDGES_UNI_NAME "[%d].xy, " EDGES_UNI_NAME "[%d].xy) < 0.0) {\n", i, i + 1);
+ segments->fFSCode.appendf("\t\teb%d = a%d * a%d;\n", i / 2, i, i + 1);
+ segments->fFSCode.append("\t} else {\n");
+ segments->fFSCode.appendf("\t\teb%d = a%d + a%d - a%d * a%d;\n", i / 2, i, i + 1, i, i + 1);
+ segments->fFSCode.append("\t}\n");
+ }
+ segments->fFSCode.append("\tfloat edgeAlpha = ");
+ for (int i = 0; i < count / 2 - 1; i++) {
+ segments->fFSCode.appendf("min(eb%d, ", i);
+ }
+ segments->fFSCode.appendf("eb%d", count / 2 - 1);
+ for (int i = 0; i < count / 2 - 1; i++) {
+ segments->fFSCode.append(")");
+ }
+ segments->fFSCode.append(";\n");
+ } else {
+ segments->fFSCode.append("\tfloat edgeAlpha = ");
+ for (int i = 0; i < count - 1; i++) {
+ segments->fFSCode.appendf("min(a%d * a%d, ", i, i + 1);
+ }
+ segments->fFSCode.appendf("a%d * a0", count - 1);
+ for (int i = 0; i < count - 1; i++) {
+ segments->fFSCode.append(")");
+ }
+ segments->fFSCode.append(";\n");
+ }
+ *coverageVar = "edgeAlpha";
+ } else if (layout & GrDrawTarget::kEdge_VertexLayoutBit) {
+ const char *vsName, *fsName;
+ append_varying(GrGLShaderVar::kVec4f_Type, "Edge", segments,
+ &vsName, &fsName);
+ segments->fVSAttrs.push_back().set(GrGLShaderVar::kVec4f_Type,
+ GrGLShaderVar::kAttribute_TypeModifier, EDGE_ATTR_NAME);
+ segments->fVSCode.appendf("\t%s = " EDGE_ATTR_NAME ";\n", vsName);
+ if (GrDrawState::kHairLine_EdgeType == fProgramDesc.fVertexEdgeType) {
+ segments->fFSCode.appendf("\tfloat edgeAlpha = abs(dot(vec3(gl_FragCoord.xy,1), %s.xyz));\n", fsName);
+ } else {
+ GrAssert(GrDrawState::kHairQuad_EdgeType == fProgramDesc.fVertexEdgeType);
+ // for now we know we're not in perspective, so we could compute this
+ // per-quadratic rather than per pixel
+ segments->fFSCode.appendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
+ segments->fFSCode.appendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
+ segments->fFSCode.appendf("\tfloat dfdx = 2.0*%s.x*duvdx.x - duvdx.y;\n", fsName);
+ segments->fFSCode.appendf("\tfloat dfdy = 2.0*%s.x*duvdy.x - duvdy.y;\n", fsName);
+ segments->fFSCode.appendf("\tfloat edgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
+ segments->fFSCode.append("\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / (dfdx*dfdx + dfdy*dfdy));\n");
+ if (gl->supportsES2()) {
+ segments->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n");
+ }
+ }
+ segments->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
+ *coverageVar = "edgeAlpha";
+ } else {
+ coverageVar->reset();
+ }
+}
+
+namespace {
+
+// returns true if the color output was explicitly declared or not.
+bool decl_and_get_fs_color_output(GrGLSLGeneration v,
+ VarArray* fsOutputs,
+ const char** name) {
+ switch (v) {
+ case k110_GLSLGeneration:
+ *name = "gl_FragColor";
+ return false;
+ break;
+ case k130_GLSLGeneration: // fallthru
+ case k150_GLSLGeneration:
+ *name = declared_color_output_name();
+ fsOutputs->push_back().set(GrGLShaderVar::kVec4f_Type,
+ GrGLShaderVar::kOut_TypeModifier,
+ declared_color_output_name());
+ return true;
+ break;
+ default:
+ GrCrash("Unknown GLSL version.");
+ return false; // suppress warning
+ }
+}
+
+void genInputColor(GrGLProgram::ProgramDesc::ColorInput colorInput,
+ GrGLProgram::CachedData* programData,
+ ShaderCodeSegments* segments,
+ GrStringBuilder* inColor) {
+ switch (colorInput) {
+ case GrGLProgram::ProgramDesc::kAttribute_ColorInput: {
+ segments->fVSAttrs.push_back().set(GrGLShaderVar::kVec4f_Type,
+ GrGLShaderVar::kAttribute_TypeModifier,
+ COL_ATTR_NAME);
+ const char *vsName, *fsName;
+ append_varying(GrGLShaderVar::kVec4f_Type, "Color", segments, &vsName, &fsName);
+ segments->fVSCode.appendf("\t%s = " COL_ATTR_NAME ";\n", vsName);
+ *inColor = fsName;
+ } break;
+ case GrGLProgram::ProgramDesc::kUniform_ColorInput:
+ segments->fFSUnis.push_back().set(GrGLShaderVar::kVec4f_Type,
+ GrGLShaderVar::kUniform_TypeModifier,
+ COL_UNI_NAME);
+ programData->fUniLocations.fColorUni = kUseUniform;
+ *inColor = COL_UNI_NAME;
+ break;
+ case GrGLProgram::ProgramDesc::kTransBlack_ColorInput:
+ GrAssert(!"needComputedColor should be false.");
+ break;
+ case GrGLProgram::ProgramDesc::kSolidWhite_ColorInput:
+ break;
+ default:
+ GrCrash("Unknown color type.");
+ break;
+ }
+}
+
+void genPerVertexCoverage(ShaderCodeSegments* segments,
+ GrStringBuilder* inCoverage) {
+ segments->fVSAttrs.push_back().set(GrGLShaderVar::kFloat_Type,
+ GrGLShaderVar::kAttribute_TypeModifier,
+ COV_ATTR_NAME);
+ const char *vsName, *fsName;
+ append_varying(GrGLShaderVar::kFloat_Type, "Coverage",
+ segments, &vsName, &fsName);
+ segments->fVSCode.appendf("\t%s = " COV_ATTR_NAME ";\n", vsName);
+ if (inCoverage->size()) {
+ segments->fFSCode.appendf("\tfloat edgeAndAttrCov = %s * %s;\n",
+ fsName, inCoverage->c_str());
+ *inCoverage = "edgeAndAttrCov";
+ } else {
+ *inCoverage = fsName;
+ }
+}
+
+}
+
+void GrGLProgram::genGeometryShader(const GrGLInterface* gl,
+ GrGLSLGeneration glslGeneration,
+ ShaderCodeSegments* segments) const {
+#if GR_GL_EXPERIMENTAL_GS
+ if (fProgramDesc.fExperimentalGS) {
+ GrAssert(glslGeneration >= k150_GLSLGeneration);
+ segments->fGSHeader.append("layout(triangles) in;\n"
+ "layout(triangle_strip, max_vertices = 6) out;\n");
+ segments->fGSCode.append("void main() {\n"
+ "\tfor (int i = 0; i < 3; ++i) {\n"
+ "\t\tgl_Position = gl_in[i].gl_Position;\n");
+ if (this->fProgramDesc.fEmitsPointSize) {
+ segments->fGSCode.append("\t\tgl_PointSize = 1.0;\n");
+ }
+ GrAssert(segments->fGSInputs.count() == segments->fGSOutputs.count());
+ int count = segments->fGSInputs.count();
+ for (int i = 0; i < count; ++i) {
+ segments->fGSCode.appendf("\t\t%s = %s[i];\n",
+ segments->fGSOutputs[i].getName().c_str(),
+ segments->fGSInputs[i].getName().c_str());
+ }
+ segments->fGSCode.append("\t\tEmitVertex();\n"
+ "\t}\n"
+ "\tEndPrimitive();\n"
+ "}\n");
+ }
+#endif
+}
+
+const char* GrGLProgram::adjustInColor(const GrStringBuilder& inColor) const {
+ const char* color;
+ if (inColor.size()) {
+ return inColor.c_str();
+ } else {
+ if (ProgramDesc::kSolidWhite_ColorInput == fProgramDesc.fColorInput) {
+ return all_ones_vec(4);
+ } else {
+ return all_zeros_vec(4);
+ }
+ }
+}
+
+bool GrGLProgram::genProgram(const GrGLInterface* gl,
+ GrGLSLGeneration glslGeneration,
+ GrGLProgram::CachedData* programData) const {
+
+ ShaderCodeSegments segments;
+ const uint32_t& layout = fProgramDesc.fVertexLayout;
+
+ programData->fUniLocations.reset();
+
+#if GR_GL_EXPERIMENTAL_GS
+ segments.fUsesGS = fProgramDesc.fExperimentalGS;
+#endif
+
+ SkXfermode::Coeff colorCoeff, uniformCoeff;
+ // The rest of transfer mode color filters have not been implemented
+ if (fProgramDesc.fColorFilterXfermode < SkXfermode::kCoeffModesCnt) {
+ GR_DEBUGCODE(bool success =)
+ SkXfermode::ModeAsCoeff(static_cast<SkXfermode::Mode>
+ (fProgramDesc.fColorFilterXfermode),
+ &uniformCoeff, &colorCoeff);
+ GR_DEBUGASSERT(success);
+ } else {
+ colorCoeff = SkXfermode::kOne_Coeff;
+ uniformCoeff = SkXfermode::kZero_Coeff;
+ }
+
+ // If we know the final color is going to be all zeros then we can
+ // simplify the color filter coeffecients. needComputedColor will then
+ // come out false below.
+ if (ProgramDesc::kTransBlack_ColorInput == fProgramDesc.fColorInput) {
+ colorCoeff = SkXfermode::kZero_Coeff;
+ if (SkXfermode::kDC_Coeff == uniformCoeff ||
+ SkXfermode::kDA_Coeff == uniformCoeff) {
+ uniformCoeff = SkXfermode::kZero_Coeff;
+ } else if (SkXfermode::kIDC_Coeff == uniformCoeff ||
+ SkXfermode::kIDA_Coeff == uniformCoeff) {
+ uniformCoeff = SkXfermode::kOne_Coeff;
+ }
+ }
+
+ bool needColorFilterUniform;
+ bool needComputedColor;
+ needBlendInputs(uniformCoeff, colorCoeff,
+ &needColorFilterUniform, &needComputedColor);
+
+ // the dual source output has no canonical var name, have to
+ // declare an output, which is incompatible with gl_FragColor/gl_FragData.
+ const char* fsColorOutput = NULL;
+ bool dualSourceOutputWritten = false;
+ segments.fHeader.printf(glsl_version_string(gl, glslGeneration));
+ bool isColorDeclared = decl_and_get_fs_color_output(glslGeneration,
+ &segments.fFSOutputs,
+ &fsColorOutput);
+
+#if GR_GL_ATTRIBUTE_MATRICES
+ segments.fVSAttrs.push_back().set(GrGLShaderVar::kMat33f_Type,
+ GrGLShaderVar::kAttribute_TypeModifier, VIEW_MATRIX_NAME);
+ programData->fUniLocations.fViewMatrixUni = kSetAsAttribute;
+#else
+ segments.fVSUnis.push_back().set(GrGLShaderVar::kMat33f_Type,
+ GrGLShaderVar::kUniform_TypeModifier, VIEW_MATRIX_NAME);
+ programData->fUniLocations.fViewMatrixUni = kUseUniform;
+#endif
+ segments.fVSAttrs.push_back().set(GrGLShaderVar::kVec2f_Type,
+ GrGLShaderVar::kAttribute_TypeModifier, POS_ATTR_NAME);
+
+ segments.fVSCode.append(
+ "void main() {\n"
+ "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3("POS_ATTR_NAME", 1);\n"
+ "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n");
+
+ // incoming color to current stage being processed.
+ GrStringBuilder inColor;
+
+ if (needComputedColor) {
+ genInputColor((ProgramDesc::ColorInput) fProgramDesc.fColorInput,
+ programData, &segments, &inColor);
+ }
+
+ // we output point size in the GS if present
+ if (fProgramDesc.fEmitsPointSize && !segments.fUsesGS){
+ segments.fVSCode.append("\tgl_PointSize = 1.0;\n");
+ }
+
+ segments.fFSCode.append("void main() {\n");
+
+ // add texture coordinates that are used to the list of vertex attr decls
+ GrStringBuilder texCoordAttrs[GrDrawState::kMaxTexCoords];
+ for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
+ if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
+ tex_attr_name(t, texCoordAttrs + t);
+ segments.fVSAttrs.push_back().set(GrGLShaderVar::kVec2f_Type,
+ GrGLShaderVar::kAttribute_TypeModifier,
+ texCoordAttrs[t].c_str());
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // compute the final color
+
+ // if we have color stages string them together, feeding the output color
+ // of each to the next and generating code for each stage.
+ if (needComputedColor) {
+ GrStringBuilder outColor;
+ for (int s = 0; s < fProgramDesc.fFirstCoverageStage; ++s) {
+ if (fProgramDesc.fStages[s].isEnabled()) {
+ // create var to hold stage result
+ outColor = "color";
+ outColor.appendS32(s);
+ segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
+
+ const char* inCoords;
+ // figure out what our input coords are
+ if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) &
+ layout) {
+ inCoords = POS_ATTR_NAME;
+ } else {
+ int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
+ // we better have input tex coordinates if stage is enabled.
+ GrAssert(tcIdx >= 0);
+ GrAssert(texCoordAttrs[tcIdx].size());
+ inCoords = texCoordAttrs[tcIdx].c_str();
+ }
+
+ this->genStageCode(gl,
+ s,
+ fProgramDesc.fStages[s],
+ inColor.size() ? inColor.c_str() : NULL,
+ outColor.c_str(),
+ inCoords,
+ &segments,
+ &programData->fUniLocations.fStages[s]);
+ inColor = outColor;
+ }
+ }
+ }
+
+ // if have all ones or zeros for the "dst" input to the color filter then we
+ // may be able to make additional optimizations.
+ if (needColorFilterUniform && needComputedColor && !inColor.size()) {
+ GrAssert(ProgramDesc::kSolidWhite_ColorInput == fProgramDesc.fColorInput);
+ bool uniformCoeffIsZero = SkXfermode::kIDC_Coeff == uniformCoeff ||
+ SkXfermode::kIDA_Coeff == uniformCoeff;
+ if (uniformCoeffIsZero) {
+ uniformCoeff = SkXfermode::kZero_Coeff;
+ bool bogus;
+ needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff,
+ &needColorFilterUniform, &bogus);
+ }
+ }
+ if (needColorFilterUniform) {
+ segments.fFSUnis.push_back().set(GrGLShaderVar::kVec4f_Type,
+ GrGLShaderVar::kUniform_TypeModifier,
+ COL_FILTER_UNI_NAME);
+ programData->fUniLocations.fColorFilterUni = kUseUniform;
+ }
+ bool wroteFragColorZero = false;
+ if (SkXfermode::kZero_Coeff == uniformCoeff &&
+ SkXfermode::kZero_Coeff == colorCoeff &&
+ !fProgramDesc.fColorMatrixEnabled) {
+ segments.fFSCode.appendf("\t%s = %s;\n",
+ fsColorOutput,
+ all_zeros_vec(4));
+ wroteFragColorZero = true;
+ } else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) {
+ segments.fFSCode.appendf("\tvec4 filteredColor;\n");
+ const char* color = adjustInColor(inColor);
+ addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff,
+ colorCoeff, color);
+ inColor = "filteredColor";
+ }
+ if (fProgramDesc.fColorMatrixEnabled) {
+ segments.fFSUnis.push_back().set(GrGLShaderVar::kMat44f_Type,
+ GrGLShaderVar::kUniform_TypeModifier,
+ COL_MATRIX_UNI_NAME);
+ segments.fFSUnis.push_back().set(GrGLShaderVar::kVec4f_Type,
+ GrGLShaderVar::kUniform_TypeModifier,
+ COL_MATRIX_VEC_UNI_NAME);
+ programData->fUniLocations.fColorMatrixUni = kUseUniform;
+ programData->fUniLocations.fColorMatrixVecUni = kUseUniform;
+ segments.fFSCode.appendf("\tvec4 matrixedColor;\n");
+ const char* color = adjustInColor(inColor);
+ addColorMatrix(&segments.fFSCode, "matrixedColor", color);
+ inColor = "matrixedColor";
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // compute the partial coverage (coverage stages and edge aa)
+
+ GrStringBuilder inCoverage;
+
+ // we don't need to compute coverage at all if we know the final shader
+ // output will be zero and we don't have a dual src blend output.
+ if (!wroteFragColorZero ||
+ ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) {
+
+ // get edge AA coverage and use it as inCoverage to first coverage stage
+ this->genEdgeCoverage(gl, layout, programData, &inCoverage, &segments);
+
+ // include explicit per-vertex coverage if we have it
+ if (GrDrawTarget::kCoverage_VertexLayoutBit & layout) {
+ genPerVertexCoverage(&segments, &inCoverage);
+ }
+
+ GrStringBuilder outCoverage;
+ const int& startStage = fProgramDesc.fFirstCoverageStage;
+ for (int s = startStage; s < GrDrawState::kNumStages; ++s) {
+ if (fProgramDesc.fStages[s].isEnabled()) {
+ // create var to hold stage output
+ outCoverage = "coverage";
+ outCoverage.appendS32(s);
+ segments.fFSCode.appendf("\tvec4 %s;\n", outCoverage.c_str());
+
+ const char* inCoords;
+ // figure out what our input coords are
+ if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) {
+ inCoords = POS_ATTR_NAME;
+ } else {
+ int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout);
+ // we better have input tex coordinates if stage is enabled.
+ GrAssert(tcIdx >= 0);
+ GrAssert(texCoordAttrs[tcIdx].size());
+ inCoords = texCoordAttrs[tcIdx].c_str();
+ }
+
+ genStageCode(gl, s,
+ fProgramDesc.fStages[s],
+ inCoverage.size() ? inCoverage.c_str() : NULL,
+ outCoverage.c_str(),
+ inCoords,
+ &segments,
+ &programData->fUniLocations.fStages[s]);
+ inCoverage = outCoverage;
+ }
+ }
+ if (ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) {
+ segments.fFSOutputs.push_back().set(GrGLShaderVar::kVec4f_Type,
+ GrGLShaderVar::kOut_TypeModifier,
+ dual_source_output_name());
+ bool outputIsZero = false;
+ GrStringBuilder coeff;
+ if (ProgramDesc::kCoverage_DualSrcOutput !=
+ fProgramDesc.fDualSrcOutput && !wroteFragColorZero) {
+ if (!inColor.size()) {
+ outputIsZero = true;
+ } else {
+ if (fProgramDesc.fDualSrcOutput ==
+ ProgramDesc::kCoverageISA_DualSrcOutput) {
+ coeff.printf("(1 - %s.a)", inColor.c_str());
+ } else {
+ coeff.printf("(vec4(1,1,1,1) - %s)", inColor.c_str());
+ }
+ }
+ }
+ if (outputIsZero) {
+ segments.fFSCode.appendf("\t%s = %s;\n",
+ dual_source_output_name(),
+ all_zeros_vec(4));
+ } else {
+ modulate_helper(dual_source_output_name(),
+ coeff.c_str(),
+ inCoverage.c_str(),
+ &segments.fFSCode);
+ }
+ dualSourceOutputWritten = true;
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // combine color and coverage as frag color
+
+ if (!wroteFragColorZero) {
+ modulate_helper(fsColorOutput,
+ inColor.c_str(),
+ inCoverage.c_str(),
+ &segments.fFSCode);
+ if (ProgramDesc::kNo_OutputPM == fProgramDesc.fOutputPM) {
+ segments.fFSCode.appendf("\t%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(%s.rgb / %s.a, %s.a);\n",
+ fsColorOutput,
+ fsColorOutput,
+ fsColorOutput,
+ fsColorOutput,
+ fsColorOutput);
+ }
+ }
+
+ segments.fVSCode.append("}\n");
+ segments.fFSCode.append("}\n");
+
+ ///////////////////////////////////////////////////////////////////////////
+ // insert GS
+#if GR_DEBUG
+ this->genGeometryShader(gl, glslGeneration, &segments);
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ // compile and setup attribs and unis
+
+ if (!CompileShaders(gl, glslGeneration, segments, programData)) {
+ return false;
+ }
+
+ if (!this->bindOutputsAttribsAndLinkProgram(gl, texCoordAttrs,
+ isColorDeclared,
+ dualSourceOutputWritten,
+ programData)) {
+ return false;
+ }
+
+ this->getUniformLocationsAndInitCache(gl, programData);
+
+ return true;
+}
+
+namespace {
+
+inline void expand_decls(const VarArray& vars,
+ const GrGLInterface* gl,
+ GrStringBuilder* string,
+ GrGLSLGeneration gen) {
+ const int count = vars.count();
+ for (int i = 0; i < count; ++i) {
+ vars[i].appendDecl(gl, string, gen);
+ }
+}
+
+inline void print_shader(int stringCnt,
+ const char** strings,
+ int* stringLengths) {
+ for (int i = 0; i < stringCnt; ++i) {
+ if (NULL == stringLengths || stringLengths[i] < 0) {
+ GrPrintf(strings[i]);
+ } else {
+ GrPrintf("%.*s", stringLengths[i], strings[i]);
+ }
+ }
+}
+
+typedef SkTArray<const char*, true> StrArray;
+#define PREALLOC_STR_ARRAY(N) SkSTArray<(N), const char*, true>
+
+typedef SkTArray<int, true> LengthArray;
+#define PREALLOC_LENGTH_ARRAY(N) SkSTArray<(N), int, true>
+
+// these shouldn't relocate
+typedef GrTAllocator<GrStringBuilder> TempArray;
+#define PREALLOC_TEMP_ARRAY(N) GrSTAllocator<(N), GrStringBuilder>
+
+inline void append_string(const GrStringBuilder& str,
+ StrArray* strings,
+ LengthArray* lengths) {
+ int length = (int) str.size();
+ if (length) {
+ strings->push_back(str.c_str());
+ lengths->push_back(length);
+ }
+ GrAssert(strings->count() == lengths->count());
+}
+
+inline void append_decls(const VarArray& vars,
+ const GrGLInterface* gl,
+ StrArray* strings,
+ LengthArray* lengths,
+ TempArray* temp,
+ GrGLSLGeneration gen) {
+ expand_decls(vars, gl, &temp->push_back(), gen);
+ append_string(temp->back(), strings, lengths);
+}
+
+}
+
+bool GrGLProgram::CompileShaders(const GrGLInterface* gl,
+ GrGLSLGeneration glslGeneration,
+ const ShaderCodeSegments& segments,
+ CachedData* programData) {
+ enum { kPreAllocStringCnt = 8 };
+
+ PREALLOC_STR_ARRAY(kPreAllocStringCnt) strs;
+ PREALLOC_LENGTH_ARRAY(kPreAllocStringCnt) lengths;
+ PREALLOC_TEMP_ARRAY(kPreAllocStringCnt) temps;
+
+ GrStringBuilder unis;
+ GrStringBuilder inputs;
+ GrStringBuilder outputs;
+
+ append_string(segments.fHeader, &strs, &lengths);
+ append_decls(segments.fVSUnis, gl, &strs, &lengths, &temps, glslGeneration);
+ append_decls(segments.fVSAttrs, gl, &strs, &lengths,
+ &temps, glslGeneration);
+ append_decls(segments.fVSOutputs, gl, &strs, &lengths,
+ &temps, glslGeneration);
+ append_string(segments.fVSCode, &strs, &lengths);
+
+#if PRINT_SHADERS
+ print_shader(strs.count(), &strs[0], &lengths[0]);
+ GrPrintf("\n");
+#endif
+
+ programData->fVShaderID =
+ CompileShader(gl, GR_GL_VERTEX_SHADER, strs.count(),
+ &strs[0], &lengths[0]);
+
+ if (!programData->fVShaderID) {
+ return false;
+ }
+ if (segments.fUsesGS) {
+ strs.reset();
+ lengths.reset();
+ temps.reset();
+ append_string(segments.fHeader, &strs, &lengths);
+ append_string(segments.fGSHeader, &strs, &lengths);
+ append_decls(segments.fGSInputs, gl, &strs, &lengths,
+ &temps, glslGeneration);
+ append_decls(segments.fGSOutputs, gl, &strs, &lengths,
+ &temps, glslGeneration);
+ append_string(segments.fGSCode, &strs, &lengths);
+#if PRINT_SHADERS
+ print_shader(strs.count(), &strs[0], &lengths[0]);
+ GrPrintf("\n");
+#endif
+ programData->fGShaderID =
+ CompileShader(gl, GR_GL_GEOMETRY_SHADER, strs.count(),
+ &strs[0], &lengths[0]);
+ } else {
+ programData->fGShaderID = 0;
+ }
+
+ strs.reset();
+ lengths.reset();
+ temps.reset();
+
+ append_string(segments.fHeader, &strs, &lengths);
+ GrStringBuilder precisionStr(GrShaderPrecision(gl));
+ append_string(precisionStr, &strs, &lengths);
+ append_decls(segments.fFSUnis, gl, &strs, &lengths, &temps, glslGeneration);
+ append_decls(segments.fFSInputs, gl, &strs, &lengths,
+ &temps, glslGeneration);
+ // We shouldn't have declared outputs on 1.10
+ GrAssert(k110_GLSLGeneration != glslGeneration ||
+ segments.fFSOutputs.empty());
+ append_decls(segments.fFSOutputs, gl, &strs, &lengths,
+ &temps, glslGeneration);
+ append_string(segments.fFSFunctions, &strs, &lengths);
+ append_string(segments.fFSCode, &strs, &lengths);
+
+#if PRINT_SHADERS
+ print_shader(strs.count(), &strs[0], &lengths[0]);
+ GrPrintf("\n");
+#endif
+
+ programData->fFShaderID =
+ CompileShader(gl, GR_GL_FRAGMENT_SHADER, strs.count(),
+ &strs[0], &lengths[0]);
+
+ if (!programData->fFShaderID) {
+ return false;
+ }
+
+ return true;
+}
+
+GrGLuint GrGLProgram::CompileShader(const GrGLInterface* gl,
+ GrGLenum type,
+ int stringCnt,
+ const char** strings,
+ int* stringLengths) {
+ SK_TRACE_EVENT1("GrGLProgram::CompileShader",
+ "stringCount", SkStringPrintf("%i", stringCnt).c_str());
+
+ GrGLuint shader;
+ GR_GL_CALL_RET(gl, shader, CreateShader(type));
+ if (0 == shader) {
+ return 0;
+ }
+
+ GrGLint compiled = GR_GL_INIT_ZERO;
+ GR_GL_CALL(gl, ShaderSource(shader, stringCnt, strings, stringLengths));
+ GR_GL_CALL(gl, CompileShader(shader));
+ GR_GL_CALL(gl, GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled));
+
+ if (!compiled) {
+ GrGLint infoLen = GR_GL_INIT_ZERO;
+ GR_GL_CALL(gl, GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen));
+ SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
+ if (infoLen > 0) {
+ // retrieve length even though we don't need it to workaround
+ // bug in chrome cmd buffer param validation.
+ GrGLsizei length = GR_GL_INIT_ZERO;
+ GR_GL_CALL(gl, GetShaderInfoLog(shader, infoLen+1,
+ &length, (char*)log.get()));
+ print_shader(stringCnt, strings, stringLengths);
+ GrPrintf("\n%s", log.get());
+ }
+ GrAssert(!"Shader compilation failed!");
+ GR_GL_CALL(gl, DeleteShader(shader));
+ return 0;
+ }
+ return shader;
+}
+
+bool GrGLProgram::bindOutputsAttribsAndLinkProgram(
+ const GrGLInterface* gl,
+ GrStringBuilder texCoordAttrNames[],
+ bool bindColorOut,
+ bool bindDualSrcOut,
+ CachedData* programData) const {
+ GR_GL_CALL_RET(gl, programData->fProgramID, CreateProgram());
+ if (!programData->fProgramID) {
+ return false;
+ }
+ const GrGLint& progID = programData->fProgramID;
+
+ GR_GL_CALL(gl, AttachShader(progID, programData->fVShaderID));
+ if (programData->fGShaderID) {
+ GR_GL_CALL(gl, AttachShader(progID, programData->fGShaderID));
+ }
+ GR_GL_CALL(gl, AttachShader(progID, programData->fFShaderID));
+
+ if (bindColorOut) {
+ GR_GL_CALL(gl, BindFragDataLocation(programData->fProgramID,
+ 0, declared_color_output_name()));
+ }
+ if (bindDualSrcOut) {
+ GR_GL_CALL(gl, BindFragDataLocationIndexed(programData->fProgramID,
+ 0, 1, dual_source_output_name()));
+ }
+
+ // Bind the attrib locations to same values for all shaders
+ GR_GL_CALL(gl, BindAttribLocation(progID, PositionAttributeIdx(),
+ POS_ATTR_NAME));
+ for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
+ if (texCoordAttrNames[t].size()) {
+ GR_GL_CALL(gl, BindAttribLocation(progID,
+ TexCoordAttributeIdx(t),
+ texCoordAttrNames[t].c_str()));
+ }
+ }
+
+ if (kSetAsAttribute == programData->fUniLocations.fViewMatrixUni) {
+ GR_GL_CALL(gl, BindAttribLocation(progID,
+ ViewMatrixAttributeIdx(),
+ VIEW_MATRIX_NAME));
+ }
+
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ const StageUniLocations& unis = programData->fUniLocations.fStages[s];
+ if (kSetAsAttribute == unis.fTextureMatrixUni) {
+ GrStringBuilder matName;
+ tex_matrix_name(s, &matName);
+ GR_GL_CALL(gl, BindAttribLocation(progID,
+ TextureMatrixAttributeIdx(s),
+ matName.c_str()));
+ }
+ }
+
+ GR_GL_CALL(gl, BindAttribLocation(progID, ColorAttributeIdx(),
+ COL_ATTR_NAME));
+ GR_GL_CALL(gl, BindAttribLocation(progID, CoverageAttributeIdx(),
+ COV_ATTR_NAME));
+ GR_GL_CALL(gl, BindAttribLocation(progID, EdgeAttributeIdx(),
+ EDGE_ATTR_NAME));
+
+ GR_GL_CALL(gl, LinkProgram(progID));
+
+ GrGLint linked = GR_GL_INIT_ZERO;
+ GR_GL_CALL(gl, GetProgramiv(progID, GR_GL_LINK_STATUS, &linked));
+ if (!linked) {
+ GrGLint infoLen = GR_GL_INIT_ZERO;
+ GR_GL_CALL(gl, GetProgramiv(progID, GR_GL_INFO_LOG_LENGTH, &infoLen));
+ SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
+ if (infoLen > 0) {
+ // retrieve length even though we don't need it to workaround
+ // bug in chrome cmd buffer param validation.
+ GrGLsizei length = GR_GL_INIT_ZERO;
+ GR_GL_CALL(gl, GetProgramInfoLog(progID, infoLen+1,
+ &length, (char*)log.get()));
+ GrPrintf((char*)log.get());
+ }
+ GrAssert(!"Error linking program");
+ GR_GL_CALL(gl, DeleteProgram(progID));
+ programData->fProgramID = 0;
+ return false;
+ }
+ return true;
+}
+
+void GrGLProgram::getUniformLocationsAndInitCache(const GrGLInterface* gl,
+ CachedData* programData) const {
+ const GrGLint& progID = programData->fProgramID;
+
+ if (kUseUniform == programData->fUniLocations.fViewMatrixUni) {
+ GR_GL_CALL_RET(gl, programData->fUniLocations.fViewMatrixUni,
+ GetUniformLocation(progID, VIEW_MATRIX_NAME));
+ GrAssert(kUnusedUniform != programData->fUniLocations.fViewMatrixUni);
+ }
+ if (kUseUniform == programData->fUniLocations.fColorUni) {
+ GR_GL_CALL_RET(gl, programData->fUniLocations.fColorUni,
+ GetUniformLocation(progID, COL_UNI_NAME));
+ GrAssert(kUnusedUniform != programData->fUniLocations.fColorUni);
+ }
+ if (kUseUniform == programData->fUniLocations.fColorFilterUni) {
+ GR_GL_CALL_RET(gl, programData->fUniLocations.fColorFilterUni,
+ GetUniformLocation(progID, COL_FILTER_UNI_NAME));
+ GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni);
+ }
+
+ if (kUseUniform == programData->fUniLocations.fColorMatrixUni) {
+ GR_GL_CALL_RET(gl, programData->fUniLocations.fColorMatrixUni,
+ GetUniformLocation(progID, COL_MATRIX_UNI_NAME));
+ }
+
+ if (kUseUniform == programData->fUniLocations.fColorMatrixVecUni) {
+ GR_GL_CALL_RET(gl, programData->fUniLocations.fColorMatrixVecUni,
+ GetUniformLocation(progID, COL_MATRIX_VEC_UNI_NAME));
+ }
+
+ if (kUseUniform == programData->fUniLocations.fEdgesUni) {
+ GR_GL_CALL_RET(gl, programData->fUniLocations.fEdgesUni,
+ GetUniformLocation(progID, EDGES_UNI_NAME));
+ GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni);
+ } else {
+ programData->fUniLocations.fEdgesUni = kUnusedUniform;
+ }
+
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ StageUniLocations& locations = programData->fUniLocations.fStages[s];
+ if (fProgramDesc.fStages[s].isEnabled()) {
+ if (kUseUniform == locations.fTextureMatrixUni) {
+ GrStringBuilder texMName;
+ tex_matrix_name(s, &texMName);
+ GR_GL_CALL_RET(gl, locations.fTextureMatrixUni,
+ GetUniformLocation(progID, texMName.c_str()));
+ GrAssert(kUnusedUniform != locations.fTextureMatrixUni);
+ }
+
+ if (kUseUniform == locations.fSamplerUni) {
+ GrStringBuilder samplerName;
+ sampler_name(s, &samplerName);
+ GR_GL_CALL_RET(gl, locations.fSamplerUni,
+ GetUniformLocation(progID,samplerName.c_str()));
+ GrAssert(kUnusedUniform != locations.fSamplerUni);
+ }
+
+ if (kUseUniform == locations.fNormalizedTexelSizeUni) {
+ GrStringBuilder texelSizeName;
+ normalized_texel_size_name(s, &texelSizeName);
+ GR_GL_CALL_RET(gl, locations.fNormalizedTexelSizeUni,
+ GetUniformLocation(progID, texelSizeName.c_str()));
+ GrAssert(kUnusedUniform != locations.fNormalizedTexelSizeUni);
+ }
+
+ if (kUseUniform == locations.fRadial2Uni) {
+ GrStringBuilder radial2ParamName;
+ radial2_param_name(s, &radial2ParamName);
+ GR_GL_CALL_RET(gl, locations.fRadial2Uni,
+ GetUniformLocation(progID, radial2ParamName.c_str()));
+ GrAssert(kUnusedUniform != locations.fRadial2Uni);
+ }
+
+ if (kUseUniform == locations.fTexDomUni) {
+ GrStringBuilder texDomName;
+ tex_domain_name(s, &texDomName);
+ GR_GL_CALL_RET(gl, locations.fTexDomUni,
+ GetUniformLocation(progID, texDomName.c_str()));
+ GrAssert(kUnusedUniform != locations.fTexDomUni);
+ }
+
+ GrStringBuilder kernelName, imageIncrementName;
+ convolve_param_names(s, &kernelName, &imageIncrementName);
+ if (kUseUniform == locations.fKernelUni) {
+ GR_GL_CALL_RET(gl, locations.fKernelUni,
+ GetUniformLocation(progID, kernelName.c_str()));
+ GrAssert(kUnusedUniform != locations.fKernelUni);
+ }
+
+ if (kUseUniform == locations.fImageIncrementUni) {
+ GR_GL_CALL_RET(gl, locations.fImageIncrementUni,
+ GetUniformLocation(progID,
+ imageIncrementName.c_str()));
+ GrAssert(kUnusedUniform != locations.fImageIncrementUni);
+ }
+ }
+ }
+ GR_GL_CALL(gl, UseProgram(progID));
+
+ // init sampler unis and set bogus values for state tracking
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ if (kUnusedUniform != programData->fUniLocations.fStages[s].fSamplerUni) {
+ GR_GL_CALL(gl, Uniform1i(programData->fUniLocations.fStages[s].fSamplerUni, s));
+ }
+ programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
+ programData->fRadial2CenterX1[s] = GR_ScalarMax;
+ programData->fRadial2Radius0[s] = -GR_ScalarMax;
+ programData->fTextureWidth[s] = -1;
+ programData->fTextureHeight[s] = -1;
+ }
+ programData->fViewMatrix = GrMatrix::InvalidMatrix();
+ programData->fColor = GrColor_ILLEGAL;
+ programData->fColorFilterColor = GrColor_ILLEGAL;
+}
+
+//============================================================================
+// Stage code generation
+//============================================================================
+
+namespace {
+
+bool isRadialMapping(GrGLProgram::StageDesc::CoordMapping mapping) {
+ return
+ (GrGLProgram::StageDesc::kRadial2Gradient_CoordMapping == mapping ||
+ GrGLProgram::StageDesc::kRadial2GradientDegenerate_CoordMapping == mapping);
+}
+
+GrGLShaderVar* genRadialVS(int stageNum,
+ ShaderCodeSegments* segments,
+ GrGLProgram::StageUniLocations* locations,
+ const char** radial2VaryingVSName,
+ const char** radial2VaryingFSName,
+ const char* varyingVSName,
+ int varyingDims, int coordDims) {
+
+ GrGLShaderVar* radial2FSParams = &segments->fFSUnis.push_back();
+ radial2FSParams->setType(GrGLShaderVar::kFloat_Type);
+ radial2FSParams->setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
+ radial2FSParams->setArrayCount(6);
+ radial2_param_name(stageNum, radial2FSParams->accessName());
+ segments->fVSUnis.push_back(*radial2FSParams).setEmitPrecision(true);
+
+ locations->fRadial2Uni = kUseUniform;
+
+ // for radial grads without perspective we can pass the linear
+ // part of the quadratic as a varying.
+ if (varyingDims == coordDims) {
+ GrAssert(2 == coordDims);
+ append_varying(GrGLShaderVar::kFloat_Type,
+ "Radial2BCoeff",
+ stageNum,
+ segments,
+ radial2VaryingVSName,
+ radial2VaryingFSName);
+
+ GrStringBuilder radial2p2;
+ GrStringBuilder radial2p3;
+ radial2FSParams->appendArrayAccess(2, &radial2p2);
+ radial2FSParams->appendArrayAccess(3, &radial2p3);
+
+ // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
+ const char* r2ParamName = radial2FSParams->getName().c_str();
+ segments->fVSCode.appendf("\t%s = 2.0 *(%s * %s.x - %s);\n",
+ *radial2VaryingVSName, radial2p2.c_str(),
+ varyingVSName, radial2p3.c_str());
+ }
+
+ return radial2FSParams;
+}
+
+bool genRadial2GradientCoordMapping(int stageNum,
+ ShaderCodeSegments* segments,
+ const char* radial2VaryingFSName,
+ GrGLShaderVar* radial2Params,
+ GrStringBuilder& sampleCoords,
+ GrStringBuilder& fsCoordName,
+ int varyingDims,
+ int coordDims) {
+ GrStringBuilder cName("c");
+ GrStringBuilder ac4Name("ac4");
+ GrStringBuilder rootName("root");
+
+ cName.appendS32(stageNum);
+ ac4Name.appendS32(stageNum);
+ rootName.appendS32(stageNum);
+
+ GrStringBuilder radial2p0;
+ GrStringBuilder radial2p1;
+ GrStringBuilder radial2p2;
+ GrStringBuilder radial2p3;
+ GrStringBuilder radial2p4;
+ GrStringBuilder radial2p5;
+ radial2Params->appendArrayAccess(0, &radial2p0);
+ radial2Params->appendArrayAccess(1, &radial2p1);
+ radial2Params->appendArrayAccess(2, &radial2p2);
+ radial2Params->appendArrayAccess(3, &radial2p3);
+ radial2Params->appendArrayAccess(4, &radial2p4);
+ radial2Params->appendArrayAccess(5, &radial2p5);
+
+ // if we were able to interpolate the linear component bVar is the varying
+ // otherwise compute it
+ GrStringBuilder bVar;
+ if (coordDims == varyingDims) {
+ bVar = radial2VaryingFSName;
+ GrAssert(2 == varyingDims);
+ } else {
+ GrAssert(3 == varyingDims);
+ bVar = "b";
+ bVar.appendS32(stageNum);
+ segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s * %s.x - %s);\n",
+ bVar.c_str(), radial2p2.c_str(),
+ fsCoordName.c_str(), radial2p3.c_str());
+ }
+
+ // c = (x^2)+(y^2) - params[4]
+ segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s;\n",
+ cName.c_str(), fsCoordName.c_str(),
+ fsCoordName.c_str(),
+ radial2p4.c_str());
+ // ac4 = 4.0 * params[0] * c
+ segments->fFSCode.appendf("\tfloat %s = %s * 4.0 * %s;\n",
+ ac4Name.c_str(), radial2p0.c_str(),
+ cName.c_str());
+
+ // root = sqrt(b^2-4ac)
+ // (abs to avoid exception due to fp precision)
+ segments->fFSCode.appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
+ rootName.c_str(), bVar.c_str(), bVar.c_str(),
+ ac4Name.c_str());
+
+ // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
+ // y coord is 0.5 (texture is effectively 1D)
+ sampleCoords.printf("vec2((-%s + %s * %s) * %s, 0.5)",
+ bVar.c_str(), radial2p5.c_str(),
+ rootName.c_str(), radial2p1.c_str());
+ return true;
+}
+
+bool genRadial2GradientDegenerateCoordMapping(int stageNum,
+ ShaderCodeSegments* segments,
+ const char* radial2VaryingFSName,
+ GrGLShaderVar* radial2Params,
+ GrStringBuilder& sampleCoords,
+ GrStringBuilder& fsCoordName,
+ int varyingDims,
+ int coordDims) {
+ GrStringBuilder cName("c");
+
+ cName.appendS32(stageNum);
+
+ GrStringBuilder radial2p2;
+ GrStringBuilder radial2p3;
+ GrStringBuilder radial2p4;
+ radial2Params->appendArrayAccess(2, &radial2p2);
+ radial2Params->appendArrayAccess(3, &radial2p3);
+ radial2Params->appendArrayAccess(4, &radial2p4);
+
+ // if we were able to interpolate the linear component bVar is the varying
+ // otherwise compute it
+ GrStringBuilder bVar;
+ if (coordDims == varyingDims) {
+ bVar = radial2VaryingFSName;
+ GrAssert(2 == varyingDims);
+ } else {
+ GrAssert(3 == varyingDims);
+ bVar = "b";
+ bVar.appendS32(stageNum);
+ segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s * %s.x - %s);\n",
+ bVar.c_str(), radial2p2.c_str(),
+ fsCoordName.c_str(), radial2p3.c_str());
+ }
+
+ // c = (x^2)+(y^2) - params[4]
+ segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s;\n",
+ cName.c_str(), fsCoordName.c_str(),
+ fsCoordName.c_str(),
+ radial2p4.c_str());
+
+ // x coord is: -c/b
+ // y coord is 0.5 (texture is effectively 1D)
+ sampleCoords.printf("vec2((-%s / %s), 0.5)", cName.c_str(), bVar.c_str());
+ return true;
+}
+
+void gen2x2FS(int stageNum,
+ ShaderCodeSegments* segments,
+ GrGLProgram::StageUniLocations* locations,
+ GrStringBuilder* sampleCoords,
+ const char* samplerName,
+ const char* texelSizeName,
+ const char* swizzle,
+ const char* fsOutColor,
+ GrStringBuilder& texFunc,
+ GrStringBuilder& modulate,
+ bool complexCoord,
+ int coordDims) {
+ locations->fNormalizedTexelSizeUni = kUseUniform;
+ if (complexCoord) {
+ // assign the coord to a var rather than compute 4x.
+ GrStringBuilder coordVar("tCoord");
+ coordVar.appendS32(stageNum);
+ segments->fFSCode.appendf("\t%s %s = %s;\n",
+ float_vector_type_str(coordDims),
+ coordVar.c_str(), sampleCoords->c_str());
+ *sampleCoords = coordVar;
+ }
+ GrAssert(2 == coordDims);
+ GrStringBuilder accumVar("accum");
+ accumVar.appendS32(stageNum);
+ segments->fFSCode.appendf("\tvec4 %s = %s(%s, %s + vec2(-%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, sampleCoords->c_str(), texelSizeName, texelSizeName, swizzle);
+ segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, sampleCoords->c_str(), texelSizeName, texelSizeName, swizzle);
+ segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(-%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, sampleCoords->c_str(), texelSizeName, texelSizeName, swizzle);
+ segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, sampleCoords->c_str(), texelSizeName, texelSizeName, swizzle);
+ segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
+
+}
+
+void genConvolutionVS(int stageNum,
+ const StageDesc& desc,
+ ShaderCodeSegments* segments,
+ GrGLProgram::StageUniLocations* locations,
+ GrGLShaderVar** kernel,
+ const char** imageIncrementName,
+ const char* varyingVSName) {
+ //GrGLShaderVar* kernel = &segments->fFSUnis.push_back();
+ *kernel = &segments->fFSUnis.push_back();
+ (*kernel)->setType(GrGLShaderVar::kFloat_Type);
+ (*kernel)->setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
+ (*kernel)->setArrayCount(desc.fKernelWidth);
+ GrGLShaderVar* imgInc = &segments->fFSUnis.push_back();
+ imgInc->setType(GrGLShaderVar::kVec2f_Type);
+ imgInc->setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
+
+ convolve_param_names(stageNum,
+ (*kernel)->accessName(),
+ imgInc->accessName());
+ *imageIncrementName = imgInc->getName().c_str();
+
+ // need image increment in both VS and FS
+ segments->fVSUnis.push_back(*imgInc).setEmitPrecision(true);
+
+ locations->fKernelUni = kUseUniform;
+ locations->fImageIncrementUni = kUseUniform;
+ float scale = (desc.fKernelWidth - 1) * 0.5f;
+ segments->fVSCode.appendf("\t%s -= vec2(%g, %g) * %s;\n",
+ varyingVSName, scale, scale,
+ *imageIncrementName);
+}
+
+void genConvolutionFS(int stageNum,
+ const StageDesc& desc,
+ ShaderCodeSegments* segments,
+ const char* samplerName,
+ GrGLShaderVar* kernel,
+ const char* swizzle,
+ const char* imageIncrementName,
+ const char* fsOutColor,
+ GrStringBuilder& sampleCoords,
+ GrStringBuilder& texFunc,
+ GrStringBuilder& modulate) {
+ GrStringBuilder sumVar("sum");
+ sumVar.appendS32(stageNum);
+ GrStringBuilder coordVar("coord");
+ coordVar.appendS32(stageNum);
+
+ GrStringBuilder kernelIndex;
+ kernel->appendArrayAccess("i", &kernelIndex);
+
+ segments->fFSCode.appendf("\tvec4 %s = vec4(0, 0, 0, 0);\n",
+ sumVar.c_str());
+ segments->fFSCode.appendf("\tvec2 %s = %s;\n",
+ coordVar.c_str(),
+ sampleCoords.c_str());
+ segments->fFSCode.appendf("\tfor (int i = 0; i < %d; i++) {\n",
+ desc.fKernelWidth);
+ segments->fFSCode.appendf("\t\t%s += %s(%s, %s)%s * %s;\n",
+ sumVar.c_str(), texFunc.c_str(),
+ samplerName, coordVar.c_str(), swizzle,
+ kernelIndex.c_str());
+ segments->fFSCode.appendf("\t\t%s += %s;\n",
+ coordVar.c_str(),
+ imageIncrementName);
+ segments->fFSCode.appendf("\t}\n");
+ segments->fFSCode.appendf("\t%s = %s%s;\n", fsOutColor,
+ sumVar.c_str(), modulate.c_str());
+}
+
+}
+
+void GrGLProgram::genStageCode(const GrGLInterface* gl,
+ int stageNum,
+ const GrGLProgram::StageDesc& desc,
+ const char* fsInColor, // NULL means no incoming color
+ const char* fsOutColor,
+ const char* vsInCoord,
+ ShaderCodeSegments* segments,
+ StageUniLocations* locations) const {
+
+ GrAssert(stageNum >= 0 && stageNum <= GrDrawState::kNumStages);
+ GrAssert((desc.fInConfigFlags & StageDesc::kInConfigBitMask) ==
+ desc.fInConfigFlags);
+
+ // First decide how many coords are needed to access the texture
+ // Right now it's always 2 but we could start using 1D textures for
+ // gradients.
+ static const int coordDims = 2;
+ int varyingDims;
+ /// Vertex Shader Stuff
+
+ // decide whether we need a matrix to transform texture coords
+ // and whether the varying needs a perspective coord.
+ const char* matName = NULL;
+ if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
+ varyingDims = coordDims;
+ } else {
+ GrGLShaderVar* mat;
+ #if GR_GL_ATTRIBUTE_MATRICES
+ mat = &segments->fVSAttrs.push_back();
+ mat->setTypeModifier(GrGLShaderVar::kAttribute_TypeModifier);
+ locations->fTextureMatrixUni = kSetAsAttribute;
+ #else
+ mat = &segments->fVSUnis.push_back();
+ mat->setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
+ locations->fTextureMatrixUni = kUseUniform;
+ #endif
+ tex_matrix_name(stageNum, mat->accessName());
+ mat->setType(GrGLShaderVar::kMat33f_Type);
+ matName = mat->getName().c_str();
+
+ if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) {
+ varyingDims = coordDims;
+ } else {
+ varyingDims = coordDims + 1;
+ }
+ }
+
+ segments->fFSUnis.push_back().set(GrGLShaderVar::kSampler2D_Type,
+ GrGLShaderVar::kUniform_TypeModifier, "");
+ sampler_name(stageNum, segments->fFSUnis.back().accessName());
+ locations->fSamplerUni = kUseUniform;
+ const char* samplerName = segments->fFSUnis.back().getName().c_str();
+
+ const char* texelSizeName = NULL;
+ if (StageDesc::k2x2_FetchMode == desc.fFetchMode) {
+ segments->fFSUnis.push_back().set(GrGLShaderVar::kVec2f_Type,
+ GrGLShaderVar::kUniform_TypeModifier, "");
+ normalized_texel_size_name(stageNum, segments->fFSUnis.back().accessName());
+ texelSizeName = segments->fFSUnis.back().getName().c_str();
+ }
+
+ const char *varyingVSName, *varyingFSName;
+ append_varying(float_vector_type(varyingDims),
+ "Stage",
+ stageNum,
+ segments,
+ &varyingVSName,
+ &varyingFSName);
+
+ if (!matName) {
+ GrAssert(varyingDims == coordDims);
+ segments->fVSCode.appendf("\t%s = %s;\n", varyingVSName, vsInCoord);
+ } else {
+ // varying = texMatrix * texCoord
+ segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
+ varyingVSName, matName, vsInCoord,
+ vector_all_coords(varyingDims));
+ }
+
+ GrGLShaderVar* radial2Params = NULL;
+ const char* radial2VaryingVSName = NULL;
+ const char* radial2VaryingFSName = NULL;
+
+ if (isRadialMapping((StageDesc::CoordMapping) desc.fCoordMapping)) {
+ radial2Params = genRadialVS(stageNum, segments,
+ locations,
+ &radial2VaryingVSName,
+ &radial2VaryingFSName,
+ varyingVSName,
+ varyingDims, coordDims);
+ }
+
+ GrGLShaderVar* kernel = NULL;
+ const char* imageIncrementName = NULL;
+ if (StageDesc::kConvolution_FetchMode == desc.fFetchMode) {
+ genConvolutionVS(stageNum, desc, segments, locations,
+ &kernel, &imageIncrementName, varyingVSName);
+ }
+
+ /// Fragment Shader Stuff
+ GrStringBuilder fsCoordName;
+ // function used to access the shader, may be made projective
+ GrStringBuilder texFunc("texture2D");
+ if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit |
+ StageDesc::kNoPerspective_OptFlagBit)) {
+ GrAssert(varyingDims == coordDims);
+ fsCoordName = varyingFSName;
+ } else {
+ // if we have to do some special op on the varyings to get
+ // our final tex coords then when in perspective we have to
+ // do an explicit divide. Otherwise, we can use a Proj func.
+ if (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
+ StageDesc::kSingle_FetchMode == desc.fFetchMode) {
+ texFunc.append("Proj");
+ fsCoordName = varyingFSName;
+ } else {
+ fsCoordName = "inCoord";
+ fsCoordName.appendS32(stageNum);
+ segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
+ GrGLShaderVar::TypeString(float_vector_type(coordDims)),
+ fsCoordName.c_str(),
+ varyingFSName,
+ vector_nonhomog_coords(varyingDims),
+ varyingFSName,
+ vector_homog_coord(varyingDims));
+ }
+ }
+
+ GrStringBuilder sampleCoords;
+ bool complexCoord = false;
+ switch (desc.fCoordMapping) {
+ case StageDesc::kIdentity_CoordMapping:
+ sampleCoords = fsCoordName;
+ break;
+ case StageDesc::kSweepGradient_CoordMapping:
+ sampleCoords.printf("vec2(atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5, 0.5)", fsCoordName.c_str(), fsCoordName.c_str());
+ complexCoord = true;
+ break;
+ case StageDesc::kRadialGradient_CoordMapping:
+ sampleCoords.printf("vec2(length(%s.xy), 0.5)", fsCoordName.c_str());
+ complexCoord = true;
+ break;
+ case StageDesc::kRadial2Gradient_CoordMapping:
+ complexCoord = genRadial2GradientCoordMapping(
+ stageNum, segments,
+ radial2VaryingFSName, radial2Params,
+ sampleCoords, fsCoordName,
+ varyingDims, coordDims);
+
+ break;
+ case StageDesc::kRadial2GradientDegenerate_CoordMapping:
+ complexCoord = genRadial2GradientDegenerateCoordMapping(
+ stageNum, segments,
+ radial2VaryingFSName, radial2Params,
+ sampleCoords, fsCoordName,
+ varyingDims, coordDims);
+ break;
+
+ };
+
+ const char* swizzle = "";
+ if (desc.fInConfigFlags & StageDesc::kSwapRAndB_InConfigFlag) {
+ GrAssert(!(desc.fInConfigFlags & StageDesc::kSmearAlpha_InConfigFlag));
+ swizzle = ".bgra";
+ } else if (desc.fInConfigFlags & StageDesc::kSmearAlpha_InConfigFlag) {
+ GrAssert(!(desc.fInConfigFlags &
+ StageDesc::kMulRGBByAlpha_InConfigFlag));
+ swizzle = ".aaaa";
+ }
+
+ GrStringBuilder modulate;
+ if (NULL != fsInColor) {
+ modulate.printf(" * %s", fsInColor);
+ }
+
+ if (desc.fOptFlags &
+ StageDesc::kCustomTextureDomain_OptFlagBit) {
+ GrStringBuilder texDomainName;
+ tex_domain_name(stageNum, &texDomainName);
+ segments->fFSUnis.push_back().set(GrGLShaderVar::kVec4f_Type,
+ GrGLShaderVar::kUniform_TypeModifier, texDomainName);
+ GrStringBuilder coordVar("clampCoord");
+ segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n",
+ float_vector_type_str(coordDims),
+ coordVar.c_str(),
+ sampleCoords.c_str(),
+ texDomainName.c_str(),
+ texDomainName.c_str());
+ sampleCoords = coordVar;
+ locations->fTexDomUni = kUseUniform;
+ }
+
+ switch (desc.fFetchMode) {
+ case StageDesc::k2x2_FetchMode:
+ GrAssert(!(desc.fInConfigFlags &
+ StageDesc::kMulRGBByAlpha_InConfigFlag));
+ gen2x2FS(stageNum, segments, locations, &sampleCoords,
+ samplerName, texelSizeName, swizzle, fsOutColor,
+ texFunc, modulate, complexCoord, coordDims);
+ break;
+ case StageDesc::kConvolution_FetchMode:
+ GrAssert(!(desc.fInConfigFlags &
+ StageDesc::kMulRGBByAlpha_InConfigFlag));
+ genConvolutionFS(stageNum, desc, segments,
+ samplerName, kernel, swizzle, imageIncrementName, fsOutColor,
+ sampleCoords, texFunc, modulate);
+ break;
+ default:
+ if (desc.fInConfigFlags & StageDesc::kMulRGBByAlpha_InConfigFlag) {
+ GrAssert(!(desc.fInConfigFlags &
+ StageDesc::kSmearAlpha_InConfigFlag));
+ segments->fFSCode.appendf("\t%s = %s(%s, %s)%s;\n",
+ fsOutColor, texFunc.c_str(),
+ samplerName, sampleCoords.c_str(),
+ swizzle);
+ segments->fFSCode.appendf("\t%s = vec4(%s.rgb*%s.a,%s.a)%s;\n",
+ fsOutColor, fsOutColor, fsOutColor,
+ fsOutColor, modulate.c_str());
+ } else {
+ segments->fFSCode.appendf("\t%s = %s(%s, %s)%s%s;\n",
+ fsOutColor, texFunc.c_str(),
+ samplerName, sampleCoords.c_str(),
+ swizzle, modulate.c_str());
+ }
+ }
+}
+
+
diff --git a/src/gpu/GrGLProgram.h b/src/gpu/GrGLProgram.h
new file mode 100644
index 0000000..b4ad4af
--- /dev/null
+++ b/src/gpu/GrGLProgram.h
@@ -0,0 +1,386 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrGLProgram_DEFINED
+#define GrGLProgram_DEFINED
+
+#include "GrDrawState.h"
+#include "GrGLInterface.h"
+#include "GrGLSL.h"
+#include "GrStringBuilder.h"
+#include "GrGpu.h"
+
+#include "SkXfermode.h"
+
+class GrBinHashKeyBuilder;
+
+struct ShaderCodeSegments;
+
+// optionally compile the experimental GS code. Set to GR_DEBUG
+// so that debug build bots will execute the code.
+#define GR_GL_EXPERIMENTAL_GS GR_DEBUG
+
+/**
+ * This class manages a GPU program and records per-program information.
+ * We can specify the attribute locations so that they are constant
+ * across our shaders. But the driver determines the uniform locations
+ * at link time. We don't need to remember the sampler uniform location
+ * because we will bind a texture slot to it and never change it
+ * Uniforms are program-local so we can't rely on fHWState to hold the
+ * previous uniform state after a program change.
+ */
+class GrGLProgram {
+public:
+
+ class CachedData;
+
+ GrGLProgram();
+ ~GrGLProgram();
+
+ /**
+ * This is the heavy initilization routine for building a GLProgram.
+ * The result of heavy init is not stored in datamembers of GrGLProgam,
+ * but in a separate cacheable container.
+ */
+ bool genProgram(const GrGLInterface* gl,
+ GrGLSLGeneration glslVersion,
+ CachedData* programData) const;
+
+ /**
+ * The shader may modify the blend coeffecients. Params are in/out
+ */
+ void overrideBlend(GrBlendCoeff* srcCoeff, GrBlendCoeff* dstCoeff) const;
+
+ /**
+ * Attribute indices. These should not overlap. Matrices consume 3 slots.
+ */
+ static int PositionAttributeIdx() { return 0; }
+ static int TexCoordAttributeIdx(int tcIdx) { return 1 + tcIdx; }
+ static int ColorAttributeIdx() { return 1 + GrDrawState::kMaxTexCoords; }
+ static int CoverageAttributeIdx() {
+ return 2 + GrDrawState::kMaxTexCoords;
+ }
+ static int EdgeAttributeIdx() { return 3 + GrDrawState::kMaxTexCoords; }
+
+ static int ViewMatrixAttributeIdx() {
+ return 4 + GrDrawState::kMaxTexCoords;
+ }
+ static int TextureMatrixAttributeIdx(int stage) {
+ return 7 + GrDrawState::kMaxTexCoords + 3 * stage;
+ }
+
+public:
+
+ // Parameters that affect code generation
+ // These structs should be kept compact; they are the input to an
+ // expensive hash key generator.
+ struct ProgramDesc {
+ ProgramDesc() {
+ // since we use this as part of a key we can't have any unitialized
+ // padding
+ memset(this, 0, sizeof(ProgramDesc));
+ }
+
+ enum OutputPM {
+ // PM-color OR color with no alpha channel
+ kYes_OutputPM,
+ // nonPM-color with alpha channel
+ kNo_OutputPM,
+
+ kOutputPMCnt
+ };
+
+ struct StageDesc {
+ enum OptFlagBits {
+ kNoPerspective_OptFlagBit = 1 << 0,
+ kIdentityMatrix_OptFlagBit = 1 << 1,
+ kCustomTextureDomain_OptFlagBit = 1 << 2,
+ kIsEnabled_OptFlagBit = 1 << 7
+ };
+ enum FetchMode {
+ kSingle_FetchMode,
+ k2x2_FetchMode,
+ kConvolution_FetchMode,
+
+ kFetchModeCnt,
+ };
+ /**
+ Flags set based on a src texture's pixel config. The operations
+ described are performed after reading a texel.
+ */
+ enum InConfigFlags {
+ kNone_InConfigFlag = 0x0,
+
+ /**
+ Swap the R and B channels. This is incompatible with
+ kSmearAlpha. It is prefereable to perform the swizzle outside
+ the shader using GL_ARB_texture_swizzle if possible rather
+ than setting this flag.
+ */
+ kSwapRAndB_InConfigFlag = 0x1,
+
+ /**
+ Smear alpha across all four channels. This is incompatible with
+ kSwapRAndB and kPremul. It is prefereable to perform the
+ smear outside the shader using GL_ARB_texture_swizzle if
+ possible rather than setting this flag.
+ */
+ kSmearAlpha_InConfigFlag = 0x2,
+
+ /**
+ Multiply r,g,b by a after texture reads. This flag incompatible
+ with kSmearAlpha and may only be used with FetchMode kSingle.
+ */
+ kMulRGBByAlpha_InConfigFlag = 0x4,
+
+ kDummyInConfigFlag,
+ kInConfigBitMask = (kDummyInConfigFlag-1) |
+ (kDummyInConfigFlag-2)
+ };
+ enum CoordMapping {
+ kIdentity_CoordMapping,
+ kRadialGradient_CoordMapping,
+ kSweepGradient_CoordMapping,
+ kRadial2Gradient_CoordMapping,
+ // need different shader computation when quadratic
+ // eq describing the gradient degenerates to a linear eq.
+ kRadial2GradientDegenerate_CoordMapping,
+ kCoordMappingCnt
+ };
+
+ uint8_t fOptFlags;
+ uint8_t fInConfigFlags; // bitfield of InConfigFlags values
+ uint8_t fFetchMode; // casts to enum FetchMode
+ uint8_t fCoordMapping; // casts to enum CoordMapping
+ uint8_t fKernelWidth;
+
+ GR_STATIC_ASSERT((InConfigFlags)(uint8_t)kInConfigBitMask ==
+ kInConfigBitMask);
+
+ inline bool isEnabled() const {
+ return SkToBool(fOptFlags & kIsEnabled_OptFlagBit);
+ }
+ inline void setEnabled(bool newValue) {
+ if (newValue) {
+ fOptFlags |= kIsEnabled_OptFlagBit;
+ } else {
+ fOptFlags &= ~kIsEnabled_OptFlagBit;
+ }
+ }
+ };
+
+ // Specifies where the intitial color comes from before the stages are
+ // applied.
+ enum ColorInput {
+ kSolidWhite_ColorInput,
+ kTransBlack_ColorInput,
+ kAttribute_ColorInput,
+ kUniform_ColorInput,
+
+ kColorInputCnt
+ };
+ // Dual-src blending makes use of a secondary output color that can be
+ // used as a per-pixel blend coeffecient. This controls whether a
+ // secondary source is output and what value it holds.
+ enum DualSrcOutput {
+ kNone_DualSrcOutput,
+ kCoverage_DualSrcOutput,
+ kCoverageISA_DualSrcOutput,
+ kCoverageISC_DualSrcOutput,
+
+ kDualSrcOutputCnt
+ };
+
+ GrDrawState::VertexEdgeType fVertexEdgeType;
+
+ // stripped of bits that don't affect prog generation
+ GrVertexLayout fVertexLayout;
+
+ StageDesc fStages[GrDrawState::kNumStages];
+
+ // To enable experimental geometry shader code (not for use in
+ // production)
+#if GR_GL_EXPERIMENTAL_GS
+ bool fExperimentalGS;
+#endif
+
+ uint8_t fColorInput; // casts to enum ColorInput
+ uint8_t fOutputPM; // cases to enum OutputPM
+ uint8_t fDualSrcOutput; // casts to enum DualSrcOutput
+ int8_t fFirstCoverageStage;
+ SkBool8 fEmitsPointSize;
+ SkBool8 fEdgeAAConcave;
+ SkBool8 fColorMatrixEnabled;
+
+ int8_t fEdgeAANumEdges;
+ uint8_t fColorFilterXfermode; // casts to enum SkXfermode::Mode
+ int8_t fPadding[3];
+
+ } fProgramDesc;
+ GR_STATIC_ASSERT(!(sizeof(ProgramDesc) % 4));
+
+ // for code readability
+ typedef ProgramDesc::StageDesc StageDesc;
+
+private:
+
+ const ProgramDesc& getDesc() { return fProgramDesc; }
+ const char* adjustInColor(const GrStringBuilder& inColor) const;
+
+public:
+ enum {
+ kUnusedUniform = -1,
+ kSetAsAttribute = 1000,
+ };
+
+ struct StageUniLocations {
+ GrGLint fTextureMatrixUni;
+ GrGLint fNormalizedTexelSizeUni;
+ GrGLint fSamplerUni;
+ GrGLint fRadial2Uni;
+ GrGLint fTexDomUni;
+ GrGLint fKernelUni;
+ GrGLint fImageIncrementUni;
+ void reset() {
+ fTextureMatrixUni = kUnusedUniform;
+ fNormalizedTexelSizeUni = kUnusedUniform;
+ fSamplerUni = kUnusedUniform;
+ fRadial2Uni = kUnusedUniform;
+ fTexDomUni = kUnusedUniform;
+ fKernelUni = kUnusedUniform;
+ fImageIncrementUni = kUnusedUniform;
+ }
+ };
+
+ struct UniLocations {
+ GrGLint fViewMatrixUni;
+ GrGLint fColorUni;
+ GrGLint fEdgesUni;
+ GrGLint fColorFilterUni;
+ GrGLint fColorMatrixUni;
+ GrGLint fColorMatrixVecUni;
+ StageUniLocations fStages[GrDrawState::kNumStages];
+ void reset() {
+ fViewMatrixUni = kUnusedUniform;
+ fColorUni = kUnusedUniform;
+ fEdgesUni = kUnusedUniform;
+ fColorFilterUni = kUnusedUniform;
+ fColorMatrixUni = kUnusedUniform;
+ fColorMatrixVecUni = kUnusedUniform;
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ fStages[s].reset();
+ }
+ }
+ };
+
+ class CachedData : public ::GrNoncopyable {
+ public:
+ CachedData() {
+ }
+
+ ~CachedData() {
+ }
+
+ void copyAndTakeOwnership(CachedData& other) {
+ memcpy(this, &other, sizeof(*this));
+ }
+
+ public:
+
+ // IDs
+ GrGLuint fVShaderID;
+ GrGLuint fGShaderID;
+ GrGLuint fFShaderID;
+ GrGLuint fProgramID;
+ // shader uniform locations (-1 if shader doesn't use them)
+ UniLocations fUniLocations;
+
+ GrMatrix fViewMatrix;
+
+ // these reflect the current values of uniforms
+ // (GL uniform values travel with program)
+ GrColor fColor;
+ GrColor fColorFilterColor;
+ GrMatrix fTextureMatrices[GrDrawState::kNumStages];
+ // width and height used for normalized texel size
+ int fTextureWidth[GrDrawState::kNumStages];
+ int fTextureHeight[GrDrawState::kNumStages];
+ GrScalar fRadial2CenterX1[GrDrawState::kNumStages];
+ GrScalar fRadial2Radius0[GrDrawState::kNumStages];
+ bool fRadial2PosRoot[GrDrawState::kNumStages];
+ GrRect fTextureDomain[GrDrawState::kNumStages];
+
+ private:
+ enum Constants {
+ kUniLocationPreAllocSize = 8
+ };
+
+ }; // CachedData
+
+ enum Constants {
+ kProgramKeySize = sizeof(ProgramDesc)
+ };
+
+ // Provide an opaque ProgramDesc
+ const uint32_t* keyData() const{
+ return reinterpret_cast<const uint32_t*>(&fProgramDesc);
+ }
+
+private:
+
+ // Determines which uniforms will need to be bound.
+ void genStageCode(const GrGLInterface* gl,
+ int stageNum,
+ const ProgramDesc::StageDesc& desc,
+ const char* fsInColor, // NULL means no incoming color
+ const char* fsOutColor,
+ const char* vsInCoord,
+ ShaderCodeSegments* segments,
+ StageUniLocations* locations) const;
+
+ void genGeometryShader(const GrGLInterface* gl,
+ GrGLSLGeneration glslVersion,
+ ShaderCodeSegments* segments) const;
+
+ // generates code to compute coverage based on edge AA.
+ void genEdgeCoverage(const GrGLInterface* gl,
+ GrVertexLayout layout,
+ CachedData* programData,
+ GrStringBuilder* coverageVar,
+ ShaderCodeSegments* segments) const;
+
+ static bool CompileShaders(const GrGLInterface* gl,
+ GrGLSLGeneration glslVersion,
+ const ShaderCodeSegments& segments,
+ CachedData* programData);
+
+ // Compiles a GL shader, returns shader ID or 0 if failed
+ // params have same meaning as glShaderSource
+ static GrGLuint CompileShader(const GrGLInterface* gl,
+ GrGLenum type, int stringCnt,
+ const char** strings,
+ int* stringLengths);
+
+ // Creates a GL program ID, binds shader attributes to GL vertex attrs, and
+ // links the program
+ bool bindOutputsAttribsAndLinkProgram(
+ const GrGLInterface* gl,
+ GrStringBuilder texCoordAttrNames[GrDrawState::kMaxTexCoords],
+ bool bindColorOut,
+ bool bindDualSrcOut,
+ CachedData* programData) const;
+
+ // Binds uniforms; initializes cache to invalid values.
+ void getUniformLocationsAndInitCache(const GrGLInterface* gl,
+ CachedData* programData) const;
+
+ friend class GrGpuGLShaders;
+};
+
+#endif
diff --git a/src/gpu/GrGLRenderTarget.cpp b/src/gpu/GrGLRenderTarget.cpp
new file mode 100644
index 0000000..c98914a
--- /dev/null
+++ b/src/gpu/GrGLRenderTarget.cpp
@@ -0,0 +1,97 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrGLRenderTarget.h"
+
+#include "GrGpuGL.h"
+
+#define GPUGL static_cast<GrGpuGL*>(getGpu())
+
+#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
+
+void GrGLRenderTarget::init(const Desc& desc,
+ const GrGLIRect& viewport,
+ GrGLTexID* texID) {
+ fRTFBOID = desc.fRTFBOID;
+ fTexFBOID = desc.fTexFBOID;
+ fMSColorRenderbufferID = desc.fMSColorRenderbufferID;
+ fViewport = viewport;
+ fOwnIDs = desc.fOwnIDs;
+ fTexIDObj = texID;
+ GrSafeRef(fTexIDObj);
+}
+
+GrGLRenderTarget::GrGLRenderTarget(GrGpuGL* gpu,
+ const Desc& desc,
+ const GrGLIRect& viewport,
+ GrGLTexID* texID,
+ GrGLTexture* texture)
+ : INHERITED(gpu,
+ texture,
+ viewport.fWidth,
+ viewport.fHeight,
+ desc.fConfig,
+ desc.fSampleCnt) {
+ GrAssert(NULL != texID);
+ GrAssert(NULL != texture);
+ // FBO 0 can't also be a texture, right?
+ GrAssert(0 != desc.fRTFBOID);
+ GrAssert(0 != desc.fTexFBOID);
+
+ // we assume this is true, TODO: get rid of viewport as a param.
+ GrAssert(viewport.fWidth == texture->width());
+ GrAssert(viewport.fHeight == texture->height());
+
+ this->init(desc, viewport, texID);
+}
+
+GrGLRenderTarget::GrGLRenderTarget(GrGpuGL* gpu,
+ const Desc& desc,
+ const GrGLIRect& viewport)
+ : INHERITED(gpu,
+ NULL,
+ viewport.fWidth,
+ viewport.fHeight,
+ desc.fConfig,
+ desc.fSampleCnt) {
+ this->init(desc, viewport, NULL);
+}
+
+void GrGLRenderTarget::onRelease() {
+ GPUGL->notifyRenderTargetDelete(this);
+ if (fOwnIDs) {
+ if (fTexFBOID) {
+ GL_CALL(DeleteFramebuffers(1, &fTexFBOID));
+ }
+ if (fRTFBOID && fRTFBOID != fTexFBOID) {
+ GL_CALL(DeleteFramebuffers(1, &fRTFBOID));
+ }
+ if (fMSColorRenderbufferID) {
+ GL_CALL(DeleteRenderbuffers(1, &fMSColorRenderbufferID));
+ }
+ }
+ fRTFBOID = 0;
+ fTexFBOID = 0;
+ fMSColorRenderbufferID = 0;
+ GrSafeUnref(fTexIDObj);
+ fTexIDObj = NULL;
+ this->setStencilBuffer(NULL);
+}
+
+void GrGLRenderTarget::onAbandon() {
+ fRTFBOID = 0;
+ fTexFBOID = 0;
+ fMSColorRenderbufferID = 0;
+ if (NULL != fTexIDObj) {
+ fTexIDObj->abandon();
+ fTexIDObj = NULL;
+ }
+ this->setStencilBuffer(NULL);
+}
+
diff --git a/src/gpu/GrGLRenderTarget.h b/src/gpu/GrGLRenderTarget.h
new file mode 100644
index 0000000..eb817df
--- /dev/null
+++ b/src/gpu/GrGLRenderTarget.h
@@ -0,0 +1,110 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrGLRenderTarget_DEFINED
+#define GrGLRenderTarget_DEFINED
+
+#include "GrGLIRect.h"
+#include "GrRenderTarget.h"
+#include "GrScalar.h"
+
+class GrGpuGL;
+class GrGLTexture;
+class GrGLTexID;
+
+class GrGLRenderTarget : public GrRenderTarget {
+
+public:
+ // set fTexFBOID to this value to indicate that it is multisampled but
+ // Gr doesn't know how to resolve it.
+ enum { kUnresolvableFBOID = 0 };
+
+ struct Desc {
+ GrGLuint fRTFBOID;
+ GrGLuint fTexFBOID;
+ GrGLuint fMSColorRenderbufferID;
+ bool fOwnIDs;
+ GrPixelConfig fConfig;
+ int fSampleCnt;
+ };
+
+ // creates a GrGLRenderTarget associated with a texture
+ GrGLRenderTarget(GrGpuGL* gpu,
+ const Desc& desc,
+ const GrGLIRect& viewport,
+ GrGLTexID* texID,
+ GrGLTexture* texture);
+
+ // creates an independent GrGLRenderTarget
+ GrGLRenderTarget(GrGpuGL* gpu,
+ const Desc& desc,
+ const GrGLIRect& viewport);
+
+ virtual ~GrGLRenderTarget() { this->release(); }
+
+ void setViewport(const GrGLIRect& rect) { fViewport = rect; }
+ const GrGLIRect& getViewport() const { return fViewport; }
+
+ // The following two functions return the same ID when a
+ // texture-rendertarget is multisampled, and different IDs when
+ // it is.
+ // FBO ID used to render into
+ GrGLuint renderFBOID() const { return fRTFBOID; }
+ // FBO ID that has texture ID attached.
+ GrGLuint textureFBOID() const { return fTexFBOID; }
+
+ // override of GrRenderTarget
+ virtual intptr_t getRenderTargetHandle() const {
+ return this->renderFBOID();
+ }
+ virtual intptr_t getRenderTargetResolvedHandle() const {
+ return this->textureFBOID();
+ }
+ virtual ResolveType getResolveType() const {
+
+ if (!this->isMultisampled() ||
+ fRTFBOID == fTexFBOID) {
+ // catches FBO 0 and non MSAA case
+ return kAutoResolves_ResolveType;
+ } else if (kUnresolvableFBOID == fTexFBOID) {
+ return kCantResolve_ResolveType;
+ } else {
+ return kCanResolve_ResolveType;
+ }
+ }
+
+protected:
+ // override of GrResource
+ virtual void onAbandon();
+ virtual void onRelease();
+
+private:
+ GrGLuint fRTFBOID;
+ GrGLuint fTexFBOID;
+
+ GrGLuint fMSColorRenderbufferID;
+
+ // Should this object delete IDs when it is destroyed or does someone
+ // else own them.
+ bool fOwnIDs;
+
+ // when we switch to this rendertarget we want to set the viewport to
+ // only render to to content area (as opposed to the whole allocation) and
+ // we want the rendering to be at top left (GL has origin in bottom left)
+ GrGLIRect fViewport;
+
+ // non-NULL if this RT was created by Gr with an associated GrGLTexture.
+ GrGLTexID* fTexIDObj;
+
+ void init(const Desc& desc, const GrGLIRect& viewport, GrGLTexID* texID);
+
+ typedef GrRenderTarget INHERITED;
+};
+
+#endif
diff --git a/src/gpu/GrGLSL.cpp b/src/gpu/GrGLSL.cpp
new file mode 100644
index 0000000..1062c81
--- /dev/null
+++ b/src/gpu/GrGLSL.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrGLSL.h"
+
+GrGLSLGeneration GetGLSLGeneration(GrGLBinding binding,
+ const GrGLInterface* gl) {
+ GrGLSLVersion ver = GrGLGetGLSLVersion(gl);
+ switch (binding) {
+ case kDesktop_GrGLBinding:
+ GrAssert(ver >= GR_GLSL_VER(1,10));
+ if (ver >= GR_GLSL_VER(1,50)) {
+ return k150_GLSLGeneration;
+ } else if (ver >= GR_GLSL_VER(1,30)) {
+ return k130_GLSLGeneration;
+ } else {
+ return k110_GLSLGeneration;
+ }
+ case kES2_GrGLBinding:
+ // version 1.00 of ES GLSL based on ver 1.20 of desktop GLSL
+ GrAssert(ver >= GR_GL_VER(1,00));
+ return k110_GLSLGeneration;
+ default:
+ GrCrash("Unknown GL Binding");
+ return k110_GLSLGeneration; // suppress warning
+ }
+}
+
diff --git a/src/gpu/GrGLSL.h b/src/gpu/GrGLSL.h
new file mode 100644
index 0000000..501d1ba
--- /dev/null
+++ b/src/gpu/GrGLSL.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrGLSL_DEFINED
+#define GrGLSL_DEFINED
+
+#include "GrGLInterface.h"
+
+// Limited set of GLSL versions we build shaders for. Caller should round
+// down the GLSL version to one of these enums.
+enum GrGLSLGeneration {
+ /**
+ * Desktop GLSL 1.10 and ES2 shading lang (based on desktop GLSL 1.20)
+ */
+ k110_GLSLGeneration,
+ /**
+ * Desktop GLSL 1.30
+ */
+ k130_GLSLGeneration,
+ /**
+ * Dekstop GLSL 1.50
+ */
+ k150_GLSLGeneration,
+};
+
+GrGLSLGeneration GetGLSLGeneration(GrGLBinding binding,
+ const GrGLInterface* gl);
+
+#endif
+
diff --git a/src/gpu/GrGLShaderVar.h b/src/gpu/GrGLShaderVar.h
new file mode 100644
index 0000000..1d5d7ca
--- /dev/null
+++ b/src/gpu/GrGLShaderVar.h
@@ -0,0 +1,304 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrGLShaderVar_DEFINED
+#define GrGLShaderVar_DEFINED
+
+#include "GrGLInterface.h"
+#include "GrGLSL.h"
+#include "GrStringBuilder.h"
+
+#define USE_UNIFORM_FLOAT_ARRAYS true
+
+/**
+ * Represents a variable in a shader
+ */
+class GrGLShaderVar {
+public:
+
+ enum Type {
+ kFloat_Type,
+ kVec2f_Type,
+ kVec3f_Type,
+ kVec4f_Type,
+ kMat33f_Type,
+ kMat44f_Type,
+ kSampler2D_Type,
+ };
+
+ /**
+ * Early versions of GLSL have Varying and Attribute; those are later
+ * deprecated, but we still need to know whether a Varying variable
+ * should be treated as In or Out.
+ */
+ enum TypeModifier {
+ kNone_TypeModifier,
+ kOut_TypeModifier,
+ kIn_TypeModifier,
+ kUniform_TypeModifier,
+ kAttribute_TypeModifier
+ };
+
+ /**
+ * Defaults to a float with no precision specifier
+ */
+ GrGLShaderVar() {
+ fType = kFloat_Type;
+ fTypeModifier = kNone_TypeModifier;
+ fCount = kNonArray;
+ fEmitPrecision = false;
+ fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
+ }
+
+ GrGLShaderVar(const GrGLShaderVar& var)
+ : fType(var.fType)
+ , fTypeModifier(var.fTypeModifier)
+ , fName(var.fName)
+ , fCount(var.fCount)
+ , fEmitPrecision(var.fEmitPrecision)
+ , fUseUniformFloatArrays(var.fUseUniformFloatArrays) {}
+
+ /**
+ * Values for array count that have special meaning. We allow 1-sized arrays.
+ */
+ enum {
+ kNonArray = 0, // not an array
+ kUnsizedArray = -1, // an unsized array (declared with [])
+ };
+
+ /**
+ * Sets as a non-array.
+ */
+ void set(Type type,
+ TypeModifier typeModifier,
+ const GrStringBuilder& name,
+ bool emitPrecision = false,
+ bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
+ fType = type;
+ fTypeModifier = typeModifier;
+ fName = name;
+ fCount = kNonArray;
+ fEmitPrecision = emitPrecision;
+ fUseUniformFloatArrays = useUniformFloatArrays;
+ }
+
+ /**
+ * Sets as a non-array.
+ */
+ void set(Type type,
+ TypeModifier typeModifier,
+ const char* name,
+ bool specifyPrecision = false,
+ bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
+ fType = type;
+ fTypeModifier = typeModifier;
+ fName = name;
+ fCount = kNonArray;
+ fEmitPrecision = specifyPrecision;
+ fUseUniformFloatArrays = useUniformFloatArrays;
+ }
+
+ /**
+ * Set all var options
+ */
+ void set(Type type,
+ TypeModifier typeModifier,
+ const GrStringBuilder& name,
+ int count,
+ bool specifyPrecision = false,
+ bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
+ fType = type;
+ fTypeModifier = typeModifier;
+ fName = name;
+ fCount = count;
+ fEmitPrecision = specifyPrecision;
+ fUseUniformFloatArrays = useUniformFloatArrays;
+ }
+
+ /**
+ * Set all var options
+ */
+ void set(Type type,
+ TypeModifier typeModifier,
+ const char* name,
+ int count,
+ bool specifyPrecision = false,
+ bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
+ fType = type;
+ fTypeModifier = typeModifier;
+ fName = name;
+ fCount = count;
+ fEmitPrecision = specifyPrecision;
+ fUseUniformFloatArrays = useUniformFloatArrays;
+ }
+
+ /**
+ * Is the var an array.
+ */
+ bool isArray() const { return kNonArray != fCount; }
+ /**
+ * Is this an unsized array, (i.e. declared with []).
+ */
+ bool isUnsizedArray() const { return kUnsizedArray == fCount; }
+ /**
+ * Get the array length of the var.
+ */
+ int getArrayCount() const { return fCount; }
+ /**
+ * Set the array length of the var
+ */
+ void setArrayCount(int count) { fCount = count; }
+ /**
+ * Set to be a non-array.
+ */
+ void setNonArray() { fCount = kNonArray; }
+ /**
+ * Set to be an unsized array.
+ */
+ void setUnsizedArray() { fCount = kUnsizedArray; }
+
+ /**
+ * Access the var name as a writable string
+ */
+ GrStringBuilder* accessName() { return &fName; }
+ /**
+ * Set the var name
+ */
+ void setName(const GrStringBuilder& n) { fName = n; }
+ void setName(const char* n) { fName = n; }
+ /**
+ * Get the var name.
+ */
+ const GrStringBuilder& getName() const { return fName; }
+
+ /**
+ * Get the type of the var
+ */
+ Type getType() const { return fType; }
+ /**
+ * Set the type of the var
+ */
+ void setType(Type type) { fType = type; }
+
+ TypeModifier getTypeModifier() const { return fTypeModifier; }
+ void setTypeModifier(TypeModifier type) { fTypeModifier = type; }
+
+ /**
+ * Must the variable declaration emit a precision specifier
+ */
+ bool emitsPrecision() const { return fEmitPrecision; }
+ /**
+ * Specify whether the declaration should specify precision
+ */
+ void setEmitPrecision(bool p) { fEmitPrecision = p; }
+
+ /**
+ * Write a declaration of this variable to out.
+ */
+ void appendDecl(const GrGLInterface* gl, GrStringBuilder* out,
+ GrGLSLGeneration gen) const {
+ if (this->getTypeModifier() != kNone_TypeModifier) {
+ out->append(TypeModifierString(this->getTypeModifier(), gen));
+ out->append(" ");
+ }
+ if (this->emitsPrecision()) {
+ out->append(PrecisionString(gl));
+ out->append(" ");
+ }
+ Type effectiveType = this->getType();
+ if (this->isArray()) {
+ if (this->isUnsizedArray()) {
+ out->appendf("%s %s[]",
+ TypeString(effectiveType),
+ this->getName().c_str());
+ } else {
+ GrAssert(this->getArrayCount() > 0);
+ out->appendf("%s %s[%d]",
+ TypeString(effectiveType),
+ this->getName().c_str(),
+ this->getArrayCount());
+ }
+ } else {
+ out->appendf("%s %s",
+ TypeString(effectiveType),
+ this->getName().c_str());
+ }
+ out->append(";\n");
+ }
+
+ static const char* TypeString(Type t) {
+ switch (t) {
+ case kFloat_Type:
+ return "float";
+ case kVec2f_Type:
+ return "vec2";
+ case kVec3f_Type:
+ return "vec3";
+ case kVec4f_Type:
+ return "vec4";
+ case kMat33f_Type:
+ return "mat3";
+ case kMat44f_Type:
+ return "mat4";
+ case kSampler2D_Type:
+ return "sampler2D";
+ default:
+ GrCrash("Unknown shader var type.");
+ return ""; // suppress warning
+ }
+ }
+
+ void appendArrayAccess(int index, GrStringBuilder* out) {
+ out->appendf("%s[%d]%s",
+ this->getName().c_str(),
+ index,
+ fUseUniformFloatArrays ? "" : ".x");
+ }
+
+ void appendArrayAccess(const char* indexName, GrStringBuilder* out) {
+ out->appendf("%s[%s]%s",
+ this->getName().c_str(),
+ indexName,
+ fUseUniformFloatArrays ? "" : ".x");
+ }
+
+private:
+ static const char* PrecisionString(const GrGLInterface* gl) {
+ return gl->supportsDesktop() ? "" : "mediump";
+ }
+
+ static const char* TypeModifierString(TypeModifier t,
+ GrGLSLGeneration gen) {
+ switch (t) {
+ case kNone_TypeModifier:
+ return "";
+ case kOut_TypeModifier:
+ return k110_GLSLGeneration == gen ? "varying" : "out";
+ case kIn_TypeModifier:
+ return k110_GLSLGeneration == gen ? "varying" : "in";
+ case kUniform_TypeModifier:
+ return "uniform";
+ case kAttribute_TypeModifier:
+ return k110_GLSLGeneration == gen ? "attribute" : "in";
+ default:
+ GrCrash("Unknown shader variable type modifier.");
+ return ""; // suppress warning
+ }
+ }
+
+ Type fType;
+ TypeModifier fTypeModifier;
+ GrStringBuilder fName;
+ int fCount;
+ bool fEmitPrecision;
+ /// Work around driver bugs on some hardware that don't correctly
+ /// support uniform float []
+ bool fUseUniformFloatArrays;
+};
+
+#endif
diff --git a/src/gpu/GrGLStencilBuffer.cpp b/src/gpu/GrGLStencilBuffer.cpp
new file mode 100644
index 0000000..bc0bb36
--- /dev/null
+++ b/src/gpu/GrGLStencilBuffer.cpp
@@ -0,0 +1,40 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrGLStencilBuffer.h"
+#include "GrGpuGL.h"
+
+GrGLStencilBuffer::~GrGLStencilBuffer() {
+ this->release();
+}
+
+size_t GrGLStencilBuffer::sizeInBytes() const {
+ uint64_t size = this->width();
+ size *= this->height();
+ size *= fFormat.fTotalBits;
+ size *= GrMax(1,this->numSamples());
+ return static_cast<size_t>(size / 8);
+}
+
+void GrGLStencilBuffer::onRelease() {
+ if (0 != fRenderbufferID) {
+ GrGpuGL* gpuGL = (GrGpuGL*) this->getGpu();
+ const GrGLInterface* gl = gpuGL->glInterface();
+ GR_GL_CALL(gl, DeleteRenderbuffers(1, &fRenderbufferID));
+ fRenderbufferID = 0;
+ }
+ INHERITED::onRelease();
+}
+
+void GrGLStencilBuffer::onAbandon() {
+ fRenderbufferID = 0;
+ INHERITED::onAbandon();
+}
+
+
diff --git a/src/gpu/GrGLStencilBuffer.h b/src/gpu/GrGLStencilBuffer.h
new file mode 100644
index 0000000..eaf7942
--- /dev/null
+++ b/src/gpu/GrGLStencilBuffer.h
@@ -0,0 +1,60 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrGLStencilBuffer_DEFINED
+#define GrGLStencilBuffer_DEFINED
+
+#include "GrGLInterface.h"
+#include "GrStencilBuffer.h"
+
+class GrGLStencilBuffer : public GrStencilBuffer {
+public:
+ static const GrGLenum kUnknownInternalFormat = ~0;
+ struct Format {
+ GrGLenum fInternalFormat;
+ GrGLuint fStencilBits;
+ GrGLuint fTotalBits;
+ bool fPacked;
+ };
+
+ GrGLStencilBuffer(GrGpu* gpu, GrGLint rbid,
+ int width, int height,
+ int sampleCnt,
+ const Format& format)
+ : GrStencilBuffer(gpu, width, height, format.fStencilBits, sampleCnt)
+ , fFormat(format)
+ , fRenderbufferID(rbid) {
+ }
+
+ virtual ~GrGLStencilBuffer();
+
+ virtual size_t sizeInBytes() const;
+
+ GrGLuint renderbufferID() const {
+ return fRenderbufferID;
+ }
+
+ const Format& format() const { return fFormat; }
+
+protected:
+ virtual void onRelease();
+
+ virtual void onAbandon();
+
+private:
+ Format fFormat;
+ // may be zero for external SBs associated with external RTs
+ // (we don't require the client to give us the id, just tell
+ // us how many bits of stencil there are).
+ GrGLuint fRenderbufferID;
+
+ typedef GrStencilBuffer INHERITED;
+};
+
+#endif
diff --git a/src/gpu/GrGLTexture.cpp b/src/gpu/GrGLTexture.cpp
new file mode 100644
index 0000000..0a38da3
--- /dev/null
+++ b/src/gpu/GrGLTexture.cpp
@@ -0,0 +1,90 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrGLTexture.h"
+
+#include "GrGpuGL.h"
+
+#define GPUGL static_cast<GrGpuGL*>(getGpu())
+
+#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
+
+const GrGLenum* GrGLTexture::WrapMode2GLWrap() {
+ static const GrGLenum repeatModes[] = {
+ GR_GL_CLAMP_TO_EDGE,
+ GR_GL_REPEAT,
+ GR_GL_MIRRORED_REPEAT
+ };
+ return repeatModes;
+};
+
+void GrGLTexture::init(GrGpuGL* gpu,
+ const Desc& textureDesc,
+ const GrGLRenderTarget::Desc* rtDesc) {
+
+ GrAssert(0 != textureDesc.fTextureID);
+
+ fTexParams.invalidate();
+ fTexParamsTimestamp = GrGpu::kExpiredTimestamp;
+ fTexIDObj = new GrGLTexID(GPUGL->glInterface(),
+ textureDesc.fTextureID,
+ textureDesc.fOwnsID);
+ fOrientation = textureDesc.fOrientation;
+
+ if (NULL != rtDesc) {
+ // we render to the top left
+ GrGLIRect vp;
+ vp.fLeft = 0;
+ vp.fWidth = textureDesc.fWidth;
+ vp.fBottom = 0;
+ vp.fHeight = textureDesc.fHeight;
+
+ fRenderTarget = new GrGLRenderTarget(gpu, *rtDesc, vp, fTexIDObj, this);
+ }
+}
+
+GrGLTexture::GrGLTexture(GrGpuGL* gpu,
+ const Desc& textureDesc)
+ : INHERITED(gpu,
+ textureDesc.fWidth,
+ textureDesc.fHeight,
+ textureDesc.fConfig) {
+ this->init(gpu, textureDesc, NULL);
+}
+
+GrGLTexture::GrGLTexture(GrGpuGL* gpu,
+ const Desc& textureDesc,
+ const GrGLRenderTarget::Desc& rtDesc)
+ : INHERITED(gpu,
+ textureDesc.fWidth,
+ textureDesc.fHeight,
+ textureDesc.fConfig) {
+ this->init(gpu, textureDesc, &rtDesc);
+}
+
+void GrGLTexture::onRelease() {
+ INHERITED::onRelease();
+ GPUGL->notifyTextureDelete(this);
+ if (NULL != fTexIDObj) {
+ fTexIDObj->unref();
+ fTexIDObj = NULL;
+ }
+}
+
+void GrGLTexture::onAbandon() {
+ INHERITED::onAbandon();
+ if (NULL != fTexIDObj) {
+ fTexIDObj->abandon();
+ }
+}
+
+intptr_t GrGLTexture::getTextureHandle() const {
+ return fTexIDObj->id();
+}
+
diff --git a/src/gpu/GrGLTexture.h b/src/gpu/GrGLTexture.h
new file mode 100644
index 0000000..664742c
--- /dev/null
+++ b/src/gpu/GrGLTexture.h
@@ -0,0 +1,128 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrGLTexture_DEFINED
+#define GrGLTexture_DEFINED
+
+#include "GrGpu.h"
+#include "GrGLRenderTarget.h"
+
+/**
+ * A ref counted tex id that deletes the texture in its destructor.
+ */
+class GrGLTexID : public GrRefCnt {
+
+public:
+ GrGLTexID(const GrGLInterface* gl, GrGLuint texID, bool ownsID)
+ : fGL(gl)
+ , fTexID(texID)
+ , fOwnsID(ownsID) {
+ }
+
+ virtual ~GrGLTexID() {
+ if (0 != fTexID && fOwnsID) {
+ GR_GL_CALL(fGL, DeleteTextures(1, &fTexID));
+ }
+ }
+
+ void abandon() { fTexID = 0; }
+ GrGLuint id() const { return fTexID; }
+
+private:
+ const GrGLInterface* fGL;
+ GrGLuint fTexID;
+ bool fOwnsID;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+class GrGLTexture : public GrTexture {
+
+public:
+ enum Orientation {
+ kBottomUp_Orientation,
+ kTopDown_Orientation,
+ };
+
+ struct TexParams {
+ GrGLenum fFilter;
+ GrGLenum fWrapS;
+ GrGLenum fWrapT;
+ GrGLenum fSwizzleRGBA[4];
+ void invalidate() { memset(this, 0xff, sizeof(TexParams)); }
+ };
+
+ struct Desc {
+ int fWidth;
+ int fHeight;
+ GrPixelConfig fConfig;
+ GrGLuint fTextureID;
+ bool fOwnsID;
+ Orientation fOrientation;
+ };
+
+ // creates a texture that is also an RT
+ GrGLTexture(GrGpuGL* gpu,
+ const Desc& textureDesc,
+ const GrGLRenderTarget::Desc& rtDesc);
+
+ // creates a non-RT texture
+ GrGLTexture(GrGpuGL* gpu,
+ const Desc& textureDesc);
+
+
+ virtual ~GrGLTexture() { this->release(); }
+
+ virtual intptr_t getTextureHandle() const;
+
+ // these functions
+ const TexParams& getCachedTexParams(GrGpu::ResetTimestamp* timestamp) const {
+ *timestamp = fTexParamsTimestamp;
+ return fTexParams;
+ }
+ void setCachedTexParams(const TexParams& texParams,
+ GrGpu::ResetTimestamp timestamp) {
+ fTexParams = texParams;
+ fTexParamsTimestamp = timestamp;
+ }
+ GrGLuint textureID() const { return fTexIDObj->id(); }
+
+ // Ganesh assumes texture coordinates have their origin
+ // in the top-left corner of the image. OpenGL, however,
+ // has the origin in the lower-left corner. For content that
+ // is loaded by Ganesh we just push the content "upside down"
+ // (by GL's understanding of the world) in glTex*Image and the
+ // addressing just works out. However, content generated by GL
+ // (FBO or externally imported texture) will be updside down
+ // and it is up to the GrGpuGL derivative to handle y-mirroing.
+ Orientation orientation() const { return fOrientation; }
+
+ static const GrGLenum* WrapMode2GLWrap();
+
+protected:
+
+ // overrides of GrTexture
+ virtual void onAbandon();
+ virtual void onRelease();
+
+private:
+ TexParams fTexParams;
+ GrGpu::ResetTimestamp fTexParamsTimestamp;
+ GrGLTexID* fTexIDObj;
+ Orientation fOrientation;
+
+ void init(GrGpuGL* gpu,
+ const Desc& textureDesc,
+ const GrGLRenderTarget::Desc* rtDesc);
+
+ typedef GrTexture INHERITED;
+};
+
+#endif
diff --git a/src/gpu/GrGLUtil.cpp b/src/gpu/GrGLUtil.cpp
new file mode 100644
index 0000000..f12b407
--- /dev/null
+++ b/src/gpu/GrGLUtil.cpp
@@ -0,0 +1,42 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrGLConfig.h"
+#include "GrGLInterface.h"
+
+void GrGLClearErr(const GrGLInterface* gl) {
+ while (GR_GL_NO_ERROR != gl->fGetError()) {}
+}
+
+void GrGLCheckErr(const GrGLInterface* gl,
+ const char* location,
+ const char* call) {
+ uint32_t err = GR_GL_GET_ERROR(gl);
+ if (GR_GL_NO_ERROR != err) {
+ GrPrintf("---- glGetError %x", err);
+ if (NULL != location) {
+ GrPrintf(" at\n\t%s", location);
+ }
+ if (NULL != call) {
+ GrPrintf("\n\t\t%s", call);
+ }
+ GrPrintf("\n");
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#if GR_GL_LOG_CALLS
+ bool gLogCallsGL = !!(GR_GL_LOG_CALLS_START);
+#endif
+
+#if GR_GL_CHECK_ERROR
+ bool gCheckErrorGL = !!(GR_GL_CHECK_ERROR_START);
+#endif
+
diff --git a/src/gpu/GrGLVertexBuffer.cpp b/src/gpu/GrGLVertexBuffer.cpp
new file mode 100644
index 0000000..33c1e7e
--- /dev/null
+++ b/src/gpu/GrGLVertexBuffer.cpp
@@ -0,0 +1,126 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#include "GrGLVertexBuffer.h"
+#include "GrGpuGL.h"
+
+#define GPUGL static_cast<GrGpuGL*>(getGpu())
+
+#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
+
+GrGLVertexBuffer::GrGLVertexBuffer(GrGpuGL* gpu,
+ GrGLuint id,
+ size_t sizeInBytes,
+ bool dynamic)
+ : INHERITED(gpu, sizeInBytes, dynamic)
+ , fBufferID(id)
+ , fLockPtr(NULL) {
+}
+
+void GrGLVertexBuffer::onRelease() {
+ // make sure we've not been abandoned
+ if (fBufferID) {
+ GPUGL->notifyVertexBufferDelete(this);
+ GL_CALL(DeleteBuffers(1, &fBufferID));
+ fBufferID = 0;
+ }
+}
+
+void GrGLVertexBuffer::onAbandon() {
+ fBufferID = 0;
+ fLockPtr = NULL;
+}
+
+void GrGLVertexBuffer::bind() const {
+ GL_CALL(BindBuffer(GR_GL_ARRAY_BUFFER, fBufferID));
+ GPUGL->notifyVertexBufferBind(this);
+}
+
+GrGLuint GrGLVertexBuffer::bufferID() const {
+ return fBufferID;
+}
+
+void* GrGLVertexBuffer::lock() {
+ GrAssert(fBufferID);
+ GrAssert(!isLocked());
+ if (this->getGpu()->getCaps().fBufferLockSupport) {
+ this->bind();
+ // Let driver know it can discard the old data
+ GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, this->sizeInBytes(), NULL,
+ this->dynamic() ? GR_GL_DYNAMIC_DRAW :
+ GR_GL_STATIC_DRAW));
+ GR_GL_CALL_RET(GPUGL->glInterface(),
+ fLockPtr,
+ MapBuffer(GR_GL_ARRAY_BUFFER, GR_GL_WRITE_ONLY));
+ return fLockPtr;
+ }
+ return NULL;
+}
+
+void* GrGLVertexBuffer::lockPtr() const {
+ return fLockPtr;
+}
+
+void GrGLVertexBuffer::unlock() {
+
+ GrAssert(fBufferID);
+ GrAssert(isLocked());
+ GrAssert(this->getGpu()->getCaps().fBufferLockSupport);
+
+ this->bind();
+ GL_CALL(UnmapBuffer(GR_GL_ARRAY_BUFFER));
+ fLockPtr = NULL;
+}
+
+bool GrGLVertexBuffer::isLocked() const {
+ GrAssert(!this->isValid() || fBufferID);
+#if GR_DEBUG
+ if (this->isValid() && this->getGpu()->getCaps().fBufferLockSupport) {
+ GrGLint mapped;
+ this->bind();
+ GL_CALL(GetBufferParameteriv(GR_GL_ARRAY_BUFFER,
+ GR_GL_BUFFER_MAPPED, &mapped));
+ GrAssert(!!mapped == !!fLockPtr);
+ }
+#endif
+ return NULL != fLockPtr;
+}
+
+bool GrGLVertexBuffer::updateData(const void* src, size_t srcSizeInBytes) {
+ GrAssert(fBufferID);
+ GrAssert(!isLocked());
+ if (srcSizeInBytes > this->sizeInBytes()) {
+ return false;
+ }
+ this->bind();
+ GrGLenum usage = dynamic() ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW;
+#if !GR_GL_USE_BUFFER_DATA_NULL_HINT
+ // Note that we're cheating on the size here. Currently no methods
+ // allow a partial update that preserves contents of non-updated
+ // portions of the buffer (and lock() does a glBufferData(..size, NULL..))
+ GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, srcSizeInBytes, src, usage));
+#else
+ if (this->sizeInBytes() == srcSizeInBytes) {
+ GL_CALL(BufferData(GR_GL_ARRAY_BUFFER, srcSizeInBytes, src, usage));
+ } else {
+ // Before we call glBufferSubData we give the driver a hint using
+ // glBufferData with NULL. This makes the old buffer contents
+ // inaccessible to future draws. The GPU may still be processing draws
+ // that reference the old contents. With this hint it can assign a
+ // different allocation for the new contents to avoid flushing the gpu
+ // past draws consuming the old contents.
+ GL_CALL(BufferData(GR_GL_ARRAY_BUFFER,
+ this->sizeInBytes(), NULL, usage));
+ GL_CALL(BufferSubData(GR_GL_ARRAY_BUFFER, 0, srcSizeInBytes, src));
+ }
+#endif
+ return true;
+}
+
diff --git a/gpu/include/GrGLVertexBuffer.h b/src/gpu/GrGLVertexBuffer.h
index b2ada31..15fc54a 100644
--- a/gpu/include/GrGLVertexBuffer.h
+++ b/src/gpu/GrGLVertexBuffer.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrGLVertexBuffer_DEFINED
#define GrGLVertexBuffer_DEFINED
@@ -33,9 +26,6 @@ public:
virtual void unlock();
virtual bool isLocked() const;
virtual bool updateData(const void* src, size_t srcSizeInBytes);
- virtual bool updateSubData(const void* src,
- size_t srcSizeInBytes,
- size_t offset);
GrGLuint bufferID() const;
protected:
diff --git a/gpu/include/GrGeometryBuffer.h b/src/gpu/GrGeometryBuffer.h
index 98f58bd..c74b254 100644
--- a/gpu/include/GrGeometryBuffer.h
+++ b/src/gpu/GrGeometryBuffer.h
@@ -1,19 +1,12 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrGeometryBuffer_DEFINED
#define GrGeometryBuffer_DEFINED
@@ -26,12 +19,6 @@ class GrGpu;
*/
class GrGeometryBuffer : public GrResource {
public:
- /**
- * Retrieves the size of the buffer
- *
- * @return the size of the buffer in bytes
- */
- size_t size() const { return fSizeInBytes; }
/**
*Retrieves whether the buffer was created with the dynamic flag
@@ -84,16 +71,9 @@ public:
*/
virtual bool updateData(const void* src, size_t srcSizeInBytes) = 0;
- /**
- * Updates a portion of the buffer data.
- *
- * The contents of the buffer outside the update region are preserved.
- *
- * @return returns true if the update succeeds, false otherwise.
- */
- virtual bool updateSubData(const void* src,
- size_t srcSizeInBytes,
- size_t offset) = 0;
+ // GrResource overrides
+ virtual size_t sizeInBytes() const { return fSizeInBytes; }
+
protected:
GrGeometryBuffer(GrGpu* gpu, size_t sizeInBytes, bool dynamic)
: INHERITED(gpu)
diff --git a/gpu/src/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 4f260c7..8a7d3e4 100644
--- a/gpu/src/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -1,64 +1,65 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "GrGpu.h"
-#include "GrMemory.h"
-#include "GrTextStrike.h"
-#include "GrTextureCache.h"
+
+#include "GrBufferAllocPool.h"
#include "GrClipIterator.h"
+#include "GrContext.h"
#include "GrIndexBuffer.h"
-#include "GrVertexBuffer.h"
-#include "GrBufferAllocPool.h"
#include "GrPathRenderer.h"
+#include "GrGLStencilBuffer.h"
+#include "GrVertexBuffer.h"
// probably makes no sense for this to be less than a page
-static const size_t VERTEX_POOL_VB_SIZE = 1 << 12;
-static const int VERTEX_POOL_VB_COUNT = 1;
-
+static const size_t VERTEX_POOL_VB_SIZE = 1 << 18;
+static const int VERTEX_POOL_VB_COUNT = 4;
+static const size_t INDEX_POOL_IB_SIZE = 1 << 16;
+static const int INDEX_POOL_IB_COUNT = 4;
////////////////////////////////////////////////////////////////////////////////
extern void gr_run_unittests();
+#define DEBUG_INVAL_BUFFER 0xdeadcafe
+#define DEBUG_INVAL_START_IDX -1
+
GrGpu::GrGpu()
- : f8bitPaletteSupport(false)
- , fCurrPoolVertexBuffer(NULL)
- , fCurrPoolStartVertex(0)
- , fCurrPoolIndexBuffer(NULL)
- , fCurrPoolStartIndex(0)
- , fContext(NULL)
+ : fContext(NULL)
+ , fResetTimestamp(kExpiredTimestamp+1)
, fVertexPool(NULL)
, fIndexPool(NULL)
+ , fVertexPoolUseCnt(0)
+ , fIndexPoolUseCnt(0)
, fQuadIndexBuffer(NULL)
, fUnitSquareVertexBuffer(NULL)
- , fDefaultPathRenderer(NULL)
- , fClientPathRenderer(NULL)
+ , fPathRendererChain(NULL)
, fContextIsDirty(true)
- , fVertexPoolInUse(false)
- , fIndexPoolInUse(false)
, fResourceHead(NULL) {
#if GR_DEBUG
//gr_run_unittests();
#endif
+
+ fGeomPoolStateStack.push_back();
+#if GR_DEBUG
+ GeometryPoolState& poolState = fGeomPoolStateStack.back();
+ poolState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
+ poolState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
+ poolState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
+ poolState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
+#endif
resetStats();
}
GrGpu::~GrGpu() {
- releaseResources();
+ this->releaseResources();
}
void GrGpu::abandonResources() {
@@ -76,6 +77,8 @@ void GrGpu::abandonResources() {
fVertexPool = NULL;
delete fIndexPool;
fIndexPool = NULL;
+ // in case path renderer has any GrResources, start from scratch
+ GrSafeSetNull(fPathRendererChain);
}
void GrGpu::releaseResources() {
@@ -93,6 +96,8 @@ void GrGpu::releaseResources() {
fVertexPool = NULL;
delete fIndexPool;
fIndexPool = NULL;
+ // in case path renderer has any GrResources, start from scratch
+ GrSafeSetNull(fPathRendererChain);
}
void GrGpu::insertResource(GrResource* resource) {
@@ -139,12 +144,75 @@ void GrGpu::unimpl(const char msg[]) {
GrTexture* GrGpu::createTexture(const GrTextureDesc& desc,
const void* srcData, size_t rowBytes) {
this->handleDirtyContext();
- return this->onCreateTexture(desc, srcData, rowBytes);
+ GrTexture* tex = this->onCreateTexture(desc, srcData, rowBytes);
+ if (NULL != tex &&
+ (kRenderTarget_GrTextureFlagBit & desc.fFlags) &&
+ !(kNoStencil_GrTextureFlagBit & desc.fFlags)) {
+ GrAssert(NULL != tex->asRenderTarget());
+ // TODO: defer this and attach dynamically
+ if (!this->attachStencilBufferToRenderTarget(tex->asRenderTarget())) {
+ tex->unref();
+ return NULL;
+ }
+ }
+ return tex;
+}
+
+bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) {
+ GrAssert(NULL == rt->getStencilBuffer());
+ GrStencilBuffer* sb =
+ this->getContext()->findStencilBuffer(rt->width(),
+ rt->height(),
+ rt->numSamples());
+ if (NULL != sb) {
+ rt->setStencilBuffer(sb);
+ bool attached = this->attachStencilBufferToRenderTarget(sb, rt);
+ if (!attached) {
+ rt->setStencilBuffer(NULL);
+ }
+ return attached;
+ }
+ if (this->createStencilBufferForRenderTarget(rt,
+ rt->width(), rt->height())) {
+ rt->getStencilBuffer()->ref();
+ rt->getStencilBuffer()->transferToCacheAndLock();
+
+ // Right now we're clearing the stencil buffer here after it is
+ // attached to an RT for the first time. When we start matching
+ // stencil buffers with smaller color targets this will no longer
+ // be correct because it won't be guaranteed to clear the entire
+ // sb.
+ // We used to clear down in the GL subclass using a special purpose
+ // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported
+ // FBO status.
+ GrDrawState::AutoRenderTargetRestore artr(this->drawState(), rt);
+ this->clearStencil();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+GrTexture* GrGpu::createPlatformTexture(const GrPlatformTextureDesc& desc) {
+ this->handleDirtyContext();
+ GrTexture* tex = this->onCreatePlatformTexture(desc);
+ if (NULL == tex) {
+ return NULL;
+ }
+ // TODO: defer this and attach dynamically
+ GrRenderTarget* tgt = tex->asRenderTarget();
+ if (NULL != tgt &&
+ !this->attachStencilBufferToRenderTarget(tgt)) {
+ tex->unref();
+ return NULL;
+ } else {
+ return tex;
+ }
}
-GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
+GrRenderTarget* GrGpu::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
this->handleDirtyContext();
- return this->onCreateRenderTargetFrom3DApiState();
+ return this->onCreatePlatformRenderTarget(desc);
}
GrResource* GrGpu::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
@@ -163,6 +231,9 @@ GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
}
void GrGpu::clear(const GrIRect* rect, GrColor color) {
+ if (NULL == this->getDrawState().getRenderTarget()) {
+ return;
+ }
this->handleDirtyContext();
this->onClear(rect, color);
}
@@ -174,10 +245,24 @@ void GrGpu::forceRenderTargetFlush() {
bool GrGpu::readPixels(GrRenderTarget* target,
int left, int top, int width, int height,
- GrPixelConfig config, void* buffer) {
+ GrPixelConfig config, void* buffer,
+ size_t rowBytes, bool invertY) {
+ GrAssert(GrPixelConfigIsUnpremultiplied(config) ==
+ GrPixelConfigIsUnpremultiplied(target->config()));
+ this->handleDirtyContext();
+ return this->onReadPixels(target, left, top, width, height,
+ config, buffer, rowBytes, invertY);
+}
+void GrGpu::writeTexturePixels(GrTexture* texture,
+ int left, int top, int width, int height,
+ GrPixelConfig config, const void* buffer,
+ size_t rowBytes) {
+ GrAssert(GrPixelConfigIsUnpremultiplied(config) ==
+ GrPixelConfigIsUnpremultiplied(texture->config()));
this->handleDirtyContext();
- return this->onReadPixels(target, left, top, width, height, config, buffer);
+ this->onWriteTexturePixels(texture, left, top, width, height,
+ config, buffer, rowBytes);
}
////////////////////////////////////////////////////////////////////////////////
@@ -256,23 +341,15 @@ const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const {
////////////////////////////////////////////////////////////////////////////////
-void GrGpu::clipWillBeSet(const GrClip& newClip) {
- if (newClip != fClip) {
- fClipState.fClipIsDirty = true;
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
// stencil settings to use when clip is in stencil
-const GrStencilSettings GrGpu::gClipStencilSettings = {
- kKeep_StencilOp, kKeep_StencilOp,
- kKeep_StencilOp, kKeep_StencilOp,
- kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
- 0, 0,
- 0, 0,
- 0, 0
-};
+GR_STATIC_CONST_SAME_STENCIL(gClipStencilSettings,
+ kKeep_StencilOp,
+ kKeep_StencilOp,
+ kAlwaysIfInClip_StencilFunc,
+ 0x0000,
+ 0x0000,
+ 0x0000);
+const GrStencilSettings& GrGpu::gClipStencilSettings = ::gClipStencilSettings;
// mapping of clip-respecting stencil funcs to normal stencil funcs
// mapping depends on whether stencil-clipping is in effect.
@@ -367,25 +444,112 @@ void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
#define SET_RANDOM_COLOR
#endif
+namespace {
+// determines how many elements at the head of the clip can be skipped and
+// whether the initial clear should be to the inside- or outside-the-clip value,
+// and what op should be used to draw the first element that isn't skipped.
+int process_initial_clip_elements(const GrClip& clip,
+ const GrRect& bounds,
+ bool* clearToInside,
+ GrSetOp* startOp) {
+
+ // logically before the first element of the clip stack is
+ // processed the clip is entirely open. However, depending on the
+ // first set op we may prefer to clear to 0 for performance. We may
+ // also be able to skip the initial clip paths/rects. We loop until
+ // we cannot skip an element.
+ int curr;
+ bool done = false;
+ *clearToInside = true;
+ int count = clip.getElementCount();
+
+ for (curr = 0; curr < count && !done; ++curr) {
+ switch (clip.getOp(curr)) {
+ case kReplace_SetOp:
+ // replace ignores everything previous
+ *startOp = kReplace_SetOp;
+ *clearToInside = false;
+ done = true;
+ break;
+ case kIntersect_SetOp:
+ // if this element contains the entire bounds then we
+ // can skip it.
+ if (kRect_ClipType == clip.getElementType(curr)
+ && clip.getRect(curr).contains(bounds)) {
+ break;
+ }
+ // if everything is initially clearToInside then intersect is
+ // same as clear to 0 and treat as a replace. Otherwise,
+ // set stays empty.
+ if (*clearToInside) {
+ *startOp = kReplace_SetOp;
+ *clearToInside = false;
+ done = true;
+ }
+ break;
+ // we can skip a leading union.
+ case kUnion_SetOp:
+ // if everything is initially outside then union is
+ // same as replace. Otherwise, every pixel is still
+ // clearToInside
+ if (!*clearToInside) {
+ *startOp = kReplace_SetOp;
+ done = true;
+ }
+ break;
+ case kXor_SetOp:
+ // xor is same as difference or replace both of which
+ // can be 1-pass instead of 2 for xor.
+ if (*clearToInside) {
+ *startOp = kDifference_SetOp;
+ } else {
+ *startOp = kReplace_SetOp;
+ }
+ done = true;
+ break;
+ case kDifference_SetOp:
+ // if all pixels are clearToInside then we have to process the
+ // difference, otherwise it has no effect and all pixels
+ // remain outside.
+ if (*clearToInside) {
+ *startOp = kDifference_SetOp;
+ done = true;
+ }
+ break;
+ case kReverseDifference_SetOp:
+ // if all pixels are clearToInside then reverse difference
+ // produces empty set. Otherise it is same as replace
+ if (*clearToInside) {
+ *clearToInside = false;
+ } else {
+ *startOp = kReplace_SetOp;
+ done = true;
+ }
+ break;
+ default:
+ GrCrash("Unknown set op.");
+ }
+ }
+ return done ? curr-1 : count;
+}
+}
+
bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
const GrIRect* r = NULL;
GrIRect clipRect;
- // we check this early because we need a valid
- // render target to setup stencil clipping
- // before even going into flushGraphicsState
- if (NULL == fCurrDrawState.fRenderTarget) {
- GrAssert(!"No render target bound.");
- return false;
- }
+ GrDrawState* drawState = this->drawState();
+ const GrRenderTarget* rt = drawState->getRenderTarget();
+
+ // GrDrawTarget should have filtered this for us
+ GrAssert(NULL != rt);
- if (fCurrDrawState.fFlagBits & kClip_StateBit) {
- GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;
+ if (drawState->isClipState()) {
GrRect bounds;
GrRect rtRect;
rtRect.setLTRB(0, 0,
- GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
+ GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
if (fClip.hasConservativeBounds()) {
bounds = fClip.getConservativeBounds();
if (!bounds.intersect(rtRect)) {
@@ -401,53 +565,60 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
}
r = &clipRect;
- fClipState.fClipInStencil = !fClip.isRect() &&
- !fClip.isEmpty() &&
- !bounds.isEmpty();
+ // use the stencil clip if we can't represent the clip as a rectangle.
+ fClipInStencil = !fClip.isRect() && !fClip.isEmpty() &&
+ !bounds.isEmpty();
+
+ // TODO: dynamically attach a SB when needed.
+ GrStencilBuffer* stencilBuffer = rt->getStencilBuffer();
+ if (fClipInStencil && NULL == stencilBuffer) {
+ return false;
+ }
- if (fClipState.fClipInStencil &&
- (fClipState.fClipIsDirty ||
- fClip != rt.fLastStencilClip)) {
+ if (fClipInStencil &&
+ stencilBuffer->mustRenderClip(fClip, rt->width(), rt->height())) {
+
+ stencilBuffer->setLastClip(fClip, rt->width(), rt->height());
- rt.fLastStencilClip = fClip;
// we set the current clip to the bounds so that our recursive
// draws are scissored to them. We use the copy of the complex clip
- // in the rt to render
- const GrClip& clip = rt.fLastStencilClip;
+ // we just stashed on the SB to render from. We set it back after
+ // we finish drawing it into the stencil.
+ const GrClip& clip = stencilBuffer->getLastClip();
fClip.setFromRect(bounds);
AutoStateRestore asr(this);
- AutoInternalDrawGeomRestore aidgr(this);
+ AutoGeometryPush agp(this);
- this->setViewMatrix(GrMatrix::I());
- this->clearStencilClip(clipRect);
+ drawState->setViewMatrix(GrMatrix::I());
this->flushScissor(NULL);
#if !VISUALIZE_COMPLEX_CLIP
- this->enableState(kNoColorWrites_StateBit);
+ drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
#else
- this->disableState(kNoColorWrites_StateBit);
+ drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
#endif
int count = clip.getElementCount();
- int clipBit = rt.stencilBits();
+ int clipBit = stencilBuffer->bits();
+ SkASSERT((clipBit <= 16) &&
+ "Ganesh only handles 16b or smaller stencil buffers");
clipBit = (1 << (clipBit-1));
+
+ bool clearToInside;
+ GrSetOp startOp = kReplace_SetOp; // suppress warning
+ int start = process_initial_clip_elements(clip,
+ rtRect,
+ &clearToInside,
+ &startOp);
- // often we'll see the first two elements of the clip are
- // the full rt size and another element intersected with it.
- // We can skip the first full-size rect and save a big rect draw.
- int firstElement = 0;
- if (clip.getElementCount() > 1 &&
- kRect_ClipType == clip.getElementType(0) &&
- kIntersect_SetOp == clip.getOp(1)&&
- clip.getRect(0).contains(bounds)) {
- firstElement = 1;
- }
+ this->clearStencilClip(clipRect, clearToInside);
// walk through each clip element and perform its set op
// with the existing clip.
- for (int c = firstElement; c < count; ++c) {
+ for (int c = start; c < count; ++c) {
GrPathFill fill;
+ bool fillInverted;
// enabled at bottom of loop
- this->disableState(kModifyStencilClip_StateBit);
+ drawState->disableState(kModifyStencilClip_StateBit);
bool canRenderDirectToStencil; // can the clip element be drawn
// directly to the stencil buffer
@@ -457,19 +628,34 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
GrPathRenderer* pr = NULL;
const GrPath* clipPath = NULL;
+ GrPathRenderer::AutoClearPath arp;
if (kRect_ClipType == clip.getElementType(c)) {
canRenderDirectToStencil = true;
fill = kEvenOdd_PathFill;
+ fillInverted = false;
+ // there is no point in intersecting a screen filling
+ // rectangle.
+ if (kIntersect_SetOp == clip.getOp(c) &&
+ clip.getRect(c).contains(rtRect)) {
+ continue;
+ }
} else {
fill = clip.getPathFill(c);
+ fillInverted = GrIsFillInverted(fill);
+ fill = GrNonInvertedFill(fill);
clipPath = &clip.getPath(c);
- pr = this->getClipPathRenderer(*clipPath, NonInvertedFill(fill));
+ pr = this->getClipPathRenderer(*clipPath, fill);
+ if (NULL == pr) {
+ fClipInStencil = false;
+ fClip = clip;
+ return false;
+ }
canRenderDirectToStencil =
- !pr->requiresStencilPass(this, *clipPath,
- NonInvertedFill(fill));
+ !pr->requiresStencilPass(this, *clipPath, fill);
+ arp.set(pr, this, clipPath, fill, false, NULL);
}
- GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
+ GrSetOp op = (c == start) ? startOp : clip.getOp(c);
int passes;
GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
@@ -481,49 +667,44 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
GrStencilSettings::GetClipPasses(op,
canRenderDirectToStencil,
clipBit,
- IsFillInverted(fill),
+ fillInverted,
&passes, stencilSettings);
// draw the element to the client stencil bits if necessary
if (!canDrawDirectToClip) {
- static const GrStencilSettings gDrawToStencil = {
- kIncClamp_StencilOp, kIncClamp_StencilOp,
- kIncClamp_StencilOp, kIncClamp_StencilOp,
- kAlways_StencilFunc, kAlways_StencilFunc,
- 0xffffffff, 0xffffffff,
- 0x00000000, 0x00000000,
- 0xffffffff, 0xffffffff,
- };
+ GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil,
+ kIncClamp_StencilOp,
+ kIncClamp_StencilOp,
+ kAlways_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
SET_RANDOM_COLOR
if (kRect_ClipType == clip.getElementType(c)) {
- this->setStencil(gDrawToStencil);
+ *drawState->stencil() = gDrawToStencil;
this->drawSimpleRect(clip.getRect(c), NULL, 0);
} else {
if (canRenderDirectToStencil) {
- this->setStencil(gDrawToStencil);
- pr->drawPath(this, 0, *clipPath, NonInvertedFill(fill),
- NULL);
+ *drawState->stencil() = gDrawToStencil;
+ pr->drawPath(0);
} else {
- pr->drawPathToStencil(this, *clipPath,
- NonInvertedFill(fill),
- NULL);
+ pr->drawPathToStencil();
}
}
}
// now we modify the clip bit by rendering either the clip
// element directly or a bounding rect of the entire clip.
- this->enableState(kModifyStencilClip_StateBit);
+ drawState->enableState(kModifyStencilClip_StateBit);
for (int p = 0; p < passes; ++p) {
- this->setStencil(stencilSettings[p]);
+ *drawState->stencil() = stencilSettings[p];
if (canDrawDirectToClip) {
if (kRect_ClipType == clip.getElementType(c)) {
SET_RANDOM_COLOR
this->drawSimpleRect(clip.getRect(c), NULL, 0);
} else {
SET_RANDOM_COLOR
- GrAssert(!IsFillInverted(fill));
- pr->drawPath(this, 0, *clipPath, fill, NULL);
+ pr->drawPath(0);
}
} else {
SET_RANDOM_COLOR
@@ -531,12 +712,12 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
}
}
}
+ // restore clip
fClip = clip;
- // recusive draws would have disabled this.
- fClipState.fClipInStencil = true;
+ // recusive draws would have disabled this since they drew with
+ // the clip bounds as clip.
+ fClipInStencil = true;
}
-
- fClipState.fClipIsDirty = false;
}
// Must flush the scissor after graphics state
@@ -549,32 +730,48 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
GrPathFill fill) {
- if (NULL != fClientPathRenderer &&
- fClientPathRenderer->canDrawPath(this, path, fill)) {
- return fClientPathRenderer;
- } else {
- if (NULL == fDefaultPathRenderer) {
- fDefaultPathRenderer =
- new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
- this->supportsStencilWrapOps());
- }
- GrAssert(fDefaultPathRenderer->canDrawPath(this, path, fill));
- return fDefaultPathRenderer;
+ if (NULL == fPathRendererChain) {
+ fPathRendererChain =
+ new GrPathRendererChain(this->getContext(),
+ GrPathRendererChain::kNonAAOnly_UsageFlag);
}
+ return fPathRendererChain->getPathRenderer(this->getCaps(),
+ path, fill, false);
}
////////////////////////////////////////////////////////////////////////////////
-void GrGpu::drawIndexed(GrPrimitiveType type,
- int startVertex,
- int startIndex,
- int vertexCount,
- int indexCount) {
- GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
- fReservedGeometry.fLocked);
- GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fIndexSrc ||
- fReservedGeometry.fLocked);
+void GrGpu::geometrySourceWillPush() {
+ const GeometrySrcState& geoSrc = this->getGeomSrc();
+ if (kArray_GeometrySrcType == geoSrc.fVertexSrc ||
+ kReserved_GeometrySrcType == geoSrc.fVertexSrc) {
+ this->finalizeReservedVertices();
+ }
+ if (kArray_GeometrySrcType == geoSrc.fIndexSrc ||
+ kReserved_GeometrySrcType == geoSrc.fIndexSrc) {
+ this->finalizeReservedIndices();
+ }
+ GeometryPoolState& newState = fGeomPoolStateStack.push_back();
+#if GR_DEBUG
+ newState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
+ newState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
+ newState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
+ newState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
+#endif
+}
+
+void GrGpu::geometrySourceWillPop(const GeometrySrcState& restoredState) {
+ // if popping last entry then pops are unbalanced with pushes
+ GrAssert(fGeomPoolStateStack.count() > 1);
+ fGeomPoolStateStack.pop_back();
+}
+
+void GrGpu::onDrawIndexed(GrPrimitiveType type,
+ int startVertex,
+ int startIndex,
+ int vertexCount,
+ int indexCount) {
this->handleDirtyContext();
@@ -592,16 +789,13 @@ void GrGpu::drawIndexed(GrPrimitiveType type,
int sIndex = startIndex;
setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
- this->onDrawIndexed(type, sVertex, sIndex,
- vertexCount, indexCount);
+ this->onGpuDrawIndexed(type, sVertex, sIndex,
+ vertexCount, indexCount);
}
-void GrGpu::drawNonIndexed(GrPrimitiveType type,
+void GrGpu::onDrawNonIndexed(GrPrimitiveType type,
int startVertex,
int vertexCount) {
- GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
- fReservedGeometry.fLocked);
-
this->handleDirtyContext();
if (!this->setupClipAndFlushState(type)) {
@@ -615,7 +809,7 @@ void GrGpu::drawNonIndexed(GrPrimitiveType type,
int sVertex = startVertex;
setupGeometry(&sVertex, NULL, vertexCount, 0);
- this->onDrawNonIndexed(type, sVertex, vertexCount);
+ this->onGpuDrawNonIndexed(type, sVertex, vertexCount);
}
void GrGpu::finalizeReservedVertices() {
@@ -630,11 +824,12 @@ void GrGpu::finalizeReservedIndices() {
void GrGpu::prepareVertexPool() {
if (NULL == fVertexPool) {
+ GrAssert(0 == fVertexPoolUseCnt);
fVertexPool = new GrVertexBufferAllocPool(this, true,
VERTEX_POOL_VB_SIZE,
VERTEX_POOL_VB_COUNT);
fVertexPool->releaseGpuRef();
- } else if (!fVertexPoolInUse) {
+ } else if (!fVertexPoolUseCnt) {
// the client doesn't have valid data in the pool
fVertexPool->reset();
}
@@ -642,81 +837,119 @@ void GrGpu::prepareVertexPool() {
void GrGpu::prepareIndexPool() {
if (NULL == fIndexPool) {
- fIndexPool = new GrIndexBufferAllocPool(this, true, 0, 1);
+ GrAssert(0 == fIndexPoolUseCnt);
+ fIndexPool = new GrIndexBufferAllocPool(this, true,
+ INDEX_POOL_IB_SIZE,
+ INDEX_POOL_IB_COUNT);
fIndexPool->releaseGpuRef();
- } else if (!fIndexPoolInUse) {
+ } else if (!fIndexPoolUseCnt) {
// the client doesn't have valid data in the pool
fIndexPool->reset();
}
}
-bool GrGpu::onAcquireGeometry(GrVertexLayout vertexLayout,
- void** vertices,
- void** indices) {
- GrAssert(!fReservedGeometry.fLocked);
- size_t reservedVertexSpace = 0;
-
- if (fReservedGeometry.fVertexCount) {
- GrAssert(NULL != vertices);
-
- this->prepareVertexPool();
-
- *vertices = fVertexPool->makeSpace(vertexLayout,
- fReservedGeometry.fVertexCount,
- &fCurrPoolVertexBuffer,
- &fCurrPoolStartVertex);
- if (NULL == *vertices) {
- return false;
- }
- reservedVertexSpace = VertexSize(vertexLayout) *
- fReservedGeometry.fVertexCount;
+bool GrGpu::onReserveVertexSpace(GrVertexLayout vertexLayout,
+ int vertexCount,
+ void** vertices) {
+ GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
+
+ GrAssert(vertexCount > 0);
+ GrAssert(NULL != vertices);
+
+ this->prepareVertexPool();
+
+ *vertices = fVertexPool->makeSpace(vertexLayout,
+ vertexCount,
+ &geomPoolState.fPoolVertexBuffer,
+ &geomPoolState.fPoolStartVertex);
+ if (NULL == *vertices) {
+ return false;
}
- if (fReservedGeometry.fIndexCount) {
- GrAssert(NULL != indices);
+ ++fVertexPoolUseCnt;
+ return true;
+}
- this->prepareIndexPool();
+bool GrGpu::onReserveIndexSpace(int indexCount, void** indices) {
+ GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
+
+ GrAssert(indexCount > 0);
+ GrAssert(NULL != indices);
- *indices = fIndexPool->makeSpace(fReservedGeometry.fIndexCount,
- &fCurrPoolIndexBuffer,
- &fCurrPoolStartIndex);
- if (NULL == *indices) {
- fVertexPool->putBack(reservedVertexSpace);
- fCurrPoolVertexBuffer = NULL;
- return false;
- }
+ this->prepareIndexPool();
+
+ *indices = fIndexPool->makeSpace(indexCount,
+ &geomPoolState.fPoolIndexBuffer,
+ &geomPoolState.fPoolStartIndex);
+ if (NULL == *indices) {
+ return false;
}
+ ++fIndexPoolUseCnt;
return true;
}
-void GrGpu::onReleaseGeometry() {}
+void GrGpu::releaseReservedVertexSpace() {
+ const GeometrySrcState& geoSrc = this->getGeomSrc();
+ GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc);
+ size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
+ fVertexPool->putBack(bytes);
+ --fVertexPoolUseCnt;
+}
+
+void GrGpu::releaseReservedIndexSpace() {
+ const GeometrySrcState& geoSrc = this->getGeomSrc();
+ GrAssert(kReserved_GeometrySrcType == geoSrc.fIndexSrc);
+ size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
+ fIndexPool->putBack(bytes);
+ --fIndexPoolUseCnt;
+}
void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
- GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
this->prepareVertexPool();
+ GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
#if GR_DEBUG
bool success =
#endif
- fVertexPool->appendVertices(fGeometrySrc.fVertexLayout,
+ fVertexPool->appendVertices(this->getGeomSrc().fVertexLayout,
vertexCount,
vertexArray,
- &fCurrPoolVertexBuffer,
- &fCurrPoolStartVertex);
+ &geomPoolState.fPoolVertexBuffer,
+ &geomPoolState.fPoolStartVertex);
+ ++fVertexPoolUseCnt;
GR_DEBUGASSERT(success);
}
void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
- GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
this->prepareIndexPool();
+ GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
#if GR_DEBUG
bool success =
#endif
fIndexPool->appendIndices(indexCount,
indexArray,
- &fCurrPoolIndexBuffer,
- &fCurrPoolStartIndex);
+ &geomPoolState.fPoolIndexBuffer,
+ &geomPoolState.fPoolStartIndex);
+ ++fIndexPoolUseCnt;
GR_DEBUGASSERT(success);
}
+void GrGpu::releaseVertexArray() {
+ // if vertex source was array, we stowed data in the pool
+ const GeometrySrcState& geoSrc = this->getGeomSrc();
+ GrAssert(kArray_GeometrySrcType == geoSrc.fVertexSrc);
+ size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
+ fVertexPool->putBack(bytes);
+ --fVertexPoolUseCnt;
+}
+
+void GrGpu::releaseIndexArray() {
+ // if index source was array, we stowed data in the pool
+ const GeometrySrcState& geoSrc = this->getGeomSrc();
+ GrAssert(kArray_GeometrySrcType == geoSrc.fIndexSrc);
+ size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
+ fIndexPool->putBack(bytes);
+ --fIndexPoolUseCnt;
+}
+
////////////////////////////////////////////////////////////////////////////////
const GrGpuStats& GrGpu::getStats() const {
@@ -743,14 +976,3 @@ void GrGpu::printStats() const {
}
}
-////////////////////////////////////////////////////////////////////////////////
-const GrSamplerState GrSamplerState::gClampNoFilter(
- GrSamplerState::kClamp_WrapMode,
- GrSamplerState::kClamp_WrapMode,
- GrSamplerState::kNormal_SampleMode,
- GrMatrix::I(),
- GrSamplerState::kNearest_Filter);
-
-
-
-
diff --git a/gpu/include/GrGpu.h b/src/gpu/GrGpu.h
index 5cb885a..0836ec8 100644
--- a/gpu/include/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -1,31 +1,26 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrGpu_DEFINED
#define GrGpu_DEFINED
#include "GrDrawTarget.h"
-#include "GrPathRenderer.h"
#include "GrRect.h"
#include "GrRefCnt.h"
#include "GrTexture.h"
class GrContext;
class GrIndexBufferAllocPool;
+class GrPathRenderer;
+class GrPathRendererChain;
class GrResource;
+class GrStencilBuffer;
class GrVertexBufferAllocPool;
/**
@@ -36,29 +31,30 @@ struct GrGpuStats {
uint32_t fIndexCnt; //<! Number of indices drawn
uint32_t fDrawCnt; //<! Number of draws
- uint32_t fProgChngCnt;//<! Number of program changes (N/A for fixed)
+ uint32_t fProgChngCnt;//<! Number of program changes
- /*
- * Number of times the texture is set in 3D API
- */
+ /**
+ * Number of times the texture is set in 3D API
+ */
uint32_t fTextureChngCnt;
- /*
- * Number of times the render target is set in 3D API
- */
+ /**
+ * Number of times the render target is set in 3D API
+ */
uint32_t fRenderTargetChngCnt;
- /*
- * Number of textures created (includes textures that are rendertargets).
- */
+ /**
+ * Number of textures created (includes textures that are rendertargets).
+ */
uint32_t fTextureCreateCnt;
- /*
- * Number of rendertargets created.
- */
+ /**
+ * Number of rendertargets created.
+ */
uint32_t fRenderTargetCreateCnt;
};
class GrGpu : public GrDrawTarget {
public:
+
/**
* Additional blend coeffecients for dual source blending, not exposed
* through GrPaint/GrContext.
@@ -125,18 +121,20 @@ public:
GrTexture* createTexture(const GrTextureDesc& desc,
const void* srcData, size_t rowBytes);
- GrResource* createPlatformSurface(const GrPlatformSurfaceDesc& desc);
+ /**
+ * Implements GrContext::createPlatformTexture
+ */
+ GrTexture* createPlatformTexture(const GrPlatformTextureDesc& desc);
/**
- * Reads the current target object (e.g. FBO or IDirect3DSurface9*) and
- * viewport state from the underlying 3D API and wraps it in a
- * GrRenderTarget. The GrRenderTarget will not attempt to delete/destroy the
- * underlying object in its destructor and it is up to caller to guarantee
- * that it remains valid while the GrRenderTarget is used.
- *
- * @return the newly created GrRenderTarget
+ * Implements GrContext::createPlatformTexture
*/
- GrRenderTarget* createRenderTargetFrom3DApiState();
+ GrRenderTarget* createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc);
+
+ /**
+ * DEPRECATED. This will be removed.
+ */
+ GrResource* createPlatformSurface(const GrPlatformSurfaceDesc& desc);
/**
* Creates a vertex buffer.
@@ -163,119 +161,6 @@ public:
GrIndexBuffer* createIndexBuffer(uint32_t size, bool dynamic);
/**
- * Are 8 bit paletted textures supported.
- *
- * @return true if 8bit palette textures are supported, false otherwise
- */
- bool supports8BitPalette() const { return f8bitPaletteSupport; }
-
- /**
- * returns true if two sided stenciling is supported. If false then only
- * the front face values of the GrStencilSettings
- * @return true if only a single stencil pass is needed.
- */
- bool supportsTwoSidedStencil() const
- { return fTwoSidedStencilSupport; }
-
- /**
- * returns true if stencil wrap is supported. If false then
- * kIncWrap_StencilOp and kDecWrap_StencilOp are treated as
- * kIncClamp_StencilOp and kDecClamp_StencilOp, respectively.
- * @return true if stencil wrap ops are supported.
- */
- bool supportsStencilWrapOps() const
- { return fStencilWrapOpsSupport; }
-
- /**
- * Checks whether locking vertex and index buffers is supported.
- *
- * @return true if locking is supported.
- */
- bool supportsBufferLocking() const { return fBufferLockSupport; }
-
- /**
- * Does the 3D API support anti-aliased lines. If so then line primitive
- * types will use this functionality when the AA state flag is set.
- */
- bool supportsAALines() const { return fAALineSupport; }
-
- /**
- * Does the subclass support GrSamplerState::k4x4Downsample_Filter
- */
- bool supports4x4DownsampleFilter() const { return f4X4DownsampleFilterSupport; }
-
- /**
- * Does this instance support dual-source blending? Required for proper
- * blending with partial coverage with certain blend modes (dst coeff is
- * not 1, ISA, or ISC)
- */
- bool supportsDualSourceBlending() const {
- return fDualSourceBlendingSupport;
- }
-
- /**
- * Gets the minimum width of a render target. If a texture/rt is created
- * with a width less than this size the GrGpu object will clamp it to this
- * value.
- */
- int minRenderTargetWidth() const { return fMinRenderTargetWidth; }
-
- /**
- * Gets the minimum width of a render target. If a texture/rt is created
- * with a height less than this size the GrGpu object will clamp it to this
- * value.
- */
- int minRenderTargetHeight() const { return fMinRenderTargetHeight; }
-
- /**
- * Reports whether full scene anti-aliasing is supported.
- */
- bool supportsFullsceneAA() const { return fFSAASupport; }
-
- /**
- * Returns true if NPOT textures can be created
- *
- * @return true if NPOT textures can be created
- */
- bool npotTextureSupport() const { return fNPOTTextureSupport; }
-
- /**
- * Returns true if NPOT textures can be repeat/mirror tiled.
- *
- * @return true if NPOT textures can be tiled
- */
- bool npotTextureTileSupport() const { return fNPOTTextureTileSupport; }
-
- /**
- * Returns true if a NPOT texture can be a rendertarget
- *
- * @return the true if NPOT texture/rendertarget can be created.
- */
- bool npotRenderTargetSupport() const { return fNPOTRenderTargetSupport; }
-
- int maxTextureDimension() const { return fMaxTextureDimension; }
-
- // GrDrawTarget overrides
- virtual void drawIndexed(GrPrimitiveType type,
- int startVertex,
- int startIndex,
- int vertexCount,
- int indexCount);
-
- virtual void drawNonIndexed(GrPrimitiveType type,
- int startVertex,
- int vertexCount);
- virtual void clear(const GrIRect* rect, GrColor color);
-
- /**
- * Installs a path renderer that will be used to draw paths that are
- * part of the clip.
- */
- void setClipPathRenderer(GrPathRenderer* pathRenderer) {
- GrSafeAssign(fClientPathRenderer, pathRenderer);
- }
-
- /**
* Returns an index buffer that can be used to render quads.
* Six indices per quad: 0, 1, 2, 0, 2, 3, etc.
* The max number of quads can be queried using GrIndexBuffer::maxQuads().
@@ -299,7 +184,60 @@ public:
void forceRenderTargetFlush();
/**
- * Reads a rectangle of pixels from a render target.
+ * readPixels with some configs may be slow. Given a desired config this
+ * function returns a fast-path config. The returned config must have the
+ * same components, component sizes, and not require conversion between
+ * pre- and unpremultiplied alpha. The caller is free to ignore the result
+ * and call readPixels with the original config.
+ */
+ virtual GrPixelConfig preferredReadPixelsConfig(GrPixelConfig config)
+ const {
+ return config;
+ }
+
+ /**
+ * Same as above but applies to writeTexturePixels
+ */
+ virtual GrPixelConfig preferredWritePixelsConfig(GrPixelConfig config)
+ const {
+ return config;
+ }
+
+ /**
+ * OpenGL's readPixels returns the result bottom-to-top while the skia
+ * API is top-to-bottom. Thus we have to do a y-axis flip. The obvious
+ * solution is to have the subclass do the flip using either the CPU or GPU.
+ * However, the caller (GrContext) may have transformations to apply and can
+ * simply fold in the y-flip for free. On the other hand, the subclass may
+ * be able to do it for free itself. For example, the subclass may have to
+ * do memcpys to handle rowBytes that aren't tight. It could do the y-flip
+ * concurrently.
+ *
+ * This function returns true if a y-flip is required to put the pixels in
+ * top-to-bottom order and the subclass cannot do it for free.
+ *
+ * See read pixels for the params
+ * @return true if calling readPixels with the same set of params will
+ * produce bottom-to-top data
+ */
+ virtual bool readPixelsWillPayForYFlip(GrRenderTarget* renderTarget,
+ int left, int top,
+ int width, int height,
+ GrPixelConfig config,
+ size_t rowBytes) const = 0;
+ /**
+ * This should return true if reading a NxM rectangle of pixels from a
+ * render target is faster if the target has dimensons N and M and the read
+ * rectangle has its top-left at 0,0.
+ */
+ virtual bool fullReadPixelsIsFasterThanPartial() const { return false; };
+
+ /**
+ * Reads a rectangle of pixels from a render target. Fails if read requires
+ * conversion between premultiplied and unpremultiplied configs. The caller
+ * should do the conversion by rendering to a target with the desire config
+ * first.
+ *
* @param renderTarget the render target to read from. NULL means the
* current render target.
* @param left left edge of the rectangle to read (inclusive)
@@ -308,6 +246,10 @@ public:
* @param height height of rectangle to read in pixels.
* @param config the pixel config of the destination buffer
* @param buffer memory to read the rectangle into.
+ * @param rowBytes the number of bytes between consecutive rows. Zero
+ * means rows are tightly packed.
+ * @param invertY buffer should be populated bottom-to-top as opposed
+ * to top-to-bottom (skia's usual order)
*
* @return true if the read succeeded, false if not. The read can fail
* because of a unsupported pixel config or because no render
@@ -315,7 +257,25 @@ public:
*/
bool readPixels(GrRenderTarget* renderTarget,
int left, int top, int width, int height,
- GrPixelConfig config, void* buffer);
+ GrPixelConfig config, void* buffer, size_t rowBytes,
+ bool invertY);
+
+ /**
+ * Updates the pixels in a rectangle of a texture.
+ *
+ * @param left left edge of the rectangle to write (inclusive)
+ * @param top top edge of the rectangle to write (inclusive)
+ * @param width width of rectangle to write in pixels.
+ * @param height height of rectangle to write in pixels.
+ * @param config the pixel config of the source buffer
+ * @param buffer memory to read pixels from
+ * @param rowBytes number of bytes bewtween consecutive rows. Zero
+ * means rows are tightly packed.
+ */
+ void writeTexturePixels(GrTexture* texture,
+ int left, int top, int width, int height,
+ GrPixelConfig config, const void* buffer,
+ size_t rowBytes);
const GrGpuStats& getStats() const;
void resetStats();
@@ -323,12 +283,13 @@ public:
/**
* Called to tell Gpu object that all GrResources have been lost and should
- * be abandoned.
+ * be abandoned. Overrides must call INHERITED::abandonResources().
*/
virtual void abandonResources();
/**
- * Called to tell Gpu object to release all GrResources.
+ * Called to tell Gpu object to release all GrResources. Overrides must call
+ * INHERITED::releaseResources().
*/
void releaseResources();
@@ -345,25 +306,38 @@ public:
*/
void removeResource(GrResource* resource);
+ // GrDrawTarget overrides
+ virtual void clear(const GrIRect* rect, GrColor color);
+
+ // After the client interacts directly with the 3D context state the GrGpu
+ // must resync its internal state and assumptions about 3D context state.
+ // Each time this occurs the GrGpu bumps a timestamp.
+ // state of the 3D context
+ // At 10 resets / frame and 60fps a 64bit timestamp will overflow in about
+ // a billion years.
+ typedef uint64_t ResetTimestamp;
+
+ // This timestamp is always older than the current timestamp
+ static const ResetTimestamp kExpiredTimestamp = 0;
+ // Returns a timestamp based on the number of times the context was reset.
+ // This timestamp can be used to lazily detect when cached 3D context state
+ // is dirty.
+ ResetTimestamp getResetTimestamp() const {
+ return fResetTimestamp;
+ }
+
protected:
- enum PrivateStateBits {
- kFirstBit = (kLastPublicStateBit << 1),
+ enum PrivateDrawStateStateBits {
+ kFirstBit = (GrDrawState::kLastPublicStateBit << 1),
kModifyStencilClip_StateBit = kFirstBit, // allows draws to modify
// stencil bits used for
// clipping.
};
- /**
- * Extensions to GrDrawTarget::StateBits to implement stencil clipping
- */
- struct ClipState {
- bool fClipInStencil;
- bool fClipIsDirty;
- } fClipState;
-
- // GrDrawTarget override
- virtual void clipWillBeSet(const GrClip& newClip);
+ // keep track of whether we are using stencil clipping (as opposed to
+ // scissor).
+ bool fClipInStencil;
// prepares clip flushes gpu state before a draw
bool setupClipAndFlushState(GrPrimitiveType type);
@@ -381,64 +355,53 @@ protected:
// stencil settings to clip drawing when stencil clipping is in effect
// and the client isn't using the stencil test.
- static const GrStencilSettings gClipStencilSettings;
-
- // defaults to false, subclass can set true to support palleted textures
- bool f8bitPaletteSupport;
-
- // set by subclass
- bool fNPOTTextureSupport;
- bool fNPOTTextureTileSupport;
- bool fNPOTRenderTargetSupport;
- bool fTwoSidedStencilSupport;
- bool fStencilWrapOpsSupport;
- bool fAALineSupport;
- bool fFSAASupport;
- bool f4X4DownsampleFilterSupport; // supports GrSamplerState::k4x4Downsample_Filter
- bool fDualSourceBlendingSupport;
-
- // set by subclass to true if index and vertex buffers can be locked, false
- // otherwise.
- bool fBufferLockSupport;
-
- // set by subclass
- int fMinRenderTargetWidth;
- int fMinRenderTargetHeight;
- int fMaxTextureDimension;
+ static const GrStencilSettings& gClipStencilSettings;
GrGpuStats fStats;
- const GrVertexBuffer* fCurrPoolVertexBuffer;
- int fCurrPoolStartVertex;
-
- const GrIndexBuffer* fCurrPoolIndexBuffer;
- int fCurrPoolStartIndex;
+ struct GeometryPoolState {
+ const GrVertexBuffer* fPoolVertexBuffer;
+ int fPoolStartVertex;
+
+ const GrIndexBuffer* fPoolIndexBuffer;
+ int fPoolStartIndex;
+ };
+ const GeometryPoolState& getGeomPoolState() {
+ return fGeomPoolStateStack.back();
+ }
// GrDrawTarget overrides
- virtual bool onAcquireGeometry(GrVertexLayout vertexLayout,
- void** vertices,
- void** indices);
- virtual void onReleaseGeometry();
-
+ virtual bool onReserveVertexSpace(GrVertexLayout vertexLayout,
+ int vertexCount,
+ void** vertices);
+ virtual bool onReserveIndexSpace(int indexCount, void** indices);
+ virtual void releaseReservedVertexSpace();
+ virtual void releaseReservedIndexSpace();
virtual void onSetVertexSourceToArray(const void* vertexArray,
int vertexCount);
-
virtual void onSetIndexSourceToArray(const void* indexArray,
int indexCount);
+ virtual void releaseVertexArray();
+ virtual void releaseIndexArray();
+ virtual void geometrySourceWillPush();
+ virtual void geometrySourceWillPop(const GeometrySrcState& restoredState);
+
// Helpers for setting up geometry state
void finalizeReservedVertices();
void finalizeReservedIndices();
- // overridden by API-specific derived class to handle re-emitting 3D API
- // preample and dirtying state cache.
- virtual void resetContext() = 0;
+ // called when the 3D context state is unknown. Subclass should emit any
+ // assumed 3D context state and dirty any state cache
+ virtual void onResetContext() = 0;
+
// overridden by API-specific derived class to create objects.
virtual GrTexture* onCreateTexture(const GrTextureDesc& desc,
const void* srcData,
size_t rowBytes) = 0;
+ virtual GrTexture* onCreatePlatformTexture(const GrPlatformTextureDesc& desc) = 0;
+ virtual GrRenderTarget* onCreatePlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) = 0;
virtual GrResource* onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc) = 0;
- virtual GrRenderTarget* onCreateRenderTargetFrom3DApiState() = 0;
virtual GrVertexBuffer* onCreateVertexBuffer(uint32_t size,
bool dynamic) = 0;
virtual GrIndexBuffer* onCreateIndexBuffer(uint32_t size,
@@ -449,15 +412,15 @@ protected:
virtual void onClear(const GrIRect* rect, GrColor color) = 0;
// overridden by API-specific derived class to perform the draw call.
- virtual void onDrawIndexed(GrPrimitiveType type,
- uint32_t startVertex,
- uint32_t startIndex,
- uint32_t vertexCount,
- uint32_t indexCount) = 0;
-
- virtual void onDrawNonIndexed(GrPrimitiveType type,
+ virtual void onGpuDrawIndexed(GrPrimitiveType type,
+ uint32_t startVertex,
+ uint32_t startIndex,
uint32_t vertexCount,
- uint32_t numVertices) = 0;
+ uint32_t indexCount) = 0;
+
+ virtual void onGpuDrawNonIndexed(GrPrimitiveType type,
+ uint32_t vertexCount,
+ uint32_t numVertices) = 0;
// overridden by API-specific derived class to perform flush
virtual void onForceRenderTargetFlush() = 0;
@@ -465,7 +428,16 @@ protected:
// overridden by API-specific derived class to perform the read pixels.
virtual bool onReadPixels(GrRenderTarget* target,
int left, int top, int width, int height,
- GrPixelConfig, void* buffer) = 0;
+ GrPixelConfig,
+ void* buffer,
+ size_t rowBytes,
+ bool invertY) = 0;
+
+ // overridden by API-specific derived class to perform the texture update
+ virtual void onWriteTexturePixels(GrTexture* texture,
+ int left, int top, int width, int height,
+ GrPixelConfig config, const void* buffer,
+ size_t rowBytes) = 0;
// called to program the vertex data, indexCount will be 0 if drawing non-
// indexed geometry. The subclass may adjust the startVertex and/or
@@ -475,6 +447,16 @@ protected:
int vertexCount,
int indexCount) = 0;
+ // width and height may be larger than rt (if underlying API allows it).
+ // Should attach the SB to the RT. Returns false if compatible sb could
+ // not be created.
+ virtual bool createStencilBufferForRenderTarget(GrRenderTarget* rt,
+ int width,
+ int height) = 0;
+
+ // attaches an existing SB to an existing RT.
+ virtual bool attachStencilBufferToRenderTarget(GrStencilBuffer* sb,
+ GrRenderTarget* rt) = 0;
// The GrGpu typically records the clients requested state and then flushes
// deltas from previous state at draw time. This function does the
@@ -485,35 +467,60 @@ protected:
// Sets the scissor rect, or disables if rect is NULL.
virtual void flushScissor(const GrIRect* rect) = 0;
- // GrGpu subclass removes the clip from the stencil buffer
- virtual void clearStencilClip(const GrIRect& rect) = 0;
+ // GrGpu subclass sets clip bit in the stencil buffer. The subclass is
+ // free to clear the remaining bits to zero if masked clears are more
+ // expensive than clearing all bits.
+ virtual void clearStencilClip(const GrIRect& rect, bool insideClip) = 0;
+
+ // clears the entire stencil buffer to 0
+ virtual void clearStencil() = 0;
private:
GrContext* fContext; // not reffed (context refs gpu)
+
+ ResetTimestamp fResetTimestamp;
GrVertexBufferAllocPool* fVertexPool;
GrIndexBufferAllocPool* fIndexPool;
-
+
+ // counts number of uses of vertex/index pool in the geometry stack
+ int fVertexPoolUseCnt;
+ int fIndexPoolUseCnt;
+
+ enum {
+ kPreallocGeomPoolStateStackCnt = 4,
+ };
+ SkSTArray<kPreallocGeomPoolStateStackCnt,
+ GeometryPoolState, true> fGeomPoolStateStack;
+
mutable GrIndexBuffer* fQuadIndexBuffer; // mutable so it can be
// created on-demand
mutable GrVertexBuffer* fUnitSquareVertexBuffer; // mutable so it can be
// created on-demand
- GrDefaultPathRenderer* fDefaultPathRenderer;
- GrPathRenderer* fClientPathRenderer;
+ // must be instantiated after GrGpu object has been given its owning
+ // GrContext ptr. (GrGpu is constructed first then handed off to GrContext).
+ GrPathRendererChain* fPathRendererChain;
bool fContextIsDirty;
- // when in an internal draw these indicate whether the pools are in use
- // by one of the outer draws. If false then it is safe to reset the
- // pool.
- bool fVertexPoolInUse;
- bool fIndexPoolInUse;
-
GrResource* fResourceHead;
+ // Given a rt, find or create a stencil buffer and attach it
+ bool attachStencilBufferToRenderTarget(GrRenderTarget* target);
+
+ // GrDrawTarget overrides
+ virtual void onDrawIndexed(GrPrimitiveType type,
+ int startVertex,
+ int startIndex,
+ int vertexCount,
+ int indexCount);
+ virtual void onDrawNonIndexed(GrPrimitiveType type,
+ int startVertex,
+ int vertexCount);
+
// readies the pools to provide vertex/index data.
void prepareVertexPool();
void prepareIndexPool();
@@ -521,6 +528,11 @@ private:
// determines the path renderer used to draw a clip path element.
GrPathRenderer* getClipPathRenderer(const SkPath& path, GrPathFill fill);
+ void resetContext() {
+ this->onResetContext();
+ ++fResetTimestamp;
+ }
+
void handleDirtyContext() {
if (fContextIsDirty) {
this->resetContext();
@@ -528,52 +540,6 @@ private:
}
}
- // used to save and restore state when the GrGpu needs
- // to make its geometry pools available internally
- class AutoInternalDrawGeomRestore {
- public:
- AutoInternalDrawGeomRestore(GrGpu* gpu) : fAgsr(gpu) {
- fGpu = gpu;
-
- fVertexPoolWasInUse = gpu->fVertexPoolInUse;
- fIndexPoolWasInUse = gpu->fIndexPoolInUse;
-
- gpu->fVertexPoolInUse = fVertexPoolWasInUse ||
- (kBuffer_GeometrySrcType !=
- gpu->fGeometrySrc.fVertexSrc);
- gpu->fIndexPoolInUse = fIndexPoolWasInUse ||
- (kBuffer_GeometrySrcType !=
- gpu->fGeometrySrc.fIndexSrc);;
-
- fSavedPoolVertexBuffer = gpu->fCurrPoolVertexBuffer;
- fSavedPoolStartVertex = gpu->fCurrPoolStartVertex;
- fSavedPoolIndexBuffer = gpu->fCurrPoolIndexBuffer;
- fSavedPoolStartIndex = gpu->fCurrPoolStartIndex;
-
- fSavedReservedGeometry = gpu->fReservedGeometry;
- gpu->fReservedGeometry.fLocked = false;
- }
- ~AutoInternalDrawGeomRestore() {
- fGpu->fCurrPoolVertexBuffer = fSavedPoolVertexBuffer;
- fGpu->fCurrPoolStartVertex = fSavedPoolStartVertex;
- fGpu->fCurrPoolIndexBuffer = fSavedPoolIndexBuffer;
- fGpu->fCurrPoolStartIndex = fSavedPoolStartIndex;
- fGpu->fVertexPoolInUse = fVertexPoolWasInUse;
- fGpu->fIndexPoolInUse = fIndexPoolWasInUse;
- fGpu->fReservedGeometry = fSavedReservedGeometry;
- }
- private:
- AutoGeometrySrcRestore fAgsr;
- GrGpu* fGpu;
- const GrVertexBuffer* fSavedPoolVertexBuffer;
- int fSavedPoolStartVertex;
- const GrIndexBuffer* fSavedPoolIndexBuffer;
- int fSavedPoolStartIndex;
- bool fVertexPoolWasInUse;
- bool fIndexPoolWasInUse;
- ReservedGeometry fSavedReservedGeometry;
- };
-
typedef GrDrawTarget INHERITED;
};
diff --git a/src/gpu/GrGpuFactory.cpp b/src/gpu/GrGpuFactory.cpp
new file mode 100644
index 0000000..c954c7a
--- /dev/null
+++ b/src/gpu/GrGpuFactory.cpp
@@ -0,0 +1,53 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrTypes.h"
+
+// must be before GrGLConfig.h
+#if GR_WIN32_BUILD
+// #include "GrGpuD3D9.h"
+#endif
+
+#include "GrGLConfig.h"
+
+#include "GrGpu.h"
+#include "GrGpuGLShaders.h"
+
+GrGpu* GrGpu::Create(GrEngine engine, GrPlatform3DContext context3D) {
+
+ const GrGLInterface* glInterface = NULL;
+ SkAutoTUnref<const GrGLInterface> glInterfaceUnref;
+
+ if (kOpenGL_Shaders_GrEngine == engine) {
+ glInterface = reinterpret_cast<const GrGLInterface*>(context3D);
+ if (NULL == glInterface) {
+ glInterface = GrGLDefaultInterface();
+ // By calling GrGLDefaultInterface we've taken a ref on the
+ // returned object. We only want to hold that ref until after
+ // the GrGpu is constructed and has taken ownership.
+ glInterfaceUnref.reset(glInterface);
+ }
+ if (NULL == glInterface) {
+#if GR_DEBUG
+ GrPrintf("No GL interface provided!\n");
+#endif
+ return NULL;
+ }
+ if (!glInterface->validate()) {
+#if GR_DEBUG
+ GrPrintf("Failed GL interface validation!\n");
+#endif
+ return NULL;
+ }
+
+ return new GrGpuGLShaders(glInterface);
+ } else {
+ return NULL;
+ }
+}
diff --git a/src/gpu/GrGpuGL.cpp b/src/gpu/GrGpuGL.cpp
new file mode 100644
index 0000000..d0fb12f
--- /dev/null
+++ b/src/gpu/GrGpuGL.cpp
@@ -0,0 +1,2540 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrGpuGL.h"
+#include "GrGLStencilBuffer.h"
+#include "GrTypes.h"
+#include "SkTemplates.h"
+
+static const GrGLuint GR_MAX_GLUINT = ~0;
+static const GrGLint GR_INVAL_GLINT = ~0;
+
+#define GL_CALL(X) GR_GL_CALL(this->glInterface(), X)
+#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->glInterface(), RET, X)
+
+// we use a spare texture unit to avoid
+// mucking with the state of any of the stages.
+static const int SPARE_TEX_UNIT = GrDrawState::kNumStages;
+
+#define SKIP_CACHE_CHECK true
+
+static const GrGLenum gXfermodeCoeff2Blend[] = {
+ GR_GL_ZERO,
+ GR_GL_ONE,
+ GR_GL_SRC_COLOR,
+ GR_GL_ONE_MINUS_SRC_COLOR,
+ GR_GL_DST_COLOR,
+ GR_GL_ONE_MINUS_DST_COLOR,
+ GR_GL_SRC_ALPHA,
+ GR_GL_ONE_MINUS_SRC_ALPHA,
+ GR_GL_DST_ALPHA,
+ GR_GL_ONE_MINUS_DST_ALPHA,
+ GR_GL_CONSTANT_COLOR,
+ GR_GL_ONE_MINUS_CONSTANT_COLOR,
+ GR_GL_CONSTANT_ALPHA,
+ GR_GL_ONE_MINUS_CONSTANT_ALPHA,
+
+ // extended blend coeffs
+ GR_GL_SRC1_COLOR,
+ GR_GL_ONE_MINUS_SRC1_COLOR,
+ GR_GL_SRC1_ALPHA,
+ GR_GL_ONE_MINUS_SRC1_ALPHA,
+};
+
+bool GrGpuGL::BlendCoeffReferencesConstant(GrBlendCoeff coeff) {
+ static const bool gCoeffReferencesBlendConst[] = {
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true,
+ true,
+ true,
+ true,
+
+ // extended blend coeffs
+ false,
+ false,
+ false,
+ false,
+ };
+ return gCoeffReferencesBlendConst[coeff];
+ GR_STATIC_ASSERT(kTotalBlendCoeffCount == GR_ARRAY_COUNT(gCoeffReferencesBlendConst));
+
+ GR_STATIC_ASSERT(0 == kZero_BlendCoeff);
+ GR_STATIC_ASSERT(1 == kOne_BlendCoeff);
+ GR_STATIC_ASSERT(2 == kSC_BlendCoeff);
+ GR_STATIC_ASSERT(3 == kISC_BlendCoeff);
+ GR_STATIC_ASSERT(4 == kDC_BlendCoeff);
+ GR_STATIC_ASSERT(5 == kIDC_BlendCoeff);
+ GR_STATIC_ASSERT(6 == kSA_BlendCoeff);
+ GR_STATIC_ASSERT(7 == kISA_BlendCoeff);
+ GR_STATIC_ASSERT(8 == kDA_BlendCoeff);
+ GR_STATIC_ASSERT(9 == kIDA_BlendCoeff);
+ GR_STATIC_ASSERT(10 == kConstC_BlendCoeff);
+ GR_STATIC_ASSERT(11 == kIConstC_BlendCoeff);
+ GR_STATIC_ASSERT(12 == kConstA_BlendCoeff);
+ GR_STATIC_ASSERT(13 == kIConstA_BlendCoeff);
+
+ GR_STATIC_ASSERT(14 == kS2C_BlendCoeff);
+ GR_STATIC_ASSERT(15 == kIS2C_BlendCoeff);
+ GR_STATIC_ASSERT(16 == kS2A_BlendCoeff);
+ GR_STATIC_ASSERT(17 == kIS2A_BlendCoeff);
+
+ // assertion for gXfermodeCoeff2Blend have to be in GrGpu scope
+ GR_STATIC_ASSERT(kTotalBlendCoeffCount == GR_ARRAY_COUNT(gXfermodeCoeff2Blend));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GrGpuGL::AdjustTextureMatrix(const GrGLTexture* texture,
+ GrSamplerState::SampleMode mode,
+ GrMatrix* matrix) {
+ GrAssert(NULL != texture);
+ GrAssert(NULL != matrix);
+ GrGLTexture::Orientation orientation = texture->orientation();
+ if (GrGLTexture::kBottomUp_Orientation == orientation) {
+ GrMatrix invY;
+ invY.setAll(GR_Scalar1, 0, 0,
+ 0, -GR_Scalar1, GR_Scalar1,
+ 0, 0, GrMatrix::I()[8]);
+ matrix->postConcat(invY);
+ } else {
+ GrAssert(GrGLTexture::kTopDown_Orientation == orientation);
+ }
+}
+
+bool GrGpuGL::TextureMatrixIsIdentity(const GrGLTexture* texture,
+ const GrSamplerState& sampler) {
+ GrAssert(NULL != texture);
+ if (!sampler.getMatrix().isIdentity()) {
+ return false;
+ }
+ GrGLTexture::Orientation orientation = texture->orientation();
+ if (GrGLTexture::kBottomUp_Orientation == orientation) {
+ return false;
+ } else {
+ GrAssert(GrGLTexture::kTopDown_Orientation == orientation);
+ }
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static bool gPrintStartupSpew;
+
+static bool fbo_test(const GrGLInterface* gl, int w, int h) {
+
+ GR_GL_CALL(gl, ActiveTexture(GR_GL_TEXTURE0 + SPARE_TEX_UNIT));
+
+ GrGLuint testFBO;
+ GR_GL_CALL(gl, GenFramebuffers(1, &testFBO));
+ GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, testFBO));
+ GrGLuint testRTTex;
+ GR_GL_CALL(gl, GenTextures(1, &testRTTex));
+ GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, testRTTex));
+ // some implementations require texture to be mip-map complete before
+ // FBO with level 0 bound as color attachment will be framebuffer complete.
+ GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D,
+ GR_GL_TEXTURE_MIN_FILTER,
+ GR_GL_NEAREST));
+ GR_GL_CALL(gl, TexImage2D(GR_GL_TEXTURE_2D, 0, GR_GL_RGBA, w, h,
+ 0, GR_GL_RGBA, GR_GL_UNSIGNED_BYTE, NULL));
+ GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, 0));
+ GR_GL_CALL(gl, FramebufferTexture2D(GR_GL_FRAMEBUFFER,
+ GR_GL_COLOR_ATTACHMENT0,
+ GR_GL_TEXTURE_2D, testRTTex, 0));
+ GrGLenum status;
+ GR_GL_CALL_RET(gl, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
+ GR_GL_CALL(gl, DeleteFramebuffers(1, &testFBO));
+ GR_GL_CALL(gl, DeleteTextures(1, &testRTTex));
+
+ return status == GR_GL_FRAMEBUFFER_COMPLETE;
+}
+
+GrGpuGL::GrGpuGL(const GrGLInterface* gl, GrGLBinding glBinding) {
+
+ fPrintedCaps = false;
+
+ gl->ref();
+ fGL = gl;
+ fGLBinding = glBinding;
+ switch (glBinding) {
+ case kDesktop_GrGLBinding:
+ GrAssert(gl->supportsDesktop());
+ break;
+ case kES2_GrGLBinding:
+ GrAssert(gl->supportsES2());
+ break;
+ default:
+ GrCrash("Expect exactly one valid GL binding bit to be in use.");
+ }
+
+ GrGLClearErr(fGL);
+
+ const GrGLubyte* ext;
+ GL_CALL_RET(ext, GetString(GR_GL_EXTENSIONS));
+ if (gPrintStartupSpew) {
+ const GrGLubyte* vendor;
+ const GrGLubyte* renderer;
+ const GrGLubyte* version;
+ GL_CALL_RET(vendor, GetString(GR_GL_VENDOR));
+ GL_CALL_RET(renderer, GetString(GR_GL_RENDERER));
+ GL_CALL_RET(version, GetString(GR_GL_VERSION));
+ GrPrintf("------------------------- create GrGpuGL %p --------------\n",
+ this);
+ GrPrintf("------ VENDOR %s\n", vendor);
+ GrPrintf("------ RENDERER %s\n", renderer);
+ GrPrintf("------ VERSION %s\n", version);
+ GrPrintf("------ EXTENSIONS\n %s \n", ext);
+ }
+
+ fGLVersion = GrGLGetVersion(gl);
+ GrAssert(0 != fGLVersion);
+ fExtensionString = (const char*) ext;
+
+ this->resetDirtyFlags();
+
+ this->initCaps();
+
+ fLastSuccessfulStencilFmtIdx = 0;
+}
+
+GrGpuGL::~GrGpuGL() {
+ // This must be called by before the GrDrawTarget destructor
+ this->releaseGeometry();
+ // This subclass must do this before the base class destructor runs
+ // since we will unref the GrGLInterface.
+ this->releaseResources();
+ fGL->unref();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static const GrGLuint kUnknownBitCount = ~0;
+
+void GrGpuGL::initCaps() {
+ GrGLint maxTextureUnits;
+ // check FS and fixed-function texture unit limits
+ // we only use textures in the fragment stage currently.
+ // checks are > to make sure we have a spare unit.
+ GR_GL_GetIntegerv(fGL, GR_GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
+ GrAssert(maxTextureUnits > GrDrawState::kNumStages);
+ if (kES2_GrGLBinding != this->glBinding()) {
+ GR_GL_GetIntegerv(fGL, GR_GL_MAX_TEXTURE_UNITS, &maxTextureUnits);
+ GrAssert(maxTextureUnits > GrDrawState::kNumStages);
+ }
+ if (kES2_GrGLBinding == this->glBinding()) {
+ GR_GL_GetIntegerv(fGL, GR_GL_MAX_FRAGMENT_UNIFORM_VECTORS,
+ &fGLCaps.fMaxFragmentUniformVectors);
+ } else if (kDesktop_GrGLBinding != this->glBinding()) {
+ GrGLint max;
+ GR_GL_GetIntegerv(fGL, GR_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &max);
+ fGLCaps.fMaxFragmentUniformVectors = max / 4;
+ } else {
+ fGLCaps.fMaxFragmentUniformVectors = 16;
+ }
+
+ GrGLint numFormats;
+ GR_GL_GetIntegerv(fGL, GR_GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numFormats);
+ SkAutoSTMalloc<10, GrGLint> formats(numFormats);
+ GR_GL_GetIntegerv(fGL, GR_GL_COMPRESSED_TEXTURE_FORMATS, formats);
+ for (int i = 0; i < numFormats; ++i) {
+ if (formats[i] == GR_GL_PALETTE8_RGBA8) {
+ fCaps.f8BitPaletteSupport = true;
+ break;
+ }
+ }
+
+ if (kDesktop_GrGLBinding == this->glBinding()) {
+ // we could also look for GL_ATI_separate_stencil extension or
+ // GL_EXT_stencil_two_side but they use different function signatures
+ // than GL2.0+ (and than each other).
+ fCaps.fTwoSidedStencilSupport = (fGLVersion >= GR_GL_VER(2,0));
+ // supported on GL 1.4 and higher or by extension
+ fCaps.fStencilWrapOpsSupport = (fGLVersion >= GR_GL_VER(1,4)) ||
+ this->hasExtension("GL_EXT_stencil_wrap");
+ } else {
+ // ES 2 has two sided stencil and stencil wrap
+ fCaps.fTwoSidedStencilSupport = true;
+ fCaps.fStencilWrapOpsSupport = true;
+ }
+
+ if (kDesktop_GrGLBinding == this->glBinding()) {
+ fGLCaps.fRGBA8RenderbufferSupport = true;
+ } else {
+ fGLCaps.fRGBA8RenderbufferSupport =
+ this->hasExtension("GL_OES_rgb8_rgba8") ||
+ this->hasExtension("GL_ARM_rgba8");
+ }
+
+
+ if (kDesktop_GrGLBinding == this->glBinding()) {
+ fGLCaps.fBGRAFormatSupport = this->glVersion() >= GR_GL_VER(1,2) ||
+ this->hasExtension("GL_EXT_bgra");
+ } else {
+ bool hasBGRAExt = false;
+ if (this->hasExtension("GL_APPLE_texture_format_BGRA8888")) {
+ fGLCaps.fBGRAFormatSupport = true;
+ } else if (this->hasExtension("GL_EXT_texture_format_BGRA8888")) {
+ fGLCaps.fBGRAFormatSupport = true;
+ fGLCaps.fBGRAIsInternalFormat = true;
+ }
+ GrAssert(fGLCaps.fBGRAFormatSupport ||
+ kSkia8888_PM_GrPixelConfig != kBGRA_8888_PM_GrPixelConfig);
+ }
+
+ if (kDesktop_GrGLBinding == this->glBinding()) {
+ fGLCaps.fTextureSwizzleSupport = this->glVersion() >= GR_GL_VER(3,3) ||
+ this->hasExtension("GL_ARB_texture_swizzle");
+ } else {
+ fGLCaps.fTextureSwizzleSupport = false;
+ }
+
+ if (kDesktop_GrGLBinding == this->glBinding()) {
+ fGLCaps.fUnpackRowLengthSupport = true;
+ fGLCaps.fUnpackFlipYSupport = false;
+ fGLCaps.fPackRowLengthSupport = true;
+ fGLCaps.fPackFlipYSupport = false;
+ } else {
+ fGLCaps.fUnpackRowLengthSupport =this->hasExtension("GL_EXT_unpack_subimage");
+ fGLCaps.fUnpackFlipYSupport = this->hasExtension("GL_CHROMIUM_flipy");
+ // no extension for pack row length
+ fGLCaps.fPackRowLengthSupport = false;
+ fGLCaps.fPackFlipYSupport =
+ this->hasExtension("GL_ANGLE_pack_reverse_row_order");
+ }
+
+ if (kDesktop_GrGLBinding == this->glBinding()) {
+ fCaps.fBufferLockSupport = true; // we require VBO support and the desktop VBO
+ // extension includes glMapBuffer.
+ } else {
+ fCaps.fBufferLockSupport = this->hasExtension("GL_OES_mapbuffer");
+ }
+
+ if (kDesktop_GrGLBinding == this->glBinding()) {
+ if (fGLVersion >= GR_GL_VER(2,0) ||
+ this->hasExtension("GL_ARB_texture_non_power_of_two")) {
+ fCaps.fNPOTTextureTileSupport = true;
+ } else {
+ fCaps.fNPOTTextureTileSupport = false;
+ }
+ } else {
+ // Unextended ES2 supports NPOT textures with clamp_to_edge and non-mip filters only
+ fCaps.fNPOTTextureTileSupport = this->hasExtension("GL_OES_texture_npot");
+ }
+
+ fGLCaps.fTextureUsageSupport = (kES2_GrGLBinding == this->glBinding()) &&
+ this->hasExtension("GL_ANGLE_texture_usage");
+
+ // Tex storage is in desktop 4.2 and can be an extension to desktop or ES.
+ fGLCaps.fTexStorageSupport = (kDesktop_GrGLBinding == this->glBinding() &&
+ fGLVersion >= GR_GL_VER(4,2)) ||
+ this->hasExtension("GL_ARB_texture_storage") ||
+ this->hasExtension("GL_EXT_texture_storage");
+
+ fCaps.fHWAALineSupport = (kDesktop_GrGLBinding == this->glBinding());
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Experiments to determine limitations that can't be queried.
+ // TODO: Make these a preprocess that generate some compile time constants.
+ // TODO: probe once at startup, rather than once per context creation.
+
+ GR_GL_GetIntegerv(fGL, GR_GL_MAX_TEXTURE_SIZE, &fCaps.fMaxTextureSize);
+ GR_GL_GetIntegerv(fGL, GR_GL_MAX_RENDERBUFFER_SIZE, &fCaps.fMaxRenderTargetSize);
+ // Our render targets are always created with textures as the color
+ // attachment, hence this min:
+ fCaps.fMaxRenderTargetSize = GrMin(fCaps.fMaxTextureSize, fCaps.fMaxRenderTargetSize);
+
+ this->initFSAASupport();
+ this->initStencilFormats();
+}
+
+void GrGpuGL::initFSAASupport() {
+ // TODO: Get rid of GrAALevel and use # samples directly.
+ GR_STATIC_ASSERT(0 == kNone_GrAALevel);
+ GR_STATIC_ASSERT(1 == kLow_GrAALevel);
+ GR_STATIC_ASSERT(2 == kMed_GrAALevel);
+ GR_STATIC_ASSERT(3 == kHigh_GrAALevel);
+ memset(fGLCaps.fAASamples, 0, sizeof(fGLCaps.fAASamples));
+
+ fGLCaps.fMSFBOType = GLCaps::kNone_MSFBO;
+ if (kDesktop_GrGLBinding != this->glBinding()) {
+ if (this->hasExtension("GL_CHROMIUM_framebuffer_multisample")) {
+ // chrome's extension is equivalent to the EXT msaa
+ // and fbo_blit extensions.
+ fGLCaps.fMSFBOType = GLCaps::kDesktopEXT_MSFBO;
+ } else if (this->hasExtension("GL_APPLE_framebuffer_multisample")) {
+ fGLCaps.fMSFBOType = GLCaps::kAppleES_MSFBO;
+ }
+ } else {
+ if ((fGLVersion >= GR_GL_VER(3,0)) || this->hasExtension("GL_ARB_framebuffer_object")) {
+ fGLCaps.fMSFBOType = GLCaps::kDesktopARB_MSFBO;
+ } else if (this->hasExtension("GL_EXT_framebuffer_multisample") &&
+ this->hasExtension("GL_EXT_framebuffer_blit")) {
+ fGLCaps.fMSFBOType = GLCaps::kDesktopEXT_MSFBO;
+ }
+ }
+
+ if (GLCaps::kNone_MSFBO != fGLCaps.fMSFBOType) {
+ GrGLint maxSamples;
+ GR_GL_GetIntegerv(fGL, GR_GL_MAX_SAMPLES, &maxSamples);
+ if (maxSamples > 1 ) {
+ fGLCaps.fAASamples[kNone_GrAALevel] = 0;
+ fGLCaps.fAASamples[kLow_GrAALevel] =
+ GrMax(2, GrFixedFloorToInt((GR_FixedHalf) * maxSamples));
+ fGLCaps.fAASamples[kMed_GrAALevel] =
+ GrMax(2, GrFixedFloorToInt(((GR_Fixed1*3)/4) * maxSamples));
+ fGLCaps.fAASamples[kHigh_GrAALevel] = maxSamples;
+ }
+ }
+ fCaps.fFSAASupport = fGLCaps.fAASamples[kHigh_GrAALevel] > 0;
+}
+
+void GrGpuGL::initStencilFormats() {
+
+ // Build up list of legal stencil formats (though perhaps not supported on
+ // the particular gpu/driver) from most preferred to least.
+
+ // these consts are in order of most preferred to least preferred
+ // we don't bother with GL_STENCIL_INDEX1 or GL_DEPTH32F_STENCIL8
+ static const GrGLStencilBuffer::Format
+ // internal Format stencil bits total bits packed?
+ gS8 = {GR_GL_STENCIL_INDEX8, 8, 8, false},
+ gS16 = {GR_GL_STENCIL_INDEX16, 16, 16, false},
+ gD24S8 = {GR_GL_DEPTH24_STENCIL8, 8, 32, true },
+ gS4 = {GR_GL_STENCIL_INDEX4, 4, 4, false},
+ gS = {GR_GL_STENCIL_INDEX, kUnknownBitCount, kUnknownBitCount, false},
+ gDS = {GR_GL_DEPTH_STENCIL, kUnknownBitCount, kUnknownBitCount, true };
+
+ if (kDesktop_GrGLBinding == this->glBinding()) {
+ bool supportsPackedDS = fGLVersion >= GR_GL_VER(3,0) ||
+ this->hasExtension("GL_EXT_packed_depth_stencil") ||
+ this->hasExtension("GL_ARB_framebuffer_object");
+
+ // S1 thru S16 formats are in GL 3.0+, EXT_FBO, and ARB_FBO since we
+ // require FBO support we can expect these are legal formats and don't
+ // check. These also all support the unsized GL_STENCIL_INDEX.
+ fGLCaps.fStencilFormats.push_back() = gS8;
+ fGLCaps.fStencilFormats.push_back() = gS16;
+ if (supportsPackedDS) {
+ fGLCaps.fStencilFormats.push_back() = gD24S8;
+ }
+ fGLCaps.fStencilFormats.push_back() = gS4;
+ if (supportsPackedDS) {
+ fGLCaps.fStencilFormats.push_back() = gDS;
+ }
+ } else {
+ // ES2 has STENCIL_INDEX8 without extensions but requires extensions
+ // for other formats.
+ // ES doesn't support using the unsized format.
+
+ fGLCaps.fStencilFormats.push_back() = gS8;
+ //fStencilFormats.push_back() = gS16;
+ if (this->hasExtension("GL_OES_packed_depth_stencil")) {
+ fGLCaps.fStencilFormats.push_back() = gD24S8;
+ }
+ if (this->hasExtension("GL_OES_stencil4")) {
+ fGLCaps.fStencilFormats.push_back() = gS4;
+ }
+ }
+}
+
+GrPixelConfig GrGpuGL::preferredReadPixelsConfig(GrPixelConfig config) const {
+ if (GR_GL_RGBA_8888_PIXEL_OPS_SLOW && GrPixelConfigIsRGBA8888(config)) {
+ return GrPixelConfigSwapRAndB(config);
+ } else {
+ return config;
+ }
+}
+
+GrPixelConfig GrGpuGL::preferredWritePixelsConfig(GrPixelConfig config) const {
+ if (GR_GL_RGBA_8888_PIXEL_OPS_SLOW && GrPixelConfigIsRGBA8888(config)) {
+ return GrPixelConfigSwapRAndB(config);
+ } else {
+ return config;
+ }
+}
+
+bool GrGpuGL::fullReadPixelsIsFasterThanPartial() const {
+ return SkToBool(GR_GL_FULL_READPIXELS_FASTER_THAN_PARTIAL);
+}
+
+void GrGpuGL::onResetContext() {
+ if (gPrintStartupSpew && !fPrintedCaps) {
+ fPrintedCaps = true;
+ this->getCaps().print();
+ fGLCaps.print();
+ }
+
+ // We detect cases when blending is effectively off
+ fHWBlendDisabled = false;
+ GL_CALL(Enable(GR_GL_BLEND));
+
+ // we don't use the zb at all
+ GL_CALL(Disable(GR_GL_DEPTH_TEST));
+ GL_CALL(DepthMask(GR_GL_FALSE));
+
+ GL_CALL(Disable(GR_GL_CULL_FACE));
+ GL_CALL(FrontFace(GR_GL_CCW));
+ fHWDrawState.setDrawFace(GrDrawState::kBoth_DrawFace);
+
+ GL_CALL(Disable(GR_GL_DITHER));
+ if (kDesktop_GrGLBinding == this->glBinding()) {
+ GL_CALL(Disable(GR_GL_LINE_SMOOTH));
+ GL_CALL(Disable(GR_GL_POINT_SMOOTH));
+ GL_CALL(Disable(GR_GL_MULTISAMPLE));
+ fHWAAState.fMSAAEnabled = false;
+ fHWAAState.fSmoothLineEnabled = false;
+ }
+
+ GL_CALL(ColorMask(GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE));
+ fHWDrawState.resetStateFlags();
+
+ // we only ever use lines in hairline mode
+ GL_CALL(LineWidth(1));
+
+ // invalid
+ fActiveTextureUnitIdx = -1;
+
+ // illegal values
+ fHWDrawState.setBlendFunc((GrBlendCoeff)0xFF, (GrBlendCoeff)0xFF);
+
+ fHWDrawState.setBlendConstant(0x00000000);
+ GL_CALL(BlendColor(0,0,0,0));
+
+ fHWDrawState.setColor(GrColor_ILLEGAL);
+
+ fHWDrawState.setViewMatrix(GrMatrix::InvalidMatrix());
+
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ fHWDrawState.setTexture(s, NULL);
+ fHWDrawState.sampler(s)->setRadial2Params(-GR_ScalarMax,
+ -GR_ScalarMax,
+ true);
+ *fHWDrawState.sampler(s)->matrix() = GrMatrix::InvalidMatrix();
+ fHWDrawState.sampler(s)->setConvolutionParams(0, NULL, NULL);
+ }
+
+ fHWBounds.fScissorRect.invalidate();
+ fHWBounds.fScissorEnabled = false;
+ GL_CALL(Disable(GR_GL_SCISSOR_TEST));
+ fHWBounds.fViewportRect.invalidate();
+
+ fHWDrawState.stencil()->invalidate();
+ fHWStencilClip = false;
+ fClipInStencil = false;
+
+ fHWGeometryState.fIndexBuffer = NULL;
+ fHWGeometryState.fVertexBuffer = NULL;
+
+ fHWGeometryState.fArrayPtrsDirty = true;
+
+ GL_CALL(ColorMask(GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE));
+ fHWDrawState.setRenderTarget(NULL);
+
+ // we assume these values
+ if (this->glCaps().fUnpackRowLengthSupport) {
+ GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
+ }
+ if (this->glCaps().fPackRowLengthSupport) {
+ GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, 0));
+ }
+ if (this->glCaps().fUnpackFlipYSupport) {
+ GL_CALL(PixelStorei(GR_GL_UNPACK_FLIP_Y, GR_GL_FALSE));
+ }
+ if (this->glCaps().fPackFlipYSupport) {
+ GL_CALL(PixelStorei(GR_GL_PACK_REVERSE_ROW_ORDER, GR_GL_FALSE));
+ }
+}
+
+GrTexture* GrGpuGL::onCreatePlatformTexture(const GrPlatformTextureDesc& desc) {
+ GrGLTexture::Desc glTexDesc;
+ if (!configToGLFormats(desc.fConfig, false, NULL, NULL, NULL)) {
+ return NULL;
+ }
+
+ glTexDesc.fWidth = desc.fWidth;
+ glTexDesc.fHeight = desc.fHeight;
+ glTexDesc.fConfig = desc.fConfig;
+ glTexDesc.fTextureID = static_cast<GrGLuint>(desc.fTextureHandle);
+ glTexDesc.fOwnsID = false;
+ glTexDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
+
+ GrGLTexture* texture = NULL;
+ if (desc.fFlags & kRenderTarget_GrPlatformTextureFlag) {
+ GrGLRenderTarget::Desc glRTDesc;
+ glRTDesc.fRTFBOID = 0;
+ glRTDesc.fTexFBOID = 0;
+ glRTDesc.fMSColorRenderbufferID = 0;
+ glRTDesc.fOwnIDs = true;
+ glRTDesc.fConfig = desc.fConfig;
+ glRTDesc.fSampleCnt = desc.fSampleCnt;
+ if (!this->createRenderTargetObjects(glTexDesc.fWidth,
+ glTexDesc.fHeight,
+ glTexDesc.fTextureID,
+ &glRTDesc)) {
+ return NULL;
+ }
+ texture = new GrGLTexture(this, glTexDesc, glRTDesc);
+ } else {
+ texture = new GrGLTexture(this, glTexDesc);
+ }
+ if (NULL == texture) {
+ return NULL;
+ }
+
+ this->setSpareTextureUnit();
+ return texture;
+}
+
+GrRenderTarget* GrGpuGL::onCreatePlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
+ GrGLRenderTarget::Desc glDesc;
+ glDesc.fConfig = desc.fConfig;
+ glDesc.fRTFBOID = static_cast<GrGLuint>(desc.fRenderTargetHandle);
+ glDesc.fMSColorRenderbufferID = 0;
+ glDesc.fTexFBOID = GrGLRenderTarget::kUnresolvableFBOID;
+ glDesc.fSampleCnt = desc.fSampleCnt;
+ glDesc.fOwnIDs = false;
+ GrGLIRect viewport;
+ viewport.fLeft = 0;
+ viewport.fBottom = 0;
+ viewport.fWidth = desc.fWidth;
+ viewport.fHeight = desc.fHeight;
+
+ GrRenderTarget* tgt = new GrGLRenderTarget(this, glDesc, viewport);
+ if (desc.fStencilBits) {
+ GrGLStencilBuffer::Format format;
+ format.fInternalFormat = GrGLStencilBuffer::kUnknownInternalFormat;
+ format.fPacked = false;
+ format.fStencilBits = desc.fStencilBits;
+ format.fTotalBits = desc.fStencilBits;
+ GrGLStencilBuffer* sb = new GrGLStencilBuffer(this,
+ 0,
+ desc.fWidth,
+ desc.fHeight,
+ desc.fSampleCnt,
+ format);
+ tgt->setStencilBuffer(sb);
+ sb->unref();
+ }
+ return tgt;
+}
+
+GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc) {
+
+ bool isTexture = kTexture_GrPlatformSurfaceType == desc.fSurfaceType ||
+ kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType;
+ bool isRenderTarget = kRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType ||
+ kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType;
+
+ GrGLRenderTarget::Desc rtDesc;
+ SkAutoTUnref<GrGLStencilBuffer> sb;
+
+ if (isRenderTarget) {
+ rtDesc.fRTFBOID = desc.fPlatformRenderTarget;
+ rtDesc.fConfig = desc.fConfig;
+ if (desc.fSampleCnt) {
+ if (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) {
+ rtDesc.fTexFBOID = desc.fPlatformResolveDestination;
+ } else {
+ GrAssert(!isTexture); // this should have been filtered by GrContext
+ rtDesc.fTexFBOID = GrGLRenderTarget::kUnresolvableFBOID;
+ }
+ } else {
+ rtDesc.fTexFBOID = desc.fPlatformRenderTarget;
+ }
+ // we don't know what the RB ids are without glGets and we don't care
+ // since we aren't responsible for deleting them.
+ rtDesc.fMSColorRenderbufferID = 0;
+ rtDesc.fSampleCnt = desc.fSampleCnt;
+ if (desc.fStencilBits) {
+ GrGLStencilBuffer::Format format;
+ format.fInternalFormat = GrGLStencilBuffer::kUnknownInternalFormat;
+ format.fPacked = false;
+ format.fStencilBits = desc.fStencilBits;
+ format.fTotalBits = desc.fStencilBits;
+ sb.reset(new GrGLStencilBuffer(this, 0, desc.fWidth, desc.fHeight,
+ rtDesc.fSampleCnt, format));
+ }
+ rtDesc.fOwnIDs = false;
+ }
+
+ if (isTexture) {
+ GrGLTexture::Desc texDesc;
+ if (!this->configToGLFormats(desc.fConfig, false, NULL, NULL, NULL)) {
+ return NULL;
+ }
+ texDesc.fWidth = desc.fWidth;
+ texDesc.fHeight = desc.fHeight;
+
+ texDesc.fConfig = desc.fConfig;
+ texDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
+ texDesc.fTextureID = desc.fPlatformTexture;
+ texDesc.fOwnsID = false;
+
+ if (isRenderTarget) {
+ GrTexture* tex = new GrGLTexture(this, texDesc, rtDesc);
+ tex->asRenderTarget()->setStencilBuffer(sb.get());
+ return tex;
+ } else {
+ return new GrGLTexture(this, texDesc);
+ }
+ } else {
+ GrGLIRect viewport;
+ viewport.fLeft = 0;
+ viewport.fBottom = 0;
+ viewport.fWidth = desc.fWidth;
+ viewport.fHeight = desc.fHeight;
+
+ GrGLRenderTarget* rt = new GrGLRenderTarget(this, rtDesc, viewport);
+ rt->setStencilBuffer(sb.get());
+ return rt;
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrGpuGL::onWriteTexturePixels(GrTexture* texture,
+ int left, int top, int width, int height,
+ GrPixelConfig config, const void* buffer,
+ size_t rowBytes) {
+ if (NULL == buffer) {
+ return;
+ }
+ GrGLTexture* glTex = static_cast<GrGLTexture*>(texture);
+
+ this->setSpareTextureUnit();
+ GL_CALL(BindTexture(GR_GL_TEXTURE_2D, glTex->textureID()));
+ GrGLTexture::Desc desc;
+ desc.fConfig = glTex->config();
+ desc.fWidth = glTex->width();
+ desc.fHeight = glTex->height();
+ desc.fOrientation = glTex->orientation();
+ desc.fTextureID = glTex->textureID();
+
+ this->uploadTexData(desc, false,
+ left, top, width, height,
+ config, buffer, rowBytes);
+}
+
+namespace {
+bool adjust_pixel_ops_params(int surfaceWidth,
+ int surfaceHeight,
+ size_t bpp,
+ int* left, int* top, int* width, int* height,
+ const void** data,
+ size_t* rowBytes) {
+ if (!*rowBytes) {
+ *rowBytes = *width * bpp;
+ }
+
+ GrIRect subRect = GrIRect::MakeXYWH(*left, *top, *width, *height);
+ GrIRect bounds = GrIRect::MakeWH(surfaceWidth, surfaceHeight);
+
+ if (!subRect.intersect(bounds)) {
+ return false;
+ }
+ *data = reinterpret_cast<const void*>(reinterpret_cast<intptr_t>(*data) +
+ (subRect.fTop - *top) * *rowBytes + (subRect.fLeft - *left) * bpp);
+
+ *left = subRect.fLeft;
+ *top = subRect.fTop;
+ *width = subRect.width();
+ *height = subRect.height();
+ return true;
+}
+}
+
+bool GrGpuGL::uploadTexData(const GrGLTexture::Desc& desc,
+ bool isNewTexture,
+ int left, int top, int width, int height,
+ GrPixelConfig dataConfig,
+ const void* data,
+ size_t rowBytes) {
+ GrAssert(NULL != data || isNewTexture);
+
+ size_t bpp = GrBytesPerPixel(dataConfig);
+ if (!adjust_pixel_ops_params(desc.fWidth, desc.fHeight, bpp, &left, &top,
+ &width, &height, &data, &rowBytes)) {
+ return false;
+ }
+ size_t trimRowBytes = width * bpp;
+
+ // in case we need a temporary, trimmed copy of the src pixels
+ SkAutoSMalloc<128 * 128> tempStorage;
+
+ bool useTexStorage = isNewTexture &&
+ this->glCaps().fTexStorageSupport;
+ if (useTexStorage) {
+ if (kDesktop_GrGLBinding == this->glBinding()) {
+ // 565 is not a sized internal format on desktop GL. So on desktop
+ // with 565 we always use an unsized internal format to let the
+ // system pick the best sized format to convert the 565 data to.
+ // Since glTexStorage only allows sized internal formats we will
+ // instead fallback to glTexImage2D.
+ useTexStorage = desc.fConfig != kRGB_565_GrPixelConfig;
+ } else {
+ // ES doesn't allow paletted textures to be used with tex storage
+ useTexStorage = desc.fConfig != kIndex_8_GrPixelConfig;
+ }
+ }
+
+ GrGLenum internalFormat;
+ GrGLenum externalFormat;
+ GrGLenum externalType;
+ // glTexStorage requires sized internal formats on both desktop and ES. ES
+ // glTexImage requires an unsized format.
+ if (!this->configToGLFormats(dataConfig, useTexStorage, &internalFormat,
+ &externalFormat, &externalType)) {
+ return false;
+ }
+
+ if (!isNewTexture && GR_GL_PALETTE8_RGBA8 == internalFormat) {
+ // paletted textures cannot be updated
+ return false;
+ }
+
+ /*
+ * check whether to allocate a temporary buffer for flipping y or
+ * because our srcData has extra bytes past each row. If so, we need
+ * to trim those off here, since GL ES may not let us specify
+ * GL_UNPACK_ROW_LENGTH.
+ */
+ bool restoreGLRowLength = false;
+ bool swFlipY = false;
+ bool glFlipY = false;
+ if (NULL != data) {
+ if (GrGLTexture::kBottomUp_Orientation == desc.fOrientation) {
+ if (this->glCaps().fUnpackFlipYSupport) {
+ glFlipY = true;
+ } else {
+ swFlipY = true;
+ }
+ }
+ if (this->glCaps().fUnpackRowLengthSupport && !swFlipY) {
+ // can't use this for flipping, only non-neg values allowed. :(
+ if (rowBytes != trimRowBytes) {
+ GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp);
+ GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength));
+ restoreGLRowLength = true;
+ }
+ } else {
+ if (trimRowBytes != rowBytes || swFlipY) {
+ // copy data into our new storage, skipping the trailing bytes
+ size_t trimSize = height * trimRowBytes;
+ const char* src = (const char*)data;
+ if (swFlipY) {
+ src += (height - 1) * rowBytes;
+ }
+ char* dst = (char*)tempStorage.reset(trimSize);
+ for (int y = 0; y < height; y++) {
+ memcpy(dst, src, trimRowBytes);
+ if (swFlipY) {
+ src -= rowBytes;
+ } else {
+ src += rowBytes;
+ }
+ dst += trimRowBytes;
+ }
+ // now point data to our copied version
+ data = tempStorage.get();
+ }
+ }
+ if (glFlipY) {
+ GL_CALL(PixelStorei(GR_GL_UNPACK_FLIP_Y, GR_GL_TRUE));
+ }
+ GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, static_cast<GrGLint>(bpp)));
+ }
+ bool succeeded = true;
+ if (isNewTexture &&
+ 0 == left && 0 == top &&
+ desc.fWidth == width && desc.fHeight == height) {
+ GrGLClearErr(this->glInterface());
+ if (useTexStorage) {
+ // We never resize or change formats of textures. We don't use
+ // mipmaps currently.
+ GR_GL_CALL_NOERRCHECK(this->glInterface(),
+ TexStorage2D(GR_GL_TEXTURE_2D,
+ 1, // levels
+ internalFormat,
+ desc.fWidth, desc.fHeight));
+ } else {
+ if (GR_GL_PALETTE8_RGBA8 == internalFormat) {
+ GrGLsizei imageSize = desc.fWidth * desc.fHeight +
+ kGrColorTableSize;
+ GR_GL_CALL_NOERRCHECK(this->glInterface(),
+ CompressedTexImage2D(GR_GL_TEXTURE_2D,
+ 0, // level
+ internalFormat,
+ desc.fWidth,
+ desc.fHeight,
+ 0, // border
+ imageSize,
+ data));
+ } else {
+ GR_GL_CALL_NOERRCHECK(this->glInterface(),
+ TexImage2D(GR_GL_TEXTURE_2D,
+ 0, // level
+ internalFormat,
+ desc.fWidth, desc.fHeight,
+ 0, // border
+ externalFormat, externalType,
+ data));
+ }
+ }
+ GrGLenum error = GR_GL_GET_ERROR(this->glInterface());
+ if (error != GR_GL_NO_ERROR) {
+ succeeded = false;
+ } else {
+ // if we have data and we used TexStorage to create the texture, we
+ // now upload with TexSubImage.
+ if (NULL != data && useTexStorage) {
+ GL_CALL(TexSubImage2D(GR_GL_TEXTURE_2D,
+ 0, // level
+ left, top,
+ width, height,
+ externalFormat, externalType,
+ data));
+ }
+ }
+ } else {
+ if (swFlipY || glFlipY) {
+ top = desc.fHeight - (top + height);
+ }
+ GL_CALL(TexSubImage2D(GR_GL_TEXTURE_2D,
+ 0, // level
+ left, top,
+ width, height,
+ externalFormat, externalType, data));
+ }
+
+ if (restoreGLRowLength) {
+ GrAssert(this->glCaps().fUnpackRowLengthSupport);
+ GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
+ }
+ if (glFlipY) {
+ GL_CALL(PixelStorei(GR_GL_UNPACK_FLIP_Y, GR_GL_FALSE));
+ }
+ return succeeded;
+}
+
+bool GrGpuGL::createRenderTargetObjects(int width, int height,
+ GrGLuint texID,
+ GrGLRenderTarget::Desc* desc) {
+ desc->fMSColorRenderbufferID = 0;
+ desc->fRTFBOID = 0;
+ desc->fTexFBOID = 0;
+ desc->fOwnIDs = true;
+
+ GrGLenum status;
+ GrGLint err;
+
+ GrGLenum msColorFormat = 0; // suppress warning
+
+ GL_CALL(GenFramebuffers(1, &desc->fTexFBOID));
+ if (!desc->fTexFBOID) {
+ goto FAILED;
+ }
+
+
+ // If we are using multisampling we will create two FBOS. We render
+ // to one and then resolve to the texture bound to the other.
+ if (desc->fSampleCnt > 0) {
+ if (GLCaps::kNone_MSFBO == fGLCaps.fMSFBOType) {
+ goto FAILED;
+ }
+ GL_CALL(GenFramebuffers(1, &desc->fRTFBOID));
+ GL_CALL(GenRenderbuffers(1, &desc->fMSColorRenderbufferID));
+ if (!desc->fRTFBOID ||
+ !desc->fMSColorRenderbufferID ||
+ !this->configToGLFormats(desc->fConfig,
+ // GLES requires sized internal formats
+ kES2_GrGLBinding == this->glBinding(),
+ &msColorFormat, NULL, NULL)) {
+ goto FAILED;
+ }
+ } else {
+ desc->fRTFBOID = desc->fTexFBOID;
+ }
+
+ // below here we may bind the FBO
+ fHWDrawState.setRenderTarget(NULL);
+ if (desc->fRTFBOID != desc->fTexFBOID) {
+ GrAssert(desc->fSampleCnt > 1);
+ GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER,
+ desc->fMSColorRenderbufferID));
+ GrGLClearErr(this->glInterface());
+ GR_GL_CALL_NOERRCHECK(this->glInterface(),
+ RenderbufferStorageMultisample(GR_GL_RENDERBUFFER,
+ desc->fSampleCnt,
+ msColorFormat,
+ width, height));
+ err = GR_GL_GET_ERROR(this->glInterface());
+ if (err != GR_GL_NO_ERROR) {
+ goto FAILED;
+ }
+ GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, desc->fRTFBOID));
+ GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+ GR_GL_COLOR_ATTACHMENT0,
+ GR_GL_RENDERBUFFER,
+ desc->fMSColorRenderbufferID));
+ GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
+ if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
+ goto FAILED;
+ }
+ }
+ GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, desc->fTexFBOID));
+
+ GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER,
+ GR_GL_COLOR_ATTACHMENT0,
+ GR_GL_TEXTURE_2D,
+ texID, 0));
+ GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
+ if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
+ goto FAILED;
+ }
+
+ return true;
+
+FAILED:
+ if (desc->fMSColorRenderbufferID) {
+ GL_CALL(DeleteRenderbuffers(1, &desc->fMSColorRenderbufferID));
+ }
+ if (desc->fRTFBOID != desc->fTexFBOID) {
+ GL_CALL(DeleteFramebuffers(1, &desc->fRTFBOID));
+ }
+ if (desc->fTexFBOID) {
+ GL_CALL(DeleteFramebuffers(1, &desc->fTexFBOID));
+ }
+ return false;
+}
+
+// good to set a break-point here to know when createTexture fails
+static GrTexture* return_null_texture() {
+// GrAssert(!"null texture");
+ return NULL;
+}
+
+#if GR_DEBUG
+static size_t as_size_t(int x) {
+ return x;
+}
+#endif
+
+GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc,
+ const void* srcData,
+ size_t rowBytes) {
+
+#if GR_COLLECT_STATS
+ ++fStats.fTextureCreateCnt;
+#endif
+
+ GrGLTexture::Desc glTexDesc;
+ GrGLRenderTarget::Desc glRTDesc;
+
+ glTexDesc.fWidth = desc.fWidth;
+ glTexDesc.fHeight = desc.fHeight;
+ glTexDesc.fConfig = desc.fConfig;
+ glTexDesc.fOwnsID = true;
+
+ glRTDesc.fMSColorRenderbufferID = 0;
+ glRTDesc.fRTFBOID = 0;
+ glRTDesc.fTexFBOID = 0;
+ glRTDesc.fOwnIDs = true;
+ glRTDesc.fConfig = glTexDesc.fConfig;
+
+ bool renderTarget = 0 != (desc.fFlags & kRenderTarget_GrTextureFlagBit);
+
+ const Caps& caps = this->getCaps();
+
+ // We keep GrRenderTargets in GL's normal orientation so that they
+ // can be drawn to by the outside world without the client having
+ // to render upside down.
+ glTexDesc.fOrientation = renderTarget ? GrGLTexture::kBottomUp_Orientation :
+ GrGLTexture::kTopDown_Orientation;
+
+ GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fGLCaps.fAASamples));
+ glRTDesc.fSampleCnt = fGLCaps.fAASamples[desc.fAALevel];
+ if (GLCaps::kNone_MSFBO == fGLCaps.fMSFBOType &&
+ desc.fAALevel != kNone_GrAALevel) {
+ GrPrintf("AA RT requested but not supported on this platform.");
+ }
+
+ if (renderTarget) {
+ if (glTexDesc.fWidth > caps.fMaxRenderTargetSize ||
+ glTexDesc.fHeight > caps.fMaxRenderTargetSize) {
+ return return_null_texture();
+ }
+ }
+
+ GL_CALL(GenTextures(1, &glTexDesc.fTextureID));
+ if (renderTarget && this->glCaps().fTextureUsageSupport) {
+ // provides a hint about how this texture will be used
+ GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+ GR_GL_TEXTURE_USAGE,
+ GR_GL_FRAMEBUFFER_ATTACHMENT));
+ }
+ if (!glTexDesc.fTextureID) {
+ return return_null_texture();
+ }
+
+ this->setSpareTextureUnit();
+ GL_CALL(BindTexture(GR_GL_TEXTURE_2D, glTexDesc.fTextureID));
+
+ // Some drivers like to know filter/wrap before seeing glTexImage2D. Some
+ // drivers have a bug where an FBO won't be complete if it includes a
+ // texture that is not mipmap complete (considering the filter in use).
+ GrGLTexture::TexParams initialTexParams;
+ // we only set a subset here so invalidate first
+ initialTexParams.invalidate();
+ initialTexParams.fFilter = GR_GL_NEAREST;
+ initialTexParams.fWrapS = GR_GL_CLAMP_TO_EDGE;
+ initialTexParams.fWrapT = GR_GL_CLAMP_TO_EDGE;
+ GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+ GR_GL_TEXTURE_MAG_FILTER,
+ initialTexParams.fFilter));
+ GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+ GR_GL_TEXTURE_MIN_FILTER,
+ initialTexParams.fFilter));
+ GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+ GR_GL_TEXTURE_WRAP_S,
+ initialTexParams.fWrapS));
+ GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+ GR_GL_TEXTURE_WRAP_T,
+ initialTexParams.fWrapT));
+ if (!this->uploadTexData(glTexDesc, true, 0, 0,
+ glTexDesc.fWidth, glTexDesc.fHeight,
+ desc.fConfig, srcData, rowBytes)) {
+ GL_CALL(DeleteTextures(1, &glTexDesc.fTextureID));
+ return return_null_texture();
+ }
+
+ GrGLTexture* tex;
+ if (renderTarget) {
+#if GR_COLLECT_STATS
+ ++fStats.fRenderTargetCreateCnt;
+#endif
+ if (!this->createRenderTargetObjects(glTexDesc.fWidth,
+ glTexDesc.fHeight,
+ glTexDesc.fTextureID,
+ &glRTDesc)) {
+ GL_CALL(DeleteTextures(1, &glTexDesc.fTextureID));
+ return return_null_texture();
+ }
+ tex = new GrGLTexture(this, glTexDesc, glRTDesc);
+ } else {
+ tex = new GrGLTexture(this, glTexDesc);
+ }
+ tex->setCachedTexParams(initialTexParams, this->getResetTimestamp());
+#ifdef TRACE_TEXTURE_CREATION
+ GrPrintf("--- new texture [%d] size=(%d %d) config=%d\n",
+ glTexDesc.fTextureID, desc.fWidth, desc.fHeight, desc.fConfig);
+#endif
+ return tex;
+}
+
+namespace {
+void inline get_stencil_rb_sizes(const GrGLInterface* gl,
+ GrGLuint rb,
+ GrGLStencilBuffer::Format* format) {
+ // we shouldn't ever know one size and not the other
+ GrAssert((kUnknownBitCount == format->fStencilBits) ==
+ (kUnknownBitCount == format->fTotalBits));
+ if (kUnknownBitCount == format->fStencilBits) {
+ GR_GL_GetRenderbufferParameteriv(gl, GR_GL_RENDERBUFFER,
+ GR_GL_RENDERBUFFER_STENCIL_SIZE,
+ (GrGLint*)&format->fStencilBits);
+ if (format->fPacked) {
+ GR_GL_GetRenderbufferParameteriv(gl, GR_GL_RENDERBUFFER,
+ GR_GL_RENDERBUFFER_DEPTH_SIZE,
+ (GrGLint*)&format->fTotalBits);
+ format->fTotalBits += format->fStencilBits;
+ } else {
+ format->fTotalBits = format->fStencilBits;
+ }
+ }
+}
+}
+
+bool GrGpuGL::createStencilBufferForRenderTarget(GrRenderTarget* rt,
+ int width, int height) {
+
+ // All internally created RTs are also textures. We don't create
+ // SBs for a client's standalone RT (that is RT that isnt also a texture).
+ GrAssert(rt->asTexture());
+ GrAssert(width >= rt->width());
+ GrAssert(height >= rt->height());
+
+ int samples = rt->numSamples();
+ GrGLuint sbID;
+ GL_CALL(GenRenderbuffers(1, &sbID));
+ if (!sbID) {
+ return false;
+ }
+
+ GrGLStencilBuffer* sb = NULL;
+
+ int stencilFmtCnt = fGLCaps.fStencilFormats.count();
+ for (int i = 0; i < stencilFmtCnt; ++i) {
+ GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, sbID));
+ // we start with the last stencil format that succeeded in hopes
+ // that we won't go through this loop more than once after the
+ // first (painful) stencil creation.
+ int sIdx = (i + fLastSuccessfulStencilFmtIdx) % stencilFmtCnt;
+ const GrGLStencilBuffer::Format& sFmt = fGLCaps.fStencilFormats[sIdx];
+ GrGLClearErr(this->glInterface());
+ // we do this "if" so that we don't call the multisample
+ // version on a GL that doesn't have an MSAA extension.
+ if (samples > 1) {
+ GR_GL_CALL_NOERRCHECK(this->glInterface(),
+ RenderbufferStorageMultisample(
+ GR_GL_RENDERBUFFER,
+ samples,
+ sFmt.fInternalFormat,
+ width,
+ height));
+ } else {
+ GR_GL_CALL_NOERRCHECK(this->glInterface(),
+ RenderbufferStorage(GR_GL_RENDERBUFFER,
+ sFmt.fInternalFormat,
+ width, height));
+ }
+
+ GrGLenum err = GR_GL_GET_ERROR(this->glInterface());
+ if (err == GR_GL_NO_ERROR) {
+ // After sized formats we attempt an unsized format and take whatever
+ // sizes GL gives us. In that case we query for the size.
+ GrGLStencilBuffer::Format format = sFmt;
+ get_stencil_rb_sizes(this->glInterface(), sbID, &format);
+ sb = new GrGLStencilBuffer(this, sbID, width, height,
+ samples, format);
+ if (this->attachStencilBufferToRenderTarget(sb, rt)) {
+ fLastSuccessfulStencilFmtIdx = sIdx;
+ rt->setStencilBuffer(sb);
+ sb->unref();
+ return true;
+ }
+ sb->abandon(); // otherwise we lose sbID
+ sb->unref();
+ }
+ }
+ GL_CALL(DeleteRenderbuffers(1, &sbID));
+ return false;
+}
+
+bool GrGpuGL::attachStencilBufferToRenderTarget(GrStencilBuffer* sb,
+ GrRenderTarget* rt) {
+ GrGLRenderTarget* glrt = (GrGLRenderTarget*) rt;
+
+ GrGLuint fbo = glrt->renderFBOID();
+
+ if (NULL == sb) {
+ if (NULL != rt->getStencilBuffer()) {
+ GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+ GR_GL_STENCIL_ATTACHMENT,
+ GR_GL_RENDERBUFFER, 0));
+ GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+ GR_GL_DEPTH_ATTACHMENT,
+ GR_GL_RENDERBUFFER, 0));
+#if GR_DEBUG
+ GrGLenum status;
+ GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
+ GrAssert(GR_GL_FRAMEBUFFER_COMPLETE == status);
+#endif
+ }
+ return true;
+ } else {
+ GrGLStencilBuffer* glsb = (GrGLStencilBuffer*) sb;
+ GrGLuint rb = glsb->renderbufferID();
+
+ fHWDrawState.setRenderTarget(NULL);
+ GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fbo));
+ GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+ GR_GL_STENCIL_ATTACHMENT,
+ GR_GL_RENDERBUFFER, rb));
+ if (glsb->format().fPacked) {
+ GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+ GR_GL_DEPTH_ATTACHMENT,
+ GR_GL_RENDERBUFFER, rb));
+ } else {
+ GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+ GR_GL_DEPTH_ATTACHMENT,
+ GR_GL_RENDERBUFFER, 0));
+ }
+
+ GrGLenum status;
+ GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
+ if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
+ GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+ GR_GL_STENCIL_ATTACHMENT,
+ GR_GL_RENDERBUFFER, 0));
+ if (glsb->format().fPacked) {
+ GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+ GR_GL_DEPTH_ATTACHMENT,
+ GR_GL_RENDERBUFFER, 0));
+ }
+ return false;
+ } else {
+ return true;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+GrVertexBuffer* GrGpuGL::onCreateVertexBuffer(uint32_t size, bool dynamic) {
+ GrGLuint id;
+ GL_CALL(GenBuffers(1, &id));
+ if (id) {
+ GL_CALL(BindBuffer(GR_GL_ARRAY_BUFFER, id));
+ fHWGeometryState.fArrayPtrsDirty = true;
+ GrGLClearErr(this->glInterface());
+ // make sure driver can allocate memory for this buffer
+ GR_GL_CALL_NOERRCHECK(this->glInterface(),
+ BufferData(GR_GL_ARRAY_BUFFER, size, NULL,
+ dynamic ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW));
+ if (GR_GL_GET_ERROR(this->glInterface()) != GR_GL_NO_ERROR) {
+ GL_CALL(DeleteBuffers(1, &id));
+ // deleting bound buffer does implicit bind to 0
+ fHWGeometryState.fVertexBuffer = NULL;
+ return NULL;
+ }
+ GrGLVertexBuffer* vertexBuffer = new GrGLVertexBuffer(this, id,
+ size, dynamic);
+ fHWGeometryState.fVertexBuffer = vertexBuffer;
+ return vertexBuffer;
+ }
+ return NULL;
+}
+
+GrIndexBuffer* GrGpuGL::onCreateIndexBuffer(uint32_t size, bool dynamic) {
+ GrGLuint id;
+ GL_CALL(GenBuffers(1, &id));
+ if (id) {
+ GL_CALL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, id));
+ GrGLClearErr(this->glInterface());
+ // make sure driver can allocate memory for this buffer
+ GR_GL_CALL_NOERRCHECK(this->glInterface(),
+ BufferData(GR_GL_ELEMENT_ARRAY_BUFFER, size, NULL,
+ dynamic ? GR_GL_DYNAMIC_DRAW : GR_GL_STATIC_DRAW));
+ if (GR_GL_GET_ERROR(this->glInterface()) != GR_GL_NO_ERROR) {
+ GL_CALL(DeleteBuffers(1, &id));
+ // deleting bound buffer does implicit bind to 0
+ fHWGeometryState.fIndexBuffer = NULL;
+ return NULL;
+ }
+ GrIndexBuffer* indexBuffer = new GrGLIndexBuffer(this, id,
+ size, dynamic);
+ fHWGeometryState.fIndexBuffer = indexBuffer;
+ return indexBuffer;
+ }
+ return NULL;
+}
+
+void GrGpuGL::flushScissor(const GrIRect* rect) {
+ const GrDrawState& drawState = this->getDrawState();
+ const GrGLRenderTarget* rt =
+ static_cast<const GrGLRenderTarget*>(drawState.getRenderTarget());
+
+ GrAssert(NULL != rt);
+ const GrGLIRect& vp = rt->getViewport();
+
+ GrGLIRect scissor;
+ if (NULL != rect) {
+ scissor.setRelativeTo(vp, rect->fLeft, rect->fTop,
+ rect->width(), rect->height());
+ if (scissor.contains(vp)) {
+ rect = NULL;
+ }
+ }
+
+ if (NULL != rect) {
+ if (fHWBounds.fScissorRect != scissor) {
+ scissor.pushToGLScissor(this->glInterface());
+ fHWBounds.fScissorRect = scissor;
+ }
+ if (!fHWBounds.fScissorEnabled) {
+ GL_CALL(Enable(GR_GL_SCISSOR_TEST));
+ fHWBounds.fScissorEnabled = true;
+ }
+ } else {
+ if (fHWBounds.fScissorEnabled) {
+ GL_CALL(Disable(GR_GL_SCISSOR_TEST));
+ fHWBounds.fScissorEnabled = false;
+ }
+ }
+}
+
+void GrGpuGL::onClear(const GrIRect* rect, GrColor color) {
+ const GrDrawState& drawState = this->getDrawState();
+ const GrRenderTarget* rt = drawState.getRenderTarget();
+ // parent class should never let us get here with no RT
+ GrAssert(NULL != rt);
+
+ GrIRect clippedRect;
+ if (NULL != rect) {
+ // flushScissor expects rect to be clipped to the target.
+ clippedRect = *rect;
+ GrIRect rtRect = SkIRect::MakeWH(rt->width(), rt->height());
+ if (clippedRect.intersect(rtRect)) {
+ rect = &clippedRect;
+ } else {
+ return;
+ }
+ }
+ this->flushRenderTarget(rect);
+ this->flushScissor(rect);
+
+ GrGLfloat r, g, b, a;
+ static const GrGLfloat scale255 = 1.f / 255.f;
+ a = GrColorUnpackA(color) * scale255;
+ GrGLfloat scaleRGB = scale255;
+ if (GrPixelConfigIsUnpremultiplied(rt->config())) {
+ scaleRGB *= a;
+ }
+ r = GrColorUnpackR(color) * scaleRGB;
+ g = GrColorUnpackG(color) * scaleRGB;
+ b = GrColorUnpackB(color) * scaleRGB;
+
+ GL_CALL(ColorMask(GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE));
+ fHWDrawState.disableState(GrDrawState::kNoColorWrites_StateBit);
+ GL_CALL(ClearColor(r, g, b, a));
+ GL_CALL(Clear(GR_GL_COLOR_BUFFER_BIT));
+}
+
+void GrGpuGL::clearStencil() {
+ if (NULL == this->getDrawState().getRenderTarget()) {
+ return;
+ }
+
+ this->flushRenderTarget(&GrIRect::EmptyIRect());
+
+ if (fHWBounds.fScissorEnabled) {
+ GL_CALL(Disable(GR_GL_SCISSOR_TEST));
+ fHWBounds.fScissorEnabled = false;
+ }
+ GL_CALL(StencilMask(0xffffffff));
+ GL_CALL(ClearStencil(0));
+ GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT));
+ fHWDrawState.stencil()->invalidate();
+}
+
+void GrGpuGL::clearStencilClip(const GrIRect& rect, bool insideClip) {
+ const GrDrawState& drawState = this->getDrawState();
+ const GrRenderTarget* rt = drawState.getRenderTarget();
+ GrAssert(NULL != rt);
+
+ // this should only be called internally when we know we have a
+ // stencil buffer.
+ GrAssert(NULL != rt->getStencilBuffer());
+ GrGLint stencilBitCount = rt->getStencilBuffer()->bits();
+#if 0
+ GrAssert(stencilBitCount > 0);
+ GrGLint clipStencilMask = (1 << (stencilBitCount - 1));
+#else
+ // we could just clear the clip bit but when we go through
+ // ANGLE a partial stencil mask will cause clears to be
+ // turned into draws. Our contract on GrDrawTarget says that
+ // changing the clip between stencil passes may or may not
+ // zero the client's clip bits. So we just clear the whole thing.
+ static const GrGLint clipStencilMask = ~0;
+#endif
+ GrGLint value;
+ if (insideClip) {
+ value = (1 << (stencilBitCount - 1));
+ } else {
+ value = 0;
+ }
+ this->flushRenderTarget(&GrIRect::EmptyIRect());
+ this->flushScissor(&rect);
+ GL_CALL(StencilMask(clipStencilMask));
+ GL_CALL(ClearStencil(value));
+ GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT));
+ fHWDrawState.stencil()->invalidate();
+}
+
+void GrGpuGL::onForceRenderTargetFlush() {
+ this->flushRenderTarget(&GrIRect::EmptyIRect());
+}
+
+bool GrGpuGL::readPixelsWillPayForYFlip(GrRenderTarget* renderTarget,
+ int left, int top,
+ int width, int height,
+ GrPixelConfig config,
+ size_t rowBytes) const {
+ // if GL can do the flip then we'll never pay for it.
+ if (this->glCaps().fPackFlipYSupport) {
+ return false;
+ }
+
+ // If we have to do memcpy to handle non-trim rowBytes then we
+ // get the flip for free. Otherwise it costs.
+ if (this->glCaps().fPackRowLengthSupport) {
+ return true;
+ }
+ // If we have to do memcpys to handle rowBytes then y-flip is free
+ // Note the rowBytes might be tight to the passed in data, but if data
+ // gets clipped in x to the target the rowBytes will no longer be tight.
+ if (left >= 0 && (left + width) < renderTarget->width()) {
+ return 0 == rowBytes ||
+ GrBytesPerPixel(config) * width == rowBytes;
+ } else {
+ return false;
+ }
+}
+
+bool GrGpuGL::onReadPixels(GrRenderTarget* target,
+ int left, int top,
+ int width, int height,
+ GrPixelConfig config,
+ void* buffer,
+ size_t rowBytes,
+ bool invertY) {
+ GrGLenum format;
+ GrGLenum type;
+ if (!this->configToGLFormats(config, false, NULL, &format, &type)) {
+ return false;
+ }
+ size_t bpp = GrBytesPerPixel(config);
+ if (!adjust_pixel_ops_params(target->width(), target->height(), bpp,
+ &left, &top, &width, &height,
+ const_cast<const void**>(&buffer),
+ &rowBytes)) {
+ return false;
+ }
+
+ // resolve the render target if necessary
+ GrGLRenderTarget* tgt = static_cast<GrGLRenderTarget*>(target);
+ GrDrawState::AutoRenderTargetRestore artr;
+ switch (tgt->getResolveType()) {
+ case GrGLRenderTarget::kCantResolve_ResolveType:
+ return false;
+ case GrGLRenderTarget::kAutoResolves_ResolveType:
+ artr.set(this->drawState(), target);
+ this->flushRenderTarget(&GrIRect::EmptyIRect());
+ break;
+ case GrGLRenderTarget::kCanResolve_ResolveType:
+ this->resolveRenderTarget(tgt);
+ // we don't track the state of the READ FBO ID.
+ GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER,
+ tgt->textureFBOID()));
+ break;
+ default:
+ GrCrash("Unknown resolve type");
+ }
+
+ const GrGLIRect& glvp = tgt->getViewport();
+
+ // the read rect is viewport-relative
+ GrGLIRect readRect;
+ readRect.setRelativeTo(glvp, left, top, width, height);
+
+ size_t tightRowBytes = bpp * width;
+ if (0 == rowBytes) {
+ rowBytes = tightRowBytes;
+ }
+ size_t readDstRowBytes = tightRowBytes;
+ void* readDst = buffer;
+
+ // determine if GL can read using the passed rowBytes or if we need
+ // a scratch buffer.
+ SkAutoSMalloc<32 * sizeof(GrColor)> scratch;
+ if (rowBytes != tightRowBytes) {
+ if (this->glCaps().fPackRowLengthSupport) {
+ GrAssert(!(rowBytes % sizeof(GrColor)));
+ GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, rowBytes / sizeof(GrColor)));
+ readDstRowBytes = rowBytes;
+ } else {
+ scratch.reset(tightRowBytes * height);
+ readDst = scratch.get();
+ }
+ }
+ if (!invertY && this->glCaps().fPackFlipYSupport) {
+ GL_CALL(PixelStorei(GR_GL_PACK_REVERSE_ROW_ORDER, 1));
+ }
+ GL_CALL(ReadPixels(readRect.fLeft, readRect.fBottom,
+ readRect.fWidth, readRect.fHeight,
+ format, type, readDst));
+ if (readDstRowBytes != tightRowBytes) {
+ GrAssert(this->glCaps().fPackRowLengthSupport);
+ GL_CALL(PixelStorei(GR_GL_PACK_ROW_LENGTH, 0));
+ }
+ if (!invertY && this->glCaps().fPackFlipYSupport) {
+ GL_CALL(PixelStorei(GR_GL_PACK_REVERSE_ROW_ORDER, 0));
+ invertY = true;
+ }
+
+ // now reverse the order of the rows, since GL's are bottom-to-top, but our
+ // API presents top-to-bottom. We must preserve the padding contents. Note
+ // that the above readPixels did not overwrite the padding.
+ if (readDst == buffer) {
+ GrAssert(rowBytes == readDstRowBytes);
+ if (!invertY) {
+ scratch.reset(tightRowBytes);
+ void* tmpRow = scratch.get();
+ // flip y in-place by rows
+ const int halfY = height >> 1;
+ char* top = reinterpret_cast<char*>(buffer);
+ char* bottom = top + (height - 1) * rowBytes;
+ for (int y = 0; y < halfY; y++) {
+ memcpy(tmpRow, top, tightRowBytes);
+ memcpy(top, bottom, tightRowBytes);
+ memcpy(bottom, tmpRow, tightRowBytes);
+ top += rowBytes;
+ bottom -= rowBytes;
+ }
+ }
+ } else {
+ GrAssert(readDst != buffer); GrAssert(rowBytes != tightRowBytes);
+ // copy from readDst to buffer while flipping y
+ const int halfY = height >> 1;
+ const char* src = reinterpret_cast<const char*>(readDst);
+ char* dst = reinterpret_cast<char*>(buffer);
+ if (!invertY) {
+ dst += (height-1) * rowBytes;
+ }
+ for (int y = 0; y < height; y++) {
+ memcpy(dst, src, tightRowBytes);
+ src += readDstRowBytes;
+ if (invertY) {
+ dst += rowBytes;
+ } else {
+ dst -= rowBytes;
+ }
+ }
+ }
+ return true;
+}
+
+void GrGpuGL::flushRenderTarget(const GrIRect* bound) {
+
+ GrGLRenderTarget* rt =
+ static_cast<GrGLRenderTarget*>(this->drawState()->getRenderTarget());
+ GrAssert(NULL != rt);
+
+ if (fHWDrawState.getRenderTarget() != rt) {
+ GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, rt->renderFBOID()));
+ #if GR_COLLECT_STATS
+ ++fStats.fRenderTargetChngCnt;
+ #endif
+ #if GR_DEBUG
+ GrGLenum status;
+ GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
+ if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
+ GrPrintf("GrGpuGL::flushRenderTarget glCheckFramebufferStatus %x\n", status);
+ }
+ #endif
+ fDirtyFlags.fRenderTargetChanged = true;
+ fHWDrawState.setRenderTarget(rt);
+ const GrGLIRect& vp = rt->getViewport();
+ if (fHWBounds.fViewportRect != vp) {
+ vp.pushToGLViewport(this->glInterface());
+ fHWBounds.fViewportRect = vp;
+ }
+ }
+ if (NULL == bound || !bound->isEmpty()) {
+ rt->flagAsNeedingResolve(bound);
+ }
+}
+
+GrGLenum gPrimitiveType2GLMode[] = {
+ GR_GL_TRIANGLES,
+ GR_GL_TRIANGLE_STRIP,
+ GR_GL_TRIANGLE_FAN,
+ GR_GL_POINTS,
+ GR_GL_LINES,
+ GR_GL_LINE_STRIP
+};
+
+#define SWAP_PER_DRAW 0
+
+#if SWAP_PER_DRAW
+ #if GR_MAC_BUILD
+ #include <AGL/agl.h>
+ #elif GR_WIN32_BUILD
+ void SwapBuf() {
+ DWORD procID = GetCurrentProcessId();
+ HWND hwnd = GetTopWindow(GetDesktopWindow());
+ while(hwnd) {
+ DWORD wndProcID = 0;
+ GetWindowThreadProcessId(hwnd, &wndProcID);
+ if(wndProcID == procID) {
+ SwapBuffers(GetDC(hwnd));
+ }
+ hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
+ }
+ }
+ #endif
+#endif
+
+void GrGpuGL::onGpuDrawIndexed(GrPrimitiveType type,
+ uint32_t startVertex,
+ uint32_t startIndex,
+ uint32_t vertexCount,
+ uint32_t indexCount) {
+ GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
+
+ GrGLvoid* indices = (GrGLvoid*)(sizeof(uint16_t) * startIndex);
+
+ GrAssert(NULL != fHWGeometryState.fIndexBuffer);
+ GrAssert(NULL != fHWGeometryState.fVertexBuffer);
+
+ // our setupGeometry better have adjusted this to zero since
+ // DrawElements always draws from the begining of the arrays for idx 0.
+ GrAssert(0 == startVertex);
+
+ GL_CALL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
+ GR_GL_UNSIGNED_SHORT, indices));
+#if SWAP_PER_DRAW
+ glFlush();
+ #if GR_MAC_BUILD
+ aglSwapBuffers(aglGetCurrentContext());
+ int set_a_break_pt_here = 9;
+ aglSwapBuffers(aglGetCurrentContext());
+ #elif GR_WIN32_BUILD
+ SwapBuf();
+ int set_a_break_pt_here = 9;
+ SwapBuf();
+ #endif
+#endif
+}
+
+void GrGpuGL::onGpuDrawNonIndexed(GrPrimitiveType type,
+ uint32_t startVertex,
+ uint32_t vertexCount) {
+ GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
+
+ GrAssert(NULL != fHWGeometryState.fVertexBuffer);
+
+ // our setupGeometry better have adjusted this to zero.
+ // DrawElements doesn't take an offset so we always adjus the startVertex.
+ GrAssert(0 == startVertex);
+
+ // pass 0 for parameter first. We have to adjust gl*Pointer() to
+ // account for startVertex in the DrawElements case. So we always
+ // rely on setupGeometry to have accounted for startVertex.
+ GL_CALL(DrawArrays(gPrimitiveType2GLMode[type], 0, vertexCount));
+#if SWAP_PER_DRAW
+ glFlush();
+ #if GR_MAC_BUILD
+ aglSwapBuffers(aglGetCurrentContext());
+ int set_a_break_pt_here = 9;
+ aglSwapBuffers(aglGetCurrentContext());
+ #elif GR_WIN32_BUILD
+ SwapBuf();
+ int set_a_break_pt_here = 9;
+ SwapBuf();
+ #endif
+#endif
+}
+
+void GrGpuGL::resolveRenderTarget(GrGLRenderTarget* rt) {
+
+ if (rt->needsResolve()) {
+ GrAssert(GLCaps::kNone_MSFBO != fGLCaps.fMSFBOType);
+ GrAssert(rt->textureFBOID() != rt->renderFBOID());
+ GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER,
+ rt->renderFBOID()));
+ GL_CALL(BindFramebuffer(GR_GL_DRAW_FRAMEBUFFER,
+ rt->textureFBOID()));
+ #if GR_COLLECT_STATS
+ ++fStats.fRenderTargetChngCnt;
+ #endif
+ // make sure we go through flushRenderTarget() since we've modified
+ // the bound DRAW FBO ID.
+ fHWDrawState.setRenderTarget(NULL);
+ const GrGLIRect& vp = rt->getViewport();
+ const GrIRect dirtyRect = rt->getResolveRect();
+ GrGLIRect r;
+ r.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop,
+ dirtyRect.width(), dirtyRect.height());
+
+ if (GLCaps::kAppleES_MSFBO == fGLCaps.fMSFBOType) {
+ // Apple's extension uses the scissor as the blit bounds.
+ GL_CALL(Enable(GR_GL_SCISSOR_TEST));
+ GL_CALL(Scissor(r.fLeft, r.fBottom,
+ r.fWidth, r.fHeight));
+ GL_CALL(ResolveMultisampleFramebuffer());
+ fHWBounds.fScissorRect.invalidate();
+ fHWBounds.fScissorEnabled = true;
+ } else {
+ if (GLCaps::kDesktopARB_MSFBO != fGLCaps.fMSFBOType) {
+ // this respects the scissor during the blit, so disable it.
+ GrAssert(GLCaps::kDesktopEXT_MSFBO == fGLCaps.fMSFBOType);
+ this->flushScissor(NULL);
+ }
+ int right = r.fLeft + r.fWidth;
+ int top = r.fBottom + r.fHeight;
+ GL_CALL(BlitFramebuffer(r.fLeft, r.fBottom, right, top,
+ r.fLeft, r.fBottom, right, top,
+ GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
+ }
+ rt->flagAsResolved();
+ }
+}
+
+static const GrGLenum grToGLStencilFunc[] = {
+ GR_GL_ALWAYS, // kAlways_StencilFunc
+ GR_GL_NEVER, // kNever_StencilFunc
+ GR_GL_GREATER, // kGreater_StencilFunc
+ GR_GL_GEQUAL, // kGEqual_StencilFunc
+ GR_GL_LESS, // kLess_StencilFunc
+ GR_GL_LEQUAL, // kLEqual_StencilFunc,
+ GR_GL_EQUAL, // kEqual_StencilFunc,
+ GR_GL_NOTEQUAL, // kNotEqual_StencilFunc,
+};
+GR_STATIC_ASSERT(GR_ARRAY_COUNT(grToGLStencilFunc) == kBasicStencilFuncCount);
+GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
+GR_STATIC_ASSERT(1 == kNever_StencilFunc);
+GR_STATIC_ASSERT(2 == kGreater_StencilFunc);
+GR_STATIC_ASSERT(3 == kGEqual_StencilFunc);
+GR_STATIC_ASSERT(4 == kLess_StencilFunc);
+GR_STATIC_ASSERT(5 == kLEqual_StencilFunc);
+GR_STATIC_ASSERT(6 == kEqual_StencilFunc);
+GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc);
+
+static const GrGLenum grToGLStencilOp[] = {
+ GR_GL_KEEP, // kKeep_StencilOp
+ GR_GL_REPLACE, // kReplace_StencilOp
+ GR_GL_INCR_WRAP, // kIncWrap_StencilOp
+ GR_GL_INCR, // kIncClamp_StencilOp
+ GR_GL_DECR_WRAP, // kDecWrap_StencilOp
+ GR_GL_DECR, // kDecClamp_StencilOp
+ GR_GL_ZERO, // kZero_StencilOp
+ GR_GL_INVERT, // kInvert_StencilOp
+};
+GR_STATIC_ASSERT(GR_ARRAY_COUNT(grToGLStencilOp) == kStencilOpCount);
+GR_STATIC_ASSERT(0 == kKeep_StencilOp);
+GR_STATIC_ASSERT(1 == kReplace_StencilOp);
+GR_STATIC_ASSERT(2 == kIncWrap_StencilOp);
+GR_STATIC_ASSERT(3 == kIncClamp_StencilOp);
+GR_STATIC_ASSERT(4 == kDecWrap_StencilOp);
+GR_STATIC_ASSERT(5 == kDecClamp_StencilOp);
+GR_STATIC_ASSERT(6 == kZero_StencilOp);
+GR_STATIC_ASSERT(7 == kInvert_StencilOp);
+
+void GrGpuGL::flushStencil() {
+ const GrDrawState& drawState = this->getDrawState();
+
+ const GrStencilSettings* settings = &drawState.getStencil();
+
+ // use stencil for clipping if clipping is enabled and the clip
+ // has been written into the stencil.
+ bool stencilClip = fClipInStencil && drawState.isClipState();
+ bool drawClipToStencil =
+ drawState.isStateFlagEnabled(kModifyStencilClip_StateBit);
+ bool stencilChange = (fHWDrawState.getStencil() != *settings) ||
+ (fHWStencilClip != stencilClip) ||
+ (fHWDrawState.isStateFlagEnabled(kModifyStencilClip_StateBit) !=
+ drawClipToStencil);
+
+ if (stencilChange) {
+
+ // we can't simultaneously perform stencil-clipping and
+ // modify the stencil clip
+ GrAssert(!stencilClip || !drawClipToStencil);
+
+ if (settings->isDisabled()) {
+ if (stencilClip) {
+ settings = &gClipStencilSettings;
+ }
+ }
+
+ if (settings->isDisabled()) {
+ GL_CALL(Disable(GR_GL_STENCIL_TEST));
+ } else {
+ GL_CALL(Enable(GR_GL_STENCIL_TEST));
+ #if GR_DEBUG
+ if (!this->getCaps().fStencilWrapOpsSupport) {
+ GrAssert(settings->frontPassOp() != kIncWrap_StencilOp);
+ GrAssert(settings->frontPassOp() != kDecWrap_StencilOp);
+ GrAssert(settings->frontFailOp() != kIncWrap_StencilOp);
+ GrAssert(settings->backFailOp() != kDecWrap_StencilOp);
+ GrAssert(settings->backPassOp() != kIncWrap_StencilOp);
+ GrAssert(settings->backPassOp() != kDecWrap_StencilOp);
+ GrAssert(settings->backFailOp() != kIncWrap_StencilOp);
+ GrAssert(settings->frontFailOp() != kDecWrap_StencilOp);
+ }
+ #endif
+ int stencilBits = 0;
+ GrStencilBuffer* stencilBuffer =
+ drawState.getRenderTarget()->getStencilBuffer();
+ if (NULL != stencilBuffer) {
+ stencilBits = stencilBuffer->bits();
+ }
+ // TODO: dynamically attach a stencil buffer
+ GrAssert(stencilBits || settings->isDisabled());
+
+ GrGLuint clipStencilMask = 0;
+ GrGLuint userStencilMask = ~0;
+ if (stencilBits > 0) {
+ clipStencilMask = 1 << (stencilBits - 1);
+ userStencilMask = clipStencilMask - 1;
+ }
+
+ unsigned int frontRef = settings->frontFuncRef();
+ unsigned int frontMask = settings->frontFuncMask();
+ unsigned int frontWriteMask = settings->frontWriteMask();
+ GrGLenum frontFunc;
+
+ if (drawClipToStencil) {
+ GrAssert(settings->frontFunc() < kBasicStencilFuncCount);
+ frontFunc = grToGLStencilFunc[settings->frontFunc()];
+ } else {
+ frontFunc = grToGLStencilFunc[ConvertStencilFunc(
+ stencilClip, settings->frontFunc())];
+
+ ConvertStencilFuncAndMask(settings->frontFunc(),
+ stencilClip,
+ clipStencilMask,
+ userStencilMask,
+ &frontRef,
+ &frontMask);
+ frontWriteMask &= userStencilMask;
+ }
+ GrAssert((size_t)
+ settings->frontFailOp() < GR_ARRAY_COUNT(grToGLStencilOp));
+ GrAssert((size_t)
+ settings->frontPassOp() < GR_ARRAY_COUNT(grToGLStencilOp));
+ GrAssert((size_t)
+ settings->backFailOp() < GR_ARRAY_COUNT(grToGLStencilOp));
+ GrAssert((size_t)
+ settings->backPassOp() < GR_ARRAY_COUNT(grToGLStencilOp));
+ if (this->getCaps().fTwoSidedStencilSupport) {
+ GrGLenum backFunc;
+
+ unsigned int backRef = settings->backFuncRef();
+ unsigned int backMask = settings->backFuncMask();
+ unsigned int backWriteMask = settings->backWriteMask();
+
+
+ if (drawClipToStencil) {
+ GrAssert(settings->backFunc() < kBasicStencilFuncCount);
+ backFunc = grToGLStencilFunc[settings->backFunc()];
+ } else {
+ backFunc = grToGLStencilFunc[ConvertStencilFunc(
+ stencilClip, settings->backFunc())];
+ ConvertStencilFuncAndMask(settings->backFunc(),
+ stencilClip,
+ clipStencilMask,
+ userStencilMask,
+ &backRef,
+ &backMask);
+ backWriteMask &= userStencilMask;
+ }
+
+ GL_CALL(StencilFuncSeparate(GR_GL_FRONT, frontFunc,
+ frontRef, frontMask));
+ GL_CALL(StencilMaskSeparate(GR_GL_FRONT, frontWriteMask));
+ GL_CALL(StencilFuncSeparate(GR_GL_BACK, backFunc,
+ backRef, backMask));
+ GL_CALL(StencilMaskSeparate(GR_GL_BACK, backWriteMask));
+ GL_CALL(StencilOpSeparate(GR_GL_FRONT,
+ grToGLStencilOp[settings->frontFailOp()],
+ grToGLStencilOp[settings->frontPassOp()],
+ grToGLStencilOp[settings->frontPassOp()]));
+
+ GL_CALL(StencilOpSeparate(GR_GL_BACK,
+ grToGLStencilOp[settings->backFailOp()],
+ grToGLStencilOp[settings->backPassOp()],
+ grToGLStencilOp[settings->backPassOp()]));
+ } else {
+ GL_CALL(StencilFunc(frontFunc, frontRef, frontMask));
+ GL_CALL(StencilMask(frontWriteMask));
+ GL_CALL(StencilOp(grToGLStencilOp[settings->frontFailOp()],
+ grToGLStencilOp[settings->frontPassOp()],
+ grToGLStencilOp[settings->frontPassOp()]));
+ }
+ }
+ *fHWDrawState.stencil() = *settings;
+ fHWStencilClip = stencilClip;
+ }
+}
+
+void GrGpuGL::flushAAState(GrPrimitiveType type) {
+ const GrRenderTarget* rt = this->getDrawState().getRenderTarget();
+ if (kDesktop_GrGLBinding == this->glBinding()) {
+ // ES doesn't support toggling GL_MULTISAMPLE and doesn't have
+ // smooth lines.
+
+ // we prefer smooth lines over multisampled lines
+ // msaa should be disabled if drawing smooth lines.
+ if (GrIsPrimTypeLines(type)) {
+ bool smooth = this->willUseHWAALines();
+ if (!fHWAAState.fSmoothLineEnabled && smooth) {
+ GL_CALL(Enable(GR_GL_LINE_SMOOTH));
+ fHWAAState.fSmoothLineEnabled = true;
+ } else if (fHWAAState.fSmoothLineEnabled && !smooth) {
+ GL_CALL(Disable(GR_GL_LINE_SMOOTH));
+ fHWAAState.fSmoothLineEnabled = false;
+ }
+ if (rt->isMultisampled() &&
+ fHWAAState.fMSAAEnabled) {
+ GL_CALL(Disable(GR_GL_MULTISAMPLE));
+ fHWAAState.fMSAAEnabled = false;
+ }
+ } else if (rt->isMultisampled() &&
+ this->getDrawState().isHWAntialiasState() !=
+ fHWAAState.fMSAAEnabled) {
+ if (fHWAAState.fMSAAEnabled) {
+ GL_CALL(Disable(GR_GL_MULTISAMPLE));
+ fHWAAState.fMSAAEnabled = false;
+ } else {
+ GL_CALL(Enable(GR_GL_MULTISAMPLE));
+ fHWAAState.fMSAAEnabled = true;
+ }
+ }
+ }
+}
+
+void GrGpuGL::flushBlend(GrPrimitiveType type,
+ GrBlendCoeff srcCoeff,
+ GrBlendCoeff dstCoeff) {
+ if (GrIsPrimTypeLines(type) && this->willUseHWAALines()) {
+ if (fHWBlendDisabled) {
+ GL_CALL(Enable(GR_GL_BLEND));
+ fHWBlendDisabled = false;
+ }
+ if (kSA_BlendCoeff != fHWDrawState.getSrcBlendCoeff() ||
+ kISA_BlendCoeff != fHWDrawState.getDstBlendCoeff()) {
+ GL_CALL(BlendFunc(gXfermodeCoeff2Blend[kSA_BlendCoeff],
+ gXfermodeCoeff2Blend[kISA_BlendCoeff]));
+ fHWDrawState.setBlendFunc(kSA_BlendCoeff, kISA_BlendCoeff);
+ }
+ } else {
+ // any optimization to disable blending should
+ // have already been applied and tweaked the coeffs
+ // to (1, 0).
+ bool blendOff = kOne_BlendCoeff == srcCoeff &&
+ kZero_BlendCoeff == dstCoeff;
+ if (fHWBlendDisabled != blendOff) {
+ if (blendOff) {
+ GL_CALL(Disable(GR_GL_BLEND));
+ } else {
+ GL_CALL(Enable(GR_GL_BLEND));
+ }
+ fHWBlendDisabled = blendOff;
+ }
+ if (!blendOff) {
+ if (fHWDrawState.getSrcBlendCoeff() != srcCoeff ||
+ fHWDrawState.getDstBlendCoeff() != dstCoeff) {
+ GL_CALL(BlendFunc(gXfermodeCoeff2Blend[srcCoeff],
+ gXfermodeCoeff2Blend[dstCoeff]));
+ fHWDrawState.setBlendFunc(srcCoeff, dstCoeff);
+ }
+ GrColor blendConst = fCurrDrawState.getBlendConstant();
+ if ((BlendCoeffReferencesConstant(srcCoeff) ||
+ BlendCoeffReferencesConstant(dstCoeff)) &&
+ fHWDrawState.getBlendConstant() != blendConst) {
+
+ float c[] = {
+ GrColorUnpackR(blendConst) / 255.f,
+ GrColorUnpackG(blendConst) / 255.f,
+ GrColorUnpackB(blendConst) / 255.f,
+ GrColorUnpackA(blendConst) / 255.f
+ };
+ GL_CALL(BlendColor(c[0], c[1], c[2], c[3]));
+ fHWDrawState.setBlendConstant(blendConst);
+ }
+ }
+ }
+}
+
+namespace {
+
+unsigned gr_to_gl_filter(GrSamplerState::Filter filter) {
+ switch (filter) {
+ case GrSamplerState::kBilinear_Filter:
+ case GrSamplerState::k4x4Downsample_Filter:
+ return GR_GL_LINEAR;
+ case GrSamplerState::kNearest_Filter:
+ case GrSamplerState::kConvolution_Filter:
+ return GR_GL_NEAREST;
+ default:
+ GrAssert(!"Unknown filter type");
+ return GR_GL_LINEAR;
+ }
+}
+
+const GrGLenum* get_swizzle(GrPixelConfig config,
+ const GrSamplerState& sampler) {
+ if (GrPixelConfigIsAlphaOnly(config)) {
+ static const GrGLenum gAlphaSmear[] = { GR_GL_ALPHA, GR_GL_ALPHA,
+ GR_GL_ALPHA, GR_GL_ALPHA };
+ return gAlphaSmear;
+ } else if (sampler.swapsRAndB()) {
+ static const GrGLenum gRedBlueSwap[] = { GR_GL_BLUE, GR_GL_GREEN,
+ GR_GL_RED, GR_GL_ALPHA };
+ return gRedBlueSwap;
+ } else {
+ static const GrGLenum gStraight[] = { GR_GL_RED, GR_GL_GREEN,
+ GR_GL_BLUE, GR_GL_ALPHA };
+ return gStraight;
+ }
+}
+
+void set_tex_swizzle(GrGLenum swizzle[4], const GrGLInterface* gl) {
+ // should add texparameteri to interface to make 1 instead of 4 calls here
+ GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D,
+ GR_GL_TEXTURE_SWIZZLE_R,
+ swizzle[0]));
+ GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D,
+ GR_GL_TEXTURE_SWIZZLE_G,
+ swizzle[1]));
+ GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D,
+ GR_GL_TEXTURE_SWIZZLE_B,
+ swizzle[2]));
+ GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D,
+ GR_GL_TEXTURE_SWIZZLE_A,
+ swizzle[3]));
+}
+}
+
+bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) {
+
+ GrDrawState* drawState = this->drawState();
+ // GrGpu::setupClipAndFlushState should have already checked this
+ // and bailed if not true.
+ GrAssert(NULL != drawState->getRenderTarget());
+
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ // bind texture and set sampler state
+ if (this->isStageEnabled(s)) {
+ GrGLTexture* nextTexture =
+ static_cast<GrGLTexture*>(drawState->getTexture(s));
+
+ // true for now, but maybe not with GrEffect.
+ GrAssert(NULL != nextTexture);
+ // if we created a rt/tex and rendered to it without using a
+ // texture and now we're texuring from the rt it will still be
+ // the last bound texture, but it needs resolving. So keep this
+ // out of the "last != next" check.
+ GrGLRenderTarget* texRT =
+ static_cast<GrGLRenderTarget*>(nextTexture->asRenderTarget());
+ if (NULL != texRT) {
+ resolveRenderTarget(texRT);
+ }
+
+ if (fHWDrawState.getTexture(s) != nextTexture) {
+ setTextureUnit(s);
+ GL_CALL(BindTexture(GR_GL_TEXTURE_2D, nextTexture->textureID()));
+ #if GR_COLLECT_STATS
+ ++fStats.fTextureChngCnt;
+ #endif
+ //GrPrintf("---- bindtexture %d\n", nextTexture->textureID());
+ fHWDrawState.setTexture(s, nextTexture);
+ // The texture matrix has to compensate for texture width/height
+ // and NPOT-embedded-in-POT
+ fDirtyFlags.fTextureChangedMask |= (1 << s);
+ }
+
+ const GrSamplerState& sampler = drawState->getSampler(s);
+ ResetTimestamp timestamp;
+ const GrGLTexture::TexParams& oldTexParams =
+ nextTexture->getCachedTexParams(&timestamp);
+ bool setAll = timestamp < this->getResetTimestamp();
+ GrGLTexture::TexParams newTexParams;
+
+ newTexParams.fFilter = gr_to_gl_filter(sampler.getFilter());
+
+ const GrGLenum* wraps = GrGLTexture::WrapMode2GLWrap();
+ newTexParams.fWrapS = wraps[sampler.getWrapX()];
+ newTexParams.fWrapT = wraps[sampler.getWrapY()];
+ memcpy(newTexParams.fSwizzleRGBA,
+ get_swizzle(nextTexture->config(), sampler),
+ sizeof(newTexParams.fSwizzleRGBA));
+ if (setAll || newTexParams.fFilter != oldTexParams.fFilter) {
+ setTextureUnit(s);
+ GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+ GR_GL_TEXTURE_MAG_FILTER,
+ newTexParams.fFilter));
+ GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+ GR_GL_TEXTURE_MIN_FILTER,
+ newTexParams.fFilter));
+ }
+ if (setAll || newTexParams.fWrapS != oldTexParams.fWrapS) {
+ setTextureUnit(s);
+ GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+ GR_GL_TEXTURE_WRAP_S,
+ newTexParams.fWrapS));
+ }
+ if (setAll || newTexParams.fWrapT != oldTexParams.fWrapT) {
+ setTextureUnit(s);
+ GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+ GR_GL_TEXTURE_WRAP_T,
+ newTexParams.fWrapT));
+ }
+ if (this->glCaps().fTextureSwizzleSupport &&
+ (setAll ||
+ memcmp(newTexParams.fSwizzleRGBA,
+ oldTexParams.fSwizzleRGBA,
+ sizeof(newTexParams.fSwizzleRGBA)))) {
+ setTextureUnit(s);
+ set_tex_swizzle(newTexParams.fSwizzleRGBA,
+ this->glInterface());
+ }
+ nextTexture->setCachedTexParams(newTexParams,
+ this->getResetTimestamp());
+ }
+ }
+
+ GrIRect* rect = NULL;
+ GrIRect clipBounds;
+ if (drawState->isClipState() &&
+ fClip.hasConservativeBounds()) {
+ fClip.getConservativeBounds().roundOut(&clipBounds);
+ rect = &clipBounds;
+ }
+ this->flushRenderTarget(rect);
+ this->flushAAState(type);
+
+ if (drawState->isDitherState() != fHWDrawState.isDitherState()) {
+ if (drawState->isDitherState()) {
+ GL_CALL(Enable(GR_GL_DITHER));
+ } else {
+ GL_CALL(Disable(GR_GL_DITHER));
+ }
+ }
+
+ if (drawState->isColorWriteDisabled() !=
+ fHWDrawState.isColorWriteDisabled()) {
+ GrGLenum mask;
+ if (drawState->isColorWriteDisabled()) {
+ mask = GR_GL_FALSE;
+ } else {
+ mask = GR_GL_TRUE;
+ }
+ GL_CALL(ColorMask(mask, mask, mask, mask));
+ }
+
+ if (fHWDrawState.getDrawFace() != drawState->getDrawFace()) {
+ switch (fCurrDrawState.getDrawFace()) {
+ case GrDrawState::kCCW_DrawFace:
+ GL_CALL(Enable(GR_GL_CULL_FACE));
+ GL_CALL(CullFace(GR_GL_BACK));
+ break;
+ case GrDrawState::kCW_DrawFace:
+ GL_CALL(Enable(GR_GL_CULL_FACE));
+ GL_CALL(CullFace(GR_GL_FRONT));
+ break;
+ case GrDrawState::kBoth_DrawFace:
+ GL_CALL(Disable(GR_GL_CULL_FACE));
+ break;
+ default:
+ GrCrash("Unknown draw face.");
+ }
+ fHWDrawState.setDrawFace(drawState->getDrawFace());
+ }
+
+#if GR_DEBUG
+ // check for circular rendering
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ GrAssert(!this->isStageEnabled(s) ||
+ NULL == drawState->getRenderTarget() ||
+ NULL == drawState->getTexture(s) ||
+ drawState->getTexture(s)->asRenderTarget() !=
+ drawState->getRenderTarget());
+ }
+#endif
+
+ this->flushStencil();
+
+ // This copy must happen after flushStencil() is called. flushStencil()
+ // relies on detecting when the kModifyStencilClip_StateBit state has
+ // changed since the last draw.
+ fHWDrawState.copyStateFlags(*drawState);
+ return true;
+}
+
+void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
+ if (fHWGeometryState.fVertexBuffer != buffer) {
+ fHWGeometryState.fArrayPtrsDirty = true;
+ fHWGeometryState.fVertexBuffer = buffer;
+ }
+}
+
+void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
+ if (fHWGeometryState.fVertexBuffer == buffer) {
+ // deleting bound buffer does implied bind to 0
+ fHWGeometryState.fVertexBuffer = NULL;
+ fHWGeometryState.fArrayPtrsDirty = true;
+ }
+}
+
+void GrGpuGL::notifyIndexBufferBind(const GrGLIndexBuffer* buffer) {
+ fHWGeometryState.fIndexBuffer = buffer;
+}
+
+void GrGpuGL::notifyIndexBufferDelete(const GrGLIndexBuffer* buffer) {
+ if (fHWGeometryState.fIndexBuffer == buffer) {
+ // deleting bound buffer does implied bind to 0
+ fHWGeometryState.fIndexBuffer = NULL;
+ }
+}
+
+void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) {
+ GrAssert(NULL != renderTarget);
+ GrDrawState* drawState = this->drawState();
+ if (drawState->getRenderTarget() == renderTarget) {
+ drawState->setRenderTarget(NULL);
+ }
+ if (fHWDrawState.getRenderTarget() == renderTarget) {
+ fHWDrawState.setRenderTarget(NULL);
+ }
+}
+
+void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ GrDrawState* drawState = this->drawState();
+ if (drawState->getTexture(s) == texture) {
+ fCurrDrawState.setTexture(s, NULL);
+ }
+ if (fHWDrawState.getTexture(s) == texture) {
+ // deleting bound texture does implied bind to 0
+ fHWDrawState.setTexture(s, NULL);
+ }
+ }
+}
+
+bool GrGpuGL::configToGLFormats(GrPixelConfig config,
+ bool getSizedInternalFormat,
+ GrGLenum* internalFormat,
+ GrGLenum* externalFormat,
+ GrGLenum* externalType) {
+ GrGLenum dontCare;
+ if (NULL == internalFormat) {
+ internalFormat = &dontCare;
+ }
+ if (NULL == externalFormat) {
+ externalFormat = &dontCare;
+ }
+ if (NULL == externalType) {
+ externalType = &dontCare;
+ }
+
+ switch (config) {
+ case kRGBA_8888_PM_GrPixelConfig:
+ case kRGBA_8888_UPM_GrPixelConfig:
+ *internalFormat = GR_GL_RGBA;
+ *externalFormat = GR_GL_RGBA;
+ if (getSizedInternalFormat) {
+ *internalFormat = GR_GL_RGBA8;
+ } else {
+ *internalFormat = GR_GL_RGBA;
+ }
+ *externalType = GR_GL_UNSIGNED_BYTE;
+ break;
+ case kBGRA_8888_PM_GrPixelConfig:
+ case kBGRA_8888_UPM_GrPixelConfig:
+ if (!fGLCaps.fBGRAFormatSupport) {
+ return false;
+ }
+ if (fGLCaps.fBGRAIsInternalFormat) {
+ if (getSizedInternalFormat) {
+ *internalFormat = GR_GL_BGRA8;
+ } else {
+ *internalFormat = GR_GL_BGRA;
+ }
+ } else {
+ if (getSizedInternalFormat) {
+ *internalFormat = GR_GL_RGBA8;
+ } else {
+ *internalFormat = GR_GL_RGBA;
+ }
+ }
+ *externalFormat = GR_GL_BGRA;
+ *externalType = GR_GL_UNSIGNED_BYTE;
+ break;
+ case kRGB_565_GrPixelConfig:
+ *internalFormat = GR_GL_RGB;
+ *externalFormat = GR_GL_RGB;
+ if (getSizedInternalFormat) {
+ if (this->glBinding() == kDesktop_GrGLBinding) {
+ return false;
+ } else {
+ *internalFormat = GR_GL_RGB565;
+ }
+ } else {
+ *internalFormat = GR_GL_RGB;
+ }
+ *externalType = GR_GL_UNSIGNED_SHORT_5_6_5;
+ break;
+ case kRGBA_4444_GrPixelConfig:
+ *internalFormat = GR_GL_RGBA;
+ *externalFormat = GR_GL_RGBA;
+ if (getSizedInternalFormat) {
+ *internalFormat = GR_GL_RGBA4;
+ } else {
+ *internalFormat = GR_GL_RGBA;
+ }
+ *externalType = GR_GL_UNSIGNED_SHORT_4_4_4_4;
+ break;
+ case kIndex_8_GrPixelConfig:
+ if (this->getCaps().f8BitPaletteSupport) {
+ *internalFormat = GR_GL_PALETTE8_RGBA8;
+ // glCompressedTexImage doesn't take external params
+ *externalFormat = GR_GL_PALETTE8_RGBA8;
+ // no sized/unsized internal format distinction here
+ *internalFormat = GR_GL_PALETTE8_RGBA8;
+ // unused with CompressedTexImage
+ *externalType = GR_GL_UNSIGNED_BYTE;
+ } else {
+ return false;
+ }
+ break;
+ case kAlpha_8_GrPixelConfig:
+ *internalFormat = GR_GL_ALPHA;
+ *externalFormat = GR_GL_ALPHA;
+ if (getSizedInternalFormat) {
+ *internalFormat = GR_GL_ALPHA8;
+ } else {
+ *internalFormat = GR_GL_ALPHA;
+ }
+ *externalType = GR_GL_UNSIGNED_BYTE;
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+void GrGpuGL::setTextureUnit(int unit) {
+ GrAssert(unit >= 0 && unit < GrDrawState::kNumStages);
+ if (fActiveTextureUnitIdx != unit) {
+ GL_CALL(ActiveTexture(GR_GL_TEXTURE0 + unit));
+ fActiveTextureUnitIdx = unit;
+ }
+}
+
+void GrGpuGL::setSpareTextureUnit() {
+ if (fActiveTextureUnitIdx != (GR_GL_TEXTURE0 + SPARE_TEX_UNIT)) {
+ GL_CALL(ActiveTexture(GR_GL_TEXTURE0 + SPARE_TEX_UNIT));
+ fActiveTextureUnitIdx = SPARE_TEX_UNIT;
+ }
+}
+
+void GrGpuGL::resetDirtyFlags() {
+ Gr_bzero(&fDirtyFlags, sizeof(fDirtyFlags));
+}
+
+void GrGpuGL::setBuffers(bool indexed,
+ int* extraVertexOffset,
+ int* extraIndexOffset) {
+
+ GrAssert(NULL != extraVertexOffset);
+
+ const GeometryPoolState& geoPoolState = this->getGeomPoolState();
+
+ GrGLVertexBuffer* vbuf;
+ switch (this->getGeomSrc().fVertexSrc) {
+ case kBuffer_GeometrySrcType:
+ *extraVertexOffset = 0;
+ vbuf = (GrGLVertexBuffer*) this->getGeomSrc().fVertexBuffer;
+ break;
+ case kArray_GeometrySrcType:
+ case kReserved_GeometrySrcType:
+ this->finalizeReservedVertices();
+ *extraVertexOffset = geoPoolState.fPoolStartVertex;
+ vbuf = (GrGLVertexBuffer*) geoPoolState.fPoolVertexBuffer;
+ break;
+ default:
+ vbuf = NULL; // suppress warning
+ GrCrash("Unknown geometry src type!");
+ }
+
+ GrAssert(NULL != vbuf);
+ GrAssert(!vbuf->isLocked());
+ if (fHWGeometryState.fVertexBuffer != vbuf) {
+ GL_CALL(BindBuffer(GR_GL_ARRAY_BUFFER, vbuf->bufferID()));
+ fHWGeometryState.fArrayPtrsDirty = true;
+ fHWGeometryState.fVertexBuffer = vbuf;
+ }
+
+ if (indexed) {
+ GrAssert(NULL != extraIndexOffset);
+
+ GrGLIndexBuffer* ibuf;
+ switch (this->getGeomSrc().fIndexSrc) {
+ case kBuffer_GeometrySrcType:
+ *extraIndexOffset = 0;
+ ibuf = (GrGLIndexBuffer*)this->getGeomSrc().fIndexBuffer;
+ break;
+ case kArray_GeometrySrcType:
+ case kReserved_GeometrySrcType:
+ this->finalizeReservedIndices();
+ *extraIndexOffset = geoPoolState.fPoolStartIndex;
+ ibuf = (GrGLIndexBuffer*) geoPoolState.fPoolIndexBuffer;
+ break;
+ default:
+ ibuf = NULL; // suppress warning
+ GrCrash("Unknown geometry src type!");
+ }
+
+ GrAssert(NULL != ibuf);
+ GrAssert(!ibuf->isLocked());
+ if (fHWGeometryState.fIndexBuffer != ibuf) {
+ GL_CALL(BindBuffer(GR_GL_ELEMENT_ARRAY_BUFFER, ibuf->bufferID()));
+ fHWGeometryState.fIndexBuffer = ibuf;
+ }
+ }
+}
+
+int GrGpuGL::getMaxEdges() const {
+ // FIXME: This is a pessimistic estimate based on how many other things
+ // want to add uniforms. This should be centralized somewhere.
+ return GR_CT_MIN(fGLCaps.fMaxFragmentUniformVectors - 8,
+ GrDrawState::kMaxEdges);
+}
+
+void GrGpuGL::GLCaps::print() const {
+ for (int i = 0; i < fStencilFormats.count(); ++i) {
+ GrPrintf("Stencil Format %d, stencil bits: %02d, total bits: %02d\n",
+ i,
+ fStencilFormats[i].fStencilBits,
+ fStencilFormats[i].fTotalBits);
+ }
+
+ GR_STATIC_ASSERT(0 == kNone_MSFBO);
+ GR_STATIC_ASSERT(1 == kDesktopARB_MSFBO);
+ GR_STATIC_ASSERT(2 == kDesktopEXT_MSFBO);
+ GR_STATIC_ASSERT(3 == kAppleES_MSFBO);
+ static const char* gMSFBOExtStr[] = {
+ "None",
+ "ARB",
+ "EXT",
+ "Apple",
+ };
+ GrPrintf("MSAA Type: %s\n", gMSFBOExtStr[fMSFBOType]);
+ for (int i = 0; i < (int)GR_ARRAY_COUNT(fAASamples); ++i) {
+ GrPrintf("AA Level %d has %d samples\n", i, fAASamples[i]);
+ }
+ GrPrintf("Max FS Uniform Vectors: %d\n", fMaxFragmentUniformVectors);
+ GrPrintf("Support RGBA8 Render Buffer: %s\n",
+ (fRGBA8RenderbufferSupport ? "YES": "NO"));
+ GrPrintf("BGRA is an internal format: %s\n",
+ (fBGRAIsInternalFormat ? "YES": "NO"));
+ GrPrintf("Support texture swizzle: %s\n",
+ (fTextureSwizzleSupport ? "YES": "NO"));
+ GrPrintf("Unpack Row length support: %s\n",
+ (fUnpackRowLengthSupport ? "YES": "NO"));
+ GrPrintf("Unpack Flip Y support: %s\n",
+ (fUnpackFlipYSupport ? "YES": "NO"));
+ GrPrintf("Pack Row length support: %s\n",
+ (fPackRowLengthSupport ? "YES": "NO"));
+ GrPrintf("Pack Flip Y support: %s\n",
+ (fPackFlipYSupport ? "YES": "NO"));
+}
diff --git a/src/gpu/GrGpuGL.h b/src/gpu/GrGpuGL.h
new file mode 100644
index 0000000..36fead1
--- /dev/null
+++ b/src/gpu/GrGpuGL.h
@@ -0,0 +1,334 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrGpuGL_DEFINED
+#define GrGpuGL_DEFINED
+
+#include "GrDrawState.h"
+#include "GrGpu.h"
+#include "GrGLIndexBuffer.h"
+#include "GrGLIRect.h"
+#include "GrGLStencilBuffer.h"
+#include "GrGLTexture.h"
+#include "GrGLVertexBuffer.h"
+
+#include "SkString.h"
+
+class GrGpuGL : public GrGpu {
+public:
+ virtual ~GrGpuGL();
+
+ const GrGLInterface* glInterface() const { return fGL; }
+ GrGLBinding glBinding() const { return fGLBinding; }
+ GrGLVersion glVersion() const { return fGLVersion; }
+
+ // GrGpu overrides
+ virtual GrPixelConfig preferredReadPixelsConfig(GrPixelConfig config)
+ const SK_OVERRIDE;
+ virtual GrPixelConfig preferredWritePixelsConfig(GrPixelConfig config)
+ const SK_OVERRIDE;
+ virtual bool readPixelsWillPayForYFlip(
+ GrRenderTarget* renderTarget,
+ int left, int top,
+ int width, int height,
+ GrPixelConfig config,
+ size_t rowBytes) const SK_OVERRIDE;
+ virtual bool fullReadPixelsIsFasterThanPartial() const SK_OVERRIDE;
+protected:
+ GrGpuGL(const GrGLInterface* glInterface, GrGLBinding glBinding);
+
+ struct GLCaps {
+ GLCaps()
+ // make defaults be the most restrictive
+ : fStencilFormats(8) // prealloc space for stencil formats
+ , fMSFBOType(kNone_MSFBO)
+ , fMaxFragmentUniformVectors(0)
+ , fRGBA8RenderbufferSupport(false)
+ , fBGRAFormatSupport(false)
+ , fBGRAIsInternalFormat(false)
+ , fTextureSwizzleSupport(false)
+ , fUnpackRowLengthSupport(false)
+ , fUnpackFlipYSupport(false)
+ , fPackRowLengthSupport(false)
+ , fPackFlipYSupport(false)
+ , fTextureUsageSupport(false)
+ , fTexStorageSupport(false) {
+ memset(fAASamples, 0, sizeof(fAASamples));
+ }
+ SkTArray<GrGLStencilBuffer::Format, true> fStencilFormats;
+
+ enum {
+ /**
+ * no support for MSAA FBOs
+ */
+ kNone_MSFBO = 0,
+ /**
+ * GL3.0-style MSAA FBO (GL_ARB_framebuffer_object)
+ */
+ kDesktopARB_MSFBO,
+ /**
+ * earlier GL_EXT_framebuffer* extensions
+ */
+ kDesktopEXT_MSFBO,
+ /**
+ * GL_APPLE_framebuffer_multisample ES extension
+ */
+ kAppleES_MSFBO,
+ } fMSFBOType;
+
+ // TODO: get rid of GrAALevel and use sample cnt directly
+ GrGLuint fAASamples[4];
+
+ // The maximum number of fragment uniform vectors (GLES has min. 16).
+ int fMaxFragmentUniformVectors;
+
+ // ES requires an extension to support RGBA8 in RenderBufferStorage
+ bool fRGBA8RenderbufferSupport;
+
+ // Is GL_BGRA supported
+ bool fBGRAFormatSupport;
+
+ // Depending on the ES extensions present the BGRA external format may
+ // correspond either a BGRA or RGBA internalFormat. On desktop GL it is
+ // RGBA
+ bool fBGRAIsInternalFormat;
+
+ // GL_ARB_texture_swizzle support
+ bool fTextureSwizzleSupport;
+
+ // Is there support for GL_UNPACK_ROW_LENGTH
+ bool fUnpackRowLengthSupport;
+
+ // Is there support for GL_UNPACK_FLIP_Y
+ bool fUnpackFlipYSupport;
+
+ // Is there support for GL_PACK_ROW_LENGTH
+ bool fPackRowLengthSupport;
+
+ // Is there support for GL_PACK_REVERSE_ROW_ORDER
+ bool fPackFlipYSupport;
+
+ // Is there support for texture parameter GL_TEXTURE_USAGE
+ bool fTextureUsageSupport;
+
+ // Is there support for glTexStorage
+ bool fTexStorageSupport;
+
+ void print() const;
+ } fGLCaps;
+
+ struct {
+ size_t fVertexOffset;
+ GrVertexLayout fVertexLayout;
+ const GrVertexBuffer* fVertexBuffer;
+ const GrIndexBuffer* fIndexBuffer;
+ bool fArrayPtrsDirty;
+ } fHWGeometryState;
+
+ struct AAState {
+ bool fMSAAEnabled;
+ bool fSmoothLineEnabled;
+ } fHWAAState;
+
+ GrDrawState fHWDrawState;
+ bool fHWStencilClip;
+
+ // As flush of GL state proceeds it updates fHDrawState
+ // to reflect the new state. Later parts of the state flush
+ // may perform cascaded changes but cannot refer to fHWDrawState.
+ // These code paths can refer to the dirty flags. Subclass should
+ // call resetDirtyFlags after its flush is complete
+ struct {
+ bool fRenderTargetChanged : 1;
+ int fTextureChangedMask;
+ } fDirtyFlags;
+ GR_STATIC_ASSERT(8 * sizeof(int) >= GrDrawState::kNumStages);
+
+ // clears the dirty flags
+ void resetDirtyFlags();
+
+ // last scissor / viewport scissor state seen by the GL.
+ struct {
+ bool fScissorEnabled;
+ GrGLIRect fScissorRect;
+ GrGLIRect fViewportRect;
+ } fHWBounds;
+
+ const GLCaps& glCaps() const { return fGLCaps; }
+
+ // GrGpu overrides
+ virtual void onResetContext() SK_OVERRIDE;
+
+ virtual GrTexture* onCreateTexture(const GrTextureDesc& desc,
+ const void* srcData,
+ size_t rowBytes);
+ virtual GrVertexBuffer* onCreateVertexBuffer(uint32_t size,
+ bool dynamic);
+ virtual GrIndexBuffer* onCreateIndexBuffer(uint32_t size,
+ bool dynamic);
+ virtual GrResource* onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc);
+ virtual GrTexture* onCreatePlatformTexture(const GrPlatformTextureDesc& desc) SK_OVERRIDE;
+ virtual GrRenderTarget* onCreatePlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) SK_OVERRIDE;
+ virtual bool createStencilBufferForRenderTarget(GrRenderTarget* rt,
+ int width, int height);
+ virtual bool attachStencilBufferToRenderTarget(GrStencilBuffer* sb,
+ GrRenderTarget* rt);
+
+ virtual void onClear(const GrIRect* rect, GrColor color);
+
+ virtual void onForceRenderTargetFlush();
+
+ virtual bool onReadPixels(GrRenderTarget* target,
+ int left, int top,
+ int width, int height,
+ GrPixelConfig,
+ void* buffer,
+ size_t rowBytes,
+ bool invertY) SK_OVERRIDE;
+
+ virtual void onWriteTexturePixels(GrTexture* texture,
+ int left, int top, int width, int height,
+ GrPixelConfig config, const void* buffer,
+ size_t rowBytes) SK_OVERRIDE;
+
+ virtual void onGpuDrawIndexed(GrPrimitiveType type,
+ uint32_t startVertex,
+ uint32_t startIndex,
+ uint32_t vertexCount,
+ uint32_t indexCount);
+ virtual void onGpuDrawNonIndexed(GrPrimitiveType type,
+ uint32_t vertexCount,
+ uint32_t numVertices);
+ virtual void flushScissor(const GrIRect* rect);
+ virtual void clearStencil();
+ virtual void clearStencilClip(const GrIRect& rect, bool insideClip);
+ virtual int getMaxEdges() const;
+
+ // binds texture unit in GL
+ void setTextureUnit(int unitIdx);
+
+ // binds appropriate vertex and index buffers, also returns any extra
+ // extra verts or indices to offset by.
+ void setBuffers(bool indexed,
+ int* extraVertexOffset,
+ int* extraIndexOffset);
+
+ // flushes state that is common to fixed and programmable GL
+ // dither
+ // line smoothing
+ // texture binding
+ // sampler state (filtering, tiling)
+ // FBO binding
+ // line width
+ bool flushGLStateCommon(GrPrimitiveType type);
+
+ // Subclasses should call this to flush the blend state.
+ // The params should be the final coeffecients to apply
+ // (after any blending optimizations or dual source blending considerations
+ // have been accounted for).
+ void flushBlend(GrPrimitiveType type,
+ GrBlendCoeff srcCoeff,
+ GrBlendCoeff dstCoeff);
+
+ bool hasExtension(const char* ext) {
+ return GrGLHasExtensionFromString(ext, fExtensionString.c_str());
+ }
+
+ // adjusts texture matrix to account for orientation
+ static void AdjustTextureMatrix(const GrGLTexture* texture,
+ GrSamplerState::SampleMode mode,
+ GrMatrix* matrix);
+
+ // subclass may try to take advantage of identity tex matrices.
+ // This helper determines if matrix will be identity after all
+ // adjustments are applied.
+ static bool TextureMatrixIsIdentity(const GrGLTexture* texture,
+ const GrSamplerState& sampler);
+
+ static bool BlendCoeffReferencesConstant(GrBlendCoeff coeff);
+
+private:
+ // Inits GrDrawTarget::Caps and GLCaps, sublcass may enable
+ // additional caps.
+ void initCaps();
+
+ void initFSAASupport();
+
+ // determines valid stencil formats
+ void initStencilFormats();
+
+ // notify callbacks to update state tracking when related
+ // objects are bound to GL or deleted outside of the class
+ void notifyVertexBufferBind(const GrGLVertexBuffer* buffer);
+ void notifyVertexBufferDelete(const GrGLVertexBuffer* buffer);
+ void notifyIndexBufferBind(const GrGLIndexBuffer* buffer);
+ void notifyIndexBufferDelete(const GrGLIndexBuffer* buffer);
+ void notifyTextureDelete(GrGLTexture* texture);
+ void notifyRenderTargetDelete(GrRenderTarget* renderTarget);
+
+ void setSpareTextureUnit();
+
+ // bound is region that may be modified and therefore has to be resolved.
+ // NULL means whole target. Can be an empty rect.
+ void flushRenderTarget(const GrIRect* bound);
+ void flushStencil();
+ void flushAAState(GrPrimitiveType type);
+
+ void resolveRenderTarget(GrGLRenderTarget* texture);
+
+ bool configToGLFormats(GrPixelConfig config,
+ bool getSizedInternal,
+ GrGLenum* internalFormat,
+ GrGLenum* externalFormat,
+ GrGLenum* externalType);
+ // helper for onCreateTexture and writeTexturePixels
+ bool uploadTexData(const GrGLTexture::Desc& desc,
+ bool isNewTexture,
+ int left, int top, int width, int height,
+ GrPixelConfig dataConfig,
+ const void* data,
+ size_t rowBytes);
+
+ bool createRenderTargetObjects(int width, int height,
+ GrGLuint texID,
+ GrGLRenderTarget::Desc* desc);
+
+ friend class GrGLVertexBuffer;
+ friend class GrGLIndexBuffer;
+ friend class GrGLTexture;
+ friend class GrGLRenderTarget;
+
+ // read these once at begining and then never again
+ SkString fExtensionString;
+ GrGLVersion fGLVersion;
+
+ // we want to clear stencil buffers when they are created. We want to clear
+ // the entire buffer even if it is larger than the color attachment. We
+ // attach it to this fbo with no color attachment to do the initial clear.
+ GrGLuint fStencilClearFBO;
+
+ bool fHWBlendDisabled;
+
+ int fActiveTextureUnitIdx;
+
+ // we record what stencil format worked last time to hopefully exit early
+ // from our loop that tries stencil formats and calls check fb status.
+ int fLastSuccessfulStencilFmtIdx;
+
+ const GrGLInterface* fGL;
+ GrGLBinding fGLBinding;
+
+ bool fPrintedCaps;
+
+ typedef GrGpu INHERITED;
+};
+
+#endif
+
diff --git a/src/gpu/GrGpuGLShaders.cpp b/src/gpu/GrGpuGLShaders.cpp
new file mode 100644
index 0000000..c203168
--- /dev/null
+++ b/src/gpu/GrGpuGLShaders.cpp
@@ -0,0 +1,1137 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrBinHashKey.h"
+#include "GrGLProgram.h"
+#include "GrGLSL.h"
+#include "GrGpuGLShaders.h"
+#include "GrGpuVertex.h"
+#include "GrNoncopyable.h"
+#include "GrStringBuilder.h"
+#include "GrRandom.h"
+
+#define SKIP_CACHE_CHECK true
+#define GR_UINT32_MAX static_cast<uint32_t>(-1)
+
+#include "GrTHashCache.h"
+
+class GrGpuGLShaders::ProgramCache : public ::GrNoncopyable {
+private:
+ class Entry;
+
+ typedef GrBinHashKey<Entry, GrGLProgram::kProgramKeySize> ProgramHashKey;
+
+ class Entry : public ::GrNoncopyable {
+ public:
+ Entry() {}
+ void copyAndTakeOwnership(Entry& entry) {
+ fProgramData.copyAndTakeOwnership(entry.fProgramData);
+ fKey = entry.fKey; // ownership transfer
+ fLRUStamp = entry.fLRUStamp;
+ }
+
+ public:
+ int compare(const ProgramHashKey& key) const { return fKey.compare(key); }
+
+ public:
+ GrGLProgram::CachedData fProgramData;
+ ProgramHashKey fKey;
+ unsigned int fLRUStamp;
+ };
+
+ GrTHashTable<Entry, ProgramHashKey, 8> fHashCache;
+
+ // We may have kMaxEntries+1 shaders in the GL context because
+ // we create a new shader before evicting from the cache.
+ enum {
+ kMaxEntries = 32
+ };
+ Entry fEntries[kMaxEntries];
+ int fCount;
+ unsigned int fCurrLRUStamp;
+ const GrGLInterface* fGL;
+ GrGLSLGeneration fGLSLGeneration;
+
+public:
+ ProgramCache(const GrGLInterface* gl,
+ GrGLSLGeneration glslGeneration)
+ : fCount(0)
+ , fCurrLRUStamp(0)
+ , fGL(gl)
+ , fGLSLGeneration(glslGeneration) {
+ }
+
+ ~ProgramCache() {
+ for (int i = 0; i < fCount; ++i) {
+ GrGpuGLShaders::DeleteProgram(fGL, &fEntries[i].fProgramData);
+ }
+ }
+
+ void abandon() {
+ fCount = 0;
+ }
+
+ void invalidateViewMatrices() {
+ for (int i = 0; i < fCount; ++i) {
+ // set to illegal matrix
+ fEntries[i].fProgramData.fViewMatrix = GrMatrix::InvalidMatrix();
+ }
+ }
+
+ GrGLProgram::CachedData* getProgramData(const GrGLProgram& desc) {
+ Entry newEntry;
+ newEntry.fKey.setKeyData(desc.keyData());
+
+ Entry* entry = fHashCache.find(newEntry.fKey);
+ if (NULL == entry) {
+ if (!desc.genProgram(fGL, fGLSLGeneration,
+ &newEntry.fProgramData)) {
+ return NULL;
+ }
+ if (fCount < kMaxEntries) {
+ entry = fEntries + fCount;
+ ++fCount;
+ } else {
+ GrAssert(kMaxEntries == fCount);
+ entry = fEntries;
+ for (int i = 1; i < kMaxEntries; ++i) {
+ if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
+ entry = fEntries + i;
+ }
+ }
+ fHashCache.remove(entry->fKey, entry);
+ GrGpuGLShaders::DeleteProgram(fGL, &entry->fProgramData);
+ }
+ entry->copyAndTakeOwnership(newEntry);
+ fHashCache.insert(entry->fKey, entry);
+ }
+
+ entry->fLRUStamp = fCurrLRUStamp;
+ if (GR_UINT32_MAX == fCurrLRUStamp) {
+ // wrap around! just trash our LRU, one time hit.
+ for (int i = 0; i < fCount; ++i) {
+ fEntries[i].fLRUStamp = 0;
+ }
+ }
+ ++fCurrLRUStamp;
+ return &entry->fProgramData;
+ }
+};
+
+void GrGpuGLShaders::abandonResources(){
+ INHERITED::abandonResources();
+ fProgramCache->abandon();
+}
+
+void GrGpuGLShaders::DeleteProgram(const GrGLInterface* gl,
+ CachedData* programData) {
+ GR_GL_CALL(gl, DeleteShader(programData->fVShaderID));
+ if (programData->fGShaderID) {
+ GR_GL_CALL(gl, DeleteShader(programData->fGShaderID));
+ }
+ GR_GL_CALL(gl, DeleteShader(programData->fFShaderID));
+ GR_GL_CALL(gl, DeleteProgram(programData->fProgramID));
+ GR_DEBUGCODE(memset(programData, 0, sizeof(*programData));)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define GL_CALL(X) GR_GL_CALL(this->glInterface(), X)
+
+namespace {
+
+// GrRandoms nextU() values have patterns in the low bits
+// So using nextU() % array_count might never take some values.
+int random_int(GrRandom* r, int count) {
+ return (int)(r->nextF() * count);
+}
+
+// min is inclusive, max is exclusive
+int random_int(GrRandom* r, int min, int max) {
+ return (int)(r->nextF() * (max-min)) + min;
+}
+
+bool random_bool(GrRandom* r) {
+ return r->nextF() > .5f;
+}
+
+}
+
+bool GrGpuGLShaders::programUnitTest() {
+
+ GrGLSLGeneration glslGeneration =
+ GetGLSLGeneration(this->glBinding(), this->glInterface());
+ static const int STAGE_OPTS[] = {
+ 0,
+ StageDesc::kNoPerspective_OptFlagBit,
+ StageDesc::kIdentity_CoordMapping
+ };
+ static const int IN_CONFIG_FLAGS[] = {
+ StageDesc::kNone_InConfigFlag,
+ StageDesc::kSwapRAndB_InConfigFlag,
+ StageDesc::kSwapRAndB_InConfigFlag | StageDesc::kMulRGBByAlpha_InConfigFlag,
+ StageDesc::kMulRGBByAlpha_InConfigFlag,
+ StageDesc::kSmearAlpha_InConfigFlag,
+ };
+ GrGLProgram program;
+ ProgramDesc& pdesc = program.fProgramDesc;
+
+ static const int NUM_TESTS = 512;
+
+ GrRandom random;
+ for (int t = 0; t < NUM_TESTS; ++t) {
+
+#if 0
+ GrPrintf("\nTest Program %d\n-------------\n", t);
+ static const int stop = -1;
+ if (t == stop) {
+ int breakpointhere = 9;
+ }
+#endif
+
+ pdesc.fVertexLayout = 0;
+ pdesc.fEmitsPointSize = random.nextF() > .5f;
+ pdesc.fColorInput = random_int(&random, ProgramDesc::kColorInputCnt);
+
+ pdesc.fColorFilterXfermode = random_int(&random, SkXfermode::kCoeffModesCnt);
+
+ pdesc.fFirstCoverageStage = random_int(&random, GrDrawState::kNumStages);
+
+ pdesc.fVertexLayout |= random_bool(&random) ?
+ GrDrawTarget::kCoverage_VertexLayoutBit :
+ 0;
+
+#if GR_GL_EXPERIMENTAL_GS
+ pdesc.fExperimentalGS = this->getCaps().fGeometryShaderSupport &&
+ random_bool(&random);
+#endif
+ pdesc.fOutputPM = random_int(&random, ProgramDesc::kOutputPMCnt);
+
+ bool edgeAA = random_bool(&random);
+ if (edgeAA) {
+ bool vertexEdgeAA = random_bool(&random);
+ if (vertexEdgeAA) {
+ pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
+ if (this->getCaps().fShaderDerivativeSupport) {
+ pdesc.fVertexEdgeType = random_bool(&random) ?
+ GrDrawState::kHairQuad_EdgeType :
+ GrDrawState::kHairLine_EdgeType;
+ } else {
+ pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
+ }
+ pdesc.fEdgeAANumEdges = 0;
+ } else {
+ pdesc.fEdgeAANumEdges = random_int(&random, 1, this->getMaxEdges());
+ pdesc.fEdgeAAConcave = random_bool(&random);
+ }
+ } else {
+ pdesc.fEdgeAANumEdges = 0;
+ }
+
+ pdesc.fColorMatrixEnabled = random_bool(&random);
+
+ if (this->getCaps().fDualSourceBlendingSupport) {
+ pdesc.fDualSrcOutput = random_int(&random, ProgramDesc::kDualSrcOutputCnt);
+ } else {
+ pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
+ }
+
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ // enable the stage?
+ if (random_bool(&random)) {
+ // use separate tex coords?
+ if (random_bool(&random)) {
+ int t = random_int(&random, GrDrawState::kMaxTexCoords);
+ pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
+ } else {
+ pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
+ }
+ }
+ // use text-formatted verts?
+ if (random_bool(&random)) {
+ pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
+ }
+ StageDesc& stage = pdesc.fStages[s];
+ stage.fOptFlags = STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
+ stage.fInConfigFlags = IN_CONFIG_FLAGS[random_int(&random, GR_ARRAY_COUNT(IN_CONFIG_FLAGS))];
+ stage.fCoordMapping = random_int(&random, StageDesc::kCoordMappingCnt);
+ stage.fFetchMode = random_int(&random, StageDesc::kFetchModeCnt);
+ // convolution shaders don't work with persp tex matrix
+ if (stage.fFetchMode == StageDesc::kConvolution_FetchMode) {
+ stage.fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
+ }
+ stage.setEnabled(VertexUsesStage(s, pdesc.fVertexLayout));
+ switch (stage.fFetchMode) {
+ case StageDesc::kSingle_FetchMode:
+ stage.fKernelWidth = 0;
+ break;
+ case StageDesc::kConvolution_FetchMode:
+ stage.fKernelWidth = random_int(&random, 2, 8);
+ stage.fInConfigFlags &= ~StageDesc::kMulRGBByAlpha_InConfigFlag;
+ break;
+ case StageDesc::k2x2_FetchMode:
+ stage.fKernelWidth = 0;
+ stage.fInConfigFlags &= ~StageDesc::kMulRGBByAlpha_InConfigFlag;
+ break;
+ }
+ }
+ CachedData cachedData;
+ if (!program.genProgram(this->glInterface(),
+ glslGeneration,
+ &cachedData)) {
+ return false;
+ }
+ DeleteProgram(this->glInterface(), &cachedData);
+ }
+ return true;
+}
+
+namespace {
+GrGLBinding get_binding_in_use(const GrGLInterface* gl) {
+ if (gl->supportsDesktop()) {
+ return kDesktop_GrGLBinding;
+ } else {
+ GrAssert(gl->supportsES2());
+ return kES2_GrGLBinding;
+ }
+}
+}
+
+GrGpuGLShaders::GrGpuGLShaders(const GrGLInterface* gl)
+ : GrGpuGL(gl, get_binding_in_use(gl)) {
+
+ GrGLSLGeneration glslGeneration =
+ GetGLSLGeneration(this->glBinding(), gl);
+
+ // Enable supported shader-related caps
+ fCaps.fSupportPerVertexCoverage = true;
+ if (kDesktop_GrGLBinding == this->glBinding()) {
+ fCaps.fDualSourceBlendingSupport =
+ this->glVersion() >= GR_GL_VER(3,3) ||
+ this->hasExtension("GL_ARB_blend_func_extended");
+ fCaps.fShaderDerivativeSupport = true;
+ // we don't support GL_ARB_geometry_shader4, just GL 3.2+ GS
+ fCaps.fGeometryShaderSupport =
+ this->glVersion() >= GR_GL_VER(3,2) &&
+ glslGeneration >= k150_GLSLGeneration;
+ } else {
+ fCaps.fShaderDerivativeSupport =
+ this->hasExtension("GL_OES_standard_derivatives");
+ }
+
+ GR_GL_GetIntegerv(gl, GR_GL_MAX_VERTEX_ATTRIBS, &fMaxVertexAttribs);
+
+ fProgramData = NULL;
+ fProgramCache = new ProgramCache(gl, glslGeneration);
+
+#if 0
+ this->programUnitTest();
+#endif
+}
+
+GrGpuGLShaders::~GrGpuGLShaders() {
+ delete fProgramCache;
+}
+
+const GrMatrix& GrGpuGLShaders::getHWViewMatrix() {
+ GrAssert(fProgramData);
+
+ if (GrGLProgram::kSetAsAttribute ==
+ fProgramData->fUniLocations.fViewMatrixUni) {
+ return fHWDrawState.getViewMatrix();
+ } else {
+ return fProgramData->fViewMatrix;
+ }
+}
+
+void GrGpuGLShaders::recordHWViewMatrix(const GrMatrix& matrix) {
+ GrAssert(fProgramData);
+ if (GrGLProgram::kSetAsAttribute ==
+ fProgramData->fUniLocations.fViewMatrixUni) {
+ fHWDrawState.setViewMatrix(matrix);
+ } else {
+ fProgramData->fViewMatrix = matrix;
+ }
+}
+
+const GrMatrix& GrGpuGLShaders::getHWSamplerMatrix(int stage) {
+ GrAssert(fProgramData);
+
+ if (GrGLProgram::kSetAsAttribute ==
+ fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
+ return fHWDrawState.getSampler(stage).getMatrix();
+ } else {
+ return fProgramData->fTextureMatrices[stage];
+ }
+}
+
+void GrGpuGLShaders::recordHWSamplerMatrix(int stage, const GrMatrix& matrix) {
+ GrAssert(fProgramData);
+ if (GrGLProgram::kSetAsAttribute ==
+ fProgramData->fUniLocations.fStages[stage].fTextureMatrixUni) {
+ *fHWDrawState.sampler(stage)->matrix() = matrix;
+ } else {
+ fProgramData->fTextureMatrices[stage] = matrix;
+ }
+}
+
+void GrGpuGLShaders::onResetContext() {
+ INHERITED::onResetContext();
+
+ fHWGeometryState.fVertexOffset = ~0;
+
+ // Third party GL code may have left vertex attributes enabled. Some GL
+ // implementations (osmesa) may read vetex attributes that are not required
+ // by the current shader. Therefore, we have to ensure that only the
+ // attributes we require for the current draw are enabled or we may cause an
+ // invalid read.
+
+ // Disable all vertex layout bits so that next flush will assume all
+ // optional vertex attributes are disabled.
+ fHWGeometryState.fVertexLayout = 0;
+
+ // We always use the this attribute and assume it is always enabled.
+ int posAttrIdx = GrGLProgram::PositionAttributeIdx();
+ GL_CALL(EnableVertexAttribArray(posAttrIdx));
+ // Disable all other vertex attributes.
+ for (int va = 0; va < fMaxVertexAttribs; ++va) {
+ if (va != posAttrIdx) {
+ GL_CALL(DisableVertexAttribArray(va));
+ }
+ }
+
+ fHWProgramID = 0;
+}
+
+void GrGpuGLShaders::flushViewMatrix() {
+ const GrMatrix& vm = this->getDrawState().getViewMatrix();
+ if (GrGpuGLShaders::getHWViewMatrix() != vm) {
+
+ const GrRenderTarget* rt = this->getDrawState().getRenderTarget();
+ GrAssert(NULL != rt);
+ GrMatrix m;
+ m.setAll(
+ GrIntToScalar(2) / rt->width(), 0, -GR_Scalar1,
+ 0,-GrIntToScalar(2) / rt->height(), GR_Scalar1,
+ 0, 0, GrMatrix::I()[8]);
+ m.setConcat(m, vm);
+
+ // ES doesn't allow you to pass true to the transpose param,
+ // so do our own transpose
+ GrGLfloat mt[] = {
+ GrScalarToFloat(m[GrMatrix::kMScaleX]),
+ GrScalarToFloat(m[GrMatrix::kMSkewY]),
+ GrScalarToFloat(m[GrMatrix::kMPersp0]),
+ GrScalarToFloat(m[GrMatrix::kMSkewX]),
+ GrScalarToFloat(m[GrMatrix::kMScaleY]),
+ GrScalarToFloat(m[GrMatrix::kMPersp1]),
+ GrScalarToFloat(m[GrMatrix::kMTransX]),
+ GrScalarToFloat(m[GrMatrix::kMTransY]),
+ GrScalarToFloat(m[GrMatrix::kMPersp2])
+ };
+
+ if (GrGLProgram::kSetAsAttribute ==
+ fProgramData->fUniLocations.fViewMatrixUni) {
+ int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
+ GL_CALL(VertexAttrib4fv(baseIdx + 0, mt+0));
+ GL_CALL(VertexAttrib4fv(baseIdx + 1, mt+3));
+ GL_CALL(VertexAttrib4fv(baseIdx + 2, mt+6));
+ } else {
+ GrAssert(GrGLProgram::kUnusedUniform !=
+ fProgramData->fUniLocations.fViewMatrixUni);
+ GL_CALL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
+ 1, false, mt));
+ }
+ this->recordHWViewMatrix(vm);
+ }
+}
+
+void GrGpuGLShaders::flushTextureDomain(int s) {
+ const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni;
+ const GrDrawState& drawState = this->getDrawState();
+ if (GrGLProgram::kUnusedUniform != uni) {
+ const GrRect &texDom = drawState.getSampler(s).getTextureDomain();
+
+ if (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
+ fProgramData->fTextureDomain[s] != texDom) {
+
+ fProgramData->fTextureDomain[s] = texDom;
+
+ float values[4] = {
+ GrScalarToFloat(texDom.left()),
+ GrScalarToFloat(texDom.top()),
+ GrScalarToFloat(texDom.right()),
+ GrScalarToFloat(texDom.bottom())
+ };
+
+ const GrGLTexture* texture =
+ static_cast<const GrGLTexture*>(drawState.getTexture(s));
+ GrGLTexture::Orientation orientation = texture->orientation();
+
+ // vertical flip if necessary
+ if (GrGLTexture::kBottomUp_Orientation == orientation) {
+ values[1] = 1.0f - values[1];
+ values[3] = 1.0f - values[3];
+ // The top and bottom were just flipped, so correct the ordering
+ // of elements so that values = (l, t, r, b).
+ SkTSwap(values[1], values[3]);
+ }
+
+ GL_CALL(Uniform4fv(uni, 1, values));
+ }
+ }
+}
+
+void GrGpuGLShaders::flushTextureMatrix(int s) {
+ const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTextureMatrixUni;
+ const GrDrawState& drawState = this->getDrawState();
+ const GrGLTexture* texture =
+ static_cast<const GrGLTexture*>(drawState.getTexture(s));
+ if (NULL != texture) {
+ if (GrGLProgram::kUnusedUniform != uni &&
+ (((1 << s) & fDirtyFlags.fTextureChangedMask) ||
+ this->getHWSamplerMatrix(s) != drawState.getSampler(s).getMatrix())) {
+
+ GrMatrix m = drawState.getSampler(s).getMatrix();
+ GrSamplerState::SampleMode mode =
+ drawState.getSampler(s).getSampleMode();
+ AdjustTextureMatrix(texture, mode, &m);
+
+ // ES doesn't allow you to pass true to the transpose param,
+ // so do our own transpose
+ GrGLfloat mt[] = {
+ GrScalarToFloat(m[GrMatrix::kMScaleX]),
+ GrScalarToFloat(m[GrMatrix::kMSkewY]),
+ GrScalarToFloat(m[GrMatrix::kMPersp0]),
+ GrScalarToFloat(m[GrMatrix::kMSkewX]),
+ GrScalarToFloat(m[GrMatrix::kMScaleY]),
+ GrScalarToFloat(m[GrMatrix::kMPersp1]),
+ GrScalarToFloat(m[GrMatrix::kMTransX]),
+ GrScalarToFloat(m[GrMatrix::kMTransY]),
+ GrScalarToFloat(m[GrMatrix::kMPersp2])
+ };
+
+ if (GrGLProgram::kSetAsAttribute ==
+ fProgramData->fUniLocations.fStages[s].fTextureMatrixUni) {
+ int baseIdx = GrGLProgram::TextureMatrixAttributeIdx(s);
+ GL_CALL(VertexAttrib4fv(baseIdx + 0, mt+0));
+ GL_CALL(VertexAttrib4fv(baseIdx + 1, mt+3));
+ GL_CALL(VertexAttrib4fv(baseIdx + 2, mt+6));
+ } else {
+ GL_CALL(UniformMatrix3fv(uni, 1, false, mt));
+ }
+ this->recordHWSamplerMatrix(s, drawState.getSampler(s).getMatrix());
+ }
+ }
+}
+
+void GrGpuGLShaders::flushRadial2(int s) {
+
+ const int &uni = fProgramData->fUniLocations.fStages[s].fRadial2Uni;
+ const GrSamplerState& sampler = this->getDrawState().getSampler(s);
+ if (GrGLProgram::kUnusedUniform != uni &&
+ (fProgramData->fRadial2CenterX1[s] != sampler.getRadial2CenterX1() ||
+ fProgramData->fRadial2Radius0[s] != sampler.getRadial2Radius0() ||
+ fProgramData->fRadial2PosRoot[s] != sampler.isRadial2PosRoot())) {
+
+ GrScalar centerX1 = sampler.getRadial2CenterX1();
+ GrScalar radius0 = sampler.getRadial2Radius0();
+
+ GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
+
+ // when were in the degenerate (linear) case the second
+ // value will be INF but the program doesn't read it. (We
+ // use the same 6 uniforms even though we don't need them
+ // all in the linear case just to keep the code complexity
+ // down).
+ float values[6] = {
+ GrScalarToFloat(a),
+ 1 / (2.f * GrScalarToFloat(a)),
+ GrScalarToFloat(centerX1),
+ GrScalarToFloat(radius0),
+ GrScalarToFloat(GrMul(radius0, radius0)),
+ sampler.isRadial2PosRoot() ? 1.f : -1.f
+ };
+ GL_CALL(Uniform1fv(uni, 6, values));
+ fProgramData->fRadial2CenterX1[s] = sampler.getRadial2CenterX1();
+ fProgramData->fRadial2Radius0[s] = sampler.getRadial2Radius0();
+ fProgramData->fRadial2PosRoot[s] = sampler.isRadial2PosRoot();
+ }
+}
+
+void GrGpuGLShaders::flushConvolution(int s) {
+ const GrSamplerState& sampler = this->getDrawState().getSampler(s);
+ int kernelUni = fProgramData->fUniLocations.fStages[s].fKernelUni;
+ if (GrGLProgram::kUnusedUniform != kernelUni) {
+ GL_CALL(Uniform1fv(kernelUni, sampler.getKernelWidth(),
+ sampler.getKernel()));
+ }
+ int imageIncrementUni = fProgramData->fUniLocations.fStages[s].fImageIncrementUni;
+ if (GrGLProgram::kUnusedUniform != imageIncrementUni) {
+ GL_CALL(Uniform2fv(imageIncrementUni, 1, sampler.getImageIncrement()));
+ }
+}
+
+void GrGpuGLShaders::flushTexelSize(int s) {
+ const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni;
+ if (GrGLProgram::kUnusedUniform != uni) {
+ const GrGLTexture* texture =
+ static_cast<const GrGLTexture*>(this->getDrawState().getTexture(s));
+ if (texture->width() != fProgramData->fTextureWidth[s] ||
+ texture->height() != fProgramData->fTextureHeight[s]) {
+
+ float texelSize[] = {1.f / texture->width(),
+ 1.f / texture->height()};
+ GL_CALL(Uniform2fv(uni, 1, texelSize));
+ fProgramData->fTextureWidth[s] = texture->width();
+ fProgramData->fTextureHeight[s] = texture->height();
+ }
+ }
+}
+
+void GrGpuGLShaders::flushEdgeAAData() {
+ const int& uni = fProgramData->fUniLocations.fEdgesUni;
+ if (GrGLProgram::kUnusedUniform != uni) {
+ int count = this->getDrawState().getNumAAEdges();
+ GrDrawState::Edge edges[GrDrawState::kMaxEdges];
+ // Flip the edges in Y
+ float height =
+ static_cast<float>(this->getDrawState().getRenderTarget()->height());
+ for (int i = 0; i < count; ++i) {
+ edges[i] = this->getDrawState().getAAEdges()[i];
+ float b = edges[i].fY;
+ edges[i].fY = -b;
+ edges[i].fZ += b * height;
+ }
+ GL_CALL(Uniform3fv(uni, count, &edges[0].fX));
+ }
+}
+
+void GrGpuGLShaders::flushColorMatrix() {
+ const ProgramDesc& desc = fCurrentProgram.getDesc();
+ int matrixUni = fProgramData->fUniLocations.fColorMatrixUni;
+ int vecUni = fProgramData->fUniLocations.fColorMatrixVecUni;
+ if (GrGLProgram::kUnusedUniform != matrixUni
+ && GrGLProgram::kUnusedUniform != vecUni) {
+ const float* m = this->getDrawState().getColorMatrix();
+ GrGLfloat mt[] = {
+ m[0], m[5], m[10], m[15],
+ m[1], m[6], m[11], m[16],
+ m[2], m[7], m[12], m[17],
+ m[3], m[8], m[13], m[18],
+ };
+ static float scale = 1.0f / 255.0f;
+ GrGLfloat vec[] = {
+ m[4] * scale, m[9] * scale, m[14] * scale, m[19] * scale,
+ };
+ GL_CALL(UniformMatrix4fv(matrixUni, 1, false, mt));
+ GL_CALL(Uniform4fv(vecUni, 1, vec));
+ }
+}
+
+static const float ONE_OVER_255 = 1.f / 255.f;
+
+#define GR_COLOR_TO_VEC4(color) {\
+ GrColorUnpackR(color) * ONE_OVER_255,\
+ GrColorUnpackG(color) * ONE_OVER_255,\
+ GrColorUnpackB(color) * ONE_OVER_255,\
+ GrColorUnpackA(color) * ONE_OVER_255 \
+}
+
+void GrGpuGLShaders::flushColor(GrColor color) {
+ const ProgramDesc& desc = fCurrentProgram.getDesc();
+ const GrDrawState& drawState = this->getDrawState();
+
+ if (this->getGeomSrc().fVertexLayout & kColor_VertexLayoutBit) {
+ // color will be specified per-vertex as an attribute
+ // invalidate the const vertex attrib color
+ fHWDrawState.setColor(GrColor_ILLEGAL);
+ } else {
+ switch (desc.fColorInput) {
+ case ProgramDesc::kAttribute_ColorInput:
+ if (fHWDrawState.getColor() != color) {
+ // OpenGL ES only supports the float varities of glVertexAttrib
+ float c[] = GR_COLOR_TO_VEC4(color);
+ GL_CALL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(),
+ c));
+ fHWDrawState.setColor(color);
+ }
+ break;
+ case ProgramDesc::kUniform_ColorInput:
+ if (fProgramData->fColor != color) {
+ // OpenGL ES only supports the float varities of glVertexAttrib
+ float c[] = GR_COLOR_TO_VEC4(color);
+ GrAssert(GrGLProgram::kUnusedUniform !=
+ fProgramData->fUniLocations.fColorUni);
+ GL_CALL(Uniform4fv(fProgramData->fUniLocations.fColorUni,
+ 1, c));
+ fProgramData->fColor = color;
+ }
+ break;
+ case ProgramDesc::kSolidWhite_ColorInput:
+ case ProgramDesc::kTransBlack_ColorInput:
+ break;
+ default:
+ GrCrash("Unknown color type.");
+ }
+ }
+ if (fProgramData->fUniLocations.fColorFilterUni
+ != GrGLProgram::kUnusedUniform
+ && fProgramData->fColorFilterColor
+ != drawState.getColorFilterColor()) {
+ float c[] = GR_COLOR_TO_VEC4(drawState.getColorFilterColor());
+ GL_CALL(Uniform4fv(fProgramData->fUniLocations.fColorFilterUni, 1, c));
+ fProgramData->fColorFilterColor = drawState.getColorFilterColor();
+ }
+}
+
+
+bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
+ if (!flushGLStateCommon(type)) {
+ return false;
+ }
+
+ const GrDrawState& drawState = this->getDrawState();
+
+ if (fDirtyFlags.fRenderTargetChanged) {
+ // our coords are in pixel space and the GL matrices map to NDC
+ // so if the viewport changed, our matrix is now wrong.
+ fHWDrawState.setViewMatrix(GrMatrix::InvalidMatrix());
+ // we assume all shader matrices may be wrong after viewport changes
+ fProgramCache->invalidateViewMatrices();
+ }
+
+ GrBlendCoeff srcCoeff;
+ GrBlendCoeff dstCoeff;
+ BlendOptFlags blendOpts = this->getBlendOpts(false, &srcCoeff, &dstCoeff);
+ if (kSkipDraw_BlendOptFlag & blendOpts) {
+ return false;
+ }
+
+ this->buildProgram(type, blendOpts, dstCoeff);
+ fProgramData = fProgramCache->getProgramData(fCurrentProgram);
+ if (NULL == fProgramData) {
+ GrAssert(!"Failed to create program!");
+ return false;
+ }
+
+ if (fHWProgramID != fProgramData->fProgramID) {
+ GL_CALL(UseProgram(fProgramData->fProgramID));
+ fHWProgramID = fProgramData->fProgramID;
+ }
+ fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
+ this->flushBlend(type, srcCoeff, dstCoeff);
+
+ GrColor color;
+ if (blendOpts & kEmitTransBlack_BlendOptFlag) {
+ color = 0;
+ } else if (blendOpts & kEmitCoverage_BlendOptFlag) {
+ color = 0xffffffff;
+ } else {
+ color = drawState.getColor();
+ }
+ this->flushColor(color);
+
+ this->flushViewMatrix();
+
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ if (this->isStageEnabled(s)) {
+ this->flushTextureMatrix(s);
+
+ this->flushRadial2(s);
+
+ this->flushConvolution(s);
+
+ this->flushTexelSize(s);
+
+ this->flushTextureDomain(s);
+ }
+ }
+ this->flushEdgeAAData();
+ this->flushColorMatrix();
+ resetDirtyFlags();
+ return true;
+}
+
+void GrGpuGLShaders::postDraw() {
+}
+
+void GrGpuGLShaders::setupGeometry(int* startVertex,
+ int* startIndex,
+ int vertexCount,
+ int indexCount) {
+
+ int newColorOffset;
+ int newCoverageOffset;
+ int newTexCoordOffsets[GrDrawState::kMaxTexCoords];
+ int newEdgeOffset;
+
+ GrGLsizei newStride = VertexSizeAndOffsetsByIdx(
+ this->getGeomSrc().fVertexLayout,
+ newTexCoordOffsets,
+ &newColorOffset,
+ &newCoverageOffset,
+ &newEdgeOffset);
+ int oldColorOffset;
+ int oldCoverageOffset;
+ int oldTexCoordOffsets[GrDrawState::kMaxTexCoords];
+ int oldEdgeOffset;
+
+ GrGLsizei oldStride = VertexSizeAndOffsetsByIdx(
+ fHWGeometryState.fVertexLayout,
+ oldTexCoordOffsets,
+ &oldColorOffset,
+ &oldCoverageOffset,
+ &oldEdgeOffset);
+ bool indexed = NULL != startIndex;
+
+ int extraVertexOffset;
+ int extraIndexOffset;
+ this->setBuffers(indexed, &extraVertexOffset, &extraIndexOffset);
+
+ GrGLenum scalarType;
+ bool texCoordNorm;
+ if (this->getGeomSrc().fVertexLayout & kTextFormat_VertexLayoutBit) {
+ scalarType = GrGLTextType;
+ texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
+ } else {
+ scalarType = GrGLType;
+ texCoordNorm = false;
+ }
+
+ size_t vertexOffset = (*startVertex + extraVertexOffset) * newStride;
+ *startVertex = 0;
+ if (indexed) {
+ *startIndex += extraIndexOffset;
+ }
+
+ // all the Pointers must be set if any of these are true
+ bool allOffsetsChange = fHWGeometryState.fArrayPtrsDirty ||
+ vertexOffset != fHWGeometryState.fVertexOffset ||
+ newStride != oldStride;
+
+ // position and tex coord offsets change if above conditions are true
+ // or the type/normalization changed based on text vs nontext type coords.
+ bool posAndTexChange = allOffsetsChange ||
+ (((GrGLTextType != GrGLType) || GR_GL_TEXT_TEXTURE_NORMALIZED) &&
+ (kTextFormat_VertexLayoutBit &
+ (fHWGeometryState.fVertexLayout ^
+ this->getGeomSrc().fVertexLayout)));
+
+ if (posAndTexChange) {
+ int idx = GrGLProgram::PositionAttributeIdx();
+ GL_CALL(VertexAttribPointer(idx, 2, scalarType, false, newStride,
+ (GrGLvoid*)vertexOffset));
+ fHWGeometryState.fVertexOffset = vertexOffset;
+ }
+
+ for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) {
+ if (newTexCoordOffsets[t] > 0) {
+ GrGLvoid* texCoordOffset = (GrGLvoid*)(vertexOffset + newTexCoordOffsets[t]);
+ int idx = GrGLProgram::TexCoordAttributeIdx(t);
+ if (oldTexCoordOffsets[t] <= 0) {
+ GL_CALL(EnableVertexAttribArray(idx));
+ GL_CALL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
+ newStride, texCoordOffset));
+ } else if (posAndTexChange ||
+ newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
+ GL_CALL(VertexAttribPointer(idx, 2, scalarType, texCoordNorm,
+ newStride, texCoordOffset));
+ }
+ } else if (oldTexCoordOffsets[t] > 0) {
+ GL_CALL(DisableVertexAttribArray(GrGLProgram::TexCoordAttributeIdx(t)));
+ }
+ }
+
+ if (newColorOffset > 0) {
+ GrGLvoid* colorOffset = (int8_t*)(vertexOffset + newColorOffset);
+ int idx = GrGLProgram::ColorAttributeIdx();
+ if (oldColorOffset <= 0) {
+ GL_CALL(EnableVertexAttribArray(idx));
+ GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
+ true, newStride, colorOffset));
+ } else if (allOffsetsChange || newColorOffset != oldColorOffset) {
+ GL_CALL(VertexAttribPointer(idx, 4, GR_GL_UNSIGNED_BYTE,
+ true, newStride, colorOffset));
+ }
+ } else if (oldColorOffset > 0) {
+ GL_CALL(DisableVertexAttribArray(GrGLProgram::ColorAttributeIdx()));
+ }
+
+ if (newCoverageOffset > 0) {
+ // bind a single channel, they should all have the same value.
+ GrGLvoid* coverageOffset = (int8_t*)(vertexOffset + newCoverageOffset);
+ int idx = GrGLProgram::CoverageAttributeIdx();
+ if (oldCoverageOffset <= 0) {
+ GL_CALL(EnableVertexAttribArray(idx));
+ GL_CALL(VertexAttribPointer(idx, 1, GR_GL_UNSIGNED_BYTE,
+ true, newStride, coverageOffset));
+ } else if (allOffsetsChange || newCoverageOffset != oldCoverageOffset) {
+ GL_CALL(VertexAttribPointer(idx, 1, GR_GL_UNSIGNED_BYTE,
+ true, newStride, coverageOffset));
+ }
+ } else if (oldCoverageOffset > 0) {
+ GL_CALL(DisableVertexAttribArray(GrGLProgram::CoverageAttributeIdx()));
+ }
+
+ if (newEdgeOffset > 0) {
+ GrGLvoid* edgeOffset = (int8_t*)(vertexOffset + newEdgeOffset);
+ int idx = GrGLProgram::EdgeAttributeIdx();
+ if (oldEdgeOffset <= 0) {
+ GL_CALL(EnableVertexAttribArray(idx));
+ GL_CALL(VertexAttribPointer(idx, 4, scalarType,
+ false, newStride, edgeOffset));
+ } else if (allOffsetsChange || newEdgeOffset != oldEdgeOffset) {
+ GL_CALL(VertexAttribPointer(idx, 4, scalarType,
+ false, newStride, edgeOffset));
+ }
+ } else if (oldEdgeOffset > 0) {
+ GL_CALL(DisableVertexAttribArray(GrGLProgram::EdgeAttributeIdx()));
+ }
+
+ fHWGeometryState.fVertexLayout = this->getGeomSrc().fVertexLayout;
+ fHWGeometryState.fArrayPtrsDirty = false;
+}
+
+void GrGpuGLShaders::buildProgram(GrPrimitiveType type,
+ BlendOptFlags blendOpts,
+ GrBlendCoeff dstCoeff) {
+ ProgramDesc& desc = fCurrentProgram.fProgramDesc;
+ const GrDrawState& drawState = this->getDrawState();
+
+ // This should already have been caught
+ GrAssert(!(kSkipDraw_BlendOptFlag & blendOpts));
+
+ bool skipCoverage = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag);
+
+ bool skipColor = SkToBool(blendOpts & (kEmitTransBlack_BlendOptFlag |
+ kEmitCoverage_BlendOptFlag));
+
+ // The descriptor is used as a cache key. Thus when a field of the
+ // descriptor will not affect program generation (because of the vertex
+ // layout in use or other descriptor field settings) it should be set
+ // to a canonical value to avoid duplicate programs with different keys.
+
+ // Must initialize all fields or cache will have false negatives!
+ desc.fVertexLayout = this->getGeomSrc().fVertexLayout;
+
+ desc.fEmitsPointSize = kPoints_PrimitiveType == type;
+
+ bool requiresAttributeColors =
+ !skipColor && SkToBool(desc.fVertexLayout & kColor_VertexLayoutBit);
+ // fColorInput records how colors are specified for the program. Strip
+ // the bit from the layout to avoid false negatives when searching for an
+ // existing program in the cache.
+ desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
+
+ desc.fColorFilterXfermode = skipColor ?
+ SkXfermode::kDst_Mode :
+ drawState.getColorFilterMode();
+
+ desc.fColorMatrixEnabled = drawState.isStateFlagEnabled(GrDrawState::kColorMatrix_StateBit);
+
+ // no reason to do edge aa or look at per-vertex coverage if coverage is
+ // ignored
+ if (skipCoverage) {
+ desc.fVertexLayout &= ~(kEdge_VertexLayoutBit |
+ kCoverage_VertexLayoutBit);
+ }
+
+ bool colorIsTransBlack = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag);
+ bool colorIsSolidWhite = (blendOpts & kEmitCoverage_BlendOptFlag) ||
+ (!requiresAttributeColors &&
+ 0xffffffff == drawState.getColor());
+ if (GR_AGGRESSIVE_SHADER_OPTS && colorIsTransBlack) {
+ desc.fColorInput = ProgramDesc::kTransBlack_ColorInput;
+ } else if (GR_AGGRESSIVE_SHADER_OPTS && colorIsSolidWhite) {
+ desc.fColorInput = ProgramDesc::kSolidWhite_ColorInput;
+ } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeColors) {
+ desc.fColorInput = ProgramDesc::kUniform_ColorInput;
+ } else {
+ desc.fColorInput = ProgramDesc::kAttribute_ColorInput;
+ }
+
+ desc.fEdgeAANumEdges = skipCoverage ? 0 : drawState.getNumAAEdges();
+ desc.fEdgeAAConcave = desc.fEdgeAANumEdges > 0 &&
+ drawState.isConcaveEdgeAAState();
+
+ int lastEnabledStage = -1;
+
+ if (!skipCoverage && (desc.fVertexLayout &
+ GrDrawTarget::kEdge_VertexLayoutBit)) {
+ desc.fVertexEdgeType = drawState.getVertexEdgeType();
+ } else {
+ // use canonical value when not set to avoid cache misses
+ desc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
+ }
+
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ StageDesc& stage = desc.fStages[s];
+
+ stage.fOptFlags = 0;
+ stage.setEnabled(this->isStageEnabled(s));
+
+ bool skip = s < drawState.getFirstCoverageStage() ? skipColor :
+ skipCoverage;
+
+ if (!skip && stage.isEnabled()) {
+ lastEnabledStage = s;
+ const GrGLTexture* texture =
+ static_cast<const GrGLTexture*>(drawState.getTexture(s));
+ GrAssert(NULL != texture);
+ const GrSamplerState& sampler = drawState.getSampler(s);
+ // we matrix to invert when orientation is TopDown, so make sure
+ // we aren't in that case before flagging as identity.
+ if (TextureMatrixIsIdentity(texture, sampler)) {
+ stage.fOptFlags |= StageDesc::kIdentityMatrix_OptFlagBit;
+ } else if (!sampler.getMatrix().hasPerspective()) {
+ stage.fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
+ }
+ switch (sampler.getSampleMode()) {
+ case GrSamplerState::kNormal_SampleMode:
+ stage.fCoordMapping = StageDesc::kIdentity_CoordMapping;
+ break;
+ case GrSamplerState::kRadial_SampleMode:
+ stage.fCoordMapping = StageDesc::kRadialGradient_CoordMapping;
+ break;
+ case GrSamplerState::kRadial2_SampleMode:
+ if (sampler.radial2IsDegenerate()) {
+ stage.fCoordMapping =
+ StageDesc::kRadial2GradientDegenerate_CoordMapping;
+ } else {
+ stage.fCoordMapping =
+ StageDesc::kRadial2Gradient_CoordMapping;
+ }
+ break;
+ case GrSamplerState::kSweep_SampleMode:
+ stage.fCoordMapping = StageDesc::kSweepGradient_CoordMapping;
+ break;
+ default:
+ GrCrash("Unexpected sample mode!");
+ break;
+ }
+
+ switch (sampler.getFilter()) {
+ // these both can use a regular texture2D()
+ case GrSamplerState::kNearest_Filter:
+ case GrSamplerState::kBilinear_Filter:
+ stage.fFetchMode = StageDesc::kSingle_FetchMode;
+ break;
+ // performs 4 texture2D()s
+ case GrSamplerState::k4x4Downsample_Filter:
+ stage.fFetchMode = StageDesc::k2x2_FetchMode;
+ break;
+ // performs fKernelWidth texture2D()s
+ case GrSamplerState::kConvolution_Filter:
+ stage.fFetchMode = StageDesc::kConvolution_FetchMode;
+ break;
+ default:
+ GrCrash("Unexpected filter!");
+ break;
+ }
+
+ if (sampler.hasTextureDomain()) {
+ GrAssert(GrSamplerState::kClamp_WrapMode ==
+ sampler.getWrapX() &&
+ GrSamplerState::kClamp_WrapMode ==
+ sampler.getWrapY());
+ stage.fOptFlags |= StageDesc::kCustomTextureDomain_OptFlagBit;
+ }
+
+ stage.fInConfigFlags = 0;
+ if (!this->glCaps().fTextureSwizzleSupport) {
+ if (GrPixelConfigIsAlphaOnly(texture->config())) {
+ // if we don't have texture swizzle support then
+ // the shader must do an alpha smear after reading
+ // the texture
+ stage.fInConfigFlags |= StageDesc::kSmearAlpha_InConfigFlag;
+ } else if (sampler.swapsRAndB()) {
+ stage.fInConfigFlags |= StageDesc::kSwapRAndB_InConfigFlag;
+ }
+ }
+ if (GrPixelConfigIsUnpremultiplied(texture->config())) {
+ stage.fInConfigFlags |= StageDesc::kMulRGBByAlpha_InConfigFlag;
+ }
+
+ if (sampler.getFilter() == GrSamplerState::kConvolution_Filter) {
+ stage.fKernelWidth = sampler.getKernelWidth();
+ } else {
+ stage.fKernelWidth = 0;
+ }
+ } else {
+ stage.fOptFlags = 0;
+ stage.fCoordMapping = (StageDesc::CoordMapping) 0;
+ stage.fInConfigFlags = 0;
+ stage.fFetchMode = (StageDesc::FetchMode) 0;
+ stage.fKernelWidth = 0;
+ }
+ }
+
+ if (GrPixelConfigIsUnpremultiplied(drawState.getRenderTarget()->config())) {
+ desc.fOutputPM = ProgramDesc::kNo_OutputPM;
+ } else {
+ desc.fOutputPM = ProgramDesc::kYes_OutputPM;
+ }
+
+ desc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
+
+ // currently the experimental GS will only work with triangle prims
+ // (and it doesn't do anything other than pass through values from
+ // the VS to the FS anyway).
+#if 0 && GR_GL_EXPERIMENTAL_GS
+ desc.fExperimentalGS = this->getCaps().fGeometryShaderSupport;
+#endif
+
+ // we want to avoid generating programs with different "first cov stage"
+ // values when they would compute the same result.
+ // We set field in the desc to kNumStages when either there are no
+ // coverage stages or the distinction between coverage and color is
+ // immaterial.
+ int firstCoverageStage = GrDrawState::kNumStages;
+ desc.fFirstCoverageStage = GrDrawState::kNumStages;
+ bool hasCoverage = drawState.getFirstCoverageStage() <= lastEnabledStage;
+ if (hasCoverage) {
+ firstCoverageStage = drawState.getFirstCoverageStage();
+ }
+
+ // other coverage inputs
+ if (!hasCoverage) {
+ hasCoverage =
+ desc.fEdgeAANumEdges ||
+ (desc.fVertexLayout & GrDrawTarget::kCoverage_VertexLayoutBit) ||
+ (desc.fVertexLayout & GrDrawTarget::kEdge_VertexLayoutBit);
+ }
+
+ if (hasCoverage) {
+ // color filter is applied between color/coverage computation
+ if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) {
+ desc.fFirstCoverageStage = firstCoverageStage;
+ }
+
+ if (this->getCaps().fDualSourceBlendingSupport &&
+ !(blendOpts & (kEmitCoverage_BlendOptFlag |
+ kCoverageAsAlpha_BlendOptFlag))) {
+ if (kZero_BlendCoeff == dstCoeff) {
+ // write the coverage value to second color
+ desc.fDualSrcOutput = ProgramDesc::kCoverage_DualSrcOutput;
+ desc.fFirstCoverageStage = firstCoverageStage;
+ } else if (kSA_BlendCoeff == dstCoeff) {
+ // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
+ // cover
+ desc.fDualSrcOutput = ProgramDesc::kCoverageISA_DualSrcOutput;
+ desc.fFirstCoverageStage = firstCoverageStage;
+ } else if (kSC_BlendCoeff == dstCoeff) {
+ // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
+ // cover
+ desc.fDualSrcOutput = ProgramDesc::kCoverageISC_DualSrcOutput;
+ desc.fFirstCoverageStage = firstCoverageStage;
+ }
+ }
+ }
+}
diff --git a/gpu/src/GrGpuGLShaders.h b/src/gpu/GrGpuGLShaders.h
index 557a4e3..4b972b5 100644
--- a/gpu/src/GrGpuGLShaders.h
+++ b/src/gpu/GrGpuGLShaders.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrGpuGLShaders_DEFINED
#define GrGpuGLShaders_DEFINED
@@ -26,15 +19,16 @@ class GrGpuGLProgram;
// Programmable OpenGL or OpenGL ES 2.0
class GrGpuGLShaders : public GrGpuGL {
public:
- GrGpuGLShaders();
+ GrGpuGLShaders(const GrGLInterface* glInterface);
virtual ~GrGpuGLShaders();
- virtual void resetContext();
-
virtual void abandonResources();
+ bool programUnitTest();
+
protected:
// overrides from GrGpu
+ virtual void onResetContext() SK_OVERRIDE;
virtual bool flushGraphicsState(GrPrimitiveType type);
virtual void setupGeometry(int* startVertex,
int* startIndex,
@@ -44,9 +38,16 @@ protected:
private:
+ // for readability of function impls
+ typedef GrGLProgram::ProgramDesc ProgramDesc;
+ typedef ProgramDesc::StageDesc StageDesc;
+ typedef GrGLProgram::CachedData CachedData;
+
class ProgramCache;
// Helpers to make code more readable
+ const GrMatrix& getHWViewMatrix();
+ void recordHWViewMatrix(const GrMatrix& matrix);
const GrMatrix& getHWSamplerMatrix(int stage);
void recordHWSamplerMatrix(int stage, const GrMatrix& matrix);
@@ -57,7 +58,7 @@ private:
void flushTextureDomain(int stage);
// sets the color specified by GrDrawTarget::setColor()
- void flushColor();
+ void flushColor(GrColor color);
// sets the MVP matrix uniform for currently bound program
void flushViewMatrix();
@@ -65,22 +66,32 @@ private:
// flushes the parameters to two point radial gradient
void flushRadial2(int stage);
+ // flushes the parameters for convolution
+ void flushConvolution(int stage);
+
// flushes the normalized texel size
void flushTexelSize(int stage);
// flushes the edges for edge AA
void flushEdgeAAData();
- static void DeleteProgram(GrGLProgram::CachedData* programData);
+ // flushes the color matrix
+ void flushColorMatrix();
- void ProgramUnitTest();
+ static void DeleteProgram(const GrGLInterface* gl,
+ CachedData* programData);
- void buildProgram(GrPrimitiveType type);
+ void buildProgram(GrPrimitiveType typeBlend,
+ BlendOptFlags blendOpts,
+ GrBlendCoeff dstCoeff);
ProgramCache* fProgramCache;
- GrGLProgram::CachedData* fProgramData;
+ CachedData* fProgramData;
GrGLuint fHWProgramID;
GrGLProgram fCurrentProgram;
+ // If we get rid of fixed function subclass this should move
+ // to the GLCaps struct in parent class
+ GrGLint fMaxVertexAttribs;
typedef GrGpuGL INHERITED;
};
diff --git a/gpu/include/GrGpuVertex.h b/src/gpu/GrGpuVertex.h
index 1e3293a..2abc2f4 100644
--- a/gpu/include/GrGpuVertex.h
+++ b/src/gpu/GrGpuVertex.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrGpuVertex_DEFINED
#define GrGpuVertex_DEFINED
diff --git a/gpu/src/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index 7df1f23..cbe153c 100644
--- a/gpu/src/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -1,56 +1,52 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "GrInOrderDrawBuffer.h"
+#include "GrRenderTarget.h"
#include "GrTexture.h"
#include "GrBufferAllocPool.h"
#include "GrIndexBuffer.h"
#include "GrVertexBuffer.h"
#include "GrGpu.h"
-GrInOrderDrawBuffer::GrInOrderDrawBuffer(GrVertexBufferAllocPool* vertexPool,
- GrIndexBufferAllocPool* indexPool) :
- fDraws(&fDrawStorage),
- fStates(&fStateStorage),
- fClears(&fClearStorage),
- fClips(&fClipStorage),
- fClipSet(true),
-
- fLastRectVertexLayout(0),
- fQuadIndexBuffer(NULL),
- fMaxQuads(0),
- fCurrQuad(0),
-
- fVertexPool(*vertexPool),
- fCurrPoolVertexBuffer(NULL),
- fCurrPoolStartVertex(0),
- fIndexPool(*indexPool),
- fCurrPoolIndexBuffer(NULL),
- fCurrPoolStartIndex(0),
- fReservedVertexBytes(0),
- fReservedIndexBytes(0),
- fUsedReservedVertexBytes(0),
- fUsedReservedIndexBytes(0) {
+GrInOrderDrawBuffer::GrInOrderDrawBuffer(const GrGpu* gpu,
+ GrVertexBufferAllocPool* vertexPool,
+ GrIndexBufferAllocPool* indexPool)
+ : fClipSet(true)
+ , fLastRectVertexLayout(0)
+ , fQuadIndexBuffer(NULL)
+ , fMaxQuads(0)
+ , fCurrQuad(0)
+ , fVertexPool(*vertexPool)
+ , fIndexPool(*indexPool) {
+
+ fCaps = gpu->getCaps();
+
GrAssert(NULL != vertexPool);
GrAssert(NULL != indexPool);
+
+ GeometryPoolState& poolState = fGeoPoolStateStack.push_back();
+ poolState.fUsedPoolVertexBytes = 0;
+ poolState.fUsedPoolIndexBytes = 0;
+#if GR_DEBUG
+ poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0;
+ poolState.fPoolStartVertex = ~0;
+ poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0;
+ poolState.fPoolStartIndex = ~0;
+#endif
}
GrInOrderDrawBuffer::~GrInOrderDrawBuffer() {
this->reset();
+ // This must be called by before the GrDrawTarget destructor
+ this->releaseGeometry();
GrSafeUnref(fQuadIndexBuffer);
}
@@ -75,7 +71,7 @@ void GrInOrderDrawBuffer::setQuadIndexBuffer(const GrIndexBuffer* indexBuffer) {
void GrInOrderDrawBuffer::drawRect(const GrRect& rect,
const GrMatrix* matrix,
- StageBitfield stageEnableBitfield,
+ StageMask stageMask,
const GrRect* srcRects[],
const GrMatrix* srcMatrices[]) {
@@ -83,16 +79,21 @@ void GrInOrderDrawBuffer::drawRect(const GrRect& rect,
GrAssert(!(fDraws.empty() && fCurrQuad));
GrAssert(!(0 != fMaxQuads && NULL == fQuadIndexBuffer));
+ GrDrawState* drawState = this->drawState();
+
// if we have a quad IB then either append to the previous run of
// rects or start a new run
if (fMaxQuads) {
bool appendToPreviousDraw = false;
- GrVertexLayout layout = GetRectVertexLayout(stageEnableBitfield, srcRects);
+ GrVertexLayout layout = GetRectVertexLayout(stageMask, srcRects);
AutoReleaseGeometry geo(this, layout, 4, 0);
- AutoViewMatrixRestore avmr(this);
- GrMatrix combinedMatrix = this->getViewMatrix();
- this->setViewMatrix(GrMatrix::I());
+ if (!geo.succeeded()) {
+ GrPrintf("Failed to get space for vertices!\n");
+ return;
+ }
+ GrMatrix combinedMatrix = drawState->getViewMatrix();
+ GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I());
if (NULL != matrix) {
combinedMatrix.preConcat(*matrix);
}
@@ -103,14 +104,14 @@ void GrInOrderDrawBuffer::drawRect(const GrRect& rect,
// simply because the clip has changed if the clip doesn't affect
// the rect.
bool disabledClip = false;
- if (this->isClipState() && fClip.isRect()) {
+ if (drawState->isClipState() && fClip.isRect()) {
GrRect clipRect = fClip.getRect(0);
// If the clip rect touches the edge of the viewport, extended it
// out (close) to infinity to avoid bogus intersections.
// We might consider a more exact clip to viewport if this
// conservative test fails.
- const GrRenderTarget* target = this->getRenderTarget();
+ const GrRenderTarget* target = drawState->getRenderTarget();
if (0 >= clipRect.fLeft) {
clipRect.fLeft = GR_ScalarMin;
}
@@ -133,7 +134,7 @@ void GrInOrderDrawBuffer::drawRect(const GrRect& rect,
}
}
if (insideClip) {
- this->disableState(kClip_StateBit);
+ drawState->disableState(GrDrawState::kClip_StateBit);
disabledClip = true;
}
}
@@ -150,19 +151,24 @@ void GrInOrderDrawBuffer::drawRect(const GrRect& rect,
GrAssert(0 == lastDraw.fIndexCount % 6);
GrAssert(0 == lastDraw.fStartIndex);
+ GeometryPoolState& poolState = fGeoPoolStateStack.back();
bool clearSinceLastDraw =
fClears.count() &&
fClears.back().fBeforeDrawIdx == fDraws.count();
- appendToPreviousDraw = !clearSinceLastDraw &&
- lastDraw.fVertexBuffer == fCurrPoolVertexBuffer &&
- (fCurrQuad * 4 + lastDraw.fStartVertex) == fCurrPoolStartVertex;
+ appendToPreviousDraw =
+ !clearSinceLastDraw &&
+ lastDraw.fVertexBuffer == poolState.fPoolVertexBuffer &&
+ (fCurrQuad * 4 + lastDraw.fStartVertex) == poolState.fPoolStartVertex;
+
if (appendToPreviousDraw) {
lastDraw.fVertexCount += 4;
lastDraw.fIndexCount += 6;
fCurrQuad += 1;
- GrAssert(0 == fUsedReservedVertexBytes);
- fUsedReservedVertexBytes = 4 * vsize;
+ // we reserved above, so we should be the first
+ // use of this vertex reserveation.
+ GrAssert(0 == poolState.fUsedPoolVertexBytes);
+ poolState.fUsedPoolVertexBytes = 4 * vsize;
}
}
if (!appendToPreviousDraw) {
@@ -172,18 +178,18 @@ void GrInOrderDrawBuffer::drawRect(const GrRect& rect,
fLastRectVertexLayout = layout;
}
if (disabledClip) {
- this->enableState(kClip_StateBit);
+ drawState->enableState(GrDrawState::kClip_StateBit);
}
} else {
- INHERITED::drawRect(rect, matrix, stageEnableBitfield, srcRects, srcMatrices);
+ INHERITED::drawRect(rect, matrix, stageMask, srcRects, srcMatrices);
}
}
-void GrInOrderDrawBuffer::drawIndexed(GrPrimitiveType primitiveType,
- int startVertex,
- int startIndex,
- int vertexCount,
- int indexCount) {
+void GrInOrderDrawBuffer::onDrawIndexed(GrPrimitiveType primitiveType,
+ int startVertex,
+ int startIndex,
+ int vertexCount,
+ int indexCount) {
if (!vertexCount || !indexCount) {
return;
@@ -191,6 +197,8 @@ void GrInOrderDrawBuffer::drawIndexed(GrPrimitiveType primitiveType,
fCurrQuad = 0;
+ GeometryPoolState& poolState = fGeoPoolStateStack.back();
+
Draw& draw = fDraws.push_back();
draw.fPrimitiveType = primitiveType;
draw.fStartVertex = startVertex;
@@ -208,52 +216,56 @@ void GrInOrderDrawBuffer::drawIndexed(GrPrimitiveType primitiveType,
this->pushState();
}
- draw.fVertexLayout = fGeometrySrc.fVertexLayout;
- switch (fGeometrySrc.fVertexSrc) {
+ draw.fVertexLayout = this->getGeomSrc().fVertexLayout;
+ switch (this->getGeomSrc().fVertexSrc) {
case kBuffer_GeometrySrcType:
- draw.fVertexBuffer = fGeometrySrc.fVertexBuffer;
+ draw.fVertexBuffer = this->getGeomSrc().fVertexBuffer;
break;
- case kReserved_GeometrySrcType: {
+ case kReserved_GeometrySrcType: // fallthrough
+ case kArray_GeometrySrcType: {
size_t vertexBytes = (vertexCount + startVertex) *
- VertexSize(fGeometrySrc.fVertexLayout);
- fUsedReservedVertexBytes = GrMax(fUsedReservedVertexBytes, vertexBytes);
- } // fallthrough
- case kArray_GeometrySrcType:
- draw.fVertexBuffer = fCurrPoolVertexBuffer;
- draw.fStartVertex += fCurrPoolStartVertex;
+ VertexSize(this->getGeomSrc().fVertexLayout);
+ poolState.fUsedPoolVertexBytes =
+ GrMax(poolState.fUsedPoolVertexBytes, vertexBytes);
+ draw.fVertexBuffer = poolState.fPoolVertexBuffer;
+ draw.fStartVertex += poolState.fPoolStartVertex;
break;
+ }
default:
GrCrash("unknown geom src type");
}
draw.fVertexBuffer->ref();
- switch (fGeometrySrc.fIndexSrc) {
+ switch (this->getGeomSrc().fIndexSrc) {
case kBuffer_GeometrySrcType:
- draw.fIndexBuffer = fGeometrySrc.fIndexBuffer;
+ draw.fIndexBuffer = this->getGeomSrc().fIndexBuffer;
break;
- case kReserved_GeometrySrcType: {
+ case kReserved_GeometrySrcType: // fallthrough
+ case kArray_GeometrySrcType: {
size_t indexBytes = (indexCount + startIndex) * sizeof(uint16_t);
- fUsedReservedIndexBytes = GrMax(fUsedReservedIndexBytes, indexBytes);
- } // fallthrough
- case kArray_GeometrySrcType:
- draw.fIndexBuffer = fCurrPoolIndexBuffer;
- draw.fStartIndex += fCurrPoolStartVertex;
+ poolState.fUsedPoolIndexBytes =
+ GrMax(poolState.fUsedPoolIndexBytes, indexBytes);
+ draw.fIndexBuffer = poolState.fPoolIndexBuffer;
+ draw.fStartIndex += poolState.fPoolStartVertex;
break;
+ }
default:
GrCrash("unknown geom src type");
}
draw.fIndexBuffer->ref();
}
-void GrInOrderDrawBuffer::drawNonIndexed(GrPrimitiveType primitiveType,
- int startVertex,
- int vertexCount) {
+void GrInOrderDrawBuffer::onDrawNonIndexed(GrPrimitiveType primitiveType,
+ int startVertex,
+ int vertexCount) {
if (!vertexCount) {
return;
}
fCurrQuad = 0;
+ GeometryPoolState& poolState = fGeoPoolStateStack.back();
+
Draw& draw = fDraws.push_back();
draw.fPrimitiveType = primitiveType;
draw.fStartVertex = startVertex;
@@ -271,21 +283,21 @@ void GrInOrderDrawBuffer::drawNonIndexed(GrPrimitiveType primitiveType,
this->pushState();
}
- draw.fVertexLayout = fGeometrySrc.fVertexLayout;
- switch (fGeometrySrc.fVertexSrc) {
+ draw.fVertexLayout = this->getGeomSrc().fVertexLayout;
+ switch (this->getGeomSrc().fVertexSrc) {
case kBuffer_GeometrySrcType:
- draw.fVertexBuffer = fGeometrySrc.fVertexBuffer;
+ draw.fVertexBuffer = this->getGeomSrc().fVertexBuffer;
break;
- case kReserved_GeometrySrcType: {
+ case kReserved_GeometrySrcType: // fallthrough
+ case kArray_GeometrySrcType: {
size_t vertexBytes = (vertexCount + startVertex) *
- VertexSize(fGeometrySrc.fVertexLayout);
- fUsedReservedVertexBytes = GrMax(fUsedReservedVertexBytes,
- vertexBytes);
- } // fallthrough
- case kArray_GeometrySrcType:
- draw.fVertexBuffer = fCurrPoolVertexBuffer;
- draw.fStartVertex += fCurrPoolStartVertex;
+ VertexSize(this->getGeomSrc().fVertexLayout);
+ poolState.fUsedPoolVertexBytes =
+ GrMax(poolState.fUsedPoolVertexBytes, vertexBytes);
+ draw.fVertexBuffer = poolState.fPoolVertexBuffer;
+ draw.fStartVertex += poolState.fPoolStartVertex;
break;
+ }
default:
GrCrash("unknown geom src type");
}
@@ -300,8 +312,8 @@ void GrInOrderDrawBuffer::clear(const GrIRect* rect, GrColor color) {
// the current render target. If we get that smart we have to make sure
// those draws aren't read before this clear (render-to-texture).
r.setLTRB(0, 0,
- this->getRenderTarget()->width(),
- this->getRenderTarget()->height());
+ this->getDrawState().getRenderTarget()->width(),
+ this->getDrawState().getRenderTarget()->height());
rect = &r;
}
Clear& clr = fClears.push_back();
@@ -311,14 +323,16 @@ void GrInOrderDrawBuffer::clear(const GrIRect* rect, GrColor color) {
}
void GrInOrderDrawBuffer::reset() {
- GrAssert(!fReservedGeometry.fLocked);
+ GrAssert(1 == fGeoPoolStateStack.count());
+ this->resetVertexSource();
+ this->resetIndexSource();
uint32_t numStates = fStates.count();
for (uint32_t i = 0; i < numStates; ++i) {
- const DrState& dstate = this->accessSavedDrawState(fStates[i]);
- for (int s = 0; s < kNumStages; ++s) {
- GrSafeUnref(dstate.fTextures[s]);
+ const GrDrawState& dstate = this->accessSavedDrawState(fStates[i]);
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ GrSafeUnref(dstate.getTexture(s));
}
- GrSafeUnref(dstate.fRenderTarget);
+ GrSafeUnref(dstate.getRenderTarget());
}
int numDraws = fDraws.count();
for (int d = 0; d < numDraws; ++d) {
@@ -341,7 +355,8 @@ void GrInOrderDrawBuffer::reset() {
}
void GrInOrderDrawBuffer::playback(GrDrawTarget* target) {
- GrAssert(!fReservedGeometry.fLocked);
+ GrAssert(kReserved_GeometrySrcType != this->getGeomSrc().fVertexSrc);
+ GrAssert(kReserved_GeometrySrcType != this->getGeomSrc().fIndexSrc);
GrAssert(NULL != target);
GrAssert(target != this); // not considered and why?
@@ -355,9 +370,7 @@ void GrInOrderDrawBuffer::playback(GrDrawTarget* target) {
GrDrawTarget::AutoStateRestore asr(target);
GrDrawTarget::AutoClipRestore acr(target);
- // important to not mess with reserve/lock geometry in the target with this
- // on the stack.
- GrDrawTarget::AutoGeometrySrcRestore agsr(target);
+ AutoGeometryPush agp(target);
int currState = ~0;
int currClip = ~0;
@@ -435,108 +448,163 @@ bool GrInOrderDrawBuffer::geometryHints(GrVertexLayout vertexLayout,
return flush;
}
-bool GrInOrderDrawBuffer::onAcquireGeometry(GrVertexLayout vertexLayout,
- void** vertices,
- void** indices) {
- GrAssert(!fReservedGeometry.fLocked);
- if (fReservedGeometry.fVertexCount) {
- GrAssert(NULL != vertices);
- GrAssert(0 == fReservedVertexBytes);
- GrAssert(0 == fUsedReservedVertexBytes);
-
- fReservedVertexBytes = VertexSize(vertexLayout) *
- fReservedGeometry.fVertexCount;
- *vertices = fVertexPool.makeSpace(vertexLayout,
- fReservedGeometry.fVertexCount,
- &fCurrPoolVertexBuffer,
- &fCurrPoolStartVertex);
- if (NULL == *vertices) {
- return false;
- }
- }
- if (fReservedGeometry.fIndexCount) {
- GrAssert(NULL != indices);
- GrAssert(0 == fReservedIndexBytes);
- GrAssert(0 == fUsedReservedIndexBytes);
-
- *indices = fIndexPool.makeSpace(fReservedGeometry.fIndexCount,
- &fCurrPoolIndexBuffer,
- &fCurrPoolStartIndex);
- if (NULL == *indices) {
- fVertexPool.putBack(fReservedVertexBytes);
- fReservedVertexBytes = 0;
- fCurrPoolVertexBuffer = NULL;
- return false;
- }
- }
- return true;
+bool GrInOrderDrawBuffer::onReserveVertexSpace(GrVertexLayout vertexLayout,
+ int vertexCount,
+ void** vertices) {
+ GeometryPoolState& poolState = fGeoPoolStateStack.back();
+ GrAssert(vertexCount > 0);
+ GrAssert(NULL != vertices);
+ GrAssert(0 == poolState.fUsedPoolVertexBytes);
+
+ *vertices = fVertexPool.makeSpace(vertexLayout,
+ vertexCount,
+ &poolState.fPoolVertexBuffer,
+ &poolState.fPoolStartVertex);
+ return NULL != *vertices;
+}
+
+bool GrInOrderDrawBuffer::onReserveIndexSpace(int indexCount, void** indices) {
+ GeometryPoolState& poolState = fGeoPoolStateStack.back();
+ GrAssert(indexCount > 0);
+ GrAssert(NULL != indices);
+ GrAssert(0 == poolState.fUsedPoolIndexBytes);
+
+ *indices = fIndexPool.makeSpace(indexCount,
+ &poolState.fPoolIndexBuffer,
+ &poolState.fPoolStartIndex);
+ return NULL != *indices;
}
-void GrInOrderDrawBuffer::onReleaseGeometry() {
- GrAssert(fUsedReservedVertexBytes <= fReservedVertexBytes);
- GrAssert(fUsedReservedIndexBytes <= fReservedIndexBytes);
-
- size_t vertexSlack = fReservedVertexBytes - fUsedReservedVertexBytes;
- fVertexPool.putBack(vertexSlack);
-
- size_t indexSlack = fReservedIndexBytes - fUsedReservedIndexBytes;
- fIndexPool.putBack(indexSlack);
+void GrInOrderDrawBuffer::releaseReservedVertexSpace() {
+ GeometryPoolState& poolState = fGeoPoolStateStack.back();
+ const GeometrySrcState& geoSrc = this->getGeomSrc();
+
+ GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc);
+
+ size_t reservedVertexBytes = VertexSize(geoSrc.fVertexLayout) *
+ geoSrc.fVertexCount;
+ fVertexPool.putBack(reservedVertexBytes -
+ poolState.fUsedPoolVertexBytes);
+ poolState.fUsedPoolVertexBytes = 0;
+ poolState.fPoolVertexBuffer = 0;
+}
- fReservedVertexBytes = 0;
- fReservedIndexBytes = 0;
- fUsedReservedVertexBytes = 0;
- fUsedReservedIndexBytes = 0;
- fCurrPoolVertexBuffer = 0;
- fCurrPoolStartVertex = 0;
+void GrInOrderDrawBuffer::releaseReservedIndexSpace() {
+ GeometryPoolState& poolState = fGeoPoolStateStack.back();
+ const GeometrySrcState& geoSrc = this->getGeomSrc();
+ GrAssert(kReserved_GeometrySrcType == geoSrc.fIndexSrc);
+
+ size_t reservedIndexBytes = sizeof(uint16_t) * geoSrc.fIndexCount;
+ fIndexPool.putBack(reservedIndexBytes - poolState.fUsedPoolIndexBytes);
+ poolState.fUsedPoolIndexBytes = 0;
+ poolState.fPoolStartVertex = 0;
}
-
+
void GrInOrderDrawBuffer::onSetVertexSourceToArray(const void* vertexArray,
int vertexCount) {
- GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
+
+ GeometryPoolState& poolState = fGeoPoolStateStack.back();
+ GrAssert(0 == poolState.fUsedPoolVertexBytes);
#if GR_DEBUG
bool success =
#endif
- fVertexPool.appendVertices(fGeometrySrc.fVertexLayout,
+ fVertexPool.appendVertices(this->getGeomSrc().fVertexLayout,
vertexCount,
vertexArray,
- &fCurrPoolVertexBuffer,
- &fCurrPoolStartVertex);
+ &poolState.fPoolVertexBuffer,
+ &poolState.fPoolStartVertex);
GR_DEBUGASSERT(success);
}
void GrInOrderDrawBuffer::onSetIndexSourceToArray(const void* indexArray,
int indexCount) {
- GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
+ GeometryPoolState& poolState = fGeoPoolStateStack.back();
+ GrAssert(0 == poolState.fUsedPoolIndexBytes);
#if GR_DEBUG
bool success =
#endif
fIndexPool.appendIndices(indexCount,
indexArray,
- &fCurrPoolIndexBuffer,
- &fCurrPoolStartIndex);
+ &poolState.fPoolIndexBuffer,
+ &poolState.fPoolStartIndex);
GR_DEBUGASSERT(success);
}
+void GrInOrderDrawBuffer::geometrySourceWillPush() {
+ GeometryPoolState& poolState = fGeoPoolStateStack.push_back();
+ poolState.fUsedPoolVertexBytes = 0;
+ poolState.fUsedPoolIndexBytes = 0;
+#if GR_DEBUG
+ poolState.fPoolVertexBuffer = (GrVertexBuffer*)~0;
+ poolState.fPoolStartVertex = ~0;
+ poolState.fPoolIndexBuffer = (GrIndexBuffer*)~0;
+ poolState.fPoolStartIndex = ~0;
+#endif
+}
+
+void GrInOrderDrawBuffer::releaseVertexArray() {
+ GeometryPoolState& poolState = fGeoPoolStateStack.back();
+ const GeometrySrcState& geoSrc = this->getGeomSrc();
+
+ size_t reservedVertexBytes = VertexSize(geoSrc.fVertexLayout) *
+ geoSrc.fVertexCount;
+ fVertexPool.putBack(reservedVertexBytes - poolState.fUsedPoolVertexBytes);
+
+ poolState.fUsedPoolVertexBytes = 0;
+}
+
+void GrInOrderDrawBuffer::releaseIndexArray() {
+ GeometryPoolState& poolState = fGeoPoolStateStack.back();
+ const GeometrySrcState& geoSrc = this->getGeomSrc();
+
+ size_t reservedIndexBytes = sizeof(uint16_t) * geoSrc.fIndexCount;
+ fIndexPool.putBack(reservedIndexBytes - poolState.fUsedPoolIndexBytes);
+
+ poolState.fUsedPoolIndexBytes = 0;
+}
+
+void GrInOrderDrawBuffer::geometrySourceWillPop(
+ const GeometrySrcState& restoredState) {
+ GrAssert(fGeoPoolStateStack.count() > 1);
+ fGeoPoolStateStack.pop_back();
+ GeometryPoolState& poolState = fGeoPoolStateStack.back();
+ // we have to assume that any slack we had in our vertex/index data
+ // is now unreleasable because data may have been appended later in the
+ // pool.
+ if (kReserved_GeometrySrcType == restoredState.fVertexSrc ||
+ kArray_GeometrySrcType == restoredState.fVertexSrc) {
+ poolState.fUsedPoolVertexBytes =
+ VertexSize(restoredState.fVertexLayout) *
+ restoredState.fVertexCount;
+ }
+ if (kReserved_GeometrySrcType == restoredState.fIndexSrc ||
+ kArray_GeometrySrcType == restoredState.fIndexSrc) {
+ poolState.fUsedPoolVertexBytes = sizeof(uint16_t) *
+ restoredState.fIndexCount;
+ }
+}
+
bool GrInOrderDrawBuffer::needsNewState() const {
if (fStates.empty()) {
return true;
} else {
- const DrState& old = this->accessSavedDrawState(fStates.back());
+ const GrDrawState& old = this->accessSavedDrawState(fStates.back());
return old != fCurrDrawState;
}
}
void GrInOrderDrawBuffer::pushState() {
- for (int s = 0; s < kNumStages; ++s) {
- GrSafeRef(fCurrDrawState.fTextures[s]);
+ const GrDrawState& drawState = this->getDrawState();
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ GrSafeRef(drawState.getTexture(s));
}
- GrSafeRef(fCurrDrawState.fRenderTarget);
+ GrSafeRef(drawState.getRenderTarget());
this->saveCurrentDrawState(&fStates.push_back());
}
bool GrInOrderDrawBuffer::needsNewClip() const {
- if (fCurrDrawState.fFlagBits & kClip_StateBit) {
+ if (this->getDrawState().isClipState()) {
if (fClips.empty() || (fClipSet && fClips.back() != fClip)) {
return true;
}
@@ -549,6 +617,7 @@ void GrInOrderDrawBuffer::pushClip() {
fClipSet = false;
}
-void GrInOrderDrawBuffer::clipWillBeSet(const GrClip& newClip) {
+void GrInOrderDrawBuffer::clipWillBeSet(const GrClip& newClip) {
+ INHERITED::clipWillBeSet(newClip);
fClipSet = true;
}
diff --git a/gpu/include/GrInOrderDrawBuffer.h b/src/gpu/GrInOrderDrawBuffer.h
index b26cd72..f935be1 100644
--- a/gpu/include/GrInOrderDrawBuffer.h
+++ b/src/gpu/GrInOrderDrawBuffer.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrInOrderDrawBuffer_DEFINED
#define GrInOrderDrawBuffer_DEFINED
@@ -23,8 +16,9 @@
#include "GrAllocator.h"
#include "GrClip.h"
-class GrVertexBufferAllocPool;
+class GrGpu;
class GrIndexBufferAllocPool;
+class GrVertexBufferAllocPool;
/**
* GrInOrderDrawBuffer is an implementation of GrDrawTarget that queues up
@@ -44,12 +38,16 @@ public:
/**
* Creates a GrInOrderDrawBuffer
*
+ * @param gpu the gpu object where this will be played back
+ * (possible indirectly). GrResources used with the draw
+ * buffer are created by this gpu object.
* @param vertexPool pool where vertices for queued draws will be saved when
* the vertex source is either reserved or array.
* @param indexPool pool where indices for queued draws will be saved when
* the index source is either reserved or array.
*/
- GrInOrderDrawBuffer(GrVertexBufferAllocPool* vertexPool,
+ GrInOrderDrawBuffer(const GrGpu* gpu,
+ GrVertexBufferAllocPool* vertexPool,
GrIndexBufferAllocPool* indexPool);
virtual ~GrInOrderDrawBuffer();
@@ -81,18 +79,9 @@ public:
void playback(GrDrawTarget* target);
// overrides from GrDrawTarget
- virtual void drawIndexed(GrPrimitiveType primitiveType,
- int startVertex,
- int startIndex,
- int vertexCount,
- int indexCount);
- virtual void drawNonIndexed(GrPrimitiveType primitiveType,
- int startVertex,
- int vertexCount);
-
virtual void drawRect(const GrRect& rect,
const GrMatrix* matrix = NULL,
- int stageEnableMask = 0,
+ StageMask stageEnableMask = 0,
const GrRect* srcRects[] = NULL,
const GrMatrix* srcMatrices[] = NULL);
@@ -123,29 +112,52 @@ private:
GrColor fColor;
};
- virtual bool onAcquireGeometry(GrVertexLayout vertexLayout,
- void** vertices,
- void** indices);
- virtual void onReleaseGeometry();
- virtual void clipWillBeSet(const GrClip& newClip);
-
+ // overrides from GrDrawTarget
+ virtual void onDrawIndexed(GrPrimitiveType primitiveType,
+ int startVertex,
+ int startIndex,
+ int vertexCount,
+ int indexCount);
+ virtual void onDrawNonIndexed(GrPrimitiveType primitiveType,
+ int startVertex,
+ int vertexCount);
+ virtual bool onReserveVertexSpace(GrVertexLayout layout,
+ int vertexCount,
+ void** vertices);
+ virtual bool onReserveIndexSpace(int indexCount, void** indices);
+ virtual void releaseReservedVertexSpace();
+ virtual void releaseReservedIndexSpace();
virtual void onSetVertexSourceToArray(const void* vertexArray,
- int vertexCount);
-
+ int vertexCount);
virtual void onSetIndexSourceToArray(const void* indexArray,
int indexCount);
+ virtual void releaseVertexArray();
+ virtual void releaseIndexArray();
+ virtual void geometrySourceWillPush();
+ virtual void geometrySourceWillPop(const GeometrySrcState& restoredState);
+ virtual void clipWillBeSet(const GrClip& newClip);
bool needsNewState() const;
bool needsNewClip() const;
void pushState();
void pushClip();
+
+ enum {
+ kDrawPreallocCnt = 8,
+ kStatePreallocCnt = 8,
+ kClipPreallocCnt = 8,
+ kClearPreallocCnt = 4,
+ kGeoPoolStatePreAllocCnt = 4,
+ };
- GrTAllocator<Draw> fDraws;
- GrTAllocator<SavedDrawState> fStates;
- GrTAllocator<Clear> fClears;
+ const GrGpu* fGpu;
- GrTAllocator<GrClip> fClips;
+ GrSTAllocator<kDrawPreallocCnt, Draw> fDraws;
+ GrSTAllocator<kStatePreallocCnt, SavedDrawState> fStates;
+ GrSTAllocator<kClearPreallocCnt, Clear> fClears;
+ GrSTAllocator<kClipPreallocCnt, GrClip> fClips;
+
bool fClipSet;
GrVertexLayout fLastRectVertexLayout;
@@ -154,31 +166,21 @@ private:
int fCurrQuad;
GrVertexBufferAllocPool& fVertexPool;
- const GrVertexBuffer* fCurrPoolVertexBuffer;
- int fCurrPoolStartVertex;
GrIndexBufferAllocPool& fIndexPool;
- const GrIndexBuffer* fCurrPoolIndexBuffer;
- int fCurrPoolStartIndex;
-
- // caller may conservatively over reserve vertices / indices.
- // we release unused space back to allocator if possible
- size_t fReservedVertexBytes;
- size_t fReservedIndexBytes;
- size_t fUsedReservedVertexBytes;
- size_t fUsedReservedIndexBytes;
-
- enum {
- kDrawPreallocCnt = 8,
- kStatePreallocCnt = 8,
- kClipPreallocCnt = 8,
- kClearPreallocCnt = 4,
- };
- GrAlignedSTStorage<kDrawPreallocCnt, Draw> fDrawStorage;
- GrAlignedSTStorage<kStatePreallocCnt, SavedDrawState> fStateStorage;
- GrAlignedSTStorage<kClipPreallocCnt, GrClip> fClipStorage;
- GrAlignedSTStorage<kClearPreallocCnt, Clear> fClearStorage;
+ struct GeometryPoolState {
+ const GrVertexBuffer* fPoolVertexBuffer;
+ int fPoolStartVertex;
+ const GrIndexBuffer* fPoolIndexBuffer;
+ int fPoolStartIndex;
+ // caller may conservatively over reserve vertices / indices.
+ // we release unused space back to allocator if possible
+ // can only do this if there isn't an intervening pushGeometrySource()
+ size_t fUsedPoolVertexBytes;
+ size_t fUsedPoolIndexBytes;
+ };
+ SkSTArray<kGeoPoolStatePreAllocCnt, GeometryPoolState> fGeoPoolStateStack;
typedef GrDrawTarget INHERITED;
};
diff --git a/src/gpu/GrIndexBuffer.h b/src/gpu/GrIndexBuffer.h
new file mode 100644
index 0000000..faa5018
--- /dev/null
+++ b/src/gpu/GrIndexBuffer.h
@@ -0,0 +1,33 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrIndexBuffer_DEFINED
+#define GrIndexBuffer_DEFINED
+
+#include "GrGeometryBuffer.h"
+
+class GrIndexBuffer : public GrGeometryBuffer {
+public:
+ /**
+ * Retrieves the maximum number of quads that could be rendered
+ * from the index buffer (using kTriangles_PrimitiveType).
+ * @return the maximum number of quads using full size of index buffer.
+ */
+ int maxQuads() const {
+ return this->sizeInBytes() / (sizeof(uint16_t) * 6);
+ }
+protected:
+ GrIndexBuffer(GrGpu* gpu, size_t sizeInBytes, bool dynamic)
+ : INHERITED(gpu, sizeInBytes, dynamic) {}
+private:
+ typedef GrGeometryBuffer INHERITED;
+};
+
+#endif
diff --git a/gpu/src/GrMatrix.cpp b/src/gpu/GrMatrix.cpp
index 476d9a2..e71636b 100644
--- a/gpu/src/GrMatrix.cpp
+++ b/src/gpu/GrMatrix.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "GrMatrix.h"
#include "GrRect.h"
#include <stddef.h>
diff --git a/src/gpu/GrMemory.cpp b/src/gpu/GrMemory.cpp
new file mode 100644
index 0000000..fa6ee2f
--- /dev/null
+++ b/src/gpu/GrMemory.cpp
@@ -0,0 +1,27 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#include <stdlib.h>
+
+void* GrMalloc(size_t bytes) {
+ void* ptr = ::malloc(bytes);
+ if (NULL == ptr) {
+ ::exit(-1);
+ }
+ return ptr;
+}
+
+void GrFree(void* ptr) {
+ if (ptr) {
+ ::free(ptr);
+ }
+}
+
+
diff --git a/src/gpu/GrPathRenderer.cpp b/src/gpu/GrPathRenderer.cpp
new file mode 100644
index 0000000..a4f7d0c
--- /dev/null
+++ b/src/gpu/GrPathRenderer.cpp
@@ -0,0 +1,43 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrPathRenderer.h"
+
+GrPathRenderer::GrPathRenderer()
+ : fPath(NULL)
+ , fTarget(NULL) {
+}
+
+void GrPathRenderer::setPath(GrDrawTarget* target,
+ const SkPath* path,
+ GrPathFill fill,
+ bool antiAlias,
+ const GrPoint* translate) {
+ GrAssert(NULL == fPath);
+ GrAssert(NULL == fTarget);
+ GrAssert(NULL != target);
+
+ fTarget = target;
+ fPath = path;
+ fFill = fill;
+ fAntiAlias = antiAlias;
+ if (NULL != translate) {
+ fTranslate = *translate;
+ } else {
+ fTranslate.fX = fTranslate.fY = 0;
+ }
+ this->pathWasSet();
+}
+
+void GrPathRenderer::clearPath() {
+ this->pathWillClear();
+ fTarget->resetVertexSource();
+ fTarget->resetIndexSource();
+ fTarget = NULL;
+ fPath = NULL;
+}
diff --git a/src/gpu/GrPathRenderer.h b/src/gpu/GrPathRenderer.h
new file mode 100644
index 0000000..e24b982
--- /dev/null
+++ b/src/gpu/GrPathRenderer.h
@@ -0,0 +1,218 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrPathRenderer_DEFINED
+#define GrPathRenderer_DEFINED
+
+#include "GrDrawTarget.h"
+#include "GrPathRendererChain.h"
+
+#include "SkTArray.h"
+
+class SkPath;
+
+struct GrPoint;
+
+/**
+ * Base class for drawing paths into a GrDrawTarget.
+ * Paths may be drawn multiple times as when tiling for supersampling. The
+ * calls on GrPathRenderer to draw a path will look like this:
+ *
+ * pr->setPath(target, path, fill, aa, translate); // sets the path to draw
+ * pr->drawPath(...); // draw the path
+ * pr->drawPath(...);
+ * ...
+ * pr->clearPath(); // finished with the path
+ */
+class GR_API GrPathRenderer : public GrRefCnt {
+public:
+
+ /**
+ * This is called to install custom path renderers in every GrContext at
+ * create time. The default implementation in GrCreatePathRenderer_none.cpp
+ * does not add any additional renderers. Link against another
+ * implementation to install your own. The first added is the most preferred
+ * path renderer, second is second most preferred, etc.
+ *
+ * @param context the context that will use the path renderer
+ * @param flags flags indicating how path renderers will be used
+ * @param prChain the chain to add path renderers to.
+ */
+ static void AddPathRenderers(GrContext* context,
+ GrPathRendererChain::UsageFlags flags,
+ GrPathRendererChain* prChain);
+
+
+ GrPathRenderer(void);
+ /**
+ * Returns true if this path renderer is able to render the path.
+ * Returning false allows the caller to fallback to another path renderer.
+ * When searching for a path renderer capable of rendering a path this
+ * function is called.
+ *
+ * @param targetCaps The caps of the draw target that will be used to draw
+ * the path.
+ * @param path The path to draw
+ * @param fill The fill rule to use
+ * @param antiAlias True if anti-aliasing is required.
+ *
+ * @return true if the path can be drawn by this object, false otherwise.
+ */
+ virtual bool canDrawPath(const GrDrawTarget::Caps& targetCaps,
+ const SkPath& path,
+ GrPathFill fill,
+ bool antiAlias) const = 0;
+
+ /**
+ * For complex clips Gr uses the stencil buffer. The path renderer must be
+ * able to render paths into the stencil buffer. However, the path renderer
+ * itself may require the stencil buffer to resolve the path fill rule.
+ * This function queries whether the path render needs its own stencil
+ * pass. If this returns false then drawPath() should not modify the
+ * the target's stencil settings but use those already set on target. The
+ * target is passed as a param in case the answer depends upon draw state.
+ * The view matrix and render target set on the draw target may change
+ * before setPath/drawPath is called and so shouldn't be considered.
+ *
+ * @param target target that the path will be rendered to
+ * @param path the path that will be drawn
+ * @param fill the fill rule that will be used, will never be an inverse
+ * rule.
+ *
+ * @return false if this path renderer can generate interior-only fragments
+ * without changing the stencil settings on the target. If it
+ * returns true the drawPathToStencil will be used when rendering
+ * clips.
+ */
+ virtual bool requiresStencilPass(const GrDrawTarget* target,
+ const SkPath& path,
+ GrPathFill fill) const { return false; }
+
+ /**
+ * Sets the path to render and target to render into. All calls to drawPath
+ * and drawPathToStencil must occur between setPath and clearPath. The
+ * path cannot be modified externally between setPath and clearPath. The
+ * path may be drawn several times (e.g. tiled supersampler). The target's
+ * state may change between setPath and drawPath* calls. However, if the
+ * path renderer specified vertices/indices during setPath or drawPath*
+ * they will still be set at subsequent drawPath* calls until the next
+ * clearPath. The target's draw state may change between drawPath* calls
+ * so if the subclass does any caching of tesselation, etc. then it must
+ * validate that target parameters that guided the decisions still hold.
+ *
+ * @param target the target to draw into.
+ * @param path the path to draw.
+ * @param fill the fill rule to apply.
+ * @param antiAlias perform antiAliasing when drawing the path.
+ * @param translate optional additional translation to apply to
+ * the path. NULL means (0,0).
+ */
+ void setPath(GrDrawTarget* target,
+ const SkPath* path,
+ GrPathFill fill,
+ bool antiAlias,
+ const GrPoint* translate);
+
+ /**
+ * Notifies path renderer that path set in setPath is no longer in use.
+ */
+ void clearPath();
+
+ /**
+ * Draws the path into the draw target. If requiresStencilBuffer returned
+ * false then the target may be setup for stencil rendering (since the
+ * path renderer didn't claim that it needs to use the stencil internally).
+ *
+ * Only called between setPath / clearPath.
+ *
+ * @param stages bitfield that indicates which stages are
+ * in use. All enabled stages expect positions
+ * as texture coordinates. The path renderer
+ * use the remaining stages for its path
+ * filling algorithm.
+ */
+ virtual void drawPath(GrDrawState::StageMask stageMask) = 0;
+
+ /**
+ * Draws the path to the stencil buffer. Assume the writable stencil bits
+ * are already initialized to zero. Fill will always be either
+ * kWinding_PathFill or kEvenOdd_PathFill.
+ *
+ * Only called if requiresStencilPass returns true for the same combo of
+ * target, path, and fill. Never called with an inverse fill.
+ *
+ * The default implementation assumes the path filling algorithm doesn't
+ * require a separate stencil pass and so crashes.
+ *
+ * Only called between setPath / clearPath.
+ */
+ virtual void drawPathToStencil() {
+ GrCrash("Unexpected call to drawPathToStencil.");
+ }
+
+ /**
+ * Helper that sets a path and automatically remove it in destructor.
+ */
+ class AutoClearPath {
+ public:
+ AutoClearPath() {
+ fPathRenderer = NULL;
+ }
+ AutoClearPath(GrPathRenderer* pr,
+ GrDrawTarget* target,
+ const SkPath* path,
+ GrPathFill fill,
+ bool antiAlias,
+ const GrPoint* translate) {
+ GrAssert(NULL != pr);
+ pr->setPath(target, path, fill, antiAlias, translate);
+ fPathRenderer = pr;
+ }
+ void set(GrPathRenderer* pr,
+ GrDrawTarget* target,
+ const SkPath* path,
+ GrPathFill fill,
+ bool antiAlias,
+ const GrPoint* translate) {
+ if (NULL != fPathRenderer) {
+ fPathRenderer->clearPath();
+ }
+ GrAssert(NULL != pr);
+ pr->setPath(target, path, fill, antiAlias, translate);
+ fPathRenderer = pr;
+ }
+ ~AutoClearPath() {
+ if (NULL != fPathRenderer) {
+ fPathRenderer->clearPath();
+ }
+ }
+ private:
+ GrPathRenderer* fPathRenderer;
+ };
+
+protected:
+
+ // subclass can override these to be notified just after a path is set
+ // and just before the path is cleared.
+ virtual void pathWasSet() {}
+ virtual void pathWillClear() {}
+
+ const SkPath* fPath;
+ GrDrawTarget* fTarget;
+ GrPathFill fFill;
+ GrPoint fTranslate;
+ bool fAntiAlias;
+
+private:
+
+ typedef GrRefCnt INHERITED;
+};
+
+#endif
+
diff --git a/src/gpu/GrPathRendererChain.cpp b/src/gpu/GrPathRendererChain.cpp
new file mode 100644
index 0000000..a45437b
--- /dev/null
+++ b/src/gpu/GrPathRendererChain.cpp
@@ -0,0 +1,59 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrPathRendererChain.h"
+
+#include "GrContext.h"
+#include "GrDefaultPathRenderer.h"
+#include "GrGpu.h"
+
+GrPathRendererChain::GrPathRendererChain(GrContext* context, UsageFlags flags)
+ : fInit(false)
+ , fOwner(context)
+ , fFlags(flags) {
+ fInit = false;
+}
+
+GrPathRendererChain::~GrPathRendererChain() {
+ for (int i = 0; i < fChain.count(); ++i) {
+ fChain[i]->unref();
+ }
+}
+
+GrPathRenderer* GrPathRendererChain::addPathRenderer(GrPathRenderer* pr) {
+ fChain.push_back() = pr;
+ pr->ref();
+ return pr;
+}
+
+GrPathRenderer* GrPathRendererChain::getPathRenderer(
+ const GrDrawTarget::Caps& targetCaps,
+ const GrPath& path,
+ GrPathFill fill,
+ bool antiAlias) {
+ if (!fInit) {
+ this->init();
+ }
+ for (int i = 0; i < fChain.count(); ++i) {
+ if (fChain[i]->canDrawPath(targetCaps, path, fill, antiAlias)) {
+ return fChain[i];
+ }
+ }
+ return NULL;
+}
+
+void GrPathRendererChain::init() {
+ GrAssert(!fInit);
+ GrGpu* gpu = fOwner->getGpu();
+ bool twoSided = gpu->getCaps().fTwoSidedStencilSupport;
+ bool wrapOp = gpu->getCaps().fStencilWrapOpsSupport;
+ GrPathRenderer::AddPathRenderers(fOwner, fFlags, this);
+ this->addPathRenderer(new GrDefaultPathRenderer(twoSided, wrapOp))->unref();
+ fInit = true;
+}
diff --git a/src/gpu/GrPathRendererChain.h b/src/gpu/GrPathRendererChain.h
new file mode 100644
index 0000000..8f95ea3
--- /dev/null
+++ b/src/gpu/GrPathRendererChain.h
@@ -0,0 +1,65 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrPathRendererChain_DEFINED
+#define GrPathRendererChain_DEFINED
+
+#include "GrDrawTarget.h"
+#include "GrRefCnt.h"
+#include "SkTArray.h"
+
+class GrContext;
+
+class SkPath;
+class GrPathRenderer;
+
+/**
+ * Keeps track of a ordered list of path renderers. When a path needs to be
+ * drawn this list is scanned to find the most preferred renderer. To add your
+ * path renderer to the list implement the GrPathRenderer::AddPathRenderers
+ * function.
+ */
+class GrPathRendererChain : public SkRefCnt {
+public:
+
+ enum UsageFlags {
+ kNone_UsageFlag = 0,
+ kNonAAOnly_UsageFlag = 1,
+ };
+
+ GrPathRendererChain(GrContext* context, UsageFlags flags);
+
+ ~GrPathRendererChain();
+
+ // takes a ref and unrefs in destructor
+ GrPathRenderer* addPathRenderer(GrPathRenderer* pr);
+
+ GrPathRenderer* getPathRenderer(const GrDrawTarget::Caps& targetCaps,
+ const SkPath& path,
+ GrPathFill fill,
+ bool antiAlias);
+
+private:
+
+ GrPathRendererChain();
+
+ void init();
+
+ enum {
+ kPreAllocCount = 8,
+ };
+ bool fInit;
+ GrContext* fOwner;
+ UsageFlags fFlags;
+ SkSTArray<kPreAllocCount, GrPathRenderer*, true> fChain;
+};
+
+GR_MAKE_BITFIELD_OPS(GrPathRendererChain::UsageFlags)
+
+#endif
diff --git a/gpu/src/GrPathUtils.cpp b/src/gpu/GrPathUtils.cpp
index 8a72ba8..0a7759d 100644
--- a/gpu/src/GrPathUtils.cpp
+++ b/src/gpu/GrPathUtils.cpp
@@ -1,30 +1,51 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "GrPathUtils.h"
+
#include "GrPoint.h"
-const GrScalar GrPathUtils::gTolerance = GR_Scalar1;
+GrScalar GrPathUtils::scaleToleranceToSrc(GrScalar devTol,
+ const GrMatrix& viewM,
+ const GrRect& pathBounds) {
+ // In order to tesselate the path we get a bound on how much the matrix can
+ // stretch when mapping to screen coordinates.
+ GrScalar stretch = viewM.getMaxStretch();
+ GrScalar srcTol = devTol;
+
+ if (stretch < 0) {
+ // take worst case mapRadius amoung four corners.
+ // (less than perfect)
+ for (int i = 0; i < 4; ++i) {
+ GrMatrix mat;
+ mat.setTranslate((i % 2) ? pathBounds.fLeft : pathBounds.fRight,
+ (i < 2) ? pathBounds.fTop : pathBounds.fBottom);
+ mat.postConcat(viewM);
+ stretch = SkMaxScalar(stretch, mat.mapRadius(SK_Scalar1));
+ }
+ }
+ srcTol = GrScalarDiv(srcTol, stretch);
+ return srcTol;
+}
-static const uint32_t MAX_POINTS_PER_CURVE = 1 << 10;
+static const int MAX_POINTS_PER_CURVE = 1 << 10;
+static const GrScalar gMinCurveTol = GrFloatToScalar(0.0001f);
uint32_t GrPathUtils::quadraticPointCount(const GrPoint points[],
- GrScalar tol) {
+ GrScalar tol) {
+ if (tol < gMinCurveTol) {
+ tol = gMinCurveTol;
+ }
+ GrAssert(tol > 0);
+
GrScalar d = points[1].distanceToLineSegmentBetween(points[0], points[2]);
- if (d < tol) {
+ if (d <= tol) {
return 1;
} else {
// Each time we subdivide, d should be cut in 4. So we need to
@@ -32,16 +53,23 @@ uint32_t GrPathUtils::quadraticPointCount(const GrPoint points[],
// points.
// 2^(log4(x)) = sqrt(x);
int temp = SkScalarCeil(SkScalarSqrt(SkScalarDiv(d, tol)));
- return GrMin(GrNextPow2(temp), MAX_POINTS_PER_CURVE);
+ int pow2 = GrNextPow2(temp);
+ // Because of NaNs & INFs we can wind up with a degenerate temp
+ // such that pow2 comes out negative. Also, our point generator
+ // will always output at least one pt.
+ if (pow2 < 1) {
+ pow2 = 1;
+ }
+ return GrMin(pow2, MAX_POINTS_PER_CURVE);
}
}
uint32_t GrPathUtils::generateQuadraticPoints(const GrPoint& p0,
- const GrPoint& p1,
- const GrPoint& p2,
- GrScalar tolSqd,
- GrPoint** points,
- uint32_t pointsLeft) {
+ const GrPoint& p1,
+ const GrPoint& p2,
+ GrScalar tolSqd,
+ GrPoint** points,
+ uint32_t pointsLeft) {
if (pointsLeft < 2 ||
(p1.distanceToLineSegmentBetweenSqd(p0, p2)) < tolSqd) {
(*points)[0] = p2;
@@ -63,24 +91,37 @@ uint32_t GrPathUtils::generateQuadraticPoints(const GrPoint& p0,
uint32_t GrPathUtils::cubicPointCount(const GrPoint points[],
GrScalar tol) {
- GrScalar d = GrMax(points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]),
- points[2].distanceToLineSegmentBetweenSqd(points[0], points[3]));
+ if (tol < gMinCurveTol) {
+ tol = gMinCurveTol;
+ }
+ GrAssert(tol > 0);
+
+ GrScalar d = GrMax(
+ points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]),
+ points[2].distanceToLineSegmentBetweenSqd(points[0], points[3]));
d = SkScalarSqrt(d);
- if (d < tol) {
+ if (d <= tol) {
return 1;
} else {
int temp = SkScalarCeil(SkScalarSqrt(SkScalarDiv(d, tol)));
- return GrMin(GrNextPow2(temp), MAX_POINTS_PER_CURVE);
+ int pow2 = GrNextPow2(temp);
+ // Because of NaNs & INFs we can wind up with a degenerate temp
+ // such that pow2 comes out negative. Also, our point generator
+ // will always output at least one pt.
+ if (pow2 < 1) {
+ pow2 = 1;
+ }
+ return GrMin(pow2, MAX_POINTS_PER_CURVE);
}
}
uint32_t GrPathUtils::generateCubicPoints(const GrPoint& p0,
- const GrPoint& p1,
- const GrPoint& p2,
- const GrPoint& p3,
- GrScalar tolSqd,
- GrPoint** points,
- uint32_t pointsLeft) {
+ const GrPoint& p1,
+ const GrPoint& p2,
+ const GrPoint& p3,
+ GrScalar tolSqd,
+ GrPoint** points,
+ uint32_t pointsLeft) {
if (pointsLeft < 2 ||
(p1.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd &&
p2.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd)) {
@@ -106,12 +147,17 @@ uint32_t GrPathUtils::generateCubicPoints(const GrPoint& p0,
int GrPathUtils::worstCasePointCount(const GrPath& path, int* subpaths,
GrScalar tol) {
+ if (tol < gMinCurveTol) {
+ tol = gMinCurveTol;
+ }
+ GrAssert(tol > 0);
+
int pointCount = 0;
*subpaths = 1;
bool first = true;
- SkPath::Iter iter(path, true);
+ SkPath::Iter iter(path, false);
GrPathCmd cmd;
GrPoint pts[4];
diff --git a/src/gpu/GrPathUtils.h b/src/gpu/GrPathUtils.h
new file mode 100644
index 0000000..5dc06aa
--- /dev/null
+++ b/src/gpu/GrPathUtils.h
@@ -0,0 +1,50 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrPathUtils_DEFINED
+#define GrPathUtils_DEFINED
+
+#include "GrMatrix.h"
+#include "GrPath.h"
+
+/**
+ * Utilities for evaluating paths.
+ */
+namespace GrPathUtils {
+ GrScalar scaleToleranceToSrc(GrScalar devTol,
+ const GrMatrix& viewM,
+ const GrRect& pathBounds);
+
+ /// Since we divide by tol if we're computing exact worst-case bounds,
+ /// very small tolerances will be increased to gMinCurveTol.
+ int worstCasePointCount(const GrPath&,
+ int* subpaths,
+ GrScalar tol);
+ /// Since we divide by tol if we're computing exact worst-case bounds,
+ /// very small tolerances will be increased to gMinCurveTol.
+ uint32_t quadraticPointCount(const GrPoint points[], GrScalar tol);
+ uint32_t generateQuadraticPoints(const GrPoint& p0,
+ const GrPoint& p1,
+ const GrPoint& p2,
+ GrScalar tolSqd,
+ GrPoint** points,
+ uint32_t pointsLeft);
+ /// Since we divide by tol if we're computing exact worst-case bounds,
+ /// very small tolerances will be increased to gMinCurveTol.
+ uint32_t cubicPointCount(const GrPoint points[], GrScalar tol);
+ uint32_t generateCubicPoints(const GrPoint& p0,
+ const GrPoint& p1,
+ const GrPoint& p2,
+ const GrPoint& p3,
+ GrScalar tolSqd,
+ GrPoint** points,
+ uint32_t pointsLeft);
+
+};
+#endif
diff --git a/gpu/include/GrPlotMgr.h b/src/gpu/GrPlotMgr.h
index cd60bde..0e631a9 100644
--- a/gpu/include/GrPlotMgr.h
+++ b/src/gpu/GrPlotMgr.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrPlotMgr_DEFINED
#define GrPlotMgr_DEFINED
diff --git a/src/gpu/GrPrintf_printf.cpp b/src/gpu/GrPrintf_printf.cpp
new file mode 100644
index 0000000..909a4f0
--- /dev/null
+++ b/src/gpu/GrPrintf_printf.cpp
@@ -0,0 +1,29 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#include "GrTypes.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+void GrPrintf(const char format[], ...) {
+ const size_t MAX_BUFFER_SIZE = 2048;
+
+ char buffer[MAX_BUFFER_SIZE + 1];
+ va_list args;
+
+ va_start(args, format);
+ vsnprintf(buffer, MAX_BUFFER_SIZE, format, args);
+ va_end(args);
+
+ printf("%s", buffer);
+}
+
+
diff --git a/src/gpu/GrPrintf_skia.cpp b/src/gpu/GrPrintf_skia.cpp
index 6da8822..9bab419 100644
--- a/src/gpu/GrPrintf_skia.cpp
+++ b/src/gpu/GrPrintf_skia.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "GrTypes.h"
#include <stdarg.h>
diff --git a/gpu/include/GrRandom.h b/src/gpu/GrRandom.h
index 408f61d..c98a8fb 100644
--- a/gpu/include/GrRandom.h
+++ b/src/gpu/GrRandom.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrRandom_DEFINED
#define GrRandom_DEFINED
diff --git a/gpu/src/GrRectanizer.cpp b/src/gpu/GrRectanizer.cpp
index cb6576a..628b890 100644
--- a/gpu/src/GrRectanizer.cpp
+++ b/src/gpu/GrRectanizer.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "GrRectanizer.h"
#include "GrTBSearch.h"
diff --git a/gpu/include/GrRectanizer.h b/src/gpu/GrRectanizer.h
index 50bb8fe..d1f5033 100644
--- a/gpu/include/GrRectanizer.h
+++ b/src/gpu/GrRectanizer.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrRectanizer_DEFINED
#define GrRectanizer_DEFINED
diff --git a/gpu/src/GrRectanizer_fifo.cpp b/src/gpu/GrRectanizer_fifo.cpp
index 6b1cad2..3bfc46f 100644
--- a/gpu/src/GrRectanizer_fifo.cpp
+++ b/src/gpu/GrRectanizer_fifo.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "GrRectanizer.h"
#include "GrTBSearch.h"
diff --git a/gpu/src/GrRedBlackTree.h b/src/gpu/GrRedBlackTree.h
index b57ce9e..da5ae3e 100644
--- a/gpu/src/GrRedBlackTree.h
+++ b/src/gpu/GrRedBlackTree.h
@@ -1,19 +1,12 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrRedBlackTree_DEFINED
#define GrRedBlackTree_DEFINED
@@ -361,7 +354,7 @@ typename GrRedBlackTree<T,C>::Iter GrRedBlackTree<T,C>::insert(const T& t) {
Node* p = NULL;
Node* n = fRoot;
Child pc = kLeft_Child; // suppress uninit warning
- Child gpc;
+ Child gpc = kLeft_Child;
bool first = true;
bool last = true;
diff --git a/src/gpu/GrRenderTarget.cpp b/src/gpu/GrRenderTarget.cpp
new file mode 100644
index 0000000..7901648
--- /dev/null
+++ b/src/gpu/GrRenderTarget.cpp
@@ -0,0 +1,92 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrRenderTarget.h"
+
+#include "GrContext.h"
+#include "GrGpu.h"
+#include "GrStencilBuffer.h"
+
+bool GrRenderTarget::readPixels(int left, int top, int width, int height,
+ GrPixelConfig config, void* buffer,
+ size_t rowBytes) {
+ // go through context so that all necessary flushing occurs
+ GrContext* context = this->getContext();
+ if (NULL == context) {
+ return false;
+ }
+ return context->readRenderTargetPixels(this,
+ left, top,
+ width, height,
+ config, buffer, rowBytes);
+}
+
+void GrRenderTarget::writePixels(int left, int top, int width, int height,
+ GrPixelConfig config, const void* buffer,
+ size_t rowBytes) {
+ // go through context so that all necessary flushing occurs
+ GrContext* context = this->getContext();
+ if (NULL == context) {
+ return;
+ }
+ context->writeRenderTargetPixels(this,
+ left, top,
+ width, height,
+ config, buffer, rowBytes);
+}
+
+size_t GrRenderTarget::sizeInBytes() const {
+ int colorBits;
+ if (kUnknown_GrPixelConfig == fConfig) {
+ colorBits = 32; // don't know, make a guess
+ } else {
+ colorBits = GrBytesPerPixel(fConfig);
+ }
+ uint64_t size = fWidth;
+ size *= fHeight;
+ size *= colorBits;
+ size *= GrMax(1,fSampleCnt);
+ return (size_t)(size / 8);
+}
+
+void GrRenderTarget::flagAsNeedingResolve(const GrIRect* rect) {
+ if (kCanResolve_ResolveType == getResolveType()) {
+ if (NULL != rect) {
+ fResolveRect.join(*rect);
+ if (!fResolveRect.intersect(0, 0, this->width(), this->height())) {
+ fResolveRect.setEmpty();
+ }
+ } else {
+ fResolveRect.setLTRB(0, 0, this->width(), this->height());
+ }
+ }
+}
+
+void GrRenderTarget::overrideResolveRect(const GrIRect rect) {
+ fResolveRect = rect;
+ if (fResolveRect.isEmpty()) {
+ fResolveRect.setLargestInverted();
+ } else {
+ if (!fResolveRect.intersect(0, 0, this->width(), this->height())) {
+ fResolveRect.setLargestInverted();
+ }
+ }
+}
+
+void GrRenderTarget::setStencilBuffer(GrStencilBuffer* stencilBuffer) {
+ if (NULL != fStencilBuffer) {
+ fStencilBuffer->wasDetachedFromRenderTarget(this);
+ fStencilBuffer->unref();
+ }
+ fStencilBuffer = stencilBuffer;
+ if (NULL != fStencilBuffer) {
+ fStencilBuffer->wasAttachedToRenderTarget(this);
+ fStencilBuffer->ref();
+ }
+}
diff --git a/src/gpu/GrResource.cpp b/src/gpu/GrResource.cpp
new file mode 100644
index 0000000..63d2e7b
--- /dev/null
+++ b/src/gpu/GrResource.cpp
@@ -0,0 +1,51 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrResource.h"
+#include "GrGpu.h"
+
+GrResource::GrResource(GrGpu* gpu) {
+ fGpu = gpu;
+ fNext = NULL;
+ fPrevious = NULL;
+ fGpu->insertResource(this);
+}
+
+void GrResource::release() {
+ if (NULL != fGpu) {
+ this->onRelease();
+ fGpu->removeResource(this);
+ fGpu = NULL;
+ }
+}
+
+void GrResource::abandon() {
+ if (NULL != fGpu) {
+ this->onAbandon();
+ fGpu->removeResource(this);
+ fGpu = NULL;
+ }
+}
+
+const GrContext* GrResource::getContext() const {
+ if (NULL != fGpu) {
+ return fGpu->getContext();
+ } else {
+ return NULL;
+ }
+}
+
+GrContext* GrResource::getContext() {
+ if (NULL != fGpu) {
+ return fGpu->getContext();
+ } else {
+ return NULL;
+ }
+}
+
diff --git a/src/gpu/GrResourceCache.cpp b/src/gpu/GrResourceCache.cpp
new file mode 100644
index 0000000..afbe9b3
--- /dev/null
+++ b/src/gpu/GrResourceCache.cpp
@@ -0,0 +1,380 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#include "GrResourceCache.h"
+#include "GrResource.h"
+
+GrResourceEntry::GrResourceEntry(const GrResourceKey& key, GrResource* resource)
+ : fKey(key), fResource(resource) {
+ fLockCount = 0;
+ fPrev = fNext = NULL;
+
+ // we assume ownership of the resource, and will unref it when we die
+ GrAssert(resource);
+}
+
+GrResourceEntry::~GrResourceEntry() {
+ fResource->unref();
+}
+
+#if GR_DEBUG
+void GrResourceEntry::validate() const {
+ GrAssert(fLockCount >= 0);
+ GrAssert(fResource);
+ fResource->validate();
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrResourceCache::GrResourceCache(int maxCount, size_t maxBytes) :
+ fMaxCount(maxCount),
+ fMaxBytes(maxBytes) {
+ fEntryCount = 0;
+ fUnlockedEntryCount = 0;
+ fEntryBytes = 0;
+ fClientDetachedCount = 0;
+ fClientDetachedBytes = 0;
+
+ fHead = fTail = NULL;
+ fPurging = false;
+}
+
+GrResourceCache::~GrResourceCache() {
+ GrAutoResourceCacheValidate atcv(this);
+
+ this->removeAll();
+}
+
+void GrResourceCache::getLimits(int* maxResources, size_t* maxResourceBytes) const{
+ if (maxResources) {
+ *maxResources = fMaxCount;
+ }
+ if (maxResourceBytes) {
+ *maxResourceBytes = fMaxBytes;
+ }
+}
+
+void GrResourceCache::setLimits(int maxResources, size_t maxResourceBytes) {
+ bool smaller = (maxResources < fMaxCount) || (maxResourceBytes < fMaxBytes);
+
+ fMaxCount = maxResources;
+ fMaxBytes = maxResourceBytes;
+
+ if (smaller) {
+ this->purgeAsNeeded();
+ }
+}
+
+void GrResourceCache::internalDetach(GrResourceEntry* entry,
+ bool clientDetach) {
+ GrResourceEntry* prev = entry->fPrev;
+ GrResourceEntry* next = entry->fNext;
+
+ if (prev) {
+ prev->fNext = next;
+ } else {
+ fHead = next;
+ }
+ if (next) {
+ next->fPrev = prev;
+ } else {
+ fTail = prev;
+ }
+ if (!entry->isLocked()) {
+ --fUnlockedEntryCount;
+ }
+
+ // update our stats
+ if (clientDetach) {
+ fClientDetachedCount += 1;
+ fClientDetachedBytes += entry->resource()->sizeInBytes();
+ } else {
+ fEntryCount -= 1;
+ fEntryBytes -= entry->resource()->sizeInBytes();
+ }
+}
+
+void GrResourceCache::attachToHead(GrResourceEntry* entry,
+ bool clientReattach) {
+ entry->fPrev = NULL;
+ entry->fNext = fHead;
+ if (fHead) {
+ fHead->fPrev = entry;
+ }
+ fHead = entry;
+ if (NULL == fTail) {
+ fTail = entry;
+ }
+ if (!entry->isLocked()) {
+ ++fUnlockedEntryCount;
+ }
+
+ // update our stats
+ if (clientReattach) {
+ fClientDetachedCount -= 1;
+ fClientDetachedBytes -= entry->resource()->sizeInBytes();
+ } else {
+ fEntryCount += 1;
+ fEntryBytes += entry->resource()->sizeInBytes();
+ }
+}
+
+class GrResourceCache::Key {
+ typedef GrResourceEntry T;
+
+ const GrResourceKey& fKey;
+public:
+ Key(const GrResourceKey& key) : fKey(key) {}
+
+ uint32_t getHash() const { return fKey.hashIndex(); }
+
+ static bool LT(const T& entry, const Key& key) {
+ return entry.key() < key.fKey;
+ }
+ static bool EQ(const T& entry, const Key& key) {
+ return entry.key() == key.fKey;
+ }
+#if GR_DEBUG
+ static uint32_t GetHash(const T& entry) {
+ return entry.key().hashIndex();
+ }
+ static bool LT(const T& a, const T& b) {
+ return a.key() < b.key();
+ }
+ static bool EQ(const T& a, const T& b) {
+ return a.key() == b.key();
+ }
+#endif
+};
+
+GrResourceEntry* GrResourceCache::findAndLock(const GrResourceKey& key,
+ LockType type) {
+ GrAutoResourceCacheValidate atcv(this);
+
+ GrResourceEntry* entry = fCache.find(key);
+ if (entry) {
+ this->internalDetach(entry, false);
+ // mark the entry as "busy" so it doesn't get purged
+ // do this between detach and attach for locked count tracking
+ if (kNested_LockType == type || !entry->isLocked()) {
+ entry->lock();
+ }
+ this->attachToHead(entry, false);
+ }
+ return entry;
+}
+
+bool GrResourceCache::hasKey(const GrResourceKey& key) const {
+ return NULL != fCache.find(key);
+}
+
+GrResourceEntry* GrResourceCache::createAndLock(const GrResourceKey& key,
+ GrResource* resource) {
+ // we don't expect to create new resources during a purge. In theory
+ // this could cause purgeAsNeeded() into an infinite loop (e.g.
+ // each resource destroyed creates and locks 2 resources and
+ // unlocks 1 thereby causing a new purge).
+ GrAssert(!fPurging);
+ GrAutoResourceCacheValidate atcv(this);
+
+ GrResourceEntry* entry = new GrResourceEntry(key, resource);
+
+ // mark the entry as "busy" so it doesn't get purged
+ // do this before attach for locked count tracking
+ entry->lock();
+
+ this->attachToHead(entry, false);
+ fCache.insert(key, entry);
+
+#if GR_DUMP_TEXTURE_UPLOAD
+ GrPrintf("--- add resource to cache %p, count=%d bytes= %d %d\n",
+ entry, fEntryCount, resource->sizeInBytes(), fEntryBytes);
+#endif
+
+ this->purgeAsNeeded();
+ return entry;
+}
+
+void GrResourceCache::detach(GrResourceEntry* entry) {
+ GrAutoResourceCacheValidate atcv(this);
+ internalDetach(entry, true);
+ fCache.remove(entry->fKey, entry);
+}
+
+void GrResourceCache::reattachAndUnlock(GrResourceEntry* entry) {
+ GrAutoResourceCacheValidate atcv(this);
+ if (entry->resource()->isValid()) {
+ attachToHead(entry, true);
+ fCache.insert(entry->key(), entry);
+ } else {
+ // If the resource went invalid while it was detached then purge it
+ // This can happen when a 3D context was lost,
+ // the client called GrContext::contextDestroyed() to notify Gr,
+ // and then later an SkGpuDevice's destructor releases its backing
+ // texture (which was invalidated at contextDestroyed time).
+ fClientDetachedCount -= 1;
+ fEntryCount -= 1;
+ size_t size = entry->resource()->sizeInBytes();
+ fClientDetachedBytes -= size;
+ fEntryBytes -= size;
+ }
+ this->unlock(entry);
+}
+
+void GrResourceCache::unlock(GrResourceEntry* entry) {
+ GrAutoResourceCacheValidate atcv(this);
+
+ GrAssert(entry);
+ GrAssert(entry->isLocked());
+ GrAssert(fCache.find(entry->key()));
+
+ entry->unlock();
+ if (!entry->isLocked()) {
+ ++fUnlockedEntryCount;
+ }
+ this->purgeAsNeeded();
+}
+
+/**
+ * Destroying a resource may potentially trigger the unlock of additional
+ * resources which in turn will trigger a nested purge. We block the nested
+ * purge using the fPurging variable. However, the initial purge will keep
+ * looping until either all resources in the cache are unlocked or we've met
+ * the budget. There is an assertion in createAndLock to check against a
+ * resource's destructor inserting new resources into the cache. If these
+ * new resources were unlocked before purgeAsNeeded completed it could
+ * potentially make purgeAsNeeded loop infinitely.
+ */
+void GrResourceCache::purgeAsNeeded() {
+ if (!fPurging) {
+ fPurging = true;
+ bool withinBudget = false;
+ do {
+ GrResourceEntry* entry = fTail;
+ while (entry && fUnlockedEntryCount) {
+ GrAutoResourceCacheValidate atcv(this);
+ if (fEntryCount <= fMaxCount && fEntryBytes <= fMaxBytes) {
+ withinBudget = true;
+ break;
+ }
+
+ GrResourceEntry* prev = entry->fPrev;
+ if (!entry->isLocked()) {
+ // remove from our cache
+ fCache.remove(entry->fKey, entry);
+
+ // remove from our llist
+ this->internalDetach(entry, false);
+
+ #if GR_DUMP_TEXTURE_UPLOAD
+ GrPrintf("--- ~resource from cache %p [%d %d]\n",
+ entry->resource(),
+ entry->resource()->width(),
+ entry->resource()->height());
+ #endif
+ delete entry;
+ }
+ entry = prev;
+ }
+ } while (!withinBudget && fUnlockedEntryCount);
+ fPurging = false;
+ }
+}
+
+void GrResourceCache::removeAll() {
+ GrAutoResourceCacheValidate atcv(this);
+
+ GrResourceEntry* entry = fHead;
+
+ // we can have one GrResource holding a lock on another
+ // so we don't want to just do a simple loop kicking each
+ // entry out. Instead change the budget and purge.
+
+ int savedMaxBytes = fMaxBytes;
+ int savedMaxCount = fMaxCount;
+ fMaxBytes = -1;
+ fMaxCount = 0;
+ this->purgeAsNeeded();
+
+ GrAssert(!fCache.count());
+ GrAssert(!fUnlockedEntryCount);
+ // Items may have been detached from the cache (such as the backing texture
+ // for an SkGpuDevice). The above purge would not have removed them.
+ GrAssert(fEntryCount == fClientDetachedCount);
+ GrAssert(fEntryBytes == fClientDetachedBytes);
+ GrAssert(NULL == fHead);
+ GrAssert(NULL == fTail);
+
+ fMaxBytes = savedMaxBytes;
+ fMaxCount = savedMaxCount;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#if GR_DEBUG
+static int countMatches(const GrResourceEntry* head, const GrResourceEntry* target) {
+ const GrResourceEntry* entry = head;
+ int count = 0;
+ while (entry) {
+ if (target == entry) {
+ count += 1;
+ }
+ entry = entry->next();
+ }
+ return count;
+}
+
+#if GR_DEBUG
+static bool both_zero_or_nonzero(int count, size_t bytes) {
+ return (count == 0 && bytes == 0) || (count > 0 && bytes > 0);
+}
+#endif
+
+void GrResourceCache::validate() const {
+ GrAssert(!fHead == !fTail);
+ GrAssert(both_zero_or_nonzero(fEntryCount, fEntryBytes));
+ GrAssert(both_zero_or_nonzero(fClientDetachedCount, fClientDetachedBytes));
+ GrAssert(fClientDetachedBytes <= fEntryBytes);
+ GrAssert(fClientDetachedCount <= fEntryCount);
+ GrAssert((fEntryCount - fClientDetachedCount) == fCache.count());
+
+ fCache.validate();
+
+ GrResourceEntry* entry = fHead;
+ int count = 0;
+ int unlockCount = 0;
+ size_t bytes = 0;
+ while (entry) {
+ entry->validate();
+ GrAssert(fCache.find(entry->key()));
+ count += 1;
+ bytes += entry->resource()->sizeInBytes();
+ if (!entry->isLocked()) {
+ unlockCount += 1;
+ }
+ entry = entry->fNext;
+ }
+ GrAssert(count == fEntryCount - fClientDetachedCount);
+ GrAssert(bytes == fEntryBytes - fClientDetachedBytes);
+ GrAssert(unlockCount == fUnlockedEntryCount);
+
+ count = 0;
+ for (entry = fTail; entry; entry = entry->fPrev) {
+ count += 1;
+ }
+ GrAssert(count == fEntryCount - fClientDetachedCount);
+
+ for (int i = 0; i < count; i++) {
+ int matches = countMatches(fHead, fCache.getArray()[i]);
+ GrAssert(1 == matches);
+ }
+}
+#endif
diff --git a/src/gpu/GrResourceCache.h b/src/gpu/GrResourceCache.h
new file mode 100644
index 0000000..e21c605
--- /dev/null
+++ b/src/gpu/GrResourceCache.h
@@ -0,0 +1,318 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrResourceCache_DEFINED
+#define GrResourceCache_DEFINED
+
+#include "GrTypes.h"
+#include "GrTHashCache.h"
+
+class GrResource;
+
+// return true if a<b, or false if b<a
+//
+#define RET_IF_LT_OR_GT(a, b) \
+ do { \
+ if ((a) < (b)) { \
+ return true; \
+ } \
+ if ((b) < (a)) { \
+ return false; \
+ } \
+ } while (0)
+
+/**
+ * Helper class for GrResourceCache, the Key is used to identify src data for
+ * a resource. It is identified by 2 32bit data fields which can hold any
+ * data (uninterpreted by the cache) and a width/height.
+ */
+class GrResourceKey {
+public:
+ enum {
+ kHashBits = 7,
+ kHashCount = 1 << kHashBits,
+ kHashMask = kHashCount - 1
+ };
+
+ GrResourceKey(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3) {
+ fP[0] = p0;
+ fP[1] = p1;
+ fP[2] = p2;
+ fP[3] = p3;
+ this->computeHashIndex();
+ }
+
+ GrResourceKey(uint32_t v[4]) {
+ memcpy(fP, v, 4 * sizeof(uint32_t));
+ this->computeHashIndex();
+ }
+
+ GrResourceKey(const GrResourceKey& src) {
+ memcpy(fP, src.fP, 4 * sizeof(uint32_t));
+#if GR_DEBUG
+ this->computeHashIndex();
+ GrAssert(fHashIndex == src.fHashIndex);
+#endif
+ fHashIndex = src.fHashIndex;
+ }
+
+ //!< returns hash value [0..kHashMask] for the key
+ int hashIndex() const { return fHashIndex; }
+
+ friend bool operator==(const GrResourceKey& a, const GrResourceKey& b) {
+ GR_DEBUGASSERT(-1 != a.fHashIndex && -1 != b.fHashIndex);
+ return 0 == memcmp(a.fP, b.fP, 4 * sizeof(uint32_t));
+ }
+
+ friend bool operator!=(const GrResourceKey& a, const GrResourceKey& b) {
+ GR_DEBUGASSERT(-1 != a.fHashIndex && -1 != b.fHashIndex);
+ return !(a == b);
+ }
+
+ friend bool operator<(const GrResourceKey& a, const GrResourceKey& b) {
+ RET_IF_LT_OR_GT(a.fP[0], b.fP[0]);
+ RET_IF_LT_OR_GT(a.fP[1], b.fP[1]);
+ RET_IF_LT_OR_GT(a.fP[2], b.fP[2]);
+ return a.fP[3] < b.fP[3];
+ }
+
+ uint32_t getValue32(int i) const {
+ GrAssert(i >=0 && i < 4);
+ return fP[i];
+ }
+private:
+
+ static uint32_t rol(uint32_t x) {
+ return (x >> 24) | (x << 8);
+ }
+ static uint32_t ror(uint32_t x) {
+ return (x >> 8) | (x << 24);
+ }
+ static uint32_t rohalf(uint32_t x) {
+ return (x >> 16) | (x << 16);
+ }
+
+ void computeHashIndex() {
+ uint32_t hash = fP[0] ^ rol(fP[1]) ^ ror(fP[2]) ^ rohalf(fP[3]);
+ // this way to mix and reduce hash to its index may have to change
+ // depending on how many bits we allocate to the index
+ hash ^= hash >> 16;
+ hash ^= hash >> 8;
+ fHashIndex = hash & kHashMask;
+ }
+
+ uint32_t fP[4];
+
+ // this is computed from the fP... fields
+ int fHashIndex;
+
+ friend class GrContext;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GrResourceEntry {
+public:
+ GrResource* resource() const { return fResource; }
+ const GrResourceKey& key() const { return fKey; }
+
+#if GR_DEBUG
+ GrResourceEntry* next() const { return fNext; }
+ GrResourceEntry* prev() const { return fPrev; }
+#endif
+
+#if GR_DEBUG
+ void validate() const;
+#else
+ void validate() const {}
+#endif
+
+private:
+ GrResourceEntry(const GrResourceKey& key, GrResource* resource);
+ ~GrResourceEntry();
+
+ bool isLocked() const { return fLockCount != 0; }
+ void lock() { ++fLockCount; }
+ void unlock() {
+ GrAssert(fLockCount > 0);
+ --fLockCount;
+ }
+
+ GrResourceKey fKey;
+ GrResource* fResource;
+
+ // track if we're in use, used when we need to purge
+ // we only purge unlocked entries
+ int fLockCount;
+
+ // we're a dlinklist
+ GrResourceEntry* fPrev;
+ GrResourceEntry* fNext;
+
+ friend class GrResourceCache;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "GrTHashCache.h"
+
+/**
+ * Cache of GrResource objects.
+ *
+ * These have a corresponding GrResourceKey, built from 128bits identifying the
+ * resource.
+ *
+ * The cache stores the entries in a double-linked list, which is its LRU.
+ * When an entry is "locked" (i.e. given to the caller), it is moved to the
+ * head of the list. If/when we must purge some of the entries, we walk the
+ * list backwards from the tail, since those are the least recently used.
+ *
+ * For fast searches, we maintain a sorted array (based on the GrResourceKey)
+ * which we can bsearch. When a new entry is added, it is inserted into this
+ * array.
+ *
+ * For even faster searches, a hash is computed from the Key. If there is
+ * a collision between two keys with the same hash, we fall back on the
+ * bsearch, and update the hash to reflect the most recent Key requested.
+ */
+class GrResourceCache {
+public:
+ GrResourceCache(int maxCount, size_t maxBytes);
+ ~GrResourceCache();
+
+ /**
+ * Return the current resource cache limits.
+ *
+ * @param maxResource If non-null, returns maximum number of resources
+ * that can be held in the cache.
+ * @param maxBytes If non-null, returns maximum number of bytes of
+ * gpu memory that can be held in the cache.
+ */
+ void getLimits(int* maxResources, size_t* maxBytes) const;
+
+ /**
+ * Specify the resource cache limits. If the current cache exceeds either
+ * of these, it will be purged (LRU) to keep the cache within these limits.
+ *
+ * @param maxResources The maximum number of resources that can be held in
+ * the cache.
+ * @param maxBytes The maximum number of bytes of resource memory that
+ * can be held in the cache.
+ */
+ void setLimits(int maxResource, size_t maxResourceBytes);
+
+ /**
+ * Controls whether locks should be nestable or not.
+ */
+ enum LockType {
+ kNested_LockType,
+ kSingle_LockType,
+ };
+
+ /**
+ * Search for an entry with the same Key. If found, "lock" it and return it.
+ * If not found, return null.
+ */
+ GrResourceEntry* findAndLock(const GrResourceKey&, LockType style);
+
+ /**
+ * Create a new entry, based on the specified key and resource, and return
+ * its "locked" entry.
+ *
+ * Ownership of the resource is transferred to the Entry, which will unref()
+ * it when we are purged or deleted.
+ */
+ GrResourceEntry* createAndLock(const GrResourceKey&, GrResource*);
+
+ /**
+ * Determines if the cache contains an entry matching a key. If a matching
+ * entry exists but was detached then it will not be found.
+ */
+ bool hasKey(const GrResourceKey& key) const;
+
+ /**
+ * Detach removes an entry from the cache. This prevents the entry from
+ * being found by a subsequent findAndLock() until it is reattached. The
+ * entry still counts against the cache's budget and should be reattached
+ * when exclusive access is no longer needed.
+ */
+ void detach(GrResourceEntry*);
+
+ /**
+ * Reattaches a resource to the cache and unlocks it. Allows it to be found
+ * by a subsequent findAndLock or be purged (provided its lock count is
+ * now 0.)
+ */
+ void reattachAndUnlock(GrResourceEntry*);
+
+ /**
+ * When done with an entry, call unlock(entry) on it, which returns it to
+ * a purgable state.
+ */
+ void unlock(GrResourceEntry*);
+
+ void removeAll();
+
+#if GR_DEBUG
+ void validate() const;
+#else
+ void validate() const {}
+#endif
+
+private:
+ void internalDetach(GrResourceEntry*, bool);
+ void attachToHead(GrResourceEntry*, bool);
+ void purgeAsNeeded();
+
+ class Key;
+ GrTHashTable<GrResourceEntry, Key, 8> fCache;
+
+ // manage the dlink list
+ GrResourceEntry* fHead;
+ GrResourceEntry* fTail;
+
+ // our budget, used in purgeAsNeeded()
+ int fMaxCount;
+ size_t fMaxBytes;
+
+ // our current stats, related to our budget
+ int fEntryCount;
+ int fUnlockedEntryCount;
+ size_t fEntryBytes;
+ int fClientDetachedCount;
+ size_t fClientDetachedBytes;
+
+ // prevents recursive purging
+ bool fPurging;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+#if GR_DEBUG
+ class GrAutoResourceCacheValidate {
+ public:
+ GrAutoResourceCacheValidate(GrResourceCache* cache) : fCache(cache) {
+ cache->validate();
+ }
+ ~GrAutoResourceCacheValidate() {
+ fCache->validate();
+ }
+ private:
+ GrResourceCache* fCache;
+ };
+#else
+ class GrAutoResourceCacheValidate {
+ public:
+ GrAutoResourceCacheValidate(GrResourceCache*) {}
+ };
+#endif
+
+#endif
+
diff --git a/src/gpu/GrStencil.cpp b/src/gpu/GrStencil.cpp
new file mode 100644
index 0000000..6624942
--- /dev/null
+++ b/src/gpu/GrStencil.cpp
@@ -0,0 +1,355 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrStencil.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Stencil Rules for Merging user stencil space into clip
+
+// We can't include the clip bit in the ref or mask values because the division
+// between user and clip bits in the stencil depends on the number of stencil
+// bits in the runtime. Comments below indicate what the code should do to
+// incorporate the clip bit into these settings.
+
+///////
+// Replace
+
+// set the ref to be the clip bit, but mask it out for the test
+GR_STATIC_CONST_SAME_STENCIL(gUserToClipReplace,
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kLess_StencilFunc,
+ 0xffff, // unset clip bit
+ 0x0000, // set clip bit
+ 0xffff);
+
+GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipReplace,
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff, // unset clip bit
+ 0x0000, // set clip bit
+ 0xffff);
+
+///////
+// Intersect
+GR_STATIC_CONST_SAME_STENCIL(gUserToClipIsect,
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kLess_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0xffff);
+
+GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipIsect,
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0xffff);
+
+///////
+// Difference
+GR_STATIC_CONST_SAME_STENCIL(gUserToClipDiff,
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0xffff);
+
+GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipDiff,
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kLess_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0xffff);
+
+///////
+// Union
+
+// first pass makes all the passing cases >= just clip bit set.
+GR_STATIC_CONST_SAME_STENCIL(gUserToClipUnionPass0,
+ kReplace_StencilOp,
+ kKeep_StencilOp,
+ kLEqual_StencilFunc,
+ 0xffff,
+ 0x0001, // set clip bit
+ 0xffff);
+
+// second pass allows anything greater than just clip bit set to pass
+GR_STATIC_CONST_SAME_STENCIL(gUserToClipUnionPass1,
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kLEqual_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0xffff);
+
+// first pass finds zeros in the user bits and if found sets
+// the clip bit to 1
+GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipUnionPass0,
+ kReplace_StencilOp,
+ kKeep_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0x0000 // set clip bit
+);
+
+// second pass zeros the user bits
+GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipUnionPass1,
+ kZero_StencilOp,
+ kZero_StencilOp,
+ kLess_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff // unset clip bit
+);
+
+///////
+// Xor
+GR_STATIC_CONST_SAME_STENCIL(gUserToClipXorPass0,
+ kInvert_StencilOp,
+ kKeep_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff, // unset clip bit
+ 0x0000,
+ 0xffff);
+
+GR_STATIC_CONST_SAME_STENCIL(gUserToClipXorPass1,
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kGreater_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0xffff);
+
+GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipXorPass0,
+ kInvert_StencilOp,
+ kKeep_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff, // unset clip bit
+ 0x0000,
+ 0xffff);
+
+GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipXorPass1,
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kLess_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0xffff);
+
+///////
+// Reverse Diff
+GR_STATIC_CONST_SAME_STENCIL(gUserToClipRDiffPass0,
+ kInvert_StencilOp,
+ kZero_StencilOp,
+ kLess_StencilFunc,
+ 0xffff, // unset clip bit
+ 0x0000, // set clip bit
+ 0xffff);
+
+GR_STATIC_CONST_SAME_STENCIL(gUserToClipRDiffPass1,
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kEqual_StencilFunc,
+ 0x0000, // set clip bit
+ 0x0000, // set clip bit
+ 0xffff);
+
+GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipRDiff,
+ kInvert_StencilOp,
+ kZero_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0x0000 // set clip bit
+);
+///////
+// Direct to Stencil
+
+// We can render a clip element directly without first writing to the client
+// portion of the clip when the fill is not inverse and the set operation will
+// only modify the in/out status of samples covered by the clip element.
+
+// this one only works if used right after stencil clip was cleared.
+// Our GrClip doesn't allow midstream replace ops.
+GR_STATIC_CONST_SAME_STENCIL(gReplaceClip,
+ kReplace_StencilOp,
+ kReplace_StencilOp,
+ kAlways_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0x0000 // set clipBit
+);
+
+GR_STATIC_CONST_SAME_STENCIL(gUnionClip,
+ kReplace_StencilOp,
+ kReplace_StencilOp,
+ kAlways_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0x0000 // set clip bit
+);
+
+GR_STATIC_CONST_SAME_STENCIL(gXorClip,
+ kInvert_StencilOp,
+ kInvert_StencilOp,
+ kAlways_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0x0000 // set clip bit
+);
+
+GR_STATIC_CONST_SAME_STENCIL(gDiffClip,
+ kZero_StencilOp,
+ kZero_StencilOp,
+ kAlways_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0x0000 // set clip bit
+);
+
+bool GrStencilSettings::GetClipPasses(GrSetOp op,
+ bool canBeDirect,
+ unsigned int stencilClipMask,
+ bool invertedFill,
+ int* numPasses,
+ GrStencilSettings settings[kMaxStencilClipPasses]) {
+ if (canBeDirect && !invertedFill) {
+ *numPasses = 0;
+ switch (op) {
+ case kReplace_SetOp:
+ *numPasses = 1;
+ settings[0] = gReplaceClip;
+ break;
+ case kUnion_SetOp:
+ *numPasses = 1;
+ settings[0] = gUnionClip;
+ break;
+ case kXor_SetOp:
+ *numPasses = 1;
+ settings[0] = gXorClip;
+ break;
+ case kDifference_SetOp:
+ *numPasses = 1;
+ settings[0] = gDiffClip;
+ break;
+ default: // suppress warning
+ break;
+ }
+ if (1 == *numPasses) {
+ settings[0].fFrontFuncRef |= stencilClipMask;
+ settings[0].fFrontWriteMask |= stencilClipMask;
+ settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+ settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
+ return true;
+ }
+ }
+ switch (op) {
+ // if we make the path renderer go to stencil we always give it a
+ // non-inverted fill and we use the stencil rules on the client->clipbit
+ // pass to select either the zeros or nonzeros.
+ case kReplace_SetOp:
+ *numPasses= 1;
+ settings[0] = invertedFill ? gInvUserToClipReplace : gUserToClipReplace;
+ settings[0].fFrontFuncMask &= ~stencilClipMask;
+ settings[0].fFrontFuncRef |= stencilClipMask;
+ settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
+ settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+ break;
+ case kIntersect_SetOp:
+ *numPasses = 1;
+ settings[0] = invertedFill ? gInvUserToClipIsect : gUserToClipIsect;
+ settings[0].fFrontFuncRef = stencilClipMask;
+ settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+ break;
+ case kUnion_SetOp:
+ *numPasses = 2;
+ if (invertedFill) {
+ settings[0] = gInvUserToClipUnionPass0;
+ settings[0].fFrontFuncMask &= ~stencilClipMask;
+ settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
+ settings[0].fFrontFuncRef |= stencilClipMask;
+ settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+ settings[0].fFrontWriteMask |= stencilClipMask;
+ settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
+
+ settings[1] = gInvUserToClipUnionPass1;
+ settings[1].fFrontWriteMask &= ~stencilClipMask;
+ settings[1].fBackWriteMask &= settings[1].fFrontWriteMask;
+
+ } else {
+ settings[0] = gUserToClipUnionPass0;
+ settings[0].fFrontFuncMask &= ~stencilClipMask;
+ settings[0].fFrontFuncRef |= stencilClipMask;
+ settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
+ settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+
+ settings[1] = gUserToClipUnionPass1;
+ settings[1].fFrontFuncRef |= stencilClipMask;
+ settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
+ }
+ break;
+ case kXor_SetOp:
+ *numPasses = 2;
+ if (invertedFill) {
+ settings[0] = gInvUserToClipXorPass0;
+ settings[0].fFrontFuncMask &= ~stencilClipMask;
+ settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
+
+ settings[1] = gInvUserToClipXorPass1;
+ settings[1].fFrontFuncRef |= stencilClipMask;
+ settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
+ } else {
+ settings[0] = gUserToClipXorPass0;
+ settings[0].fFrontFuncMask &= ~stencilClipMask;
+ settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
+
+ settings[1] = gUserToClipXorPass1;
+ settings[1].fFrontFuncRef |= stencilClipMask;
+ settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
+ }
+ break;
+ case kDifference_SetOp:
+ *numPasses = 1;
+ settings[0] = invertedFill ? gInvUserToClipDiff : gUserToClipDiff;
+ settings[0].fFrontFuncRef |= stencilClipMask;
+ settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+ break;
+ case kReverseDifference_SetOp:
+ if (invertedFill) {
+ *numPasses = 1;
+ settings[0] = gInvUserToClipRDiff;
+ settings[0].fFrontWriteMask |= stencilClipMask;
+ settings[0].fBackWriteMask = settings[0].fFrontWriteMask;
+ } else {
+ *numPasses = 2;
+ settings[0] = gUserToClipRDiffPass0;
+ settings[0].fFrontFuncMask &= ~stencilClipMask;
+ settings[0].fBackFuncMask = settings[0].fFrontFuncMask;
+ settings[0].fFrontFuncRef |= stencilClipMask;
+ settings[0].fBackFuncRef = settings[0].fFrontFuncRef;
+
+ settings[1] = gUserToClipRDiffPass1;
+ settings[1].fFrontFuncMask |= stencilClipMask;
+ settings[1].fFrontFuncRef |= stencilClipMask;
+ settings[1].fBackFuncMask = settings[1].fFrontFuncMask;
+ settings[1].fBackFuncRef = settings[1].fFrontFuncRef;
+ }
+ break;
+ default:
+ GrCrash("Unknown set op");
+ }
+ return false;
+}
diff --git a/src/gpu/GrStencil.h b/src/gpu/GrStencil.h
new file mode 100644
index 0000000..ae81840
--- /dev/null
+++ b/src/gpu/GrStencil.h
@@ -0,0 +1,323 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrStencil_DEFINED
+#define GrStencil_DEFINED
+
+#include "GrTypes.h"
+/**
+ * Gr uses the stencil buffer to implement complex clipping inside the
+ * GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer
+ * bits available for other uses by external code (clients). Client code can
+ * modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits
+ * provided by clients that overlap the bits used to implement clipping.
+ *
+ * When code outside the GrDrawTarget class uses the stencil buffer the contract
+ * is as follows:
+ *
+ * > Normal stencil funcs allow the client to pass / fail regardless of the
+ * reserved clip bits.
+ * > Additional functions allow a test against the clip along with a limited
+ * set of tests against the client bits.
+ * > Client can assume all client bits are zero initially.
+ * > Client must ensure that after all its passes are finished it has only
+ * written to the color buffer in the region inside the clip. Furthermore, it
+ * must zero all client bits that were modifed (both inside and outside the
+ * clip).
+ */
+
+/**
+ * Determines which pixels pass / fail the stencil test.
+ * Stencil test passes if (ref & mask) FUNC (stencil & mask) is true
+ */
+enum GrStencilFunc {
+ kAlways_StencilFunc = 0,
+ kNever_StencilFunc,
+ kGreater_StencilFunc,
+ kGEqual_StencilFunc,
+ kLess_StencilFunc,
+ kLEqual_StencilFunc,
+ kEqual_StencilFunc,
+ kNotEqual_StencilFunc,
+
+ // Gr stores the current clip in the
+ // stencil buffer in the high bits that
+ // are not directly accessible modifiable
+ // via the GrDrawTarget interface. The below
+ // stencil funcs test against the current
+ // clip in addition to the GrDrawTarget
+ // client's stencil bits.
+
+ // pass if inside the clip
+ kAlwaysIfInClip_StencilFunc,
+ kEqualIfInClip_StencilFunc,
+ kLessIfInClip_StencilFunc,
+ kLEqualIfInClip_StencilFunc,
+ kNonZeroIfInClip_StencilFunc, // this one forces the ref to be 0
+
+ // counts
+ kStencilFuncCount,
+ kClipStencilFuncCount = kNonZeroIfInClip_StencilFunc -
+ kAlwaysIfInClip_StencilFunc + 1,
+ kBasicStencilFuncCount = kStencilFuncCount - kClipStencilFuncCount
+};
+
+/**
+ * Operations to perform based on whether stencil test passed failed.
+ */
+enum GrStencilOp {
+ kKeep_StencilOp = 0, // preserve existing stencil value
+ kReplace_StencilOp, // replace with reference value from stencl test
+ kIncWrap_StencilOp, // increment and wrap at max
+ kIncClamp_StencilOp, // increment and clamp at max
+ kDecWrap_StencilOp, // decrement and wrap at 0
+ kDecClamp_StencilOp, // decrement and clamp at 0
+ kZero_StencilOp, // zero stencil bits
+ kInvert_StencilOp, // invert stencil bits
+
+ kStencilOpCount
+};
+
+/**
+ * GrStencilState needs to be a class with accessors and setters so that it
+ * can maintain flags related to its current state. However, we also want to
+ * be able to declare pre-made stencil settings at compile time (without
+ * inserting static initializer code). So all the data members are in this
+ * struct. A macro defined after the class can be used to jam an instance of
+ * this struct that is created from an initializer list into a
+ * GrStencilSettings. (We hang our heads in shame.)
+ */
+struct GrStencilSettingsStruct {
+ GrStencilOp fFrontPassOp : 8; // op to perform when front faces pass
+ GrStencilOp fBackPassOp : 8; // op to perform when back faces pass
+ GrStencilOp fFrontFailOp : 8; // op to perform when front faces fail
+ GrStencilOp fBackFailOp : 8; // op to perform when back faces fail
+ GrStencilFunc fFrontFunc : 8; // test function for front faces
+ GrStencilFunc fBackFunc : 8; // test function for back faces
+ int fPad0 : 8;
+ int fPad1 : 8;
+ unsigned short fFrontFuncMask; // mask for front face test
+ unsigned short fBackFuncMask; // mask for back face test
+ unsigned short fFrontFuncRef; // reference value for front face test
+ unsigned short fBackFuncRef; // reference value for back face test
+ unsigned short fFrontWriteMask; // stencil write mask for front faces
+ unsigned short fBackWriteMask; // stencil write mask for back faces
+ mutable uint32_t fFlags;
+};
+// We rely on this being packed and aligned (memcmp'ed and memcpy'ed)
+GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) % 4 == 0);
+GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) ==
+ 4*sizeof(uint8_t) + // ops
+ 2*sizeof(uint8_t) + // funcs
+ 2*sizeof(uint8_t) + // pads
+ 2*sizeof(unsigned short) + // func masks
+ 2*sizeof(unsigned short) + // ref values
+ 2*sizeof(unsigned short) + // write masks
+ sizeof(uint32_t)); // flags
+
+/**
+ * Class representing stencil state.
+ */
+class GrStencilSettings : private GrStencilSettingsStruct {
+
+public:
+ GrStencilSettings() {
+ fPad0 = fPad1 = 0;
+ this->setDisabled();
+ }
+
+ GrStencilOp frontPassOp() const { return fFrontPassOp; }
+ GrStencilOp backPassOp() const { return fBackPassOp; }
+ GrStencilOp frontFailOp() const { return fFrontFailOp; }
+ GrStencilOp backFailOp() const { return fBackFailOp; }
+ GrStencilFunc frontFunc() const { return fFrontFunc; }
+ GrStencilFunc backFunc() const { return fBackFunc; }
+ unsigned short frontFuncMask() const { return fFrontFuncMask; }
+ unsigned short backFuncMask() const { return fBackFuncMask; }
+ unsigned short frontFuncRef() const { return fFrontFuncRef; }
+ unsigned short backFuncRef() const { return fBackFuncRef; }
+ unsigned short frontWriteMask() const {return fFrontWriteMask; }
+ unsigned short backWriteMask() const { return fBackWriteMask; }
+
+ void setFrontPassOp(GrStencilOp op) { fFrontPassOp = op; fFlags = 0;}
+ void setBackPassOp(GrStencilOp op) { fBackPassOp = op; fFlags = 0;}
+ void setFrontFailOp(GrStencilOp op) {fFrontFailOp = op; fFlags = 0;}
+ void setBackFailOp(GrStencilOp op) { fBackFailOp = op; fFlags = 0;}
+ void setFrontFunc(GrStencilFunc func) { fFrontFunc = func; fFlags = 0;}
+ void setBackFunc(GrStencilFunc func) { fBackFunc = func; fFlags = 0;}
+ void setFrontFuncMask(unsigned short mask) { fFrontFuncMask = mask; }
+ void setBackFuncMask(unsigned short mask) { fBackFuncMask = mask; }
+ void setFrontFuncRef(unsigned short ref) { fFrontFuncRef = ref; }
+ void setBackFuncRef(unsigned short ref) { fBackFuncRef = ref; }
+ void setFrontWriteMask(unsigned short writeMask) { fFrontWriteMask = writeMask; }
+ void setBackWriteMask(unsigned short writeMask) { fBackWriteMask = writeMask; }
+
+ void setSame(GrStencilOp passOp,
+ GrStencilOp failOp,
+ GrStencilFunc func,
+ unsigned short funcMask,
+ unsigned short funcRef,
+ unsigned short writeMask) {
+ fFrontPassOp = passOp;
+ fBackPassOp = passOp;
+ fFrontFailOp = failOp;
+ fBackFailOp = failOp;
+ fFrontFunc = func;
+ fBackFunc = func;
+ fFrontFuncMask = funcMask;
+ fBackFuncMask = funcMask;
+ fFrontFuncRef = funcRef;
+ fBackFuncRef = funcRef;
+ fFrontWriteMask = writeMask;
+ fBackWriteMask = writeMask;
+ fFlags = 0;
+ }
+
+ void setDisabled() {
+ memset(this, 0, sizeof(*this));
+ GR_STATIC_ASSERT(0 == kKeep_StencilOp);
+ GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
+ fFlags = kIsDisabled_Flag | kDoesNotWrite_Flag;
+ }
+
+ bool isDisabled() const {
+ if (fFlags & kIsDisabled_Flag) {
+ return true;
+ }
+ if (fFlags & kNotDisabled_Flag) {
+ return false;
+ }
+ bool disabled = kKeep_StencilOp == fFrontPassOp &&
+ kKeep_StencilOp == fBackPassOp &&
+ kKeep_StencilOp == fFrontFailOp &&
+ kKeep_StencilOp == fBackFailOp &&
+ kAlways_StencilFunc == fFrontFunc &&
+ kAlways_StencilFunc == fBackFunc;
+ fFlags |= disabled ? kIsDisabled_Flag : kNotDisabled_Flag;
+ return disabled;
+ }
+
+ bool doesWrite() const {
+ if (fFlags & kDoesWrite_Flag) {
+ return true;
+ }
+ if (fFlags & kDoesNotWrite_Flag) {
+ return false;
+ }
+ bool writes = !((kNever_StencilFunc == fFrontFunc ||
+ kKeep_StencilOp == fFrontPassOp) &&
+ (kNever_StencilFunc == fBackFunc ||
+ kKeep_StencilOp == fBackPassOp) &&
+ (kAlways_StencilFunc == fFrontFunc ||
+ kKeep_StencilOp == fFrontFailOp) &&
+ (kAlways_StencilFunc == fBackFunc ||
+ kKeep_StencilOp == fBackFailOp));
+ fFlags |= writes ? kDoesWrite_Flag : kDoesNotWrite_Flag;
+ return writes;
+ }
+
+ void invalidate() {
+ // write an illegal value to the first member
+ fFrontPassOp = (GrStencilOp)(uint8_t)-1;
+ fFlags = 0;
+ }
+
+ bool operator == (const GrStencilSettings& s) const {
+ static const size_t gCompareSize = sizeof(GrStencilSettings) -
+ sizeof(fFlags);
+ GrAssert((const char*)&fFlags + sizeof(fFlags) ==
+ (const char*)this + sizeof(GrStencilSettings));
+ if (this->isDisabled() & s.isDisabled()) { // using & not &&
+ return true;
+ }
+ return 0 == memcmp(this, &s, gCompareSize);
+ }
+
+ bool operator != (const GrStencilSettings& s) const {
+ return !(*this == s);
+ }
+
+ GrStencilSettings& operator =(const GrStencilSettings& s) {
+ memcpy(this, &s, sizeof(GrStencilSettings));
+ return *this;
+ }
+
+private:
+ friend class GrGpu;
+ enum {
+ kIsDisabled_Flag = 0x1,
+ kNotDisabled_Flag = 0x2,
+ kDoesWrite_Flag = 0x4,
+ kDoesNotWrite_Flag = 0x8,
+ };
+
+ enum {
+ kMaxStencilClipPasses = 2 // maximum number of passes to add a clip
+ // element to the stencil buffer.
+ };
+
+ /**
+ * Given a thing to draw into the stencil clip, a fill type, and a set op
+ * this function determines:
+ * 1. Whether the thing can be draw directly to the stencil clip or
+ * needs to be drawn to the client portion of the stencil first.
+ * 2. How many passes are needed.
+ * 3. What those passes are.
+ * 4. The fill rule that should actually be used to render (will
+ * always be non-inverted).
+ *
+ * @param op the set op to combine this element with the
+ * existing clip
+ * @param stencilClipMask mask with just the stencil bit used for clipping
+ * enabled.
+ * @param invertedFill is this path inverted
+ * @param numPasses out: the number of passes needed to add the
+ * element to the clip.
+ * @param settings out: the stencil settings to use for each pass
+ *
+ * @return true if the clip element's geometry can be drawn directly to the
+ * stencil clip bit. Will only be true if canBeDirect is true.
+ * numPasses will be 1 if return value is true.
+ */
+ static bool GetClipPasses(GrSetOp op,
+ bool canBeDirect,
+ unsigned int stencilClipMask,
+ bool invertedFill,
+ int* numPasses,
+ GrStencilSettings settings[kMaxStencilClipPasses]);
+};
+
+GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) == sizeof(GrStencilSettings));
+
+#define GR_STATIC_CONST_STENCIL(NAME, \
+ FRONT_PASS_OP, BACK_PASS_OP, \
+ FRONT_FAIL_OP, BACK_FAIL_OP, \
+ FRONT_FUNC, BACK_FUNC, \
+ FRONT_MASK, BACK_MASK, \
+ FRONT_REF, BACK_REF, \
+ FRONT_WRITE_MASK, BACK_WRITE_MASK) \
+ static const GrStencilSettingsStruct NAME ## _STRUCT = { \
+ (FRONT_PASS_OP), (BACK_PASS_OP), \
+ (FRONT_FAIL_OP), (BACK_FAIL_OP), \
+ (FRONT_FUNC), (BACK_FUNC), \
+ (0), (0), \
+ (FRONT_MASK), (BACK_MASK), \
+ (FRONT_REF), (BACK_REF), \
+ (FRONT_WRITE_MASK), (BACK_WRITE_MASK), \
+ 0 \
+ }; \
+ static const GrStencilSettings& NAME = \
+ *reinterpret_cast<const GrStencilSettings*>(&(NAME ## _STRUCT))
+#endif
+
+#define GR_STATIC_CONST_SAME_STENCIL(NAME, \
+ PASS_OP, FAIL_OP, FUNC, MASK, REF, WRITE_MASK) \
+ GR_STATIC_CONST_STENCIL(NAME, (PASS_OP), (PASS_OP), (FAIL_OP), \
+ (FAIL_OP), (FUNC), (FUNC), (MASK), (MASK), (REF), (REF), (WRITE_MASK), \
+ (WRITE_MASK))
diff --git a/src/gpu/GrStencilBuffer.cpp b/src/gpu/GrStencilBuffer.cpp
new file mode 100644
index 0000000..4b08e23
--- /dev/null
+++ b/src/gpu/GrStencilBuffer.cpp
@@ -0,0 +1,55 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrStencilBuffer.h"
+
+#include "GrContext.h"
+#include "GrGpu.h"
+
+void GrStencilBuffer::wasDetachedFromRenderTarget(const GrRenderTarget* rt) {
+ GrAssert(fRTAttachmentCnt > 0);
+ if (0 == --fRTAttachmentCnt) {
+ this->unlockInCache();
+ // At this point we could be deleted!
+ }
+}
+
+void GrStencilBuffer::transferToCacheAndLock() {
+ GrAssert(NULL == fCacheEntry);
+ fCacheEntry =
+ this->getGpu()->getContext()->addAndLockStencilBuffer(this);
+}
+
+void GrStencilBuffer::onRelease() {
+ // When the GrGpu rips through its list of resources and releases
+ // them it may release an SB before it releases its attached RTs.
+ // In that case when GrStencilBuffer sees its last detach it no
+ // long has a gpu ptr (gets nulled in GrResource::release()) and can't
+ // access the cache to unlock itself. So if we're being released and still
+ // have attachments go ahead and unlock now.
+ if (fRTAttachmentCnt) {
+ this->unlockInCache();
+ // we shouldn't be deleted here because some RT still has a ref on us.
+ }
+ fCacheEntry = NULL;
+}
+
+void GrStencilBuffer::onAbandon() {
+ // we can use the same behavior as release.
+ this->onRelease();
+}
+
+void GrStencilBuffer::unlockInCache() {
+ if (NULL != fCacheEntry) {
+ GrGpu* gpu = this->getGpu();
+ if (NULL != gpu) {
+ GrAssert(NULL != gpu->getContext());
+ gpu->getContext()->unlockStencilBuffer(fCacheEntry);
+ }
+ }
+}
diff --git a/src/gpu/GrStencilBuffer.h b/src/gpu/GrStencilBuffer.h
new file mode 100644
index 0000000..5249ce8
--- /dev/null
+++ b/src/gpu/GrStencilBuffer.h
@@ -0,0 +1,106 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrStencilBuffer_DEFINED
+#define GrStencilBuffer_DEFINED
+
+#include "GrClip.h"
+#include "GrResource.h"
+
+class GrRenderTarget;
+class GrResourceEntry;
+
+class GrStencilBuffer : public GrResource {
+public:
+ virtual ~GrStencilBuffer() {
+ // currently each rt that has attached this sb keeps a ref
+ // TODO: allow SB to be purged and detach itself from rts
+ GrAssert(0 == fRTAttachmentCnt);
+ }
+
+ int width() const { return fWidth; }
+ int height() const { return fHeight; }
+ int bits() const { return fBits; }
+ int numSamples() const { return fSampleCnt; }
+
+ // called to note the last clip drawn to this buffer.
+ void setLastClip(const GrClip& clip, int width, int height) {
+ fLastClip = clip;
+ fLastClipWidth = width;
+ fLastClipHeight = height;
+ GrAssert(width <= fWidth);
+ GrAssert(height <= fHeight);
+ }
+
+ // called to determine if we have to render the clip into SB.
+ bool mustRenderClip(const GrClip& clip, int width, int height) const {
+ // The clip is in device space. That is it doesn't scale to fit a
+ // smaller RT. It is just truncated on the right / bottom edges.
+ // Note that this assumes that the viewport origin never moves within
+ // the stencil buffer. This is valid today.
+ return width > fLastClipWidth ||
+ height > fLastClipHeight ||
+ clip != fLastClip;
+ }
+
+ const GrClip& getLastClip() const {
+ return fLastClip;
+ }
+
+ // places the sb in the cache and locks it. Caller transfers
+ // a ref to the the cache which will unref when purged.
+ void transferToCacheAndLock();
+
+ void wasAttachedToRenderTarget(const GrRenderTarget* rt) {
+ ++fRTAttachmentCnt;
+ }
+
+ void wasDetachedFromRenderTarget(const GrRenderTarget* rt);
+
+protected:
+ GrStencilBuffer(GrGpu* gpu, int width, int height, int bits, int sampleCnt)
+ : GrResource(gpu)
+ , fWidth(width)
+ , fHeight(height)
+ , fBits(bits)
+ , fSampleCnt(sampleCnt)
+ , fLastClip()
+ , fLastClipWidth(-1)
+ , fLastClipHeight(-1)
+ , fCacheEntry(NULL)
+ , fRTAttachmentCnt(0) {
+ }
+
+ // GrResource overrides
+
+ // subclass override must call INHERITED::onRelease
+ virtual void onRelease();
+ // subclass override must call INHERITED::onAbandon
+ virtual void onAbandon();
+
+private:
+
+ void unlockInCache();
+
+ int fWidth;
+ int fHeight;
+ int fBits;
+ int fSampleCnt;
+
+ GrClip fLastClip;
+ int fLastClipWidth;
+ int fLastClipHeight;
+
+ GrResourceEntry* fCacheEntry;
+ int fRTAttachmentCnt;
+
+ typedef GrResource INHERITED;
+};
+
+#endif
diff --git a/src/gpu/GrStringBuilder.h b/src/gpu/GrStringBuilder.h
new file mode 100644
index 0000000..558d041
--- /dev/null
+++ b/src/gpu/GrStringBuilder.h
@@ -0,0 +1,19 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrStringBuilder_DEFINED
+#define GrStringBuilder_DEFINED
+
+#include "SkString.h"
+
+typedef SkString GrStringBuilder;
+
+#endif
+
diff --git a/gpu/include/GrTBSearch.h b/src/gpu/GrTBSearch.h
index 264ccb0..2697f37 100644
--- a/gpu/include/GrTBSearch.h
+++ b/src/gpu/GrTBSearch.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrTBSearch_DEFINED
#define GrTBSearch_DEFINED
diff --git a/gpu/include/GrTDArray.h b/src/gpu/GrTDArray.h
index 092242e..731001a 100644
--- a/gpu/include/GrTDArray.h
+++ b/src/gpu/GrTDArray.h
@@ -1,24 +1,18 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrTDArray_DEFINED
#define GrTDArray_DEFINED
#include "GrTypes.h"
+#include "GrRefCnt.h"
static int GrInitialArrayAllocationCount() {
return 4;
diff --git a/gpu/include/GrTHashCache.h b/src/gpu/GrTHashCache.h
index 510f9ab..8651c35 100644
--- a/gpu/include/GrTHashCache.h
+++ b/src/gpu/GrTHashCache.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrTHashCache_DEFINED
#define GrTHashCache_DEFINED
diff --git a/gpu/include/GrTLList.h b/src/gpu/GrTLList.h
index 1f59635..ea310ac 100644
--- a/gpu/include/GrTLList.h
+++ b/src/gpu/GrTLList.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrTLList_DEFINED
#define GrTLList_DEFINED
diff --git a/src/gpu/GrTesselatedPathRenderer.cpp b/src/gpu/GrTesselatedPathRenderer.cpp
new file mode 100644
index 0000000..f6fcdef
--- /dev/null
+++ b/src/gpu/GrTesselatedPathRenderer.cpp
@@ -0,0 +1,606 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrTesselatedPathRenderer.h"
+
+#include "GrDrawState.h"
+#include "GrPathUtils.h"
+#include "GrPoint.h"
+#include "GrRenderTarget.h"
+#include "GrTDArray.h"
+
+#include "SkTemplates.h"
+
+#include <limits.h>
+#include <sk_glu.h>
+
+typedef GrTDArray<GrDrawState::Edge> GrEdgeArray;
+typedef GrTDArray<GrPoint> GrPointArray;
+typedef GrTDArray<uint16_t> GrIndexArray;
+typedef void (*TESSCB)();
+
+// limit the allowable vertex range to approximately half of the representable
+// IEEE exponent in order to avoid overflow when doing multiplies between
+// vertex components,
+const float kMaxVertexValue = 1e18f;
+
+static inline GrDrawState::Edge computeEdge(const GrPoint& p,
+ const GrPoint& q,
+ float sign) {
+ GrVec tangent = GrVec::Make(p.fY - q.fY, q.fX - p.fX);
+ float scale = sign / tangent.length();
+ float cross2 = p.fX * q.fY - q.fX * p.fY;
+ return GrDrawState::Edge(tangent.fX * scale,
+ tangent.fY * scale,
+ cross2 * scale);
+}
+
+static inline GrPoint sanitizePoint(const GrPoint& pt) {
+ GrPoint r;
+ r.fX = SkScalarPin(pt.fX, -kMaxVertexValue, kMaxVertexValue);
+ r.fY = SkScalarPin(pt.fY, -kMaxVertexValue, kMaxVertexValue);
+ return r;
+}
+
+class GrTess {
+public:
+ GrTess(int count, unsigned winding_rule) {
+ fTess = Sk_gluNewTess();
+ Sk_gluTessProperty(fTess, GLU_TESS_WINDING_RULE, winding_rule);
+ Sk_gluTessNormal(fTess, 0.0f, 0.0f, 1.0f);
+ Sk_gluTessCallback(fTess, GLU_TESS_BEGIN_DATA, (TESSCB) &beginCB);
+ Sk_gluTessCallback(fTess, GLU_TESS_VERTEX_DATA, (TESSCB) &vertexCB);
+ Sk_gluTessCallback(fTess, GLU_TESS_END_DATA, (TESSCB) &endCB);
+ Sk_gluTessCallback(fTess, GLU_TESS_EDGE_FLAG_DATA, (TESSCB) &edgeFlagCB);
+ Sk_gluTessCallback(fTess, GLU_TESS_COMBINE_DATA, (TESSCB) &combineCB);
+ fInVertices = new double[count * 3];
+ }
+ virtual ~GrTess() {
+ Sk_gluDeleteTess(fTess);
+ delete[] fInVertices;
+ }
+ void addVertex(const GrPoint& pt, int index) {
+ if (index > USHRT_MAX) return;
+ double* inVertex = &fInVertices[index * 3];
+ inVertex[0] = pt.fX;
+ inVertex[1] = pt.fY;
+ inVertex[2] = 0.0;
+ *fVertices.append() = pt;
+ Sk_gluTessVertex(fTess, inVertex, reinterpret_cast<void*>(index));
+ }
+ void addVertices(const GrPoint* points, const uint16_t* contours, int numContours) {
+ Sk_gluTessBeginPolygon(fTess, this);
+ size_t i = 0;
+ for (int j = 0; j < numContours; ++j) {
+ Sk_gluTessBeginContour(fTess);
+ size_t end = i + contours[j];
+ for (; i < end; ++i) {
+ addVertex(points[i], i);
+ }
+ Sk_gluTessEndContour(fTess);
+ }
+ Sk_gluTessEndPolygon(fTess);
+ }
+ GLUtesselator* tess() { return fTess; }
+ const GrPointArray& vertices() const { return fVertices; }
+protected:
+ virtual void begin(GLenum type) = 0;
+ virtual void vertex(int index) = 0;
+ virtual void edgeFlag(bool flag) = 0;
+ virtual void end() = 0;
+ virtual int combine(GLdouble coords[3], int vertexIndices[4],
+ GLfloat weight[4]) = 0;
+ static void beginCB(GLenum type, void* data) {
+ static_cast<GrTess*>(data)->begin(type);
+ }
+ static void vertexCB(void* vertexData, void* data) {
+ static_cast<GrTess*>(data)->vertex(reinterpret_cast<long>(vertexData));
+ }
+ static void edgeFlagCB(GLboolean flag, void* data) {
+ static_cast<GrTess*>(data)->edgeFlag(flag != 0);
+ }
+ static void endCB(void* data) {
+ static_cast<GrTess*>(data)->end();
+ }
+ static void combineCB(GLdouble coords[3], void* vertexData[4],
+ GLfloat weight[4], void **outData, void* data) {
+ int vertexIndex[4];
+ vertexIndex[0] = reinterpret_cast<long>(vertexData[0]);
+ vertexIndex[1] = reinterpret_cast<long>(vertexData[1]);
+ vertexIndex[2] = reinterpret_cast<long>(vertexData[2]);
+ vertexIndex[3] = reinterpret_cast<long>(vertexData[3]);
+ GrTess* tess = static_cast<GrTess*>(data);
+ int outIndex = tess->combine(coords, vertexIndex, weight);
+ *reinterpret_cast<long*>(outData) = outIndex;
+ }
+protected:
+ GLUtesselator* fTess;
+ GrPointArray fVertices;
+ double* fInVertices;
+};
+
+class GrPolygonTess : public GrTess {
+public:
+ GrPolygonTess(int count, unsigned winding_rule)
+ : GrTess(count, winding_rule) {
+ }
+ ~GrPolygonTess() {
+ }
+ const GrIndexArray& indices() const { return fIndices; }
+protected:
+ virtual void begin(GLenum type) {
+ GR_DEBUGASSERT(type == GL_TRIANGLES);
+ }
+ virtual void vertex(int index) {
+ *fIndices.append() = index;
+ }
+ virtual void edgeFlag(bool flag) {}
+ virtual void end() {}
+ virtual int combine(GLdouble coords[3], int vertexIndices[4],
+ GLfloat weight[4]) {
+ int index = fVertices.count();
+ GrPoint p = GrPoint::Make(static_cast<float>(coords[0]),
+ static_cast<float>(coords[1]));
+ *fVertices.append() = p;
+ return index;
+ }
+protected:
+ GrIndexArray fIndices;
+};
+
+class GrEdgePolygonTess : public GrPolygonTess {
+public:
+ GrEdgePolygonTess(int count, unsigned winding_rule, const SkMatrix& matrix)
+ : GrPolygonTess(count, winding_rule),
+ fMatrix(matrix),
+ fEdgeFlag(false),
+ fEdgeVertex(-1),
+ fTriStartVertex(-1),
+ fEdges(NULL) {
+ }
+ ~GrEdgePolygonTess() {
+ delete[] fEdges;
+ }
+ const GrDrawState::Edge* edges() const { return fEdges; }
+private:
+ void addEdge(int index0, int index1) {
+ GrPoint p = fVertices[index0];
+ GrPoint q = fVertices[index1];
+ fMatrix.mapPoints(&p, 1);
+ fMatrix.mapPoints(&q, 1);
+ p = sanitizePoint(p);
+ q = sanitizePoint(q);
+ if (p == q) return;
+ GrDrawState::Edge edge = computeEdge(p, q, 1.0f);
+ fEdges[index0 * 2 + 1] = edge;
+ fEdges[index1 * 2] = edge;
+ }
+ virtual void begin(GLenum type) {
+ GR_DEBUGASSERT(type == GL_TRIANGLES);
+ int count = fVertices.count() * 2;
+ fEdges = new GrDrawState::Edge[count];
+ memset(fEdges, 0, count * sizeof(GrDrawState::Edge));
+ }
+ virtual void edgeFlag(bool flag) {
+ fEdgeFlag = flag;
+ }
+ virtual void vertex(int index) {
+ bool triStart = fIndices.count() % 3 == 0;
+ GrPolygonTess::vertex(index);
+ if (fEdgeVertex != -1) {
+ if (triStart) {
+ addEdge(fEdgeVertex, fTriStartVertex);
+ } else {
+ addEdge(fEdgeVertex, index);
+ }
+ }
+ if (triStart) {
+ fTriStartVertex = index;
+ }
+ if (fEdgeFlag) {
+ fEdgeVertex = index;
+ } else {
+ fEdgeVertex = -1;
+ }
+ }
+ virtual void end() {
+ if (fEdgeVertex != -1) {
+ addEdge(fEdgeVertex, fTriStartVertex);
+ }
+ }
+ GrMatrix fMatrix;
+ bool fEdgeFlag;
+ int fEdgeVertex, fTriStartVertex;
+ GrDrawState::Edge* fEdges;
+};
+
+class GrBoundaryTess : public GrTess {
+public:
+ GrBoundaryTess(int count, unsigned winding_rule)
+ : GrTess(count, winding_rule),
+ fContourStart(0) {
+ Sk_gluTessProperty(fTess, GLU_TESS_BOUNDARY_ONLY, 1);
+ }
+ ~GrBoundaryTess() {
+ }
+ GrPointArray& contourPoints() { return fContourPoints; }
+ const GrIndexArray& contours() const { return fContours; }
+private:
+ virtual void begin(GLenum type) {
+ fContourStart = fContourPoints.count();
+ }
+ virtual void vertex(int index) {
+ *fContourPoints.append() = fVertices.at(index);
+ }
+ virtual void edgeFlag(bool flag) {}
+ virtual void end() {
+ *fContours.append() = fContourPoints.count() - fContourStart;
+ }
+ virtual int combine(GLdouble coords[3], int vertexIndices[4],
+ GLfloat weight[4]) {
+ int index = fVertices.count();
+ *fVertices.append() = GrPoint::Make(static_cast<float>(coords[0]),
+ static_cast<float>(coords[1]));
+ return index;
+ }
+ GrPointArray fContourPoints;
+ GrIndexArray fContours;
+ size_t fContourStart;
+};
+
+static bool nearlyEqual(float a, float b) {
+ return fabsf(a - b) < 0.0001f;
+}
+
+static bool nearlyEqual(const GrPoint& a, const GrPoint& b) {
+ return nearlyEqual(a.fX, b.fX) && nearlyEqual(a.fY, b.fY);
+}
+
+static bool parallel(const GrDrawState::Edge& a, const GrDrawState::Edge& b) {
+ return (nearlyEqual(a.fX, b.fX) && nearlyEqual(a.fY, b.fY)) ||
+ (nearlyEqual(a.fX, -b.fX) && nearlyEqual(a.fY, -b.fY));
+}
+
+static unsigned fill_type_to_glu_winding_rule(GrPathFill fill) {
+ switch (fill) {
+ case kWinding_PathFill:
+ return GLU_TESS_WINDING_NONZERO;
+ case kEvenOdd_PathFill:
+ return GLU_TESS_WINDING_ODD;
+ case kInverseWinding_PathFill:
+ return GLU_TESS_WINDING_POSITIVE;
+ case kInverseEvenOdd_PathFill:
+ return GLU_TESS_WINDING_ODD;
+ case kHairLine_PathFill:
+ return GLU_TESS_WINDING_NONZERO; // FIXME: handle this
+ default:
+ GrAssert(!"Unknown path fill!");
+ return 0;
+ }
+}
+
+GrTesselatedPathRenderer::GrTesselatedPathRenderer() {
+}
+
+static bool isCCW(const GrPoint* pts, int count) {
+ GrVec v1, v2;
+ do {
+ v1 = pts[1] - pts[0];
+ v2 = pts[2] - pts[1];
+ pts++;
+ count--;
+ } while (nearlyEqual(v1, v2) && count > 3);
+ return v1.cross(v2) < 0;
+}
+
+static bool validEdge(const GrDrawState::Edge& edge) {
+ return !(edge.fX == 0.0f && edge.fY == 0.0f && edge.fZ == 0.0f);
+}
+
+static size_t computeEdgesAndIntersect(const GrMatrix& matrix,
+ const GrMatrix& inverse,
+ GrPoint* vertices,
+ size_t numVertices,
+ GrEdgeArray* edges,
+ float sign) {
+ if (numVertices < 3) {
+ return 0;
+ }
+ matrix.mapPoints(vertices, numVertices);
+ if (sign == 0.0f) {
+ sign = isCCW(vertices, numVertices) ? -1.0f : 1.0f;
+ }
+ GrPoint p = sanitizePoint(vertices[numVertices - 1]);
+ for (size_t i = 0; i < numVertices; ++i) {
+ GrPoint q = sanitizePoint(vertices[i]);
+ if (p == q) {
+ continue;
+ }
+ GrDrawState::Edge edge = computeEdge(p, q, sign);
+ edge.fZ += 0.5f; // Offset by half a pixel along the tangent.
+ *edges->append() = edge;
+ p = q;
+ }
+ int count = edges->count();
+ if (count == 0) {
+ return 0;
+ }
+ GrDrawState::Edge prev_edge = edges->at(0);
+ for (int i = 0; i < count; ++i) {
+ GrDrawState::Edge edge = edges->at(i < count - 1 ? i + 1 : 0);
+ if (parallel(edge, prev_edge)) {
+ // 3 points are collinear; offset by half the tangent instead
+ vertices[i].fX -= edge.fX * 0.5f;
+ vertices[i].fY -= edge.fY * 0.5f;
+ } else {
+ vertices[i] = prev_edge.intersect(edge);
+ }
+ inverse.mapPoints(&vertices[i], 1);
+ prev_edge = edge;
+ }
+ return edges->count();
+}
+
+void GrTesselatedPathRenderer::drawPath(GrDrawState::StageMask stageMask) {
+ GrDrawTarget::AutoStateRestore asr(fTarget);
+ GrDrawState* drawState = fTarget->drawState();
+ // face culling doesn't make sense here
+ GrAssert(GrDrawState::kBoth_DrawFace == drawState->getDrawFace());
+
+ GrMatrix viewM = drawState->getViewMatrix();
+
+ GrScalar tol = GR_Scalar1;
+ tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, fPath->getBounds());
+ GrScalar tolSqd = GrMul(tol, tol);
+
+ int subpathCnt;
+ int maxPts = GrPathUtils::worstCasePointCount(*fPath, &subpathCnt, tol);
+
+ GrVertexLayout layout = 0;
+ for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+ if ((1 << s) & stageMask) {
+ layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
+ }
+ }
+
+ bool inverted = GrIsFillInverted(fFill);
+ if (inverted) {
+ maxPts += 4;
+ subpathCnt++;
+ }
+ if (maxPts > USHRT_MAX) {
+ return;
+ }
+ SkAutoSTMalloc<8, GrPoint> baseMem(maxPts);
+ GrPoint* base = baseMem;
+ GrPoint* vert = base;
+ GrPoint* subpathBase = base;
+
+ SkAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
+
+ GrPoint pts[4];
+ SkPath::Iter iter(*fPath, false);
+
+ bool first = true;
+ int subpath = 0;
+
+ for (;;) {
+ switch (iter.next(pts)) {
+ case kMove_PathCmd:
+ if (!first) {
+ subpathVertCount[subpath] = vert-subpathBase;
+ subpathBase = vert;
+ ++subpath;
+ }
+ *vert = pts[0];
+ vert++;
+ break;
+ case kLine_PathCmd:
+ *vert = pts[1];
+ vert++;
+ break;
+ case kQuadratic_PathCmd: {
+ GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
+ tolSqd, &vert,
+ GrPathUtils::quadraticPointCount(pts, tol));
+ break;
+ }
+ case kCubic_PathCmd: {
+ GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
+ tolSqd, &vert,
+ GrPathUtils::cubicPointCount(pts, tol));
+ break;
+ }
+ case kClose_PathCmd:
+ break;
+ case kEnd_PathCmd:
+ subpathVertCount[subpath] = vert-subpathBase;
+ ++subpath; // this could be only in debug
+ goto FINISHED;
+ }
+ first = false;
+ }
+FINISHED:
+ if (0 != fTranslate.fX || 0 != fTranslate.fY) {
+ for (int i = 0; i < vert - base; i++) {
+ base[i].offset(fTranslate.fX, fTranslate.fY);
+ }
+ }
+
+ if (inverted) {
+ GrRect bounds;
+ GrAssert(NULL != drawState->getRenderTarget());
+ bounds.setLTRB(0, 0,
+ GrIntToScalar(drawState->getRenderTarget()->width()),
+ GrIntToScalar(drawState->getRenderTarget()->height()));
+ GrMatrix vmi;
+ if (drawState->getViewInverse(&vmi)) {
+ vmi.mapRect(&bounds);
+ }
+ *vert++ = GrPoint::Make(bounds.fLeft, bounds.fTop);
+ *vert++ = GrPoint::Make(bounds.fLeft, bounds.fBottom);
+ *vert++ = GrPoint::Make(bounds.fRight, bounds.fBottom);
+ *vert++ = GrPoint::Make(bounds.fRight, bounds.fTop);
+ subpathVertCount[subpath++] = 4;
+ }
+
+ GrAssert(subpath == subpathCnt);
+ GrAssert((vert - base) <= maxPts);
+
+ size_t count = vert - base;
+
+ if (count < 3) {
+ return;
+ }
+
+ if (subpathCnt == 1 && !inverted && fPath->isConvex()) {
+ if (fAntiAlias) {
+ GrEdgeArray edges;
+ GrMatrix inverse, matrix = drawState->getViewMatrix();
+ drawState->getViewInverse(&inverse);
+
+ count = computeEdgesAndIntersect(matrix, inverse, base, count, &edges, 0.0f);
+ size_t maxEdges = fTarget->getMaxEdges();
+ if (count == 0) {
+ return;
+ }
+ if (count <= maxEdges) {
+ // All edges fit; upload all edges and draw all verts as a fan
+ fTarget->setVertexSourceToArray(layout, base, count);
+ drawState->setEdgeAAData(&edges[0], count);
+ fTarget->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
+ } else {
+ // Upload "maxEdges" edges and verts at a time, and draw as
+ // separate fans
+ for (size_t i = 0; i < count - 2; i += maxEdges - 2) {
+ edges[i] = edges[0];
+ base[i] = base[0];
+ int size = GR_CT_MIN(count - i, maxEdges);
+ fTarget->setVertexSourceToArray(layout, &base[i], size);
+ drawState->setEdgeAAData(&edges[i], size);
+ fTarget->drawNonIndexed(kTriangleFan_PrimitiveType, 0, size);
+ }
+ }
+ drawState->setEdgeAAData(NULL, 0);
+ } else {
+ fTarget->setVertexSourceToArray(layout, base, count);
+ fTarget->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
+ }
+ return;
+ }
+
+ if (fAntiAlias) {
+ // Run the tesselator once to get the boundaries.
+ GrBoundaryTess btess(count, fill_type_to_glu_winding_rule(fFill));
+ btess.addVertices(base, subpathVertCount, subpathCnt);
+
+ GrMatrix inverse, matrix = drawState->getViewMatrix();
+ if (!drawState->getViewInverse(&inverse)) {
+ return;
+ }
+
+ if (btess.vertices().count() > USHRT_MAX) {
+ return;
+ }
+
+ // Inflate the boundary, and run the tesselator again to generate
+ // interior polys.
+ const GrPointArray& contourPoints = btess.contourPoints();
+ const GrIndexArray& contours = btess.contours();
+ GrEdgePolygonTess ptess(contourPoints.count(), GLU_TESS_WINDING_NONZERO, matrix);
+
+ size_t i = 0;
+ Sk_gluTessBeginPolygon(ptess.tess(), &ptess);
+ for (int contour = 0; contour < contours.count(); ++contour) {
+ int count = contours[contour];
+ GrEdgeArray edges;
+ int newCount = computeEdgesAndIntersect(matrix, inverse, &btess.contourPoints()[i], count, &edges, 1.0f);
+ Sk_gluTessBeginContour(ptess.tess());
+ for (int j = 0; j < newCount; j++) {
+ ptess.addVertex(contourPoints[i + j], ptess.vertices().count());
+ }
+ i += count;
+ Sk_gluTessEndContour(ptess.tess());
+ }
+
+ Sk_gluTessEndPolygon(ptess.tess());
+
+ if (ptess.vertices().count() > USHRT_MAX) {
+ return;
+ }
+
+ // Draw the resulting polys and upload their edge data.
+ drawState->enableState(GrDrawState::kEdgeAAConcave_StateBit);
+ const GrPointArray& vertices = ptess.vertices();
+ const GrIndexArray& indices = ptess.indices();
+ const GrDrawState::Edge* edges = ptess.edges();
+ GR_DEBUGASSERT(indices.count() % 3 == 0);
+ for (int i = 0; i < indices.count(); i += 3) {
+ GrPoint tri_verts[3];
+ int index0 = indices[i];
+ int index1 = indices[i + 1];
+ int index2 = indices[i + 2];
+ tri_verts[0] = vertices[index0];
+ tri_verts[1] = vertices[index1];
+ tri_verts[2] = vertices[index2];
+ GrDrawState::Edge tri_edges[6];
+ int t = 0;
+ const GrDrawState::Edge& edge0 = edges[index0 * 2];
+ const GrDrawState::Edge& edge1 = edges[index0 * 2 + 1];
+ const GrDrawState::Edge& edge2 = edges[index1 * 2];
+ const GrDrawState::Edge& edge3 = edges[index1 * 2 + 1];
+ const GrDrawState::Edge& edge4 = edges[index2 * 2];
+ const GrDrawState::Edge& edge5 = edges[index2 * 2 + 1];
+ if (validEdge(edge0) && validEdge(edge1)) {
+ tri_edges[t++] = edge0;
+ tri_edges[t++] = edge1;
+ }
+ if (validEdge(edge2) && validEdge(edge3)) {
+ tri_edges[t++] = edge2;
+ tri_edges[t++] = edge3;
+ }
+ if (validEdge(edge4) && validEdge(edge5)) {
+ tri_edges[t++] = edge4;
+ tri_edges[t++] = edge5;
+ }
+ drawState->setEdgeAAData(&tri_edges[0], t);
+ fTarget->setVertexSourceToArray(layout, &tri_verts[0], 3);
+ fTarget->drawNonIndexed(kTriangles_PrimitiveType, 0, 3);
+ }
+ drawState->setEdgeAAData(NULL, 0);
+ drawState->disableState(GrDrawState::kEdgeAAConcave_StateBit);
+ return;
+ }
+
+ GrPolygonTess ptess(count, fill_type_to_glu_winding_rule(fFill));
+ ptess.addVertices(base, subpathVertCount, subpathCnt);
+ const GrPointArray& vertices = ptess.vertices();
+ const GrIndexArray& indices = ptess.indices();
+ if (indices.count() > 0) {
+ fTarget->setVertexSourceToArray(layout, vertices.begin(), vertices.count());
+ fTarget->setIndexSourceToArray(indices.begin(), indices.count());
+ fTarget->drawIndexed(kTriangles_PrimitiveType,
+ 0,
+ 0,
+ vertices.count(),
+ indices.count());
+ }
+}
+
+bool GrTesselatedPathRenderer::canDrawPath(const GrDrawTarget::Caps& caps,
+ const SkPath& path,
+ GrPathFill fill,
+ bool antiAlias) const {
+ return kHairLine_PathFill != fill;
+}
+
+void GrTesselatedPathRenderer::drawPathToStencil() {
+ GrAlwaysAssert(!"multipass stencil should not be needed");
+}
+
diff --git a/src/gpu/GrTesselatedPathRenderer.h b/src/gpu/GrTesselatedPathRenderer.h
new file mode 100644
index 0000000..e783958
--- /dev/null
+++ b/src/gpu/GrTesselatedPathRenderer.h
@@ -0,0 +1,27 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrTesselatedPathRenderer_DEFINED
+#define GrTesselatedPathRenderer_DEFINED
+
+#include "GrPathRenderer.h"
+
+class GrTesselatedPathRenderer : public GrPathRenderer {
+public:
+ GrTesselatedPathRenderer();
+
+ virtual void drawPath(GrDrawState::StageMask stageMask);
+ virtual bool canDrawPath(const GrDrawTarget::Caps& targetCaps,
+ const GrPath& path,
+ GrPathFill fill,
+ bool antiAlias) const SK_OVERRIDE;
+ virtual void drawPathToStencil() SK_OVERRIDE;
+};
+
+#endif
diff --git a/gpu/src/GrTextContext.cpp b/src/gpu/GrTextContext.cpp
index 2aacfa2..c22b203 100644
--- a/gpu/src/GrTextContext.cpp
+++ b/src/gpu/GrTextContext.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "GrTextContext.h"
#include "GrAtlas.h"
#include "GrContext.h"
@@ -32,7 +25,7 @@ enum {
void GrTextContext::flushGlyphs() {
if (fCurrVertex > 0) {
GrDrawTarget::AutoStateRestore asr(fDrawTarget);
-
+ GrDrawState* drawState = fDrawTarget->drawState();
// setup our sampler state for our text texture/atlas
GrSamplerState::Filter filter;
if (fExtMatrix.isIdentity()) {
@@ -40,15 +33,13 @@ void GrTextContext::flushGlyphs() {
} else {
filter = GrSamplerState::kBilinear_Filter;
}
- GrSamplerState sampler(GrSamplerState::kRepeat_WrapMode,
- GrSamplerState::kRepeat_WrapMode,
- filter);
- fDrawTarget->setSamplerState(kGlyphMaskStage, sampler);
+ drawState->sampler(kGlyphMaskStage)->reset(
+ GrSamplerState::kRepeat_WrapMode,filter);
GrAssert(GrIsALIGN4(fCurrVertex));
int nIndices = fCurrVertex + (fCurrVertex >> 1);
GrAssert(fCurrTexture);
- fDrawTarget->setTexture(kGlyphMaskStage, fCurrTexture);
+ drawState->setTexture(kGlyphMaskStage, fCurrTexture);
if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) {
if (kOne_BlendCoeff != fPaint.fSrcBlendCoeff ||
@@ -57,22 +48,22 @@ void GrTextContext::flushGlyphs() {
GrPrintf("LCD Text will not draw correctly.\n");
}
// setup blend so that we get mask * paintColor + (1-mask)*dstColor
- fDrawTarget->setBlendConstant(fPaint.fColor);
- fDrawTarget->setBlendFunc(kConstC_BlendCoeff, kISC_BlendCoeff);
+ drawState->setBlendConstant(fPaint.fColor);
+ drawState->setBlendFunc(kConstC_BlendCoeff, kISC_BlendCoeff);
// don't modulate by the paint's color in the frag since we're
// already doing it via the blend const.
- fDrawTarget->setColor(0xffffffff);
+ drawState->setColor(0xffffffff);
} else {
// set back to normal in case we took LCD path previously.
- fDrawTarget->setBlendFunc(fPaint.fSrcBlendCoeff, fPaint.fDstBlendCoeff);
- fDrawTarget->setColor(fPaint.fColor);
+ drawState->setBlendFunc(fPaint.fSrcBlendCoeff, fPaint.fDstBlendCoeff);
+ drawState->setColor(fPaint.fColor);
}
fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
fDrawTarget->drawIndexed(kTriangles_PrimitiveType,
0, 0, fCurrVertex, nIndices);
- fDrawTarget->releaseReservedGeometry();
+ fDrawTarget->resetVertexSource();
fVertices = NULL;
fMaxVertices = 0;
fCurrVertex = 0;
@@ -115,6 +106,34 @@ GrTextContext::GrTextContext(GrContext* context,
fOrigViewMatrix = fContext->getMatrix();
fContext->setMatrix(fExtMatrix);
+ /*
+ We need to call preConcatMatrix with our viewmatrix's inverse, for each
+ texture and mask in the paint. However, computing the inverse can be
+ expensive, and its possible we may not have any textures or masks, so these
+ two loops are written such that we only compute the inverse (once) if we
+ need it. We do this on our copy of the paint rather than directly on the
+ draw target because we re-provide the paint to the context when we have
+ to flush our glyphs or draw a glyph as a path midstream.
+ */
+ bool invVMComputed = false;
+ GrMatrix invVM;
+ for (int t = 0; t < GrPaint::kMaxTextures; ++t) {
+ if (NULL != fPaint.getTexture(t)) {
+ if (invVMComputed || fOrigViewMatrix.invert(&invVM)) {
+ invVMComputed = true;
+ fPaint.textureSampler(t)->preConcatMatrix(invVM);
+ }
+ }
+ }
+ for (int m = 0; m < GrPaint::kMaxMasks; ++m) {
+ if (NULL != fPaint.getMask(m)) {
+ if (invVMComputed || fOrigViewMatrix.invert(&invVM)) {
+ invVMComputed = true;
+ fPaint.maskSampler(m)->preConcatMatrix(invVM);
+ }
+ }
+ }
+
fDrawTarget = fContext->getTextTarget(fPaint);
fVertices = NULL;
@@ -126,11 +145,6 @@ GrTextContext::GrTextContext(GrContext* context,
int stageMask = paint.getActiveStageMask();
if (stageMask) {
- GrMatrix inverseViewMatrix;
- if (fOrigViewMatrix.invert(&inverseViewMatrix)) {
- fDrawTarget->preConcatSamplerMatrices(stageMask,
- inverseViewMatrix);
- }
for (int i = 0; i < GrPaint::kTotalStages; ++i) {
if ((1 << i) & stageMask) {
fVertexLayout |=
@@ -139,7 +153,6 @@ GrTextContext::GrTextContext(GrContext* context,
}
}
}
-
}
GrTextContext::~GrTextContext() {
@@ -255,17 +268,16 @@ HAS_ATLAS:
NULL);
}
- int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->size() / (6 * sizeof(uint16_t));
+ int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
if (fMaxVertices < kMinRequestedVerts) {
fMaxVertices = kDefaultRequestedVerts;
} else if (fMaxVertices > maxQuadVertices) {
// don't exceed the limit of the index buffer
fMaxVertices = maxQuadVertices;
}
- bool success = fDrawTarget->reserveAndLockGeometry(fVertexLayout,
- fMaxVertices, 0,
- GrTCast<void**>(&fVertices),
- NULL);
+ bool success = fDrawTarget->reserveVertexSpace(fVertexLayout,
+ fMaxVertices,
+ GrTCast<void**>(&fVertices));
GrAlwaysAssert(success);
}
diff --git a/gpu/src/GrTextStrike.cpp b/src/gpu/GrTextStrike.cpp
index 7aae757..b8762ad 100644
--- a/gpu/src/GrTextStrike.cpp
+++ b/src/gpu/GrTextStrike.cpp
@@ -1,23 +1,15 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "GrAtlas.h"
#include "GrGpu.h"
-#include "GrMemory.h"
#include "GrRectanizer.h"
#include "GrTextStrike.h"
#include "GrTextStrike_impl.h"
@@ -68,15 +60,19 @@ void GrFontCache::freeAll() {
void GrFontCache::purgeExceptFor(GrTextStrike* preserveStrike) {
GrTextStrike* strike = fTail;
- if (strike == preserveStrike) {
- strike = strike->fPrev;
- }
- if (strike) {
- int index = fCache.slowFindIndex(strike);
+ while (strike) {
+ if (strike == preserveStrike) {
+ strike = strike->fPrev;
+ continue;
+ }
+ GrTextStrike* strikeToPurge = strike;
+ // keep going if we won't free up any atlases with this strike.
+ strike = (NULL == strikeToPurge->fAtlas) ? strikeToPurge->fPrev : NULL;
+ int index = fCache.slowFindIndex(strikeToPurge);
GrAssert(index >= 0);
- fCache.removeAt(index, strike->fFontScalerKey->getHash());
- this->detachStrikeFromList(strike);
- delete strike;
+ fCache.removeAt(index, strikeToPurge->fFontScalerKey->getHash());
+ this->detachStrikeFromList(strikeToPurge);
+ delete strikeToPurge;
}
}
@@ -137,7 +133,7 @@ GrTextStrike::GrTextStrike(GrFontCache* cache, const GrKey* key,
fMaskFormat = format;
#if GR_DEBUG
- GrPrintf(" GrTextStrike %p %d\n", this, gCounter);
+// GrPrintf(" GrTextStrike %p %d\n", this, gCounter);
gCounter += 1;
#endif
}
@@ -151,7 +147,7 @@ GrTextStrike::~GrTextStrike() {
#if GR_DEBUG
gCounter -= 1;
- GrPrintf("~GrTextStrike %p %d\n", this, gCounter);
+// GrPrintf("~GrTextStrike %p %d\n", this, gCounter);
#endif
}
@@ -185,7 +181,7 @@ bool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
int bytesPerPixel = GrMaskFormatBytesPerPixel(fMaskFormat);
size_t size = glyph->fBounds.area() * bytesPerPixel;
- GrAutoSMalloc<1024> storage(size);
+ SkAutoSMalloc<1024> storage(size);
if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(),
glyph->height(),
glyph->width() * bytesPerPixel,
diff --git a/gpu/include/GrTextStrike.h b/src/gpu/GrTextStrike.h
index 2bdcc90..701acea 100644
--- a/gpu/include/GrTextStrike.h
+++ b/src/gpu/GrTextStrike.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrTextStrike_DEFINED
#define GrTextStrike_DEFINED
diff --git a/gpu/src/GrTextStrike_impl.h b/src/gpu/GrTextStrike_impl.h
index 7e03e2a..1b6392c 100644
--- a/gpu/src/GrTextStrike_impl.h
+++ b/src/gpu/GrTextStrike_impl.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef GrTextStrike_impl_DEFINED
#define GrTextStrike_impl_DEFINED
diff --git a/src/gpu/GrTexture.cpp b/src/gpu/GrTexture.cpp
new file mode 100644
index 0000000..c145c71
--- /dev/null
+++ b/src/gpu/GrTexture.cpp
@@ -0,0 +1,58 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrTexture.h"
+
+#include "GrContext.h"
+#include "GrGpu.h"
+#include "GrRenderTarget.h"
+
+bool GrTexture::readPixels(int left, int top, int width, int height,
+ GrPixelConfig config, void* buffer,
+ size_t rowBytes) {
+ // go through context so that all necessary flushing occurs
+ GrContext* context = this->getContext();
+ if (NULL == context) {
+ return false;
+ }
+ return context->readTexturePixels(this,
+ left, top,
+ width, height,
+ config, buffer, rowBytes);
+}
+
+void GrTexture::writePixels(int left, int top, int width, int height,
+ GrPixelConfig config, const void* buffer,
+ size_t rowBytes) {
+ // go through context so that all necessary flushing occurs
+ GrContext* context = this->getContext();
+ if (NULL == context) {
+ return;
+ }
+ context->writeTexturePixels(this,
+ left, top,
+ width, height,
+ config, buffer, rowBytes);
+}
+
+void GrTexture::releaseRenderTarget() {
+ if (NULL != fRenderTarget) {
+ GrAssert(fRenderTarget->asTexture() == this);
+ fRenderTarget->onTextureReleaseRenderTarget();
+ fRenderTarget->unref();
+ fRenderTarget = NULL;
+ }
+}
+
+void GrTexture::onAbandon() {
+ if (NULL != fRenderTarget) {
+ fRenderTarget->abandon();
+ }
+}
+
diff --git a/src/gpu/GrVertexBuffer.h b/src/gpu/GrVertexBuffer.h
new file mode 100644
index 0000000..bda235c
--- /dev/null
+++ b/src/gpu/GrVertexBuffer.h
@@ -0,0 +1,24 @@
+
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#ifndef GrVertexBuffer_DEFINED
+#define GrVertexBuffer_DEFINED
+
+#include "GrGeometryBuffer.h"
+
+class GrVertexBuffer : public GrGeometryBuffer {
+protected:
+ GrVertexBuffer(GrGpu* gpu, size_t sizeInBytes, bool dynamic)
+ : INHERITED(gpu, sizeInBytes, dynamic) {}
+private:
+ typedef GrGeometryBuffer INHERITED;
+};
+
+#endif
diff --git a/src/gpu/SkGLContext.cpp b/src/gpu/SkGLContext.cpp
new file mode 100644
index 0000000..f6b7db8
--- /dev/null
+++ b/src/gpu/SkGLContext.cpp
@@ -0,0 +1,90 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkGLContext.h"
+
+SkGLContext::SkGLContext()
+ : fFBO(0)
+ , fGL(NULL) {
+}
+
+SkGLContext::~SkGLContext() {
+ SkSafeUnref(fGL);
+}
+
+bool SkGLContext::init(int width, int height) {
+ if (fGL) {
+ fGL->unref();
+ this->destroyGLContext();
+ }
+
+ fGL = this->createGLContext();
+ if (fGL) {
+ // clear any existing GL erorrs
+ GrGLenum error;
+ do {
+ error = SK_GL(*this, GetError());
+ } while (GR_GL_NO_ERROR != error);
+ GrGLuint cbID;
+ GrGLuint dsID;
+ SK_GL(*this, GenFramebuffers(1, &fFBO));
+ SK_GL(*this, BindFramebuffer(GR_GL_FRAMEBUFFER, fFBO));
+ SK_GL(*this, GenRenderbuffers(1, &cbID));
+ SK_GL(*this, BindRenderbuffer(GR_GL_RENDERBUFFER, cbID));
+ if (fGL->supportsES2()) {
+ SK_GL(*this, RenderbufferStorage(GR_GL_RENDERBUFFER,
+ GR_GL_RGBA8,
+ width, height));
+ } else {
+ SK_GL(*this, RenderbufferStorage(GR_GL_RENDERBUFFER,
+ GR_GL_RGBA,
+ width, height));
+ }
+ SK_GL(*this, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+ GR_GL_COLOR_ATTACHMENT0,
+ GR_GL_RENDERBUFFER,
+ cbID));
+ SK_GL(*this, GenRenderbuffers(1, &dsID));
+ SK_GL(*this, BindRenderbuffer(GR_GL_RENDERBUFFER, dsID));
+ if (fGL->supportsES2()) {
+ SK_GL(*this, RenderbufferStorage(GR_GL_RENDERBUFFER,
+ GR_GL_STENCIL_INDEX8,
+ width, height));
+ } else {
+ SK_GL(*this, RenderbufferStorage(GR_GL_RENDERBUFFER,
+ GR_GL_DEPTH_STENCIL,
+ width, height));
+ SK_GL(*this, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+ GR_GL_DEPTH_ATTACHMENT,
+ GR_GL_RENDERBUFFER,
+ dsID));
+ }
+ SK_GL(*this, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
+ GR_GL_STENCIL_ATTACHMENT,
+ GR_GL_RENDERBUFFER,
+ dsID));
+ SK_GL(*this, Viewport(0, 0, width, height));
+ SK_GL(*this, ClearStencil(0));
+ SK_GL(*this, Clear(GR_GL_STENCIL_BUFFER_BIT));
+
+ error = SK_GL(*this, GetError());
+ GrGLenum status =
+ SK_GL(*this, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
+
+ if (GR_GL_FRAMEBUFFER_COMPLETE != status ||
+ GR_GL_NO_ERROR != error) {
+ fFBO = 0;
+ fGL->unref();
+ fGL = NULL;
+ this->destroyGLContext();
+ return false;
+ } else {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/gpu/SkGpuCanvas.cpp b/src/gpu/SkGpuCanvas.cpp
index 08cbb32..fa57335 100644
--- a/src/gpu/SkGpuCanvas.cpp
+++ b/src/gpu/SkGpuCanvas.cpp
@@ -1,36 +1,26 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "GrContext.h"
#include "SkGpuCanvas.h"
#include "SkGpuDevice.h"
-#include "SkGpuDeviceFactory.h"
///////////////////////////////////////////////////////////////////////////////
SkGpuCanvas::SkGpuCanvas(GrContext* context, GrRenderTarget* renderTarget) {
- SkDeviceFactory* factory = SkNEW_ARGS(SkGpuDeviceFactory,
- (context, renderTarget));
- this->setDeviceFactory(factory)->unref();
-
SkASSERT(context);
fContext = context;
fContext->ref();
+
+ this->setDevice(new SkGpuDevice(context, renderTarget))->unref();
}
SkGpuCanvas::~SkGpuCanvas() {
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index ae8ab6c..96d9fc6 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1,30 +1,24 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "GrContext.h"
#include "GrTextContext.h"
#include "SkGpuDevice.h"
-#include "SkGpuDeviceFactory.h"
#include "SkGrTexturePixelRef.h"
#include "SkColorFilter.h"
#include "SkDrawProcs.h"
#include "SkGlyphCache.h"
+#include "SkImageFilter.h"
+#include "SkTLazy.h"
#include "SkUtils.h"
#define CACHE_LAYER_TEXTURES 1
@@ -47,42 +41,54 @@ enum {
kShaderTextureIdx = 0
};
+
+#define MAX_BLUR_SIGMA 4.0f
+// FIXME: This value comes from from SkBlurMaskFilter.cpp.
+// Should probably be put in a common header someplace.
+#define MAX_BLUR_RADIUS SkIntToScalar(128)
+// This constant approximates the scaling done in the software path's
+// "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)).
+// IMHO, it actually should be 1: we blur "less" than we should do
+// according to the CSS and canvas specs, simply because Safari does the same.
+// Firefox used to do the same too, until 4.0 where they fixed it. So at some
+// point we should probably get rid of these scaling constants and rebaseline
+// all the blur tests.
+#define BLUR_SIGMA_SCALE 0.6f
///////////////////////////////////////////////////////////////////////////////
SkGpuDevice::SkAutoCachedTexture::
SkAutoCachedTexture(SkGpuDevice* device,
const SkBitmap& bitmap,
- const GrSamplerState& sampler,
+ const GrSamplerState* sampler,
GrTexture** texture) {
GrAssert(texture);
- fTex = NULL;
*texture = this->set(device, bitmap, sampler);
}
SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
- fTex = NULL;
}
GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
const SkBitmap& bitmap,
- const GrSamplerState& sampler) {
- if (fTex) {
+ const GrSamplerState* sampler) {
+ if (fTex.texture()) {
fDevice->unlockCachedTexture(fTex);
}
fDevice = device;
GrTexture* texture = (GrTexture*)bitmap.getTexture();
if (texture) {
// return the native texture
- fTex = NULL;
+ fTex.reset();
} else {
// look it up in our cache
- fTex = device->lockCachedTexture(bitmap, sampler, &texture, false);
+ fTex = device->lockCachedTexture(bitmap, sampler);
+ texture = fTex.texture();
}
return texture;
}
SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
- if (fTex) {
+ if (fTex.texture()) {
fDevice->unlockCachedTexture(fTex);
}
}
@@ -100,78 +106,130 @@ public:
///////////////////////////////////////////////////////////////////////////////
-GrRenderTarget* SkGpuDevice::Current3DApiRenderTarget() {
- return (GrRenderTarget*) -1;
+static SkBitmap::Config grConfig2skConfig(GrPixelConfig config, bool* isOpaque) {
+ switch (config) {
+ case kAlpha_8_GrPixelConfig:
+ *isOpaque = false;
+ return SkBitmap::kA8_Config;
+ case kRGB_565_GrPixelConfig:
+ *isOpaque = true;
+ return SkBitmap::kRGB_565_Config;
+ case kRGBA_4444_GrPixelConfig:
+ *isOpaque = false;
+ return SkBitmap::kARGB_4444_Config;
+ case kSkia8888_PM_GrPixelConfig:
+ // we don't currently have a way of knowing whether
+ // a 8888 is opaque based on the config.
+ *isOpaque = false;
+ return SkBitmap::kARGB_8888_Config;
+ default:
+ *isOpaque = false;
+ return SkBitmap::kNo_Config;
+ }
}
-SkGpuDevice::SkGpuDevice(GrContext* context,
- const SkBitmap& bitmap,
- GrRenderTarget* renderTargetOrNull)
- : SkDevice(NULL, bitmap, (NULL == renderTargetOrNull)) {
+static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
+ GrPixelConfig config = renderTarget->config();
+
+ bool isOpaque;
+ SkBitmap bitmap;
+ bitmap.setConfig(grConfig2skConfig(config, &isOpaque),
+ renderTarget->width(), renderTarget->height());
+ bitmap.setIsOpaque(isOpaque);
+ return bitmap;
+}
+
+SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture)
+: SkDevice(make_bitmap(context, texture->asRenderTarget())) {
+ this->initFromRenderTarget(context, texture->asRenderTarget());
+}
+
+SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
+: SkDevice(make_bitmap(context, renderTarget)) {
+ this->initFromRenderTarget(context, renderTarget);
+}
+
+void SkGpuDevice::initFromRenderTarget(GrContext* context,
+ GrRenderTarget* renderTarget) {
+ fNeedPrepareRenderTarget = false;
+ fDrawProcs = NULL;
+
+ fContext = context;
+ fContext->ref();
+
+ fTexture = NULL;
+ fRenderTarget = NULL;
+ fNeedClear = false;
+
+ GrAssert(NULL != renderTarget);
+ fRenderTarget = renderTarget;
+ fRenderTarget->ref();
+ // if this RT is also a texture, hold a ref on it
+ fTexture = fRenderTarget->asTexture();
+ SkSafeRef(fTexture);
+
+ SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
+ this->setPixelRef(pr, 0)->unref();
+}
+SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
+ int height, Usage usage)
+: SkDevice(config, width, height, false /*isOpaque*/) {
fNeedPrepareRenderTarget = false;
fDrawProcs = NULL;
fContext = context;
fContext->ref();
- fCache = NULL;
fTexture = NULL;
fRenderTarget = NULL;
fNeedClear = false;
- if (NULL == renderTargetOrNull) {
- SkBitmap::Config c = bitmap.config();
- if (c != SkBitmap::kRGB_565_Config) {
- c = SkBitmap::kARGB_8888_Config;
- }
- SkBitmap bm;
- bm.setConfig(c, this->width(), this->height());
+ if (config != SkBitmap::kRGB_565_Config) {
+ config = SkBitmap::kARGB_8888_Config;
+ }
+ SkBitmap bm;
+ bm.setConfig(config, width, height);
#if CACHE_LAYER_TEXTURES
-
- fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
- &fTexture, true);
- if (fCache) {
- SkASSERT(NULL != fTexture);
- SkASSERT(NULL != fTexture->asRenderTarget());
- }
+ TexType type = (kSaveLayer_Usage == usage) ?
+ kSaveLayerDeviceRenderTarget_TexType :
+ kDeviceRenderTarget_TexType;
+ fCache = this->lockCachedTexture(bm, NULL, type);
+ fTexture = fCache.texture();
+ if (fTexture) {
+ SkASSERT(NULL != fTexture->asRenderTarget());
+ // hold a ref directly on fTexture (even though fCache has one) to match
+ // other constructor paths. Simplifies cleanup.
+ fTexture->ref();
+ }
#else
- const GrTextureDesc desc = {
- kRenderTarget_GrTextureFlagBit,
- kNone_GrAALevel,
- this->width(),
- this->height(),
- SkGr::Bitmap2PixelConfig(bm)
- };
+ const GrTextureDesc desc = {
+ kRenderTarget_GrTextureFlagBit,
+ kNone_GrAALevel,
+ width,
+ height,
+ SkGr::Bitmap2PixelConfig(bm)
+ };
- fTexture = fContext->createUncachedTexture(desc, NULL, 0);
+ fTexture = fContext->createUncachedTexture(desc, NULL, 0);
#endif
- if (NULL != fTexture) {
- fRenderTarget = fTexture->asRenderTarget();
+ if (NULL != fTexture) {
+ fRenderTarget = fTexture->asRenderTarget();
+ fRenderTarget->ref();
- GrAssert(NULL != fRenderTarget);
+ GrAssert(NULL != fRenderTarget);
- // we defer the actual clear until our gainFocus()
- fNeedClear = true;
+ // we defer the actual clear until our gainFocus()
+ fNeedClear = true;
- // wrap the bitmap with a pixelref to expose our texture
- SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
- this->setPixelRef(pr, 0)->unref();
- } else {
- GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
- this->width(), this->height());
- GrAssert(false);
- }
- } else {
- if (Current3DApiRenderTarget() == renderTargetOrNull) {
- fRenderTarget = fContext->createRenderTargetFrom3DApiState();
- } else {
- fRenderTarget = renderTargetOrNull;
- fRenderTarget->ref();
- }
- SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
+ // wrap the bitmap with a pixelref to expose our texture
+ SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
this->setPixelRef(pr, 0)->unref();
+ } else {
+ GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
+ width, height);
+ GrAssert(false);
}
}
@@ -180,32 +238,16 @@ SkGpuDevice::~SkGpuDevice() {
delete fDrawProcs;
}
- if (fCache) {
+ SkSafeUnref(fTexture);
+ SkSafeUnref(fRenderTarget);
+ if (fCache.texture()) {
GrAssert(NULL != fTexture);
GrAssert(fRenderTarget == fTexture->asRenderTarget());
- fContext->unlockTexture((GrTextureEntry*)fCache);
- } else if (NULL != fTexture) {
- GrAssert(!CACHE_LAYER_TEXTURES);
- GrAssert(fRenderTarget == fTexture->asRenderTarget());
- fTexture->unref();
- } else if (NULL != fRenderTarget) {
- fRenderTarget->unref();
- }
+ fContext->unlockTexture(fCache);
+ }
fContext->unref();
}
-intptr_t SkGpuDevice::getLayerTextureHandle() const {
- if (fTexture) {
- return fTexture->getTextureHandle();
- } else {
- return 0;
- }
-}
-
-SkDeviceFactory* SkGpuDevice::onNewDeviceFactory() {
- return SkNEW_ARGS(SkGpuDeviceFactory, (fContext, fRenderTarget));
-}
-
///////////////////////////////////////////////////////////////////////////////
void SkGpuDevice::makeRenderTargetCurrent() {
@@ -216,52 +258,64 @@ void SkGpuDevice::makeRenderTargetCurrent() {
///////////////////////////////////////////////////////////////////////////////
-bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
- SkIRect bounds;
- bounds.set(0, 0, this->width(), this->height());
- if (!bounds.intersect(srcRect)) {
- return false;
- }
-
- const int w = bounds.width();
- const int h = bounds.height();
- SkBitmap tmp;
- // note we explicitly specify our rowBytes to be snug (no gap between rows)
- tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
- if (!tmp.allocPixels()) {
- return false;
+namespace {
+GrPixelConfig config8888_to_gr_config(SkCanvas::Config8888 config8888) {
+ switch (config8888) {
+ case SkCanvas::kNative_Premul_Config8888:
+ return kSkia8888_PM_GrPixelConfig;
+ case SkCanvas::kNative_Unpremul_Config8888:
+ return kSkia8888_UPM_GrPixelConfig;
+ case SkCanvas::kBGRA_Premul_Config8888:
+ return kBGRA_8888_PM_GrPixelConfig;
+ case SkCanvas::kBGRA_Unpremul_Config8888:
+ return kBGRA_8888_UPM_GrPixelConfig;
+ case SkCanvas::kRGBA_Premul_Config8888:
+ return kRGBA_8888_PM_GrPixelConfig;
+ case SkCanvas::kRGBA_Unpremul_Config8888:
+ return kRGBA_8888_UPM_GrPixelConfig;
+ default:
+ GrCrash("Unexpected Config8888.");
+ return kSkia8888_PM_GrPixelConfig;
}
+}
+}
- tmp.lockPixels();
-
- bool read = fContext->readRenderTargetPixels(fRenderTarget,
- bounds.fLeft, bounds.fTop,
- bounds.width(), bounds.height(),
- kRGBA_8888_GrPixelConfig,
- tmp.getPixels());
- tmp.unlockPixels();
- if (!read) {
- return false;
- }
+bool SkGpuDevice::onReadPixels(const SkBitmap& bitmap,
+ int x, int y,
+ SkCanvas::Config8888 config8888) {
+ SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
+ SkASSERT(!bitmap.isNull());
+ SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height())));
- tmp.swap(*bitmap);
- return true;
+ SkAutoLockPixels alp(bitmap);
+ GrPixelConfig config;
+ config = config8888_to_gr_config(config8888);
+ return fContext->readRenderTargetPixels(fRenderTarget,
+ x, y,
+ bitmap.width(),
+ bitmap.height(),
+ config,
+ bitmap.getPixels(),
+ bitmap.rowBytes());
}
-void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
+void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y,
+ SkCanvas::Config8888 config8888) {
SkAutoLockPixels alp(bitmap);
if (!bitmap.readyToDraw()) {
return;
}
- GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
- bitmap.isOpaque());
- fContext->setRenderTarget(fRenderTarget);
- // we aren't setting the clip or matrix, so mark as dirty
- // we don't need to set them for this call and don't have them anyway
- fNeedPrepareRenderTarget = true;
- fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
- config, bitmap.getPixels(), bitmap.rowBytes());
+ GrPixelConfig config;
+ if (SkBitmap::kARGB_8888_Config == bitmap.config()) {
+ config = config8888_to_gr_config(config8888);
+ } else {
+ config= SkGr::BitmapConfig2PixelConfig(bitmap.config(),
+ bitmap.isOpaque());
+ }
+
+ fRenderTarget->writePixels(x, y, bitmap.width(), bitmap.height(),
+ config, bitmap.getPixels(), bitmap.rowBytes());
}
///////////////////////////////////////////////////////////////////////////////
@@ -321,6 +375,10 @@ void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
}
}
+SkGpuRenderTarget* SkGpuDevice::accessRenderTarget() {
+ return (SkGpuRenderTarget*)fRenderTarget;
+}
+
bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) {
if (NULL != fTexture) {
paint->setTexture(kBitmapTextureIdx, fTexture);
@@ -361,7 +419,7 @@ bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
SkXfermode* mode = skPaint.getXfermode();
if (mode) {
if (!mode->asCoeff(&sm, &dm)) {
- SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
+ //SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)
#if 0
return false;
#endif
@@ -383,16 +441,24 @@ bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
SkColorFilter* colorFilter = skPaint.getColorFilter();
SkColor color;
SkXfermode::Mode filterMode;
+ SkScalar matrix[20];
if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
+ grPaint->fColorMatrixEnabled = false;
if (!constantColor) {
grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color);
grPaint->fColorFilterXfermode = filterMode;
- return true;
+ } else {
+ SkColor filtered = colorFilter->filterColor(skPaint.getColor());
+ grPaint->fColor = SkGr::SkColor2GrColor(filtered);
+ grPaint->resetColorFilter();
}
- SkColor filtered = colorFilter->filterColor(skPaint.getColor());
- grPaint->fColor = SkGr::SkColor2GrColor(filtered);
+ } else if (colorFilter != NULL && colorFilter->asColorMatrix(matrix)) {
+ grPaint->fColorMatrixEnabled = true;
+ memcpy(grPaint->fColorMatrix, matrix, sizeof(matrix));
+ grPaint->fColorFilterXfermode = SkXfermode::kDst_Mode;
+ } else {
+ grPaint->resetColorFilter();
}
- grPaint->resetColorFilter();
return true;
}
@@ -414,23 +480,35 @@ bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
return false;
}
- SkPaint noAlphaPaint(skPaint);
- noAlphaPaint.setAlpha(255);
- shader->setContext(this->accessBitmap(false), noAlphaPaint, ctm);
-
SkBitmap bitmap;
- SkMatrix matrix;
+ SkMatrix* matrix = grPaint->textureSampler(kShaderTextureIdx)->matrix();
SkShader::TileMode tileModes[2];
SkScalar twoPointParams[3];
- SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
+ SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, matrix,
tileModes, twoPointParams);
GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype];
if (-1 == sampleMode) {
- SkDebugf("shader->asABitmap() == kNone_BitmapType\n");
+ SkShader::GradientInfo info;
+ SkColor color;
+
+ info.fColors = &color;
+ info.fColorOffsets = NULL;
+ info.fColorCount = 1;
+ if (SkShader::kColor_GradientType == shader->asAGradient(&info)) {
+ SkPaint copy(skPaint);
+ copy.setShader(NULL);
+ // modulate the paint alpha by the shader's solid color alpha
+ U8CPU newA = SkMulDiv255Round(SkColorGetA(color), copy.getAlpha());
+ copy.setColor(SkColorSetA(color, newA));
+ return this->skPaint2GrPaintNoShader(copy,
+ false,
+ grPaint,
+ constantColor);
+ }
return false;
}
- GrSamplerState* sampler = grPaint->getTextureSampler(kShaderTextureIdx);
+ GrSamplerState* sampler = grPaint->textureSampler(kShaderTextureIdx);
sampler->setSampleMode(sampleMode);
if (skPaint.isFilterBitmap()) {
sampler->setFilter(GrSamplerState::kBilinear_Filter);
@@ -445,7 +523,7 @@ bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
twoPointParams[2] < 0);
}
- GrTexture* texture = act->set(this, bitmap, *sampler);
+ GrTexture* texture = act->set(this, bitmap, sampler);
if (NULL == texture) {
SkDebugf("Couldn't convert bitmap to texture.\n");
return false;
@@ -458,154 +536,23 @@ bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint,
if (shader->getLocalMatrix(&localM)) {
SkMatrix inverse;
if (localM.invert(&inverse)) {
- matrix.preConcat(inverse);
+ matrix->preConcat(inverse);
}
}
if (SkShader::kDefault_BitmapType == bmptype) {
GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width());
GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height());
- matrix.postScale(sx, sy);
+ matrix->postScale(sx, sy);
} else if (SkShader::kRadial_BitmapType == bmptype) {
GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width());
- matrix.postScale(s, s);
+ matrix->postScale(s, s);
}
- sampler->setMatrix(matrix);
return true;
}
///////////////////////////////////////////////////////////////////////////////
-class SkPositionSource {
-public:
- SkPositionSource(const SkPoint* points, int count)
- : fPoints(points), fCount(count) {}
-
- int count() const { return fCount; }
-
- void writeValue(int i, GrPoint* dstPosition) const {
- SkASSERT(i < fCount);
- dstPosition->fX = SkScalarToGrScalar(fPoints[i].fX);
- dstPosition->fY = SkScalarToGrScalar(fPoints[i].fY);
- }
-private:
- const SkPoint* fPoints;
- int fCount;
-};
-
-class SkTexCoordSource {
-public:
- SkTexCoordSource(const SkPoint* coords)
- : fCoords(coords) {}
-
- void writeValue(int i, GrPoint* dstCoord) const {
- dstCoord->fX = SkScalarToGrScalar(fCoords[i].fX);
- dstCoord->fY = SkScalarToGrScalar(fCoords[i].fY);
- }
-private:
- const SkPoint* fCoords;
-};
-
-class SkColorSource {
-public:
- SkColorSource(const SkColor* colors) : fColors(colors) {}
-
- void writeValue(int i, GrColor* dstColor) const {
- *dstColor = SkGr::SkColor2GrColor(fColors[i]);
- }
-private:
- const SkColor* fColors;
-};
-
-class SkIndexSource {
-public:
- SkIndexSource(const uint16_t* indices, int count)
- : fIndices(indices), fCount(count) {
- }
-
- int count() const { return fCount; }
-
- void writeValue(int i, uint16_t* dstIndex) const {
- *dstIndex = fIndices[i];
- }
-
-private:
- const uint16_t* fIndices;
- int fCount;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-#if 0 // not currently being used so don't compile,
-
-// can be used for positions or texture coordinates
-
-class SkRectFanSource {
-public:
- SkRectFanSource(const SkRect& rect) : fRect(rect) {}
-
- int count() const { return 4; }
-
- void writeValue(int i, GrPoint* dstPoint) const {
- SkASSERT(i < 4);
- dstPoint->fX = SkScalarToGrScalar((i % 3) ? fRect.fRight :
- fRect.fLeft);
- dstPoint->fY = SkScalarToGrScalar((i < 2) ? fRect.fTop :
- fRect.fBottom);
- }
-private:
- const SkRect& fRect;
-};
-
-class SkIRectFanSource {
-public:
- SkIRectFanSource(const SkIRect& rect) : fRect(rect) {}
-
- int count() const { return 4; }
-
- void writeValue(int i, GrPoint* dstPoint) const {
- SkASSERT(i < 4);
- dstPoint->fX = (i % 3) ? GrIntToScalar(fRect.fRight) :
- GrIntToScalar(fRect.fLeft);
- dstPoint->fY = (i < 2) ? GrIntToScalar(fRect.fTop) :
- GrIntToScalar(fRect.fBottom);
- }
-private:
- const SkIRect& fRect;
-};
-
-class SkMatRectFanSource {
-public:
- SkMatRectFanSource(const SkRect& rect, const SkMatrix& matrix)
- : fRect(rect), fMatrix(matrix) {}
-
- int count() const { return 4; }
-
- void writeValue(int i, GrPoint* dstPoint) const {
- SkASSERT(i < 4);
-
-#if SK_SCALAR_IS_GR_SCALAR
- fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
- (i < 2) ? fRect.fTop : fRect.fBottom,
- (SkPoint*)dstPoint);
-#else
- SkPoint dst;
- fMatrix.mapXY((i % 3) ? fRect.fRight : fRect.fLeft,
- (i < 2) ? fRect.fTop : fRect.fBottom,
- &dst);
- dstPoint->fX = SkScalarToGrScalar(dst.fX);
- dstPoint->fY = SkScalarToGrScalar(dst.fY);
-#endif
- }
-private:
- const SkRect& fRect;
- const SkMatrix& fMatrix;
-};
-
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-
void SkGpuDevice::clear(SkColor color) {
fContext->clear(NULL, color);
}
@@ -658,7 +605,6 @@ void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
return;
}
-#if SK_SCALAR_IS_GR_SCALAR
fContext->drawVertices(grPaint,
gPointMode2PrimtiveType[mode],
count,
@@ -667,11 +613,6 @@ void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
NULL,
NULL,
0);
-#else
- fContext->drawCustomVertices(grPaint,
- gPointMode2PrimtiveType[mode],
- SkPositionSource(pts, count));
-#endif
}
///////////////////////////////////////////////////////////////////////////////
@@ -680,7 +621,7 @@ void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
const SkPaint& paint) {
CHECK_SHOULD_DRAW(draw);
- bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
+ bool doStroke = paint.getStyle() != SkPaint::kFill_Style;
SkScalar width = paint.getStrokeWidth();
/*
@@ -697,6 +638,16 @@ void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) {
usePath = true;
}
+ // small miter limit means right angles show bevel...
+ if (SkPaint::kMiter_Join == paint.getStrokeJoin() &&
+ paint.getStrokeMiter() < SK_ScalarSqrt2)
+ {
+ usePath = true;
+ }
+ // until we can both stroke and fill rectangles
+ if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) {
+ usePath = true;
+ }
if (usePath) {
SkPath path;
@@ -720,6 +671,321 @@ void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
#include "SkMaskFilter.h"
#include "SkBounder.h"
+static GrPathFill skToGrFillType(SkPath::FillType fillType) {
+ switch (fillType) {
+ case SkPath::kWinding_FillType:
+ return kWinding_PathFill;
+ case SkPath::kEvenOdd_FillType:
+ return kEvenOdd_PathFill;
+ case SkPath::kInverseWinding_FillType:
+ return kInverseWinding_PathFill;
+ case SkPath::kInverseEvenOdd_FillType:
+ return kInverseEvenOdd_PathFill;
+ default:
+ SkDebugf("Unsupported path fill type\n");
+ return kHairLine_PathFill;
+ }
+}
+
+static void buildKernel(float sigma, float* kernel, int kernelWidth) {
+ int halfWidth = (kernelWidth - 1) / 2;
+ float sum = 0.0f;
+ float denom = 1.0f / (2.0f * sigma * sigma);
+ for (int i = 0; i < kernelWidth; ++i) {
+ float x = static_cast<float>(i - halfWidth);
+ // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
+ // is dropped here, since we renormalize the kernel below.
+ kernel[i] = sk_float_exp(- x * x * denom);
+ sum += kernel[i];
+ }
+ // Normalize the kernel
+ float scale = 1.0f / sum;
+ for (int i = 0; i < kernelWidth; ++i)
+ kernel[i] *= scale;
+}
+
+static void scaleRect(SkRect* rect, float xScale, float yScale) {
+ rect->fLeft *= xScale;
+ rect->fTop *= yScale;
+ rect->fRight *= xScale;
+ rect->fBottom *= yScale;
+}
+
+static float adjustSigma(float sigma, int *scaleFactor, int *halfWidth,
+ int *kernelWidth) {
+ *scaleFactor = 1;
+ while (sigma > MAX_BLUR_SIGMA) {
+ *scaleFactor *= 2;
+ sigma *= 0.5f;
+ }
+ *halfWidth = static_cast<int>(ceilf(sigma * 3.0f));
+ *kernelWidth = *halfWidth * 2 + 1;
+ return sigma;
+}
+
+// Apply a Gaussian blur to srcTexture by sigmaX and sigmaY, within the given
+// rect.
+// temp1 and temp2 are used for allocation of intermediate textures.
+// If temp2 is non-NULL, srcTexture will be untouched, and the return
+// value will be either temp1 or temp2.
+// If temp2 is NULL, srcTexture will be overwritten with intermediate
+// results, and the return value will either be temp1 or srcTexture.
+static GrTexture* gaussianBlur(GrContext* context, GrTexture* srcTexture,
+ GrAutoScratchTexture* temp1,
+ GrAutoScratchTexture* temp2,
+ const SkRect& rect,
+ float sigmaX, float sigmaY) {
+
+ GrRenderTarget* oldRenderTarget = context->getRenderTarget();
+ GrClip oldClip = context->getClip();
+ GrTexture* origTexture = srcTexture;
+ GrAutoMatrix avm(context, GrMatrix::I());
+ SkIRect clearRect;
+ int scaleFactorX, halfWidthX, kernelWidthX;
+ int scaleFactorY, halfWidthY, kernelWidthY;
+ sigmaX = adjustSigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX);
+ sigmaY = adjustSigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY);
+
+ SkRect srcRect(rect);
+ scaleRect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
+ srcRect.roundOut();
+ scaleRect(&srcRect, scaleFactorX, scaleFactorY);
+ context->setClip(srcRect);
+
+ const GrTextureDesc desc = {
+ kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit,
+ kNone_GrAALevel,
+ srcRect.width(),
+ srcRect.height(),
+ kRGBA_8888_GrPixelConfig
+ };
+
+ temp1->set(context, desc);
+ if (temp2) temp2->set(context, desc);
+
+ GrTexture* dstTexture = temp1->texture();
+ GrPaint paint;
+ paint.reset();
+ paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
+
+ for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
+ paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
+ srcTexture->height());
+ context->setRenderTarget(dstTexture->asRenderTarget());
+ SkRect dstRect(srcRect);
+ scaleRect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f,
+ i < scaleFactorY ? 0.5f : 1.0f);
+ paint.setTexture(0, srcTexture);
+ context->drawRectToRect(paint, dstRect, srcRect);
+ srcRect = dstRect;
+ SkTSwap(srcTexture, dstTexture);
+ // If temp2 is non-NULL, don't render back to origTexture
+ if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
+ }
+
+ if (sigmaX > 0.0f) {
+ SkAutoTMalloc<float> kernelStorageX(kernelWidthX);
+ float* kernelX = kernelStorageX.get();
+ buildKernel(sigmaX, kernelX, kernelWidthX);
+
+ if (scaleFactorX > 1) {
+ // Clear out a halfWidth to the right of the srcRect to prevent the
+ // X convolution from reading garbage.
+ clearRect = SkIRect::MakeXYWH(
+ srcRect.fRight, srcRect.fTop, halfWidthX, srcRect.height());
+ context->clear(&clearRect, 0x0);
+ }
+
+ context->setRenderTarget(dstTexture->asRenderTarget());
+ context->convolveInX(srcTexture, srcRect, kernelX, kernelWidthX);
+ SkTSwap(srcTexture, dstTexture);
+ if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
+ }
+
+ if (sigmaY > 0.0f) {
+ SkAutoTMalloc<float> kernelStorageY(kernelWidthY);
+ float* kernelY = kernelStorageY.get();
+ buildKernel(sigmaY, kernelY, kernelWidthY);
+
+ if (scaleFactorY > 1 || sigmaX > 0.0f) {
+ // Clear out a halfWidth below the srcRect to prevent the Y
+ // convolution from reading garbage.
+ clearRect = SkIRect::MakeXYWH(
+ srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidthY);
+ context->clear(&clearRect, 0x0);
+ }
+
+ context->setRenderTarget(dstTexture->asRenderTarget());
+ context->convolveInY(srcTexture, srcRect, kernelY, kernelWidthY);
+ SkTSwap(srcTexture, dstTexture);
+ if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture();
+ }
+
+ if (scaleFactorX > 1 || scaleFactorY > 1) {
+ // Clear one pixel to the right and below, to accommodate bilinear
+ // upsampling.
+ clearRect = SkIRect::MakeXYWH(
+ srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
+ context->clear(&clearRect, 0x0);
+ clearRect = SkIRect::MakeXYWH(
+ srcRect.fRight, srcRect.fTop, 1, srcRect.height());
+ context->clear(&clearRect, 0x0);
+ // FIXME: This should be mitchell, not bilinear.
+ paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
+ paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
+ srcTexture->height());
+ context->setRenderTarget(dstTexture->asRenderTarget());
+ paint.setTexture(0, srcTexture);
+ SkRect dstRect(srcRect);
+ scaleRect(&dstRect, scaleFactorX, scaleFactorY);
+ context->drawRectToRect(paint, dstRect, srcRect);
+ srcRect = dstRect;
+ SkTSwap(srcTexture, dstTexture);
+ }
+ context->setRenderTarget(oldRenderTarget);
+ context->setClip(oldClip);
+ return srcTexture;
+}
+
+static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
+ SkMaskFilter* filter, const SkMatrix& matrix,
+ const SkRegion& clip, SkBounder* bounder,
+ GrPaint* grp) {
+#ifdef SK_DISABLE_GPU_BLUR
+ return false;
+#endif
+ SkMaskFilter::BlurInfo info;
+ SkMaskFilter::BlurType blurType = filter->asABlur(&info);
+ if (SkMaskFilter::kNone_BlurType == blurType) {
+ return false;
+ }
+ SkScalar radius = info.fIgnoreTransform ? info.fRadius
+ : matrix.mapRadius(info.fRadius);
+ radius = SkMinScalar(radius, MAX_BLUR_RADIUS);
+ if (radius <= 0) {
+ return false;
+ }
+ float sigma = SkScalarToFloat(radius) * BLUR_SIGMA_SCALE;
+ float sigma3 = sigma * 3.0f;
+
+ SkRect srcRect = path.getBounds();
+ SkRect clipRect;
+ clipRect.set(clip.getBounds());
+
+ // Outset srcRect and clipRect by 3 * sigma, to compute affected blur area.
+ srcRect.inset(-sigma3, -sigma3);
+ clipRect.inset(-sigma3, -sigma3);
+ srcRect.intersect(clipRect);
+ SkRect finalRect = srcRect;
+ SkIRect finalIRect;
+ finalRect.roundOut(&finalIRect);
+ if (clip.quickReject(finalIRect)) {
+ return true;
+ }
+ if (bounder && !bounder->doIRect(finalIRect)) {
+ return true;
+ }
+ GrPoint offset = GrPoint::Make(-srcRect.fLeft, -srcRect.fTop);
+ srcRect.offset(offset);
+ const GrTextureDesc desc = {
+ kRenderTarget_GrTextureFlagBit,
+ kNone_GrAALevel,
+ srcRect.width(),
+ srcRect.height(),
+ // We actually only need A8, but it often isn't supported as a
+ // render target
+ kRGBA_8888_PM_GrPixelConfig
+ };
+
+ GrAutoScratchTexture pathEntry(context, desc);
+ GrTexture* pathTexture = pathEntry.texture();
+ if (NULL == pathTexture) {
+ return false;
+ }
+ GrRenderTarget* oldRenderTarget = context->getRenderTarget();
+ // Once this code moves into GrContext, this should be changed to use
+ // an AutoClipRestore.
+ GrClip oldClip = context->getClip();
+ context->setRenderTarget(pathTexture->asRenderTarget());
+ context->setClip(srcRect);
+ context->clear(NULL, 0);
+ GrPaint tempPaint;
+ tempPaint.reset();
+
+ GrAutoMatrix avm(context, GrMatrix::I());
+ tempPaint.fAntiAlias = grp->fAntiAlias;
+ if (tempPaint.fAntiAlias) {
+ // AA uses the "coverage" stages on GrDrawTarget. Coverage with a dst
+ // blend coeff of zero requires dual source blending support in order
+ // to properly blend partially covered pixels. This means the AA
+ // code path may not be taken. So we use a dst blend coeff of ISA. We
+ // could special case AA draws to a dst surface with known alpha=0 to
+ // use a zero dst coeff when dual source blending isn't available.
+ tempPaint.fSrcBlendCoeff = kOne_BlendCoeff;
+ tempPaint.fDstBlendCoeff = kISC_BlendCoeff;
+ }
+ // Draw hard shadow to pathTexture with path topleft at origin 0,0.
+ context->drawPath(tempPaint, path, skToGrFillType(path.getFillType()), &offset);
+
+ GrAutoScratchTexture temp1, temp2;
+ // If we're doing a normal blur, we can clobber the pathTexture in the
+ // gaussianBlur. Otherwise, we need to save it for later compositing.
+ bool isNormalBlur = blurType == SkMaskFilter::kNormal_BlurType;
+ GrTexture* blurTexture = gaussianBlur(context, pathTexture,
+ &temp1, isNormalBlur ? NULL : &temp2,
+ srcRect, sigma, sigma);
+
+ if (!isNormalBlur) {
+ GrPaint paint;
+ paint.reset();
+ paint.textureSampler(0)->setFilter(GrSamplerState::kNearest_Filter);
+ paint.textureSampler(0)->matrix()->setIDiv(pathTexture->width(),
+ pathTexture->height());
+ // Blend pathTexture over blurTexture.
+ context->setRenderTarget(blurTexture->asRenderTarget());
+ paint.setTexture(0, pathTexture);
+ if (SkMaskFilter::kInner_BlurType == blurType) {
+ // inner: dst = dst * src
+ paint.fSrcBlendCoeff = kDC_BlendCoeff;
+ paint.fDstBlendCoeff = kZero_BlendCoeff;
+ } else if (SkMaskFilter::kSolid_BlurType == blurType) {
+ // solid: dst = src + dst - src * dst
+ // = (1 - dst) * src + 1 * dst
+ paint.fSrcBlendCoeff = kIDC_BlendCoeff;
+ paint.fDstBlendCoeff = kOne_BlendCoeff;
+ } else if (SkMaskFilter::kOuter_BlurType == blurType) {
+ // outer: dst = dst * (1 - src)
+ // = 0 * src + (1 - src) * dst
+ paint.fSrcBlendCoeff = kZero_BlendCoeff;
+ paint.fDstBlendCoeff = kISC_BlendCoeff;
+ }
+ context->drawRect(paint, srcRect);
+ }
+ context->setRenderTarget(oldRenderTarget);
+ context->setClip(oldClip);
+
+ if (grp->hasTextureOrMask()) {
+ GrMatrix inverse;
+ if (!matrix.invert(&inverse)) {
+ return false;
+ }
+ grp->preConcatActiveSamplerMatrices(inverse);
+ }
+
+ static const int MASK_IDX = GrPaint::kMaxMasks - 1;
+ // we assume the last mask index is available for use
+ GrAssert(NULL == grp->getMask(MASK_IDX));
+ grp->setMask(MASK_IDX, blurTexture);
+ grp->maskSampler(MASK_IDX)->reset();
+
+ grp->maskSampler(MASK_IDX)->matrix()->setTranslate(-finalRect.fLeft,
+ -finalRect.fTop);
+ grp->maskSampler(MASK_IDX)->matrix()->postIDiv(blurTexture->width(),
+ blurTexture->height());
+ context->drawRect(*grp, finalRect);
+ return true;
+}
+
static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
SkMaskFilter* filter, const SkMatrix& matrix,
const SkRegion& clip, SkBounder* bounder,
@@ -730,14 +996,13 @@ static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
return false;
}
-
- SkAutoMaskImage autoSrc(&srcM, false);
+ SkAutoMaskFreeImage autoSrc(srcM.fImage);
if (!filter->filterMask(&dstM, srcM, matrix, NULL)) {
return false;
}
// this will free-up dstM when we're done (allocated in filterMask())
- SkAutoMaskImage autoDst(&dstM, false);
+ SkAutoMaskFreeImage autoDst(dstM.fImage);
if (clip.quickReject(dstM.fBounds)) {
return false;
@@ -762,11 +1027,14 @@ static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
kAlpha_8_GrPixelConfig
};
- GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
- dstM.fRowBytes);
+ GrAutoScratchTexture ast(context, desc);
+ GrTexture* texture = ast.texture();
+
if (NULL == texture) {
return false;
}
+ texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
+ dstM.fImage, dstM.fRowBytes);
if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {
grp->preConcatActiveSamplerMatrices(ivm);
@@ -776,8 +1044,7 @@ static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
// we assume the last mask index is available for use
GrAssert(NULL == grp->getMask(MASK_IDX));
grp->setMask(MASK_IDX, texture);
- texture->unref();
- grp->getMaskSampler(MASK_IDX)->setClampNoFilter();
+ grp->maskSampler(MASK_IDX)->reset();
GrRect d;
d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft),
@@ -785,23 +1052,41 @@ static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
GrIntToScalar(dstM.fBounds.fRight),
GrIntToScalar(dstM.fBounds.fBottom));
- GrMatrix m;
- m.setTranslate(-dstM.fBounds.fLeft, -dstM.fBounds.fTop);
- m.postIDiv(dstM.fBounds.width(), dstM.fBounds.height());
- grp->getMaskSampler(MASK_IDX)->setMatrix(m);
-
+ GrMatrix* m = grp->maskSampler(MASK_IDX)->matrix();
+ m->setTranslate(-dstM.fBounds.fLeft*SK_Scalar1,
+ -dstM.fBounds.fTop*SK_Scalar1);
+ m->postIDiv(texture->width(), texture->height());
context->drawRect(*grp, d);
return true;
}
void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
- const SkPaint& paint, const SkMatrix* prePathMatrix,
+ const SkPaint& origPaint, const SkMatrix* prePathMatrix,
bool pathIsMutable) {
CHECK_SHOULD_DRAW(draw);
+ bool doFill = true;
+ SkTLazy<SkPaint> lazyPaint;
+ const SkPaint* paint = &origPaint;
+
+ // can we cheat, and threat a thin stroke as a hairline (w/ modulated alpha)
+ // if we can, we draw lots faster (raster device does this same test)
+ {
+ SkAlpha newAlpha;
+ if (SkDrawTreatAsHairline(*paint, *draw.fMatrix, &newAlpha)) {
+ lazyPaint.set(*paint);
+ lazyPaint.get()->setAlpha(newAlpha);
+ lazyPaint.get()->setStrokeWidth(0);
+ paint = lazyPaint.get();
+ doFill = false;
+ }
+ }
+ // must reference paint from here down, and not origPaint
+ // since we may have change the paint (using lazyPaint for storage)
+
GrPaint grPaint;
SkAutoCachedTexture act;
- if (!this->skPaint2GrPaintShader(paint,
+ if (!this->skPaint2GrPaintShader(*paint,
&act,
*draw.fMatrix,
&grPaint,
@@ -809,11 +1094,11 @@ void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
return;
}
- // BEGIN lift from SkDraw::drawPath()
-
- SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
- bool doFill = true;
- SkPath tmpPath;
+ // If we have a prematrix, apply it to the path, optimizing for the case
+ // where the original path can in fact be modified in place (even though
+ // its parameter type is const).
+ SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
+ SkPath tmpPath;
if (prePathMatrix) {
SkPath* result = pathPtr;
@@ -830,37 +1115,28 @@ void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
// at this point we're done with prePathMatrix
SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
- // This "if" is not part of the SkDraw::drawPath() lift.
- // When we get a 1.0 wide stroke we hairline stroke it instead of creating
- // a new stroked-path. This is motivated by canvas2D sites that draw
- // lines as 1.0 wide stroked paths. We can consider doing an alpha-modulated-
- // hairline for width < 1.0 when AA is enabled.
- static const int gMatrixMask = ~(SkMatrix::kIdentity_Mask |
- SkMatrix::kTranslate_Mask);
- if (!paint.getPathEffect() &&
- SkPaint::kStroke_Style == paint.getStyle() &&
- !(draw.fMatrix->getType() & gMatrixMask) &&
- SK_Scalar1 == paint.getStrokeWidth()) {
- doFill = false;
- }
-
- if (doFill && (paint.getPathEffect() ||
- paint.getStyle() != SkPaint::kFill_Style)) {
- doFill = paint.getFillPath(*pathPtr, &tmpPath);
+ if (doFill && (paint->getPathEffect() ||
+ paint->getStyle() != SkPaint::kFill_Style)) {
+ // it is safe to use tmpPath here, even if we already used it for the
+ // prepathmatrix, since getFillPath can take the same object for its
+ // input and output safely.
+ doFill = paint->getFillPath(*pathPtr, &tmpPath);
pathPtr = &tmpPath;
}
- // END lift from SkDraw::drawPath()
-
- if (paint.getMaskFilter()) {
+ if (paint->getMaskFilter()) {
// avoid possibly allocating a new path in transform if we can
SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
// transform the path into device space
pathPtr->transform(*draw.fMatrix, devPathPtr);
-
- drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
- *draw.fMatrix, *draw.fClip, draw.fBounder, &grPaint);
+ if (!drawWithGPUMaskFilter(fContext, *devPathPtr, paint->getMaskFilter(),
+ *draw.fMatrix, *draw.fClip, draw.fBounder,
+ &grPaint)) {
+ drawWithMaskFilter(fContext, *devPathPtr, paint->getMaskFilter(),
+ *draw.fMatrix, *draw.fClip, draw.fBounder,
+ &grPaint);
+ }
return;
}
@@ -889,6 +1165,105 @@ void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
fContext->drawPath(grPaint, *pathPtr, fill);
}
+namespace {
+
+inline int get_tile_count(int l, int t, int r, int b, int tileSize) {
+ int tilesX = (r / tileSize) - (l / tileSize) + 1;
+ int tilesY = (b / tileSize) - (t / tileSize) + 1;
+ return tilesX * tilesY;
+}
+
+inline int determine_tile_size(const SkBitmap& bitmap,
+ const SkIRect* srcRectPtr,
+ int maxTextureSize) {
+ static const int kSmallTileSize = 1 << 10;
+ if (maxTextureSize <= kSmallTileSize) {
+ return maxTextureSize;
+ }
+
+ size_t maxTexTotalTileSize;
+ size_t smallTotalTileSize;
+
+ if (NULL == srcRectPtr) {
+ int w = bitmap.width();
+ int h = bitmap.height();
+ maxTexTotalTileSize = get_tile_count(0, 0, w, h, maxTextureSize);
+ smallTotalTileSize = get_tile_count(0, 0, w, h, kSmallTileSize);
+ } else {
+ maxTexTotalTileSize = get_tile_count(srcRectPtr->fLeft,
+ srcRectPtr->fTop,
+ srcRectPtr->fRight,
+ srcRectPtr->fBottom,
+ maxTextureSize);
+ smallTotalTileSize = get_tile_count(srcRectPtr->fLeft,
+ srcRectPtr->fTop,
+ srcRectPtr->fRight,
+ srcRectPtr->fBottom,
+ kSmallTileSize);
+ }
+ maxTexTotalTileSize *= maxTextureSize * maxTextureSize;
+ smallTotalTileSize *= kSmallTileSize * kSmallTileSize;
+
+ if (maxTexTotalTileSize > 2 * smallTotalTileSize) {
+ return kSmallTileSize;
+ } else {
+ return maxTextureSize;
+ }
+}
+}
+
+bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap,
+ const GrSamplerState& sampler,
+ const SkIRect* srcRectPtr,
+ int* tileSize) const {
+ SkASSERT(NULL != tileSize);
+
+ // if bitmap is explictly texture backed then just use the texture
+ if (NULL != bitmap.getTexture()) {
+ return false;
+ }
+ // if it's larger than the max texture size, then we have no choice but
+ // tiling
+ const int maxTextureSize = fContext->getMaxTextureSize();
+ if (bitmap.width() > maxTextureSize ||
+ bitmap.height() > maxTextureSize) {
+ *tileSize = determine_tile_size(bitmap, srcRectPtr, maxTextureSize);
+ return true;
+ }
+ // if we are going to have to draw the whole thing, then don't tile
+ if (NULL == srcRectPtr) {
+ return false;
+ }
+ // if the entire texture is already in our cache then no reason to tile it
+ if (this->isBitmapInTextureCache(bitmap, sampler)) {
+ return false;
+ }
+
+ // At this point we know we could do the draw by uploading the entire bitmap
+ // as a texture. However, if the texture would be large compared to the
+ // cache size and we don't require most of it for this draw then tile to
+ // reduce the amount of upload and cache spill.
+
+ // assumption here is that sw bitmap size is a good proxy for its size as
+ // a texture
+ size_t bmpSize = bitmap.getSize();
+ size_t cacheSize;
+ fContext->getTextureCacheLimits(NULL, &cacheSize);
+ if (bmpSize < cacheSize / 2) {
+ return false;
+ }
+
+ SkFixed fracUsed =
+ SkFixedMul((srcRectPtr->width() << 16) / bitmap.width(),
+ (srcRectPtr->height() << 16) / bitmap.height());
+ if (fracUsed <= SK_FixedHalf) {
+ *tileSize = determine_tile_size(bitmap, srcRectPtr, maxTextureSize);
+ return true;
+ } else {
+ return false;
+ }
+}
+
void SkGpuDevice::drawBitmap(const SkDraw& draw,
const SkBitmap& bitmap,
const SkIRect* srcRectPtr,
@@ -903,21 +1278,51 @@ void SkGpuDevice::drawBitmap(const SkDraw& draw,
srcRect = *srcRectPtr;
}
+ if (paint.getMaskFilter()){
+ // Convert the bitmap to a shader so that the rect can be drawn
+ // through drawRect, which supports mask filters.
+ SkBitmap tmp; // subset of bitmap, if necessary
+ const SkBitmap* bitmapPtr = &bitmap;
+ if (srcRectPtr) {
+ if (!bitmap.extractSubset(&tmp, srcRect)) {
+ return; // extraction failed
+ }
+ bitmapPtr = &tmp;
+ srcRect.set(0,0, srcRect.width(), srcRect.height());
+ }
+ SkPaint paintWithTexture(paint);
+ paintWithTexture.setShader(SkShader::CreateBitmapShader( *bitmapPtr,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
+ SkRect ScalarRect;
+ ScalarRect.set(srcRect);
+
+ // Transform 'm' needs to be concatenated to the draw matrix,
+ // rather than transforming the primitive directly, so that 'm' will
+ // also affect the behavior of the mask filter.
+ SkMatrix drawMatrix;
+ drawMatrix.setConcat(*draw.fMatrix, m);
+ SkDraw transformedDraw(draw);
+ transformedDraw.fMatrix = &drawMatrix;
+
+ this->drawRect(transformedDraw, ScalarRect, paintWithTexture);
+
+ return;
+ }
+
GrPaint grPaint;
if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
return;
}
- GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
+ GrSamplerState* sampler = grPaint.textureSampler(kBitmapTextureIdx);
if (paint.isFilterBitmap()) {
sampler->setFilter(GrSamplerState::kBilinear_Filter);
} else {
sampler->setFilter(GrSamplerState::kNearest_Filter);
}
- const int maxTextureDim = fContext->getMaxTextureDimension();
- if (bitmap.getTexture() || (bitmap.width() <= maxTextureDim &&
- bitmap.height() <= maxTextureDim)) {
- // take the fast case
+ int tileSize;
+ if (!this->shouldTileBitmap(bitmap, *sampler, srcRectPtr, &tileSize)) {
+ // take the simple case
this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
return;
}
@@ -941,13 +1346,13 @@ void SkGpuDevice::drawBitmap(const SkDraw& draw,
clipRect.offset(DX, DY);
}
- int nx = bitmap.width() / maxTextureDim;
- int ny = bitmap.height() / maxTextureDim;
+ int nx = bitmap.width() / tileSize;
+ int ny = bitmap.height() / tileSize;
for (int x = 0; x <= nx; x++) {
for (int y = 0; y <= ny; y++) {
SkIRect tileR;
- tileR.set(x * maxTextureDim, y * maxTextureDim,
- (x + 1) * maxTextureDim, (y + 1) * maxTextureDim);
+ tileR.set(x * tileSize, y * tileSize,
+ (x + 1) * tileSize, (y + 1) * tileSize);
if (!SkIRect::Intersects(tileR, clipRect)) {
continue;
}
@@ -986,28 +1391,29 @@ void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
const SkIRect& srcRect,
const SkMatrix& m,
GrPaint* grPaint) {
- SkASSERT(bitmap.width() <= fContext->getMaxTextureDimension() &&
- bitmap.height() <= fContext->getMaxTextureDimension());
+ SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() &&
+ bitmap.height() <= fContext->getMaxTextureSize());
- SkAutoLockPixels alp(bitmap);
+ SkAutoLockPixels alp(bitmap, !bitmap.getTexture());
if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
+ SkDebugf("nothing to draw\n");
return;
}
- GrSamplerState* sampler = grPaint->getTextureSampler(kBitmapTextureIdx);
+ GrSamplerState* sampler = grPaint->textureSampler(kBitmapTextureIdx);
sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
sampler->setSampleMode(GrSamplerState::kNormal_SampleMode);
- sampler->setMatrix(GrMatrix::I());
+ sampler->matrix()->reset();
GrTexture* texture;
- SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
+ SkAutoCachedTexture act(this, bitmap, sampler, &texture);
if (NULL == texture) {
return;
}
- grPaint->setTexture(kShaderTextureIdx, texture);
+ grPaint->setTexture(kBitmapTextureIdx, texture);
GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
GrIntToScalar(srcRect.height()));
@@ -1054,6 +1460,9 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
return;
}
+ int w = bitmap.width();
+ int h = bitmap.height();
+
GrPaint grPaint;
if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) {
return;
@@ -1061,20 +1470,34 @@ void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
GrAutoMatrix avm(fContext, GrMatrix::I());
- GrSamplerState* sampler = grPaint.getTextureSampler(kBitmapTextureIdx);
+ GrSamplerState* sampler = grPaint.textureSampler(kBitmapTextureIdx);
GrTexture* texture;
- sampler->setClampNoFilter();
- SkAutoCachedTexture act(this, bitmap, *sampler, &texture);
-
- grPaint.setTexture(kBitmapTextureIdx, texture);
+ sampler->reset();
+ SkAutoCachedTexture act(this, bitmap, sampler, &texture);
+
+ SkImageFilter* imageFilter = paint.getImageFilter();
+ SkSize blurSize;
+ if (NULL != imageFilter && imageFilter->asABlur(&blurSize)) {
+ GrAutoScratchTexture temp1, temp2;
+ GrTexture* blurTexture = gaussianBlur(fContext,
+ texture, &temp1, &temp2,
+ GrRect::MakeWH(w, h),
+ blurSize.width(),
+ blurSize.height());
+ texture = blurTexture;
+ grPaint.setTexture(kBitmapTextureIdx, texture);
+ } else {
+ grPaint.setTexture(kBitmapTextureIdx, texture);
+ }
fContext->drawRectToRect(grPaint,
- GrRect::MakeXYWH(GrIntToScalar(left),
- GrIntToScalar(top),
- GrIntToScalar(bitmap.width()),
- GrIntToScalar(bitmap.height())),
- GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
+ GrRect::MakeXYWH(GrIntToScalar(left),
+ GrIntToScalar(top),
+ GrIntToScalar(w),
+ GrIntToScalar(h)),
+ GrRect::MakeWH(GR_Scalar1 * w / texture->width(),
+ GR_Scalar1 * h / texture->height()));
}
void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
@@ -1087,7 +1510,8 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
return;
}
- SkASSERT(NULL != grPaint.getTexture(0));
+ GrTexture* devTex = grPaint.getTexture(0);
+ SkASSERT(NULL != devTex);
const SkBitmap& bm = dev->accessBitmap(false);
int w = bm.width();
@@ -1095,14 +1519,42 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
GrAutoMatrix avm(fContext, GrMatrix::I());
- grPaint.getTextureSampler(kBitmapTextureIdx)->setClampNoFilter();
+ grPaint.textureSampler(kBitmapTextureIdx)->reset();
- fContext->drawRectToRect(grPaint,
- GrRect::MakeXYWH(GrIntToScalar(x),
- GrIntToScalar(y),
- GrIntToScalar(w),
- GrIntToScalar(h)),
- GrRect::MakeWH(GR_Scalar1, GR_Scalar1));
+ GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x),
+ GrIntToScalar(y),
+ GrIntToScalar(w),
+ GrIntToScalar(h));
+
+ // The device being drawn may not fill up its texture (saveLayer uses
+ // the approximate ).
+ GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(),
+ GR_Scalar1 * h / devTex->height());
+
+ fContext->drawRectToRect(grPaint, dstRect, srcRect);
+}
+
+bool SkGpuDevice::filterImage(SkImageFilter* filter, const SkBitmap& src,
+ const SkMatrix& ctm,
+ SkBitmap* result, SkIPoint* offset) {
+ SkSize size;
+ if (!filter->asABlur(&size)) {
+ return false;
+ }
+ SkDevice* dev = this->createCompatibleDevice(SkBitmap::kARGB_8888_Config,
+ src.width(),
+ src.height(),
+ false);
+ if (NULL == dev) {
+ return false;
+ }
+ SkAutoUnref aur(dev);
+ SkCanvas canvas(dev);
+ SkPaint paint;
+ paint.setImageFilter(filter);
+ canvas.drawSprite(src, 0, 0, &paint);
+ *result = dev->accessBitmap(false);
+ return true;
}
///////////////////////////////////////////////////////////////////////////////
@@ -1142,9 +1594,7 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
}
if (NULL != xmode && NULL != texs && NULL != colors) {
- SkXfermode::Mode mode;
- if (!SkXfermode::IsMode(xmode, &mode) ||
- SkXfermode::kMultiply_Mode != mode) {
+ if (!SkXfermode::IsMode(xmode, SkXfermode::kMultiply_Mode)) {
SkDebugf("Unsupported vertex-color/texture xfer mode.\n");
#if 0
return
@@ -1152,32 +1602,23 @@ void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
}
}
-#if SK_SCALAR_IS_GR_SCALAR
- // even if GrColor and SkColor byte offsets match we need
- // to perform pre-multiply.
- if (NULL == colors) {
- fContext->drawVertices(grPaint,
- gVertexMode2PrimitiveType[vmode],
- vertexCount,
- (GrPoint*) vertices,
- (GrPoint*) texs,
- NULL,
- indices,
- indexCount);
- } else
-#endif
- {
- SkTexCoordSource texSrc(texs);
- SkColorSource colSrc(colors);
- SkIndexSource idxSrc(indices, indexCount);
-
- fContext->drawCustomVertices(grPaint,
- gVertexMode2PrimitiveType[vmode],
- SkPositionSource(vertices, vertexCount),
- (NULL == texs) ? NULL : &texSrc,
- (NULL == colors) ? NULL : &colSrc,
- (NULL == indices) ? NULL : &idxSrc);
+ SkAutoSTMalloc<128, GrColor> convertedColors(0);
+ if (NULL != colors) {
+ // need to convert byte order and from non-PM to PM
+ convertedColors.reset(vertexCount);
+ for (int i = 0; i < vertexCount; ++i) {
+ convertedColors[i] = SkGr::SkColor2GrColor(colors[i]);
+ }
+ colors = convertedColors.get();
}
+ fContext->drawVertices(grPaint,
+ gVertexMode2PrimitiveType[vmode],
+ vertexCount,
+ (GrPoint*) vertices,
+ (GrPoint*) texs,
+ colors,
+ indices,
+ indexCount);
}
///////////////////////////////////////////////////////////////////////////////
@@ -1204,30 +1645,17 @@ static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
const SkGlyph& glyph) {
SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
- GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
+ GrSkDrawProcs* procs = static_cast<GrSkDrawProcs*>(state.fDraw->fProcs);
if (NULL == procs->fFontScaler) {
procs->fFontScaler = get_gr_font_scaler(state.fCache);
}
- /*
- * What should we do with fy? (assuming horizontal/latin text)
- *
- * The raster code calls SkFixedFloorToFixed on it, as it does with fx.
- * It calls that rather than round, because our caller has already added
- * SK_FixedHalf, so that calling floor gives us the rounded integer.
- *
- * Test code between raster and gpu (they should draw the same)
- *
- * canvas->drawText("Hamburgefons", 12, 0, 16.5f, paint);
- *
- * Perhaps we should only perform this integralization if there is no
- * fExtMatrix...
- */
- fy = SkFixedFloorToFixed(fy);
-
- procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
- SkFixedFloorToFixed(fx), fy,
+ procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
+ glyph.getSubXFixed(),
+ glyph.getSubYFixed()),
+ SkFixedFloorToFixed(fx),
+ SkFixedFloorToFixed(fy),
procs->fFontScaler);
}
@@ -1251,7 +1679,7 @@ void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
const SkPaint& paint) {
CHECK_SHOULD_DRAW(draw);
- if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
+ if (draw.fMatrix->hasPerspective()) {
// this guy will just call our drawPath()
draw.drawText((const char*)text, byteLength, x, y, paint);
} else {
@@ -1279,7 +1707,7 @@ void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
const SkPaint& paint) {
CHECK_SHOULD_DRAW(draw);
- if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
+ if (draw.fMatrix->hasPerspective()) {
// this guy will just call our drawPath()
draw.drawPosText((const char*)text, byteLength, pos, constY,
scalarsPerPos, paint);
@@ -1337,17 +1765,19 @@ bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
return false;
}
+void SkGpuDevice::flush() {
+ fContext->flush(false);
+}
+
///////////////////////////////////////////////////////////////////////////////
-SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
- const GrSamplerState& sampler,
- GrTexture** texture,
- bool forDeviceRenderTarget) {
- GrTexture* newTexture = NULL;
- GrTextureEntry* entry = NULL;
+SkGpuDevice::TexCache SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
+ const GrSamplerState* sampler,
+ TexType type) {
+ GrContext::TextureCacheEntry entry;
GrContext* ctx = this->context();
- if (forDeviceRenderTarget) {
+ if (kBitmap_TexType != type) {
const GrTextureDesc desc = {
kRenderTarget_GrTextureFlagBit,
kNone_GrAALevel,
@@ -1355,86 +1785,59 @@ SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
bitmap.height(),
SkGr::Bitmap2PixelConfig(bitmap)
};
- entry = ctx->lockKeylessTexture(desc);
+ GrContext::ScratchTexMatch match;
+ if (kSaveLayerDeviceRenderTarget_TexType == type) {
+ // we know layers will only be drawn through drawDevice.
+ // drawDevice has been made to work with content embedded in a
+ // larger texture so its okay to use the approximate version.
+ match = GrContext::kApprox_ScratchTexMatch;
+ } else {
+ SkASSERT(kDeviceRenderTarget_TexType == type);
+ match = GrContext::kExact_ScratchTexMatch;
+ }
+ entry = ctx->lockScratchTexture(desc, match);
} else {
- uint32_t p0, p1;
- p0 = bitmap.getGenerationID();
- p1 = bitmap.pixelRefOffset();
-
- GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
- entry = ctx->findAndLockTexture(&key, sampler);
-
- if (NULL == entry) {
- entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
- if (NULL == entry) {
- GrPrintf("---- failed to create texture for cache [%d %d]\n",
- bitmap.width(), bitmap.height());
+ if (!bitmap.isVolatile()) {
+ GrContext::TextureKey key = bitmap.getGenerationID();
+ key |= ((uint64_t) bitmap.pixelRefOffset()) << 32;
+
+ entry = ctx->findAndLockTexture(key, bitmap.width(),
+ bitmap.height(), sampler);
+ if (NULL == entry.texture()) {
+ entry = sk_gr_create_bitmap_texture(ctx, key, sampler,
+ bitmap);
}
+ } else {
+ entry = sk_gr_create_bitmap_texture(ctx, gUNCACHED_KEY,
+ sampler, bitmap);
}
- }
-
- if (NULL != entry) {
- newTexture = entry->texture();
- if (texture) {
- *texture = newTexture;
+ if (NULL == entry.texture()) {
+ GrPrintf("---- failed to create texture for cache [%d %d]\n",
+ bitmap.width(), bitmap.height());
}
}
- return (TexCache*)entry;
+ return entry;
}
-void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
- this->context()->unlockTexture((GrTextureEntry*)cache);
+void SkGpuDevice::unlockCachedTexture(TexCache cache) {
+ this->context()->unlockTexture(cache);
}
-///////////////////////////////////////////////////////////////////////////////
-
-SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
- GrRenderTarget* rootRenderTarget) {
- GrAssert(NULL != context);
- GrAssert(NULL != rootRenderTarget);
-
- // check this now rather than passing this value to SkGpuDevice cons.
- // we want the rt that is bound *now* in the 3D API, not the one
- // at the time of newDevice.
- if (SkGpuDevice::Current3DApiRenderTarget() == rootRenderTarget) {
- fRootRenderTarget = context->createRenderTargetFrom3DApiState();
- } else {
- fRootRenderTarget = rootRenderTarget;
- rootRenderTarget->ref();
- }
-
- fContext = context;
- context->ref();
+bool SkGpuDevice::isBitmapInTextureCache(const SkBitmap& bitmap,
+ const GrSamplerState& sampler) const {
+ GrContext::TextureKey key = bitmap.getGenerationID();
+ key |= ((uint64_t) bitmap.pixelRefOffset()) << 32;
+ return this->context()->isTextureInCache(key, bitmap.width(),
+ bitmap.height(), &sampler);
- fRootTexture = NULL;
}
-SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
- GrAssert(NULL != context);
- GrAssert(NULL != rootRenderTargetTexture);
- GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
- fRootTexture = rootRenderTargetTexture;
- rootRenderTargetTexture->ref();
-
- fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
- fRootRenderTarget->ref();
-
- fContext = context;
- context->ref();
+SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config,
+ int width, int height,
+ bool isOpaque,
+ Usage usage) {
+ return SkNEW_ARGS(SkGpuDevice,(this->context(), config,
+ width, height, usage));
}
-SkGpuDeviceFactory::~SkGpuDeviceFactory() {
- fContext->unref();
- fRootRenderTarget->unref();
- GrSafeUnref(fRootTexture);
-}
-
-SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
- int width, int height,
- bool isOpaque, bool isLayer) {
- SkBitmap bm;
- bm.setConfig(config, width, height);
- bm.setIsOpaque(isOpaque);
- return new SkGpuDevice(fContext, bm, isLayer ? NULL : fRootRenderTarget);
-}
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 600c336..cab9d46 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkGr.h"
/* Fill out buffer with the compressed format Ganesh expects from a colortable
@@ -33,7 +26,7 @@ static void build_compressed_data(void* buffer, const SkBitmap& bitmap) {
SkAutoLockPixels apl(bitmap);
if (!bitmap.readyToDraw()) {
- SkASSERT(!"bitmap not ready to draw!");
+ SkDEBUGFAIL("bitmap not ready to draw!");
return;
}
@@ -63,13 +56,15 @@ static void build_compressed_data(void* buffer, const SkBitmap& bitmap) {
////////////////////////////////////////////////////////////////////////////////
-GrTextureEntry* sk_gr_create_bitmap_texture(GrContext* ctx,
- GrTextureKey* key,
- const GrSamplerState& sampler,
- const SkBitmap& origBitmap) {
+GrContext::TextureCacheEntry sk_gr_create_bitmap_texture(GrContext* ctx,
+ GrContext::TextureKey key,
+ const GrSamplerState* sampler,
+ const SkBitmap& origBitmap) {
SkAutoLockPixels alp(origBitmap);
+ GrContext::TextureCacheEntry entry;
+
if (!origBitmap.readyToDraw()) {
- return NULL;
+ return entry;
}
SkBitmap tmpBitmap;
@@ -97,8 +92,18 @@ GrTextureEntry* sk_gr_create_bitmap_texture(GrContext* ctx,
// our compressed data will be trimmed, so pass width() for its
// "rowBytes", since they are the same now.
- return ctx->createAndLockTexture(key, sampler, desc, storage.get(),
- bitmap->width());
+
+ if (gUNCACHED_KEY != key) {
+ return ctx->createAndLockTexture(key, sampler, desc, storage.get(),
+ bitmap->width());
+ } else {
+ entry = ctx->lockScratchTexture(desc,
+ GrContext::kExact_ScratchTexMatch);
+ entry.texture()->writePixels(0, 0, bitmap->width(),
+ bitmap->height(), desc.fConfig,
+ storage.get(), 0);
+ return entry;
+ }
} else {
origBitmap.copyTo(&tmpBitmap, SkBitmap::kARGB_8888_Config);
@@ -107,9 +112,21 @@ GrTextureEntry* sk_gr_create_bitmap_texture(GrContext* ctx,
}
}
- desc.fFormat = SkGr::Bitmap2PixelConfig(*bitmap);
- return ctx->createAndLockTexture(key, sampler, desc, bitmap->getPixels(),
+ desc.fConfig = SkGr::Bitmap2PixelConfig(*bitmap);
+ if (gUNCACHED_KEY != key) {
+ return ctx->createAndLockTexture(key, sampler, desc,
+ bitmap->getPixels(),
+ bitmap->rowBytes());
+ } else {
+ entry = ctx->lockScratchTexture(desc,
+ GrContext::kExact_ScratchTexMatch);
+ entry.texture()->writePixels(0, 0,
+ bitmap->width(), bitmap->height(),
+ desc.fConfig,
+ bitmap->getPixels(),
bitmap->rowBytes());
+ return entry;
+ }
}
///////////////////////////////////////////////////////////////////////////////
@@ -194,11 +211,7 @@ GrPixelConfig SkGr::BitmapConfig2PixelConfig(SkBitmap::Config config,
case SkBitmap::kARGB_4444_Config:
return kRGBA_4444_GrPixelConfig;
case SkBitmap::kARGB_8888_Config:
- if (isOpaque) {
- return kRGBX_8888_GrPixelConfig;
- } else {
- return kRGBA_8888_GrPixelConfig;
- }
+ return kSkia8888_PM_GrPixelConfig;
default:
return kUnknown_GrPixelConfig;
}
diff --git a/src/gpu/SkGrFontScaler.cpp b/src/gpu/SkGrFontScaler.cpp
index eb260fb..95c29ff 100644
--- a/src/gpu/SkGrFontScaler.cpp
+++ b/src/gpu/SkGrFontScaler.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkGr.h"
#include "SkDescriptor.h"
#include "SkGlyphCache.h"
@@ -92,6 +85,8 @@ GrMaskFormat SkGrFontScaler::getMaskFormat() {
return kA8_GrMaskFormat;
case SkMask::kLCD16_Format:
return kA565_GrMaskFormat;
+ case SkMask::kLCD32_Format:
+ return kA888_GrMaskFormat;
default:
GrAssert(!"unsupported SkMask::Format");
return kA8_GrMaskFormat;
diff --git a/src/gpu/SkGrTexturePixelRef.cpp b/src/gpu/SkGrTexturePixelRef.cpp
index 8becfd4..045ddab 100644
--- a/src/gpu/SkGrTexturePixelRef.cpp
+++ b/src/gpu/SkGrTexturePixelRef.cpp
@@ -1,26 +1,82 @@
+
/*
- Copyright 2010 Google Inc.
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
+#include "SkGrTexturePixelRef.h"
+#include "GrContext.h"
+#include "GrTexture.h"
+#include "SkGr.h"
+#include "SkRect.h"
+// since we call lockPixels recursively on fBitmap, we need a distinct mutex,
+// to avoid deadlock with the default one provided by SkPixelRef.
+static SkMutex gROLockPixelsPixelRefMutex;
-#include "SkGrTexturePixelRef.h"
+SkROLockPixelsPixelRef::SkROLockPixelsPixelRef() : INHERITED(&gROLockPixelsPixelRefMutex) {
+}
-#include "GrTexture.h"
+SkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() {
+}
-#include "SkRect.h"
-#include "SkBitmap.h"
+void* SkROLockPixelsPixelRef::onLockPixels(SkColorTable** ctable) {
+ if (ctable) {
+ *ctable = NULL;
+ }
+ fBitmap.reset();
+// SkDebugf("---------- calling readpixels in support of lockpixels\n");
+ if (!this->onReadPixels(&fBitmap, NULL)) {
+ SkDebugf("SkROLockPixelsPixelRef::onLockPixels failed!\n");
+ return NULL;
+ }
+ fBitmap.lockPixels();
+ return fBitmap.getPixels();
+}
+
+void SkROLockPixelsPixelRef::onUnlockPixels() {
+ fBitmap.unlockPixels();
+}
+
+bool SkROLockPixelsPixelRef::onLockPixelsAreWritable() const {
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkGrTexturePixelRef* copyToTexturePixelRef(GrTexture* texture,
+ SkBitmap::Config dstConfig) {
+ if (NULL == texture) {
+ return NULL;
+ }
+ GrContext* context = texture->getContext();
+ if (NULL == context) {
+ return NULL;
+ }
+ GrTextureDesc desc;
+
+ desc.fWidth = texture->width();
+ desc.fHeight = texture->height();
+ desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
+ desc.fConfig = SkGr::BitmapConfig2PixelConfig(dstConfig, false);
+ desc.fAALevel = kNone_GrAALevel;
+
+ GrTexture* dst = context->createUncachedTexture(desc, NULL, 0);
+ if (NULL == dst) {
+ return NULL;
+ }
+
+ context->copyTexture(texture, dst->asRenderTarget());
+ SkGrTexturePixelRef* pixelRef = new SkGrTexturePixelRef(dst);
+ GrSafeUnref(dst);
+ return pixelRef;
+}
+
+///////////////////////////////////////////////////////////////////////////////
SkGrTexturePixelRef::SkGrTexturePixelRef(GrTexture* tex) {
fTexture = tex;
@@ -31,6 +87,14 @@ SkGrTexturePixelRef::~SkGrTexturePixelRef() {
GrSafeUnref(fTexture);
}
+SkGpuTexture* SkGrTexturePixelRef::getTexture() {
+ return (SkGpuTexture*)fTexture;
+}
+
+SkPixelRef* SkGrTexturePixelRef::deepCopy(SkBitmap::Config dstConfig) {
+ return copyToTexturePixelRef(fTexture, dstConfig);
+}
+
bool SkGrTexturePixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
if (NULL != fTexture && fTexture->isValid()) {
int left, top, width, height;
@@ -50,14 +114,14 @@ bool SkGrTexturePixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
SkAutoLockPixels al(*dst);
void* buffer = dst->getPixels();
return fTexture->readPixels(left, top, width, height,
- kRGBA_8888_GrPixelConfig,
- buffer);
+ kSkia8888_PM_GrPixelConfig,
+ buffer, dst->rowBytes());
} else {
return false;
}
}
-////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
SkGrRenderTargetPixelRef::SkGrRenderTargetPixelRef(GrRenderTarget* rt) {
fRenderTarget = rt;
@@ -75,6 +139,19 @@ SkGpuTexture* SkGrRenderTargetPixelRef::getTexture() {
return NULL;
}
+SkPixelRef* SkGrRenderTargetPixelRef::deepCopy(SkBitmap::Config dstConfig) {
+ if (NULL == fRenderTarget) {
+ return NULL;
+ }
+ // Note that when copying an SkGrRenderTargetPixelRef, we actually
+ // return an SkGrTexturePixelRef instead. This is because
+ // SkGrRenderTargetPixelRef is usually created in conjunction with
+ // GrTexture owned elsewhere (e.g., SkGpuDevice), and cannot live
+ // independently of that texture. SkGrTexturePixelRef, on the other
+ // hand, owns its own GrTexture, and is thus self-contained.
+ return copyToTexturePixelRef(fRenderTarget->asTexture(), dstConfig);
+}
+
bool SkGrRenderTargetPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
if (NULL != fRenderTarget && fRenderTarget->isValid()) {
int left, top, width, height;
@@ -94,9 +171,10 @@ bool SkGrRenderTargetPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset
SkAutoLockPixels al(*dst);
void* buffer = dst->getPixels();
return fRenderTarget->readPixels(left, top, width, height,
- kRGBA_8888_GrPixelConfig,
- buffer);
+ kSkia8888_PM_GrPixelConfig,
+ buffer, dst->rowBytes());
} else {
return false;
}
}
+
diff --git a/src/gpu/SkNullGLContext.cpp b/src/gpu/SkNullGLContext.cpp
new file mode 100644
index 0000000..04e63d8
--- /dev/null
+++ b/src/gpu/SkNullGLContext.cpp
@@ -0,0 +1,13 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkNullGLContext.h"
+
+const GrGLInterface* SkNullGLContext::createGLContext() {
+ return GrGLCreateNullInterface();
+};
diff --git a/src/gpu/android/GrGLCreateNativeInterface_android.cpp b/src/gpu/android/GrGLCreateNativeInterface_android.cpp
new file mode 100644
index 0000000..5147627
--- /dev/null
+++ b/src/gpu/android/GrGLCreateNativeInterface_android.cpp
@@ -0,0 +1,127 @@
+// Modified from chromium/src/webkit/glue/gl_bindings_skia_cmd_buffer.cc
+
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "GrGLInterface.h"
+
+#ifndef GL_GLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES
+#endif
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+const GrGLInterface* GrGLCreateNativeInterface() {
+ static SkAutoTUnref<GrGLInterface> glInterface;
+ if (!glInterface.get()) {
+ GrGLInterface* interface = new GrGLInterface;
+ glInterface.reset(interface);
+ interface->fBindingsExported = kES2_GrGLBinding;
+ interface->fActiveTexture = glActiveTexture;
+ interface->fAttachShader = glAttachShader;
+ interface->fBindAttribLocation = glBindAttribLocation;
+ interface->fBindBuffer = glBindBuffer;
+ interface->fBindTexture = glBindTexture;
+ interface->fBlendColor = glBlendColor;
+ interface->fBlendFunc = glBlendFunc;
+ interface->fBufferData = glBufferData;
+ interface->fBufferSubData = glBufferSubData;
+ interface->fClear = glClear;
+ interface->fClearColor = glClearColor;
+ interface->fClearStencil = glClearStencil;
+ interface->fColorMask = glColorMask;
+ interface->fCompileShader = glCompileShader;
+ interface->fCompressedTexImage2D = glCompressedTexImage2D;
+ interface->fCreateProgram = glCreateProgram;
+ interface->fCreateShader = glCreateShader;
+ interface->fCullFace = glCullFace;
+ interface->fDeleteBuffers = glDeleteBuffers;
+ interface->fDeleteProgram = glDeleteProgram;
+ interface->fDeleteShader = glDeleteShader;
+ interface->fDeleteTextures = glDeleteTextures;
+ interface->fDepthMask = glDepthMask;
+ interface->fDisable = glDisable;
+ interface->fDisableVertexAttribArray = glDisableVertexAttribArray;
+ interface->fDrawArrays = glDrawArrays;
+ interface->fDrawElements = glDrawElements;
+ interface->fEnable = glEnable;
+ interface->fEnableVertexAttribArray = glEnableVertexAttribArray;
+ interface->fFinish = glFinish;
+ interface->fFlush = glFlush;
+ interface->fFrontFace = glFrontFace;
+ interface->fGenBuffers = glGenBuffers;
+ interface->fGenTextures = glGenTextures;
+ interface->fGetBufferParameteriv = glGetBufferParameteriv;
+ interface->fGetError = glGetError;
+ interface->fGetIntegerv = glGetIntegerv;
+ interface->fGetProgramInfoLog = glGetProgramInfoLog;
+ interface->fGetProgramiv = glGetProgramiv;
+ interface->fGetShaderInfoLog = glGetShaderInfoLog;
+ interface->fGetShaderiv = glGetShaderiv;
+ interface->fGetString = glGetString;
+ interface->fGetUniformLocation = glGetUniformLocation;
+ interface->fLineWidth = glLineWidth;
+ interface->fLinkProgram = glLinkProgram;
+ interface->fPixelStorei = glPixelStorei;
+ interface->fReadPixels = glReadPixels;
+ interface->fScissor = glScissor;
+ interface->fShaderSource = glShaderSource;
+ interface->fStencilFunc = glStencilFunc;
+ interface->fStencilFuncSeparate = glStencilFuncSeparate;
+ interface->fStencilMask = glStencilMask;
+ interface->fStencilMaskSeparate = glStencilMaskSeparate;
+ interface->fStencilOp = glStencilOp;
+ interface->fStencilOpSeparate = glStencilOpSeparate;
+ interface->fTexImage2D = glTexImage2D;
+ interface->fTexParameteri = glTexParameteri;
+ interface->fTexSubImage2D = glTexSubImage2D;
+#if GL_ARB_texture_storage
+ interface->fTexStorage2D = glTexStorage2D;
+#elif GL_EXT_texture_storage
+ interface->fTexStorage2D = glTexStorage2DEXT;
+#endif
+ interface->fUniform1f = glUniform1f;
+ interface->fUniform1i = glUniform1i;
+ interface->fUniform1fv = glUniform1fv;
+ interface->fUniform1iv = glUniform1iv;
+ interface->fUniform2f = glUniform2f;
+ interface->fUniform2i = glUniform2i;
+ interface->fUniform2fv = glUniform2fv;
+ interface->fUniform2iv = glUniform2iv;
+ interface->fUniform3f = glUniform3f;
+ interface->fUniform3i = glUniform3i;
+ interface->fUniform3fv = glUniform3fv;
+ interface->fUniform3iv = glUniform3iv;
+ interface->fUniform4f = glUniform4f;
+ interface->fUniform4i = glUniform4i;
+ interface->fUniform4fv = glUniform4fv;
+ interface->fUniform4iv = glUniform4iv;
+ interface->fUniformMatrix2fv = glUniformMatrix2fv;
+ interface->fUniformMatrix3fv = glUniformMatrix3fv;
+ interface->fUniformMatrix4fv = glUniformMatrix4fv;
+ interface->fUseProgram = glUseProgram;
+ interface->fVertexAttrib4fv = glVertexAttrib4fv;
+ interface->fVertexAttribPointer = glVertexAttribPointer;
+ interface->fViewport = glViewport;
+ interface->fBindFramebuffer = glBindFramebuffer;
+ interface->fBindRenderbuffer = glBindRenderbuffer;
+ interface->fCheckFramebufferStatus = glCheckFramebufferStatus;
+ interface->fDeleteFramebuffers = glDeleteFramebuffers;
+ interface->fDeleteRenderbuffers = glDeleteRenderbuffers;
+ interface->fFramebufferRenderbuffer = glFramebufferRenderbuffer;
+ interface->fFramebufferTexture2D = glFramebufferTexture2D;
+ interface->fGenFramebuffers = glGenFramebuffers;
+ interface->fGenRenderbuffers = glGenRenderbuffers;
+ interface->fGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameteriv;
+ interface->fGetRenderbufferParameteriv = glGetRenderbufferParameteriv;
+ interface->fRenderbufferStorage = glRenderbufferStorage;
+ #if GL_OES_mapbuffer
+ interface->fMapBuffer = glMapBufferOES;
+ interface->fUnmapBuffer = glUnmapBufferOES;
+ #endif
+ }
+ glInterface.get()->ref();
+ return glInterface.get();
+}
diff --git a/src/gpu/android/SkNativeGLContext_android.cpp b/src/gpu/android/SkNativeGLContext_android.cpp
new file mode 100644
index 0000000..eb58c27
--- /dev/null
+++ b/src/gpu/android/SkNativeGLContext_android.cpp
@@ -0,0 +1,104 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkNativeGLContext.h"
+
+SkNativeGLContext::AutoContextRestore::AutoContextRestore() {
+ fOldEGLContext = eglGetCurrentContext();
+ fOldDisplay = eglGetCurrentDisplay();
+ fOldSurface = eglGetCurrentSurface(EGL_DRAW);
+
+}
+
+SkNativeGLContext::AutoContextRestore::~AutoContextRestore() {
+ if (NULL != fOldDisplay) {
+ eglMakeCurrent(fOldDisplay, fOldSurface, fOldSurface, fOldEGLContext);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkNativeGLContext::SkNativeGLContext()
+ : fContext(EGL_NO_CONTEXT)
+ , fDisplay(EGL_NO_DISPLAY)
+ , fSurface(EGL_NO_SURFACE) {
+}
+
+SkNativeGLContext::~SkNativeGLContext() {
+ this->destroyGLContext();
+}
+
+void SkNativeGLContext::destroyGLContext() {
+ if (fDisplay) {
+ eglMakeCurrent(fDisplay, 0, 0, 0);
+
+ if (fContext) {
+ eglDestroyContext(fDisplay, fContext);
+ fContext = EGL_NO_CONTEXT;
+ }
+
+ if (fSurface) {
+ eglDestroySurface(fDisplay, fSurface);
+ fSurface = EGL_NO_SURFACE;
+ }
+
+ //TODO should we close the display?
+ fDisplay = EGL_NO_DISPLAY;
+ }
+}
+
+const GrGLInterface* SkNativeGLContext::createGLContext() {
+ fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+ EGLint majorVersion;
+ EGLint minorVersion;
+ eglInitialize(fDisplay, &majorVersion, &minorVersion);
+
+ EGLint numConfigs;
+ static const EGLint configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_NONE
+ };
+
+ EGLConfig surfaceConfig;
+ eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs);
+
+ static const EGLint contextAttribs[] = {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+ fContext = eglCreateContext(fDisplay, surfaceConfig, NULL, contextAttribs);
+
+
+ static const EGLint surfaceAttribs[] = {
+ EGL_WIDTH, 1,
+ EGL_HEIGHT, 1,
+ EGL_NONE
+ };
+ fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, surfaceAttribs);
+
+ eglMakeCurrent(fDisplay, fSurface, fSurface, fContext);
+
+ const GrGLInterface* interface = GrGLCreateNativeInterface();
+ if (!interface) {
+ SkDebugf("Failed to create gl interface");
+ this->destroyGLContext();
+ return NULL;
+ }
+ return interface;
+}
+
+void SkNativeGLContext::makeCurrent() const {
+ if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
+ SkDebugf("Could not set the context.\n");
+ }
+}
diff --git a/gpu/src/app-android.cpp b/src/gpu/app-android.cpp
index e07aa1d..ae8b7dd 100644
--- a/gpu/src/app-android.cpp
+++ b/src/gpu/app-android.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include <jni.h>
#include <sys/time.h>
#include <time.h>
@@ -15,7 +22,6 @@
static GrContext* make_context() {
SkDebugf("---- before create\n");
GrContext* ctx = GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, 0);
-// GrContext* ctx = GrContext::Create(GrGpu::kOpenGL_Fixed_Engine, 0);
SkDebugf("---- after create %p\n", ctx);
return ctx;
}
@@ -25,7 +31,7 @@ static GrContext* make_context() {
void gr_run_unittests() {}
#include "FlingState.h"
-#include "GrTouchGesture.h"
+#include "SkTouchGesture.h"
#include "SkView.h"
typedef SkView* (*SkViewFactory)();
@@ -64,7 +70,7 @@ private:
SkView* fView;
SkIPoint fViewport;
- GrTouchGesture fGesture;
+ SkTouchGesture fGesture;
SkTDArray<SkViewFactory> fFactory;
diff --git a/gpu/src/gr_hello_world.cpp b/src/gpu/gr_hello_world.cpp
index 5638e19..b475fb8 100644
--- a/gpu/src/gr_hello_world.cpp
+++ b/src/gpu/gr_hello_world.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkGLCanvas.h"
#include "SkBitmap.h"
#include "SkPaint.h"
diff --git a/gpu/src/gr_unittests.cpp b/src/gpu/gr_unittests.cpp
index 338f2cc..6e51e19 100644
--- a/gpu/src/gr_unittests.cpp
+++ b/src/gpu/gr_unittests.cpp
@@ -1,27 +1,30 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
+#include "GrBinHashKey.h"
#include "GrDrawTarget.h"
-#include "GrTDArray.h"
-#include "GrTBSearch.h"
#include "GrMatrix.h"
-#include "GrRedBlackTree.h"
#include "GrPath.h"
-#include "GrBinHashKey.h"
+#include "GrRedBlackTree.h"
+#include "GrTDArray.h"
+
+// If we aren't inheriting these as #defines from elsewhere,
+// clang demands they be declared before we #include the template
+// that relies on them.
+static bool LT(const int& elem, int value) {
+ return elem < value;
+}
+static bool EQ(const int& elem, int value) {
+ return elem == value;
+}
+#include "GrTBSearch.h"
static void dump(const GrTDArray<int>& array) {
#if 0
@@ -53,12 +56,6 @@ static void test_tdarray() {
GrAssert(array.count() == 4);
}
-static bool LT(const int& elem, int value) {
- return elem < value;
-}
-static bool EQ(const int& elem, int value) {
- return elem == value;
-}
static void test_bsearch() {
const int array[] = {
@@ -80,72 +77,29 @@ class BogusEntry {};
static void test_binHashKey()
{
- const char* testStringA = "abcdABCD";
- const char* testStringB = "abcdBBCD";
+ const char* testStringA_ = "abcdABCD";
+ const char* testStringB_ = "abcdBBCD";
+ const uint32_t* testStringA = reinterpret_cast<const uint32_t*>(testStringA_);
+ const uint32_t* testStringB = reinterpret_cast<const uint32_t*>(testStringB_);
enum {
kDataLenUsedForKey = 8
};
- typedef GrBinHashKey<BogusEntry, kDataLenUsedForKey> KeyType;
-
- KeyType keyA;
- int passCnt = 0;
- while (keyA.doPass()) {
- ++passCnt;
- keyA.keyData(reinterpret_cast<const uint32_t*>(testStringA), kDataLenUsedForKey);
- }
- GrAssert(passCnt == 1); //We expect the static allocation to suffice
- GrBinHashKey<BogusEntry, kDataLenUsedForKey-1> keyBust;
- passCnt = 0;
- while (keyBust.doPass()) {
- ++passCnt;
- // Exceed static storage by 1
- keyBust.keyData(reinterpret_cast<const uint32_t*>(testStringA), kDataLenUsedForKey);
- }
- GrAssert(passCnt == 2); //We expect dynamic allocation to be necessary
- GrAssert(keyA.getHash() == keyBust.getHash());
-
- // Test that adding keyData in chunks gives
- // the same hash as with one chunk
- KeyType keyA2;
- while (keyA2.doPass()) {
- keyA2.keyData(reinterpret_cast<const uint32_t*>(testStringA), 4);
- keyA2.keyData(&reinterpret_cast<const uint32_t*>(testStringA)[4], kDataLenUsedForKey-4);
- }
- GrAssert(keyA.getHash() == keyA2.getHash());
-
- KeyType keyB;
- while (keyB.doPass()){
- keyB.keyData(reinterpret_cast<const uint32_t*>(testStringB), kDataLenUsedForKey);
- }
- GrAssert(keyA.compare(keyB) < 0);
+ GrBinHashKey<BogusEntry, kDataLenUsedForKey> keyA;
+ keyA.setKeyData(testStringA);
+ // test copy constructor and comparison
+ GrBinHashKey<BogusEntry, kDataLenUsedForKey> keyA2(keyA);
GrAssert(keyA.compare(keyA2) == 0);
-
- //Test ownership tranfer and copying
- keyB.copyAndTakeOwnership(keyA);
- GrAssert(keyA.fIsValid == false);
- GrAssert(keyB.fIsValid);
- GrAssert(keyB.getHash() == keyA2.getHash());
- GrAssert(keyB.compare(keyA2) == 0);
- keyA.deepCopyFrom(keyB);
- GrAssert(keyA.fIsValid);
- GrAssert(keyB.fIsValid);
GrAssert(keyA.getHash() == keyA2.getHash());
+ // test re-init
+ keyA2.setKeyData(testStringA);
GrAssert(keyA.compare(keyA2) == 0);
-
- //Test ownership tranfer and copying with key on heap
- GrBinHashKey<BogusEntry, kDataLenUsedForKey-1> keyBust2;
- keyBust2.deepCopyFrom(keyBust);
- GrAssert(keyBust.fIsValid);
- GrAssert(keyBust2.fIsValid);
- GrAssert(keyBust.getHash() == keyBust2.getHash());
- GrAssert(keyBust.compare(keyBust2) == 0);
- GrBinHashKey<BogusEntry, kDataLenUsedForKey-1> keyBust3;
- keyBust3.deepCopyFrom(keyBust);
- GrAssert(keyBust.fIsValid == false);
- GrAssert(keyBust3.fIsValid);
- GrAssert(keyBust3.getHash() == keyBust2.getHash());
- GrAssert(keyBust3.compare(keyBust2) == 0);
+ GrAssert(keyA.getHash() == keyA2.getHash());
+ // test sorting
+ GrBinHashKey<BogusEntry, kDataLenUsedForKey> keyB;
+ keyB.setKeyData(testStringB);
+ GrAssert(keyA.compare(keyB) < 0);
+ GrAssert(keyA.getHash() != keyB.getHash());
}
static void test_convex() {
diff --git a/src/gpu/ios/GrGLDefaultInterface_iOS.cpp b/src/gpu/ios/GrGLDefaultInterface_iOS.cpp
new file mode 100644
index 0000000..189fb25
--- /dev/null
+++ b/src/gpu/ios/GrGLDefaultInterface_iOS.cpp
@@ -0,0 +1,140 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrGLInterface.h"
+
+#import <OpenGLES/ES2/gl.h>
+#import <OpenGLES/ES2/glext.h>
+
+const GrGLInterface* GrGLDefaultInterface() {
+ static SkAutoTUnref<GrGLInterface> glInterface;
+ if (!glInterface.get()) {
+ GrGLInteface* interface = new GrGLInterface;
+ glInterface.reset(interface);
+
+ interface->fActiveTexture = glActiveTexture;
+ interface->fAttachShader = glAttachShader;
+ interface->fBindAttribLocation = glBindAttribLocation;
+ interface->fBindBuffer = glBindBuffer;
+ interface->fBindTexture = glBindTexture;
+ interface->fBlendColor = glBlendColor;
+ interface->fBlendFunc = glBlendFunc;
+ interface->fBufferData = (GrGLBufferDataProc)glBufferData;
+ interface->fBufferSubData = (GrGLBufferSubDataProc)glBufferSubData;
+ interface->fClear = glClear;
+ interface->fClearColor = glClearColor;
+ interface->fClearStencil = glClearStencil;
+ interface->fColorMask = glColorMask;
+ interface->fColorPointer = glColorPointer;
+ interface->fCompileShader = glCompileShader;
+ interface->fCompressedTexImage2D = glCompressedTexImage2D;
+ interface->fCreateProgram = glCreateProgram;
+ interface->fCreateShader = glCreateShader;
+ interface->fCullFace = glCullFace;
+ interface->fDeleteBuffers = glDeleteBuffers;
+ interface->fDeleteProgram = glDeleteProgram;
+ interface->fDeleteShader = glDeleteShader;
+ interface->fDeleteTextures = glDeleteTextures;
+ interface->fDepthMask = glDepthMask;
+ interface->fDisable = glDisable;
+ interface->fDisableVertexAttribArray = glDisableVertexAttribArray;
+ interface->fDrawArrays = glDrawArrays;
+ interface->fDrawBuffer = NULL;
+ interface->fDrawBuffers = NULL;
+ interface->fDrawElements = glDrawElements;
+ interface->fEnable = glEnable;
+ interface->fEnableVertexAttribArray = glEnableVertexAttribArray;
+ interface->fFrontFace = glFrontFace;
+ interface->fGenBuffers = glGenBuffers;
+ interface->fGetBufferParameteriv = glGetBufferParameteriv;
+ interface->fGetError = glGetError;
+ interface->fGetIntegerv = glGetIntegerv;
+ interface->fGetProgramInfoLog = glGetProgramInfoLog;
+ interface->fGetProgramiv = glGetProgramiv;
+ interface->fGetShaderInfoLog = glGetShaderInfoLog;
+ interface->fGetShaderiv = glGetShaderiv;
+ interface->fGetString = glGetString;
+ interface->fGenTextures = glGenTextures;
+ interface->fGetUniformLocation = glGetUniformLocation;
+ interface->fLineWidth = glLineWidth;
+ interface->fLinkProgram = glLinkProgram;
+ interface->fPixelStorei = glPixelStorei;
+ interface->fReadBuffer = NULL;
+ interface->fReadPixels = glReadPixels;
+ interface->fScissor = glScissor;
+ interface->fShaderSource = glShaderSource;
+ interface->fStencilFunc = glStencilFunc;
+ interface->fStencilFuncSeparate = glStencilFuncSeparate;
+ interface->fStencilMask = glStencilMask;
+ interface->fStencilMaskSeparate = glStencilMaskSeparate;
+ interface->fStencilOp = glStencilOp;
+ interface->fStencilOpSeparate = glStencilOpSeparate;
+ // mac uses GLenum for internalFormat param (non-standard)
+ // amounts to int vs. uint.
+ interface->fTexImage2D = (GrGLTexImage2DProc)glTexImage2D;
+ #if GL_ARB_texture_storage
+ interface->fTexStorage2D = glTexStorage2D;
+ #elif GL_EXT_texture_storage
+ interface->fTexStorage2D = glTexStorage2DEXT;
+ #endif
+ interface->fTexParameteri = glTexParameteri;
+ interface->fTexSubImage2D = glTexSubImage2D;
+ interface->fUniform1f = glUniform1f;
+ interface->fUniform1i = glUniform1i;
+ interface->fUniform1fv = glUniform1fv;
+ interface->fUniform1iv = glUniform1iv;
+ interface->fUniform2f = glUniform2f;
+ interface->fUniform2i = glUniform2i;
+ interface->fUniform2fv = glUniform2fv;
+ interface->fUniform2iv = glUniform2iv;
+ interface->fUniform3f = glUniform3f;
+ interface->fUniform3i = glUniform3i;
+ interface->fUniform3fv = glUniform3fv;
+ interface->fUniform3iv = glUniform3iv;
+ interface->fUniform4f = glUniform4f;
+ interface->fUniform4i = glUniform4i;
+ interface->fUniform4fv = glUniform4fv;
+ interface->fUniform4iv = glUniform4iv;
+ interface->fUniform4fv = glUniform4fv;
+ interface->fUniformMatrix2fv = glUniformMatrix2fv;
+ interface->fUniformMatrix3fv = glUniformMatrix3fv;
+ interface->fUniformMatrix4fv = glUniformMatrix4fv;
+ interface->fUseProgram = glUseProgram;
+ interface->fVertexAttrib4fv = glVertexAttrib4fv;
+ interface->fVertexAttribPointer = glVertexAttribPointer;
+ interface->fViewport = glViewport;
+ interface->fGenFramebuffers = glGenFramebuffers;
+ interface->fGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameteriv;
+ interface->fGetRenderbufferParameteriv = glGetRenderbufferParameteriv;
+ interface->fBindFramebuffer = glBindFramebuffer;
+ interface->fFramebufferTexture2D = glFramebufferTexture2D;
+ interface->fCheckFramebufferStatus = glCheckFramebufferStatus;
+ interface->fDeleteFramebuffers = glDeleteFramebuffers;
+ interface->fRenderbufferStorage = glRenderbufferStorage;
+ interface->fGenRenderbuffers = glGenRenderbuffers;
+ interface->fDeleteRenderbuffers = glDeleteRenderbuffers;
+ interface->fFramebufferRenderbuffer = glFramebufferRenderbuffer;
+ interface->fBindRenderbuffer = glBindRenderbuffer;
+
+ #if GL_OES_mapbuffer
+ interface->fMapBuffer = glMapBufferOES;
+ interface->fUnmapBuffer = glUnmapBufferOES;
+ #endif
+
+ #if GL_APPLE_framebuffer_multisample
+ interface->fRenderbufferStorageMultisample = glRenderbufferStorageMultisampleAPPLE;
+ interface->fResolveMultisampleFramebuffer = glResolveMultisampleFramebufferAPPLE;
+ #endif
+ interface->fBindFragDataLocationIndexed = NULL;
+
+ interface->fBindingsExported = kES2_GrGLBinding;
+ }
+ glInterface.get()->ref();
+ return glInterface.get();
+}
diff --git a/src/gpu/mac/GrGLCreateNativeInterface_mac.cpp b/src/gpu/mac/GrGLCreateNativeInterface_mac.cpp
new file mode 100644
index 0000000..51a4111
--- /dev/null
+++ b/src/gpu/mac/GrGLCreateNativeInterface_mac.cpp
@@ -0,0 +1,273 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrGLInterface.h"
+
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+
+#include <mach-o/dyld.h>
+
+
+// This uses deprecated functions, should rewrite using dlopen, dlsym, dlclose
+void* GetProcAddress(const char* name) {
+ NSSymbol symbol = NULL;
+ if (NSIsSymbolNameDefined(name)) {
+ symbol = NSLookupAndBindSymbol(name);
+ }
+ return NULL == symbol ? NULL : NSAddressOfSymbol(symbol);
+}
+
+#define GET_PROC(name) ((GrGL ## name ## Proc) GetProcAddress("_gl" #name))
+#define GET_PROC_SUFFIX(name, suffix) ((GrGL ## name ## Proc) GetProcAddress("_gl" #name #suffix))
+
+const GrGLInterface* GrGLCreateNativeInterface() {
+ // The gl functions are not context-specific so we create one global
+ // interface
+ static SkAutoTUnref<GrGLInterface> glInterface;
+ if (!glInterface.get()) {
+ GrGLInterface* interface = new GrGLInterface;
+ glInterface.reset(interface);
+ const char* verStr = (const char*) glGetString(GL_VERSION);
+ GrGLVersion ver = GrGLGetVersionFromString(verStr);
+ const char* extStr = (const char*) glGetString(GL_EXTENSIONS);
+
+ interface->fBindingsExported = kDesktop_GrGLBinding;
+ interface->fActiveTexture = glActiveTexture;
+ interface->fAttachShader = glAttachShader;
+ interface->fBeginQuery = glBeginQuery;
+ interface->fBindAttribLocation = glBindAttribLocation;
+ interface->fBindBuffer = glBindBuffer;
+ if (ver >= GR_GL_VER(3,0)) {
+ #if GL_VERSION_3_0
+ interface->fBindFragDataLocation = glBindFragDataLocation;
+ #else
+ interface->fBindFragDataLocation = GET_PROC(BindFragDataLocation);
+ #endif
+ }
+ interface->fBindTexture = glBindTexture;
+ interface->fBlendColor = glBlendColor;
+ interface->fBlendFunc = glBlendFunc;
+ interface->fBufferData = glBufferData;
+ interface->fBufferSubData = glBufferSubData;
+ interface->fClear = glClear;
+ interface->fClearColor = glClearColor;
+ interface->fClearStencil = glClearStencil;
+ interface->fColorMask = glColorMask;
+ interface->fColorPointer = glColorPointer;
+ interface->fCompileShader = glCompileShader;
+ interface->fCompressedTexImage2D = glCompressedTexImage2D;
+ interface->fCreateProgram = glCreateProgram;
+ interface->fCreateShader = glCreateShader;
+ interface->fCullFace = glCullFace;
+ interface->fDeleteBuffers = glDeleteBuffers;
+ interface->fDeleteProgram = glDeleteProgram;
+ interface->fDeleteQueries = glDeleteQueries;
+ interface->fDeleteShader = glDeleteShader;
+ interface->fDeleteTextures = glDeleteTextures;
+ interface->fDepthMask = glDepthMask;
+ interface->fDisable = glDisable;
+ interface->fDisableVertexAttribArray =
+ glDisableVertexAttribArray;
+ interface->fDrawArrays = glDrawArrays;
+ interface->fDrawBuffer = glDrawBuffer;
+ interface->fDrawBuffers = glDrawBuffers;
+ interface->fDrawElements = glDrawElements;
+ interface->fEnable = glEnable;
+ interface->fEnableVertexAttribArray = glEnableVertexAttribArray;
+ interface->fEndQuery = glEndQuery;
+ interface->fFinish = glFinish;
+ interface->fFlush = glFlush;
+ interface->fFrontFace = glFrontFace;
+ interface->fGenBuffers = glGenBuffers;
+ interface->fGenQueries = glGenQueries;
+ interface->fGetBufferParameteriv = glGetBufferParameteriv;
+ interface->fGetError = glGetError;
+ interface->fGetIntegerv = glGetIntegerv;
+ interface->fGetProgramInfoLog = glGetProgramInfoLog;
+ interface->fGetProgramiv = glGetProgramiv;
+ interface->fGetQueryiv = glGetQueryiv;
+ interface->fGetQueryObjectiv = glGetQueryObjectiv;
+ interface->fGetQueryObjectuiv = glGetQueryObjectuiv;
+ interface->fGetShaderInfoLog = glGetShaderInfoLog;
+ interface->fGetShaderiv = glGetShaderiv;
+ interface->fGetString = glGetString;
+ interface->fGetTexLevelParameteriv = glGetTexLevelParameteriv;
+ interface->fGenTextures = glGenTextures;
+ interface->fGetUniformLocation = glGetUniformLocation;
+ interface->fLineWidth = glLineWidth;
+ interface->fLinkProgram = glLinkProgram;
+ interface->fMapBuffer = glMapBuffer;
+ interface->fPixelStorei = glPixelStorei;
+ interface->fReadBuffer = glReadBuffer;
+ interface->fReadPixels = glReadPixels;
+ interface->fScissor = glScissor;
+ interface->fShaderSource = glShaderSource;
+ interface->fStencilFunc = glStencilFunc;
+ interface->fStencilFuncSeparate = glStencilFuncSeparate;
+ interface->fStencilMask = glStencilMask;
+ interface->fStencilMaskSeparate = glStencilMaskSeparate;
+ interface->fStencilOp = glStencilOp;
+ interface->fStencilOpSeparate = glStencilOpSeparate;
+ // mac uses GLenum for internalFormat param (non-standard)
+ // amounts to int vs. uint.
+ interface->fTexImage2D = (GrGLTexImage2DProc)glTexImage2D;
+ interface->fTexParameteri = glTexParameteri;
+ #if GL_ARB_texture_storage || GL_VERSION_4_2
+ interface->fTexStorage2D = glTexStorage2D
+ #elif GL_EXT_texture_storage
+ interface->fTexStorage2D = glTexStorage2DEXT;
+ #else
+ if (ver >= GR_GL_VER(4,2) ||
+ GrGLHasExtensionFromString("GL_ARB_texture_storage", extStr)) {
+ GET_PROC(TexStorage2D);
+ } else if (GrGLHasExtensionFromString("GL_EXT_texture_storage", extStr)) {
+ GET_PROC_SUFFIX(TexStorage2D, EXT);
+ }
+ #endif
+ interface->fTexSubImage2D = glTexSubImage2D;
+ interface->fUniform1f = glUniform1f;
+ interface->fUniform1i = glUniform1i;
+ interface->fUniform1fv = glUniform1fv;
+ interface->fUniform1iv = glUniform1iv;
+ interface->fUniform2f = glUniform2f;
+ interface->fUniform2i = glUniform2i;
+ interface->fUniform2fv = glUniform2fv;
+ interface->fUniform2iv = glUniform2iv;
+ interface->fUniform3f = glUniform3f;
+ interface->fUniform3i = glUniform3i;
+ interface->fUniform3fv = glUniform3fv;
+ interface->fUniform3iv = glUniform3iv;
+ interface->fUniform4f = glUniform4f;
+ interface->fUniform4i = glUniform4i;
+ interface->fUniform4fv = glUniform4fv;
+ interface->fUniform4iv = glUniform4iv;
+ interface->fUniform4fv = glUniform4fv;
+ interface->fUniformMatrix2fv = glUniformMatrix2fv;
+ interface->fUniformMatrix3fv = glUniformMatrix3fv;
+ interface->fUniformMatrix4fv = glUniformMatrix4fv;
+ interface->fUnmapBuffer = glUnmapBuffer;
+ interface->fUseProgram = glUseProgram;
+ interface->fVertexAttrib4fv = glVertexAttrib4fv;
+ interface->fVertexAttribPointer = glVertexAttribPointer;
+ interface->fViewport = glViewport;
+
+ if (ver >= GR_GL_VER(3,3) || GrGLHasExtensionFromString("GL_ARB_timer_query", extStr)) {
+ // ARB extension doesn't use the ARB suffix on the function name
+ #if GL_ARB_timer_query || GL_VERSION_3_3
+ interface->fQueryCounter = glQueryCounter;
+ interface->fGetQueryObjecti64v = glGetQueryObjecti64v;
+ interface->fGetQueryObjectui64v = glGetQueryObjectui64v;
+ #else
+ interface->fQueryCounter = GET_PROC(QueryCounter);
+ interface->fGetQueryObjecti64v = GET_PROC(GetQueryObjecti64v);
+ interface->fGetQueryObjectui64v = GET_PROC(GetQueryObjectui64v);
+ #endif
+ } else if (GrGLHasExtensionFromString("GL_EXT_timer_query", extStr)) {
+ #if GL_EXT_timer_query
+ interface->fGetQueryObjecti64v = glGetQueryObjecti64vEXT;
+ interface->fGetQueryObjectui64v = glGetQueryObjectui64vEXT;
+ #else
+ interface->fGetQueryObjecti64v = GET_PROC_SUFFIX(GetQueryObjecti64v, EXT);
+ interface->fGetQueryObjectui64v = GET_PROC_SUFFIX(GetQueryObjectui64v, EXT);
+ #endif
+ }
+
+ if (ver >= GR_GL_VER(3,0) || GrGLHasExtensionFromString("GL_ARB_framebuffer_object", extStr)) {
+ // ARB extension doesn't use the ARB suffix on the function names
+ #if GL_VERSION_3_0 || GL_ARB_framebuffer_object
+ interface->fGenFramebuffers = glGenFramebuffers;
+ interface->fGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameteriv;
+ interface->fGetRenderbufferParameteriv = glGetRenderbufferParameteriv;
+ interface->fBindFramebuffer = glBindFramebuffer;
+ interface->fFramebufferTexture2D = glFramebufferTexture2D;
+ interface->fCheckFramebufferStatus = glCheckFramebufferStatus;
+ interface->fDeleteFramebuffers = glDeleteFramebuffers;
+ interface->fRenderbufferStorage = glRenderbufferStorage;
+ interface->fGenRenderbuffers = glGenRenderbuffers;
+ interface->fDeleteRenderbuffers = glDeleteRenderbuffers;
+ interface->fFramebufferRenderbuffer = glFramebufferRenderbuffer;
+ interface->fBindRenderbuffer = glBindRenderbuffer;
+ interface->fRenderbufferStorageMultisample = glRenderbufferStorageMultisample;
+ interface->fBlitFramebuffer = glBlitFramebuffer;
+ #else
+ interface->fGenFramebuffers = GET_PROC(GenFramebuffers);
+ interface->fGetFramebufferAttachmentParameteriv = GET_PROC(GetFramebufferAttachmentParameteriv);
+ interface->fGetRenderbufferParameteriv = GET_PROC(GetRenderbufferParameteriv);
+ interface->fBindFramebuffer = GET_PROC(BindFramebuffer);
+ interface->fFramebufferTexture2D = GET_PROC(FramebufferTexture2D);
+ interface->fCheckFramebufferStatus = GET_PROC(CheckFramebufferStatus);
+ interface->fDeleteFramebuffers = GET_PROC(DeleteFramebuffers);
+ interface->fRenderbufferStorage = GET_PROC(RenderbufferStorage);
+ interface->fGenRenderbuffers = GET_PROC(GenRenderbuffers);
+ interface->fDeleteRenderbuffers = GET_PROC(DeleteRenderbuffers);
+ interface->fFramebufferRenderbuffer = GET_PROC(FramebufferRenderbuffer);
+ interface->fBindRenderbuffer = GET_PROC(BindRenderbuffer);
+ interface->fRenderbufferStorageMultisample = GET_PROC(RenderbufferStorageMultisample);
+ interface->fBlitFramebuffer = GET_PROC(BlitFramebuffer);
+ #endif
+ } else {
+ if (GrGLHasExtensionFromString("GL_EXT_framebuffer_object", extStr)) {
+ #if GL_EXT_framebuffer_object
+ interface->fGenFramebuffers = glGenFramebuffersEXT;
+ interface->fGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameterivEXT;
+ interface->fGetRenderbufferParameteriv = glGetRenderbufferParameterivEXT;
+ interface->fBindFramebuffer = glBindFramebufferEXT;
+ interface->fFramebufferTexture2D = glFramebufferTexture2DEXT;
+ interface->fCheckFramebufferStatus = glCheckFramebufferStatusEXT;
+ interface->fDeleteFramebuffers = glDeleteFramebuffersEXT;
+ interface->fRenderbufferStorage = glRenderbufferStorageEXT;
+ interface->fGenRenderbuffers = glGenRenderbuffersEXT;
+ interface->fDeleteRenderbuffers = glDeleteRenderbuffersEXT;
+ interface->fFramebufferRenderbuffer = glFramebufferRenderbufferEXT;
+ interface->fBindRenderbuffer = glBindRenderbufferEXT;
+ #else
+ interface->fGenFramebuffers = GET_PROC_SUFFIX(GenFramebuffers, EXT);
+ interface->fGetFramebufferAttachmentParameteriv = GET_PROC_SUFFIX(GetFramebufferAttachmentParameteriv, EXT);
+ interface->fGetRenderbufferParameteriv = GET_PROC_SUFFIX(GetRenderbufferParameteriv, EXT);
+ interface->fBindFramebuffer = GET_PROC_SUFFIX(BindFramebuffer, EXT);
+ interface->fFramebufferTexture2D = GET_PROC_SUFFIX(FramebufferTexture2D, EXT);
+ interface->fCheckFramebufferStatus = GET_PROC_SUFFIX(CheckFramebufferStatus, EXT);
+ interface->fDeleteFramebuffers = GET_PROC_SUFFIX(DeleteFramebuffers, EXT);
+ interface->fRenderbufferStorage = GET_PROC_SUFFIX(RenderbufferStorage, EXT);
+ interface->fGenRenderbuffers = GET_PROC_SUFFIX(GenRenderbuffers, EXT);
+ interface->fDeleteRenderbuffers = GET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
+ interface->fFramebufferRenderbuffer = GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
+ interface->fBindRenderbuffer = GET_PROC_SUFFIX(BindRenderbuffer, EXT);
+ #endif
+ }
+ if (GrGLHasExtensionFromString("GL_EXT_framebuffer_multisample", extStr)) {
+ #if GL_EXT_framebuffer_multisample
+ interface->fRenderbufferStorageMultisample = glRenderbufferStorageMultisampleEXT;
+ #else
+ interface->fRenderbufferStorageMultisample = GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
+ #endif
+ }
+ if (GrGLHasExtensionFromString("", extStr)) {
+ #if GL_EXT_framebuffer_blit
+ interface->fBlitFramebuffer = glBlitFramebufferEXT;
+ #else
+ interface->fBlitFramebuffer = GET_PROC_SUFFIX(BlitFramebuffer, EXT);
+ #endif
+ }
+ }
+ if (ver >= GR_GL_VER(3,3) || GrGLHasExtensionFromString("GL_ARB_blend_func_extended", extStr)) {
+ // ARB extension doesn't use the ARB suffix on the function name
+ #if GL_VERSION_3_3 || GL_ARB_blend_func_extended
+ interface->fBindFragDataLocationIndexed = glBindFragDataLocationIndexed;
+ #else
+ interface->fBindFragDataLocationIndexed = GET_PROC(BindFragDataLocationIndexed);
+ #endif
+ }
+
+ interface->fBindingsExported = kDesktop_GrGLBinding;
+ }
+ glInterface.get()->ref();
+ return glInterface.get();
+}
diff --git a/src/gpu/mac/SkNativeGLContext_mac.cpp b/src/gpu/mac/SkNativeGLContext_mac.cpp
new file mode 100644
index 0000000..ad68c40
--- /dev/null
+++ b/src/gpu/mac/SkNativeGLContext_mac.cpp
@@ -0,0 +1,74 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkNativeGLContext.h"
+
+SkNativeGLContext::AutoContextRestore::AutoContextRestore() {
+ fOldAGLContext = aglGetCurrentContext();
+}
+
+SkNativeGLContext::AutoContextRestore::~AutoContextRestore() {
+ aglSetCurrentContext(fOldAGLContext);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkNativeGLContext::SkNativeGLContext()
+ : fContext(NULL) {
+}
+
+SkNativeGLContext::~SkNativeGLContext() {
+ this->destroyGLContext();
+}
+
+void SkNativeGLContext::destroyGLContext() {
+ if (fContext) {
+ aglDestroyContext(fContext);
+ }
+}
+
+const GrGLInterface* SkNativeGLContext::createGLContext() {
+ GLint major, minor;
+ AGLContext ctx;
+
+ aglGetVersion(&major, &minor);
+ //SkDebugf("---- agl version %d %d\n", major, minor);
+
+ const GLint pixelAttrs[] = {
+ AGL_RGBA,
+ AGL_ACCELERATED,
+ AGL_NONE
+ };
+ AGLPixelFormat format = aglChoosePixelFormat(NULL, 0, pixelAttrs);
+ if (NULL == format) {
+ SkDebugf("Format could not be found.\n");
+ this->destroyGLContext();
+ return NULL;
+ }
+ fContext = aglCreateContext(format, NULL);
+ if (NULL == fContext) {
+ SkDebugf("Context could not be created.\n");
+ this->destroyGLContext();
+ return NULL;
+ }
+ aglDestroyPixelFormat(format);
+
+ aglSetCurrentContext(fContext);
+
+ const GrGLInterface* interface = GrGLCreateNativeInterface();
+ if (NULL == interface) {
+ SkDebugf("Context could not create GL interface.\n");
+ this->destroyGLContext();
+ return NULL;
+ }
+
+ return interface;
+}
+
+void SkNativeGLContext::makeCurrent() const {
+ aglSetCurrentContext(fContext);
+}
diff --git a/src/gpu/mesa/GrGLCreateMesaInterface.cpp b/src/gpu/mesa/GrGLCreateMesaInterface.cpp
new file mode 100644
index 0000000..7303d1b
--- /dev/null
+++ b/src/gpu/mesa/GrGLCreateMesaInterface.cpp
@@ -0,0 +1,197 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrGLInterface.h"
+
+#define GL_GLEXT_PROTOTYPES
+#include <GL/osmesa.h>
+
+#define GR_GL_GET_PROC(F) interface->f ## F = (GrGL ## F ## Proc) \
+ OSMesaGetProcAddress("gl" #F);
+#define GR_GL_GET_PROC_SUFFIX(F, S) interface->f ## F = (GrGL ## F ## Proc) \
+ OSMesaGetProcAddress("gl" #F #S);
+
+// We use OSMesaGetProcAddress for every gl function to avoid accidentally using
+// non-Mesa gl functions.
+
+const GrGLInterface* GrGLCreateMesaInterface() {
+ if (NULL != OSMesaGetCurrentContext()) {
+ GrGLGetStringProc getString = (GrGLGetStringProc) OSMesaGetProcAddress("glGetString");
+ const char* versionString = (const char*) getString(GL_VERSION);
+ const char* extString = (const char*) getString(GL_EXTENSIONS);
+ GrGLVersion glVer = GrGLGetVersionFromString(versionString);
+
+ if (glVer < GR_GL_VER(1,5)) {
+ // We must have array and element_array buffer objects.
+ return NULL;
+ }
+ GrGLInterface* interface = new GrGLInterface();
+
+ GR_GL_GET_PROC(ActiveTexture);
+ GR_GL_GET_PROC(BeginQuery);
+ GR_GL_GET_PROC(AttachShader);
+ GR_GL_GET_PROC(BindAttribLocation);
+ GR_GL_GET_PROC(BindBuffer);
+ GR_GL_GET_PROC(BindFragDataLocation);
+ GR_GL_GET_PROC(BindTexture);
+ GR_GL_GET_PROC(BlendColor);
+ GR_GL_GET_PROC(BlendFunc);
+ GR_GL_GET_PROC(BufferData);
+ GR_GL_GET_PROC(BufferSubData);
+ GR_GL_GET_PROC(Clear);
+ GR_GL_GET_PROC(ClearColor);
+ GR_GL_GET_PROC(ClearStencil);
+ GR_GL_GET_PROC(ColorMask);
+ GR_GL_GET_PROC(CompileShader);
+ GR_GL_GET_PROC(CompressedTexImage2D);
+ GR_GL_GET_PROC(CreateProgram);
+ GR_GL_GET_PROC(CreateShader);
+ GR_GL_GET_PROC(CullFace);
+ GR_GL_GET_PROC(DeleteBuffers);
+ GR_GL_GET_PROC(DeleteProgram);
+ GR_GL_GET_PROC(DeleteQueries);
+ GR_GL_GET_PROC(DeleteShader);
+ GR_GL_GET_PROC(DeleteTextures);
+ GR_GL_GET_PROC(DepthMask);
+ GR_GL_GET_PROC(Disable);
+ GR_GL_GET_PROC(DisableVertexAttribArray);
+ GR_GL_GET_PROC(DrawArrays);
+ GR_GL_GET_PROC(DrawBuffer);
+ GR_GL_GET_PROC(DrawBuffers);
+ GR_GL_GET_PROC(DrawElements);
+ GR_GL_GET_PROC(Enable);
+ GR_GL_GET_PROC(EnableVertexAttribArray);
+ GR_GL_GET_PROC(EndQuery);
+ GR_GL_GET_PROC(Finish);
+ GR_GL_GET_PROC(Flush);
+ GR_GL_GET_PROC(FrontFace);
+ GR_GL_GET_PROC(GenBuffers);
+ GR_GL_GET_PROC(GenQueries);
+ GR_GL_GET_PROC(GetBufferParameteriv);
+ GR_GL_GET_PROC(GetError);
+ GR_GL_GET_PROC(GetIntegerv);
+ GR_GL_GET_PROC(GetProgramInfoLog);
+ GR_GL_GET_PROC(GetProgramiv);
+ if (glVer >= GR_GL_VER(3,3) ||
+ GrGLHasExtensionFromString("GL_ARB_timer_query", extString)) {
+ GR_GL_GET_PROC(GetQueryObjecti64v);
+ GR_GL_GET_PROC(GetQueryObjectui64v)
+ GR_GL_GET_PROC(QueryCounter);
+ } else if (GrGLHasExtensionFromString("GL_EXT_timer_query", extString)) {
+ GR_GL_GET_PROC_SUFFIX(GetQueryObjecti64v, EXT);
+ GR_GL_GET_PROC_SUFFIX(GetQueryObjectui64v, EXT);
+ }
+ GR_GL_GET_PROC(GetQueryObjectiv);
+ GR_GL_GET_PROC(GetQueryObjectuiv);
+ GR_GL_GET_PROC(GetQueryiv);
+ GR_GL_GET_PROC(GetShaderInfoLog);
+ GR_GL_GET_PROC(GetShaderiv);
+ GR_GL_GET_PROC(GetString);
+ GR_GL_GET_PROC(GetTexLevelParameteriv);
+ GR_GL_GET_PROC(GenTextures);
+ GR_GL_GET_PROC(GetUniformLocation);
+ GR_GL_GET_PROC(LineWidth);
+ GR_GL_GET_PROC(LinkProgram);
+ GR_GL_GET_PROC(MapBuffer);
+ GR_GL_GET_PROC(PixelStorei);
+ GR_GL_GET_PROC(ReadBuffer);
+ GR_GL_GET_PROC(ReadPixels);
+ GR_GL_GET_PROC(Scissor);
+ GR_GL_GET_PROC(ShaderSource);
+ GR_GL_GET_PROC(StencilFunc);
+ GR_GL_GET_PROC(StencilFuncSeparate);
+ GR_GL_GET_PROC(StencilMask);
+ GR_GL_GET_PROC(StencilMaskSeparate);
+ GR_GL_GET_PROC(StencilOp);
+ GR_GL_GET_PROC(StencilOpSeparate);
+ GR_GL_GET_PROC(TexImage2D)
+ GR_GL_GET_PROC(TexParameteri);
+ GR_GL_GET_PROC(TexStorage2D);
+ if (NULL == interface->fTexStorage2D) {
+ GR_GL_GET_PROC_SUFFIX(TexStorage2D, EXT);
+ }
+ GR_GL_GET_PROC(TexSubImage2D);
+ GR_GL_GET_PROC(Uniform1f);
+ GR_GL_GET_PROC(Uniform1i);
+ GR_GL_GET_PROC(Uniform1fv);
+ GR_GL_GET_PROC(Uniform1iv);
+ GR_GL_GET_PROC(Uniform2f);
+ GR_GL_GET_PROC(Uniform2i);
+ GR_GL_GET_PROC(Uniform2fv);
+ GR_GL_GET_PROC(Uniform2iv);
+ GR_GL_GET_PROC(Uniform3f);
+ GR_GL_GET_PROC(Uniform3i);
+ GR_GL_GET_PROC(Uniform3fv);
+ GR_GL_GET_PROC(Uniform3iv);
+ GR_GL_GET_PROC(Uniform4f);
+ GR_GL_GET_PROC(Uniform4i);
+ GR_GL_GET_PROC(Uniform4fv);
+ GR_GL_GET_PROC(Uniform4iv);
+ GR_GL_GET_PROC(UniformMatrix2fv);
+ GR_GL_GET_PROC(UniformMatrix3fv);
+ GR_GL_GET_PROC(UniformMatrix4fv);
+ GR_GL_GET_PROC(UnmapBuffer);
+ GR_GL_GET_PROC(UseProgram);
+ GR_GL_GET_PROC(VertexAttrib4fv);
+ GR_GL_GET_PROC(VertexAttribPointer);
+ GR_GL_GET_PROC(Viewport);
+
+ // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since
+ // GL_ARB_framebuffer_object doesn't use ARB suffix.)
+ if (glVer >= GR_GL_VER(3,0) ||
+ GrGLHasExtensionFromString("GL_ARB_framebuffer_object",
+ extString)) {
+ GR_GL_GET_PROC(GenFramebuffers);
+ GR_GL_GET_PROC(GetFramebufferAttachmentParameteriv);
+ GR_GL_GET_PROC(GetRenderbufferParameteriv);
+ GR_GL_GET_PROC(BindFramebuffer);
+ GR_GL_GET_PROC(FramebufferTexture2D);
+ GR_GL_GET_PROC(CheckFramebufferStatus);
+ GR_GL_GET_PROC(DeleteFramebuffers);
+ GR_GL_GET_PROC(RenderbufferStorage);
+ GR_GL_GET_PROC(GenRenderbuffers);
+ GR_GL_GET_PROC(DeleteRenderbuffers);
+ GR_GL_GET_PROC(FramebufferRenderbuffer);
+ GR_GL_GET_PROC(BindRenderbuffer);
+ GR_GL_GET_PROC(RenderbufferStorageMultisample);
+ GR_GL_GET_PROC(BlitFramebuffer);
+ } else if (GrGLHasExtensionFromString("GL_EXT_framebuffer_object",
+ extString)) {
+ GR_GL_GET_PROC_SUFFIX(GenFramebuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(GetFramebufferAttachmentParameteriv, EXT);
+ GR_GL_GET_PROC_SUFFIX(GetRenderbufferParameteriv, EXT);
+ GR_GL_GET_PROC_SUFFIX(BindFramebuffer, EXT);
+ GR_GL_GET_PROC_SUFFIX(FramebufferTexture2D, EXT);
+ GR_GL_GET_PROC_SUFFIX(CheckFramebufferStatus, EXT);
+ GR_GL_GET_PROC_SUFFIX(DeleteFramebuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(RenderbufferStorage, EXT);
+ GR_GL_GET_PROC_SUFFIX(GenRenderbuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
+ GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, EXT);
+ if (GrGLHasExtensionFromString("GL_EXT_framebuffer_multisample",
+ extString)) {
+ GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
+ }
+ if (GrGLHasExtensionFromString("GL_EXT_framebuffer_blit",
+ extString)) {
+ GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT);
+ }
+ } else {
+ // we must have FBOs
+ delete interface;
+ return NULL;
+ }
+ GR_GL_GET_PROC(BindFragDataLocationIndexed);
+ interface->fBindingsExported = kDesktop_GrGLBinding;
+ return interface;
+ } else {
+ return NULL;
+ }
+}
diff --git a/src/gpu/mesa/SkMesaGLContext.cpp b/src/gpu/mesa/SkMesaGLContext.cpp
new file mode 100644
index 0000000..b817fa7
--- /dev/null
+++ b/src/gpu/mesa/SkMesaGLContext.cpp
@@ -0,0 +1,103 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <GL/osmesa.h>
+
+#include "SkMesaGLContext.h"
+
+SkMesaGLContext::AutoContextRestore::AutoContextRestore() {
+ fOldContext = (Context)OSMesaGetCurrentContext();
+ if (NULL != (OSMesaContext)fOldContext) {
+ OSMesaGetColorBuffer((OSMesaContext)fOldContext,
+ &fOldWidth, &fOldHeight,
+ &fOldFormat, &fOldImage);
+ }
+}
+
+SkMesaGLContext::AutoContextRestore::~AutoContextRestore() {
+ if (NULL != (OSMesaContext)fOldContext) {
+ OSMesaMakeCurrent((OSMesaContext)fOldContext, fOldImage,
+ fOldFormat, fOldWidth, fOldHeight);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkMesaGLContext::SkMesaGLContext()
+ : fContext(NULL)
+ , fImage(NULL) {
+ GR_STATIC_ASSERT(sizeof(Context) == sizeof(OSMesaContext));
+}
+
+SkMesaGLContext::~SkMesaGLContext() {
+ this->destroyGLContext();
+}
+
+void SkMesaGLContext::destroyGLContext() {
+ if (fImage) {
+ sk_free(fImage);
+ }
+
+ if (fContext) {
+ OSMesaDestroyContext((OSMesaContext)fContext);
+ }
+}
+
+static const GrGLint gBOGUS_SIZE = 16;
+
+const GrGLInterface* SkMesaGLContext::createGLContext() {
+ /* Create an RGBA-mode context */
+#if OSMESA_MAJOR_VERSION * 100 + OSMESA_MINOR_VERSION >= 305
+ /* specify Z, stencil, accum sizes */
+ fContext = (Context)OSMesaCreateContextExt(OSMESA_BGRA, 0, 0, 0, NULL);
+#else
+ fContext = (Context)OSMesaCreateContext(OSMESA_BGRA, NULL);
+#endif
+ if (!fContext) {
+ SkDebugf("OSMesaCreateContext failed!\n");
+ this->destroyGLContext();
+ return NULL;
+ }
+ // Allocate the image buffer
+ fImage = (GrGLubyte *) sk_malloc_throw(gBOGUS_SIZE * gBOGUS_SIZE *
+ 4 * sizeof(GrGLubyte));
+ if (!fImage) {
+ SkDebugf("Alloc image buffer failed!\n");
+ this->destroyGLContext();
+ return NULL;
+ }
+
+ // Bind the buffer to the context and make it current
+ if (!OSMesaMakeCurrent((OSMesaContext)fContext,
+ fImage,
+ GR_GL_UNSIGNED_BYTE,
+ gBOGUS_SIZE,
+ gBOGUS_SIZE)) {
+ SkDebugf("OSMesaMakeCurrent failed!\n");
+ this->destroyGLContext();
+ return NULL;
+ }
+
+ const GrGLInterface* interface = GrGLCreateMesaInterface();
+ if (!interface) {
+ SkDebugf("Could not create GL interface!\n");
+ this->destroyGLContext();
+ return NULL;
+ }
+ return interface;
+
+}
+
+void SkMesaGLContext::makeCurrent() const {
+ if (fContext) {
+ if (!OSMesaMakeCurrent((OSMesaContext)fContext, fImage,
+ GR_GL_UNSIGNED_BYTE, gBOGUS_SIZE, gBOGUS_SIZE)) {
+ SkDebugf("Could not make MESA context current.");
+ }
+ }
+}
diff --git a/src/gpu/skgr_files.mk b/src/gpu/skgr_files.mk
deleted file mode 100644
index 7623fca..0000000
--- a/src/gpu/skgr_files.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-SOURCE := \
- SkGpuCanvas.cpp \
- SkGpuDevice.cpp \
- SkGr.cpp \
- SkGrTexturePixelRef.cpp \
- SkGrFontScaler.cpp \
- GrPrintf_skia.cpp
-
diff --git a/src/gpu/unix/GrGLCreateNativeInterface_unix.cpp b/src/gpu/unix/GrGLCreateNativeInterface_unix.cpp
new file mode 100644
index 0000000..ab0d351
--- /dev/null
+++ b/src/gpu/unix/GrGLCreateNativeInterface_unix.cpp
@@ -0,0 +1,200 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrGLInterface.h"
+
+#include <GL/glx.h>
+#include <GL/gl.h>
+#include <GL/glext.h>
+#include <GL/glu.h>
+
+#define GR_GL_GET_PROC(F) interface->f ## F = (GrGL ## F ## Proc) \
+ glXGetProcAddress(reinterpret_cast<const GLubyte*>("gl" #F));
+#define GR_GL_GET_PROC_SUFFIX(F, S) interface->f ## F = (GrGL ## F ## Proc) \
+ glXGetProcAddress(reinterpret_cast<const GLubyte*>("gl" #F #S));
+
+const GrGLInterface* GrGLCreateNativeInterface() {
+ if (NULL != glXGetCurrentContext()) {
+ const char* versionString = (const char*) glGetString(GL_VERSION);
+ const char* extString = (const char*) glGetString(GL_EXTENSIONS);
+ GrGLVersion glVer = GrGLGetVersionFromString(versionString);
+
+ if (glVer < GR_GL_VER(1,5)) {
+ // We must have array and element_array buffer objects.
+ return NULL;
+ }
+
+ GrGLInterface* interface = new GrGLInterface();
+
+ interface->fActiveTexture = glActiveTexture;
+ GR_GL_GET_PROC(AttachShader);
+ GR_GL_GET_PROC(BindAttribLocation);
+ GR_GL_GET_PROC(BindBuffer);
+ GR_GL_GET_PROC(BindFragDataLocation);
+ GR_GL_GET_PROC(BeginQuery);
+ interface->fBindTexture = glBindTexture;
+ interface->fBlendColor = glBlendColor;
+ interface->fBlendFunc = glBlendFunc;
+ GR_GL_GET_PROC(BufferData);
+ GR_GL_GET_PROC(BufferSubData);
+ interface->fClear = glClear;
+ interface->fClearColor = glClearColor;
+ interface->fClearStencil = glClearStencil;
+ interface->fColorMask = glColorMask;
+ interface->fColorPointer = glColorPointer;
+ GR_GL_GET_PROC(CompileShader);
+ interface->fCompressedTexImage2D = glCompressedTexImage2D;
+ GR_GL_GET_PROC(CreateProgram);
+ GR_GL_GET_PROC(CreateShader);
+ interface->fCullFace = glCullFace;
+ GR_GL_GET_PROC(DeleteBuffers);
+ GR_GL_GET_PROC(DeleteProgram);
+ GR_GL_GET_PROC(DeleteQueries);
+ GR_GL_GET_PROC(DeleteShader);
+ interface->fDeleteTextures = glDeleteTextures;
+ interface->fDepthMask = glDepthMask;
+ interface->fDisable = glDisable;
+ GR_GL_GET_PROC(DisableVertexAttribArray);
+ interface->fDrawArrays = glDrawArrays;
+ interface->fDrawBuffer = glDrawBuffer;
+ GR_GL_GET_PROC(DrawBuffers);
+ interface->fDrawElements = glDrawElements;
+ interface->fEnable = glEnable;
+ GR_GL_GET_PROC(EnableVertexAttribArray);
+ GR_GL_GET_PROC(EndQuery);
+ interface->fFinish = glFinish;
+ interface->fFlush = glFlush;
+ interface->fFrontFace = glFrontFace;
+ GR_GL_GET_PROC(GenBuffers);
+ GR_GL_GET_PROC(GetBufferParameteriv);
+ interface->fGetError = glGetError;
+ interface->fGetIntegerv = glGetIntegerv;
+ GR_GL_GET_PROC(GetQueryObjectiv);
+ GR_GL_GET_PROC(GetQueryObjectuiv);
+ if (glVer >= GR_GL_VER(3,3) ||
+ GrGLHasExtensionFromString("GL_ARB_timer_query", extString)) {
+ GR_GL_GET_PROC(GetQueryObjecti64v);
+ GR_GL_GET_PROC(GetQueryObjectui64v);
+ GR_GL_GET_PROC(QueryCounter);
+ } else if (GrGLHasExtensionFromString("GL_EXT_timer_query", extString)) {
+ GR_GL_GET_PROC_SUFFIX(GetQueryObjecti64v, EXT);
+ GR_GL_GET_PROC_SUFFIX(GetQueryObjectui64v, EXT);
+ }
+ GR_GL_GET_PROC(GetQueryiv);
+ GR_GL_GET_PROC(GetProgramInfoLog);
+ GR_GL_GET_PROC(GetProgramiv);
+ GR_GL_GET_PROC(GetShaderInfoLog);
+ GR_GL_GET_PROC(GetShaderiv);
+ interface->fGetString = glGetString;
+ interface->fGetTexLevelParameteriv = glGetTexLevelParameteriv;
+ GR_GL_GET_PROC(GenQueries);
+ interface->fGenTextures = glGenTextures;
+ GR_GL_GET_PROC(GetUniformLocation);
+ interface->fLineWidth = glLineWidth;
+ GR_GL_GET_PROC(LinkProgram);
+ GR_GL_GET_PROC(MapBuffer);
+ interface->fPixelStorei = glPixelStorei;
+ interface->fReadBuffer = glReadBuffer;
+ interface->fReadPixels = glReadPixels;
+ interface->fScissor = glScissor;
+ GR_GL_GET_PROC(ShaderSource);
+ interface->fStencilFunc = glStencilFunc;
+ GR_GL_GET_PROC(StencilFuncSeparate);
+ interface->fStencilMask = glStencilMask;
+ GR_GL_GET_PROC(StencilMaskSeparate);
+ interface->fStencilOp = glStencilOp;
+ GR_GL_GET_PROC(StencilOpSeparate);
+ interface->fTexImage2D = glTexImage2D;
+ interface->fTexParameteri = glTexParameteri;
+ if (glVer >= GR_GL_VER(4,2) ||
+ GrGLHasExtensionFromString("GL_ARB_texture_storage", extString)) {
+ GR_GL_GET_PROC(TexStorage2D);
+ } else if (GrGLHasExtensionFromString("GL_EXT_texture_storage", extString)) {
+ GR_GL_GET_PROC_SUFFIX(TexStorage2D, EXT);
+ }
+ interface->fTexSubImage2D = glTexSubImage2D;
+ GR_GL_GET_PROC(Uniform1f);
+ GR_GL_GET_PROC(Uniform1i);
+ GR_GL_GET_PROC(Uniform1fv);
+ GR_GL_GET_PROC(Uniform1iv);
+ GR_GL_GET_PROC(Uniform2f);
+ GR_GL_GET_PROC(Uniform2i);
+ GR_GL_GET_PROC(Uniform2fv);
+ GR_GL_GET_PROC(Uniform2iv);
+ GR_GL_GET_PROC(Uniform3f);
+ GR_GL_GET_PROC(Uniform3i);
+ GR_GL_GET_PROC(Uniform3fv);
+ GR_GL_GET_PROC(Uniform3iv);
+ GR_GL_GET_PROC(Uniform4f);
+ GR_GL_GET_PROC(Uniform4i);
+ GR_GL_GET_PROC(Uniform4fv);
+ GR_GL_GET_PROC(Uniform4iv);
+ GR_GL_GET_PROC(UniformMatrix2fv);
+ GR_GL_GET_PROC(UniformMatrix3fv);
+ GR_GL_GET_PROC(UniformMatrix4fv);
+ GR_GL_GET_PROC(UnmapBuffer);
+ GR_GL_GET_PROC(UseProgram);
+ GR_GL_GET_PROC(VertexAttrib4fv);
+ GR_GL_GET_PROC(VertexAttribPointer);
+ interface->fViewport = glViewport;
+ GR_GL_GET_PROC(BindFragDataLocationIndexed);
+
+ // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since
+ // GL_ARB_framebuffer_object doesn't use ARB suffix.)
+ if (glVer >= GR_GL_VER(3,0) ||
+ GrGLHasExtensionFromString("GL_ARB_framebuffer_object",
+ extString)) {
+ GR_GL_GET_PROC(GenFramebuffers);
+ GR_GL_GET_PROC(GetFramebufferAttachmentParameteriv);
+ GR_GL_GET_PROC(GetRenderbufferParameteriv);
+ GR_GL_GET_PROC(BindFramebuffer);
+ GR_GL_GET_PROC(FramebufferTexture2D);
+ GR_GL_GET_PROC(CheckFramebufferStatus);
+ GR_GL_GET_PROC(DeleteFramebuffers);
+ GR_GL_GET_PROC(RenderbufferStorage);
+ GR_GL_GET_PROC(GenRenderbuffers);
+ GR_GL_GET_PROC(DeleteRenderbuffers);
+ GR_GL_GET_PROC(FramebufferRenderbuffer);
+ GR_GL_GET_PROC(BindRenderbuffer);
+ GR_GL_GET_PROC(RenderbufferStorageMultisample);
+ GR_GL_GET_PROC(BlitFramebuffer);
+ } else if (GrGLHasExtensionFromString("GL_EXT_framebuffer_object",
+ extString)) {
+ GR_GL_GET_PROC_SUFFIX(GenFramebuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(GetFramebufferAttachmentParameteriv, EXT);
+ GR_GL_GET_PROC_SUFFIX(GetRenderbufferParameteriv, EXT);
+ GR_GL_GET_PROC_SUFFIX(BindFramebuffer, EXT);
+ GR_GL_GET_PROC_SUFFIX(FramebufferTexture2D, EXT);
+ GR_GL_GET_PROC_SUFFIX(CheckFramebufferStatus, EXT);
+ GR_GL_GET_PROC_SUFFIX(DeleteFramebuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(RenderbufferStorage, EXT);
+ GR_GL_GET_PROC_SUFFIX(GenRenderbuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
+ GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, EXT);
+ if (GrGLHasExtensionFromString("GL_EXT_framebuffer_multisample",
+ extString)) {
+ GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
+ }
+ if (GrGLHasExtensionFromString("GL_EXT_framebuffer_blit",
+ extString)) {
+ GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT);
+ }
+ } else {
+ // we must have FBOs
+ delete interface;
+ return NULL;
+ }
+ interface->fBindingsExported = kDesktop_GrGLBinding;
+
+ return interface;
+ } else {
+ return NULL;
+ }
+}
diff --git a/src/utils/unix/SkEGLContext_Unix.cpp b/src/gpu/unix/SkNativeGLContext_unix.cpp
index 7921b8a..907e2b8 100644
--- a/src/utils/unix/SkEGLContext_Unix.cpp
+++ b/src/gpu/unix/SkNativeGLContext_unix.cpp
@@ -1,14 +1,27 @@
-#include "SkEGLContext.h"
-#include "SkTypes.h"
-#include <GL/gl.h>
-#include <GL/glext.h>
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkNativeGLContext.h"
+
#include <GL/glu.h>
-#include <GL/glx.h>
-#include <X11/Xlib.h>
-#define SK_GL_GET_PROC(T, F) T F = NULL; \
- F = (T) glXGetProcAddressARB(reinterpret_cast<const GLubyte*>(#F));
+SkNativeGLContext::AutoContextRestore::AutoContextRestore() {
+ fOldGLXContext = glXGetCurrentContext();
+ fOldDisplay = glXGetCurrentDisplay();
+ fOldDrawable = glXGetCurrentDrawable();
+}
+
+SkNativeGLContext::AutoContextRestore::~AutoContextRestore() {
+ if (NULL != fOldDisplay) {
+ glXMakeCurrent(fOldDisplay, fOldDrawable, fOldGLXContext);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
static bool ctxErrorOccurred = false;
static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
@@ -16,70 +29,76 @@ static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
return 0;
}
-SkEGLContext::SkEGLContext() : context(NULL), display(NULL), pixmap(0), glxPixmap(0) {
+SkNativeGLContext::SkNativeGLContext()
+ : fContext(NULL)
+ , fDisplay(NULL)
+ , fPixmap(0)
+ , fGlxPixmap(0) {
}
-SkEGLContext::~SkEGLContext() {
- if (this->display) {
- glXMakeCurrent(this->display, 0, 0);
+SkNativeGLContext::~SkNativeGLContext() {
+ this->destroyGLContext();
+}
- if (this->context)
- glXDestroyContext(this->display, this->context);
+void SkNativeGLContext::destroyGLContext() {
+ if (fDisplay) {
+ glXMakeCurrent(fDisplay, 0, 0);
- if (this->glxPixmap)
- glXDestroyGLXPixmap(this->display, this->glxPixmap);
+ if (fContext) {
+ glXDestroyContext(fDisplay, fContext);
+ fContext = NULL;
+ }
- if (this->pixmap)
- XFreePixmap(this->display, this->pixmap);
+ if (fGlxPixmap) {
+ glXDestroyGLXPixmap(fDisplay, fGlxPixmap);
+ fGlxPixmap = 0;
+ }
- XCloseDisplay(this->display);
+ if (fPixmap) {
+ XFreePixmap(fDisplay, fPixmap);
+ fPixmap = 0;
+ }
+
+ XCloseDisplay(fDisplay);
+ fDisplay = NULL;
}
}
-bool SkEGLContext::init(const int width, const int height) {
- Display *display = XOpenDisplay(0);
- this->display = display;
+const GrGLInterface* SkNativeGLContext::createGLContext() {
+ fDisplay = XOpenDisplay(0);
- if (!display) {
+ if (!fDisplay) {
SkDebugf("Failed to open X display.\n");
- return false;
+ this->destroyGLContext();
+ return NULL;
}
// Get a matching FB config
static int visual_attribs[] = {
GLX_X_RENDERABLE , True,
GLX_DRAWABLE_TYPE , GLX_PIXMAP_BIT,
- GLX_RENDER_TYPE , GLX_RGBA_BIT,
- GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR,
- GLX_RED_SIZE , 8,
- GLX_GREEN_SIZE , 8,
- GLX_BLUE_SIZE , 8,
- GLX_ALPHA_SIZE , 8,
- GLX_DEPTH_SIZE , 24,
- GLX_STENCIL_SIZE , 8,
- GLX_DOUBLEBUFFER , True,
- //GLX_SAMPLE_BUFFERS , 1,
- //GLX_SAMPLES , 4,
None
};
int glx_major, glx_minor;
// FBConfigs were added in GLX version 1.3.
- if (!glXQueryVersion( display, &glx_major, &glx_minor) ||
+ if (!glXQueryVersion(fDisplay, &glx_major, &glx_minor) ||
( (glx_major == 1) && (glx_minor < 3) ) || (glx_major < 1))
{
SkDebugf("Invalid GLX version.");
- return false;
+ this->destroyGLContext();
+ return NULL;
}
//SkDebugf("Getting matching framebuffer configs.\n");
int fbcount;
- GLXFBConfig *fbc = glXChooseFBConfig(display, DefaultScreen(display),
+ GLXFBConfig *fbc = glXChooseFBConfig(fDisplay, DefaultScreen(fDisplay),
visual_attribs, &fbcount);
if (!fbc) {
SkDebugf("Failed to retrieve a framebuffer config.\n");
- return false;
+ this->destroyGLContext();
+ return NULL;
}
//SkDebugf("Found %d matching FB configs.\n", fbcount);
@@ -89,11 +108,11 @@ bool SkEGLContext::init(const int width, const int height) {
int i;
for (i = 0; i < fbcount; ++i) {
- XVisualInfo *vi = glXGetVisualFromFBConfig(display, fbc[i]);
+ XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, fbc[i]);
if (vi) {
int samp_buf, samples;
- glXGetFBConfigAttrib(display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
- glXGetFBConfigAttrib(display, fbc[i], GLX_SAMPLES, &samples);
+ glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
+ glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLES, &samples);
//SkDebugf(" Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d,"
// " SAMPLES = %d\n",
@@ -113,27 +132,23 @@ bool SkEGLContext::init(const int width, const int height) {
XFree(fbc);
// Get a visual
- XVisualInfo *vi = glXGetVisualFromFBConfig(display, bestFbc);
+ XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, bestFbc);
//SkDebugf("Chosen visual ID = 0x%x\n", (unsigned int)vi->visualid);
- Pixmap pixmap = XCreatePixmap(
- display, RootWindow(display, vi->screen), width, height, vi->depth
- );
+ fPixmap = XCreatePixmap(fDisplay, RootWindow(fDisplay, vi->screen), 10, 10, vi->depth);
- this->pixmap = pixmap;
- if (!pixmap) {
+ if (!fPixmap) {
SkDebugf("Failed to create pixmap.\n");
- return false;
+ this->destroyGLContext();
+ return NULL;
}
- GLXPixmap glxPixmap = glXCreateGLXPixmap(display, vi, pixmap);
- this->glxPixmap = glxPixmap;
+ fGlxPixmap = glXCreateGLXPixmap(fDisplay, vi, fPixmap);
// Done with the visual info data
XFree(vi);
// Create the context
- GLXContext ctx = 0;
// Install an X error handler so the application won't exit if GL 3.0
// context allocation fails.
@@ -148,7 +163,7 @@ bool SkEGLContext::init(const int width, const int height) {
// Get the default screen's GLX extension list
const char *glxExts = glXQueryExtensionsString(
- display, DefaultScreen(display)
+ fDisplay, DefaultScreen(fDisplay)
);
// Check for the GLX_ARB_create_context extension string and the function.
// If either is not present, use GLX 1.3 context creation method.
@@ -158,25 +173,26 @@ bool SkEGLContext::init(const int width, const int height) {
{
//SkDebugf("GLX_ARB_create_context not found."
// " Using old-style GLX context.\n");
- ctx = glXCreateNewContext(display, bestFbc, GLX_RGBA_TYPE, 0, True);
+ fContext = glXCreateNewContext(fDisplay, bestFbc, GLX_RGBA_TYPE, 0, True);
} else {
//SkDebugf("Creating context.\n");
- SK_GL_GET_PROC(PFNGLXCREATECONTEXTATTRIBSARBPROC, glXCreateContextAttribsARB)
+ PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB =
+ (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddressARB((GrGLubyte*)"glXCreateContextAttribsARB");
int context_attribs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 0,
//GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
None
};
- ctx = glXCreateContextAttribsARB(
- display, bestFbc, 0, True, context_attribs
+ fContext = glXCreateContextAttribsARB(
+ fDisplay, bestFbc, 0, True, context_attribs
);
// Sync to ensure any errors generated are processed.
- XSync(display, False);
- if (!ctxErrorOccurred && ctx) {
+ XSync(fDisplay, False);
+ if (!ctxErrorOccurred && fContext) {
//SkDebugf( "Created GL 3.0 context.\n" );
} else {
// Couldn't create GL 3.0 context.
@@ -194,71 +210,49 @@ bool SkEGLContext::init(const int width, const int height) {
//SkDebugf("Failed to create GL 3.0 context."
// " Using old-style GLX context.\n");
- ctx = glXCreateContextAttribsARB(
- display, bestFbc, 0, True, context_attribs
+ fContext = glXCreateContextAttribsARB(
+ fDisplay, bestFbc, 0, True, context_attribs
);
}
}
// Sync to ensure any errors generated are processed.
- XSync(display, False);
+ XSync(fDisplay, False);
// Restore the original error handler
XSetErrorHandler(oldHandler);
- if (ctxErrorOccurred || !ctx) {
+ if (ctxErrorOccurred || !fContext) {
SkDebugf("Failed to create an OpenGL context.\n");
- return false;
+ this->destroyGLContext();
+ return NULL;
}
- this->context = ctx;
// Verify that context is a direct context
- if (!glXIsDirect(display, ctx)) {
+ if (!glXIsDirect(fDisplay, fContext)) {
//SkDebugf("Indirect GLX rendering context obtained.\n");
} else {
//SkDebugf("Direct GLX rendering context obtained.\n");
}
//SkDebugf("Making context current.\n");
- if (!glXMakeCurrent(display, glxPixmap, ctx)) {
+ if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
SkDebugf("Could not set the context.\n");
- return false;
+ this->destroyGLContext();
+ return NULL;
}
- //Setup the framebuffers
- const GLubyte* glExts = glGetString(GL_EXTENSIONS);
- if (!gluCheckExtension(
- reinterpret_cast<const GLubyte*>("GL_EXT_framebuffer_object")
- , glExts))
- {
- SkDebugf("GL_EXT_framebuffer_object not found.\n");
- return false;
+ const GrGLInterface* interface = GrGLCreateNativeInterface();
+ if (!interface) {
+ SkDebugf("Failed to create gl interface");
+ this->destroyGLContext();
+ return NULL;
+ }
+ return interface;
+}
+
+void SkNativeGLContext::makeCurrent() const {
+ if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
+ SkDebugf("Could not set the context.\n");
}
- SK_GL_GET_PROC(PFNGLGENFRAMEBUFFERSEXTPROC, glGenFramebuffersEXT)
- SK_GL_GET_PROC(PFNGLBINDFRAMEBUFFEREXTPROC, glBindFramebufferEXT)
- SK_GL_GET_PROC(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffersEXT)
- SK_GL_GET_PROC(PFNGLBINDRENDERBUFFERPROC, glBindRenderbufferEXT)
- SK_GL_GET_PROC(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorageEXT)
- SK_GL_GET_PROC(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbufferEXT)
- SK_GL_GET_PROC(PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC, glCheckFramebufferStatusEXT)
-
- GLuint fboID;
- GLuint cbID;
- GLuint dsID;
- glGenFramebuffersEXT(1, &fboID);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboID);
- glGenRenderbuffersEXT(1, &cbID);
- glBindRenderbufferEXT(GL_RENDERBUFFER, cbID);
- glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_RGBA, width, height);
- glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, cbID);
- glGenRenderbuffersEXT(1, &dsID);
- glBindRenderbufferEXT(GL_RENDERBUFFER, dsID);
- glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_STENCIL, width, height);
- glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, dsID);
- glViewport(0, 0, width, height);
- glClearStencil(0);
- glClear(GL_STENCIL_BUFFER_BIT);
-
- GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
- return GL_FRAMEBUFFER_COMPLETE == status;
}
diff --git a/src/gpu/win/GrGLCreateNativeInterface_win.cpp b/src/gpu/win/GrGLCreateNativeInterface_win.cpp
new file mode 100644
index 0000000..b59f930
--- /dev/null
+++ b/src/gpu/win/GrGLCreateNativeInterface_win.cpp
@@ -0,0 +1,206 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "GrGLInterface.h"
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <GL/GL.h>
+
+/*
+ * Windows makes the GL funcs all be __stdcall instead of __cdecl :(
+ * This implementation will only work if GR_GL_FUNCTION_TYPE is __stdcall.
+ * Otherwise, a springboard would be needed that hides the calling convention.
+ */
+
+#define GR_GL_GET_PROC(F) interface->f ## F = (GrGL ## F ## Proc) wglGetProcAddress("gl" #F);
+#define GR_GL_GET_PROC_SUFFIX(F, S) interface->f ## F = (GrGL ## F ## Proc) wglGetProcAddress("gl" #F #S);
+
+const GrGLInterface* GrGLCreateNativeInterface() {
+ // wglGetProcAddress requires a context.
+ // GL Function pointers retrieved in one context may not be valid in another
+ // context. For that reason we create a new GrGLInterface each time we're
+ // called.
+ if (NULL != wglGetCurrentContext()) {
+ const char* versionString = (const char*) glGetString(GL_VERSION);
+ const char* extString = (const char*) glGetString(GL_EXTENSIONS);
+ GrGLVersion glVer = GrGLGetVersionFromString(versionString);
+
+ if (glVer < GR_GL_VER(1,5)) {
+ // We must have array and element_array buffer objects.
+ return NULL;
+ }
+ GrGLInterface* interface = new GrGLInterface();
+
+ // Functions that are part of GL 1.1 will return NULL in
+ // wglGetProcAddress
+ interface->fBindTexture = glBindTexture;
+ interface->fBlendFunc = glBlendFunc;
+ interface->fClear = glClear;
+ interface->fClearColor = glClearColor;
+ interface->fClearStencil = glClearStencil;
+ interface->fColorMask = glColorMask;
+ interface->fColorPointer = glColorPointer;
+ interface->fCullFace = glCullFace;
+ interface->fDeleteTextures = glDeleteTextures;
+ interface->fDepthMask = glDepthMask;
+ interface->fDisable = glDisable;
+ interface->fDrawArrays = glDrawArrays;
+ interface->fDrawElements = glDrawElements;
+ interface->fDrawBuffer = glDrawBuffer;
+ interface->fEnable = glEnable;
+ interface->fFrontFace = glFrontFace;
+ interface->fFinish = glFinish;
+ interface->fFlush = glFlush;
+ interface->fGenTextures = glGenTextures;
+ interface->fGetError = glGetError;
+ interface->fGetIntegerv = glGetIntegerv;
+ interface->fGetString = glGetString;
+ interface->fGetTexLevelParameteriv = glGetTexLevelParameteriv;
+ interface->fLineWidth = glLineWidth;
+ interface->fPixelStorei = glPixelStorei;
+ interface->fReadBuffer = glReadBuffer;
+ interface->fReadPixels = glReadPixels;
+ interface->fScissor = glScissor;
+ interface->fStencilFunc = glStencilFunc;
+ interface->fStencilMask = glStencilMask;
+ interface->fStencilOp = glStencilOp;
+ interface->fTexImage2D = glTexImage2D;
+ interface->fTexParameteri = glTexParameteri;
+ if (glVer >= GR_GL_VER(4,2) ||
+ GrGLHasExtensionFromString("GL_ARB_texture_storage", extString)) {
+ GR_GL_GET_PROC(TexStorage2D);
+ } else if (GrGLHasExtensionFromString("GL_EXT_texture_storage", extString)) {
+ GR_GL_GET_PROC_SUFFIX(TexStorage2D, EXT);
+ }
+ interface->fTexSubImage2D = glTexSubImage2D;
+ interface->fViewport = glViewport;
+
+ GR_GL_GET_PROC(ActiveTexture);
+ GR_GL_GET_PROC(AttachShader);
+ GR_GL_GET_PROC(BeginQuery);
+ GR_GL_GET_PROC(BindAttribLocation);
+ GR_GL_GET_PROC(BindBuffer);
+ GR_GL_GET_PROC(BindFragDataLocation);
+ GR_GL_GET_PROC(BlendColor);
+ GR_GL_GET_PROC(BufferData);
+ GR_GL_GET_PROC(BufferSubData);
+ GR_GL_GET_PROC(CompileShader);
+ GR_GL_GET_PROC(CompressedTexImage2D);
+ GR_GL_GET_PROC(CreateProgram);
+ GR_GL_GET_PROC(CreateShader);
+ GR_GL_GET_PROC(DeleteBuffers);
+ GR_GL_GET_PROC(DeleteQueries);
+ GR_GL_GET_PROC(DeleteProgram);
+ GR_GL_GET_PROC(DeleteShader);
+ GR_GL_GET_PROC(DisableVertexAttribArray);
+ GR_GL_GET_PROC(DrawBuffers);
+ GR_GL_GET_PROC(EnableVertexAttribArray);
+ GR_GL_GET_PROC(EndQuery);
+ GR_GL_GET_PROC(GenBuffers);
+ GR_GL_GET_PROC(GenQueries);
+ GR_GL_GET_PROC(GetBufferParameteriv);
+ GR_GL_GET_PROC(GetQueryiv);
+ GR_GL_GET_PROC(GetQueryObjectiv);
+ GR_GL_GET_PROC(GetQueryObjectuiv);
+ if (glVer > GR_GL_VER(3,3) ||
+ GrGLHasExtensionFromString("GL_ARB_timer_query", extString)) {
+ GR_GL_GET_PROC(GetQueryObjecti64v);
+ GR_GL_GET_PROC(GetQueryObjectui64v);
+ GR_GL_GET_PROC(QueryCounter);
+ } else if (GrGLHasExtensionFromString("GL_EXT_timer_query", extString)) {
+ GR_GL_GET_PROC_SUFFIX(GetQueryObjecti64v, EXT);
+ GR_GL_GET_PROC_SUFFIX(GetQueryObjectui64v, EXT);
+ }
+ GR_GL_GET_PROC(GetProgramInfoLog);
+ GR_GL_GET_PROC(GetProgramiv);
+ GR_GL_GET_PROC(GetShaderInfoLog);
+ GR_GL_GET_PROC(GetShaderiv);
+ GR_GL_GET_PROC(GetUniformLocation);
+ GR_GL_GET_PROC(LinkProgram);
+ GR_GL_GET_PROC(ShaderSource);
+ GR_GL_GET_PROC(StencilFuncSeparate);
+ GR_GL_GET_PROC(StencilMaskSeparate);
+ GR_GL_GET_PROC(StencilOpSeparate);
+ GR_GL_GET_PROC(Uniform1f);
+ GR_GL_GET_PROC(Uniform1i);
+ GR_GL_GET_PROC(Uniform1fv);
+ GR_GL_GET_PROC(Uniform1iv);
+ GR_GL_GET_PROC(Uniform2f);
+ GR_GL_GET_PROC(Uniform2i);
+ GR_GL_GET_PROC(Uniform2fv);
+ GR_GL_GET_PROC(Uniform2iv);
+ GR_GL_GET_PROC(Uniform3f);
+ GR_GL_GET_PROC(Uniform3i);
+ GR_GL_GET_PROC(Uniform3fv);
+ GR_GL_GET_PROC(Uniform3iv);
+ GR_GL_GET_PROC(Uniform4f);
+ GR_GL_GET_PROC(Uniform4i);
+ GR_GL_GET_PROC(Uniform4fv);
+ GR_GL_GET_PROC(Uniform4iv);
+ GR_GL_GET_PROC(UniformMatrix2fv);
+ GR_GL_GET_PROC(UniformMatrix3fv);
+ GR_GL_GET_PROC(UniformMatrix4fv);
+ GR_GL_GET_PROC(UseProgram);
+ GR_GL_GET_PROC(VertexAttrib4fv);
+ GR_GL_GET_PROC(VertexAttribPointer);
+ GR_GL_GET_PROC(BindFragDataLocationIndexed);
+
+ // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since
+ // GL_ARB_framebuffer_object doesn't use ARB suffix.)
+ if (glVer > GR_GL_VER(3,0) ||
+ GrGLHasExtensionFromString("GL_ARB_framebuffer_object", extString)) {
+ GR_GL_GET_PROC(GenFramebuffers);
+ GR_GL_GET_PROC(GetFramebufferAttachmentParameteriv);
+ GR_GL_GET_PROC(GetRenderbufferParameteriv);
+ GR_GL_GET_PROC(BindFramebuffer);
+ GR_GL_GET_PROC(FramebufferTexture2D);
+ GR_GL_GET_PROC(CheckFramebufferStatus);
+ GR_GL_GET_PROC(DeleteFramebuffers);
+ GR_GL_GET_PROC(RenderbufferStorage);
+ GR_GL_GET_PROC(GenRenderbuffers);
+ GR_GL_GET_PROC(DeleteRenderbuffers);
+ GR_GL_GET_PROC(FramebufferRenderbuffer);
+ GR_GL_GET_PROC(BindRenderbuffer);
+ GR_GL_GET_PROC(RenderbufferStorageMultisample);
+ GR_GL_GET_PROC(BlitFramebuffer);
+ } else if (GrGLHasExtensionFromString("GL_EXT_framebuffer_object",
+ extString)) {
+ GR_GL_GET_PROC_SUFFIX(GenFramebuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(GetFramebufferAttachmentParameteriv, EXT);
+ GR_GL_GET_PROC_SUFFIX(GetRenderbufferParameteriv, EXT);
+ GR_GL_GET_PROC_SUFFIX(BindFramebuffer, EXT);
+ GR_GL_GET_PROC_SUFFIX(FramebufferTexture2D, EXT);
+ GR_GL_GET_PROC_SUFFIX(CheckFramebufferStatus, EXT);
+ GR_GL_GET_PROC_SUFFIX(DeleteFramebuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(RenderbufferStorage, EXT);
+ GR_GL_GET_PROC_SUFFIX(GenRenderbuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
+ GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, EXT);
+ if (GrGLHasExtensionFromString("GL_EXT_framebuffer_multisample", extString)) {
+ GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
+ }
+ if (GrGLHasExtensionFromString("GL_EXT_framebuffer_blit", extString)) {
+ GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT);
+ }
+ } else {
+ // we must have FBOs
+ delete interface;
+ return NULL;
+ }
+ GR_GL_GET_PROC(MapBuffer);
+ GR_GL_GET_PROC(UnmapBuffer);
+
+ interface->fBindingsExported = kDesktop_GrGLBinding;
+
+ return interface;
+ } else {
+ return NULL;
+ }
+}
diff --git a/src/gpu/win/SkNativeGLContext_win.cpp b/src/gpu/win/SkNativeGLContext_win.cpp
new file mode 100644
index 0000000..5d518dd
--- /dev/null
+++ b/src/gpu/win/SkNativeGLContext_win.cpp
@@ -0,0 +1,137 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkNativeGLContext.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+
+SkNativeGLContext::AutoContextRestore::AutoContextRestore() {
+ fOldHGLRC = wglGetCurrentContext();
+ fOldHDC = wglGetCurrentDC();
+}
+
+SkNativeGLContext::AutoContextRestore::~AutoContextRestore() {
+ wglMakeCurrent(fOldHDC, fOldHGLRC);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+ATOM SkNativeGLContext::gWC = 0;
+
+SkNativeGLContext::SkNativeGLContext()
+ : fWindow(NULL)
+ , fDeviceContext(NULL)
+ , fGlRenderContext(0) {
+}
+
+SkNativeGLContext::~SkNativeGLContext() {
+ this->destroyGLContext();
+}
+
+void SkNativeGLContext::destroyGLContext() {
+ if (fGlRenderContext) {
+ wglDeleteContext(fGlRenderContext);
+ }
+ if (fWindow && fDeviceContext) {
+ ReleaseDC(fWindow, fDeviceContext);
+ }
+ if (fWindow) {
+ DestroyWindow(fWindow);
+ }
+}
+
+const GrGLInterface* SkNativeGLContext::createGLContext() {
+ HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
+
+ if (!gWC) {
+ WNDCLASS wc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hbrBackground = NULL;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hInstance = hInstance;
+ wc.lpfnWndProc = (WNDPROC) DefWindowProc;
+ wc.lpszClassName = TEXT("Griffin");
+ wc.lpszMenuName = NULL;
+ wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+
+ gWC = RegisterClass(&wc);
+ if (!gWC) {
+ SkDebugf("Could not register window class.\n");
+ return NULL;
+ }
+ }
+
+ if (!(fWindow = CreateWindow(TEXT("Griffin"),
+ TEXT("The Invisible Man"),
+ WS_OVERLAPPEDWINDOW,
+ 0, 0, 1, 1,
+ NULL, NULL,
+ hInstance, NULL))) {
+ SkDebugf("Could not create window.\n");
+ return NULL;
+ }
+
+ if (!(fDeviceContext = GetDC(fWindow))) {
+ SkDebugf("Could not get device context.\n");
+ this->destroyGLContext();
+ return NULL;
+ }
+
+ PIXELFORMATDESCRIPTOR pfd;
+ ZeroMemory(&pfd, sizeof(pfd));
+ pfd.nSize = sizeof(pfd);
+ pfd.nVersion = 1;
+ pfd.dwFlags = PFD_SUPPORT_OPENGL;
+ pfd.iPixelType = PFD_TYPE_RGBA;
+ pfd.cColorBits = 32;
+ pfd.cDepthBits = 0;
+ pfd.cStencilBits = 0;
+ pfd.iLayerType = PFD_MAIN_PLANE;
+
+ int pixelFormat = 0;
+ if (!(pixelFormat = ChoosePixelFormat(fDeviceContext, &pfd))) {
+ SkDebugf("No matching pixel format descriptor.\n");
+ this->destroyGLContext();
+ return NULL;
+ }
+
+ if (!SetPixelFormat(fDeviceContext, pixelFormat, &pfd)) {
+ SkDebugf("Could not set the pixel format %d.\n", pixelFormat);
+ this->destroyGLContext();
+ return NULL;
+ }
+
+ if (!(fGlRenderContext = wglCreateContext(fDeviceContext))) {
+ SkDebugf("Could not create rendering context.\n");
+ this->destroyGLContext();
+ return NULL;
+ }
+
+ if (!(wglMakeCurrent(fDeviceContext, fGlRenderContext))) {
+ SkDebugf("Could not set the context.\n");
+ this->destroyGLContext();
+ return NULL;
+ }
+ const GrGLInterface* interface = GrGLCreateNativeInterface();
+ if (NULL == interface) {
+ SkDebugf("Could not create GL interface.\n");
+ this->destroyGLContext();
+ return NULL;
+ }
+
+ return interface;
+}
+
+void SkNativeGLContext::makeCurrent() const {
+ if (!wglMakeCurrent(fDeviceContext, fGlRenderContext)) {
+ SkDebugf("Could not create rendering context.\n");
+ }
+}
diff --git a/src/images/SkBitmap_RLEPixels.h b/src/images/SkBitmap_RLEPixels.h
index c83bc69..dfe83a2 100644
--- a/src/images/SkBitmap_RLEPixels.h
+++ b/src/images/SkBitmap_RLEPixels.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkBitmap_RLEPixels_DEFINED
#define SkBitmap_RLEPixels_DEFINED
diff --git a/src/images/SkCreateRLEPixelRef.cpp b/src/images/SkCreateRLEPixelRef.cpp
index a3bf5bc..44652be 100644
--- a/src/images/SkCreateRLEPixelRef.cpp
+++ b/src/images/SkCreateRLEPixelRef.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkChunkAlloc.h"
#include "SkPackBits.h"
#include "SkBitmap.h"
diff --git a/src/images/SkFDStream.cpp b/src/images/SkFDStream.cpp
index db4a51a..e1e214a 100644
--- a/src/images/SkFDStream.cpp
+++ b/src/images/SkFDStream.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkStream.h"
#include <unistd.h>
diff --git a/src/images/SkFlipPixelRef.cpp b/src/images/SkFlipPixelRef.cpp
index 39e1a12..e81c83c 100644
--- a/src/images/SkFlipPixelRef.cpp
+++ b/src/images/SkFlipPixelRef.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkFlipPixelRef.h"
#include "SkFlattenable.h"
#include "SkRegion.h"
@@ -74,8 +81,7 @@ SkPixelRef* SkFlipPixelRef::Create(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkFlipPixelRef, (buffer));
}
-static SkPixelRef::Registrar reg("SkFlipPixelRef",
- SkFlipPixelRef::Create);
+SK_DEFINE_PIXEL_REF_REGISTRAR(SkFlipPixelRef)
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/images/SkImageDecoder.cpp b/src/images/SkImageDecoder.cpp
index 4a790d5..ee0d6cc 100644
--- a/src/images/SkImageDecoder.cpp
+++ b/src/images/SkImageDecoder.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/images/SkImageDecoder.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkImageDecoder.h"
#include "SkBitmap.h"
@@ -234,8 +226,8 @@ bool SkImageDecoder::DecodeFile(const char file[], SkBitmap* bm,
if (stream.isValid()) {
if (SkImageDecoder::DecodeStream(&stream, bm, pref, mode, format)) {
bm->pixelRef()->setURI(file);
+ return true;
}
- return true;
}
return false;
}
diff --git a/src/images/SkImageDecoder_Factory.cpp b/src/images/SkImageDecoder_Factory.cpp
index e5ff395..f3cb120 100644
--- a/src/images/SkImageDecoder_Factory.cpp
+++ b/src/images/SkImageDecoder_Factory.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/ports/SkImageDecoder_Factory.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkImageDecoder.h"
#include "SkMovie.h"
diff --git a/src/images/SkImageDecoder_fpdfemb.cpp b/src/images/SkImageDecoder_fpdfemb.cpp
deleted file mode 100644
index 7f37e3d..0000000
--- a/src/images/SkImageDecoder_fpdfemb.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright 2007, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "SkImageDecoder.h"
-#include "SkScaledBitmapSampler.h"
-#include "SkStream.h"
-#include "SkColorPriv.h"
-#include "SkTDArray.h"
-
-#include "fpdfemb.h"
-
-class SkFPDFEMBImageDecoder : public SkImageDecoder {
-public:
- SkFPDFEMBImageDecoder() {}
-
- virtual Format getFormat() const {
- return kBMP_Format;
- }
-
-protected:
- virtual bool onDecode(SkStream* stream, SkBitmap* bm,
- SkBitmap::Config pref, Mode mode);
-
-private:
- bool render(FPDFEMB_PAGE page, const FPDFEMB_RECT& bounds, SkBitmap* bm,
- SkBitmap::Config prefConfig, SkImageDecoder::Mode mode);
-};
-
-SkImageDecoder* SkImageDecoder_FPDFEMB_Factory(SkStream*);
-SkImageDecoder* SkImageDecoder_FPDFEMB_Factory(SkStream* stream) {
- static const char kPDFSig[] = { '%', 'P', 'D', 'F' };
-
- size_t len = stream->getLength();
- char buffer[sizeof(kPDFSig)];
-
- SkDebugf("---- SkImageDecoder_FPDFEMB_Factory len=%d\n", len);
-
- if (len != 12683) { return NULL; }
-
- if (len > sizeof(kPDFSig) &&
- stream->read(buffer, sizeof(kPDFSig)) == sizeof(kPDFSig) &&
- !memcmp(buffer, kPDFSig, sizeof(kPDFSig))) {
- return SkNEW(SkFPDFEMBImageDecoder);
- }
- return NULL;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-extern "C" {
- static void* pdf_alloc(FPDFEMB_MEMMGR* pMgr, unsigned int size) {
- void* addr = sk_malloc_throw(size);
- // SkDebugf("---- pdf_alloc %d %p\n", size, addr);
- return addr;
- }
-
- static void* pdf_alloc_nl(FPDFEMB_MEMMGR* pMgr, unsigned int size) {
- void* addr = sk_malloc_flags(size, 0);
- // SkDebugf("---- pdf_alloc_nl %d %p\n", size, addr);
- return addr;
- }
-
- static void* pdf_realloc(FPDFEMB_MEMMGR*, void* addr, unsigned int size) {
- void* newaddr = sk_realloc_throw(addr, size);
- // SkDebugf("---- pdf_realloc %p %d %p\n", addr, size, newaddr);
- return newaddr;
- }
-
- static void pdf_free(FPDFEMB_MEMMGR* pMgr, void* pointer) {
- // SkDebugf("---- pdf_free %p\n", pointer);
- sk_free(pointer);
- }
-
- void FX_OUTPUT_LOG_FUNC(const char* format, ...) {
- SkDebugf("---- LOG_FUNC %s\n", format);
- }
-
- static unsigned int file_getsize(FPDFEMB_FILE_ACCESS* file) {
- SkStream* stream = (SkStream*)file->user;
- return stream->getLength();
- }
-
- static FPDFEMB_RESULT file_readblock(FPDFEMB_FILE_ACCESS* file, void* dst,
- unsigned int offset, unsigned int size) {
- SkStream* stream = (SkStream*)file->user;
-// SkDebugf("---- readblock %p %p %d %d\n", stream, dst, offset, size);
- if (!stream->rewind()) {
- SkDebugf("---- rewind failed\n");
- return FPDFERR_ERROR;
- }
- if (stream->skip(offset) != offset) {
- SkDebugf("---- skip failed\n");
- return FPDFERR_ERROR;
- }
- if (stream->read(dst, size) != size) {
- SkDebugf("---- read failed\n");
- return FPDFERR_ERROR;
- }
- return FPDFERR_SUCCESS;
- }
-
- static void pdf_oom_handler(void* memory, int size) {
- SkDebugf("======== pdf OOM %p %d\n", memory, size);
- }
-}
-
-static inline int PDF2Pixels(int x) { return x / 100; }
-static inline SkScalar PDF2Scalar(int x) {
- return SkScalarMulDiv(SK_Scalar1, x, 100);
-}
-
-bool SkFPDFEMBImageDecoder::render(FPDFEMB_PAGE page, const FPDFEMB_RECT& bounds, SkBitmap* bm,
- SkBitmap::Config prefConfig, SkImageDecoder::Mode mode) {
- int width = PDF2Pixels(bounds.right - bounds.left);
- int height = PDF2Pixels(bounds.top - bounds.bottom);
-
- SkDebugf("----- bitmap size [%d %d], mode=%d\n", width, height, mode);
- bm->setConfig(SkBitmap::kARGB_8888_Config, width, height);
- if (SkImageDecoder::kDecodeBounds_Mode == mode) {
- return true;
- }
-
- // USE THE CODEC TO ALLOCATE THE PIXELS!!!!
- if (!this->allocPixelRef(bm, NULL)) {
- SkDebugf("----- failed to alloc pixels\n");
- return false;
- }
-
- bm->eraseColor(0);
-
- FPDFEMB_RESULT result;
- FPDFEMB_BITMAP dib;
-
- result = FPDFEMB_CreateDIB(width, height, FPDFDIB_BGRA, bm->getPixels(),
- bm->rowBytes(), &dib);
- SkDebugf("---- createdib %d\n", result);
-
- result = FPDFEMB_StartRender(dib, page, 0, 0, width, height, 0, 0, NULL, NULL);
- SkDebugf("---- render %d\n", result);
-
- result = FPDFEMB_DestroyDIB(dib);
- SkDebugf("---- destroydib %d\n", result);
-
- SkPMColor* dst = bm->getAddr32(0, 0);
- const uint8_t* src = (uint8_t*)dst;
- int n = bm->getSize() >> 2;
- for (int i = 0; i < n; i++) {
- int b = *src++;
- int g = *src++;
- int r = *src++;
- int a = *src++;
- *dst++ = SkPackARGB32(a, r, g, b);
- }
-
- return true;
-}
-
-#define USE_FIXED_MEM (4 * 1024 * 1024)
-
-bool SkFPDFEMBImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
- SkBitmap::Config prefConfig, Mode mode) {
-
- FPDFEMB_RESULT result;
-#ifdef USE_FIXED_MEM
- SkAutoMalloc storage(USE_FIXED_MEM);
- result = FPDFEMB_InitFixedMemory(storage.get(), USE_FIXED_MEM,
- pdf_oom_handler);
-#else
- FPDFEMB_MEMMGR memmgr;
- memmgr.Alloc = pdf_alloc;
- memmgr.AllocNL = pdf_alloc_nl;
- memmgr.Realloc = pdf_realloc;
- memmgr.Free = pdf_free;
-
- result = FPDFEMB_Init(&memmgr);
-#endif
- SkDebugf("----- SkImageDecoder_FPDFEMB_Factory init %d, streamLen = %d\n", result, stream->getLength());
-
- FPDFEMB_FILE_ACCESS file;
- file.GetSize = file_getsize;
- file.ReadBlock = file_readblock;
- file.user = stream;
-
- FPDFEMB_DOCUMENT document;
- result = FPDFEMB_StartLoadDocument(&file, NULL, &document, NULL);
- SkDebugf("----- SkImageDecoder_FPDFEMB_Factory open %d %p\n", result, document);
-
- int pageCount = FPDFEMB_GetPageCount(document);
- SkDebugf("----- SkImageDecoder_FPDFEMB_Factory pageCount %d\n", pageCount);
-
- if (pageCount > 0) {
- FPDFEMB_PAGE page;
- result = FPDFEMB_LoadPage(document, 0, &page);
- SkDebugf("----- SkImageDecoder_FPDFEMB_Factory load page %d\n", result);
-
- int width, height;
- result = FPDFEMB_GetPageSize(page, &width, &height);
- SkDebugf("----- SkImageDecoder_FPDFEMB_Factory page size %d [%d %d]\n", result, width, height);
-
- FPDFEMB_RECT rect;
- result = FPDFEMB_GetPageBBox(page, &rect);
- SkDebugf("----- SkImageDecoder_FPDFEMB_Factory page rect %d [%d %d %d %d]\n", result,
- rect.left, rect.top, rect.right, rect.bottom);
-
- SkDebugf("----- SkImageDecoder_FPDFEMB_Factory begin page parse...\n");
- result = FPDFEMB_StartParse(page, false, NULL);
- SkDebugf("----- SkImageDecoder_FPDFEMB_Factory page parse %d\n", result);
-
- if (0 == result) {
- this->render(page, rect, bm, prefConfig, mode);
- }
-
- result = FPDFEMB_ClosePage(page);
- SkDebugf("----- SkImageDecoder_FPDFEMB_Factory close page %d\n", result);
- }
-
- result = FPDFEMB_CloseDocument(document);
- SkDebugf("----- SkImageDecoder_FPDFEMB_Factory close %d\n", result);
-
- // FPDFEMB_Exit();
-
- return true;
-}
diff --git a/src/images/SkImageDecoder_libbmp.cpp b/src/images/SkImageDecoder_libbmp.cpp
index 30bfbdb..b5e49e8 100644
--- a/src/images/SkImageDecoder_libbmp.cpp
+++ b/src/images/SkImageDecoder_libbmp.cpp
@@ -1,18 +1,11 @@
+
/*
- * Copyright 2007, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2007 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "bmpdecoderhelper.h"
#include "SkImageDecoder.h"
diff --git a/src/images/SkImageDecoder_libgif.cpp b/src/images/SkImageDecoder_libgif.cpp
index 75a9ee0..7a451a0 100644
--- a/src/images/SkImageDecoder_libgif.cpp
+++ b/src/images/SkImageDecoder_libgif.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/images/SkImageDecoder_libgif.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkImageDecoder.h"
#include "SkColor.h"
diff --git a/src/images/SkImageDecoder_libico.cpp b/src/images/SkImageDecoder_libico.cpp
index 45d863a..bb6bc95 100644
--- a/src/images/SkImageDecoder_libico.cpp
+++ b/src/images/SkImageDecoder_libico.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/images/SkImageDecoder_libico.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkImageDecoder.h"
#include "SkStream.h"
@@ -32,6 +24,11 @@ protected:
virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
};
+SkImageDecoder* SkCreateICOImageDecoder();
+SkImageDecoder* SkCreateICOImageDecoder() {
+ return new SkICOImageDecoder;
+}
+
/////////////////////////////////////////////////////////////////////////////////////////
//read bytes starting from the begin-th index in the buffer
diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp
index 89ee9eb..8d87450 100644
--- a/src/images/SkImageDecoder_libjpeg.cpp
+++ b/src/images/SkImageDecoder_libjpeg.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright 2007, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2007 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkImageDecoder.h"
#include "SkImageEncoder.h"
#include "SkJpegUtility.h"
@@ -32,7 +25,7 @@ extern "C" {
#include "jerror.h"
}
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
#include <cutils/properties.h>
// Key to lookup the size of memory buffer set in system property
@@ -122,7 +115,7 @@ private:
jpeg_decompress_struct* cinfo_ptr;
};
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
/* Check if the memory cap property is set.
If so, use the memory size for jpeg decode.
*/
@@ -218,7 +211,7 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
jpeg_create_decompress(&cinfo);
autoClean.set(&cinfo);
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
overwrite_mem_buffer_size(&cinfo);
#endif
@@ -421,7 +414,7 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
return return_false(cinfo, *bm, "sampler.begin");
}
- uint8_t* srcRow = (uint8_t*)srcStorage.alloc(cinfo.output_width * 4);
+ uint8_t* srcRow = (uint8_t*)srcStorage.reset(cinfo.output_width * 4);
// Possibly skip initial rows [sampler.srcY0]
if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) {
@@ -491,7 +484,7 @@ bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream,
cinfo->do_fancy_upsampling = 0;
cinfo->do_block_smoothing = 0;
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
overwrite_mem_buffer_size(cinfo);
#endif
@@ -516,7 +509,7 @@ bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream,
// Init decoder to image decode mode
jpeg_create_decompress(cinfo);
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
overwrite_mem_buffer_size(cinfo);
#endif
@@ -669,7 +662,7 @@ bool SkJPEGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect region) {
return return_false(*cinfo, *bitmap, "sampler.begin");
}
- uint8_t* srcRow = (uint8_t*)srcStorage.alloc(width * 4);
+ uint8_t* srcRow = (uint8_t*)srcStorage.reset(width * 4);
// Possibly skip initial rows [sampler.srcY0]
if (!skip_src_rows_tile(cinfo, index->index, srcRow, sampler.srcY0())) {
@@ -919,7 +912,7 @@ protected:
jpeg_start_compress(&cinfo, TRUE);
const int width = bm.width();
- uint8_t* oneRowP = (uint8_t*)oneRow.alloc(width * 3);
+ uint8_t* oneRowP = (uint8_t*)oneRow.reset(width * 3);
const SkPMColor* colors = ctLocker.lockColors(bm);
const void* srcRow = bm.getPixels();
diff --git a/src/images/SkImageDecoder_libpng.cpp b/src/images/SkImageDecoder_libpng.cpp
index 5cd86f7..138c28c 100644
--- a/src/images/SkImageDecoder_libpng.cpp
+++ b/src/images/SkImageDecoder_libpng.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/images/SkImageDecoder_libpng.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkImageDecoder.h"
#include "SkImageEncoder.h"
@@ -1006,6 +998,11 @@ static inline int pack_palette(SkColorTable* ctable,
class SkPNGImageEncoder : public SkImageEncoder {
protected:
virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
+private:
+ bool doEncode(SkWStream* stream, const SkBitmap& bm,
+ const bool& hasAlpha, int colorType,
+ int bitDepth, SkBitmap::Config config,
+ png_color_8& sig_bit);
};
bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap,
@@ -1068,6 +1065,15 @@ bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap,
bitDepth = computeBitDepth(ctable->count());
}
+ return doEncode(stream, bitmap, hasAlpha, colorType,
+ bitDepth, config, sig_bit);
+}
+
+bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap,
+ const bool& hasAlpha, int colorType,
+ int bitDepth, SkBitmap::Config config,
+ png_color_8& sig_bit) {
+
png_structp png_ptr;
png_infop info_ptr;
diff --git a/src/images/SkImageDecoder_libpvjpeg.cpp b/src/images/SkImageDecoder_libpvjpeg.cpp
deleted file mode 100644
index b98763e..0000000
--- a/src/images/SkImageDecoder_libpvjpeg.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-#include "SkImageDecoder.h"
-#include "SkColor.h"
-#include "SkColorPriv.h"
-#include "SkDither.h"
-#include "SkMath.h"
-#include "SkStream.h"
-#include "SkTemplates.h"
-#include "SkUtils.h"
-
-extern void ValidateHeap();
-
-class SkPVJPEGImageDecoder : public SkImageDecoder {
-protected:
- virtual bool onDecode(SkStream* stream, SkBitmap* bm,
- SkBitmap::Config pref, Mode);
-
-private:
- enum {
- STORAGE_SIZE = 8 * 1024
- };
- char fStorage[STORAGE_SIZE];
-};
-
-SkImageDecoder* SkImageDecoder_PVJPEG_Factory(SkStream* stream)
-{
- return SkNEW(SkPVJPEGImageDecoder);
-}
-
-#include "pvjpgdecoderinterface.h"
-#include "pvjpgdecoder_factory.h"
-
-class AutoPVDelete {
-public:
- AutoPVDelete(PVJpgDecoderInterface* codec) : fCodec(codec) {}
- ~AutoPVDelete() {
- fCodec->Reset();
- PVJpgDecoderFactory::DeletePVJpgDecoder(fCodec);
- }
-private:
- PVJpgDecoderInterface* fCodec;
-};
-
-class MyObserver : public MPVJpegDecObserver {
-public:
- MyObserver() : fCount(0) {}
- ~MyObserver() {
- if (fCount != 0) {
- SkDebugf("--- pvjpeg left %d allocations\n", fCount);
- }
- }
-
- virtual void allocateBuffer(uint8* &buffer, int32 buffersize) {
- ++fCount;
- // we double the allocation to work around bug when height is odd
- buffer = (uint8*)sk_malloc_throw(buffersize << 1);
- SkDebugf("--- pvjpeg alloc [%d] %d addr=%p\n", fCount, buffersize, buffer);
- }
-
- virtual void deallocateBuffer(uint8 *buffer) {
- SkDebugf("--- pvjpeg free [%d] addr=%p\n", fCount, buffer);
- --fCount;
- sk_free(buffer);
- }
-
-private:
- int fCount;
-};
-
-static void check_status(TPvJpgDecStatus status) {
- if (TPVJPGDEC_SUCCESS != status) {
- SkDEBUGF(("--- pvjpeg status %d\n", status));
- }
-}
-
-static bool getFrame(PVJpgDecoderInterface* codec, SkBitmap* bitmap,
- SkBitmap::Config prefConfig, SkImageDecoder::Mode mode) {
- TPvJpgDecInfo info;
- TPvJpgDecStatus status = codec->GetInfo(&info);
- if (status != TPVJPGDEC_SUCCESS)
- return false;
-
- int width = info.iWidth[0];
- int height = info.iHeight[0];
-
- bitmap->setConfig(SkBitmap::kRGB_565_Config, width, height);
- bitmap->setIsOpaque(true);
-
- if (SkImageDecoder::kDecodeBounds_Mode == mode) {
- return true;
- }
-
- SkASSERT(info.iNumComponent == 3);
-
- TPvJpgDecOutputFmt format;
- format.iColorFormat = TPV_COLORFMT_RGB16;
- format.iCropped.topLeftX = 0;
- format.iCropped.topLeftY = 0;
- format.iCropped.bottomRightX = width - 1;
- format.iCropped.bottomRightY = height - 1;
- format.iOutputPitch = bitmap->rowBytes() >> 1;
- status = codec->SetOutput(&format);
- if (status != TPVJPGDEC_SUCCESS) {
- SkDebugf("--- PV SetOutput failed %d\n", status);
- return false;
- }
-
- TPvJpgDecFrame frame;
- uint8* ptrs[3];
- int32 widths[3], heights[3];
- sk_bzero(ptrs, sizeof(ptrs));
- frame.ptr = ptrs;
- frame.iWidth = widths;
- frame.iHeight = heights;
-
- status = codec->GetFrame(&frame);
- if (status != TPVJPGDEC_SUCCESS) {
- SkDebugf("--- PV GetFrame failed %d\n", status);
- return false;
- }
-
- bitmap->allocPixels();
- memcpy(bitmap->getPixels(), ptrs[0], bitmap->getSize());
- return true;
-}
-
-class OsclCleanupper {
-public:
- OsclCleanupper() {
- OsclBase::Init();
- OsclErrorTrap::Init();
- OsclMem::Init();
- }
- ~OsclCleanupper() {
- OsclMem::Cleanup();
- OsclErrorTrap::Cleanup();
- OsclBase::Cleanup();
- }
-};
-
-bool SkPVJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
- SkBitmap::Config prefConfig, Mode mode)
-{
- // do I need this guy?
- OsclCleanupper oc;
-
- PVJpgDecoderInterface* codec = PVJpgDecoderFactory::CreatePVJpgDecoder();
- TPvJpgDecStatus status = codec->Init();
- check_status(status);
-
- MyObserver observer; // must create before autopvdelete
- AutoPVDelete ad(codec);
-
- status = codec->SetObserver(&observer);
- check_status(status);
-
- char* storage = fStorage;
- int32 bytesInStorage = 0;
- for (;;)
- {
- int32 bytesRead = stream->read(storage + bytesInStorage,
- STORAGE_SIZE - bytesInStorage);
- if (bytesRead <= 0) {
- SkDEBUGF(("SkPVJPEGImageDecoder: stream read returned %d\n", bytesRead));
- return false;
- }
-
- // update bytesInStorage to account for the read()
- bytesInStorage += bytesRead;
- SkASSERT(bytesInStorage <= STORAGE_SIZE);
-
- // now call Decode to eat some of the bytes
- int32 consumed = bytesInStorage;
- status = codec->Decode((uint8*)storage, &consumed);
-
- SkASSERT(bytesInStorage >= consumed);
- bytesInStorage -= consumed;
- // now bytesInStorage is the remaining unread bytes
- if (bytesInStorage > 0) { // slide the leftovers to the beginning
- SkASSERT(storage == fStorage);
- SkASSERT(consumed >= 0 && bytesInStorage >= 0);
- SkASSERT((size_t)(consumed + bytesInStorage) <= sizeof(fStorage));
- SkASSERT(sizeof(fStorage) == STORAGE_SIZE);
- // SkDebugf("-- memmov srcOffset=%d, numBytes=%d\n", consumed, bytesInStorage);
- memmove(storage, storage + consumed, bytesInStorage);
- }
-
- switch (status) {
- case TPVJPGDEC_SUCCESS:
- SkDEBUGF(("SkPVJPEGImageDecoder::Decode returned success?\n");)
- return false;
- case TPVJPGDEC_FRAME_READY:
- case TPVJPGDEC_DONE:
- return getFrame(codec, decodedBitmap, prefConfig, mode);
- case TPVJPGDEC_FAIL:
- case TPVJPGDEC_INVALID_MEMORY:
- case TPVJPGDEC_INVALID_PARAMS:
- case TPVJPGDEC_NO_IMAGE_DATA:
- SkDEBUGF(("SkPVJPEGImageDecoder: failed to decode err=%d\n", status);)
- return false;
- case TPVJPGDEC_WAITING_FOR_INPUT:
- break; // loop around and eat more from the stream
- }
- }
- return false;
-}
-
diff --git a/src/images/SkImageDecoder_wbmp.cpp b/src/images/SkImageDecoder_wbmp.cpp
index 6d63ca9..a7d910f 100644
--- a/src/images/SkImageDecoder_wbmp.cpp
+++ b/src/images/SkImageDecoder_wbmp.cpp
@@ -1,18 +1,11 @@
-/**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkImageDecoder.h"
#include "SkColor.h"
diff --git a/src/images/SkImageEncoder.cpp b/src/images/SkImageEncoder.cpp
index d359905..e05a28c 100644
--- a/src/images/SkImageEncoder.cpp
+++ b/src/images/SkImageEncoder.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright 2009, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2009 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkImageEncoder.h"
#include "SkBitmap.h"
#include "SkStream.h"
diff --git a/src/images/SkImageEncoder_Factory.cpp b/src/images/SkImageEncoder_Factory.cpp
index 0bb4d1a..2bd1113 100644
--- a/src/images/SkImageEncoder_Factory.cpp
+++ b/src/images/SkImageEncoder_Factory.cpp
@@ -1,25 +1,19 @@
+
/*
- * Copyright 2009, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2009 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkImageEncoder.h"
#include "SkTRegistry.h"
typedef SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> EncodeReg;
-template EncodeReg* EncodeReg::gHead;
+// Can't use the typedef here because of complex C++ corner cases
+template EncodeReg* SkTRegistry<SkImageEncoder*, SkImageEncoder::Type>::gHead;
#ifdef SK_ENABLE_LIBPNG
extern SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type);
@@ -41,4 +35,3 @@ SkImageEncoder* SkImageEncoder::Create(Type t) {
#endif
return NULL;
}
-
diff --git a/src/images/SkImageRef.cpp b/src/images/SkImageRef.cpp
index 7d2d416..2d53f7e 100644
--- a/src/images/SkImageRef.cpp
+++ b/src/images/SkImageRef.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkImageRef.h"
#include "SkBitmap.h"
#include "SkFlattenable.h"
diff --git a/src/images/SkImageRefPool.cpp b/src/images/SkImageRefPool.cpp
index e322507..bfa933e 100644
--- a/src/images/SkImageRefPool.cpp
+++ b/src/images/SkImageRefPool.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkImageRefPool.h"
#include "SkImageRef.h"
#include "SkThread.h"
diff --git a/src/images/SkImageRefPool.h b/src/images/SkImageRefPool.h
index b2eb7b3..d29b8db 100644
--- a/src/images/SkImageRefPool.h
+++ b/src/images/SkImageRefPool.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkImageRefPool_DEFINED
#define SkImageRefPool_DEFINED
diff --git a/src/images/SkImageRef_GlobalPool.cpp b/src/images/SkImageRef_GlobalPool.cpp
index 1f44a84..6ea42c1 100644
--- a/src/images/SkImageRef_GlobalPool.cpp
+++ b/src/images/SkImageRef_GlobalPool.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkImageRef_GlobalPool.h"
#include "SkImageRefPool.h"
#include "SkThread.h"
@@ -50,8 +57,7 @@ SkPixelRef* SkImageRef_GlobalPool::Create(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkImageRef_GlobalPool, (buffer));
}
-static SkPixelRef::Registrar reg("SkImageRef_GlobalPool",
- SkImageRef_GlobalPool::Create);
+SK_DEFINE_PIXEL_REF_REGISTRAR(SkImageRef_GlobalPool)
///////////////////////////////////////////////////////////////////////////////
// global imagerefpool wrappers
diff --git a/src/images/SkJpegUtility.cpp b/src/images/SkJpegUtility.cpp
index a2fe9a8..aa5237f 100644
--- a/src/images/SkJpegUtility.cpp
+++ b/src/images/SkJpegUtility.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2010 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkJpegUtility.h"
/////////////////////////////////////////////////////////////////////
diff --git a/src/images/SkMovie.cpp b/src/images/SkMovie.cpp
index 7186ed5..81820a5 100644
--- a/src/images/SkMovie.cpp
+++ b/src/images/SkMovie.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkMovie.h"
#include "SkCanvas.h"
#include "SkPaint.h"
diff --git a/src/images/SkMovie_gif.cpp b/src/images/SkMovie_gif.cpp
index 0a85c2d..91d3591 100644
--- a/src/images/SkMovie_gif.cpp
+++ b/src/images/SkMovie_gif.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/images/SkImageDecoder_libgif.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkMovie.h"
#include "SkColor.h"
@@ -245,7 +237,7 @@ static void drawFrame(SkBitmap* bm, const SavedImage* frame, const ColorMapObjec
}
if (cmap == NULL || cmap->ColorCount != (1 << cmap->BitsPerPixel)) {
- SkASSERT(!"bad colortable setup");
+ SkDEBUGFAIL("bad colortable setup");
return;
}
diff --git a/src/images/SkPageFlipper.cpp b/src/images/SkPageFlipper.cpp
index 526ba09..8e51e63 100644
--- a/src/images/SkPageFlipper.cpp
+++ b/src/images/SkPageFlipper.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkPageFlipper.h"
SkPageFlipper::SkPageFlipper() {
diff --git a/src/images/SkScaledBitmapSampler.cpp b/src/images/SkScaledBitmapSampler.cpp
index 32b78ef..1af433d 100644
--- a/src/images/SkScaledBitmapSampler.cpp
+++ b/src/images/SkScaledBitmapSampler.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright 2007, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2007 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkScaledBitmapSampler.h"
#include "SkBitmap.h"
#include "SkColorPriv.h"
diff --git a/src/images/SkScaledBitmapSampler.h b/src/images/SkScaledBitmapSampler.h
index 43f1669..8a735df 100644
--- a/src/images/SkScaledBitmapSampler.h
+++ b/src/images/SkScaledBitmapSampler.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkScaledBitmapSampler_DEFINED
#define SkScaledBitmapSampler_DEFINED
diff --git a/src/images/bmpdecoderhelper.cpp b/src/images/bmpdecoderhelper.cpp
index acabf44..7749664 100644
--- a/src/images/bmpdecoderhelper.cpp
+++ b/src/images/bmpdecoderhelper.cpp
@@ -1,18 +1,11 @@
+
/*
- * Copyright 2007, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2007 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
// Author: cevans@google.com (Chris Evans)
#include "bmpdecoderhelper.h"
diff --git a/src/images/bmpdecoderhelper.h b/src/images/bmpdecoderhelper.h
index 07f0ae5..f3324ee 100644
--- a/src/images/bmpdecoderhelper.h
+++ b/src/images/bmpdecoderhelper.h
@@ -1,19 +1,12 @@
+
/*
- * Copyright 2007, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2007 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef IMAGE_CODEC_BMPDECODERHELPER_H__
#define IMAGE_CODEC_BMPDECODERHELPER_H__
diff --git a/src/opts/SkBitmapProcState_opts_SSE2.cpp b/src/opts/SkBitmapProcState_opts_SSE2.cpp
index a24c6a1..9a0a013 100644
--- a/src/opts/SkBitmapProcState_opts_SSE2.cpp
+++ b/src/opts/SkBitmapProcState_opts_SSE2.cpp
@@ -1,20 +1,12 @@
+
/*
- **
- ** Copyright 2009, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
+ * Copyright 2009 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include <emmintrin.h>
#include "SkBitmapProcState_opts_SSE2.h"
#include "SkUtils.h"
diff --git a/src/opts/SkBitmapProcState_opts_SSE2.h b/src/opts/SkBitmapProcState_opts_SSE2.h
index 11d305b..9e56642 100644
--- a/src/opts/SkBitmapProcState_opts_SSE2.h
+++ b/src/opts/SkBitmapProcState_opts_SSE2.h
@@ -1,20 +1,12 @@
+
/*
- **
- ** Copyright 2009, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
+ * Copyright 2009 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkBitmapProcState.h"
void S32_opaque_D32_filter_DX_SSE2(const SkBitmapProcState& s,
diff --git a/src/opts/SkBitmapProcState_opts_arm.cpp b/src/opts/SkBitmapProcState_opts_arm.cpp
index 1084082..20d62e1 100644
--- a/src/opts/SkBitmapProcState_opts_arm.cpp
+++ b/src/opts/SkBitmapProcState_opts_arm.cpp
@@ -1,22 +1,11 @@
+
/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2009 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
-#ifdef ANDROID
- #include <machine/cpu-features.h>
-#endif
#include "SkBitmapProcState.h"
#include "SkColorPriv.h"
diff --git a/src/opts/SkBitmapProcState_opts_none.cpp b/src/opts/SkBitmapProcState_opts_none.cpp
index 868f808..82be4ea 100644
--- a/src/opts/SkBitmapProcState_opts_none.cpp
+++ b/src/opts/SkBitmapProcState_opts_none.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBitmapProcState.h"
/* A platform may optionally overwrite any of these with accelerated
diff --git a/src/opts/SkBlitRow_opts_SSE2.cpp b/src/opts/SkBlitRow_opts_SSE2.cpp
index 4f69fdd..f03468f 100644
--- a/src/opts/SkBlitRow_opts_SSE2.cpp
+++ b/src/opts/SkBlitRow_opts_SSE2.cpp
@@ -1,20 +1,12 @@
+
/*
- **
- ** Copyright 2009, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
+ * Copyright 2009 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkBlitRow_opts_SSE2.h"
#include "SkColorPriv.h"
#include "SkUtils.h"
@@ -326,6 +318,7 @@ void Color32_SSE2(SkPMColor dst[], const SkPMColor src[], int count,
if (src != dst) {
memcpy(dst, src, count * sizeof(SkPMColor));
}
+ return;
}
unsigned colorA = SkGetPackedA32(color);
@@ -391,15 +384,15 @@ void Color32_SSE2(SkPMColor dst[], const SkPMColor src[], int count,
}
}
-void SkARGB32_BlitMask_SSE2(void* device, size_t dstRB,
- SkBitmap::Config dstConfig, const uint8_t* mask,
- size_t maskRB, SkColor origColor,
- int width, int height)
+void SkARGB32_A8_BlitMask_SSE2(void* device, size_t dstRB, const void* maskPtr,
+ size_t maskRB, SkColor origColor,
+ int width, int height)
{
SkPMColor color = SkPreMultiplyColor(origColor);
size_t dstOffset = dstRB - (width << 2);
size_t maskOffset = maskRB - width;
SkPMColor* dst = (SkPMColor *)device;
+ const uint8_t* mask = (const uint8_t*)maskPtr;
do {
int count = width;
if (count >= 4) {
diff --git a/src/opts/SkBlitRow_opts_SSE2.h b/src/opts/SkBlitRow_opts_SSE2.h
index d861bc5..8493e7a 100644
--- a/src/opts/SkBlitRow_opts_SSE2.h
+++ b/src/opts/SkBlitRow_opts_SSE2.h
@@ -1,20 +1,12 @@
+
/*
- **
- ** Copyright 2009, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
+ * Copyright 2009 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkBlitRow.h"
void S32_Blend_BlitRow32_SSE2(SkPMColor* SK_RESTRICT dst,
@@ -28,7 +20,6 @@ void S32A_Opaque_BlitRow32_SSE2(SkPMColor* SK_RESTRICT dst,
void S32A_Blend_BlitRow32_SSE2(SkPMColor* SK_RESTRICT dst,
const SkPMColor* SK_RESTRICT src,
int count, U8CPU alpha);
-void SkARGB32_BlitMask_SSE2(void* device, size_t dstRB,
- SkBitmap::Config dstConfig, const uint8_t* mask,
- size_t maskRB, SkColor color,
- int width, int height);
+void SkARGB32_A8_BlitMask_SSE2(void* device, size_t dstRB, const void* mask,
+ size_t maskRB, SkColor color,
+ int width, int height);
diff --git a/src/opts/SkBlitRow_opts_arm.cpp b/src/opts/SkBlitRow_opts_arm.cpp
index fdc89ac..6d1ce79 100644
--- a/src/opts/SkBlitRow_opts_arm.cpp
+++ b/src/opts/SkBlitRow_opts_arm.cpp
@@ -1,25 +1,13 @@
/*
- **
- ** Copyright 2009, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
+ * Copyright 2009 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
-#ifdef ANDROID
- #include <machine/cpu-features.h>
-#endif
#include "SkBlitRow.h"
+#include "SkBlitMask.h"
#include "SkColorPriv.h"
#include "SkDither.h"
@@ -1000,7 +988,7 @@ static void S32A_D565_Opaque_Dither_neon (uint16_t * SK_RESTRICT dst,
/* calculate 'd', which will be 0..7 */
/* dbase[] is 0..7; alpha is 0..256; 16 bits suffice */
-#if ANDROID
+#if defined(SK_BUILD_FOR_ANDROID)
/* SkAlpha255To256() semantic a+1 vs a+a>>7 */
alpha8 = vaddw_u8(vmovl_u8(sa), vdup_n_u8(1));
#else
@@ -1317,9 +1305,16 @@ SkBlitRow::ColorProc SkBlitRow::PlatformColorProc() {
return NULL;
}
+///////////////////////////////////////////////////////////////////////////////
-SkBlitMask::Proc SkBlitMask::PlatformProcs(SkBitmap::Config dstConfig,
- SkColor color)
-{
- return NULL;
+SkBlitMask::ColorProc SkBlitMask::PlatformColorProcs(SkBitmap::Config dstConfig,
+ SkMask::Format maskFormat,
+ SkColor color) {
+ return NULL;
+}
+
+SkBlitMask::RowProc SkBlitMask::PlatformRowProcs(SkBitmap::Config dstConfig,
+ SkMask::Format maskFormat,
+ RowFlags flags) {
+ return NULL;
}
diff --git a/src/opts/SkBlitRow_opts_none.cpp b/src/opts/SkBlitRow_opts_none.cpp
index 0fa098e..d58d2ea 100644
--- a/src/opts/SkBlitRow_opts_none.cpp
+++ b/src/opts/SkBlitRow_opts_none.cpp
@@ -1,4 +1,12 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkBlitRow.h"
+#include "SkBlitMask.h"
// Platform impl of Platform_procs with no overrides
@@ -18,9 +26,17 @@ SkBlitRow::ColorProc SkBlitRow::PlatformColorProc() {
return NULL;
}
+///////////////////////////////////////////////////////////////////////////////
-SkBlitMask::Proc SkBlitMask::PlatformProcs(SkBitmap::Config dstConfig,
- SkColor color)
-{
+SkBlitMask::ColorProc SkBlitMask::PlatformColorProcs(SkBitmap::Config dstConfig,
+ SkMask::Format maskFormat,
+ SkColor color) {
return NULL;
}
+
+SkBlitMask::RowProc SkBlitMask::PlatformRowProcs(SkBitmap::Config dstConfig,
+ SkMask::Format maskFormat,
+ RowFlags flags) {
+ return NULL;
+}
+
diff --git a/src/opts/SkUtils_opts_SSE2.cpp b/src/opts/SkUtils_opts_SSE2.cpp
index 0537033..63e7f2c 100644
--- a/src/opts/SkUtils_opts_SSE2.cpp
+++ b/src/opts/SkUtils_opts_SSE2.cpp
@@ -1,20 +1,12 @@
+
/*
- **
- ** Copyright 2009, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
+ * Copyright 2009 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include <emmintrin.h>
#include "SkUtils_opts_SSE2.h"
diff --git a/src/opts/SkUtils_opts_SSE2.h b/src/opts/SkUtils_opts_SSE2.h
index a54e82f..771656f 100644
--- a/src/opts/SkUtils_opts_SSE2.h
+++ b/src/opts/SkUtils_opts_SSE2.h
@@ -1,20 +1,12 @@
+
/*
- **
- ** Copyright 2009, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
+ * Copyright 2009 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkTypes.h"
void sk_memset16_SSE2(uint16_t *dst, uint16_t value, int count);
diff --git a/src/opts/SkUtils_opts_none.cpp b/src/opts/SkUtils_opts_none.cpp
index 108ce9c..286f10d 100644
--- a/src/opts/SkUtils_opts_none.cpp
+++ b/src/opts/SkUtils_opts_none.cpp
@@ -1,20 +1,12 @@
+
/*
- **
- ** Copyright 2009, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
+ * Copyright 2009 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkUtils.h"
SkMemset16Proc SkMemset16GetPlatformProc() {
diff --git a/src/opts/memset.arm.S b/src/opts/memset.arm.S
index 04a7027..bc0c060 100644
--- a/src/opts/memset.arm.S
+++ b/src/opts/memset.arm.S
@@ -1,17 +1,8 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright 2010 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
/* Changes:
@@ -41,6 +32,10 @@ arm_memset16:
.fnstart
push {lr}
+ /* Multiply count by 2 - go from the number of 16-bit shorts
+ * to the number of bytes desired. */
+ mov r2, r2, lsl #1
+
/* expand the data to 32 bits */
orr r1, r1, lsl #16
@@ -49,10 +44,6 @@ arm_memset16:
strneh r1, [r0], #2
subne r2, r2, #2
- /* Multiply count by 2 - go from the number of 16-bit shorts
- * to the number of bytes desired. */
- mov r2, r2, lsl #1
-
/* Now jump into the main loop below. */
b .Lwork_32
.fnend
diff --git a/src/opts/memset16_neon.S b/src/opts/memset16_neon.S
index b47cc22..b1719fa 100644
--- a/src/opts/memset16_neon.S
+++ b/src/opts/memset16_neon.S
@@ -1,17 +1,8 @@
/***************************************************************************
- Copyright (c) 2009,2010, Code Aurora Forum. All rights reserved.
-
- Licensed under the Apache License, Version 2.0 (the "License"); you
- may not use this file except in compliance with the License. You may
- obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied. See the License for the specific language governing
- permissions and limitations under the License.
+ * Copyright (c) 2009,2010, Code Aurora Forum. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
***************************************************************************/
/***************************************************************************
diff --git a/src/opts/memset32_neon.S b/src/opts/memset32_neon.S
index 9052c4f..a9eaa0e 100644
--- a/src/opts/memset32_neon.S
+++ b/src/opts/memset32_neon.S
@@ -1,17 +1,8 @@
/***************************************************************************
- Copyright (c) 2009,2010, Code Aurora Forum. All rights reserved.
-
- Licensed under the Apache License, Version 2.0 (the "License"); you
- may not use this file except in compliance with the License. You may
- obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied. See the License for the specific language governing
- permissions and limitations under the License.
+ * Copyright (c) 2009,2010, Code Aurora Forum. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
***************************************************************************/
.code 32
diff --git a/src/opts/opts_check_SSE2.cpp b/src/opts/opts_check_SSE2.cpp
index 749117a..00497c9 100644
--- a/src/opts/opts_check_SSE2.cpp
+++ b/src/opts/opts_check_SSE2.cpp
@@ -1,21 +1,12 @@
/*
- **
- ** Copyright 2009, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
+ * Copyright 2009 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
#include "SkBitmapProcState_opts_SSE2.h"
+#include "SkBlitMask.h"
#include "SkBlitRow_opts_SSE2.h"
#include "SkUtils_opts_SSE2.h"
#include "SkUtils.h"
@@ -64,8 +55,13 @@ static inline bool hasSSE2() {
}
#endif
+static bool cachedHasSSE2() {
+ static bool gHasSSE2 = hasSSE2();
+ return gHasSSE2;
+}
+
void SkBitmapProcState::platformProcs() {
- if (hasSSE2()) {
+ if (cachedHasSSE2()) {
if (fSampleProc32 == S32_opaque_D32_filter_DX) {
fSampleProc32 = S32_opaque_D32_filter_DX_SSE2;
} else if (fSampleProc32 == S32_alpha_D32_filter_DX) {
@@ -90,7 +86,7 @@ SkBlitRow::Proc SkBlitRow::PlatformProcs565(unsigned flags) {
}
SkBlitRow::ColorProc SkBlitRow::PlatformColorProc() {
- if (hasSSE2()) {
+ if (cachedHasSSE2()) {
return Color32_SSE2;
} else {
return NULL;
@@ -98,7 +94,7 @@ SkBlitRow::ColorProc SkBlitRow::PlatformColorProc() {
}
SkBlitRow::Proc32 SkBlitRow::PlatformProcs32(unsigned flags) {
- if (hasSSE2()) {
+ if (cachedHasSSE2()) {
return platform_32_procs[flags];
} else {
return NULL;
@@ -106,28 +102,38 @@ SkBlitRow::Proc32 SkBlitRow::PlatformProcs32(unsigned flags) {
}
-SkBlitMask::Proc SkBlitMask::PlatformProcs(SkBitmap::Config dstConfig,
- SkColor color)
-{
-
- SkBlitMask::Proc proc = NULL;
- if (hasSSE2()) {
+SkBlitMask::ColorProc SkBlitMask::PlatformColorProcs(SkBitmap::Config dstConfig,
+ SkMask::Format maskFormat,
+ SkColor color) {
+ if (SkMask::kA8_Format != maskFormat) {
+ return NULL;
+ }
+
+ ColorProc proc = NULL;
+ if (cachedHasSSE2()) {
switch (dstConfig) {
case SkBitmap::kARGB_8888_Config:
- // TODO: is our current SSE2 faster than the portable, even in
- // the case of black or opaque? If so, no need for this check.
- if ( SK_ColorBLACK != color && 0xFF != SkColorGetA(color))
- proc = SkARGB32_BlitMask_SSE2;
+ // The SSE2 version is not (yet) faster for black, so we check
+ // for that.
+ if (SK_ColorBLACK != color) {
+ proc = SkARGB32_A8_BlitMask_SSE2;
+ }
break;
default:
- break;
+ break;
}
}
return proc;
}
+SkBlitMask::RowProc SkBlitMask::PlatformRowProcs(SkBitmap::Config dstConfig,
+ SkMask::Format maskFormat,
+ RowFlags flags) {
+ return NULL;
+}
+
SkMemset16Proc SkMemset16GetPlatformProc() {
- if (hasSSE2()) {
+ if (cachedHasSSE2()) {
return sk_memset16_SSE2;
} else {
return NULL;
@@ -135,7 +141,7 @@ SkMemset16Proc SkMemset16GetPlatformProc() {
}
SkMemset32Proc SkMemset32GetPlatformProc() {
- if (hasSSE2()) {
+ if (cachedHasSSE2()) {
return sk_memset32_SSE2;
} else {
return NULL;
diff --git a/src/opts/opts_check_arm.cpp b/src/opts/opts_check_arm.cpp
index 4fcea2d..49e3096 100644
--- a/src/opts/opts_check_arm.cpp
+++ b/src/opts/opts_check_arm.cpp
@@ -1,18 +1,9 @@
/***************************************************************************
- Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- Copyright 2006-2010, The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License"); you
- may not use this file except in compliance with the License. You may
- obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied. See the License for the specific language governing
- permissions and limitations under the License.
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ * Copyright 2006-2010, The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
***************************************************************************/
/* Changes:
@@ -24,40 +15,32 @@
#include "SkUtils.h"
+#if defined(__ARM_HAVE_NEON) && defined(SK_CPU_LENDIAN)
extern "C" void memset16_neon(uint16_t dst[], uint16_t value, int count);
extern "C" void memset32_neon(uint32_t dst[], uint32_t value, int count);
+#endif
+#if defined(SK_CPU_LENDIAN)
extern "C" void arm_memset16(uint16_t* dst, uint16_t value, int count);
extern "C" void arm_memset32(uint32_t* dst, uint32_t value, int count);
-
-static inline bool hasNeonRegisters() {
-#if defined(__ARM_HAVE_NEON) && defined(SK_CPU_LENDIAN)
- return true;
-#else
- return false;
#endif
-}
SkMemset16Proc SkMemset16GetPlatformProc() {
- if (hasNeonRegisters()) {
- return memset16_neon;
- } else {
-#if defined(SK_CPU_LENDIAN)
- return arm_memset16;
+#if defined(__ARM_HAVE_NEON) && defined(SK_CPU_LENDIAN)
+ return memset16_neon;
+//#elif defined(SK_CPU_LENDIAN)
+// return arm_memset16;
#else
- return NULL;
+ return NULL;
#endif
- }
}
SkMemset32Proc SkMemset32GetPlatformProc() {
- if (hasNeonRegisters()) {
- return memset32_neon;
- } else {
-#if defined(SK_CPU_LENDIAN)
- return arm_memset32;
+#if defined(__ARM_HAVE_NEON) && defined(SK_CPU_LENDIAN)
+ return memset32_neon;
+#elif defined(SK_CPU_LENDIAN)
+ return arm_memset32;
#else
- return NULL;
+ return NULL;
#endif
- }
}
diff --git a/src/opts/opts_files.mk b/src/opts/opts_files.mk
deleted file mode 100644
index ae8fd77..0000000
--- a/src/opts/opts_files.mk
+++ /dev/null
@@ -1,4 +0,0 @@
-SOURCE := \
- SkBlitRow_opts_none.cpp \
- SkBitmapProcState_opts_none.cpp \
- SkUtils_opts_none.cpp
diff --git a/src/opts/opts_sse2_files.mk b/src/opts/opts_sse2_files.mk
deleted file mode 100644
index 822543d..0000000
--- a/src/opts/opts_sse2_files.mk
+++ /dev/null
@@ -1,5 +0,0 @@
-SOURCE := \
- SkBlitRow_opts_SSE2.cpp \
- SkBitmapProcState_opts_SSE2.cpp \
- SkUtils_opts_SSE2.cpp \
- opts_check_SSE2.cpp
diff --git a/src/pdf/SkBitSet.cpp b/src/pdf/SkBitSet.cpp
new file mode 100755
index 0000000..664c8cd
--- /dev/null
+++ b/src/pdf/SkBitSet.cpp
@@ -0,0 +1,83 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "SkBitSet.h"
+
+SkBitSet::SkBitSet(int numberOfBits)
+ : fBitData(NULL), fDwordCount(0), fBitCount(numberOfBits) {
+ SkASSERT(numberOfBits > 0);
+ // Round up size to 32-bit boundary.
+ fDwordCount = (numberOfBits + 31) / 32;
+ fBitData.set(malloc(fDwordCount * sizeof(uint32_t)));
+ clearAll();
+}
+
+SkBitSet::SkBitSet(const SkBitSet& source)
+ : fBitData(NULL), fDwordCount(0), fBitCount(0) {
+ *this = source;
+}
+
+const SkBitSet& SkBitSet::operator=(const SkBitSet& rhs) {
+ if (this == &rhs) {
+ return *this;
+ }
+ fBitCount = rhs.fBitCount;
+ fBitData.free();
+ fDwordCount = rhs.fDwordCount;
+ fBitData.set(malloc(fDwordCount * sizeof(uint32_t)));
+ memcpy(fBitData.get(), rhs.fBitData.get(), fDwordCount * sizeof(uint32_t));
+ return *this;
+}
+
+bool SkBitSet::operator==(const SkBitSet& rhs) {
+ if (fBitCount == rhs.fBitCount) {
+ if (fBitData.get() != NULL) {
+ return (memcmp(fBitData.get(), rhs.fBitData.get(),
+ fDwordCount * sizeof(uint32_t)) == 0);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool SkBitSet::operator!=(const SkBitSet& rhs) {
+ return !(*this == rhs);
+}
+
+void SkBitSet::clearAll() {
+ if (fBitData.get() != NULL) {
+ sk_bzero(fBitData.get(), fDwordCount * sizeof(uint32_t));
+ }
+}
+
+void SkBitSet::setBit(int index, bool value) {
+ uint32_t mask = 1 << (index % 32);
+ if (value) {
+ *(internalGet(index)) |= mask;
+ } else {
+ *(internalGet(index)) &= ~mask;
+ }
+}
+
+bool SkBitSet::isBitSet(int index) const {
+ uint32_t mask = 1 << (index % 32);
+ return 0 != (*internalGet(index) & mask);
+}
+
+bool SkBitSet::orBits(const SkBitSet& source) {
+ if (fBitCount != source.fBitCount) {
+ return false;
+ }
+ uint32_t* targetBitmap = internalGet(0);
+ uint32_t* sourceBitmap = source.internalGet(0);
+ for (size_t i = 0; i < fDwordCount; ++i) {
+ targetBitmap[i] |= sourceBitmap[i];
+ }
+ return true;
+}
diff --git a/src/pdf/SkPDFCatalog.cpp b/src/pdf/SkPDFCatalog.cpp
index afa9d9a..bc22e6a 100644
--- a/src/pdf/SkPDFCatalog.cpp
+++ b/src/pdf/SkPDFCatalog.cpp
@@ -1,37 +1,37 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2010 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkPDFCatalog.h"
#include "SkPDFTypes.h"
#include "SkStream.h"
#include "SkTypes.h"
-SkPDFCatalog::SkPDFCatalog()
+SkPDFCatalog::SkPDFCatalog(SkPDFDocument::Flags flags)
: fFirstPageCount(0),
fNextObjNum(1),
- fNextFirstPageObjNum(0) {
+ fNextFirstPageObjNum(0),
+ fDocumentFlags(flags) {
}
-SkPDFCatalog::~SkPDFCatalog() {}
+SkPDFCatalog::~SkPDFCatalog() {
+ fSubstituteResourcesRemaining.safeUnrefAll();
+ fSubstituteResourcesFirstPage.safeUnrefAll();
+}
SkPDFObject* SkPDFCatalog::addObject(SkPDFObject* obj, bool onFirstPage) {
- SkASSERT(findObjectIndex(obj) == -1);
+ if (findObjectIndex(obj) != -1) { // object already added
+ return obj;
+ }
SkASSERT(fNextFirstPageObjNum == 0);
- if (onFirstPage)
+ if (onFirstPage) {
fFirstPageCount++;
+ }
struct Rec newEntry(obj, onFirstPage);
fCatalog.append(1, &newEntry);
@@ -44,7 +44,7 @@ size_t SkPDFCatalog::setFileOffset(SkPDFObject* obj, size_t offset) {
SkASSERT(fCatalog[objIndex].fFileOffset == 0);
fCatalog[objIndex].fFileOffset = offset;
- return obj->getOutputSize(this, true);
+ return getSubstituteObject(obj)->getOutputSize(this, true);
}
void SkPDFCatalog::emitObjectNumber(SkWStream* stream, SkPDFObject* obj) {
@@ -60,8 +60,15 @@ size_t SkPDFCatalog::getObjectNumberSize(SkPDFObject* obj) {
int SkPDFCatalog::findObjectIndex(SkPDFObject* obj) const {
for (int i = 0; i < fCatalog.count(); i++) {
- if (fCatalog[i].fObject == obj)
+ if (fCatalog[i].fObject == obj) {
return i;
+ }
+ }
+ // If it's not in the main array, check if it's a substitute object.
+ for (int i = 0; i < fSubstituteMap.count(); ++i) {
+ if (fSubstituteMap[i].fSubstitute == obj) {
+ return findObjectIndex(fSubstituteMap[i].fOriginal);
+ }
}
return -1;
}
@@ -72,12 +79,14 @@ int SkPDFCatalog::assignObjNum(SkPDFObject* obj) {
// to the resource list.
SkASSERT(pos >= 0);
uint32_t currentIndex = pos;
- if (fCatalog[currentIndex].fObjNumAssigned)
+ if (fCatalog[currentIndex].fObjNumAssigned) {
return currentIndex + 1;
+ }
// First assignment.
- if (fNextFirstPageObjNum == 0)
+ if (fNextFirstPageObjNum == 0) {
fNextFirstPageObjNum = fCatalog.count() - fFirstPageCount + 1;
+ }
uint32_t objNum;
if (fCatalog[currentIndex].fOnFirstPage) {
@@ -91,8 +100,9 @@ int SkPDFCatalog::assignObjNum(SkPDFObject* obj) {
// When we assign an object an object number, we put it in that array
// offset (minus 1 because object number 0 is reserved).
SkASSERT(!fCatalog[objNum - 1].fObjNumAssigned);
- if (objNum - 1 != currentIndex)
+ if (objNum - 1 != currentIndex) {
SkTSwap(fCatalog[objNum - 1], fCatalog[currentIndex]);
+ }
fCatalog[objNum - 1].fObjNumAssigned = true;
return objNum;
}
@@ -100,12 +110,12 @@ int SkPDFCatalog::assignObjNum(SkPDFObject* obj) {
int32_t SkPDFCatalog::emitXrefTable(SkWStream* stream, bool firstPage) {
int first = -1;
int last = fCatalog.count() - 1;
- // TODO(vandebo) support linearized format.
- //int last = fCatalog.count() - fFirstPageCount - 1;
- //if (firstPage) {
- // first = fCatalog.count() - fFirstPageCount;
- // last = fCatalog.count() - 1;
- //}
+ // TODO(vandebo): Support linearized format.
+ // int last = fCatalog.count() - fFirstPageCount - 1;
+ // if (firstPage) {
+ // first = fCatalog.count() - fFirstPageCount;
+ // last = fCatalog.count() - 1;
+ // }
stream->writeText("xref\n");
stream->writeDecAsText(first + 1);
@@ -126,3 +136,73 @@ int32_t SkPDFCatalog::emitXrefTable(SkWStream* stream, bool firstPage) {
return fCatalog.count() + 1;
}
+
+void SkPDFCatalog::setSubstitute(SkPDFObject* original,
+ SkPDFObject* substitute) {
+#if defined(SK_DEBUG)
+ // Sanity check: is the original already in substitute list?
+ for (int i = 0; i < fSubstituteMap.count(); ++i) {
+ if (original == fSubstituteMap[i].fSubstitute ||
+ original == fSubstituteMap[i].fOriginal) {
+ SkASSERT(false);
+ return;
+ }
+ }
+#endif
+ // Check if the original is on first page.
+ bool onFirstPage = false;
+ for (int i = 0; i < fCatalog.count(); ++i) {
+ if (fCatalog[i].fObject == original) {
+ onFirstPage = fCatalog[i].fOnFirstPage;
+ break;
+ }
+#if defined(SK_DEBUG)
+ if (i == fCatalog.count() - 1) {
+ SkASSERT(false); // original not in catalog
+ return;
+ }
+#endif
+ }
+
+ SubstituteMapping newMapping(original, substitute);
+ fSubstituteMap.append(1, &newMapping);
+
+ // Add resource objects of substitute object to catalog.
+ SkTDArray<SkPDFObject*>* targetList = getSubstituteList(onFirstPage);
+ int existingSize = targetList->count();
+ newMapping.fSubstitute->getResources(targetList);
+ for (int i = existingSize; i < targetList->count(); ++i) {
+ addObject((*targetList)[i], onFirstPage);
+ }
+}
+
+SkPDFObject* SkPDFCatalog::getSubstituteObject(SkPDFObject* object) {
+ for (int i = 0; i < fSubstituteMap.count(); ++i) {
+ if (object == fSubstituteMap[i].fOriginal) {
+ return fSubstituteMap[i].fSubstitute;
+ }
+ }
+ return object;
+}
+
+off_t SkPDFCatalog::setSubstituteResourcesOffsets(off_t fileOffset,
+ bool firstPage) {
+ SkTDArray<SkPDFObject*>* targetList = getSubstituteList(firstPage);
+ off_t offsetSum = fileOffset;
+ for (int i = 0; i < targetList->count(); ++i) {
+ offsetSum += setFileOffset((*targetList)[i], offsetSum);
+ }
+ return offsetSum - fileOffset;
+}
+
+void SkPDFCatalog::emitSubstituteResources(SkWStream *stream, bool firstPage) {
+ SkTDArray<SkPDFObject*>* targetList = getSubstituteList(firstPage);
+ for (int i = 0; i < targetList->count(); ++i) {
+ (*targetList)[i]->emit(stream, this, true);
+ }
+}
+
+SkTDArray<SkPDFObject*>* SkPDFCatalog::getSubstituteList(bool firstPage) {
+ return firstPage ? &fSubstituteResourcesFirstPage :
+ &fSubstituteResourcesRemaining;
+}
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index c6ddf39..ba88956 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -1,23 +1,17 @@
+
/*
- * Copyright (C) 2011 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2011 Google Inc.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkPDFDevice.h"
#include "SkColor.h"
#include "SkClipStack.h"
+#include "SkData.h"
#include "SkDraw.h"
#include "SkGlyphCache.h"
#include "SkPaint.h"
@@ -60,10 +54,11 @@ static SkPaint calculate_text_paint(const SkPaint& paint) {
kStdFakeBoldInterpValues,
kStdFakeBoldInterpLength);
SkScalar width = SkScalarMul(result.getTextSize(), fakeBoldScale);
- if (result.getStyle() == SkPaint::kFill_Style)
+ if (result.getStyle() == SkPaint::kFill_Style) {
result.setStyle(SkPaint::kStrokeAndFill_Style);
- else
+ } else {
width += result.getStrokeWidth();
+ }
result.setStrokeWidth(width);
}
return result;
@@ -71,30 +66,30 @@ static SkPaint calculate_text_paint(const SkPaint& paint) {
// Stolen from measure_text in SkDraw.cpp and then tweaked.
static void align_text(SkDrawCacheProc glyphCacheProc, const SkPaint& paint,
- const uint16_t* glyphs, size_t len, SkScalar* x,
- SkScalar* y, SkScalar* width) {
- if (paint.getTextAlign() == SkPaint::kLeft_Align && width == NULL)
+ const uint16_t* glyphs, size_t len,
+ SkScalar* x, SkScalar* y) {
+ if (paint.getTextAlign() == SkPaint::kLeft_Align) {
return;
+ }
SkMatrix ident;
ident.reset();
SkAutoGlyphCache autoCache(paint, &ident);
SkGlyphCache* cache = autoCache.getCache();
- const char* start = (char*)glyphs;
- const char* stop = (char*)(glyphs + len);
+ const char* start = reinterpret_cast<const char*>(glyphs);
+ const char* stop = reinterpret_cast<const char*>(glyphs + len);
SkFixed xAdv = 0, yAdv = 0;
- // TODO(vandebo) This probably needs to take kerning into account.
+ // TODO(vandebo): This probably needs to take kerning into account.
while (start < stop) {
const SkGlyph& glyph = glyphCacheProc(cache, &start, 0, 0);
xAdv += glyph.fAdvanceX;
yAdv += glyph.fAdvanceY;
};
- if (width)
- *width = SkFixedToScalar(xAdv);
- if (paint.getTextAlign() == SkPaint::kLeft_Align)
+ if (paint.getTextAlign() == SkPaint::kLeft_Align) {
return;
+ }
SkScalar xAdj = SkFixedToScalar(xAdv);
SkScalar yAdj = SkFixedToScalar(yAdv);
@@ -184,7 +179,7 @@ public:
}
void updateClip(const SkClipStack& clipStack, const SkRegion& clipRegion,
- const SkIPoint& translation);
+ const SkPoint& translation);
void updateMatrix(const SkMatrix& matrix);
void updateDrawingState(const GraphicStateEntry& state);
@@ -240,7 +235,7 @@ static void skip_clip_stack_prefix(const SkClipStack& prefix,
SkASSERT(iterEntry);
// Because of SkClipStack does internal intersection, the last clip
// entry may differ.
- if(*prefixEntry != *iterEntry) {
+ if (*prefixEntry != *iterEntry) {
SkASSERT(prefixEntry->fOp == SkRegion::kIntersect_Op);
SkASSERT(iterEntry->fOp == SkRegion::kIntersect_Op);
SkASSERT((iterEntry->fRect == NULL) ==
@@ -269,7 +264,7 @@ static void emit_clip(SkPath* clipPath, SkRect* clipRect,
if (clipPath) {
SkPDFUtils::EmitPath(*clipPath, contentStream);
clipFill = clipPath->getFillType();
- } else if (clipRect) {
+ } else {
SkPDFUtils::AppendRectangle(*clipRect, contentStream);
clipFill = SkPath::kWinding_FillType;
}
@@ -283,12 +278,12 @@ static void emit_clip(SkPath* clipPath, SkRect* clipRect,
}
}
-// TODO(vandebo) Take advantage of SkClipStack::getSaveCount(), the PDF
+// TODO(vandebo): Take advantage of SkClipStack::getSaveCount(), the PDF
// graphic state stack, and the fact that we can know all the clips used
// on the page to optimize this.
void GraphicStackState::updateClip(const SkClipStack& clipStack,
const SkRegion& clipRegion,
- const SkIPoint& translation) {
+ const SkPoint& translation) {
if (clipStack == currentEntry()->fClipStack) {
return;
}
@@ -423,6 +418,17 @@ void GraphicStackState::updateDrawingState(const GraphicStateEntry& state) {
}
}
+SkDevice* SkPDFDevice::onCreateCompatibleDevice(SkBitmap::Config config,
+ int width, int height,
+ bool isOpaque,
+ Usage usage) {
+ SkMatrix initialTransform;
+ initialTransform.reset();
+ SkISize size = SkISize::Make(width, height);
+ return SkNEW_ARGS(SkPDFDevice, (size, size, initialTransform));
+}
+
+
struct ContentEntry {
GraphicStateEntry fState;
SkDynamicMemoryWStream fContent;
@@ -475,20 +481,6 @@ private:
////////////////////////////////////////////////////////////////////////////////
-SkDevice* SkPDFDeviceFactory::newDevice(SkCanvas* c, SkBitmap::Config config,
- int width, int height, bool isOpaque,
- bool isForLayer) {
- SkMatrix initialTransform;
- initialTransform.reset();
- SkISize size = SkISize::Make(width, height);
- if (isForLayer) {
- return SkNEW_ARGS(SkPDFDevice, (size, c->getTotalClipStack(),
- c->getTotalClip()));
- } else {
- return SkNEW_ARGS(SkPDFDevice, (size, size, initialTransform));
- }
-}
-
static inline SkBitmap makeContentBitmap(const SkISize& contentSize,
const SkMatrix* initialTransform) {
SkBitmap bitmap;
@@ -496,7 +488,8 @@ static inline SkBitmap makeContentBitmap(const SkISize& contentSize,
// Compute the size of the drawing area.
SkVector drawingSize;
SkMatrix inverse;
- drawingSize.set(contentSize.fWidth, contentSize.fHeight);
+ drawingSize.set(SkIntToScalar(contentSize.fWidth),
+ SkIntToScalar(contentSize.fHeight));
initialTransform->invert(&inverse);
inverse.mapVectors(&drawingSize, 1);
SkISize size = SkSize::Make(drawingSize.fX, drawingSize.fY).toRound();
@@ -510,62 +503,74 @@ static inline SkBitmap makeContentBitmap(const SkISize& contentSize,
return bitmap;
}
+// TODO(vandebo) change pageSize to SkSize.
SkPDFDevice::SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize,
const SkMatrix& initialTransform)
- : SkDevice(NULL, makeContentBitmap(contentSize, &initialTransform), false),
+ : SkDevice(makeContentBitmap(contentSize, &initialTransform)),
fPageSize(pageSize),
fContentSize(contentSize),
- fLastContentEntry(NULL) {
+ fLastContentEntry(NULL),
+ fLastMarginContentEntry(NULL) {
// Skia generally uses the top left as the origin but PDF natively has the
// origin at the bottom left. This matrix corrects for that. But that only
// needs to be done once, we don't do it when layering.
- fInitialTransform.setTranslate(0, pageSize.fHeight);
- fInitialTransform.preScale(1, -1);
+ fInitialTransform.setTranslate(0, SkIntToScalar(pageSize.fHeight));
+ fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1);
fInitialTransform.preConcat(initialTransform);
SkIRect existingClip = SkIRect::MakeWH(this->width(), this->height());
- fExistingClipStack.clipDevRect(existingClip);
fExistingClipRegion.setRect(existingClip);
this->init();
}
+// TODO(vandebo) change layerSize to SkSize.
SkPDFDevice::SkPDFDevice(const SkISize& layerSize,
const SkClipStack& existingClipStack,
const SkRegion& existingClipRegion)
- : SkDevice(NULL, makeContentBitmap(layerSize, NULL), false),
+ : SkDevice(makeContentBitmap(layerSize, NULL)),
fPageSize(layerSize),
fContentSize(layerSize),
fExistingClipStack(existingClipStack),
fExistingClipRegion(existingClipRegion),
- fLastContentEntry(NULL) {
+ fLastContentEntry(NULL),
+ fLastMarginContentEntry(NULL) {
fInitialTransform.reset();
this->init();
}
SkPDFDevice::~SkPDFDevice() {
- this->cleanUp();
+ this->cleanUp(true);
}
void SkPDFDevice::init() {
fResourceDict = NULL;
fContentEntries.reset();
fLastContentEntry = NULL;
+ fMarginContentEntries.reset();
+ fLastMarginContentEntry = NULL;
+ fDrawingArea = kContent_DrawingArea;
+ if (fFontGlyphUsage == NULL) {
+ fFontGlyphUsage.reset(new SkPDFGlyphSetMap());
+ }
}
-SkDeviceFactory* SkPDFDevice::onNewDeviceFactory() {
- return SkNEW(SkPDFDeviceFactory);
-}
-
-void SkPDFDevice::cleanUp() {
+void SkPDFDevice::cleanUp(bool clearFontUsage) {
fGraphicStateResources.unrefAll();
fXObjectResources.unrefAll();
fFontResources.unrefAll();
fShaderResources.unrefAll();
+ if (clearFontUsage) {
+ fFontGlyphUsage->reset();
+ }
+}
+
+uint32_t SkPDFDevice::getDeviceCapabilities() {
+ return kVector_Capability;
}
void SkPDFDevice::clear(SkColor color) {
- this->cleanUp();
+ this->cleanUp(true);
this->init();
SkPaint paint;
@@ -795,9 +800,8 @@ void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
// We want the text in glyph id encoding and a writable buffer, so we end
// up making a copy either way.
size_t numGlyphs = paint.textToGlyphs(text, len, NULL);
- uint16_t* glyphIDs =
- (uint16_t*)sk_malloc_flags(numGlyphs * 2,
- SK_MALLOC_TEMP | SK_MALLOC_THROW);
+ uint16_t* glyphIDs = reinterpret_cast<uint16_t*>(
+ sk_malloc_flags(numGlyphs * 2, SK_MALLOC_TEMP | SK_MALLOC_THROW));
SkAutoFree autoFreeGlyphIDs(glyphIDs);
if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) {
paint.textToGlyphs(text, len, glyphIDs);
@@ -808,14 +812,8 @@ void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
memcpy(glyphIDs, text, len);
}
- SkScalar width;
- SkScalar* widthPtr = NULL;
- if (textPaint.isUnderlineText() || textPaint.isStrikeThruText())
- widthPtr = &width;
-
SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
- align_text(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y,
- widthPtr);
+ align_text(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y);
content.entry()->fContent.writeText("BT\n");
set_text_transform(x, y, textPaint.getTextSkewX(),
&content.entry()->fContent);
@@ -826,34 +824,16 @@ void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
size_t availableGlyphs =
font->glyphsToPDFFontEncoding(glyphIDs + consumedGlyphCount,
numGlyphs - consumedGlyphCount);
+ fFontGlyphUsage->noteGlyphUsage(font, glyphIDs + consumedGlyphCount,
+ availableGlyphs);
SkString encodedString =
- SkPDFString::formatString(glyphIDs + consumedGlyphCount,
+ SkPDFString::FormatString(glyphIDs + consumedGlyphCount,
availableGlyphs, font->multiByteGlyphs());
content.entry()->fContent.writeText(encodedString.c_str());
consumedGlyphCount += availableGlyphs;
content.entry()->fContent.writeText(" Tj\n");
}
content.entry()->fContent.writeText("ET\n");
-
- // Draw underline and/or strikethrough if the paint has them.
- // drawPosText() and drawTextOnPath() don't draw underline or strikethrough
- // because the raster versions don't. Use paint instead of textPaint
- // because we may have changed strokeWidth to do fakeBold text.
- if (paint.isUnderlineText() || paint.isStrikeThruText()) {
- SkScalar textSize = paint.getTextSize();
- SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
-
- if (paint.isUnderlineText()) {
- SkScalar top = SkScalarMulAdd(textSize, kStdUnderline_Offset, y);
- SkRect r = SkRect::MakeXYWH(x, top - height, width, height);
- drawRect(d, r, paint);
- }
- if (paint.isStrikeThruText()) {
- SkScalar top = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, y);
- SkRect r = SkRect::MakeXYWH(x, top - height, width, height);
- drawRect(d, r, paint);
- }
- }
}
void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
@@ -872,15 +852,15 @@ void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
size_t numGlyphs;
if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) {
numGlyphs = paint.textToGlyphs(text, len, NULL);
- glyphIDs = (uint16_t*)sk_malloc_flags(numGlyphs * 2,
- SK_MALLOC_TEMP | SK_MALLOC_THROW);
+ glyphIDs = reinterpret_cast<uint16_t*>(sk_malloc_flags(
+ numGlyphs * 2, SK_MALLOC_TEMP | SK_MALLOC_THROW));
glyphStorage.set(glyphIDs);
paint.textToGlyphs(text, len, glyphIDs);
textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
} else {
SkASSERT((len & 1) == 0);
numGlyphs = len / 2;
- glyphIDs = (uint16_t*)text;
+ glyphIDs = reinterpret_cast<uint16_t*>(const_cast<void*>((text)));
}
SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
@@ -894,13 +874,14 @@ void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
i--;
continue;
}
+ fFontGlyphUsage->noteGlyphUsage(font, &encodedValue, 1);
SkScalar x = pos[i * scalarsPerPos];
SkScalar y = scalarsPerPos == 1 ? constY : pos[i * scalarsPerPos + 1];
- align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y, NULL);
+ align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y);
set_text_transform(x, y, textPaint.getTextSkewX(),
&content.entry()->fContent);
SkString encodedString =
- SkPDFString::formatString(&encodedValue, 1,
+ SkPDFString::FormatString(&encodedValue, 1,
font->multiByteGlyphs());
content.entry()->fContent.writeText(encodedString.c_str());
content.entry()->fContent.writeText(" Tj\n");
@@ -914,7 +895,7 @@ void SkPDFDevice::drawTextOnPath(const SkDraw& d, const void* text, size_t len,
if (d.fClip->isEmpty()) {
return;
}
- NOT_IMPLEMENTED("drawTextOnPath", true);
+ d.drawTextOnPath((const char*)text, len, path, matrix, paint);
}
void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode,
@@ -953,9 +934,42 @@ void SkPDFDevice::drawDevice(const SkDraw& d, SkDevice* device, int x, int y,
fXObjectResources.push(xobject); // Transfer reference.
SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
&content.entry()->fContent);
+
+ // Merge glyph sets from the drawn device.
+ fFontGlyphUsage->merge(pdfDevice->getFontGlyphUsage());
}
-const SkRefPtr<SkPDFDict>& SkPDFDevice::getResourceDict() {
+ContentEntry* SkPDFDevice::getLastContentEntry() {
+ if (fDrawingArea == kContent_DrawingArea) {
+ return fLastContentEntry;
+ } else {
+ return fLastMarginContentEntry;
+ }
+}
+
+SkTScopedPtr<ContentEntry>* SkPDFDevice::getContentEntries() {
+ if (fDrawingArea == kContent_DrawingArea) {
+ return &fContentEntries;
+ } else {
+ return &fMarginContentEntries;
+ }
+}
+
+void SkPDFDevice::setLastContentEntry(ContentEntry* contentEntry) {
+ if (fDrawingArea == kContent_DrawingArea) {
+ fLastContentEntry = contentEntry;
+ } else {
+ fLastMarginContentEntry = contentEntry;
+ }
+}
+
+void SkPDFDevice::setDrawingArea(DrawingArea drawingArea) {
+ // A ScopedContentEntry only exists during the course of a draw call, so
+ // this can't be called while a ScopedContentEntry exists.
+ fDrawingArea = drawingArea;
+}
+
+SkPDFDict* SkPDFDevice::getResourceDict() {
if (fResourceDict.get() == NULL) {
fResourceDict = new SkPDFDict;
fResourceDict->unref(); // SkRefPtr and new both took a reference.
@@ -1017,10 +1031,10 @@ const SkRefPtr<SkPDFDict>& SkPDFDevice::getResourceDict() {
procSets->unref(); // SkRefPtr and new both took a reference.
procSets->reserve(SK_ARRAY_COUNT(procs));
for (size_t i = 0; i < SK_ARRAY_COUNT(procs); i++)
- procSets->append(new SkPDFName(procs[i]))->unref();
+ procSets->appendName(procs[i]);
fResourceDict->insert("ProcSet", procSets.get());
}
- return fResourceDict;
+ return fResourceDict.get();
}
void SkPDFDevice::getResources(SkTDArray<SkPDFObject*>* resourceList) const {
@@ -1064,16 +1078,51 @@ SkRefPtr<SkPDFArray> SkPDFDevice::getMediaBox() const {
mediaBox->reserve(4);
mediaBox->append(zero.get());
mediaBox->append(zero.get());
- mediaBox->append(new SkPDFInt(fPageSize.fWidth))->unref();
- mediaBox->append(new SkPDFInt(fPageSize.fHeight))->unref();
+ mediaBox->appendInt(fPageSize.fWidth);
+ mediaBox->appendInt(fPageSize.fHeight);
return mediaBox;
}
SkStream* SkPDFDevice::content() const {
+ SkMemoryStream* result = new SkMemoryStream;
+ result->setData(this->copyContentToData())->unref();
+ return result;
+}
+
+void SkPDFDevice::copyContentEntriesToData(ContentEntry* entry,
+ SkWStream* data) const {
+ // TODO(ctguil): For margins, I'm not sure fExistingClipStack/Region is the
+ // right thing to pass here.
+ GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, data);
+ while (entry != NULL) {
+ SkPoint translation;
+ translation.iset(this->getOrigin());
+ translation.negate();
+ gsState.updateClip(entry->fState.fClipStack, entry->fState.fClipRegion,
+ translation);
+ gsState.updateMatrix(entry->fState.fMatrix);
+ gsState.updateDrawingState(entry->fState);
+
+ SkAutoDataUnref copy(entry->fContent.copyToData());
+ data->write(copy.data(), copy.size());
+ entry = entry->fNext.get();
+ }
+ gsState.drainStack();
+}
+
+SkData* SkPDFDevice::copyContentToData() const {
SkDynamicMemoryWStream data;
if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) {
SkPDFUtils::AppendTransform(fInitialTransform, &data);
}
+
+ // TODO(aayushkumar): Apply clip along the margins. Currently, webkit
+ // colors the contentArea white before it starts drawing into it and
+ // that currently acts as our clip.
+ // Also, think about adding a transform here (or assume that the values
+ // sent across account for that)
+ SkPDFDevice::copyContentEntriesToData(fMarginContentEntries.get(), &data);
+
// If the content area is the entire page, then we don't need to clip
// the content area (PDF area clips to the page size). Otherwise,
// we have to clip to the content area; we've already applied the
@@ -1083,30 +1132,21 @@ SkStream* SkPDFDevice::content() const {
emit_clip(NULL, &r, &data);
}
- GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, &data);
- for (ContentEntry* entry = fContentEntries.get();
- entry != NULL;
- entry = entry->fNext.get()) {
- SkIPoint translation = this->getOrigin();
- translation.negate();
- gsState.updateClip(entry->fState.fClipStack, entry->fState.fClipRegion,
- translation);
- gsState.updateMatrix(entry->fState.fMatrix);
- gsState.updateDrawingState(entry->fState);
- data.write(entry->fContent.getStream(), entry->fContent.getOffset());
- }
- gsState.drainStack();
+ SkPDFDevice::copyContentEntriesToData(fContentEntries.get(), &data);
- SkMemoryStream* result = new SkMemoryStream;
- result->setMemoryOwned(data.detach(), data.getOffset());
- return result;
+ // potentially we could cache this SkData, and only rebuild it if we
+ // see that our state has changed.
+ return data.copyToData();
}
void SkPDFDevice::createFormXObjectFromDevice(
SkRefPtr<SkPDFFormXObject>* xobject) {
*xobject = new SkPDFFormXObject(this);
(*xobject)->unref(); // SkRefPtr and new both took a reference.
- cleanUp(); // Reset this device to have no content.
+ // We always draw the form xobjects that we create back into the device, so
+ // we simply preserve the font usage instead of pulling it out and merging
+ // it back in later.
+ cleanUp(false); // Reset this device to have no content.
init();
}
@@ -1142,7 +1182,7 @@ void SkPDFDevice::drawFormXObjectWithClip(SkPDFFormXObject* xobject,
SkRefPtr<SkPDFFormXObject> maskFormXObject;
createFormXObjectFromDevice(&maskFormXObject);
SkRefPtr<SkPDFGraphicState> sMaskGS =
- SkPDFGraphicState::getSMaskGraphicState(maskFormXObject.get(),
+ SkPDFGraphicState::GetSMaskGraphicState(maskFormXObject.get(),
invertClip);
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
@@ -1159,7 +1199,7 @@ void SkPDFDevice::drawFormXObjectWithClip(SkPDFFormXObject* xobject,
fXObjectResources.push(xobject);
xobject->ref();
- sMaskGS = SkPDFGraphicState::getNoSMaskGraphicState();
+ sMaskGS = SkPDFGraphicState::GetNoSMaskGraphicState();
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
&content.entry()->fContent);
@@ -1187,7 +1227,8 @@ ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
synthesizedClipStack = fExistingClipStack;
SkPath clipPath;
clipRegion.getBoundaryPath(&clipPath);
- synthesizedClipStack.clipDevPath(clipPath, SkRegion::kReplace_Op);
+ synthesizedClipStack.clipDevPath(clipPath, SkRegion::kReplace_Op,
+ false);
clipStack = &synthesizedClipStack;
}
}
@@ -1213,7 +1254,7 @@ ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
createFormXObjectFromDevice(dst);
}
}
- // TODO(vandebo) Figure out how/if we can handle the following modes:
+ // TODO(vandebo): Figure out how/if we can handle the following modes:
// SrcAtop, DestAtop, Xor, Plus.
// These xfer modes don't draw source at all.
@@ -1224,8 +1265,10 @@ ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
ContentEntry* entry;
SkTScopedPtr<ContentEntry> newEntry;
- if (fLastContentEntry && fLastContentEntry->fContent.getOffset() == 0) {
- entry = fLastContentEntry;
+
+ ContentEntry* lastContentEntry = getLastContentEntry();
+ if (lastContentEntry && lastContentEntry->fContent.getOffset() == 0) {
+ entry = lastContentEntry;
} else {
newEntry.reset(new ContentEntry);
entry = newEntry.get();
@@ -1233,20 +1276,21 @@ ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint,
hasText, &entry->fState);
- if (fLastContentEntry && xfermode != SkXfermode::kDstOver_Mode &&
- entry->fState.compareInitialState(fLastContentEntry->fState)) {
- return fLastContentEntry;
+ if (lastContentEntry && xfermode != SkXfermode::kDstOver_Mode &&
+ entry->fState.compareInitialState(lastContentEntry->fState)) {
+ return lastContentEntry;
}
- if (!fLastContentEntry) {
- fContentEntries.reset(entry);
- fLastContentEntry = entry;
+ SkTScopedPtr<ContentEntry>* contentEntries = getContentEntries();
+ if (!lastContentEntry) {
+ contentEntries->reset(entry);
+ setLastContentEntry(entry);
} else if (xfermode == SkXfermode::kDstOver_Mode) {
- entry->fNext.reset(fContentEntries.release());
- fContentEntries.reset(entry);
+ entry->fNext.reset(contentEntries->release());
+ contentEntries->reset(entry);
} else {
- fLastContentEntry->fNext.reset(entry);
- fLastContentEntry = entry;
+ lastContentEntry->fNext.reset(entry);
+ setLastContentEntry(entry);
}
newEntry.release();
return entry;
@@ -1261,13 +1305,14 @@ void SkPDFDevice::finishContentEntry(const SkXfermode::Mode xfermode,
SkASSERT(!dst);
return;
}
- SkASSERT(dst);
- SkASSERT(!fContentEntries->fNext.get());
+ ContentEntry* contentEntries = getContentEntries()->get();
+ SkASSERT(dst);
+ SkASSERT(!contentEntries->fNext.get());
// We have to make a copy of these here because changing the current
// content into a form xobject will destroy them.
- SkClipStack clipStack = fContentEntries->fState.fClipStack;
- SkRegion clipRegion = fContentEntries->fState.fClipRegion;
+ SkClipStack clipStack = contentEntries->fState.fClipStack;
+ SkRegion clipRegion = contentEntries->fState.fClipRegion;
SkRefPtr<SkPDFFormXObject> srcFormXObject;
if (!isContentEmpty()) {
@@ -1294,12 +1339,12 @@ void SkPDFDevice::finishContentEntry(const SkXfermode::Mode xfermode,
SkRefPtr<SkPDFGraphicState> sMaskGS;
if (xfermode == SkXfermode::kSrcIn_Mode ||
xfermode == SkXfermode::kSrcOut_Mode) {
- sMaskGS = SkPDFGraphicState::getSMaskGraphicState(
+ sMaskGS = SkPDFGraphicState::GetSMaskGraphicState(
dst, xfermode == SkXfermode::kSrcOut_Mode);
fXObjectResources.push(srcFormXObject.get());
srcFormXObject->ref();
} else {
- sMaskGS = SkPDFGraphicState::getSMaskGraphicState(
+ sMaskGS = SkPDFGraphicState::GetSMaskGraphicState(
srcFormXObject.get(), xfermode == SkXfermode::kDstOut_Mode);
// dst already added to fXObjectResources in drawFormXObjectWithClip.
}
@@ -1310,21 +1355,21 @@ void SkPDFDevice::finishContentEntry(const SkXfermode::Mode xfermode,
SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
&inClipContentEntry.entry()->fContent);
- sMaskGS = SkPDFGraphicState::getNoSMaskGraphicState();
+ sMaskGS = SkPDFGraphicState::GetNoSMaskGraphicState();
sMaskGS->unref(); // SkRefPtr and getSMaskGraphicState both took a ref.
SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
&inClipContentEntry.entry()->fContent);
}
bool SkPDFDevice::isContentEmpty() {
- if (!fContentEntries.get() || fContentEntries->fContent.getOffset() == 0) {
- SkASSERT(!fContentEntries.get() || !fContentEntries->fNext.get());
+ ContentEntry* contentEntries = getContentEntries()->get();
+ if (!contentEntries || contentEntries->fContent.getOffset() == 0) {
+ SkASSERT(!contentEntries || !contentEntries->fNext.get());
return true;
}
return false;
}
-
void SkPDFDevice::populateGraphicStateEntryFromPaint(
const SkMatrix& matrix,
const SkClipStack& clipStack,
@@ -1342,7 +1387,7 @@ void SkPDFDevice::populateGraphicStateEntryFromPaint(
entry->fClipRegion = clipRegion;
// PDF treats a shader as a color, so we only set one or the other.
- SkRefPtr<SkPDFShader> pdfShader;
+ SkRefPtr<SkPDFObject> pdfShader;
const SkShader* shader = paint.getShader();
SkColor color = paint.getColor();
if (shader) {
@@ -1354,12 +1399,23 @@ void SkPDFDevice::populateGraphicStateEntryFromPaint(
// PDF doesn't support kClamp_TileMode, so we simulate it by making
// a pattern the size of the current clip.
SkIRect bounds = clipRegion.getBounds();
- pdfShader = SkPDFShader::getPDFShader(*shader, transform, bounds);
+ pdfShader = SkPDFShader::GetPDFShader(*shader, transform, bounds);
SkSafeUnref(pdfShader.get()); // getShader and SkRefPtr both took a ref
- // A color shader is treated as an invalid shader so we don't have
- // to set a shader just for a color.
- if (pdfShader.get() == NULL) {
+ if (pdfShader.get()) {
+ // pdfShader has been canonicalized so we can directly compare
+ // pointers.
+ int resourceIndex = fShaderResources.find(pdfShader.get());
+ if (resourceIndex < 0) {
+ resourceIndex = fShaderResources.count();
+ fShaderResources.push(pdfShader.get());
+ pdfShader->ref();
+ }
+ entry->fShaderIndex = resourceIndex;
+ } else {
+ // A color shader is treated as an invalid shader so we don't have
+ // to set a shader just for a color.
+ entry->fShaderIndex = -1;
entry->fColor = 0;
color = 0;
@@ -1375,18 +1431,6 @@ void SkPDFDevice::populateGraphicStateEntryFromPaint(
color = gradientColor;
}
}
- }
-
- if (pdfShader) {
- // pdfShader has been canonicalized so we can directly compare
- // pointers.
- int resourceIndex = fShaderResources.find(pdfShader.get());
- if (resourceIndex < 0) {
- resourceIndex = fShaderResources.count();
- fShaderResources.push(pdfShader.get());
- pdfShader->ref();
- }
- entry->fShaderIndex = resourceIndex;
} else {
entry->fShaderIndex = -1;
entry->fColor = SkColorSetA(paint.getColor(), 0xFF);
@@ -1395,11 +1439,11 @@ void SkPDFDevice::populateGraphicStateEntryFromPaint(
SkRefPtr<SkPDFGraphicState> newGraphicState;
if (color == paint.getColor()) {
- newGraphicState = SkPDFGraphicState::getGraphicStateForPaint(paint);
+ newGraphicState = SkPDFGraphicState::GetGraphicStateForPaint(paint);
} else {
SkPaint newPaint = paint;
newPaint.setColor(color);
- newGraphicState = SkPDFGraphicState::getGraphicStateForPaint(newPaint);
+ newGraphicState = SkPDFGraphicState::GetGraphicStateForPaint(newPaint);
}
newGraphicState->unref(); // getGraphicState and SkRefPtr both took a ref.
int resourceIndex = addGraphicStateResource(newGraphicState.get());
@@ -1442,7 +1486,7 @@ void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID,
}
int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) {
- SkRefPtr<SkPDFFont> newFont = SkPDFFont::getFontResource(typeface, glyphID);
+ SkRefPtr<SkPDFFont> newFont = SkPDFFont::GetFontResource(typeface, glyphID);
newFont->unref(); // getFontResource and SkRefPtr both took a ref.
int resourceIndex = fFontResources.find(newFont.get());
if (resourceIndex < 0) {
@@ -1461,8 +1505,8 @@ void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix,
const SkPaint& paint) {
SkMatrix scaled;
// Adjust for origin flip.
- scaled.setScale(1, -1);
- scaled.postTranslate(0, 1);
+ scaled.setScale(SK_Scalar1, -SK_Scalar1);
+ scaled.postTranslate(0, SK_Scalar1);
// Scale the image up from 1x1 to WxH.
SkIRect subset = SkIRect::MakeWH(bitmap.width(), bitmap.height());
scaled.postScale(SkIntToScalar(subset.width()),
@@ -1486,3 +1530,13 @@ void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix,
SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
&content.entry()->fContent);
}
+
+bool SkPDFDevice::onReadPixels(const SkBitmap& bitmap, int x, int y,
+ SkCanvas::Config8888) {
+ return false;
+}
+
+bool SkPDFDevice::allowImageFilter(SkImageFilter*) {
+ return false;
+}
+
diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp
index 95370b4..cb87d8f 100644
--- a/src/pdf/SkPDFDocument.cpp
+++ b/src/pdf/SkPDFDocument.cpp
@@ -1,22 +1,17 @@
+
/*
- * Copyright (C) 2011 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2011 Google Inc.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
+#include "SkPDFCatalog.h"
#include "SkPDFDevice.h"
#include "SkPDFDocument.h"
#include "SkPDFPage.h"
+#include "SkPDFFont.h"
#include "SkStream.h"
// Add the resources, starting at firstIndex to the catalog, removing any dupes.
@@ -36,10 +31,36 @@ void addResourcesToCatalog(int firstIndex, bool firstPage,
}
}
-SkPDFDocument::SkPDFDocument() : fXRefFileOffset(0) {
+static void perform_font_subsetting(SkPDFCatalog* catalog,
+ const SkTDArray<SkPDFPage*>& pages,
+ SkTDArray<SkPDFObject*>* substitutes) {
+ SkASSERT(catalog);
+ SkASSERT(substitutes);
+
+ SkPDFGlyphSetMap usage;
+ for (int i = 0; i < pages.count(); ++i) {
+ usage.merge(pages[i]->getFontGlyphUsage());
+ }
+ SkPDFGlyphSetMap::F2BIter iterator(usage);
+ SkPDFGlyphSetMap::FontGlyphSetPair* entry = iterator.next();
+ while (entry) {
+ SkPDFFont* subsetFont =
+ entry->fFont->getFontSubset(entry->fGlyphSet);
+ if (subsetFont) {
+ catalog->setSubstitute(entry->fFont, subsetFont);
+ substitutes->push(subsetFont); // Transfer ownership to substitutes
+ }
+ entry = iterator.next();
+ }
+}
+
+SkPDFDocument::SkPDFDocument(Flags flags)
+ : fXRefFileOffset(0),
+ fSecondPageFirstResourceIndex(0) {
+ fCatalog.reset(new SkPDFCatalog(flags));
fDocCatalog = new SkPDFDict("Catalog");
fDocCatalog->unref(); // SkRefPtr and new both took a reference.
- fCatalog.addObject(fDocCatalog.get(), true);
+ fCatalog->addObject(fDocCatalog.get(), true);
}
SkPDFDocument::~SkPDFDocument() {
@@ -47,24 +68,32 @@ SkPDFDocument::~SkPDFDocument() {
// The page tree has both child and parent pointers, so it creates a
// reference cycle. We must clear that cycle to properly reclaim memory.
- for (int i = 0; i < fPageTree.count(); i++)
+ for (int i = 0; i < fPageTree.count(); i++) {
fPageTree[i]->clear();
+ }
fPageTree.safeUnrefAll();
fPageResources.safeUnrefAll();
+ fSubstitutes.safeUnrefAll();
}
bool SkPDFDocument::emitPDF(SkWStream* stream) {
- if (fPages.isEmpty())
+ if (fPages.isEmpty()) {
return false;
+ }
+ for (int i = 0; i < fPages.count(); i++) {
+ if (fPages[i] == NULL) {
+ return false;
+ }
+ }
// We haven't emitted the document before if fPageTree is empty.
- if (fPageTree.count() == 0) {
+ if (fPageTree.isEmpty()) {
SkPDFDict* pageTreeRoot;
- SkPDFPage::generatePageTree(fPages, &fCatalog, &fPageTree,
+ SkPDFPage::GeneratePageTree(fPages, fCatalog.get(), &fPageTree,
&pageTreeRoot);
fDocCatalog->insert("Pages", new SkPDFObjRef(pageTreeRoot))->unref();
- /* TODO(vandebo) output intent
+ /* TODO(vandebo): output intent
SkRefPtr<SkPDFDict> outputIntent = new SkPDFDict("OutputIntent");
outputIntent->unref(); // SkRefPtr and new both took a reference.
outputIntent->insert("S", new SkPDFName("GTS_PDFA1"))->unref();
@@ -76,81 +105,120 @@ bool SkPDFDocument::emitPDF(SkWStream* stream) {
fDocCatalog->insert("OutputIntent", intentArray.get());
*/
- bool first_page = true;
+ bool firstPage = true;
for (int i = 0; i < fPages.count(); i++) {
int resourceCount = fPageResources.count();
- fPages[i]->finalizePage(&fCatalog, first_page, &fPageResources);
- addResourcesToCatalog(resourceCount, first_page, &fPageResources,
- &fCatalog);
+ fPages[i]->finalizePage(fCatalog.get(), firstPage, &fPageResources);
+ addResourcesToCatalog(resourceCount, firstPage, &fPageResources,
+ fCatalog.get());
if (i == 0) {
- first_page = false;
+ firstPage = false;
fSecondPageFirstResourceIndex = fPageResources.count();
}
}
+ // Build font subsetting info before proceeding.
+ perform_font_subsetting(fCatalog.get(), fPages, &fSubstitutes);
+
// Figure out the size of things and inform the catalog of file offsets.
off_t fileOffset = headerSize();
- fileOffset += fCatalog.setFileOffset(fDocCatalog.get(), fileOffset);
- fileOffset += fCatalog.setFileOffset(fPages[0], fileOffset);
- fileOffset += fPages[0]->getPageSize(&fCatalog, fileOffset);
- for (int i = 0; i < fSecondPageFirstResourceIndex; i++)
- fileOffset += fCatalog.setFileOffset(fPageResources[i], fileOffset);
+ fileOffset += fCatalog->setFileOffset(fDocCatalog.get(), fileOffset);
+ fileOffset += fCatalog->setFileOffset(fPages[0], fileOffset);
+ fileOffset += fPages[0]->getPageSize(fCatalog.get(), fileOffset);
+ for (int i = 0; i < fSecondPageFirstResourceIndex; i++) {
+ fileOffset += fCatalog->setFileOffset(fPageResources[i],
+ fileOffset);
+ }
+ // Add the size of resources of substitute objects used on page 1.
+ fileOffset += fCatalog->setSubstituteResourcesOffsets(fileOffset, true);
if (fPages.count() > 1) {
- // TODO(vandebo) For linearized format, save the start of the
+ // TODO(vandebo): For linearized format, save the start of the
// first page xref table and calculate the size.
}
- for (int i = 0; i < fPageTree.count(); i++)
- fileOffset += fCatalog.setFileOffset(fPageTree[i], fileOffset);
+ for (int i = 0; i < fPageTree.count(); i++) {
+ fileOffset += fCatalog->setFileOffset(fPageTree[i], fileOffset);
+ }
- for (int i = 1; i < fPages.count(); i++)
- fileOffset += fPages[i]->getPageSize(&fCatalog, fileOffset);
+ for (int i = 1; i < fPages.count(); i++) {
+ fileOffset += fPages[i]->getPageSize(fCatalog.get(), fileOffset);
+ }
for (int i = fSecondPageFirstResourceIndex;
i < fPageResources.count();
- i++)
- fileOffset += fCatalog.setFileOffset(fPageResources[i], fileOffset);
+ i++) {
+ fileOffset += fCatalog->setFileOffset(fPageResources[i],
+ fileOffset);
+ }
+ fileOffset += fCatalog->setSubstituteResourcesOffsets(fileOffset,
+ false);
fXRefFileOffset = fileOffset;
}
emitHeader(stream);
- fDocCatalog->emitObject(stream, &fCatalog, true);
- fPages[0]->emitObject(stream, &fCatalog, true);
- fPages[0]->emitPage(stream, &fCatalog);
- for (int i = 0; i < fSecondPageFirstResourceIndex; i++)
- fPageResources[i]->emitObject(stream, &fCatalog, true);
- // TODO(vandebo) support linearized format
- //if (fPages.size() > 1) {
- // // TODO(vandebo) save the file offset for the first page xref table.
- // fCatalog.emitXrefTable(stream, true);
- //}
-
- for (int i = 0; i < fPageTree.count(); i++)
- fPageTree[i]->emitObject(stream, &fCatalog, true);
-
- for (int i = 1; i < fPages.count(); i++)
- fPages[i]->emitPage(stream, &fCatalog);
-
- for (int i = fSecondPageFirstResourceIndex; i < fPageResources.count(); i++)
- fPageResources[i]->emitObject(stream, &fCatalog, true);
-
- int64_t objCount = fCatalog.emitXrefTable(stream, fPages.count() > 1);
+ fDocCatalog->emitObject(stream, fCatalog.get(), true);
+ fPages[0]->emitObject(stream, fCatalog.get(), true);
+ fPages[0]->emitPage(stream, fCatalog.get());
+ for (int i = 0; i < fSecondPageFirstResourceIndex; i++) {
+ fPageResources[i]->emit(stream, fCatalog.get(), true);
+ }
+ fCatalog->emitSubstituteResources(stream, true);
+ // TODO(vandebo): Support linearized format
+ // if (fPages.size() > 1) {
+ // // TODO(vandebo): Save the file offset for the first page xref table.
+ // fCatalog->emitXrefTable(stream, true);
+ // }
+
+ for (int i = 0; i < fPageTree.count(); i++) {
+ fPageTree[i]->emitObject(stream, fCatalog.get(), true);
+ }
+
+ for (int i = 1; i < fPages.count(); i++) {
+ fPages[i]->emitPage(stream, fCatalog.get());
+ }
+
+ for (int i = fSecondPageFirstResourceIndex;
+ i < fPageResources.count();
+ i++) {
+ fPageResources[i]->emit(stream, fCatalog.get(), true);
+ }
+
+ fCatalog->emitSubstituteResources(stream, false);
+ int64_t objCount = fCatalog->emitXrefTable(stream, fPages.count() > 1);
emitFooter(stream, objCount);
return true;
}
-bool SkPDFDocument::appendPage(const SkRefPtr<SkPDFDevice>& pdfDevice) {
- if (fPageTree.count() != 0)
+bool SkPDFDocument::setPage(int pageNumber, SkPDFDevice* pdfDevice) {
+ if (!fPageTree.isEmpty()) {
return false;
+ }
+
+ pageNumber--;
+ SkASSERT(pageNumber >= 0);
+
+ if (pageNumber >= fPages.count()) {
+ int oldSize = fPages.count();
+ fPages.setCount(pageNumber + 1);
+ for (int i = oldSize; i <= pageNumber; i++) {
+ fPages[i] = NULL;
+ }
+ }
+
+ SkPDFPage* page = new SkPDFPage(pdfDevice);
+ SkSafeUnref(fPages[pageNumber]);
+ fPages[pageNumber] = page; // Reference from new passed to fPages.
+ return true;
+}
+
+bool SkPDFDocument::appendPage(SkPDFDevice* pdfDevice) {
+ if (!fPageTree.isEmpty()) {
+ return false;
+ }
SkPDFPage* page = new SkPDFPage(pdfDevice);
fPages.push(page); // Reference from new passed to fPages.
- // The rest of the pages will be added to the catalog along with the rest
- // of the page tree. But the first page has to be marked as such, so we
- // handle it here.
- if (fPages.count() == 1)
- fCatalog.addObject(page, true);
return true;
}
@@ -177,15 +245,15 @@ void SkPDFDocument::emitFooter(SkWStream* stream, int64_t objCount) {
fTrailerDict = new SkPDFDict();
fTrailerDict->unref(); // SkRefPtr and new both took a reference.
- // TODO(vandebo) Linearized format will take a Prev entry too.
- // TODO(vandebo) PDF/A requires an ID entry.
- fTrailerDict->insert("Size", new SkPDFInt(objCount))->unref();
+ // TODO(vandebo): Linearized format will take a Prev entry too.
+ // TODO(vandebo): PDF/A requires an ID entry.
+ fTrailerDict->insertInt("Size", objCount);
fTrailerDict->insert("Root",
new SkPDFObjRef(fDocCatalog.get()))->unref();
}
stream->writeText("trailer\n");
- fTrailerDict->emitObject(stream, &fCatalog, false);
+ fTrailerDict->emitObject(stream, fCatalog.get(), false);
stream->writeText("\nstartxref\n");
stream->writeBigDecAsText(fXRefFileOffset);
stream->writeText("\n%%EOF");
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp
index 277ed12..465fbe1 100755..100644
--- a/src/pdf/SkPDFFont.cpp
+++ b/src/pdf/SkPDFFont.cpp
@@ -1,26 +1,22 @@
+
/*
- * Copyright (C) 2011 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2011 Google Inc.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include <ctype.h>
+#include "SkData.h"
#include "SkFontHost.h"
#include "SkGlyphCache.h"
#include "SkPaint.h"
+#include "SkPDFCatalog.h"
#include "SkPDFDevice.h"
#include "SkPDFFont.h"
+#include "SkPDFFontImpl.h"
#include "SkPDFStream.h"
#include "SkPDFTypes.h"
#include "SkPDFUtils.h"
@@ -31,8 +27,16 @@
#include "SkTypes.h"
#include "SkUtils.h"
+#if defined (SK_SFNTLY_SUBSETTER)
+#include SK_SFNTLY_SUBSETTER
+#endif
+
namespace {
+///////////////////////////////////////////////////////////////////////////////
+// File-Local Functions
+///////////////////////////////////////////////////////////////////////////////
+
bool parsePFBSection(const uint8_t** src, size_t* len, int sectionType,
size_t* size) {
// PFB sections have a two or six bytes header. 0x80 and a one byte
@@ -40,17 +44,20 @@ bool parsePFBSection(const uint8_t** src, size_t* len, int sectionType,
// an ASCII section (includes a length), type two is a binary section
// (includes a length) and type three is an EOF marker with no length.
const uint8_t* buf = *src;
- if (*len < 2 || buf[0] != 0x80 || buf[1] != sectionType)
+ if (*len < 2 || buf[0] != 0x80 || buf[1] != sectionType) {
return false;
- if (buf[1] == 3)
+ } else if (buf[1] == 3) {
return true;
- if (*len < 6)
+ } else if (*len < 6) {
return false;
+ }
- *size = buf[2] | (buf[3] << 8) | (buf[4] << 16) | (buf[5] << 24);
+ *size = (size_t)buf[2] | ((size_t)buf[3] << 8) | ((size_t)buf[4] << 16) |
+ ((size_t)buf[5] << 24);
size_t consumed = *size + 6;
- if (consumed > *len)
+ if (consumed > *len) {
return false;
+ }
*src = *src + consumed;
*len = *len - consumed;
return true;
@@ -80,17 +87,20 @@ bool parsePFA(const char* src, size_t size, size_t* headerLen,
const char* end = src + size;
const char* dataPos = strstr(src, "eexec");
- if (!dataPos)
+ if (!dataPos) {
return false;
+ }
dataPos += strlen("eexec");
while ((*dataPos == '\n' || *dataPos == '\r' || *dataPos == ' ') &&
- dataPos < end)
+ dataPos < end) {
dataPos++;
+ }
*headerLen = dataPos - src;
const char* trailerPos = strstr(dataPos, "cleartomark");
- if (!trailerPos)
+ if (!trailerPos) {
return false;
+ }
int zeroCount = 0;
for (trailerPos--; trailerPos > dataPos && zeroCount < 512; trailerPos--) {
if (*trailerPos == '\n' || *trailerPos == '\r' || *trailerPos == ' ') {
@@ -101,8 +111,9 @@ bool parsePFA(const char* src, size_t size, size_t* headerLen,
return false;
}
}
- if (zeroCount != 512)
+ if (zeroCount != 512) {
return false;
+ }
*hexDataLen = trailerPos - src - *headerLen;
*trailerLen = size - *headerLen - *hexDataLen;
@@ -110,10 +121,12 @@ bool parsePFA(const char* src, size_t size, size_t* headerLen,
// Verify that the data section is hex encoded and count the bytes.
int nibbles = 0;
for (; dataPos < trailerPos; dataPos++) {
- if (isspace(*dataPos))
+ if (isspace(*dataPos)) {
continue;
- if (!isxdigit(*dataPos))
+ }
+ if (!isxdigit(*dataPos)) {
return false;
+ }
nibbles++;
}
*dataLen = (nibbles + 1) / 2;
@@ -122,23 +135,28 @@ bool parsePFA(const char* src, size_t size, size_t* headerLen,
}
int8_t hexToBin(uint8_t c) {
- if (!isxdigit(c))
+ if (!isxdigit(c)) {
return -1;
- if (c <= '9') return c - '0';
- if (c <= 'F') return c - 'A' + 10;
- if (c <= 'f') return c - 'a' + 10;
+ } else if (c <= '9') {
+ return c - '0';
+ } else if (c <= 'F') {
+ return c - 'A' + 10;
+ } else if (c <= 'f') {
+ return c - 'a' + 10;
+ }
return -1;
}
SkStream* handleType1Stream(SkStream* srcStream, size_t* headerLen,
size_t* dataLen, size_t* trailerLen) {
- // srcStream may be backed by a file or a unseekable fd, so we may not be
+ // srcStream may be backed by a file or a unseekable fd, so we may not be
// able to use skip(), rewind(), or getMemoryBase(). read()ing through
// the input only once is doable, but very ugly. Furthermore, it'd be nice
// if the data was NUL terminated so that we can use strstr() to search it.
// Make as few copies as possible given these constraints.
SkDynamicMemoryWStream dynamicStream;
SkRefPtr<SkMemoryStream> staticStream;
+ SkData* data = NULL;
const uint8_t* src;
size_t srcLen;
if ((srcLen = srcStream->getLength()) > 0) {
@@ -152,26 +170,32 @@ SkStream* handleType1Stream(SkStream* srcStream, size_t* headerLen,
while (read < srcLen) {
size_t got = srcStream->read((void *)staticStream->getAtPos(),
srcLen - read);
- if (got == 0)
+ if (got == 0) {
return NULL;
+ }
read += got;
staticStream->seek(read);
}
}
((uint8_t *)src)[srcLen] = 0;
} else {
- static const size_t bufSize = 4096;
- uint8_t buf[bufSize];
+ static const size_t kBufSize = 4096;
+ uint8_t buf[kBufSize];
size_t amount;
- while ((amount = srcStream->read(buf, bufSize)) > 0)
+ while ((amount = srcStream->read(buf, kBufSize)) > 0) {
dynamicStream.write(buf, amount);
+ }
amount = 0;
dynamicStream.write(&amount, 1); // NULL terminator.
- // getStream makes another copy, but we couldn't do any better.
- src = (const uint8_t*)dynamicStream.getStream();
- srcLen = dynamicStream.getOffset() - 1;
+ data = dynamicStream.copyToData();
+ src = data->bytes();
+ srcLen = data->size() - 1;
}
+ // this handles releasing the data we may have gotten from dynamicStream.
+ // if data is null, it is a no-op
+ SkAutoDataUnref aud(data);
+
if (parsePFB(src, srcLen, headerLen, dataLen, trailerLen)) {
SkMemoryStream* result =
new SkMemoryStream(*headerLen + *dataLen + *trailerLen);
@@ -201,8 +225,9 @@ SkStream* handleType1Stream(SkStream* srcStream, size_t* headerLen,
bool highNibble = true;
for (; hexData < trailer; hexData++) {
char curNibble = hexToBin(*hexData);
- if (curNibble < 0)
+ if (curNibble < 0) {
continue;
+ }
if (highNibble) {
dataByte = curNibble << 4;
highNibble = false;
@@ -212,8 +237,9 @@ SkStream* handleType1Stream(SkStream* srcStream, size_t* headerLen,
((char *)result->getAtPos())[outputOffset++] = dataByte;
}
}
- if (!highNibble)
+ if (!highNibble) {
((char *)result->getAtPos())[outputOffset++] = dataByte;
+ }
SkASSERT(outputOffset == *dataLen);
result->seek(*headerLen + outputOffset);
@@ -254,20 +280,16 @@ void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
SkPDFArray* makeFontBBox(SkIRect glyphBBox, uint16_t emSize) {
SkPDFArray* bbox = new SkPDFArray;
bbox->reserve(4);
- bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fLeft,
- emSize)))->unref();
- bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fBottom,
- emSize)))->unref();
- bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fRight,
- emSize)))->unref();
- bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fTop,
- emSize)))->unref();
+ bbox->appendScalar(scaleFromFontUnits(glyphBBox.fLeft, emSize));
+ bbox->appendScalar(scaleFromFontUnits(glyphBBox.fBottom, emSize));
+ bbox->appendScalar(scaleFromFontUnits(glyphBBox.fRight, emSize));
+ bbox->appendScalar(scaleFromFontUnits(glyphBBox.fTop, emSize));
return bbox;
}
SkPDFArray* appendWidth(const int16_t& width, uint16_t emSize,
SkPDFArray* array) {
- array->append(new SkPDFScalar(scaleFromFontUnits(width, emSize)))->unref();
+ array->appendScalar(scaleFromFontUnits(width, emSize));
return array;
}
@@ -301,14 +323,14 @@ SkPDFArray* composeAdvanceData(
for (int j = 0; j < advanceInfo->fAdvance.count(); j++)
appendAdvance(advanceInfo->fAdvance[j], emSize,
advanceArray.get());
- result->append(new SkPDFInt(advanceInfo->fStartId))->unref();
+ result->appendInt(advanceInfo->fStartId);
result->append(advanceArray.get());
break;
}
case SkAdvancedTypefaceMetrics::WidthRange::kRun: {
SkASSERT(advanceInfo->fAdvance.count() == 1);
- result->append(new SkPDFInt(advanceInfo->fStartId))->unref();
- result->append(new SkPDFInt(advanceInfo->fEndId))->unref();
+ result->appendInt(advanceInfo->fStartId);
+ result->appendInt(advanceInfo->fEndId);
appendAdvance(advanceInfo->fAdvance[0], emSize, result);
break;
}
@@ -355,21 +377,6 @@ static void append_tounicode_header(SkDynamicMemoryWStream* cmap) {
cmap->writeText(kTypeInfo);
}
-static void append_cmap_bfchar_table(uint16_t* glyph_id, SkUnichar* unicode,
- size_t count,
- SkDynamicMemoryWStream* cmap) {
- cmap->writeDecAsText(count);
- cmap->writeText(" beginbfchar\n");
- for (size_t i = 0; i < count; ++i) {
- cmap->writeText("<");
- cmap->writeHexAsText(glyph_id[i], 4);
- cmap->writeText("> <");
- cmap->writeHexAsText(unicode[i], 4);
- cmap->writeText(">\n");
- }
- cmap->writeText("endbfchar\n");
-}
-
static void append_cmap_footer(SkDynamicMemoryWStream* cmap) {
const char* kFooter =
"endcmap\n"
@@ -379,32 +386,298 @@ static void append_cmap_footer(SkDynamicMemoryWStream* cmap) {
cmap->writeText(kFooter);
}
-// Generate <bfchar> table according to PDF spec 1.4 and Adobe Technote 5014.
-static void append_cmap_bfchar_sections(
- const SkTDArray<SkUnichar>& glyphUnicode,
- SkDynamicMemoryWStream* cmap) {
+struct BFChar {
+ uint16_t fGlyphId;
+ SkUnichar fUnicode;
+};
+
+struct BFRange {
+ uint16_t fStart;
+ uint16_t fEnd;
+ SkUnichar fUnicode;
+};
+
+static void append_bfchar_section(const SkTDArray<BFChar>& bfchar,
+ SkDynamicMemoryWStream* cmap) {
// PDF spec defines that every bf* list can have at most 100 entries.
- const size_t kMaxEntries = 100;
- uint16_t glyphId[kMaxEntries];
- SkUnichar unicode[kMaxEntries];
- size_t index = 0;
- for (int i = 0; i < glyphUnicode.count(); i++) {
- if (glyphUnicode[i]) {
- glyphId[index] = i;
- unicode[index] = glyphUnicode[i];
- ++index;
+ for (int i = 0; i < bfchar.count(); i += 100) {
+ int count = bfchar.count() - i;
+ count = SkMin32(count, 100);
+ cmap->writeDecAsText(count);
+ cmap->writeText(" beginbfchar\n");
+ for (int j = 0; j < count; ++j) {
+ cmap->writeText("<");
+ cmap->writeHexAsText(bfchar[i + j].fGlyphId, 4);
+ cmap->writeText("> <");
+ cmap->writeHexAsText(bfchar[i + j].fUnicode, 4);
+ cmap->writeText(">\n");
}
- if (index == kMaxEntries) {
- append_cmap_bfchar_table(glyphId, unicode, index, cmap);
- index = 0;
+ cmap->writeText("endbfchar\n");
+ }
+}
+
+static void append_bfrange_section(const SkTDArray<BFRange>& bfrange,
+ SkDynamicMemoryWStream* cmap) {
+ // PDF spec defines that every bf* list can have at most 100 entries.
+ for (int i = 0; i < bfrange.count(); i += 100) {
+ int count = bfrange.count() - i;
+ count = SkMin32(count, 100);
+ cmap->writeDecAsText(count);
+ cmap->writeText(" beginbfrange\n");
+ for (int j = 0; j < count; ++j) {
+ cmap->writeText("<");
+ cmap->writeHexAsText(bfrange[i + j].fStart, 4);
+ cmap->writeText("> <");
+ cmap->writeHexAsText(bfrange[i + j].fEnd, 4);
+ cmap->writeText("> <");
+ cmap->writeHexAsText(bfrange[i + j].fUnicode, 4);
+ cmap->writeText(">\n");
}
+ cmap->writeText("endbfrange\n");
+ }
+}
+
+// Generate <bfchar> and <bfrange> table according to PDF spec 1.4 and Adobe
+// Technote 5014.
+// The function is not static so we can test it in unit tests.
+//
+// Current implementation guarantees bfchar and bfrange entries do not overlap.
+//
+// Current implementation does not attempt aggresive optimizations against
+// following case because the specification is not clear.
+//
+// 4 beginbfchar 1 beginbfchar
+// <0003> <0013> <0020> <0014>
+// <0005> <0015> to endbfchar
+// <0007> <0017> 1 beginbfrange
+// <0020> <0014> <0003> <0007> <0013>
+// endbfchar endbfrange
+//
+// Adobe Technote 5014 said: "Code mappings (unlike codespace ranges) may
+// overlap, but succeeding maps superceded preceding maps."
+//
+// In case of searching text in PDF, bfrange will have higher precedence so
+// typing char id 0x0014 in search box will get glyph id 0x0004 first. However,
+// the spec does not mention how will this kind of conflict being resolved.
+//
+// For the worst case (having 65536 continuous unicode and we use every other
+// one of them), the possible savings by aggressive optimization is 416KB
+// pre-compressed and does not provide enough motivation for implementation.
+void append_cmap_sections(const SkTDArray<SkUnichar>& glyphToUnicode,
+ const SkPDFGlyphSet* subset,
+ SkDynamicMemoryWStream* cmap) {
+ if (glyphToUnicode.isEmpty()) {
+ return;
}
- if (index) {
- append_cmap_bfchar_table(glyphId, unicode, index, cmap);
+ SkTDArray<BFChar> bfcharEntries;
+ SkTDArray<BFRange> bfrangeEntries;
+
+ BFRange currentRangeEntry = {0, 0, 0};
+ bool rangeEmpty = true;
+ const int count = glyphToUnicode.count();
+
+ for (int i = 0; i < count + 1; ++i) {
+ bool inSubset = i < count && (subset == NULL || subset->has(i));
+ if (!rangeEmpty) {
+ // PDF spec requires bfrange not changing the higher byte,
+ // e.g. <1035> <10FF> <2222> is ok, but
+ // <1035> <1100> <2222> is no good
+ bool inRange =
+ i == currentRangeEntry.fEnd + 1 &&
+ i >> 8 == currentRangeEntry.fStart >> 8 &&
+ i < count &&
+ glyphToUnicode[i] == currentRangeEntry.fUnicode + i -
+ currentRangeEntry.fStart;
+ if (!inSubset || !inRange) {
+ if (currentRangeEntry.fEnd > currentRangeEntry.fStart) {
+ bfrangeEntries.push(currentRangeEntry);
+ } else {
+ BFChar* entry = bfcharEntries.append();
+ entry->fGlyphId = currentRangeEntry.fStart;
+ entry->fUnicode = currentRangeEntry.fUnicode;
+ }
+ rangeEmpty = true;
+ }
+ }
+ if (inSubset) {
+ currentRangeEntry.fEnd = i;
+ if (rangeEmpty) {
+ currentRangeEntry.fStart = i;
+ currentRangeEntry.fUnicode = glyphToUnicode[i];
+ rangeEmpty = false;
+ }
+ }
}
+
+ // The spec requires all bfchar entries for a font must come before bfrange
+ // entries.
+ append_bfchar_section(bfcharEntries, cmap);
+ append_bfrange_section(bfrangeEntries, cmap);
+}
+
+static SkPDFStream* generate_tounicode_cmap(
+ const SkTDArray<SkUnichar>& glyphToUnicode,
+ const SkPDFGlyphSet* subset) {
+ SkDynamicMemoryWStream cmap;
+ append_tounicode_header(&cmap);
+ append_cmap_sections(glyphToUnicode, subset, &cmap);
+ append_cmap_footer(&cmap);
+ SkRefPtr<SkMemoryStream> cmapStream = new SkMemoryStream();
+ cmapStream->unref(); // SkRefPtr and new took a reference.
+ cmapStream->setData(cmap.copyToData());
+ return new SkPDFStream(cmapStream.get());
}
+static void sk_delete_array(const void* ptr, size_t, void*) {
+ // Use C-style cast to cast away const and cast type simultaneously.
+ delete[] (unsigned char*)ptr;
+}
+
+static int get_subset_font_stream(const char* fontName,
+ const SkTypeface* typeface,
+ const SkTDArray<uint32_t>& subset,
+ SkPDFStream** fontStream) {
+ SkRefPtr<SkStream> fontData =
+ SkFontHost::OpenStream(SkTypeface::UniqueID(typeface));
+ fontData->unref(); // SkRefPtr and OpenStream both took a ref.
+
+ int fontSize = fontData->getLength();
+
+#if defined (SK_SFNTLY_SUBSETTER)
+ // Read font into buffer.
+ SkPDFStream* subsetFontStream = NULL;
+ SkTDArray<unsigned char> originalFont;
+ originalFont.setCount(fontSize);
+ if (fontData->read(originalFont.begin(), fontSize) == (size_t)fontSize) {
+ unsigned char* subsetFont = NULL;
+ // sfntly requires unsigned int* to be passed in, as far as we know,
+ // unsigned int is equivalent to uint32_t on all platforms.
+ SK_COMPILE_ASSERT(sizeof(unsigned int) == sizeof(uint32_t),
+ unsigned_int_not_32_bits);
+ int subsetFontSize = SfntlyWrapper::SubsetFont(fontName,
+ originalFont.begin(),
+ fontSize,
+ subset.begin(),
+ subset.count(),
+ &subsetFont);
+ if (subsetFontSize > 0 && subsetFont != NULL) {
+ SkAutoDataUnref data(SkData::NewWithProc(subsetFont,
+ subsetFontSize,
+ sk_delete_array,
+ NULL));
+ subsetFontStream = new SkPDFStream(data.get());
+ fontSize = subsetFontSize;
+ }
+ }
+ if (subsetFontStream) {
+ *fontStream = subsetFontStream;
+ return fontSize;
+ }
+#endif
+
+ // Fail over: just embed the whole font.
+ *fontStream = new SkPDFStream(fontData.get());
+ return fontSize;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// class SkPDFGlyphSet
+///////////////////////////////////////////////////////////////////////////////
+
+SkPDFGlyphSet::SkPDFGlyphSet() : fBitSet(SK_MaxU16 + 1) {
+}
+
+void SkPDFGlyphSet::set(const uint16_t* glyphIDs, int numGlyphs) {
+ for (int i = 0; i < numGlyphs; ++i) {
+ fBitSet.setBit(glyphIDs[i], true);
+ }
+}
+
+bool SkPDFGlyphSet::has(uint16_t glyphID) const {
+ return fBitSet.isBitSet(glyphID);
+}
+
+void SkPDFGlyphSet::merge(const SkPDFGlyphSet& usage) {
+ fBitSet.orBits(usage.fBitSet);
+}
+
+void SkPDFGlyphSet::exportTo(SkTDArray<unsigned int>* glyphIDs) const {
+ fBitSet.exportTo(glyphIDs);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// class SkPDFGlyphSetMap
+///////////////////////////////////////////////////////////////////////////////
+SkPDFGlyphSetMap::FontGlyphSetPair::FontGlyphSetPair(SkPDFFont* font,
+ SkPDFGlyphSet* glyphSet)
+ : fFont(font),
+ fGlyphSet(glyphSet) {
+}
+
+SkPDFGlyphSetMap::F2BIter::F2BIter(const SkPDFGlyphSetMap& map) {
+ reset(map);
+}
+
+SkPDFGlyphSetMap::FontGlyphSetPair* SkPDFGlyphSetMap::F2BIter::next() const {
+ if (fIndex >= fMap->count()) {
+ return NULL;
+ }
+ return &((*fMap)[fIndex++]);
+}
+
+void SkPDFGlyphSetMap::F2BIter::reset(const SkPDFGlyphSetMap& map) {
+ fMap = &(map.fMap);
+ fIndex = 0;
+}
+
+SkPDFGlyphSetMap::SkPDFGlyphSetMap() {
+}
+
+SkPDFGlyphSetMap::~SkPDFGlyphSetMap() {
+ reset();
+}
+
+void SkPDFGlyphSetMap::merge(const SkPDFGlyphSetMap& usage) {
+ for (int i = 0; i < usage.fMap.count(); ++i) {
+ SkPDFGlyphSet* myUsage = getGlyphSetForFont(usage.fMap[i].fFont);
+ myUsage->merge(*(usage.fMap[i].fGlyphSet));
+ }
+}
+
+void SkPDFGlyphSetMap::reset() {
+ for (int i = 0; i < fMap.count(); ++i) {
+ delete fMap[i].fGlyphSet; // Should not be NULL.
+ }
+ fMap.reset();
+}
+
+void SkPDFGlyphSetMap::noteGlyphUsage(SkPDFFont* font, const uint16_t* glyphIDs,
+ int numGlyphs) {
+ SkPDFGlyphSet* subset = getGlyphSetForFont(font);
+ if (subset) {
+ subset->set(glyphIDs, numGlyphs);
+ }
+}
+
+SkPDFGlyphSet* SkPDFGlyphSetMap::getGlyphSetForFont(SkPDFFont* font) {
+ int index = fMap.count();
+ for (int i = 0; i < index; ++i) {
+ if (fMap[i].fFont == font) {
+ return fMap[i].fGlyphSet;
+ }
+ }
+ fMap.append();
+ index = fMap.count() - 1;
+ fMap[index].fFont = font;
+ fMap[index].fGlyphSet = new SkPDFGlyphSet();
+ return fMap[index].fGlyphSet;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// class SkPDFFont
+///////////////////////////////////////////////////////////////////////////////
+
/* Font subset design: It would be nice to be able to subset fonts
* (particularly type 3 fonts), but it's a lot of work and not a priority.
*
@@ -418,26 +691,17 @@ static void append_cmap_bfchar_sections(
*/
SkPDFFont::~SkPDFFont() {
- SkAutoMutexAcquire lock(canonicalFontsMutex());
+ SkAutoMutexAcquire lock(CanonicalFontsMutex());
int index;
- if (find(SkTypeface::UniqueID(fTypeface.get()), fFirstGlyphID, &index)) {
- canonicalFonts().removeShuffle(index);
-#ifdef SK_DEBUG
- SkASSERT(!fDescendant);
- } else {
- SkASSERT(fDescendant);
-#endif
+ if (Find(SkTypeface::UniqueID(fTypeface.get()), fFirstGlyphID, &index) &&
+ CanonicalFonts()[index].fFont == this) {
+ CanonicalFonts().removeShuffle(index);
}
fResources.unrefAll();
}
void SkPDFFont::getResources(SkTDArray<SkPDFObject*>* resourceList) {
- resourceList->setReserve(resourceList->count() + fResources.count());
- for (int i = 0; i < fResources.count(); i++) {
- resourceList->push(fResources[i]);
- fResources[i]->ref();
- fResources[i]->getResources(resourceList);
- }
+ GetResourcesHelper(&fResources, resourceList);
}
SkTypeface* SkPDFFont::typeface() {
@@ -445,21 +709,17 @@ SkTypeface* SkPDFFont::typeface() {
}
SkAdvancedTypefaceMetrics::FontType SkPDFFont::getType() {
- return fType;
+ return fFontType;
}
bool SkPDFFont::hasGlyph(uint16_t id) {
return (id >= fFirstGlyphID && id <= fLastGlyphID) || id == 0;
}
-bool SkPDFFont::multiByteGlyphs() {
- return fMultiByteGlyphs;
-}
-
size_t SkPDFFont::glyphsToPDFFontEncoding(uint16_t* glyphIDs,
size_t numGlyphs) {
// A font with multibyte glyphs will support all glyph IDs in a single font.
- if (fMultiByteGlyphs) {
+ if (this->multiByteGlyphs()) {
return numGlyphs;
}
@@ -477,159 +737,396 @@ size_t SkPDFFont::glyphsToPDFFontEncoding(uint16_t* glyphIDs,
}
// static
-SkPDFFont* SkPDFFont::getFontResource(SkTypeface* typeface, uint16_t glyphID) {
- SkAutoMutexAcquire lock(canonicalFontsMutex());
+SkPDFFont* SkPDFFont::GetFontResource(SkTypeface* typeface, uint16_t glyphID) {
+ SkAutoMutexAcquire lock(CanonicalFontsMutex());
const uint32_t fontID = SkTypeface::UniqueID(typeface);
- int index;
- if (find(fontID, glyphID, &index)) {
- canonicalFonts()[index].fFont->ref();
- return canonicalFonts()[index].fFont;
- }
-
- SkRefPtr<SkAdvancedTypefaceMetrics> fontInfo;
- SkPDFDict* fontDescriptor = NULL;
- if (index >= 0) {
- SkPDFFont* relatedFont = canonicalFonts()[index].fFont;
- SkASSERT(relatedFont->fFontInfo.get());
- fontInfo = relatedFont->fFontInfo;
- fontDescriptor = relatedFont->fDescriptor.get();
+ int relatedFontIndex;
+ if (Find(fontID, glyphID, &relatedFontIndex)) {
+ CanonicalFonts()[relatedFontIndex].fFont->ref();
+ return CanonicalFonts()[relatedFontIndex].fFont;
+ }
+
+ SkRefPtr<SkAdvancedTypefaceMetrics> fontMetrics;
+ SkPDFDict* relatedFontDescriptor = NULL;
+ if (relatedFontIndex >= 0) {
+ SkPDFFont* relatedFont = CanonicalFonts()[relatedFontIndex].fFont;
+ fontMetrics = relatedFont->fontInfo();
+ relatedFontDescriptor = relatedFont->getFontDescriptor();
} else {
SkAdvancedTypefaceMetrics::PerGlyphInfo info;
- info = SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo;
- info = SkTBitOr<SkAdvancedTypefaceMetrics::PerGlyphInfo>(
- info, SkAdvancedTypefaceMetrics::kGlyphNames_PerGlyphInfo);
+ info = SkAdvancedTypefaceMetrics::kGlyphNames_PerGlyphInfo;
info = SkTBitOr<SkAdvancedTypefaceMetrics::PerGlyphInfo>(
info, SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo);
- fontInfo = SkFontHost::GetAdvancedTypefaceMetrics(fontID, info);
- SkSafeUnref(fontInfo.get()); // SkRefPtr and Get both took a reference.
+#if !defined (SK_SFNTLY_SUBSETTER)
+ info = SkTBitOr<SkAdvancedTypefaceMetrics::PerGlyphInfo>(
+ info, SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo);
+#endif
+ fontMetrics =
+ SkFontHost::GetAdvancedTypefaceMetrics(fontID, info, NULL, 0);
+#if defined (SK_SFNTLY_SUBSETTER)
+ SkASSERT(fontMetrics);
+ SkSafeUnref(fontMetrics.get()); // SkRefPtr and Get both took a ref.
+ if (fontMetrics &&
+ fontMetrics->fType != SkAdvancedTypefaceMetrics::kTrueType_Font) {
+ // Font does not support subsetting, get new info with advance.
+ info = SkTBitOr<SkAdvancedTypefaceMetrics::PerGlyphInfo>(
+ info, SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo);
+ fontMetrics =
+ SkFontHost::GetAdvancedTypefaceMetrics(fontID, info, NULL, 0);
+ SkSafeUnref(fontMetrics.get()); // SkRefPtr and Get both took a ref
+ }
+#endif
}
- SkPDFFont* font = new SkPDFFont(fontInfo.get(), typeface, glyphID, false,
- fontDescriptor);
+ SkPDFFont* font = Create(fontMetrics.get(), typeface, glyphID,
+ relatedFontDescriptor);
FontRec newEntry(font, fontID, font->fFirstGlyphID);
- index = canonicalFonts().count();
- canonicalFonts().push(newEntry);
+ CanonicalFonts().push(newEntry);
return font; // Return the reference new SkPDFFont() created.
}
+SkPDFFont* SkPDFFont::getFontSubset(const SkPDFGlyphSet* usage) {
+ return NULL; // Default: no support.
+}
+
// static
-SkTDArray<SkPDFFont::FontRec>& SkPDFFont::canonicalFonts() {
+SkTDArray<SkPDFFont::FontRec>& SkPDFFont::CanonicalFonts() {
// This initialization is only thread safe with gcc.
static SkTDArray<FontRec> gCanonicalFonts;
return gCanonicalFonts;
}
// static
-SkMutex& SkPDFFont::canonicalFontsMutex() {
+SkMutex& SkPDFFont::CanonicalFontsMutex() {
// This initialization is only thread safe with gcc.
static SkMutex gCanonicalFontsMutex;
return gCanonicalFontsMutex;
}
// static
-bool SkPDFFont::find(uint32_t fontID, uint16_t glyphID, int* index) {
- // TODO(vandebo) optimize this, do only one search?
+bool SkPDFFont::Find(uint32_t fontID, uint16_t glyphID, int* index) {
+ // TODO(vandebo): Optimize this, do only one search?
FontRec search(NULL, fontID, glyphID);
- *index = canonicalFonts().find(search);
- if (*index >= 0)
+ *index = CanonicalFonts().find(search);
+ if (*index >= 0) {
return true;
+ }
search.fGlyphID = 0;
- *index = canonicalFonts().find(search);
+ *index = CanonicalFonts().find(search);
return false;
}
-SkPDFFont::SkPDFFont(class SkAdvancedTypefaceMetrics* fontInfo,
- SkTypeface* typeface,
- uint16_t glyphID,
- bool descendantFont,
- SkPDFDict* fontDescriptor)
+SkPDFFont::SkPDFFont(SkAdvancedTypefaceMetrics* info, SkTypeface* typeface,
+ uint16_t glyphID, bool descendantFont)
: SkPDFDict("Font"),
fTypeface(typeface),
- fType(fontInfo ? fontInfo->fType :
- SkAdvancedTypefaceMetrics::kNotEmbeddable_Font),
-#ifdef SK_DEBUG
- fDescendant(descendantFont),
-#endif
- fMultiByteGlyphs(false),
fFirstGlyphID(1),
- fLastGlyphID(fontInfo ? fontInfo->fLastGlyphID : 0),
- fFontInfo(fontInfo),
- fDescriptor(fontDescriptor) {
- if (fontInfo && fontInfo->fMultiMaster) {
+ fLastGlyphID(info ? info->fLastGlyphID : 0),
+ fFontInfo(info) {
+ if (info == NULL) {
+ fFontType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
+ } else if (info->fMultiMaster) {
+ fFontType = SkAdvancedTypefaceMetrics::kOther_Font;
+ } else {
+ fFontType = info->fType;
+ }
+}
+
+// static
+SkPDFFont* SkPDFFont::Create(SkAdvancedTypefaceMetrics* info,
+ SkTypeface* typeface, uint16_t glyphID,
+ SkPDFDict* relatedFontDescriptor) {
+ SkAdvancedTypefaceMetrics::FontType type =
+ info ? info->fType : SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
+
+ if (info && info->fMultiMaster) {
NOT_IMPLEMENTED(true, true);
- fType = SkAdvancedTypefaceMetrics::kOther_Font;
+ return new SkPDFType3Font(info,
+ typeface,
+ glyphID,
+ relatedFontDescriptor);
}
- if (fType == SkAdvancedTypefaceMetrics::kType1CID_Font ||
- fType == SkAdvancedTypefaceMetrics::kTrueType_Font) {
- if (descendantFont) {
- populateCIDFont();
- } else {
- populateType0Font();
- }
- // No need to hold onto the font info for fonts types that
- // support multibyte glyphs.
- fFontInfo = NULL;
+ if (type == SkAdvancedTypefaceMetrics::kType1CID_Font ||
+ type == SkAdvancedTypefaceMetrics::kTrueType_Font) {
+ SkASSERT(relatedFontDescriptor == NULL);
+ return new SkPDFType0Font(info, typeface);
+ }
+ if (type == SkAdvancedTypefaceMetrics::kType1_Font) {
+ return new SkPDFType1Font(info,
+ typeface,
+ glyphID,
+ relatedFontDescriptor);
+ }
+
+ SkASSERT(type == SkAdvancedTypefaceMetrics::kCFF_Font ||
+ type == SkAdvancedTypefaceMetrics::kOther_Font ||
+ type == SkAdvancedTypefaceMetrics::kNotEmbeddable_Font);
+
+ return new SkPDFType3Font(info, typeface, glyphID, relatedFontDescriptor);
+}
+
+SkAdvancedTypefaceMetrics* SkPDFFont::fontInfo() {
+ return fFontInfo.get();
+}
+
+void SkPDFFont::setFontInfo(SkAdvancedTypefaceMetrics* info) {
+ if (info == NULL || info == fFontInfo.get()) {
return;
}
+ fFontInfo = info;
+}
+
+uint16_t SkPDFFont::firstGlyphID() const {
+ return fFirstGlyphID;
+}
- if (fType == SkAdvancedTypefaceMetrics::kType1_Font &&
- populateType1Font(glyphID)) {
+uint16_t SkPDFFont::lastGlyphID() const {
+ return fLastGlyphID;
+}
+
+void SkPDFFont::setLastGlyphID(uint16_t glyphID) {
+ fLastGlyphID = glyphID;
+}
+
+void SkPDFFont::addResource(SkPDFObject* object) {
+ SkASSERT(object != NULL);
+ fResources.push(object);
+}
+
+SkPDFDict* SkPDFFont::getFontDescriptor() {
+ return fDescriptor.get();
+}
+
+void SkPDFFont::setFontDescriptor(SkPDFDict* descriptor) {
+ fDescriptor = descriptor;
+}
+
+bool SkPDFFont::addCommonFontDescriptorEntries(int16_t defaultWidth) {
+ if (fDescriptor.get() == NULL) {
+ return false;
+ }
+
+ const uint16_t emSize = fFontInfo->fEmSize;
+
+ fDescriptor->insertName("FontName", fFontInfo->fFontName);
+ fDescriptor->insertInt("Flags", fFontInfo->fStyle);
+ fDescriptor->insertScalar("Ascent",
+ scaleFromFontUnits(fFontInfo->fAscent, emSize));
+ fDescriptor->insertScalar("Descent",
+ scaleFromFontUnits(fFontInfo->fDescent, emSize));
+ fDescriptor->insertScalar("StemV",
+ scaleFromFontUnits(fFontInfo->fStemV, emSize));
+ fDescriptor->insertScalar("CapHeight",
+ scaleFromFontUnits(fFontInfo->fCapHeight, emSize));
+ fDescriptor->insertInt("ItalicAngle", fFontInfo->fItalicAngle);
+ fDescriptor->insert("FontBBox", makeFontBBox(fFontInfo->fBBox,
+ fFontInfo->fEmSize))->unref();
+
+ if (defaultWidth > 0) {
+ fDescriptor->insertScalar("MissingWidth",
+ scaleFromFontUnits(defaultWidth, emSize));
+ }
+ return true;
+}
+
+void SkPDFFont::adjustGlyphRangeForSingleByteEncoding(int16_t glyphID) {
+ // Single byte glyph encoding supports a max of 255 glyphs.
+ fFirstGlyphID = glyphID - (glyphID - 1) % 255;
+ if (fLastGlyphID > fFirstGlyphID + 255 - 1) {
+ fLastGlyphID = fFirstGlyphID + 255 - 1;
+ }
+}
+
+bool SkPDFFont::FontRec::operator==(const SkPDFFont::FontRec& b) const {
+ if (fFontID != b.fFontID) {
+ return false;
+ }
+ if (fFont != NULL && b.fFont != NULL) {
+ return fFont->fFirstGlyphID == b.fFont->fFirstGlyphID &&
+ fFont->fLastGlyphID == b.fFont->fLastGlyphID;
+ }
+ if (fGlyphID == 0 || b.fGlyphID == 0) {
+ return true;
+ }
+
+ if (fFont != NULL) {
+ return fFont->fFirstGlyphID <= b.fGlyphID &&
+ b.fGlyphID <= fFont->fLastGlyphID;
+ } else if (b.fFont != NULL) {
+ return b.fFont->fFirstGlyphID <= fGlyphID &&
+ fGlyphID <= b.fFont->fLastGlyphID;
+ }
+ return fGlyphID == b.fGlyphID;
+}
+
+SkPDFFont::FontRec::FontRec(SkPDFFont* font, uint32_t fontID, uint16_t glyphID)
+ : fFont(font),
+ fFontID(fontID),
+ fGlyphID(glyphID) {
+}
+
+void SkPDFFont::populateToUnicodeTable(const SkPDFGlyphSet* subset) {
+ if (fFontInfo == NULL || fFontInfo->fGlyphToUnicode.begin() == NULL) {
return;
}
+ SkRefPtr<SkPDFStream> pdfCmap =
+ generate_tounicode_cmap(fFontInfo->fGlyphToUnicode, subset);
+ addResource(pdfCmap.get()); // Pass reference from new.
+ insert("ToUnicode", new SkPDFObjRef(pdfCmap.get()))->unref();
+}
- SkASSERT(fType == SkAdvancedTypefaceMetrics::kType1_Font ||
- fType == SkAdvancedTypefaceMetrics::kCFF_Font ||
- fType == SkAdvancedTypefaceMetrics::kOther_Font ||
- fType == SkAdvancedTypefaceMetrics::kNotEmbeddable_Font);
- populateType3Font(glyphID);
+///////////////////////////////////////////////////////////////////////////////
+// class SkPDFType0Font
+///////////////////////////////////////////////////////////////////////////////
+
+SkPDFType0Font::SkPDFType0Font(SkAdvancedTypefaceMetrics* info,
+ SkTypeface* typeface)
+ : SkPDFFont(info, typeface, 0, false) {
+ SkDEBUGCODE(fPopulated = false);
}
-void SkPDFFont::populateType0Font() {
- fMultiByteGlyphs = true;
+SkPDFType0Font::~SkPDFType0Font() {}
- insert("Subtype", new SkPDFName("Type0"))->unref();
- insert("BaseFont", new SkPDFName(fFontInfo->fFontName))->unref();
- insert("Encoding", new SkPDFName("Identity-H"))->unref();
+SkPDFFont* SkPDFType0Font::getFontSubset(const SkPDFGlyphSet* subset) {
+ SkPDFType0Font* newSubset = new SkPDFType0Font(fontInfo(), typeface());
+ newSubset->populate(subset);
+ return newSubset;
+}
- SkRefPtr<SkPDFArray> descendantFonts = new SkPDFArray();
- descendantFonts->unref(); // SkRefPtr and new took a reference.
+#ifdef SK_DEBUG
+void SkPDFType0Font::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
+ bool indirect) {
+ SkASSERT(fPopulated);
+ return INHERITED::emitObject(stream, catalog, indirect);
+}
+#endif
+
+bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset) {
+ insertName("Subtype", "Type0");
+ insertName("BaseFont", fontInfo()->fFontName);
+ insertName("Encoding", "Identity-H");
+
+ SkPDFCIDFont* newCIDFont;
+ newCIDFont = new SkPDFCIDFont(fontInfo(), typeface(), subset);
// Pass ref new created to fResources.
- fResources.push(
- new SkPDFFont(fFontInfo.get(), fTypeface.get(), 1, true, NULL));
- descendantFonts->append(new SkPDFObjRef(fResources.top()))->unref();
+ addResource(newCIDFont);
+ SkRefPtr<SkPDFArray> descendantFonts = new SkPDFArray();
+ descendantFonts->unref(); // SkRefPtr and new took a reference.
+ descendantFonts->append(new SkPDFObjRef(newCIDFont))->unref();
insert("DescendantFonts", descendantFonts.get());
- populateToUnicodeTable();
+ populateToUnicodeTable(subset);
+
+ SkDEBUGCODE(fPopulated = true);
+ return true;
}
-void SkPDFFont::populateToUnicodeTable() {
- if (fFontInfo.get() == NULL ||
- fFontInfo->fGlyphToUnicode.begin() == NULL) {
- return;
+///////////////////////////////////////////////////////////////////////////////
+// class SkPDFCIDFont
+///////////////////////////////////////////////////////////////////////////////
+
+SkPDFCIDFont::SkPDFCIDFont(SkAdvancedTypefaceMetrics* info,
+ SkTypeface* typeface, const SkPDFGlyphSet* subset)
+ : SkPDFFont(info, typeface, 0, true) {
+ populate(subset);
+}
+
+SkPDFCIDFont::~SkPDFCIDFont() {}
+
+bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth,
+ const SkTDArray<uint32_t>* subset) {
+ SkRefPtr<SkPDFDict> descriptor = new SkPDFDict("FontDescriptor");
+ descriptor->unref(); // SkRefPtr and new both took a ref.
+ setFontDescriptor(descriptor.get());
+
+ switch (getType()) {
+ case SkAdvancedTypefaceMetrics::kTrueType_Font: {
+ SkASSERT(subset);
+ // Font subsetting
+ SkPDFStream* rawStream = NULL;
+ int fontSize = get_subset_font_stream(fontInfo()->fFontName.c_str(),
+ typeface(),
+ *subset,
+ &rawStream);
+ SkASSERT(fontSize);
+ SkASSERT(rawStream);
+ SkRefPtr<SkPDFStream> fontStream = rawStream;
+ // SkRefPtr and new both ref()'d fontStream, pass one.
+ addResource(fontStream.get());
+
+ fontStream->insertInt("Length1", fontSize);
+ descriptor->insert("FontFile2",
+ new SkPDFObjRef(fontStream.get()))->unref();
+ break;
+ }
+ case SkAdvancedTypefaceMetrics::kCFF_Font:
+ case SkAdvancedTypefaceMetrics::kType1CID_Font: {
+ SkRefPtr<SkStream> fontData =
+ SkFontHost::OpenStream(SkTypeface::UniqueID(typeface()));
+ fontData->unref(); // SkRefPtr and OpenStream both took a ref.
+ SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
+ // SkRefPtr and new both ref()'d fontStream, pass one.
+ addResource(fontStream.get());
+
+ if (getType() == SkAdvancedTypefaceMetrics::kCFF_Font) {
+ fontStream->insertName("Subtype", "Type1C");
+ } else {
+ fontStream->insertName("Subtype", "CIDFontType0c");
+ }
+ descriptor->insert("FontFile3",
+ new SkPDFObjRef(fontStream.get()))->unref();
+ break;
+ }
+ default:
+ SkASSERT(false);
}
- SkDynamicMemoryWStream cmap;
- append_tounicode_header(&cmap);
- append_cmap_bfchar_sections(fFontInfo->fGlyphToUnicode, &cmap);
- append_cmap_footer(&cmap);
- SkRefPtr<SkMemoryStream> cmapStream = new SkMemoryStream();
- cmapStream->unref(); // SkRefPtr and new took a reference.
- cmapStream->setMemoryOwned(cmap.detach(), cmap.getOffset());
- SkRefPtr<SkPDFStream> pdfCmap = new SkPDFStream(cmapStream.get());
- fResources.push(pdfCmap.get()); // Pass reference from new.
- insert("ToUnicode", new SkPDFObjRef(pdfCmap.get()))->unref();
+ addResource(descriptor.get());
+ descriptor->ref();
+
+ insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref();
+ return addCommonFontDescriptorEntries(defaultWidth);
}
-void SkPDFFont::populateCIDFont() {
- fMultiByteGlyphs = true;
- insert("BaseFont", new SkPDFName(fFontInfo->fFontName))->unref();
+bool SkPDFCIDFont::populate(const SkPDFGlyphSet* subset) {
+ // Generate new font metrics with advance info for true type fonts.
+ if (fontInfo()->fType == SkAdvancedTypefaceMetrics::kTrueType_Font) {
+ // Generate glyph id array.
+ SkTDArray<uint32_t> glyphIDs;
+ glyphIDs.push(0); // Always include glyph 0.
+ if (subset) {
+ subset->exportTo(&glyphIDs);
+ }
- if (fFontInfo->fType == SkAdvancedTypefaceMetrics::kType1CID_Font) {
- insert("Subtype", new SkPDFName("CIDFontType0"))->unref();
- } else if (fFontInfo->fType == SkAdvancedTypefaceMetrics::kTrueType_Font) {
- insert("Subtype", new SkPDFName("CIDFontType2"))->unref();
- insert("CIDToGIDMap", new SkPDFName("Identity"))->unref();
+ SkRefPtr<SkAdvancedTypefaceMetrics> fontMetrics;
+ SkAdvancedTypefaceMetrics::PerGlyphInfo info;
+ info = SkAdvancedTypefaceMetrics::kGlyphNames_PerGlyphInfo;
+ info = SkTBitOr<SkAdvancedTypefaceMetrics::PerGlyphInfo>(
+ info, SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo);
+ uint32_t* glyphs = (glyphIDs.count() == 1) ? NULL : glyphIDs.begin();
+ uint32_t glyphsCount = glyphs ? glyphIDs.count() : 0;
+ fontMetrics =
+ SkFontHost::GetAdvancedTypefaceMetrics(
+ SkTypeface::UniqueID(typeface()),
+ info,
+ glyphs,
+ glyphsCount);
+ SkSafeUnref(fontMetrics.get()); // SkRefPtr and Get both took a ref
+ setFontInfo(fontMetrics.get());
+ addFontDescriptor(0, &glyphIDs);
+ } else {
+ // Other CID fonts
+ addFontDescriptor(0, NULL);
+ }
+
+ insertName("BaseFont", fontInfo()->fFontName);
+
+ if (getType() == SkAdvancedTypefaceMetrics::kType1CID_Font) {
+ insertName("Subtype", "CIDFontType0");
+ } else if (getType() == SkAdvancedTypefaceMetrics::kTrueType_Font) {
+ insertName("Subtype", "CIDFontType2");
+ insertName("CIDToGIDMap", "Identity");
} else {
SkASSERT(false);
}
@@ -638,32 +1135,31 @@ void SkPDFFont::populateCIDFont() {
sysInfo->unref(); // SkRefPtr and new both took a reference.
sysInfo->insert("Registry", new SkPDFString("Adobe"))->unref();
sysInfo->insert("Ordering", new SkPDFString("Identity"))->unref();
- sysInfo->insert("Supplement", new SkPDFInt(0))->unref();
+ sysInfo->insertInt("Supplement", 0);
insert("CIDSystemInfo", sysInfo.get());
- addFontDescriptor(0);
-
- if (fFontInfo->fGlyphWidths.get()) {
+ if (fontInfo()->fGlyphWidths.get()) {
int16_t defaultWidth = 0;
SkRefPtr<SkPDFArray> widths =
- composeAdvanceData(fFontInfo->fGlyphWidths.get(),
- fFontInfo->fEmSize, &appendWidth, &defaultWidth);
+ composeAdvanceData(fontInfo()->fGlyphWidths.get(),
+ fontInfo()->fEmSize, &appendWidth,
+ &defaultWidth);
widths->unref(); // SkRefPtr and compose both took a reference.
if (widths->size())
insert("W", widths.get());
if (defaultWidth != 0) {
- insert("DW", new SkPDFScalar(scaleFromFontUnits(
- defaultWidth, fFontInfo->fEmSize)))->unref();
+ insertScalar("DW", scaleFromFontUnits(defaultWidth,
+ fontInfo()->fEmSize));
}
}
- if (fFontInfo->fVerticalMetrics.get()) {
+ if (fontInfo()->fVerticalMetrics.get()) {
struct SkAdvancedTypefaceMetrics::VerticalMetric defaultAdvance;
defaultAdvance.fVerticalAdvance = 0;
defaultAdvance.fOriginXDisp = 0;
defaultAdvance.fOriginYDisp = 0;
SkRefPtr<SkPDFArray> advances =
- composeAdvanceData(fFontInfo->fVerticalMetrics.get(),
- fFontInfo->fEmSize, &appendVerticalAdvance,
+ composeAdvanceData(fontInfo()->fVerticalMetrics.get(),
+ fontInfo()->fEmSize, &appendVerticalAdvance,
&defaultAdvance);
advances->unref(); // SkRefPtr and compose both took a ref.
if (advances->size())
@@ -672,22 +1168,77 @@ void SkPDFFont::populateCIDFont() {
defaultAdvance.fOriginXDisp ||
defaultAdvance.fOriginYDisp) {
insert("DW2", appendVerticalAdvance(defaultAdvance,
- fFontInfo->fEmSize,
+ fontInfo()->fEmSize,
new SkPDFArray))->unref();
}
}
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// class SkPDFType1Font
+///////////////////////////////////////////////////////////////////////////////
+
+SkPDFType1Font::SkPDFType1Font(SkAdvancedTypefaceMetrics* info,
+ SkTypeface* typeface,
+ uint16_t glyphID,
+ SkPDFDict* relatedFontDescriptor)
+ : SkPDFFont(info, typeface, glyphID, false) {
+ populate(glyphID);
+}
+
+SkPDFType1Font::~SkPDFType1Font() {}
+
+bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) {
+ SkRefPtr<SkPDFDict> descriptor = getFontDescriptor();
+ if (descriptor.get() != NULL) {
+ addResource(descriptor.get());
+ descriptor->ref();
+ insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref();
+ return true;
+ }
+
+ descriptor = new SkPDFDict("FontDescriptor");
+ descriptor->unref(); // SkRefPtr and new both took a ref.
+ setFontDescriptor(descriptor.get());
+
+ size_t header SK_INIT_TO_AVOID_WARNING;
+ size_t data SK_INIT_TO_AVOID_WARNING;
+ size_t trailer SK_INIT_TO_AVOID_WARNING;
+ SkRefPtr<SkStream> rawFontData =
+ SkFontHost::OpenStream(SkTypeface::UniqueID(typeface()));
+ rawFontData->unref(); // SkRefPtr and OpenStream both took a ref.
+ SkStream* fontData = handleType1Stream(rawFontData.get(), &header, &data,
+ &trailer);
+ if (fontData == NULL) {
+ return false;
+ }
+ SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData);
+ // SkRefPtr and new both ref()'d fontStream, pass one.
+ addResource(fontStream.get());
+ fontStream->insertInt("Length1", header);
+ fontStream->insertInt("Length2", data);
+ fontStream->insertInt("Length3", trailer);
+ descriptor->insert("FontFile", new SkPDFObjRef(fontStream.get()))->unref();
+
+ addResource(descriptor.get());
+ descriptor->ref();
+ insert("FontDescriptor", new SkPDFObjRef(descriptor.get()))->unref();
+
+ return addCommonFontDescriptorEntries(defaultWidth);
}
-bool SkPDFFont::populateType1Font(int16_t glyphID) {
- SkASSERT(!fFontInfo->fVerticalMetrics.get());
- SkASSERT(fFontInfo->fGlyphWidths.get());
+bool SkPDFType1Font::populate(int16_t glyphID) {
+ SkASSERT(!fontInfo()->fVerticalMetrics.get());
+ SkASSERT(fontInfo()->fGlyphWidths.get());
adjustGlyphRangeForSingleByteEncoding(glyphID);
int16_t defaultWidth = 0;
const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry = NULL;
const SkAdvancedTypefaceMetrics::WidthRange* widthEntry;
- for (widthEntry = fFontInfo.get()->fGlyphWidths.get();
+ for (widthEntry = fontInfo()->fGlyphWidths.get();
widthEntry != NULL;
widthEntry = widthEntry->fNext.get()) {
switch (widthEntry->fType) {
@@ -704,11 +1255,12 @@ bool SkPDFFont::populateType1Font(int16_t glyphID) {
}
}
- if (!addFontDescriptor(defaultWidth))
+ if (!addFontDescriptor(defaultWidth)) {
return false;
+ }
- insert("Subtype", new SkPDFName("Type1"))->unref();
- insert("BaseFont", new SkPDFName(fFontInfo->fFontName))->unref();
+ insertName("Subtype", "Type1");
+ insertName("BaseFont", fontInfo()->fFontName);
addWidthInfoFromRange(defaultWidth, widthRangeEntry);
@@ -720,32 +1272,73 @@ bool SkPDFFont::populateType1Font(int16_t glyphID) {
encDiffs->unref(); // SkRefPtr and new both took a reference.
encoding->insert("Differences", encDiffs.get());
- encDiffs->reserve(fLastGlyphID - fFirstGlyphID + 2);
- encDiffs->append(new SkPDFInt(1))->unref();
- for (int gID = fFirstGlyphID; gID <= fLastGlyphID; gID++) {
- encDiffs->append(
- new SkPDFName(fFontInfo->fGlyphNames->get()[gID]))->unref();
+ encDiffs->reserve(lastGlyphID() - firstGlyphID() + 2);
+ encDiffs->appendInt(1);
+ for (int gID = firstGlyphID(); gID <= lastGlyphID(); gID++) {
+ encDiffs->appendName(fontInfo()->fGlyphNames->get()[gID].c_str());
}
- if (fFontInfo->fLastGlyphID <= 255)
- fFontInfo = NULL;
return true;
}
-void SkPDFFont::populateType3Font(int16_t glyphID) {
+void SkPDFType1Font::addWidthInfoFromRange(
+ int16_t defaultWidth,
+ const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry) {
+ SkRefPtr<SkPDFArray> widthArray = new SkPDFArray();
+ widthArray->unref(); // SkRefPtr and new both took a ref.
+ int firstChar = 0;
+ if (widthRangeEntry) {
+ const uint16_t emSize = fontInfo()->fEmSize;
+ int startIndex = firstGlyphID() - widthRangeEntry->fStartId;
+ int endIndex = startIndex + lastGlyphID() - firstGlyphID() + 1;
+ if (startIndex < 0)
+ startIndex = 0;
+ if (endIndex > widthRangeEntry->fAdvance.count())
+ endIndex = widthRangeEntry->fAdvance.count();
+ if (widthRangeEntry->fStartId == 0) {
+ appendWidth(widthRangeEntry->fAdvance[0], emSize, widthArray.get());
+ } else {
+ firstChar = startIndex + widthRangeEntry->fStartId;
+ }
+ for (int i = startIndex; i < endIndex; i++) {
+ appendWidth(widthRangeEntry->fAdvance[i], emSize, widthArray.get());
+ }
+ } else {
+ appendWidth(defaultWidth, 1000, widthArray.get());
+ }
+ insertInt("FirstChar", firstChar);
+ insertInt("LastChar", firstChar + widthArray->size() - 1);
+ insert("Widths", widthArray.get());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// class SkPDFType3Font
+///////////////////////////////////////////////////////////////////////////////
+
+SkPDFType3Font::SkPDFType3Font(SkAdvancedTypefaceMetrics* info,
+ SkTypeface* typeface,
+ uint16_t glyphID,
+ SkPDFDict* relatedFontDescriptor)
+ : SkPDFFont(info, typeface, glyphID, false) {
+ populate(glyphID);
+}
+
+SkPDFType3Font::~SkPDFType3Font() {}
+
+bool SkPDFType3Font::populate(int16_t glyphID) {
SkPaint paint;
- paint.setTypeface(fTypeface.get());
+ paint.setTypeface(typeface());
paint.setTextSize(1000);
SkAutoGlyphCache autoCache(paint, NULL);
SkGlyphCache* cache = autoCache.getCache();
// If fLastGlyphID isn't set (because there is not fFontInfo), look it up.
- if (fLastGlyphID == 0) {
- fLastGlyphID = cache->getGlyphCount() - 1;
+ if (lastGlyphID() == 0) {
+ setLastGlyphID(cache->getGlyphCount() - 1);
}
adjustGlyphRangeForSingleByteEncoding(glyphID);
- insert("Subtype", new SkPDFName("Type3"))->unref();
+ insertName("Subtype", "Type3");
// Flip about the x-axis and scale by 1/1000.
SkMatrix fontMatrix;
fontMatrix.setScale(SkScalarInvert(1000), -SkScalarInvert(1000));
@@ -762,20 +1355,20 @@ void SkPDFFont::populateType3Font(int16_t glyphID) {
SkRefPtr<SkPDFArray> encDiffs = new SkPDFArray;
encDiffs->unref(); // SkRefPtr and new both took a reference.
encoding->insert("Differences", encDiffs.get());
- encDiffs->reserve(fLastGlyphID - fFirstGlyphID + 2);
- encDiffs->append(new SkPDFInt(1))->unref();
+ encDiffs->reserve(lastGlyphID() - firstGlyphID() + 2);
+ encDiffs->appendInt(1);
SkRefPtr<SkPDFArray> widthArray = new SkPDFArray();
widthArray->unref(); // SkRefPtr and new both took a ref.
SkIRect bbox = SkIRect::MakeEmpty();
- for (int gID = fFirstGlyphID; gID <= fLastGlyphID; gID++) {
+ for (int gID = firstGlyphID(); gID <= lastGlyphID(); gID++) {
SkString characterName;
characterName.printf("gid%d", gID);
- encDiffs->append(new SkPDFName(characterName))->unref();
+ encDiffs->appendName(characterName.c_str());
const SkGlyph& glyph = cache->getGlyphIDMetrics(gID);
- widthArray->append(new SkPDFScalar(SkFixedToScalar(glyph.fAdvanceX)))->unref();
+ widthArray->appendScalar(SkFixedToScalar(glyph.fAdvanceX));
SkIRect glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop,
glyph.fWidth, glyph.fHeight);
bbox.join(glyphBBox);
@@ -791,186 +1384,22 @@ void SkPDFFont::populateType3Font(int16_t glyphID) {
}
SkRefPtr<SkMemoryStream> glyphStream = new SkMemoryStream();
glyphStream->unref(); // SkRefPtr and new both took a ref.
- glyphStream->setMemoryOwned(content.detach(), content.getOffset());
+ glyphStream->setData(content.copyToData())->unref();
SkRefPtr<SkPDFStream> glyphDescription =
new SkPDFStream(glyphStream.get());
// SkRefPtr and new both ref()'d charProcs, pass one.
- fResources.push(glyphDescription.get());
+ addResource(glyphDescription.get());
charProcs->insert(characterName.c_str(),
new SkPDFObjRef(glyphDescription.get()))->unref();
}
insert("FontBBox", makeFontBBox(bbox, 1000))->unref();
- insert("FirstChar", new SkPDFInt(fFirstGlyphID))->unref();
- insert("LastChar", new SkPDFInt(fLastGlyphID))->unref();
+ insertInt("FirstChar", firstGlyphID());
+ insertInt("LastChar", lastGlyphID());
insert("Widths", widthArray.get());
- insert("CIDToGIDMap", new SkPDFName("Identity"))->unref();
+ insertName("CIDToGIDMap", "Identity");
- if (fFontInfo && fFontInfo->fLastGlyphID <= 255)
- fFontInfo = NULL;
-
- populateToUnicodeTable();
-}
-
-bool SkPDFFont::addFontDescriptor(int16_t defaultWidth) {
- if (fDescriptor.get() != NULL) {
- fResources.push(fDescriptor.get());
- fDescriptor->ref();
- insert("FontDescriptor", new SkPDFObjRef(fDescriptor.get()))->unref();
- return true;
- }
-
- fDescriptor = new SkPDFDict("FontDescriptor");
- fDescriptor->unref(); // SkRefPtr and new both took a ref.
-
- switch (fFontInfo->fType) {
- case SkAdvancedTypefaceMetrics::kType1_Font: {
- size_t header SK_INIT_TO_AVOID_WARNING;
- size_t data SK_INIT_TO_AVOID_WARNING;
- size_t trailer SK_INIT_TO_AVOID_WARNING;
- SkRefPtr<SkStream> rawFontData =
- SkFontHost::OpenStream(SkTypeface::UniqueID(fTypeface.get()));
- rawFontData->unref(); // SkRefPtr and OpenStream both took a ref.
- SkStream* fontData = handleType1Stream(rawFontData.get(), &header,
- &data, &trailer);
- if (fontData == NULL)
- return false;
- SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData);
- // SkRefPtr and new both ref()'d fontStream, pass one.
- fResources.push(fontStream.get());
- fontStream->insert("Length1", new SkPDFInt(header))->unref();
- fontStream->insert("Length2", new SkPDFInt(data))->unref();
- fontStream->insert("Length3", new SkPDFInt(trailer))->unref();
- fDescriptor->insert("FontFile",
- new SkPDFObjRef(fontStream.get()))->unref();
- break;
- }
- case SkAdvancedTypefaceMetrics::kTrueType_Font: {
- SkRefPtr<SkStream> fontData =
- SkFontHost::OpenStream(SkTypeface::UniqueID(fTypeface.get()));
- fontData->unref(); // SkRefPtr and OpenStream both took a ref.
- SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
- // SkRefPtr and new both ref()'d fontStream, pass one.
- fResources.push(fontStream.get());
-
- fontStream->insert("Length1",
- new SkPDFInt(fontData->getLength()))->unref();
- fDescriptor->insert("FontFile2",
- new SkPDFObjRef(fontStream.get()))->unref();
- break;
- }
- case SkAdvancedTypefaceMetrics::kCFF_Font:
- case SkAdvancedTypefaceMetrics::kType1CID_Font: {
- SkRefPtr<SkStream> fontData =
- SkFontHost::OpenStream(SkTypeface::UniqueID(fTypeface.get()));
- fontData->unref(); // SkRefPtr and OpenStream both took a ref.
- SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get());
- // SkRefPtr and new both ref()'d fontStream, pass one.
- fResources.push(fontStream.get());
-
- if (fFontInfo->fType == SkAdvancedTypefaceMetrics::kCFF_Font) {
- fontStream->insert("Subtype", new SkPDFName("Type1C"))->unref();
- } else {
- fontStream->insert("Subtype",
- new SkPDFName("CIDFontType0c"))->unref();
- }
- fDescriptor->insert("FontFile3",
- new SkPDFObjRef(fontStream.get()))->unref();
- break;
- }
- default:
- SkASSERT(false);
- }
-
- const uint16_t emSize = fFontInfo->fEmSize;
- fResources.push(fDescriptor.get());
- fDescriptor->ref();
- insert("FontDescriptor", new SkPDFObjRef(fDescriptor.get()))->unref();
-
- fDescriptor->insert("FontName", new SkPDFName(
- fFontInfo->fFontName))->unref();
- fDescriptor->insert("Flags", new SkPDFInt(fFontInfo->fStyle))->unref();
- fDescriptor->insert("Ascent", new SkPDFScalar(
- scaleFromFontUnits(fFontInfo->fAscent, emSize)))->unref();
- fDescriptor->insert("Descent", new SkPDFScalar(
- scaleFromFontUnits(fFontInfo->fDescent, emSize)))->unref();
- fDescriptor->insert("StemV", new SkPDFScalar(
- scaleFromFontUnits(fFontInfo->fStemV, emSize)))->unref();
- fDescriptor->insert("CapHeight", new SkPDFScalar(
- scaleFromFontUnits(fFontInfo->fCapHeight, emSize)))->unref();
- fDescriptor->insert("ItalicAngle", new SkPDFInt(
- fFontInfo->fItalicAngle))->unref();
- fDescriptor->insert("FontBBox", makeFontBBox(fFontInfo->fBBox,
- fFontInfo->fEmSize))->unref();
-
- if (defaultWidth > 0) {
- fDescriptor->insert("MissingWidth", new SkPDFScalar(
- scaleFromFontUnits(defaultWidth, emSize)))->unref();
- }
+ populateToUnicodeTable(NULL);
return true;
}
-void SkPDFFont::addWidthInfoFromRange(
- int16_t defaultWidth,
- const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry) {
- SkRefPtr<SkPDFArray> widthArray = new SkPDFArray();
- widthArray->unref(); // SkRefPtr and new both took a ref.
- int firstChar = 0;
- if (widthRangeEntry) {
- const uint16_t emSize = fFontInfo->fEmSize;
- int startIndex = fFirstGlyphID - widthRangeEntry->fStartId;
- int endIndex = startIndex + fLastGlyphID - fFirstGlyphID + 1;
- if (startIndex < 0)
- startIndex = 0;
- if (endIndex > widthRangeEntry->fAdvance.count())
- endIndex = widthRangeEntry->fAdvance.count();
- if (widthRangeEntry->fStartId == 0) {
- appendWidth(widthRangeEntry->fAdvance[0], emSize, widthArray.get());
- } else {
- firstChar = startIndex + widthRangeEntry->fStartId;
- }
- for (int i = startIndex; i < endIndex; i++)
- appendWidth(widthRangeEntry->fAdvance[i], emSize, widthArray.get());
- } else {
- appendWidth(defaultWidth, 1000, widthArray.get());
- }
- insert("FirstChar", new SkPDFInt(firstChar))->unref();
- insert("LastChar",
- new SkPDFInt(firstChar + widthArray->size() - 1))->unref();
- insert("Widths", widthArray.get());
-}
-
-void SkPDFFont::adjustGlyphRangeForSingleByteEncoding(int16_t glyphID) {
- // Single byte glyph encoding supports a max of 255 glyphs.
- fFirstGlyphID = glyphID - (glyphID - 1) % 255;
- if (fLastGlyphID > fFirstGlyphID + 255 - 1) {
- fLastGlyphID = fFirstGlyphID + 255 - 1;
- }
-}
-
-
-bool SkPDFFont::FontRec::operator==(const SkPDFFont::FontRec& b) const {
- if (fFontID != b.fFontID)
- return false;
- if (fFont != NULL && b.fFont != NULL) {
- return fFont->fFirstGlyphID == b.fFont->fFirstGlyphID &&
- fFont->fLastGlyphID == b.fFont->fLastGlyphID;
- }
- if (fGlyphID == 0 || b.fGlyphID == 0)
- return true;
-
- if (fFont != NULL) {
- return fFont->fFirstGlyphID <= b.fGlyphID &&
- b.fGlyphID <= fFont->fLastGlyphID;
- } else if (b.fFont != NULL) {
- return b.fFont->fFirstGlyphID <= fGlyphID &&
- fGlyphID <= b.fFont->fLastGlyphID;
- }
- return fGlyphID == b.fGlyphID;
-}
-
-SkPDFFont::FontRec::FontRec(SkPDFFont* font, uint32_t fontID, uint16_t glyphID)
- : fFont(font),
- fFontID(fontID),
- fGlyphID(glyphID) {
-}
diff --git a/src/pdf/SkPDFFontImpl.h b/src/pdf/SkPDFFontImpl.h
new file mode 100755
index 0000000..d298a38
--- /dev/null
+++ b/src/pdf/SkPDFFontImpl.h
@@ -0,0 +1,84 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkPDFFontImpl_DEFINED
+#define SkPDFFontImpl_DEFINED
+
+#include "SkPDFFont.h"
+
+class SkPDFType0Font : public SkPDFFont {
+public:
+ virtual ~SkPDFType0Font();
+ virtual bool multiByteGlyphs() const { return true; }
+ SK_API virtual SkPDFFont* getFontSubset(const SkPDFGlyphSet* usage);
+#ifdef SK_DEBUG
+ virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
+ bool indirect);
+#endif
+
+private:
+ friend class SkPDFFont; // to access the constructor
+#ifdef SK_DEBUG
+ bool fPopulated;
+ typedef SkPDFDict INHERITED;
+#endif
+
+ SkPDFType0Font(SkAdvancedTypefaceMetrics* info, SkTypeface* typeface);
+
+ bool populate(const SkPDFGlyphSet* subset);
+};
+
+class SkPDFCIDFont : public SkPDFFont {
+public:
+ virtual ~SkPDFCIDFont();
+ virtual bool multiByteGlyphs() const { return true; }
+
+private:
+ friend class SkPDFType0Font; // to access the constructor
+
+ SkPDFCIDFont(SkAdvancedTypefaceMetrics* info, SkTypeface* typeface,
+ const SkPDFGlyphSet* subset);
+
+ bool populate(const SkPDFGlyphSet* subset);
+ bool addFontDescriptor(int16_t defaultWidth,
+ const SkTDArray<uint32_t>* subset);
+};
+
+class SkPDFType1Font : public SkPDFFont {
+public:
+ virtual ~SkPDFType1Font();
+ virtual bool multiByteGlyphs() const { return false; }
+
+private:
+ friend class SkPDFFont; // to access the constructor
+
+ SkPDFType1Font(SkAdvancedTypefaceMetrics* info, SkTypeface* typeface,
+ uint16_t glyphID, SkPDFDict* relatedFontDescriptor);
+
+ bool populate(int16_t glyphID);
+ bool addFontDescriptor(int16_t defaultWidth);
+ void addWidthInfoFromRange(int16_t defaultWidth,
+ const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry);
+};
+
+class SkPDFType3Font : public SkPDFFont {
+public:
+ virtual ~SkPDFType3Font();
+ virtual bool multiByteGlyphs() const { return false; }
+
+private:
+ friend class SkPDFFont; // to access the constructor
+
+ SkPDFType3Font(SkAdvancedTypefaceMetrics* info, SkTypeface* typeface,
+ uint16_t glyphID, SkPDFDict* relatedFontDescriptor);
+
+ bool populate(int16_t glyphID);
+};
+
+#endif
diff --git a/src/pdf/SkPDFFormXObject.cpp b/src/pdf/SkPDFFormXObject.cpp
index 40a5564..5ac93e4 100644
--- a/src/pdf/SkPDFFormXObject.cpp
+++ b/src/pdf/SkPDFFormXObject.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2010 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkPDFFormXObject.h"
#include "SkMatrix.h"
@@ -31,13 +24,12 @@ SkPDFFormXObject::SkPDFFormXObject(SkPDFDevice* device) {
SkRefPtr<SkStream> content = device->content();
content->unref(); // SkRefPtr and content() both took a reference.
- fStream = new SkPDFStream(content.get());
- fStream->unref(); // SkRefPtr and new both took a reference.
+ setData(content.get());
- insert("Type", new SkPDFName("XObject"))->unref();
- insert("Subtype", new SkPDFName("Form"))->unref();
+ insertName("Type", "XObject");
+ insertName("Subtype", "Form");
insert("BBox", device->getMediaBox().get());
- insert("Resources", device->getResourceDict().get());
+ insert("Resources", device->getResourceDict());
// We invert the initial transform and apply that to the xobject so that
// it doesn't get applied twice. We can't just undo it because it's
@@ -53,7 +45,7 @@ SkPDFFormXObject::SkPDFFormXObject(SkPDFDevice* device) {
// isolated blending. Do this conditionally if that changes.
SkRefPtr<SkPDFDict> group = new SkPDFDict("Group");
group->unref(); // SkRefPtr and new both took a reference.
- group->insert("S", new SkPDFName("Transparency"))->unref();
+ group->insertName("S", "Transparency");
group->insert("I", new SkPDFBool(true))->unref(); // Isolated.
insert("Group", group.get());
}
@@ -62,33 +54,6 @@ SkPDFFormXObject::~SkPDFFormXObject() {
fResources.unrefAll();
}
-void SkPDFFormXObject::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
- bool indirect) {
- if (indirect)
- return emitIndirectObject(stream, catalog);
-
- fStream->emitObject(stream, catalog, indirect);
-}
-
-size_t SkPDFFormXObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
- if (indirect)
- return getIndirectOutputSize(catalog);
-
- return fStream->getOutputSize(catalog, indirect);
-}
-
void SkPDFFormXObject::getResources(SkTDArray<SkPDFObject*>* resourceList) {
- resourceList->setReserve(resourceList->count() + fResources.count());
- for (int i = 0; i < fResources.count(); i++) {
- resourceList->push(fResources[i]);
- fResources[i]->ref();
- }
-}
-
-SkPDFObject* SkPDFFormXObject::insert(SkPDFName* key, SkPDFObject* value) {
- return fStream->insert(key, value);
-}
-
-SkPDFObject* SkPDFFormXObject::insert(const char key[], SkPDFObject* value) {
- return fStream->insert(key, value);
+ GetResourcesHelper(&fResources, resourceList);
}
diff --git a/src/pdf/SkPDFGraphicState.cpp b/src/pdf/SkPDFGraphicState.cpp
index b08bf24..ad3f57b 100644
--- a/src/pdf/SkPDFGraphicState.cpp
+++ b/src/pdf/SkPDFGraphicState.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2011 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2011 Google Inc.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkPDFFormXObject.h"
#include "SkPDFGraphicState.h"
#include "SkPDFUtils.h"
@@ -46,7 +39,7 @@ static const char* blend_mode_from_xfermode(SkXfermode::Mode mode) {
case SkXfermode::kDstOut_Mode:
return "Normal";
- // TODO(vandebo) Figure out if we can support more of these modes.
+ // TODO(vandebo): Figure out if we can support more of these modes.
case SkXfermode::kSrcATop_Mode:
case SkXfermode::kDstATop_Mode:
case SkXfermode::kXor_Mode:
@@ -57,22 +50,18 @@ static const char* blend_mode_from_xfermode(SkXfermode::Mode mode) {
}
SkPDFGraphicState::~SkPDFGraphicState() {
- SkAutoMutexAcquire lock(canonicalPaintsMutex());
+ SkAutoMutexAcquire lock(CanonicalPaintsMutex());
if (!fSMask) {
- int index = find(fPaint);
+ int index = Find(fPaint);
SkASSERT(index >= 0);
- canonicalPaints().removeShuffle(index);
+ SkASSERT(CanonicalPaints()[index].fGraphicState == this);
+ CanonicalPaints().removeShuffle(index);
}
fResources.unrefAll();
}
void SkPDFGraphicState::getResources(SkTDArray<SkPDFObject*>* resourceList) {
- resourceList->setReserve(resourceList->count() + fResources.count());
- for (int i = 0; i < fResources.count(); i++) {
- resourceList->push(fResources[i]);
- fResources[i]->ref();
- fResources[i]->getResources(resourceList);
- }
+ GetResourcesHelper(&fResources, resourceList);
}
void SkPDFGraphicState::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
@@ -89,30 +78,30 @@ size_t SkPDFGraphicState::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
// static
SkTDArray<SkPDFGraphicState::GSCanonicalEntry>&
-SkPDFGraphicState::canonicalPaints() {
+SkPDFGraphicState::CanonicalPaints() {
// This initialization is only thread safe with gcc.
static SkTDArray<SkPDFGraphicState::GSCanonicalEntry> gCanonicalPaints;
return gCanonicalPaints;
}
// static
-SkMutex& SkPDFGraphicState::canonicalPaintsMutex() {
+SkMutex& SkPDFGraphicState::CanonicalPaintsMutex() {
// This initialization is only thread safe with gcc.
static SkMutex gCanonicalPaintsMutex;
return gCanonicalPaintsMutex;
}
// static
-SkPDFGraphicState* SkPDFGraphicState::getGraphicStateForPaint(
+SkPDFGraphicState* SkPDFGraphicState::GetGraphicStateForPaint(
const SkPaint& paint) {
- SkAutoMutexAcquire lock(canonicalPaintsMutex());
- int index = find(paint);
+ SkAutoMutexAcquire lock(CanonicalPaintsMutex());
+ int index = Find(paint);
if (index >= 0) {
- canonicalPaints()[index].fGraphicState->ref();
- return canonicalPaints()[index].fGraphicState;
+ CanonicalPaints()[index].fGraphicState->ref();
+ return CanonicalPaints()[index].fGraphicState;
}
GSCanonicalEntry newEntry(new SkPDFGraphicState(paint));
- canonicalPaints().push(newEntry);
+ CanonicalPaints().push(newEntry);
return newEntry.fGraphicState;
}
@@ -126,8 +115,8 @@ SkPDFObject* SkPDFGraphicState::GetInvertFunction() {
SkRefPtr<SkPDFArray> domainAndRange = new SkPDFArray;
domainAndRange->unref(); // SkRefPtr and new both took a reference.
domainAndRange->reserve(2);
- domainAndRange->append(new SkPDFInt(0))->unref();
- domainAndRange->append(new SkPDFInt(1))->unref();
+ domainAndRange->appendInt(0);
+ domainAndRange->appendInt(1);
static const char psInvert[] = "{1 exch sub}";
SkRefPtr<SkMemoryStream> psInvertStream =
@@ -135,7 +124,7 @@ SkPDFObject* SkPDFGraphicState::GetInvertFunction() {
psInvertStream->unref(); // SkRefPtr and new both took a reference.
invertFunction = new SkPDFStream(psInvertStream.get());
- invertFunction->insert("FunctionType", new SkPDFInt(4))->unref();
+ invertFunction->insertInt("FunctionType", 4);
invertFunction->insert("Domain", domainAndRange.get());
invertFunction->insert("Range", domainAndRange.get());
}
@@ -143,21 +132,21 @@ SkPDFObject* SkPDFGraphicState::GetInvertFunction() {
}
// static
-SkPDFGraphicState* SkPDFGraphicState::getSMaskGraphicState(
+SkPDFGraphicState* SkPDFGraphicState::GetSMaskGraphicState(
SkPDFFormXObject* sMask, bool invert) {
// The practical chances of using the same mask more than once are unlikely
// enough that it's not worth canonicalizing.
- SkAutoMutexAcquire lock(canonicalPaintsMutex());
+ SkAutoMutexAcquire lock(CanonicalPaintsMutex());
SkRefPtr<SkPDFDict> sMaskDict = new SkPDFDict("Mask");
sMaskDict->unref(); // SkRefPtr and new both took a reference.
- sMaskDict->insert("S", new SkPDFName("Alpha"))->unref();
+ sMaskDict->insertName("S", "Alpha");
sMaskDict->insert("G", new SkPDFObjRef(sMask))->unref();
SkPDFGraphicState* result = new SkPDFGraphicState;
result->fPopulated = true;
result->fSMask = true;
- result->insert("Type", new SkPDFName("ExtGState"))->unref();
+ result->insertName("Type", "ExtGState");
result->insert("SMask", sMaskDict.get());
result->fResources.push(sMask);
sMask->ref();
@@ -173,24 +162,24 @@ SkPDFGraphicState* SkPDFGraphicState::getSMaskGraphicState(
}
// static
-SkPDFGraphicState* SkPDFGraphicState::getNoSMaskGraphicState() {
- SkAutoMutexAcquire lock(canonicalPaintsMutex());
+SkPDFGraphicState* SkPDFGraphicState::GetNoSMaskGraphicState() {
+ SkAutoMutexAcquire lock(CanonicalPaintsMutex());
static SkPDFGraphicState* noSMaskGS = NULL;
if (!noSMaskGS) {
noSMaskGS = new SkPDFGraphicState;
noSMaskGS->fPopulated = true;
noSMaskGS->fSMask = true;
- noSMaskGS->insert("Type", new SkPDFName("ExtGState"))->unref();
- noSMaskGS->insert("SMask", new SkPDFName("None"))->unref();
+ noSMaskGS->insertName("Type", "ExtGState");
+ noSMaskGS->insertName("SMask", "None");
}
noSMaskGS->ref();
return noSMaskGS;
}
// static
-int SkPDFGraphicState::find(const SkPaint& paint) {
+int SkPDFGraphicState::Find(const SkPaint& paint) {
GSCanonicalEntry search(&paint);
- return canonicalPaints().find(search);
+ return CanonicalPaints().find(search);
}
SkPDFGraphicState::SkPDFGraphicState()
@@ -208,10 +197,10 @@ SkPDFGraphicState::SkPDFGraphicState(const SkPaint& paint)
void SkPDFGraphicState::populateDict() {
if (!fPopulated) {
fPopulated = true;
- insert("Type", new SkPDFName("ExtGState"))->unref();
+ insertName("Type", "ExtGState");
SkRefPtr<SkPDFScalar> alpha =
- new SkPDFScalar(fPaint.getAlpha() * SkScalarInvert(0xFF));
+ new SkPDFScalar(SkScalarDiv(fPaint.getAlpha(), 0xFF));
alpha->unref(); // SkRefPtr and new both took a reference.
insert("CA", alpha.get());
insert("ca", alpha.get());
@@ -221,17 +210,17 @@ void SkPDFGraphicState::populateDict() {
SK_COMPILE_ASSERT(SkPaint::kSquare_Cap == 2, paint_cap_mismatch);
SK_COMPILE_ASSERT(SkPaint::kCapCount == 3, paint_cap_mismatch);
SkASSERT(fPaint.getStrokeCap() >= 0 && fPaint.getStrokeCap() <= 2);
- insert("LC", new SkPDFInt(fPaint.getStrokeCap()))->unref();
+ insertInt("LC", fPaint.getStrokeCap());
SK_COMPILE_ASSERT(SkPaint::kMiter_Join == 0, paint_join_mismatch);
SK_COMPILE_ASSERT(SkPaint::kRound_Join == 1, paint_join_mismatch);
SK_COMPILE_ASSERT(SkPaint::kBevel_Join == 2, paint_join_mismatch);
SK_COMPILE_ASSERT(SkPaint::kJoinCount == 3, paint_join_mismatch);
SkASSERT(fPaint.getStrokeJoin() >= 0 && fPaint.getStrokeJoin() <= 2);
- insert("LJ", new SkPDFInt(fPaint.getStrokeJoin()))->unref();
+ insertInt("LJ", fPaint.getStrokeJoin());
- insert("LW", new SkPDFScalar(fPaint.getStrokeWidth()))->unref();
- insert("ML", new SkPDFScalar(fPaint.getStrokeMiter()))->unref();
+ insertScalar("LW", fPaint.getStrokeWidth());
+ insertScalar("ML", fPaint.getStrokeMiter());
insert("SA", new SkPDFBool(true))->unref(); // Auto stroke adjustment.
SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode;
@@ -244,8 +233,7 @@ void SkPDFGraphicState::populateDict() {
xfermode = SkXfermode::kSrcOver_Mode;
NOT_IMPLEMENTED("unsupported xfermode", false);
}
- insert("BM",
- new SkPDFName(blend_mode_from_xfermode(xfermode)))->unref();
+ insertName("BM", blend_mode_from_xfermode(xfermode));
}
}
diff --git a/src/pdf/SkPDFImage.cpp b/src/pdf/SkPDFImage.cpp
index be69f7f..72379b1 100644
--- a/src/pdf/SkPDFImage.cpp
+++ b/src/pdf/SkPDFImage.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2010 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkPDFImage.h"
#include "SkBitmap.h"
@@ -82,10 +75,12 @@ void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect,
dst += 3;
alphaDst[0] = (SkGetPackedA4444(src[x]) << 4) |
SkGetPackedA4444(src[x + 1]);
- if (alphaDst[0] != 0xFF)
+ if (alphaDst[0] != 0xFF) {
hasAlpha = true;
- if (alphaDst[0])
+ }
+ if (alphaDst[0]) {
isTransparent = false;
+ }
alphaDst++;
}
if (srcRect.width() & 1) {
@@ -94,10 +89,12 @@ void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect,
dst[1] = (SkGetPackedB4444(src[x]) << 4);
dst += 2;
alphaDst[0] = (SkGetPackedA4444(src[x]) << 4);
- if (alphaDst[0] != 0xF0)
+ if (alphaDst[0] != 0xF0) {
hasAlpha = true;
- if (alphaDst[0] & 0xF0)
+ }
+ if (alphaDst[0] & 0xF0) {
isTransparent = false;
+ }
alphaDst++;
}
}
@@ -133,10 +130,12 @@ void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect,
dst[2] = SkGetPackedB32(src[x]);
dst += 3;
alphaDst[0] = SkGetPackedA32(src[x]);
- if (alphaDst[0] != 0xFF)
+ if (alphaDst[0] != 0xFF) {
hasAlpha = true;
- if (alphaDst[0])
+ }
+ if (alphaDst[0]) {
isTransparent = false;
+ }
alphaDst++;
}
}
@@ -154,7 +153,7 @@ void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect,
int offset2 = 8 - offset1;
for (int y = srcRect.fTop; y < srcRect.fBottom; y++) {
uint8_t* src = bitmap.getAddr1(0, y);
- // This may read up to one byte after src, but the potentially
+ // This may read up to one byte after src, but the potentially
// invalid bits are never used for computation.
for (int x = srcRect.fLeft; x < srcRect.fRight; x += 8) {
if (offset1) {
@@ -163,20 +162,24 @@ void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect,
} else {
alphaDst[0] = src[x / 8];
}
- if (x + 7 < srcRect.fRight && alphaDst[0] != 0xFF)
+ if (x + 7 < srcRect.fRight && alphaDst[0] != 0xFF) {
hasAlpha = true;
- if (x + 7 < srcRect.fRight && alphaDst[0])
+ }
+ if (x + 7 < srcRect.fRight && alphaDst[0]) {
isTransparent = false;
+ }
alphaDst++;
}
// Calculate the mask of bits we're interested in within the
// last byte of alphaDst.
// width mod 8 == 1 -> 0x80 ... width mod 8 == 7 -> 0xFE
uint8_t mask = ~((1 << (8 - (srcRect.width() % 8))) - 1);
- if (srcRect.width() % 8 && (alphaDst[-1] & mask) != mask)
+ if (srcRect.width() % 8 && (alphaDst[-1] & mask) != mask) {
hasAlpha = true;
- if (srcRect.width() % 8 && (alphaDst[-1] & mask))
+ }
+ if (srcRect.width() % 8 && (alphaDst[-1] & mask)) {
isTransparent = false;
+ }
}
break;
}
@@ -192,10 +195,12 @@ void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect,
uint8_t* src = bitmap.getAddr8(0, y);
for (int x = srcRect.fLeft; x < srcRect.fRight; x++) {
alphaDst[0] = src[x];
- if (alphaDst[0] != 0xFF)
+ if (alphaDst[0] != 0xFF) {
hasAlpha = true;
- if (alphaDst[0])
+ }
+ if (alphaDst[0]) {
isTransparent = false;
+ }
alphaDst++;
}
}
@@ -222,9 +227,9 @@ void extractImageData(const SkBitmap& bitmap, const SkIRect& srcRect,
SkPDFArray* makeIndexedColorSpace(SkColorTable* table) {
SkPDFArray* result = new SkPDFArray();
result->reserve(4);
- result->append(new SkPDFName("Indexed"))->unref();
- result->append(new SkPDFName("DeviceRGB"))->unref();;
- result->append(new SkPDFInt(table->count() - 1))->unref();
+ result->appendName("Indexed");
+ result->appendName("DeviceRGB");
+ result->appendInt(table->count() - 1);
// Potentially, this could be represented in fewer bytes with a stream.
// Max size as a string is 1.5k.
@@ -247,8 +252,9 @@ SkPDFArray* makeIndexedColorSpace(SkColorTable* table) {
SkPDFImage* SkPDFImage::CreateImage(const SkBitmap& bitmap,
const SkIRect& srcRect,
const SkPaint& paint) {
- if (bitmap.getConfig() == SkBitmap::kNo_Config)
+ if (bitmap.getConfig() == SkBitmap::kNo_Config) {
return NULL;
+ }
SkStream* imageData = NULL;
SkStream* alphaData = NULL;
@@ -281,44 +287,20 @@ SkPDFImage* SkPDFImage::addSMask(SkPDFImage* mask) {
return mask;
}
-void SkPDFImage::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
- bool indirect) {
- if (indirect)
- return emitIndirectObject(stream, catalog);
-
- fStream->emitObject(stream, catalog, indirect);
-}
-
-size_t SkPDFImage::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
- if (indirect)
- return getIndirectOutputSize(catalog);
-
- return fStream->getOutputSize(catalog, indirect);
-}
-
void SkPDFImage::getResources(SkTDArray<SkPDFObject*>* resourceList) {
- if (fResources.count()) {
- resourceList->setReserve(resourceList->count() + fResources.count());
- for (int i = 0; i < fResources.count(); i++) {
- resourceList->push(fResources[i]);
- fResources[i]->ref();
- fResources[i]->getResources(resourceList);
- }
- }
+ GetResourcesHelper(&fResources, resourceList);
}
SkPDFImage::SkPDFImage(SkStream* imageData, const SkBitmap& bitmap,
const SkIRect& srcRect, bool doingAlpha,
const SkPaint& paint) {
- fStream = new SkPDFStream(imageData);
- fStream->unref(); // SkRefPtr and new both took a reference.
-
+ this->setData(imageData);
SkBitmap::Config config = bitmap.getConfig();
bool alphaOnly = (config == SkBitmap::kA1_Config ||
config == SkBitmap::kA8_Config);
- insert("Type", new SkPDFName("XObject"))->unref();
- insert("Subtype", new SkPDFName("Image"))->unref();
+ insertName("Type", "XObject");
+ insertName("Subtype", "Image");
if (!doingAlpha && alphaOnly) {
// For alpha only images, we stretch a single pixel of black for
@@ -328,28 +310,29 @@ SkPDFImage::SkPDFImage(SkStream* imageData, const SkBitmap& bitmap,
insert("Width", one.get());
insert("Height", one.get());
} else {
- insert("Width", new SkPDFInt(srcRect.width()))->unref();
- insert("Height", new SkPDFInt(srcRect.height()))->unref();
+ insertInt("Width", srcRect.width());
+ insertInt("Height", srcRect.height());
}
// if (!image mask) {
if (doingAlpha || alphaOnly) {
- insert("ColorSpace", new SkPDFName("DeviceGray"))->unref();
+ insertName("ColorSpace", "DeviceGray");
} else if (config == SkBitmap::kIndex8_Config ||
config == SkBitmap::kRLE_Index8_Config) {
insert("ColorSpace",
makeIndexedColorSpace(bitmap.getColorTable()))->unref();
} else {
- insert("ColorSpace", new SkPDFName("DeviceRGB"))->unref();
+ insertName("ColorSpace", "DeviceRGB");
}
// }
int bitsPerComp = 8;
- if (config == SkBitmap::kARGB_4444_Config)
+ if (config == SkBitmap::kARGB_4444_Config) {
bitsPerComp = 4;
- else if (doingAlpha && config == SkBitmap::kA1_Config)
+ } else if (doingAlpha && config == SkBitmap::kA1_Config) {
bitsPerComp = 1;
- insert("BitsPerComponent", new SkPDFInt(bitsPerComp))->unref();
+ }
+ insertInt("BitsPerComponent", bitsPerComp);
if (config == SkBitmap::kRGB_565_Config) {
SkRefPtr<SkPDFInt> zeroVal = new SkPDFInt(0);
@@ -372,11 +355,3 @@ SkPDFImage::SkPDFImage(SkStream* imageData, const SkBitmap& bitmap,
insert("Decode", decodeValue.get());
}
}
-
-SkPDFObject* SkPDFImage::insert(SkPDFName* key, SkPDFObject* value) {
- return fStream->insert(key, value);
-}
-
-SkPDFObject* SkPDFImage::insert(const char key[], SkPDFObject* value) {
- return fStream->insert(key, value);
-}
diff --git a/src/pdf/SkPDFPage.cpp b/src/pdf/SkPDFPage.cpp
index 2a8183d..136ef44 100644
--- a/src/pdf/SkPDFPage.cpp
+++ b/src/pdf/SkPDFPage.cpp
@@ -1,25 +1,18 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2010 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkPDFCatalog.h"
#include "SkPDFDevice.h"
#include "SkPDFPage.h"
#include "SkStream.h"
-SkPDFPage::SkPDFPage(const SkRefPtr<SkPDFDevice>& content)
+SkPDFPage::SkPDFPage(SkPDFDevice* content)
: SkPDFDict("Page"),
fDevice(content) {
}
@@ -29,7 +22,7 @@ SkPDFPage::~SkPDFPage() {}
void SkPDFPage::finalizePage(SkPDFCatalog* catalog, bool firstPage,
SkTDArray<SkPDFObject*>* resourceObjects) {
if (fContentStream.get() == NULL) {
- insert("Resources", fDevice->getResourceDict().get());
+ insert("Resources", fDevice->getResourceDict());
insert("MediaBox", fDevice->getMediaBox().get());
SkRefPtr<SkStream> content = fDevice->content();
@@ -54,7 +47,7 @@ void SkPDFPage::emitPage(SkWStream* stream, SkPDFCatalog* catalog) {
}
// static
-void SkPDFPage::generatePageTree(const SkTDArray<SkPDFPage*>& pages,
+void SkPDFPage::GeneratePageTree(const SkTDArray<SkPDFPage*>& pages,
SkPDFCatalog* catalog,
SkTDArray<SkPDFDict*>* pageTree,
SkPDFDict** rootNode) {
@@ -107,13 +100,14 @@ void SkPDFPage::generatePageTree(const SkTDArray<SkPDFPage*>& pages,
curNodes[i]->insert(parentName.get(), newNodeRef.get());
kids->append(new SkPDFObjRef(curNodes[i]))->unref();
- // TODO(vandebo) put the objects in strict access order.
+ // TODO(vandebo): put the objects in strict access order.
// Probably doesn't matter because they are so small.
if (curNodes[i] != pages[0]) {
- pageTree->push(curNodes[i]); // Transfer reference.
+ pageTree->push(curNodes[i]); // Transfer reference.
catalog->addObject(curNodes[i], false);
} else {
SkSafeUnref(curNodes[i]);
+ catalog->addObject(curNodes[i], true);
}
}
@@ -129,14 +123,19 @@ void SkPDFPage::generatePageTree(const SkTDArray<SkPDFPage*>& pages,
curNodes = nextRoundNodes;
nextRoundNodes.rewind();
treeCapacity *= kNodeSize;
- } while(curNodes.count() > 1);
+ } while (curNodes.count() > 1);
- pageTree->push(curNodes[0]); // Transfer reference.
+ pageTree->push(curNodes[0]); // Transfer reference.
catalog->addObject(curNodes[0], false);
- if (rootNode)
+ if (rootNode) {
*rootNode = curNodes[0];
+ }
}
const SkTDArray<SkPDFFont*>& SkPDFPage::getFontResources() const {
return fDevice->getFontResources();
}
+
+const SkPDFGlyphSetMap& SkPDFPage::getFontGlyphUsage() const {
+ return fDevice->getFontGlyphUsage();
+}
diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp
index 6845e09..b6e0939 100644
--- a/src/pdf/SkPDFShader.cpp
+++ b/src/pdf/SkPDFShader.cpp
@@ -1,22 +1,16 @@
+
/*
- * Copyright (C) 2011 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2011 Google Inc.
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkPDFShader.h"
#include "SkCanvas.h"
+#include "SkData.h"
#include "SkPDFCatalog.h"
#include "SkPDFDevice.h"
#include "SkPDFTypes.h"
@@ -206,7 +200,7 @@ static void tileModeCode(SkShader::TileMode mode, SkString* result) {
}
static SkString linearCode(const SkShader::GradientInfo& info) {
- SkString function("{pop\n"); // Just ditch the y value.
+ SkString function("{pop\n"); // Just ditch the y value.
tileModeCode(info.fTileMode, &function);
gradientFunctionCode(info, &function);
function.append("}");
@@ -286,107 +280,145 @@ static SkString sweepCode(const SkShader::GradientInfo& info) {
return function;
}
-SkPDFShader::~SkPDFShader() {
- SkAutoMutexAcquire lock(canonicalShadersMutex());
- ShaderCanonicalEntry entry(this, fState.get());
- int index = canonicalShaders().find(entry);
- SkASSERT(index >= 0);
- canonicalShaders().removeShuffle(index);
- fResources.unrefAll();
-}
+class SkPDFShader::State {
+public:
+ SkShader::GradientType fType;
+ SkShader::GradientInfo fInfo;
+ SkAutoFree fColorData;
+ SkMatrix fCanvasTransform;
+ SkMatrix fShaderTransform;
+ SkIRect fBBox;
+
+ SkBitmap fImage;
+ uint32_t fPixelGeneration;
+ SkShader::TileMode fImageTileModes[2];
+
+ explicit State(const SkShader& shader, const SkMatrix& canvasTransform,
+ const SkIRect& bbox);
+ bool operator==(const State& b) const;
+};
+
+class SkPDFFunctionShader : public SkPDFDict, public SkPDFShader {
+public:
+ explicit SkPDFFunctionShader(SkPDFShader::State* state);
+ ~SkPDFFunctionShader() {
+ if (isValid()) {
+ RemoveShader(this);
+ }
+ fResources.unrefAll();
+ }
-void SkPDFShader::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
- bool indirect) {
- if (indirect)
- return emitIndirectObject(stream, catalog);
+ bool isValid() { return fResources.count() > 0; }
- fContent->emitObject(stream, catalog, indirect);
-}
+ void getResources(SkTDArray<SkPDFObject*>* resourceList) {
+ GetResourcesHelper(&fResources, resourceList);
+ }
-size_t SkPDFShader::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
- if (indirect)
- return getIndirectOutputSize(catalog);
+private:
+ static SkPDFObject* RangeObject();
- return fContent->getOutputSize(catalog, indirect);
-}
+ SkTDArray<SkPDFObject*> fResources;
+ SkAutoTDelete<const SkPDFShader::State> fState;
+
+ SkPDFStream* makePSFunction(const SkString& psCode, SkPDFArray* domain);
+};
-void SkPDFShader::getResources(SkTDArray<SkPDFObject*>* resourceList) {
- resourceList->setReserve(resourceList->count() + fResources.count());
- for (int i = 0; i < fResources.count(); i++) {
- resourceList->push(fResources[i]);
- fResources[i]->ref();
+class SkPDFImageShader : public SkPDFStream, public SkPDFShader {
+public:
+ explicit SkPDFImageShader(SkPDFShader::State* state);
+ ~SkPDFImageShader() {
+ RemoveShader(this);
+ fResources.unrefAll();
}
+
+ void getResources(SkTDArray<SkPDFObject*>* resourceList) {
+ GetResourcesHelper(&fResources, resourceList);
+ }
+
+private:
+ SkTDArray<SkPDFObject*> fResources;
+ SkAutoTDelete<const SkPDFShader::State> fState;
+};
+
+SkPDFShader::SkPDFShader() {}
+
+// static
+void SkPDFShader::RemoveShader(SkPDFObject* shader) {
+ SkAutoMutexAcquire lock(CanonicalShadersMutex());
+ ShaderCanonicalEntry entry(shader, NULL);
+ int index = CanonicalShaders().find(entry);
+ SkASSERT(index >= 0);
+ CanonicalShaders().removeShuffle(index);
}
// static
-SkPDFShader* SkPDFShader::getPDFShader(const SkShader& shader,
+SkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader,
const SkMatrix& matrix,
const SkIRect& surfaceBBox) {
- SkRefPtr<SkPDFShader> pdfShader;
- SkAutoMutexAcquire lock(canonicalShadersMutex());
+ SkPDFObject* result;
+ SkAutoMutexAcquire lock(CanonicalShadersMutex());
SkAutoTDelete<State> shaderState(new State(shader, matrix, surfaceBBox));
ShaderCanonicalEntry entry(NULL, shaderState.get());
- int index = canonicalShaders().find(entry);
+ int index = CanonicalShaders().find(entry);
if (index >= 0) {
- SkPDFShader* result = canonicalShaders()[index].fPDFShader;
+ result = CanonicalShaders()[index].fPDFShader;
result->ref();
return result;
}
// The PDFShader takes ownership of the shaderSate.
- pdfShader = new SkPDFShader(shaderState.detach());
- // Check for a valid shader.
- if (pdfShader->fContent.get() == NULL) {
- pdfShader->unref();
- return NULL;
+ if (shaderState.get()->fType == SkShader::kNone_GradientType) {
+ result = new SkPDFImageShader(shaderState.detach());
+ } else {
+ SkPDFFunctionShader* functionShader =
+ new SkPDFFunctionShader(shaderState.detach());
+ if (!functionShader->isValid()) {
+ delete functionShader;
+ return NULL;
+ }
+ result = functionShader;
}
- entry.fPDFShader = pdfShader.get();
- canonicalShaders().push(entry);
- return pdfShader.get(); // return the reference that came from new.
+ entry.fPDFShader = result;
+ CanonicalShaders().push(entry);
+ return result; // return the reference that came from new.
}
// static
-SkTDArray<SkPDFShader::ShaderCanonicalEntry>& SkPDFShader::canonicalShaders() {
+SkTDArray<SkPDFShader::ShaderCanonicalEntry>& SkPDFShader::CanonicalShaders() {
// This initialization is only thread safe with gcc.
static SkTDArray<ShaderCanonicalEntry> gCanonicalShaders;
return gCanonicalShaders;
}
// static
-SkMutex& SkPDFShader::canonicalShadersMutex() {
+SkMutex& SkPDFShader::CanonicalShadersMutex() {
// This initialization is only thread safe with gcc.
static SkMutex gCanonicalShadersMutex;
return gCanonicalShadersMutex;
}
// static
-SkPDFObject* SkPDFShader::rangeObject() {
+SkPDFObject* SkPDFFunctionShader::RangeObject() {
// This initialization is only thread safe with gcc.
static SkPDFArray* range = NULL;
- // This method is only used with canonicalShadersMutex, so it's safe to
+ // This method is only used with CanonicalShadersMutex, so it's safe to
// populate domain.
if (range == NULL) {
range = new SkPDFArray;
range->reserve(6);
- range->append(new SkPDFInt(0))->unref();
- range->append(new SkPDFInt(1))->unref();
- range->append(new SkPDFInt(0))->unref();
- range->append(new SkPDFInt(1))->unref();
- range->append(new SkPDFInt(0))->unref();
- range->append(new SkPDFInt(1))->unref();
+ range->appendInt(0);
+ range->appendInt(1);
+ range->appendInt(0);
+ range->appendInt(1);
+ range->appendInt(0);
+ range->appendInt(1);
}
return range;
}
-SkPDFShader::SkPDFShader(State* state) : fState(state) {
- if (fState.get()->fType == SkShader::kNone_GradientType) {
- doImageShader();
- } else {
- doFunctionShader();
- }
-}
-
-void SkPDFShader::doFunctionShader() {
+SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
+ : SkPDFDict("Pattern"),
+ fState(state) {
SkString (*codeFunction)(const SkShader::GradientInfo& info) = NULL;
SkPoint transformPoints[2];
@@ -405,9 +437,8 @@ void SkPDFShader::doFunctionShader() {
codeFunction = &radialCode;
break;
case SkShader::kRadial2_GradientType: {
- // Bail out if the radii are the same. Not setting fContent will
- // cause the higher level code to detect the resulting object
- // as invalid.
+ // Bail out if the radii are the same. Empty fResources signals
+ // an error and isValid will return false.
if (info->fRadius[0] == info->fRadius[1]) {
return;
}
@@ -424,7 +455,7 @@ void SkPDFShader::doFunctionShader() {
break;
case SkShader::kColor_GradientType:
case SkShader::kNone_GradientType:
- SkASSERT(false);
+ default:
return;
}
@@ -444,10 +475,10 @@ void SkPDFShader::doFunctionShader() {
SkRefPtr<SkPDFArray> domain = new SkPDFArray;
domain->unref(); // SkRefPtr and new both took a reference.
domain->reserve(4);
- domain->append(new SkPDFScalar(bbox.fLeft))->unref();
- domain->append(new SkPDFScalar(bbox.fRight))->unref();
- domain->append(new SkPDFScalar(bbox.fTop))->unref();
- domain->append(new SkPDFScalar(bbox.fBottom))->unref();
+ domain->appendScalar(bbox.fLeft);
+ domain->appendScalar(bbox.fRight);
+ domain->appendScalar(bbox.fTop);
+ domain->appendScalar(bbox.fBottom);
SkString functionCode;
// The two point radial gradient further references fState.get()->fInfo
@@ -473,20 +504,17 @@ void SkPDFShader::doFunctionShader() {
SkRefPtr<SkPDFDict> pdfShader = new SkPDFDict;
pdfShader->unref(); // SkRefPtr and new both took a reference.
- pdfShader->insert("ShadingType", new SkPDFInt(1))->unref();
- pdfShader->insert("ColorSpace", new SkPDFName("DeviceRGB"))->unref();
+ pdfShader->insertInt("ShadingType", 1);
+ pdfShader->insertName("ColorSpace", "DeviceRGB");
pdfShader->insert("Domain", domain.get());
pdfShader->insert("Function", new SkPDFObjRef(function.get()))->unref();
- fContent = new SkPDFDict("Pattern");
- fContent->unref(); // SkRefPtr and new both took a reference.
- fContent->insert("PatternType", new SkPDFInt(2))->unref();
- fContent->insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref();
- fContent->insert("Shading", pdfShader.get());
+ insertInt("PatternType", 2);
+ insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref();
+ insert("Shading", pdfShader.get());
}
-// SkShader* shader, SkMatrix matrix, const SkRect& surfaceBBox
-void SkPDFShader::doImageShader() {
+SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) {
fState.get()->fImage.lockPixels();
SkMatrix finalMatrix = fState.get()->fCanvasTransform;
@@ -497,7 +525,7 @@ void SkPDFShader::doImageShader() {
SkMatrix unflip;
unflip.setTranslate(0, SkScalarRound(surfaceBBox.height()));
- unflip.preScale(1, -1);
+ unflip.preScale(SK_Scalar1, -SK_Scalar1);
SkISize size = SkISize::Make(SkScalarRound(surfaceBBox.width()),
SkScalarRound(surfaceBBox.height()));
SkPDFDevice pattern(size, size, unflip);
@@ -526,7 +554,7 @@ void SkPDFShader::doImageShader() {
}
if (tileModes[1] == SkShader::kMirror_TileMode) {
SkMatrix yMirror;
- yMirror.setScale(1, -1);
+ yMirror.setScale(SK_Scalar1, -SK_Scalar1);
yMirror.postTranslate(0, 2 * height);
canvas.drawBitmapMatrix(*image, yMirror);
patternBBox.fBottom += height;
@@ -588,7 +616,7 @@ void SkPDFShader::doImageShader() {
canvas.drawBitmapMatrix(left, leftMatrix);
if (tileModes[1] == SkShader::kMirror_TileMode) {
- leftMatrix.postScale(1, -1);
+ leftMatrix.postScale(SK_Scalar1, -SK_Scalar1);
leftMatrix.postTranslate(0, 2 * height);
canvas.drawBitmapMatrix(left, leftMatrix);
}
@@ -606,7 +634,7 @@ void SkPDFShader::doImageShader() {
canvas.drawBitmapMatrix(right, rightMatrix);
if (tileModes[1] == SkShader::kMirror_TileMode) {
- rightMatrix.postScale(1, -1);
+ rightMatrix.postScale(SK_Scalar1, -SK_Scalar1);
rightMatrix.postTranslate(0, 2 * height);
canvas.drawBitmapMatrix(right, rightMatrix);
}
@@ -621,7 +649,7 @@ void SkPDFShader::doImageShader() {
SkAssertResult(image->extractSubset(&top, subset));
SkMatrix topMatrix;
- topMatrix.setScale(1, -surfaceBBox.fTop);
+ topMatrix.setScale(SK_Scalar1, -surfaceBBox.fTop);
topMatrix.postTranslate(0, surfaceBBox.fTop);
canvas.drawBitmapMatrix(top, topMatrix);
@@ -639,7 +667,7 @@ void SkPDFShader::doImageShader() {
SkAssertResult(image->extractSubset(&bottom, subset));
SkMatrix bottomMatrix;
- bottomMatrix.setScale(1, surfaceBBox.fBottom - height);
+ bottomMatrix.setScale(SK_Scalar1, surfaceBBox.fBottom - height);
bottomMatrix.postTranslate(0, height);
canvas.drawBitmapMatrix(bottom, bottomMatrix);
@@ -655,44 +683,53 @@ void SkPDFShader::doImageShader() {
SkRefPtr<SkPDFArray> patternBBoxArray = new SkPDFArray;
patternBBoxArray->unref(); // SkRefPtr and new both took a reference.
patternBBoxArray->reserve(4);
- patternBBoxArray->append(new SkPDFScalar(patternBBox.fLeft))->unref();
- patternBBoxArray->append(new SkPDFScalar(patternBBox.fTop))->unref();
- patternBBoxArray->append(new SkPDFScalar(patternBBox.fRight))->unref();
- patternBBoxArray->append(new SkPDFScalar(patternBBox.fBottom))->unref();
+ patternBBoxArray->appendScalar(patternBBox.fLeft);
+ patternBBoxArray->appendScalar(patternBBox.fTop);
+ patternBBoxArray->appendScalar(patternBBox.fRight);
+ patternBBoxArray->appendScalar(patternBBox.fBottom);
// Put the canvas into the pattern stream (fContent).
SkRefPtr<SkStream> content = pattern.content();
content->unref(); // SkRefPtr and content() both took a reference.
pattern.getResources(&fResources);
- fContent = new SkPDFStream(content.get());
- fContent->unref(); // SkRefPtr and new both took a reference.
- fContent->insert("Type", new SkPDFName("Pattern"))->unref();
- fContent->insert("PatternType", new SkPDFInt(1))->unref();
- fContent->insert("PaintType", new SkPDFInt(1))->unref();
- fContent->insert("TilingType", new SkPDFInt(1))->unref();
- fContent->insert("BBox", patternBBoxArray.get());
- fContent->insert("XStep", new SkPDFScalar(patternBBox.width()))->unref();
- fContent->insert("YStep", new SkPDFScalar(patternBBox.height()))->unref();
- fContent->insert("Resources", pattern.getResourceDict().get());
- fContent->insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref();
+ setData(content.get());
+ insertName("Type", "Pattern");
+ insertInt("PatternType", 1);
+ insertInt("PaintType", 1);
+ insertInt("TilingType", 1);
+ insert("BBox", patternBBoxArray.get());
+ insertScalar("XStep", patternBBox.width());
+ insertScalar("YStep", patternBBox.height());
+ insert("Resources", pattern.getResourceDict());
+ insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref();
fState.get()->fImage.unlockPixels();
}
-SkPDFStream* SkPDFShader::makePSFunction(const SkString& psCode,
- SkPDFArray* domain) {
- SkRefPtr<SkMemoryStream> funcStream =
- new SkMemoryStream(psCode.c_str(), psCode.size(), true);
- funcStream->unref(); // SkRefPtr and new both took a reference.
-
- SkPDFStream* result = new SkPDFStream(funcStream.get());
- result->insert("FunctionType", new SkPDFInt(4))->unref();
+SkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode,
+ SkPDFArray* domain) {
+ SkAutoDataUnref funcData(SkData::NewWithCopy(psCode.c_str(),
+ psCode.size()));
+ SkPDFStream* result = new SkPDFStream(funcData.get());
+ result->insertInt("FunctionType", 4);
result->insert("Domain", domain);
- result->insert("Range", rangeObject());
+ result->insert("Range", RangeObject());
return result;
}
+SkPDFShader::ShaderCanonicalEntry::ShaderCanonicalEntry(SkPDFObject* pdfShader,
+ const State* state)
+ : fPDFShader(pdfShader),
+ fState(state) {
+}
+
+bool SkPDFShader::ShaderCanonicalEntry::operator==(
+ const ShaderCanonicalEntry& b) const {
+ return fPDFShader == b.fPDFShader ||
+ (fState != NULL && b.fState != NULL && *fState == *b.fState);
+}
+
bool SkPDFShader::State::operator==(const SkPDFShader::State& b) const {
if (fType != b.fType ||
fCanvasTransform != b.fCanvasTransform ||
@@ -749,12 +786,13 @@ bool SkPDFShader::State::operator==(const SkPDFShader::State& b) const {
SkPDFShader::State::State(const SkShader& shader,
const SkMatrix& canvasTransform, const SkIRect& bbox)
: fCanvasTransform(canvasTransform),
- fBBox(bbox) {
-
+ fBBox(bbox),
+ fPixelGeneration(0) {
fInfo.fColorCount = 0;
fInfo.fColors = NULL;
fInfo.fColorOffsets = NULL;
shader.getLocalMatrix(&fShaderTransform);
+ fImageTileModes[0] = fImageTileModes[1] = SkShader::kClamp_TileMode;
fType = shader.asAGradient(&fInfo);
@@ -771,8 +809,9 @@ SkPDFShader::State::State(const SkShader& shader,
} else {
fColorData.set(sk_malloc_throw(
fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar))));
- fInfo.fColors = (SkColor*)fColorData.get();
- fInfo.fColorOffsets = (SkScalar*)(fInfo.fColors + fInfo.fColorCount);
+ fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get());
+ fInfo.fColorOffsets =
+ reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount);
shader.asAGradient(&fInfo);
}
}
diff --git a/src/pdf/SkPDFStream.cpp b/src/pdf/SkPDFStream.cpp
index b1bd5ff..0bd63f3 100644
--- a/src/pdf/SkPDFStream.cpp
+++ b/src/pdf/SkPDFStream.cpp
@@ -1,61 +1,117 @@
+
/*
- * Copyright (C) 2010 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2010 Google Inc.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
+#include "SkData.h"
#include "SkFlate.h"
#include "SkPDFCatalog.h"
#include "SkPDFStream.h"
#include "SkStream.h"
-SkPDFStream::SkPDFStream(SkStream* stream) {
- if (SkFlate::HaveFlate())
- SkAssertResult(SkFlate::Deflate(stream, &fCompressedData));
-
- if (SkFlate::HaveFlate() &&
- fCompressedData.getOffset() < stream->getLength()) {
- fLength = fCompressedData.getOffset();
- insert("Filter", new SkPDFName("FlateDecode"))->unref();
- } else {
- fCompressedData.reset();
- fPlainData = stream;
- fLength = fPlainData->getLength();
- }
- insert("Length", new SkPDFInt(fLength))->unref();
+static bool skip_compression(SkPDFCatalog* catalog) {
+ return catalog->getDocumentFlags() & SkPDFDocument::kNoCompression_Flag;
+}
+
+SkPDFStream::SkPDFStream(SkStream* stream)
+ : fState(kUnused_State),
+ fData(stream) {
+}
+
+SkPDFStream::SkPDFStream(SkData* data) : fState(kUnused_State) {
+ SkMemoryStream* stream = new SkMemoryStream;
+ stream->setData(data);
+ fData = stream;
+ fData->unref(); // SkRefPtr and new both took a reference.
}
-SkPDFStream::~SkPDFStream() {
+SkPDFStream::SkPDFStream(const SkPDFStream& pdfStream)
+ : SkPDFDict(),
+ fState(kUnused_State),
+ fData(pdfStream.fData) {
+ bool removeLength = true;
+ // Don't uncompress an already compressed stream, but we could.
+ if (pdfStream.fState == kCompressed_State) {
+ fState = kCompressed_State;
+ removeLength = false;
+ }
+ SkPDFDict::Iter dict(pdfStream);
+ SkPDFName* key;
+ SkPDFObject* value;
+ SkPDFName lengthName("Length");
+ for (key = dict.next(&value); key != NULL; key = dict.next(&value)) {
+ if (removeLength && *key == lengthName) {
+ continue;
+ }
+ this->insert(key, value);
+ }
}
+SkPDFStream::~SkPDFStream() {}
+
void SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
bool indirect) {
- if (indirect)
+ if (indirect) {
return emitIndirectObject(stream, catalog);
+ }
+ if (!this->populate(catalog)) {
+ return fSubstitute->emitObject(stream, catalog, indirect);
+ }
this->INHERITED::emitObject(stream, catalog, false);
stream->writeText(" stream\n");
- if (fPlainData.get())
- stream->write(fPlainData->getMemoryBase(), fLength);
- else
- stream->write(fCompressedData.getStream(), fLength);
+ stream->write(fData->getMemoryBase(), fData->getLength());
stream->writeText("\nendstream");
}
size_t SkPDFStream::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
- if (indirect)
+ if (indirect) {
return getIndirectOutputSize(catalog);
+ }
+ if (!this->populate(catalog)) {
+ return fSubstitute->getOutputSize(catalog, indirect);
+ }
return this->INHERITED::getOutputSize(catalog, false) +
- strlen(" stream\n\nendstream") + fLength;
+ strlen(" stream\n\nendstream") + fData->getLength();
+}
+
+SkPDFStream::SkPDFStream() : fState(kUnused_State) {}
+
+void SkPDFStream::setData(SkStream* stream) {
+ fData = stream;
+}
+
+bool SkPDFStream::populate(SkPDFCatalog* catalog) {
+ if (fState == kUnused_State) {
+ if (!skip_compression(catalog) && SkFlate::HaveFlate()) {
+ SkDynamicMemoryWStream compressedData;
+
+ SkAssertResult(SkFlate::Deflate(fData.get(), &compressedData));
+ if (compressedData.getOffset() < fData->getLength()) {
+ SkMemoryStream* stream = new SkMemoryStream;
+ stream->setData(compressedData.copyToData());
+ fData = stream;
+ fData->unref(); // SkRefPtr and new both took a reference.
+ insertName("Filter", "FlateDecode");
+ }
+ fState = kCompressed_State;
+ } else {
+ fState = kNoCompression_State;
+ }
+ insertInt("Length", fData->getLength());
+ } else if (fState == kNoCompression_State && !skip_compression(catalog) &&
+ SkFlate::HaveFlate()) {
+ if (!fSubstitute.get()) {
+ fSubstitute = new SkPDFStream(*this);
+ fSubstitute->unref(); // SkRefPtr and new both took a reference.
+ catalog->setSubstitute(this, fSubstitute.get());
+ }
+ return false;
+ }
+ return true;
}
diff --git a/src/pdf/SkPDFTypes.cpp b/src/pdf/SkPDFTypes.cpp
index b9420eb..f97f21b 100644
--- a/src/pdf/SkPDFTypes.cpp
+++ b/src/pdf/SkPDFTypes.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2011 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2011 Google Inc.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkPDFCatalog.h"
#include "SkPDFTypes.h"
#include "SkStream.h"
@@ -27,9 +20,15 @@
SkPDFObject::SkPDFObject() {}
SkPDFObject::~SkPDFObject() {}
+void SkPDFObject::emit(SkWStream* stream, SkPDFCatalog* catalog,
+ bool indirect) {
+ SkPDFObject* realObject = catalog->getSubstituteObject(this);
+ return realObject->emitObject(stream, catalog, indirect);
+}
+
size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
SkDynamicMemoryWStream buffer;
- emitObject(&buffer, catalog, indirect);
+ emit(&buffer, catalog, indirect);
return buffer.getOffset();
}
@@ -38,18 +37,36 @@ void SkPDFObject::getResources(SkTDArray<SkPDFObject*>* resourceList) {}
void SkPDFObject::emitIndirectObject(SkWStream* stream, SkPDFCatalog* catalog) {
catalog->emitObjectNumber(stream, this);
stream->writeText(" obj\n");
- emitObject(stream, catalog, false);
+ emit(stream, catalog, false);
stream->writeText("\nendobj\n");
}
-SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {}
-SkPDFObjRef::~SkPDFObjRef() {}
-
size_t SkPDFObject::getIndirectOutputSize(SkPDFCatalog* catalog) {
return catalog->getObjectNumberSize(this) + strlen(" obj\n") +
this->getOutputSize(catalog, false) + strlen("\nendobj\n");
}
+void SkPDFObject::AddResourceHelper(SkPDFObject* resource,
+ SkTDArray<SkPDFObject*>* list) {
+ list->push(resource);
+ resource->ref();
+}
+
+void SkPDFObject::GetResourcesHelper(SkTDArray<SkPDFObject*>* resources,
+ SkTDArray<SkPDFObject*>* result) {
+ if (resources->count()) {
+ result->setReserve(result->count() + resources->count());
+ for (int i = 0; i < resources->count(); i++) {
+ result->push((*resources)[i]);
+ (*resources)[i]->ref();
+ (*resources)[i]->getResources(result);
+ }
+ }
+}
+
+SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {}
+SkPDFObjRef::~SkPDFObjRef() {}
+
void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
bool indirect) {
SkASSERT(!indirect);
@@ -67,8 +84,9 @@ SkPDFInt::~SkPDFInt() {}
void SkPDFInt::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
bool indirect) {
- if (indirect)
+ if (indirect) {
return emitIndirectObject(stream, catalog);
+ }
stream->writeDecAsText(fValue);
}
@@ -87,8 +105,9 @@ void SkPDFBool::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
size_t SkPDFBool::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
SkASSERT(!indirect);
- if (fValue)
+ if (fValue) {
return strlen("true");
+ }
return strlen("false");
}
@@ -97,8 +116,9 @@ SkPDFScalar::~SkPDFScalar() {}
void SkPDFScalar::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
bool indirect) {
- if (indirect)
+ if (indirect) {
return emitIndirectObject(stream, catalog);
+ }
Append(fValue, stream);
}
@@ -159,15 +179,15 @@ void SkPDFScalar::Append(SkScalar value, SkWStream* stream) {
}
SkPDFString::SkPDFString(const char value[])
- : fValue(formatString(value, strlen(value))) {
+ : fValue(FormatString(value, strlen(value))) {
}
SkPDFString::SkPDFString(const SkString& value)
- : fValue(formatString(value.c_str(), value.size())) {
+ : fValue(FormatString(value.c_str(), value.size())) {
}
SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars)
- : fValue(formatString(value, len, wideChars)) {
+ : fValue(FormatString(value, len, wideChars)) {
}
SkPDFString::~SkPDFString() {}
@@ -186,17 +206,17 @@ size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
}
// static
-SkString SkPDFString::formatString(const char* input, size_t len) {
- return doFormatString(input, len, false, false);
+SkString SkPDFString::FormatString(const char* input, size_t len) {
+ return DoFormatString(input, len, false, false);
}
-SkString SkPDFString::formatString(const uint16_t* input, size_t len,
+SkString SkPDFString::FormatString(const uint16_t* input, size_t len,
bool wideChars) {
- return doFormatString(input, len, true, wideChars);
+ return DoFormatString(input, len, true, wideChars);
}
// static
-SkString SkPDFString::doFormatString(const void* input, size_t len,
+SkString SkPDFString::DoFormatString(const void* input, size_t len,
bool wideInput, bool wideOutput) {
SkASSERT(len <= kMaxLen);
const uint16_t* win = (const uint16_t*) input;
@@ -206,8 +226,9 @@ SkString SkPDFString::doFormatString(const void* input, size_t len,
SkASSERT(wideInput);
SkString result;
result.append("<");
- for (size_t i = 0; i < len; i++)
+ for (size_t i = 0; i < len; i++) {
result.appendHex(win[i], 4);
+ }
result.append(">");
return result;
}
@@ -230,8 +251,9 @@ SkString SkPDFString::doFormatString(const void* input, size_t len,
for (size_t i = 0; i < len; i++) {
SkASSERT(!wideInput || !(win[i] & ~0xFF));
char val = wideInput ? win[i] : cin[i];
- if (val == '\\' || val == '(' || val == ')')
+ if (val == '\\' || val == '(' || val == ')') {
result.append("\\");
+ }
result.append(&val, 1);
}
result.append(")");
@@ -248,10 +270,14 @@ SkString SkPDFString::doFormatString(const void* input, size_t len,
return result;
}
-SkPDFName::SkPDFName(const char name[]) : fValue(formatName(SkString(name))) {}
-SkPDFName::SkPDFName(const SkString& name) : fValue(formatName(name)) {}
+SkPDFName::SkPDFName(const char name[]) : fValue(FormatName(SkString(name))) {}
+SkPDFName::SkPDFName(const SkString& name) : fValue(FormatName(name)) {}
SkPDFName::~SkPDFName() {}
+bool SkPDFName::operator==(const SkPDFName& b) const {
+ return fValue == b.fValue;
+}
+
void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
bool indirect) {
SkASSERT(!indirect);
@@ -264,7 +290,7 @@ size_t SkPDFName::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
}
// static
-SkString SkPDFName::formatName(const SkString& input) {
+SkString SkPDFName::FormatName(const SkString& input) {
SkASSERT(input.size() <= kMaxLen);
SkString result("/");
@@ -282,32 +308,37 @@ SkString SkPDFName::formatName(const SkString& input) {
SkPDFArray::SkPDFArray() {}
SkPDFArray::~SkPDFArray() {
- fValue.safeUnrefAll();
+ fValue.unrefAll();
}
void SkPDFArray::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
bool indirect) {
- if (indirect)
+ if (indirect) {
return emitIndirectObject(stream, catalog);
+ }
stream->writeText("[");
for (int i = 0; i < fValue.count(); i++) {
- fValue[i]->emitObject(stream, catalog, false);
- if (i + 1 < fValue.count())
+ fValue[i]->emit(stream, catalog, false);
+ if (i + 1 < fValue.count()) {
stream->writeText(" ");
+ }
}
stream->writeText("]");
}
size_t SkPDFArray::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
- if (indirect)
+ if (indirect) {
return getIndirectOutputSize(catalog);
+ }
size_t result = strlen("[]");
- if (fValue.count())
+ if (fValue.count()) {
result += fValue.count() - 1;
- for (int i = 0; i < fValue.count(); i++)
+ }
+ for (int i = 0; i < fValue.count(); i++) {
result += fValue[i]->getOutputSize(catalog, false);
+ }
return result;
}
@@ -318,23 +349,40 @@ void SkPDFArray::reserve(int length) {
SkPDFObject* SkPDFArray::setAt(int offset, SkPDFObject* value) {
SkASSERT(offset < fValue.count());
- SkSafeUnref(fValue[offset]);
+ value->ref();
+ fValue[offset]->unref();
fValue[offset] = value;
- SkSafeRef(fValue[offset]);
return value;
}
SkPDFObject* SkPDFArray::append(SkPDFObject* value) {
SkASSERT(fValue.count() < kMaxLen);
- SkSafeRef(value);
+ value->ref();
fValue.push(value);
return value;
}
+void SkPDFArray::appendInt(int32_t value) {
+ SkASSERT(fValue.count() < kMaxLen);
+ fValue.push(new SkPDFInt(value));
+}
+
+void SkPDFArray::appendScalar(SkScalar value) {
+ SkASSERT(fValue.count() < kMaxLen);
+ fValue.push(new SkPDFScalar(value));
+}
+
+void SkPDFArray::appendName(const char name[]) {
+ SkASSERT(fValue.count() < kMaxLen);
+ fValue.push(new SkPDFName(name));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
SkPDFDict::SkPDFDict() {}
SkPDFDict::SkPDFDict(const char type[]) {
- insert("Type", new SkPDFName(type))->unref();
+ insertName("Type", type);
}
SkPDFDict::~SkPDFDict() {
@@ -343,22 +391,24 @@ SkPDFDict::~SkPDFDict() {
void SkPDFDict::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
bool indirect) {
- if (indirect)
+ if (indirect) {
return emitIndirectObject(stream, catalog);
+ }
stream->writeText("<<");
for (int i = 0; i < fValue.count(); i++) {
fValue[i].key->emitObject(stream, catalog, false);
stream->writeText(" ");
- fValue[i].value->emitObject(stream, catalog, false);
+ fValue[i].value->emit(stream, catalog, false);
stream->writeText("\n");
}
stream->writeText(">>");
}
size_t SkPDFDict::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
- if (indirect)
+ if (indirect) {
return getIndirectOutputSize(catalog);
+ }
size_t result = strlen("<<>>") + (fValue.count() * 2);
for (int i = 0; i < fValue.count(); i++) {
@@ -369,24 +419,60 @@ size_t SkPDFDict::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
}
SkPDFObject* SkPDFDict::insert(SkPDFName* key, SkPDFObject* value) {
+ key->ref();
+ value->ref();
struct Rec* newEntry = fValue.append();
newEntry->key = key;
- SkSafeRef(newEntry->key);
newEntry->value = value;
- SkSafeRef(newEntry->value);
return value;
}
SkPDFObject* SkPDFDict::insert(const char key[], SkPDFObject* value) {
- SkRefPtr<SkPDFName> keyName = new SkPDFName(key);
- keyName->unref(); // SkRefPtr and new both took a reference.
- return insert(keyName.get(), value);
+ value->ref();
+ struct Rec* newEntry = fValue.append();
+ newEntry->key = new SkPDFName(key);
+ newEntry->value = value;
+ return value;
+}
+
+void SkPDFDict::insertInt(const char key[], int32_t value) {
+ struct Rec* newEntry = fValue.append();
+ newEntry->key = new SkPDFName(key);
+ newEntry->value = new SkPDFInt(value);
+}
+
+void SkPDFDict::insertScalar(const char key[], SkScalar value) {
+ struct Rec* newEntry = fValue.append();
+ newEntry->key = new SkPDFName(key);
+ newEntry->value = new SkPDFScalar(value);
+}
+
+void SkPDFDict::insertName(const char key[], const char name[]) {
+ struct Rec* newEntry = fValue.append();
+ newEntry->key = new SkPDFName(key);
+ newEntry->value = new SkPDFName(name);
}
void SkPDFDict::clear() {
for (int i = 0; i < fValue.count(); i++) {
- SkSafeUnref(fValue[i].key);
- SkSafeUnref(fValue[i].value);
+ fValue[i].key->unref();
+ fValue[i].value->unref();
}
fValue.reset();
}
+
+SkPDFDict::Iter::Iter(const SkPDFDict& dict)
+ : fIter(dict.fValue.begin()),
+ fStop(dict.fValue.end()) {
+}
+
+SkPDFName* SkPDFDict::Iter::next(SkPDFObject** value) {
+ if (fIter != fStop) {
+ Rec* cur = fIter;
+ fIter++;
+ *value = cur->value;
+ return cur->key;
+ }
+ *value = NULL;
+ return NULL;
+}
diff --git a/src/pdf/SkPDFUtils.cpp b/src/pdf/SkPDFUtils.cpp
index a838427..b596a27 100644
--- a/src/pdf/SkPDFUtils.cpp
+++ b/src/pdf/SkPDFUtils.cpp
@@ -1,19 +1,13 @@
+
/*
- * Copyright (C) 2011 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2011 Google Inc.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
+#include "SkGeometry.h"
#include "SkPaint.h"
#include "SkPath.h"
#include "SkPDFUtils.h"
@@ -24,12 +18,14 @@
// static
SkPDFArray* SkPDFUtils::MatrixToArray(const SkMatrix& matrix) {
SkScalar values[6];
- SkAssertResult(matrix.pdfTransform(values));
+ if (!matrix.asAffine(values)) {
+ SkMatrix::SetAffineIdentity(values);
+ }
SkPDFArray* result = new SkPDFArray;
result->reserve(6);
for (size_t i = 0; i < SK_ARRAY_COUNT(values); i++) {
- result->append(new SkPDFScalar(values[i]))->unref();
+ result->appendScalar(values[i]);
}
return result;
}
@@ -37,7 +33,9 @@ SkPDFArray* SkPDFUtils::MatrixToArray(const SkMatrix& matrix) {
// static
void SkPDFUtils::AppendTransform(const SkMatrix& matrix, SkWStream* content) {
SkScalar values[6];
- SkAssertResult(matrix.pdfTransform(values));
+ if (!matrix.asAffine(values)) {
+ SkMatrix::SetAffineIdentity(values);
+ }
for (size_t i = 0; i < SK_ARRAY_COUNT(values); i++) {
SkPDFScalar::Append(values[i], content);
content->writeText(" ");
@@ -115,15 +113,10 @@ void SkPDFUtils::EmitPath(const SkPath& path, SkWStream* content) {
AppendLine(args[1].fX, args[1].fY, content);
break;
case SkPath::kQuad_Verb: {
- // Convert quad to cubic (degree elevation). http://goo.gl/vS4i
- const SkScalar three = SkIntToScalar(3);
- args[1].scale(SkIntToScalar(2));
- SkScalar ctl1X = SkScalarDiv(args[0].fX + args[1].fX, three);
- SkScalar ctl1Y = SkScalarDiv(args[0].fY + args[1].fY, three);
- SkScalar ctl2X = SkScalarDiv(args[2].fX + args[1].fX, three);
- SkScalar ctl2Y = SkScalarDiv(args[2].fY + args[1].fY, three);
- AppendCubic(ctl1X, ctl1Y, ctl2X, ctl2Y, args[2].fX, args[2].fY,
- content);
+ SkPoint cubic[4];
+ SkConvertQuadToCubic(args, cubic);
+ AppendCubic(cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY,
+ cubic[3].fX, cubic[3].fY, content);
break;
}
case SkPath::kCubic_Verb:
@@ -133,8 +126,6 @@ void SkPDFUtils::EmitPath(const SkPath& path, SkWStream* content) {
case SkPath::kClose_Verb:
ClosePath(content);
break;
- case SkPath::kDone_Verb:
- break;
default:
SkASSERT(false);
break;
@@ -150,18 +141,20 @@ void SkPDFUtils::ClosePath(SkWStream* content) {
// static
void SkPDFUtils::PaintPath(SkPaint::Style style, SkPath::FillType fill,
SkWStream* content) {
- if (style == SkPaint::kFill_Style)
+ if (style == SkPaint::kFill_Style) {
content->writeText("f");
- else if (style == SkPaint::kStrokeAndFill_Style)
+ } else if (style == SkPaint::kStrokeAndFill_Style) {
content->writeText("B");
- else if (style == SkPaint::kStroke_Style)
+ } else if (style == SkPaint::kStroke_Style) {
content->writeText("S");
+ }
if (style != SkPaint::kStroke_Style) {
NOT_IMPLEMENTED(fill == SkPath::kInverseEvenOdd_FillType, false);
NOT_IMPLEMENTED(fill == SkPath::kInverseWinding_FillType, false);
- if (fill == SkPath::kEvenOdd_FillType)
+ if (fill == SkPath::kEvenOdd_FillType) {
content->writeText("*");
+ }
}
content->writeText("\n");
}
diff --git a/src/pdf/pdf_files.mk b/src/pdf/pdf_files.mk
deleted file mode 100644
index c9b4fb4..0000000
--- a/src/pdf/pdf_files.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-SOURCE := \
- SkPDFCatalog.cpp \
- SkPDFDevice.cpp \
- SkPDFDocument.cpp \
- SkPDFFont.cpp \
- SkPDFFormXObject.cpp \
- SkPDFGraphicState.cpp \
- SkPDFImage.cpp \
- SkPDFPage.cpp \
- SkPDFShader.cpp \
- SkPDFStream.cpp \
- SkPDFTypes.cpp \
- SkPDFUtils.cpp
diff --git a/src/pipe/SkGPipePriv.h b/src/pipe/SkGPipePriv.h
index fb15536..2baf75a 100644
--- a/src/pipe/SkGPipePriv.h
+++ b/src/pipe/SkGPipePriv.h
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#ifndef SkGPipePriv_DEFINED
#define SkGPipePriv_DEFINED
@@ -56,7 +49,6 @@ enum DrawOps {
kDrawPosText_DrawOp,
kDrawPosTextH_DrawOp,
kDrawRect_DrawOp,
- kDrawShape_DrawOp,
kDrawSprite_DrawOp,
kDrawText_DrawOp,
kDrawTextOnPath_DrawOp,
@@ -75,8 +67,6 @@ enum DrawOps {
kDef_Typeface_DrawOp,
kDef_Flattenable_DrawOp,
- kName_Flattenable_DrawOp, // index <--> name
-
// these are signals to playback, not drawing verbs
kDone_DrawOp,
};
@@ -119,7 +109,7 @@ static uint32_t DrawOp_packOpFlagData(DrawOps op, unsigned flags, unsigned data)
SkASSERT(0 == (flags & ~DRAWOPS_FLAG_MASK));
SkASSERT(0 == (data & ~DRAWOPS_DATA_MASK));
- return (op << DRAWOPS_FLAG_BITS + DRAWOPS_DATA_BITS) |
+ return (op << (DRAWOPS_FLAG_BITS + DRAWOPS_DATA_BITS)) |
(flags << DRAWOPS_DATA_BITS) |
data;
}
@@ -190,14 +180,14 @@ static unsigned PaintOp_unpackData(uint32_t op32) {
static uint32_t PaintOp_packOp(PaintOps op) {
SkASSERT(0 == (op & ~PAINTOPS_OP_MASK));
- return (op << PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS);
+ return op << (PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS);
}
static uint32_t PaintOp_packOpData(PaintOps op, unsigned data) {
SkASSERT(0 == (op & ~PAINTOPS_OP_MASK));
SkASSERT(0 == (data & ~PAINTOPS_DATA_MASK));
- return (op << PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS) | data;
+ return (op << (PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS)) | data;
}
static uint32_t PaintOp_packOpFlagData(PaintOps op, unsigned flags, unsigned data) {
@@ -205,7 +195,7 @@ static uint32_t PaintOp_packOpFlagData(PaintOps op, unsigned flags, unsigned dat
SkASSERT(0 == (flags & ~PAINTOPS_FLAG_MASK));
SkASSERT(0 == (data & ~PAINTOPS_DATA_MASK));
- return (op << PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS) |
+ return (op << (PAINTOPS_FLAG_BITS + PAINTOPS_DATA_BITS)) |
(flags << PAINTOPS_DATA_BITS) |
data;
}
diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp
index ecb19fd..f30f105 100644
--- a/src/pipe/SkGPipeRead.cpp
+++ b/src/pipe/SkGPipeRead.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkCanvas.h"
#include "SkPaint.h"
#include "SkGPipe.h"
@@ -56,7 +49,7 @@ static void set_paintflat(SkPaint* paint, SkFlattenable* obj, unsigned paintFlat
paint->setXfermode((SkXfermode*)obj);
break;
default:
- SkASSERT(!"never gets here");
+ SkDEBUGFAIL("never gets here");
}
}
@@ -72,7 +65,7 @@ public:
void setReader(SkFlattenableReadBuffer* reader) {
fReader = reader;
- fReader->setFactoryPlayback(fFactoryArray.begin(), fFactoryArray.count());
+ fReader->setFactoryArray(&fFactoryArray);
}
const SkPaint& paint() const { return fPaint; }
@@ -85,22 +78,12 @@ public:
return fFlatArray[index - 1];
}
- void defFlattenable(PaintFlats pf, unsigned index) {
+ void defFlattenable(PaintFlats pf, int index) {
SkASSERT(index == fFlatArray.count() + 1);
SkFlattenable* obj = fReader->readFlattenable();
*fFlatArray.append() = obj;
}
- void nameFlattenable(PaintFlats pf, unsigned index) {
- SkASSERT(index == fFactoryArray.count() + 1);
- const char* name = fReader->readString();
- SkFlattenable::Factory fact = SkFlattenable::NameToFactory(name);
- *fFactoryArray.append() = fact;
-
- // update this each time we grow the array
- fReader->setFactoryPlayback(fFactoryArray.begin(), fFactoryArray.count());
- }
-
void addTypeface() {
size_t size = fReader->readU32();
const void* data = fReader->skip(SkAlign4(size));
@@ -374,11 +357,6 @@ static void drawData_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
canvas->drawData(data, size);
}
-static void drawShape_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
- SkGPipeState* state) {
- UNIMPLEMENTED
-}
-
static void drawPicture_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
SkGPipeState* state) {
UNIMPLEMENTED
@@ -425,7 +403,7 @@ static void paintOp_rp(SkCanvas*, SkReader32* reader, uint32_t op32,
}
case kTypeface_PaintOp: state->setTypeface(p, data); break;
- default: SkASSERT(!"bad paintop"); return;
+ default: SkDEBUGFAIL("bad paintop"); return;
}
SkASSERT(reader->offset() <= stop);
} while (reader->offset() < stop);
@@ -444,13 +422,6 @@ static void def_PaintFlat_rp(SkCanvas*, SkReader32*, uint32_t op32,
state->defFlattenable(pf, index);
}
-static void name_PaintFlat_rp(SkCanvas*, SkReader32*, uint32_t op32,
- SkGPipeState* state) {
- PaintFlats pf = (PaintFlats)DrawOp_unpackFlags(op32);
- unsigned index = DrawOp_unpackData(op32);
- state->nameFlattenable(pf, index);
-}
-
///////////////////////////////////////////////////////////////////////////////
static void skip_rp(SkCanvas*, SkReader32* reader, uint32_t op32, SkGPipeState*) {
@@ -480,7 +451,6 @@ static const ReadProc gReadTable[] = {
drawPosText_rp,
drawPosTextH_rp,
drawRect_rp,
- drawShape_rp,
drawSprite_rp,
drawText_rp,
drawTextOnPath_rp,
@@ -497,7 +467,6 @@ static const ReadProc gReadTable[] = {
paintOp_rp,
def_Typeface_rp,
def_PaintFlat_rp,
- name_PaintFlat_rp,
done_rp
};
@@ -507,8 +476,8 @@ static const ReadProc gReadTable[] = {
SkGPipeState::SkGPipeState() {}
SkGPipeState::~SkGPipeState() {
- fTypefaces.unrefAll();
- fFlatArray.unrefAll();
+ fTypefaces.safeUnrefAll();
+ fFlatArray.safeUnrefAll();
}
///////////////////////////////////////////////////////////////////////////////
@@ -527,7 +496,7 @@ SkGPipeReader::~SkGPipeReader() {
}
SkGPipeReader::Status SkGPipeReader::playback(const void* data, size_t length,
- size_t* bytesRead) {
+ size_t* bytesRead, bool readAtom) {
if (NULL == fCanvas) {
return kError_Status;
}
@@ -559,6 +528,14 @@ SkGPipeReader::Status SkGPipeReader::playback(const void* data, size_t length,
break;
}
table[op](canvas, &reader, op32, fState);
+ if (readAtom &&
+ (table[op] != paintOp_rp &&
+ table[op] != def_Typeface_rp &&
+ table[op] != def_PaintFlat_rp
+ )) {
+ status = kReadAtom_Status;
+ break;
+ }
}
if (bytesRead) {
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index 428f864..00d5d5f 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -1,21 +1,15 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkCanvas.h"
+#include "SkData.h"
#include "SkDevice.h"
#include "SkPaint.h"
#include "SkGPipe.h"
@@ -41,7 +35,7 @@ static SkFlattenable* get_paintflat(const SkPaint& paint, unsigned paintFlat) {
case kShader_PaintFlat: return paint.getShader();
case kXfermode_PaintFlat: return paint.getXfermode();
}
- SkASSERT(!"never gets here");
+ SkDEBUGFAIL("never gets here");
return NULL;
}
@@ -68,7 +62,8 @@ static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) {
size_t size = stream.getOffset();
if (writer) {
writer->write32(size);
- writer->write(stream.getStream(), size);
+ SkAutoDataUnref data(stream.copyToData());
+ writer->write(data.data(), size);
}
return 4 + size;
}
@@ -82,8 +77,10 @@ public:
void finish() {
if (!fDone) {
- this->writeOp(kDone_DrawOp);
- this->doNotify();
+ if (this->needOpBytes()) {
+ this->writeOp(kDone_DrawOp);
+ this->doNotify();
+ }
fDone = true;
}
}
@@ -125,7 +122,6 @@ public:
const SkPath& path, const SkMatrix* matrix,
const SkPaint&);
virtual void drawPicture(SkPicture& picture);
- virtual void drawShape(SkShape*);
virtual void drawVertices(VertexMode, int vertexCount,
const SkPoint vertices[], const SkPoint texs[],
const SkColor colors[], SkXfermode*,
@@ -197,31 +193,9 @@ int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
if (NULL == obj) {
return 0;
}
-
- SkFlattenable::Factory fact = obj->getFactory();
- if (NULL == fact) {
- return 0;
- }
- if (fFactorySet) {
- uint32_t id = fFactorySet->find((void*)fact);
- if (0 == id) {
- const char* name = SkFlattenable::FactoryToName(fact);
- if (NULL == name) {
- return 0;
- }
- size_t len = strlen(name);
- size_t size = SkWriter32::WriteStringSize(name, len);
- if (!this->needOpBytes(size)) {
- return 0;
- }
- unsigned id = fFactorySet->add(fact);
- this->writeOp(kName_Flattenable_DrawOp, paintflat, id);
- fWriter.writeString(name, len);
- }
- }
-
SkFlattenableWriteBuffer tmpWriter(1024);
+ tmpWriter.setFlags(SkFlattenableWriteBuffer::kInlineFactoryNames_Flag);
tmpWriter.setFactoryRecorder(fFactorySet);
tmpWriter.writeFlattenable(obj);
@@ -259,7 +233,8 @@ int SkGPipeCanvas::flattenToIndex(SkFlattenable* obj, PaintFlats paintflat) {
SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
SkWriter32* writer, SkFactorySet* fset)
- : fWriter(*writer), fFactorySet(fset) {
+ : fWriter(*writer) {
+ fFactorySet = fset;
fController = controller;
fDone = false;
fBlockSize = 0; // need first block from controller
@@ -267,9 +242,10 @@ SkGPipeCanvas::SkGPipeCanvas(SkGPipeController* controller,
// we need a device to limit our clip
// should the caller give us the bounds?
+ // We don't allocate pixels for the bitmap
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 32767, 32767);
- SkDevice* device = SkNEW_ARGS(SkDevice, (this, bitmap, false));
+ SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap));
this->setDevice(device)->unref();
}
@@ -610,10 +586,6 @@ void SkGPipeCanvas::drawPicture(SkPicture& picture) {
this->INHERITED::drawPicture(picture);
}
-void SkGPipeCanvas::drawShape(SkShape* shape) {
- UNIMPLEMENTED
-}
-
void SkGPipeCanvas::drawVertices(VertexMode mode, int vertexCount,
const SkPoint vertices[], const SkPoint texs[],
const SkColor colors[], SkXfermode*,
diff --git a/src/ports/FontHostConfiguration_android.cpp b/src/ports/FontHostConfiguration_android.cpp
index 78f1de4..475dc4a 100644
--- a/src/ports/FontHostConfiguration_android.cpp
+++ b/src/ports/FontHostConfiguration_android.cpp
@@ -24,15 +24,16 @@
#define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml"
-// These defines are used to determine the kind of tag that we're currently populating with data.
-// We only care about the sibling tags nameset and fileset for now.
+// These defines are used to determine the kind of tag that we're currently
+// populating with data. We only care about the sibling tags nameset and fileset
+// for now.
#define NO_TAG 0
#define NAMESET_TAG 1
#define FILESET_TAG 2
/**
- * The FamilyData structure is passed around by the parser so that each handler can read these
- * variables that are relevant to the current parsing.
+ * The FamilyData structure is passed around by the parser so that each handler
+ * can read these variables that are relevant to the current parsing.
*/
struct FamilyData {
FamilyData(XML_Parser *parserRef, SkTDArray<FontFamily*> &familiesRef) :
@@ -45,8 +46,8 @@ struct FamilyData {
};
/**
- * Handler for arbitrary text. This is used to parse the text inside each name or file tag. The
- * resulting strings are put into the fNames or fFileNames arrays.
+ * Handler for arbitrary text. This is used to parse the text inside each name
+ * or file tag. The resulting strings are put into the fNames or fFileNames arrays.
*/
void textHandler(void *data, const char *s, int len) {
FamilyData *familyData = (FamilyData*) data;
@@ -73,8 +74,8 @@ void textHandler(void *data, const char *s, int len) {
}
/**
- * Handler for the start of a tag. The only tags we expect are family, nameset, fileset, name,
- * and file.
+ * Handler for the start of a tag. The only tags we expect are family, nameset,
+ * fileset, name, and file.
*/
void startElementHandler(void *data, const char *tag, const char **atts) {
FamilyData *familyData = (FamilyData*) data;
@@ -105,7 +106,8 @@ void startElementHandler(void *data, const char *tag, const char **atts) {
}
/**
- * Handler for the end of tags. We only care about family, nameset, fileset, name, and file.
+ * Handler for the end of tags. We only care about family, nameset, fileset,
+ * name, and file.
*/
void endElementHandler(void *data, const char *tag) {
FamilyData *familyData = (FamilyData*) data;
@@ -126,7 +128,8 @@ void endElementHandler(void *data, const char *tag) {
}
/**
- * This function parses the given filename and stores the results in the given families array.
+ * This function parses the given filename and stores the results in the given
+ * families array.
*/
void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &families) {
XML_Parser parser = XML_ParserCreate(NULL);
@@ -134,9 +137,9 @@ void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &families) {
XML_SetUserData(parser, familyData);
XML_SetElementHandler(parser, startElementHandler, endElementHandler);
FILE *file = fopen(filename, "r");
+ // Some of the files we attempt to parse (in particular, /vendor/etc/fallback_fonts.xml)
+ // are optional - failure here is okay because one of these optional files may not exist.
if (file == NULL) {
- // Some of the files we attempt to parse (in particular, /vendor/etc/fallback_fonts.xml)
- // are optional - failure here is okay because one of these optional files may not exist.
return;
}
char buffer[512];
@@ -152,8 +155,8 @@ void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &families) {
}
/**
- * Loads data on font families from various expected configuration files. The resulting data
- * is returned in the given fontFamilies array.
+ * Loads data on font families from various expected configuration files. The
+ * resulting data is returned in the given fontFamilies array.
*/
void getFontFamilies(SkTDArray<FontFamily*> &fontFamilies) {
@@ -163,8 +166,8 @@ void getFontFamilies(SkTDArray<FontFamily*> &fontFamilies) {
parseConfigFile(FALLBACK_FONTS_FILE, fallbackFonts);
parseConfigFile(VENDOR_FONTS_FILE, vendorFonts);
- // This loop inserts the vendor fallback fonts in the correct order in the overall
- // fallbacks list.
+ // This loop inserts the vendor fallback fonts in the correct order in the
+ // overall fallbacks list.
int currentOrder = -1;
for (int i = 0; i < vendorFonts.count(); ++i) {
FontFamily* family = vendorFonts[i];
@@ -179,8 +182,8 @@ void getFontFamilies(SkTDArray<FontFamily*> &fontFamilies) {
*fallbackFonts.insert(currentOrder++) = family;
}
} else {
- // Add the font into the fallback list in the specified order. Set currentOrder
- // for correct placement of other fonts in the vendor list.
+ // Add the font into the fallback list in the specified order. Set
+ // currentOrder for correct placement of other fonts in the vendor list.
*fallbackFonts.insert(order) = family;
currentOrder = order + 1;
}
diff --git a/src/ports/FontHostConfiguration_android.h b/src/ports/FontHostConfiguration_android.h
index 57a0126..010f0ef 100644
--- a/src/ports/FontHostConfiguration_android.h
+++ b/src/ports/FontHostConfiguration_android.h
@@ -20,11 +20,12 @@
#include "SkTDArray.h"
/**
- * The FontFamily data structure is created during parsing and handed back to Skia to fold
- * into its representation of font families. fNames is the list of font names that alias to a
- * font family. fFileNames is the list of font filenames for the family. Order is the priority
- * order for the font. This is used internally to determine the order in which to place fallback
- * fonts as they are read from the configuration files.
+ * The FontFamily data structure is created during parsing and handed back to
+ * Skia to fold into its representation of font families. fNames is the list of
+ * font names that alias to a font family. fFileNames is the list of font
+ * filenames for the family. Order is the priority order for the font. This is
+ * used internally to determine the order in which to place fallback fonts as
+ * they are read from the configuration files.
*/
struct FontFamily {
SkTDArray<const char*> fNames;
@@ -33,8 +34,8 @@ struct FontFamily {
};
/**
- * Parses all system font configuration files and returns the results in an array of FontFamily
- * structures.
+ * Parses all system font configuration files and returns the results in an
+ * array of FontFamily structures.
*/
void getFontFamilies(SkTDArray<FontFamily*> &fontFamilies);
diff --git a/src/ports/SkDebug_android.cpp b/src/ports/SkDebug_android.cpp
index f1fd34f..8e7d1d4 100644
--- a/src/ports/SkDebug_android.cpp
+++ b/src/ports/SkDebug_android.cpp
@@ -1,43 +1,22 @@
-/* libs/corecg/SkDebug_stdio.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTypes.h"
static const size_t kBufferSize = 256;
#define LOG_TAG "skia"
-#include <utils/Log.h>
+#include <android/log.h>
-void Android_SkDebugf(const char* file, int line, const char* function,
- const char* format, ...)
-{
- if (format[0] == '\n' && format[1] == '\0')
- return;
+void SkDebugf(const char format[], ...) {
va_list args;
va_start(args, format);
-#ifdef HAVE_ANDROID_OS
- char buffer[kBufferSize + 1];
- vsnprintf(buffer, kBufferSize, format, args);
- if (buffer[0] != 0)
- __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "%s", buffer);
-#else
- android_vprintLog(ANDROID_LOG_DEBUG, NULL, LOG_TAG, format, args);
-#endif
+ __android_log_vprint(ANDROID_LOG_DEBUG, LOG_TAG, format, args);
va_end(args);
}
-
-
diff --git a/src/ports/SkDebug_brew.cpp b/src/ports/SkDebug_brew.cpp
index 03f7968..b7ad3ef 100644
--- a/src/ports/SkDebug_brew.cpp
+++ b/src/ports/SkDebug_brew.cpp
@@ -1,20 +1,11 @@
/* libs/corecg/SkDebug_brew.cpp
-**
-** Copyright 2009, The Android Open Source Project
-** Copyright 2009, Company 100, Inc.
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+ *
+ * Copyright 2009, The Android Open Source Project
+ * Copyright 2009, Company 100, Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkTypes.h"
diff --git a/src/ports/SkDebug_stdio.cpp b/src/ports/SkDebug_stdio.cpp
index b40d507..bc3d98b 100644
--- a/src/ports/SkDebug_stdio.cpp
+++ b/src/ports/SkDebug_stdio.cpp
@@ -1,19 +1,11 @@
-/* libs/corecg/SkDebug_stdio.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTypes.h"
diff --git a/src/ports/SkDebug_win.cpp b/src/ports/SkDebug_win.cpp
index 6828493..b3077f1 100644
--- a/src/ports/SkDebug_win.cpp
+++ b/src/ports/SkDebug_win.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkTypes.h"
static const size_t kBufferSize = 2048;
@@ -31,5 +24,6 @@ void SkDebugf(const char format[], ...) {
va_end(args);
OutputDebugStringA(buffer);
+ printf(buffer);
}
diff --git a/src/ports/SkFontHost_FONTPATH.cpp b/src/ports/SkFontHost_FONTPATH.cpp
index afab874..f0438f4 100644
--- a/src/ports/SkFontHost_FONTPATH.cpp
+++ b/src/ports/SkFontHost_FONTPATH.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/ports/SkFontHost_android.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkFontHost.h"
#include "SkDescriptor.h"
@@ -332,8 +324,3 @@ SkScalerContext* SkFontHost::CreateFallbackScalerContext(
return SkFontHost::CreateScalerContext(desc);
}
-size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar)
-{
- return 0; // nothing to do (change me if you want to limit the font cache)
-}
-
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp
index de1ce73..61efb95 100644
--- a/src/ports/SkFontHost_FreeType.cpp
+++ b/src/ports/SkFontHost_FreeType.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/ports/SkFontHost_FreeType.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkBitmap.h"
#include "SkCanvas.h"
@@ -39,7 +31,9 @@
// In the past, FT_GlyphSlot_Own_Bitmap was defined in this header file.
#include FT_SYNTHESIS_H
#include FT_XFREE86_H
+#ifdef FT_LCD_FILTER_H
#include FT_LCD_FILTER_H
+#endif
#ifdef FT_ADVANCES_H
#include FT_ADVANCES_H
@@ -80,6 +74,16 @@ using namespace skia_advanced_typeface_metrics_utils;
#define SK_FREETYPE_LCD_LERP 96
#endif
+static bool isLCD(const SkScalerContext::Rec& rec) {
+ switch (rec.fMaskFormat) {
+ case SkMask::kLCD16_Format:
+ case SkMask::kLCD32_Format:
+ return true;
+ default:
+ return false;
+ }
+}
+
//////////////////////////////////////////////////////////////////////////
struct SkFaceRec;
@@ -91,6 +95,8 @@ static SkFaceRec* gFaceRecHead;
static bool gLCDSupportValid; // true iff |gLCDSupport| has been set.
static bool gLCDSupport; // true iff LCD is supported by the runtime.
+static const uint8_t* gGammaTables[2];
+
/////////////////////////////////////////////////////////////////////////
// See http://freetype.sourceforge.net/freetype2/docs/reference/ft2-bitmap_handling.html#FT_Bitmap_Embolden
@@ -106,8 +112,12 @@ InitFreetype() {
// Setup LCD filtering. This reduces colour fringes for LCD rendered
// glyphs.
+#ifdef FT_LCD_FILTER_H
err = FT_Library_SetLcdFilter(gFTLibrary, FT_LCD_FILTER_DEFAULT);
gLCDSupport = err == 0;
+#else
+ gLCDSupport = false;
+#endif
gLCDSupportValid = true;
return true;
@@ -142,6 +152,7 @@ private:
SkFixed fScaleX, fScaleY;
FT_Matrix fMatrix22;
uint32_t fLoadGlyphFlags;
+ bool fDoLinearMetrics;
FT_Error setupSize();
void emboldenOutline(FT_Outline* outline);
@@ -284,7 +295,7 @@ static void unref_ft_face(FT_Face face) {
prev = rec;
rec = next;
}
- SkASSERT("shouldn't get here, face not in list");
+ SkDEBUGFAIL("shouldn't get here, face not in list");
}
///////////////////////////////////////////////////////////////////////////
@@ -400,8 +411,10 @@ static void populate_glyph_to_unicode(FT_Face& face,
// static
SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
uint32_t fontID,
- SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo) {
-#if defined(SK_BUILD_FOR_MAC) || defined(ANDROID)
+ SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
+ const uint32_t* glyphIDs,
+ uint32_t glyphIDsCount) {
+#if defined(SK_BUILD_FOR_MAC)
return NULL;
#else
SkAutoMutexAcquire ac(gFTMutex);
@@ -513,7 +526,7 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
info->fBBox = SkIRect::MakeLTRB(face->bbox.xMin, face->bbox.yMax,
face->bbox.xMax, face->bbox.yMin);
- if (!canEmbed(face) || !FT_IS_SCALABLE(face) ||
+ if (!canEmbed(face) || !FT_IS_SCALABLE(face) ||
info->fType == SkAdvancedTypefaceMetrics::kOther_Font) {
perGlyphInfo = SkAdvancedTypefaceMetrics::kNo_PerGlyphInfo;
}
@@ -544,7 +557,11 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
SkAdvancedTypefaceMetrics::WidthRange::kRange);
} else {
info->fGlyphWidths.reset(
- getAdvanceData(face, face->num_glyphs, &getWidthAdvance));
+ getAdvanceData(face,
+ face->num_glyphs,
+ glyphIDs,
+ glyphIDsCount,
+ &getWidthAdvance));
}
}
@@ -580,22 +597,37 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
return info;
#endif
}
+
///////////////////////////////////////////////////////////////////////////
+#define BLACK_LUMINANCE_LIMIT 0x40
+#define WHITE_LUMINANCE_LIMIT 0xA0
+
+static bool bothZero(SkScalar a, SkScalar b) {
+ return 0 == a && 0 == b;
+}
+
+// returns false if there is any non-90-rotation or skew
+static bool isAxisAligned(const SkScalerContext::Rec& rec) {
+ return 0 == rec.fPreSkewX &&
+ (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
+ bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
+}
+
void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
if (!gLCDSupportValid) {
InitFreetype();
FT_Done_FreeType(gFTLibrary);
}
- if (!gLCDSupport && (rec->isLCD() || SkMask::kLCD16_Format == rec->fMaskFormat)) {
+ if (!gLCDSupport && isLCD(*rec)) {
// If the runtime Freetype library doesn't support LCD mode, we disable
// it here.
rec->fMaskFormat = SkMask::kA8_Format;
}
SkPaint::Hinting h = rec->getHinting();
- if (SkPaint::kFull_Hinting == h && !rec->isLCD()) {
+ if (SkPaint::kFull_Hinting == h && !isLCD(*rec)) {
// collapse full->normal hinting if we're not doing LCD
h = SkPaint::kNormal_Hinting;
} else if ((rec->fFlags & SkScalerContext::kSubpixelPositioning_Flag) &&
@@ -603,10 +635,36 @@ void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
// to do subpixel, we must have at most slight hinting
h = SkPaint::kSlight_Hinting;
}
+#ifndef SK_IGNORE_ROTATED_FREETYPE_FIX
+ // rotated text looks bad with hinting, so we disable it as needed
+ if (!isAxisAligned(*rec)) {
+ h = SkPaint::kNo_Hinting;
+ }
+#endif
rec->setHinting(h);
+
+ // for compatibility at the moment, discretize luminance to 3 settings
+ // black, white, gray. This helps with fontcache utilization, since we
+ // won't create multiple entries that in the end map to the same results.
+ {
+ unsigned lum = rec->getLuminanceByte();
+ if (gGammaTables[0] || gGammaTables[1]) {
+ if (lum <= BLACK_LUMINANCE_LIMIT) {
+ lum = 0;
+ } else if (lum >= WHITE_LUMINANCE_LIMIT) {
+ lum = SkScalerContext::kLuminance_Max;
+ } else {
+ lum = SkScalerContext::kLuminance_Max >> 1;
+ }
+ } else {
+ lum = 0; // no gamma correct, so use 0 since SkPaint uses that
+ // when measuring text w/o regard for luminance
+ }
+ rec->setLuminanceBits(lum);
+ }
}
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
uint32_t SkFontHost::GetUnitsPerEm(SkFontID fontID) {
SkAutoMutexAcquire ac(gFTMutex);
SkFaceRec *rec = ref_ft_face(fontID);
@@ -629,6 +687,7 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc)
if (!InitFreetype()) {
sk_throw();
}
+ SkFontHost::GetGammaTables(gGammaTables);
}
++gFTCount;
@@ -685,19 +744,24 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc)
// compute the flags we send to Load_Glyph
{
FT_Int32 loadFlags = FT_LOAD_DEFAULT;
+ bool linearMetrics = false;
if (SkMask::kBW_Format == fRec.fMaskFormat) {
// See http://code.google.com/p/chromium/issues/detail?id=43252#c24
loadFlags = FT_LOAD_TARGET_MONO;
- if (fRec.getHinting() == SkPaint::kNo_Hinting)
+ if (fRec.getHinting() == SkPaint::kNo_Hinting) {
loadFlags = FT_LOAD_NO_HINTING;
+ linearMetrics = true;
+ }
} else {
switch (fRec.getHinting()) {
case SkPaint::kNo_Hinting:
loadFlags = FT_LOAD_NO_HINTING;
+ linearMetrics = true;
break;
case SkPaint::kSlight_Hinting:
loadFlags = FT_LOAD_TARGET_LIGHT; // This implies FORCE_AUTOHINT
+ linearMetrics = true;
break;
case SkPaint::kNormal_Hinting:
if (fRec.fFlags & SkScalerContext::kAutohinting_Flag)
@@ -711,11 +775,12 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc)
break;
}
loadFlags = FT_LOAD_TARGET_NORMAL;
- if (SkMask::kHorizontalLCD_Format == fRec.fMaskFormat ||
- SkMask::kLCD16_Format == fRec.fMaskFormat) {
- loadFlags = FT_LOAD_TARGET_LCD;
- } else if (SkMask::kVerticalLCD_Format == fRec.fMaskFormat) {
- loadFlags = FT_LOAD_TARGET_LCD_V;
+ if (isLCD(fRec)) {
+ if (fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag) {
+ loadFlags = FT_LOAD_TARGET_LCD_V;
+ } else {
+ loadFlags = FT_LOAD_TARGET_LCD;
+ }
}
break;
default:
@@ -724,8 +789,9 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc)
}
}
- if ((fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) == 0)
+ if ((fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) == 0) {
loadFlags |= FT_LOAD_NO_BITMAP;
+ }
// Always using FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH to get correct
// advances, as fontconfig and cairo do.
@@ -733,6 +799,7 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc)
loadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
fLoadGlyphFlags = loadFlags;
+ fDoLinearMetrics = linearMetrics;
}
// now create the FT_Size
@@ -847,10 +914,6 @@ SkUnichar SkScalerContext_FreeType::generateGlyphToChar(uint16_t glyph) {
static FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) {
switch (format) {
- case SkMask::kHorizontalLCD_Format:
- case SkMask::kVerticalLCD_Format:
- SkASSERT(!"An LCD format should never be passed here");
- return FT_PIXEL_MODE_GRAY;
case SkMask::kBW_Format:
return FT_PIXEL_MODE_MONO;
case SkMask::kA8_Format:
@@ -864,7 +927,7 @@ void SkScalerContext_FreeType::generateAdvance(SkGlyph* glyph) {
/* unhinted and light hinted text have linearly scaled advances
* which are very cheap to compute with some font formats...
*/
- {
+ if (fDoLinearMetrics) {
SkAutoMutexAcquire ac(gFTMutex);
if (this->setupSize()) {
@@ -917,6 +980,14 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
case FT_GLYPH_FORMAT_OUTLINE: {
FT_BBox bbox;
+ if (0 == fFace->glyph->outline.n_contours) {
+ glyph->fWidth = 0;
+ glyph->fHeight = 0;
+ glyph->fTop = 0;
+ glyph->fLeft = 0;
+ break;
+ }
+
if (fRec.fFlags & kEmbolden_Flag) {
emboldenOutline(&fFace->glyph->outline);
}
@@ -956,7 +1027,7 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
break;
default:
- SkASSERT(!"unknown glyph format");
+ SkDEBUGFAIL("unknown glyph format");
goto ERROR;
}
@@ -978,16 +1049,6 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
#endif
}
-#if defined(SK_SUPPORT_LCDTEXT)
-namespace skia_freetype_support {
-// extern functions from SkFontHost_FreeType_Subpixel
-extern void CopyFreetypeBitmapToLCDMask(const SkGlyph& dest, const FT_Bitmap& source);
-extern void CopyFreetypeBitmapToVerticalLCDMask(const SkGlyph& dest, const FT_Bitmap& source);
-}
-
-using namespace skia_freetype_support;
-#endif
-
static int lerp(int start, int end) {
SkASSERT((unsigned)SK_FREETYPE_LCD_LERP <= 256);
return start + ((end - start) * (SK_FREETYPE_LCD_LERP) >> 8);
@@ -1004,23 +1065,64 @@ static uint16_t packTriple(unsigned r, unsigned g, unsigned b) {
return SkPackRGB16(r >> 3, g >> 2, b >> 3);
}
-static void copyFT2LCD16(const SkGlyph& glyph, const FT_Bitmap& bitmap) {
- SkASSERT(glyph.fWidth * 3 == bitmap.width - 6);
- SkASSERT(glyph.fHeight == bitmap.rows);
+static uint16_t grayToRGB16(U8CPU gray) {
+ SkASSERT(gray <= 255);
+ return SkPackRGB16(gray >> 3, gray >> 2, gray >> 3);
+}
+
+static int bittst(const uint8_t data[], int bitOffset) {
+ SkASSERT(bitOffset >= 0);
+ int lowBit = data[bitOffset >> 3] >> (~bitOffset & 7);
+ return lowBit & 1;
+}
- const uint8_t* src = bitmap.buffer + 3;
+static void copyFT2LCD16(const SkGlyph& glyph, const FT_Bitmap& bitmap,
+ int lcdIsBGR) {
+ SkASSERT(glyph.fHeight == bitmap.rows);
uint16_t* dst = reinterpret_cast<uint16_t*>(glyph.fImage);
- size_t dstRB = glyph.rowBytes();
- int width = glyph.fWidth;
-
- for (int y = 0; y < glyph.fHeight; y++) {
- const uint8_t* triple = src;
- for (int x = 0; x < width; x++) {
- dst[x] = packTriple(triple[0], triple[1], triple[2]);
- triple += 3;
- }
- src += bitmap.pitch;
- dst = (uint16_t*)((char*)dst + dstRB);
+ const size_t dstRB = glyph.rowBytes();
+ const int width = glyph.fWidth;
+ const uint8_t* src = bitmap.buffer;
+
+ switch (bitmap.pixel_mode) {
+ case FT_PIXEL_MODE_MONO: {
+ for (int y = 0; y < glyph.fHeight; ++y) {
+ for (int x = 0; x < width; ++x) {
+ dst[x] = -bittst(src, x);
+ }
+ dst = (uint16_t*)((char*)dst + dstRB);
+ src += bitmap.pitch;
+ }
+ } break;
+ case FT_PIXEL_MODE_GRAY: {
+ for (int y = 0; y < glyph.fHeight; ++y) {
+ for (int x = 0; x < width; ++x) {
+ dst[x] = grayToRGB16(src[x]);
+ }
+ dst = (uint16_t*)((char*)dst + dstRB);
+ src += bitmap.pitch;
+ }
+ } break;
+ default: {
+ SkASSERT(glyph.fWidth * 3 == bitmap.width - 6);
+ src += 3;
+ for (int y = 0; y < glyph.fHeight; y++) {
+ const uint8_t* triple = src;
+ if (lcdIsBGR) {
+ for (int x = 0; x < width; x++) {
+ dst[x] = packTriple(triple[2], triple[1], triple[0]);
+ triple += 3;
+ }
+ } else {
+ for (int x = 0; x < width; x++) {
+ dst[x] = packTriple(triple[0], triple[1], triple[2]);
+ triple += 3;
+ }
+ }
+ src += bitmap.pitch;
+ dst = (uint16_t*)((char*)dst + dstRB);
+ }
+ } break;
}
}
@@ -1042,9 +1144,6 @@ void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) {
return;
}
- const bool lcdRenderMode = fRec.fMaskFormat == SkMask::kHorizontalLCD_Format ||
- fRec.fMaskFormat == SkMask::kVerticalLCD_Format;
-
switch ( fFace->glyph->format ) {
case FT_GLYPH_FORMAT_OUTLINE: {
FT_Outline* outline = &fFace->glyph->outline;
@@ -1074,26 +1173,10 @@ void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) {
FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63),
dy - ((bbox.yMin + dy) & ~63));
-#if defined(SK_SUPPORT_LCDTEXT)
- if (lcdRenderMode) {
- // FT_Outline_Get_Bitmap cannot render LCD glyphs. In this case
- // we have to call FT_Render_Glyph and memcpy the image out.
- const bool isVertical = fRec.fMaskFormat == SkMask::kVerticalLCD_Format;
- FT_Render_Mode mode = isVertical ? FT_RENDER_MODE_LCD_V : FT_RENDER_MODE_LCD;
- FT_Render_Glyph(fFace->glyph, mode);
-
- if (isVertical)
- CopyFreetypeBitmapToVerticalLCDMask(glyph, fFace->glyph->bitmap);
- else
- CopyFreetypeBitmapToLCDMask(glyph, fFace->glyph->bitmap);
-
- break;
- }
-#endif
-
if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
FT_Render_Glyph(fFace->glyph, FT_RENDER_MODE_LCD);
- copyFT2LCD16(glyph, fFace->glyph->bitmap);
+ copyFT2LCD16(glyph, fFace->glyph->bitmap,
+ fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
} else {
target.width = glyph.fWidth;
target.rows = glyph.fHeight;
@@ -1136,9 +1219,7 @@ void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) {
dst += dstRowBytes;
}
} else if (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO &&
- (glyph.fMaskFormat == SkMask::kA8_Format ||
- glyph.fMaskFormat == SkMask::kHorizontalLCD_Format ||
- glyph.fMaskFormat == SkMask::kVerticalLCD_Format)) {
+ glyph.fMaskFormat == SkMask::kA8_Format) {
for (int y = 0; y < fFace->glyph->bitmap.rows; ++y) {
uint8_t byte = 0;
int bits = 0;
@@ -1159,19 +1240,38 @@ void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) {
src += fFace->glyph->bitmap.pitch;
dst += glyph.rowBytes();
}
+ } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
+ copyFT2LCD16(glyph, fFace->glyph->bitmap,
+ fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
} else {
- SkASSERT(!"unknown glyph bitmap transform needed");
+ SkDEBUGFAIL("unknown glyph bitmap transform needed");
}
-
- if (lcdRenderMode)
- glyph.expandA8ToLCD();
-
} break;
default:
- SkASSERT(!"unknown glyph format");
+ SkDEBUGFAIL("unknown glyph format");
goto ERROR;
}
+
+ if (gGammaTables[0] || gGammaTables[1]) {
+ bool isWhite = fRec.getLuminanceByte() >= WHITE_LUMINANCE_LIMIT;
+ bool isBlack = fRec.getLuminanceByte() <= BLACK_LUMINANCE_LIMIT;
+ if ((isWhite | isBlack) && SkMask::kA8_Format == glyph.fMaskFormat) {
+ int index = isBlack ? 0 : 1;
+ if (gGammaTables[index]) {
+ const uint8_t* SK_RESTRICT table = gGammaTables[index];
+ uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
+ unsigned rowBytes = glyph.rowBytes();
+
+ for (int y = glyph.fHeight - 1; y >= 0; --y) {
+ for (int x = glyph.fWidth - 1; x >= 0; --x) {
+ dst[x] = table[dst[x]];
+ }
+ dst += rowBytes;
+ }
+ }
+ }
+ }
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/ports/SkFontHost_FreeType_Subpixel.cpp b/src/ports/SkFontHost_FreeType_Subpixel.cpp
deleted file mode 100644
index bc01585..0000000
--- a/src/ports/SkFontHost_FreeType_Subpixel.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/* libs/graphics/ports/SkFontHost_FreeType_Subpixel.cpp
-**
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-/* This file contains functions for converting Freetype's subpixel output
- formats into the format used by SkMask for subpixel masks. See the comments
- in SkMask.h for details on the format.
-*/
-
-#include "SkColorPriv.h"
-#include "SkFontHost.h"
-#include "SkMask.h"
-#include "SkScalerContext.h"
-
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
-#if 0
-// Also include the files by name for build tools which require this.
-#include <freetype/freetype.h>
-#endif
-
-namespace skia_freetype_support {
-
-void CopyFreetypeBitmapToLCDMask(const SkGlyph& dest, const FT_Bitmap& source)
-{
- // |source| has three alpha values per pixel and has an extra column at the
- // left and right edges.
-
- // ----- <--- a single pixel in the output
- // source .oOo.. |.oO|o..
- // .OOO.. -----
- // .oOo.. --> .OO O..
- // .oO o..
-
- uint8_t* output = reinterpret_cast<uint8_t*>(dest.fImage);
- const unsigned outputPitch = SkAlign4((source.width / 3) - 2);
- const uint8_t* input = source.buffer;
-
- // First we calculate the A8 mask.
- for (int y = 0; y < source.rows; ++y) {
- const uint8_t* inputRow = input;
- uint8_t* outputRow = output;
- inputRow += 3; // skip the extra column on the left
- for (int x = 3; x < source.width - 3; x += 3) {
- const uint8_t averageAlpha = (static_cast<unsigned>(inputRow[0]) + inputRow[1] + inputRow[2] + 1) / 3;
- *outputRow++ = averageAlpha;
- inputRow += 3;
- }
-
- input += source.pitch;
- output += outputPitch;
- }
-
- // Align the 32-bit plane on a word boundary
- uint32_t* output32 = (uint32_t*) SkAlign4((uintptr_t) output);
-
- // Now we build the 32-bit alpha mask and RGB order correct.
- const int isBGR = SkFontHost::GetSubpixelOrder() == SkFontHost::kBGR_LCDOrder;
- input = source.buffer;
-
- for (int y = 0; y < source.rows; ++y) {
- const uint8_t* inputRow = input;
- for (int x = 0; x < source.width; x += 3) {
- const uint8_t alphaRed = isBGR ? inputRow[2] : inputRow[0];
- const uint8_t alphaGreen = inputRow[1];
- const uint8_t alphaBlue = isBGR ? inputRow[0] : inputRow[2];
- const uint8_t maxAlpha = SkMax32(alphaRed, SkMax32(alphaGreen, alphaBlue));
- *output32++ = SkPackARGB32(maxAlpha, alphaRed, alphaGreen, alphaBlue);
-
- inputRow += 3;
- }
-
- input += source.pitch;
- }
-}
-
-void CopyFreetypeBitmapToVerticalLCDMask(const SkGlyph& dest, const FT_Bitmap& source)
-{
- // |source| has three times as many rows as normal, and an extra triple on the
- // top and bottom.
-
- // source .oOo.. |.|oOo..
- // .OOO.. --> |.|OOO..
- // .oOo.. |.|oOo..
- // ^
- // |-------- A single pixel in the output
-
- uint8_t* output = reinterpret_cast<uint8_t*>(dest.fImage);
- const unsigned outputPitch = dest.rowBytes();
- const uint8_t* input = source.buffer;
-
- // First we calculate the A8 mask.
- input += 3 * source.pitch; // skip the extra at the beginning
- for (int y = 3; y < source.rows - 3; y += 3) {
- const uint8_t* inputRow = input;
- uint8_t* outputRow = output;
- for (int x = 0; x < source.width; ++x) {
- const uint8_t averageAlpha = (static_cast<unsigned>(*inputRow) + inputRow[source.pitch] + inputRow[source.pitch * 2] + 1) / 3;
- *outputRow++ = averageAlpha;
- inputRow++;
- }
-
- input += source.pitch * 3;
- output += outputPitch;
- }
-
- // Align the 32-bit plane on a word boundary
- uint32_t* output32 = (uint32_t*) SkAlign4((uintptr_t) output);
-
- // Now we build the 32-bit alpha mask and RGB order correct.
- const int isBGR = SkFontHost::GetSubpixelOrder() == SkFontHost::kBGR_LCDOrder;
- input = source.buffer;
-
- for (int y = 0; y < source.rows; y += 3) {
- const uint8_t* inputRow = input;
- for (int x = 0; x < source.width; ++x) {
- const uint8_t alphaRed = isBGR ? inputRow[source.pitch * 2] : inputRow[0];
- const uint8_t alphaGreen = inputRow[source.pitch];
- const uint8_t alphaBlue = isBGR ? inputRow[0] : inputRow[2 * source.pitch];
- const uint8_t maxAlpha = SkMax32(alphaRed, SkMax32(alphaGreen, alphaBlue));
- *output32++ = SkPackARGB32(maxAlpha, alphaRed, alphaGreen, alphaBlue);
- inputRow++;
- }
-
- input += source.pitch * 3;
- }
-}
-
-} // namespace skia_freetype_support
diff --git a/src/ports/SkFontHost_android.cpp b/src/ports/SkFontHost_android.cpp
index 5b7eb24..b07d93d 100644
--- a/src/ports/SkFontHost_android.cpp
+++ b/src/ports/SkFontHost_android.cpp
@@ -464,9 +464,11 @@ static void load_font_info() {
// shouldn't get here
gNumSystemFonts = 0;
}
+// SkDebugf("---- We have %d system fonts", gNumSystemFonts);
for (size_t i = 0; i < gNumSystemFonts; ++i) {
gSystemFonts[i].fFileName = fontInfo[i].fFileName;
gSystemFonts[i].fNames = fontInfo[i].fNames;
+// SkDebugf("---- gSystemFonts[%d] fileName=%s", i, fontInfo[i].fFileName);
}
fontFamilies.deleteAll();
}
@@ -511,11 +513,13 @@ static void load_system_fonts() {
isFixedWidth) // filename
);
+// SkDebugf("---- SkTypeface[%d] %s fontID %d\n", i, rec[i].fFileName, tf->uniqueID());
+
if (rec[i].fNames != NULL) {
// see if this is one of our fallback fonts
if (rec[i].fNames == gFBNames) {
- // SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
- // rec[i].fFileName, fallbackCount, tf->uniqueID());
+// SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
+// rec[i].fFileName, fallbackCount, tf->uniqueID());
gFallbackFonts[fallbackCount++] = tf->uniqueID();
}
@@ -762,13 +766,3 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
stream->unref();
return face;
}
-
-///////////////////////////////////////////////////////////////////////////////
-
-size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
- if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
- return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
- else
- return 0; // nothing to do
-}
-
diff --git a/src/ports/SkFontHost_ascender.cpp b/src/ports/SkFontHost_ascender.cpp
index 6f5cf0b..ccfedef 100644
--- a/src/ports/SkFontHost_ascender.cpp
+++ b/src/ports/SkFontHost_ascender.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkScalerContext.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
diff --git a/src/ports/SkFontHost_fontconfig.cpp b/src/ports/SkFontHost_fontconfig.cpp
index 332c911..acc5ae0 100644
--- a/src/ports/SkFontHost_fontconfig.cpp
+++ b/src/ports/SkFontHost_fontconfig.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/ports/SkFontHost_fontconfig.cpp
-**
-** Copyright 2008, Google Inc.
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
// -----------------------------------------------------------------------------
// This file provides implementations of the font resolution members of
@@ -52,9 +44,6 @@ static std::map<unsigned, std::string> global_fc_map_inverted;
static std::map<uint32_t, SkTypeface *> global_fc_typefaces;
static unsigned global_fc_map_next_id = 0;
-// This is the maximum size of the font cache.
-static const unsigned kFontCacheMemoryBudget = 2 * 1024 * 1024; // 2MB
-
static unsigned UniqueIdToFileId(unsigned uniqueid)
{
return uniqueid >> 8;
@@ -122,7 +111,7 @@ static FcPattern* FontMatch(const char* type, FcType vtype, const void* value,
fcvalue.u.i = (int)(intptr_t)value;
break;
default:
- SkASSERT(!"FontMatch unhandled type");
+ SkDEBUGFAIL("FontMatch unhandled type");
}
FcPatternAdd(pattern, type, fcvalue, 0);
@@ -303,14 +292,14 @@ SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
// static
SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream)
{
- SkASSERT(!"SkFontHost::CreateTypefaceFromStream unimplemented");
+ SkDEBUGFAIL("SkFontHost::CreateTypefaceFromStream unimplemented");
return NULL;
}
// static
SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[])
{
- SkASSERT(!"SkFontHost::CreateTypefaceFromFile unimplemented");
+ SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented");
return NULL;
}
@@ -356,11 +345,11 @@ size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
}
void SkFontHost::Serialize(const SkTypeface*, SkWStream*) {
- SkASSERT(!"SkFontHost::Serialize unimplemented");
+ SkDEBUGFAIL("SkFontHost::Serialize unimplemented");
}
SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
- SkASSERT(!"SkFontHost::Deserialize unimplemented");
+ SkDEBUGFAIL("SkFontHost::Deserialize unimplemented");
return NULL;
}
@@ -369,12 +358,3 @@ SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
return 0;
}
-///////////////////////////////////////////////////////////////////////////////
-
-size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar)
-{
- if (sizeAllocatedSoFar > kFontCacheMemoryBudget)
- return sizeAllocatedSoFar - kFontCacheMemoryBudget;
- else
- return 0; // nothing to do
-}
diff --git a/src/ports/SkFontHost_freetype_mac.cpp b/src/ports/SkFontHost_freetype_mac.cpp
new file mode 100644
index 0000000..140098d
--- /dev/null
+++ b/src/ports/SkFontHost_freetype_mac.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkFontHost.h"
+#include "SkMMapStream.h"
+#include "SkTypefaceCache.h"
+
+#define FONT_PATH "/Library/Fonts/Skia.ttf"
+
+class FTMacTypeface : public SkTypeface {
+public:
+ FTMacTypeface(Style style, uint32_t id, SkStream* stream) : SkTypeface(style, id) {
+ // we take ownership of the stream
+ fStream = stream;
+ }
+
+ virtual ~FTMacTypeface() {
+ fStream->unref();
+ }
+
+ SkStream* fStream;
+};
+
+static FTMacTypeface* create_from_path(const char path[]) {
+ SkStream* stream = new SkMMAPStream(path);
+ size_t size = stream->getLength();
+ SkASSERT(size);
+ FTMacTypeface* tf = new FTMacTypeface(SkTypeface::kNormal,
+ SkTypefaceCache::NewFontID(),
+ stream);
+ SkTypefaceCache::Add(tf, SkTypeface::kNormal);
+ return tf;
+}
+
+static SkTypeface* ref_default_typeface() {
+ static SkTypeface* gDef;
+
+ if (NULL == gDef) {
+ gDef = create_from_path(FONT_PATH);
+ }
+
+ gDef->ref();
+ return gDef;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
+ const char familyName[],
+ const void* data, size_t bytelength,
+ SkTypeface::Style style) {
+ return ref_default_typeface();
+}
+
+SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
+ SkDEBUGFAIL("SkFontHost::CreateTypefaceFromStream unimplemented");
+ return NULL;
+}
+
+SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
+ return create_from_path(path);
+}
+
+bool SkFontHost::ValidFontID(SkFontID fontID) {
+ return SkTypefaceCache::FindByID(fontID) != NULL;
+}
+
+SkStream* SkFontHost::OpenStream(uint32_t fontID) {
+ FTMacTypeface* tf = (FTMacTypeface*)SkTypefaceCache::FindByID(fontID);
+ if (tf) {
+ tf->fStream->ref();
+ return tf->fStream;
+ }
+ return NULL;
+}
+
+size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
+ int32_t* index) {
+ if (path) {
+ strncpy(path, "font", length);
+ }
+ if (index) {
+ *index = 0;
+ }
+ return 4;
+}
+
+void SkFontHost::Serialize(const SkTypeface*, SkWStream*) {
+ SkDEBUGFAIL("SkFontHost::Serialize unimplemented");
+}
+
+SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
+ SkDEBUGFAIL("SkFontHost::Deserialize unimplemented");
+ return NULL;
+}
+
+SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
+ return 0;
+}
+
+#include "SkTypeface_mac.h"
+
+SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef fontRef) {
+ SkDEBUGFAIL("Not supported");
+ return NULL;
+}
+
diff --git a/src/ports/SkFontHost_gamma.cpp b/src/ports/SkFontHost_gamma.cpp
index e4cd8f1..0d15414 100644
--- a/src/ports/SkFontHost_gamma.cpp
+++ b/src/ports/SkFontHost_gamma.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkFontHost.h"
#include <math.h>
@@ -50,7 +57,7 @@ void skia_set_text_gamma(float blackGamma, float whiteGamma) {
gBlackGammaCoeff = blackGamma;
gWhiteGammaCoeff = whiteGamma;
gGammaIsBuilt = false;
- SkGraphics::SetFontCacheUsed(0);
+ SkGraphics::PurgeFontCache();
build_power_table(gBlackGamma, gBlackGammaCoeff);
build_power_table(gWhiteGamma, gWhiteGammaCoeff);
}
@@ -98,29 +105,3 @@ void SkFontHost::GetGammaTables(const uint8_t* tables[2]) {
tables[1] = gWhiteGamma;
}
-// If the luminance is <= this value, then apply the black gamma table
-#define BLACK_GAMMA_THRESHOLD 0x40
-
-// If the luminance is >= this value, then apply the white gamma table
-#define WHITE_GAMMA_THRESHOLD 0xC0
-
-int SkFontHost::ComputeGammaFlag(const SkPaint& paint) {
- if (paint.getShader() == NULL) {
- SkColor c = paint.getColor();
- int r = SkColorGetR(c);
- int g = SkColorGetG(c);
- int b = SkColorGetB(c);
- int luminance = (r * 2 + g * 5 + b) >> 3;
-
- if (luminance <= BLACK_GAMMA_THRESHOLD) {
- // printf("------ black gamma for [%d %d %d]\n", r, g, b);
- return SkScalerContext::kGammaForBlack_Flag;
- }
- if (luminance >= WHITE_GAMMA_THRESHOLD) {
- // printf("------ white gamma for [%d %d %d]\n", r, g, b);
- return SkScalerContext::kGammaForWhite_Flag;
- }
- }
- return 0;
-}
-
diff --git a/src/ports/SkFontHost_gamma_none.cpp b/src/ports/SkFontHost_gamma_none.cpp
index 37f190d..18f113c 100644
--- a/src/ports/SkFontHost_gamma_none.cpp
+++ b/src/ports/SkFontHost_gamma_none.cpp
@@ -1,17 +1,11 @@
-/* Copyright 2008, Google Inc.
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
// -----------------------------------------------------------------------------
// This is a noop gamma implementation for systems where gamma is already
@@ -27,8 +21,3 @@ void SkFontHost::GetGammaTables(const uint8_t* tables[2])
tables[1] = NULL;
}
-int SkFontHost::ComputeGammaFlag(const SkPaint& paint)
-{
- return 0;
-}
-
diff --git a/src/ports/SkFontHost_linux.cpp b/src/ports/SkFontHost_linux.cpp
index 9ede78c..c87b036 100644
--- a/src/ports/SkFontHost_linux.cpp
+++ b/src/ports/SkFontHost_linux.cpp
@@ -1,20 +1,12 @@
-/* libs/graphics/ports/SkFontHost_android.cpp
- **
- ** Copyright 2006, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkFontHost.h"
#include "SkDescriptor.h"
#include "SkMMapStream.h"
@@ -26,8 +18,6 @@
#include "SkTSearch.h"
#include <stdio.h>
-#define FONT_CACHE_MEMORY_BUDGET (1 * 1024 * 1024)
-
#ifndef SK_FONT_FILE_PREFIX
#define SK_FONT_FILE_PREFIX "/usr/share/fonts/truetype/msttcorefonts/"
#endif
@@ -109,7 +99,7 @@ static SkTypeface* find_best_face(const FamilyRec* family,
}
}
// should never get here, since the faces list should not be empty
- SkASSERT(!"faces list is empty");
+ SkDEBUGFAIL("faces list is empty");
return NULL;
}
@@ -137,7 +127,7 @@ static SkTypeface* find_from_uniqueID(uint32_t uniqueID) {
}
curr = curr->fNext;
}
- return false;
+ return NULL;
}
static bool valid_uniqueID(uint32_t uniqueID) {
@@ -179,7 +169,7 @@ static void detach_and_delete_family(FamilyRec* family) {
prev = curr;
curr = next;
}
- SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
+ SkDEBUGFAIL("Yikes, couldn't find family in our list to remove/delete");
}
static FamilyRec* find_familyrec(const char name[]) {
@@ -608,12 +598,3 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
return face;
}
-///////////////////////////////////////////////////////////////////////////////
-
-size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
- if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
- return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
- else
- return 0; // nothing to do
-}
-
diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp
index 6adaf32..7d12f53 100755
--- a/src/ports/SkFontHost_mac.cpp
+++ b/src/ports/SkFontHost_mac.cpp
@@ -1,18 +1,11 @@
+
/*
- ** Copyright 2006, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
-*/
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
/*
@@ -30,7 +23,7 @@
** builds unless SK_USE_CORETEXT is defined.
*/
#ifndef SK_USE_CORETEXT
- #if TARGET_RT_64_BIT
+ #if TARGET_RT_64_BIT || defined(SK_USE_MAC_CORE_TEXT)
#define SK_USE_CORETEXT 1
#else
#define SK_USE_CORETEXT 0
diff --git a/src/ports/SkFontHost_mac_atsui.cpp b/src/ports/SkFontHost_mac_atsui.cpp
index fb61c60..b90757c 100644
--- a/src/ports/SkFontHost_mac_atsui.cpp
+++ b/src/ports/SkFontHost_mac_atsui.cpp
@@ -1,18 +1,11 @@
+
/*
- ** Copyright 2006, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
-*/
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include <Carbon/Carbon.h>
#include "SkFontHost.h"
@@ -22,9 +15,6 @@
#include "SkPaint.h"
#include "SkPoint.h"
-// Give 1MB font cache budget
-#define FONT_CACHE_MEMORY_BUDGET (1024 * 1024)
-
const char* gDefaultfont = "Arial"; // hard code for now
static SkMutex gFTMutex;
@@ -47,7 +37,7 @@ public:
static uint32_t find_from_name(const char name[]) {
CFStringRef str = CFStringCreateWithCString(NULL, name,
- kCFStringEncodingUTF8);
+ kCFStringEncodingUTF8);
uint32_t fontID = ::ATSFontFindFromName(str, kATSOptionFlagsDefault);
CFRelease(str);
return fontID;
@@ -100,7 +90,7 @@ private:
ATSUStyle fStyle;
CGColorSpaceRef fGrayColorSpace;
CGAffineTransform fTransform;
-
+
static OSStatus MoveTo(const Float32Point *pt, void *cb);
static OSStatus Line(const Float32Point *pt, void *cb);
static OSStatus Curve(const Float32Point *pt1, const Float32Point *pt2, const Float32Point *pt3, void *cb);
@@ -118,7 +108,8 @@ void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
rec->setHinting(h);
// we don't support LCD text
- if (SkMask::FormatIsLCD((SkMask::Format)rec->fMaskFormat)) {
+ if (SkMask::kLCD16_Format == rec->fMaskFormat ||
+ SkMask::kLCD32_Format == rec->fMaskFormat) {
rec->fMaskFormat = SkMask::kA8_Format;
}
}
@@ -128,20 +119,20 @@ SkScalerContext_Mac::SkScalerContext_Mac(const SkDescriptor* desc)
{
SkAutoMutexAcquire ac(gFTMutex);
OSStatus err;
-
+
err = ::ATSUCreateStyle(&fStyle);
SkASSERT(0 == err);
-
+
SkMatrix m;
fRec.getSingleMatrix(&m);
-
+
fTransform = CGAffineTransformMake(SkScalarToFloat(m[SkMatrix::kMScaleX]),
SkScalarToFloat(m[SkMatrix::kMSkewX]),
SkScalarToFloat(m[SkMatrix::kMSkewY]),
SkScalarToFloat(m[SkMatrix::kMScaleY]),
SkScalarToFloat(m[SkMatrix::kMTransX]),
SkScalarToFloat(m[SkMatrix::kMTransY]));
-
+
ATSStyleRenderingOptions renderOpts = kATSStyleApplyAntiAliasing;
switch (fRec.getHinting()) {
case SkPaint::kNo_Hinting:
@@ -198,16 +189,16 @@ unsigned SkScalerContext_Mac::generateGlyphCount() {
uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni)
{
SkAutoMutexAcquire ac(gFTMutex);
-
+
OSStatus err;
UniChar achar = uni;
err = ::ATSUSetTextPointerLocation(fLayout,&achar,0,1,1);
err = ::ATSUSetRunStyle(fLayout,fStyle,kATSUFromTextBeginning,kATSUToTextEnd);
-
+
ATSLayoutRecord *layoutPtr;
ItemCount count;
ATSGlyphRef glyph;
-
+
err = ::ATSUDirectGetLayoutDataArrayPtrFromTextLayout(fLayout,0,kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,(void**)&layoutPtr,&count);
glyph = layoutPtr->glyphID;
::ATSUDirectReleaseLayoutDataArrayPtr(NULL,kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,(void**)&layoutPtr);
@@ -266,7 +257,7 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph)
{
SkAutoMutexAcquire ac(gFTMutex);
SkASSERT(fLayout);
-
+
sk_bzero(glyph.fImage, glyph.fHeight * glyph.rowBytes());
CGContextRef contextRef = ::CGBitmapContextCreate(glyph.fImage,
glyph.fWidth, glyph.fHeight, 8,
@@ -276,10 +267,10 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph)
SkASSERT(false);
return;
}
-
+
::CGContextSetGrayFillColor(contextRef, 1.0, 1.0);
::CGContextSetTextDrawingMode(contextRef, kCGTextFill);
-
+
CGGlyph glyphID = glyph.getGlyphID(fBaseGlyphCount);
CGFontRef fontRef = CGFontCreateWithPlatformFont(&fRec.fFontID);
CGContextSetFont(contextRef, fontRef);
@@ -287,7 +278,7 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph)
CGContextSetTextMatrix(contextRef, fTransform);
CGContextShowGlyphsAtPoint(contextRef, -glyph.fLeft,
glyph.fTop + glyph.fHeight, &glyphID, 1);
-
+
::CGContextRelease(contextRef);
}
@@ -365,7 +356,7 @@ static bool init_vertical_metrics(ATSFontRef font, SkPoint pts[5]) {
for (int i = 0; i < 5; i++) {
pts[i].set(0, SkIntToScalar(ys[i]) / upem);
}
-
+
sk_free(hhea);
sk_free(head);
return true;
@@ -374,7 +365,7 @@ static bool init_vertical_metrics(ATSFontRef font, SkPoint pts[5]) {
void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx,
SkPaint::FontMetrics* my) {
SkPoint pts[5];
-
+
if (!init_vertical_metrics(fRec.fFontID, pts)) {
// these are not as accurate as init_vertical_metrics :(
ATSFontMetrics metrics;
@@ -386,7 +377,7 @@ void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx,
pts[3].set(0, -SkFloatToScalar(metrics.descent));
pts[4].set(0, SkFloatToScalar(metrics.leading)); //+ or -?
}
-
+
SkMatrix m;
fRec.getSingleMatrix(&m);
m.mapPoints(pts, 5);
@@ -421,7 +412,7 @@ void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path)
{
SkAutoMutexAcquire ac(gFTMutex);
OSStatus err,result;
-
+
err = ::ATSUGlyphGetCubicPaths(
fStyle,glyph.fID,
&SkScalerContext_Mac::MoveTo,
@@ -463,11 +454,11 @@ OSStatus SkScalerContext_Mac::Close(void *cb)
#pragma mark -
void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
- SkASSERT(!"SkFontHost::Serialize unimplemented");
+ SkDEBUGFAIL("SkFontHost::Serialize unimplemented");
}
SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
- SkASSERT(!"SkFontHost::Deserialize unimplemented");
+ SkDEBUGFAIL("SkFontHost::Deserialize unimplemented");
return NULL;
}
@@ -482,8 +473,10 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
// static
SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
uint32_t fontID,
- SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo) {
- SkASSERT(!"SkFontHost::GetAdvancedTypefaceMetrics unimplemented");
+ SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
+ const uint32_t* glyphIDs,
+ uint32_t glyphIDsCount) {
+ SkDEBUGFAIL("SkFontHost::GetAdvancedTypefaceMetrics unimplemented");
return NULL;
}
@@ -512,22 +505,6 @@ SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
}
}
-size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
- if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
- return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
- else
- return 0; // nothing to do
-}
-
-int SkFontHost::ComputeGammaFlag(const SkPaint& paint) {
- return 0;
-}
-
-void SkFontHost::GetGammaTables(const uint8_t* tables[2]) {
- tables[0] = NULL; // black gamma (e.g. exp=1.4)
- tables[1] = NULL; // white gamma (e.g. exp= 1/1.4)
-}
-
///////////////////////////////////////////////////////////////////////////////
struct SkSFNTHeader {
@@ -551,33 +528,33 @@ struct SfntHeader {
if (ATSFontGetTableDirectory(fontID, 0, NULL, &size)) {
return;
}
-
+
SkAutoMalloc storage(size);
SkSFNTHeader* header = reinterpret_cast<SkSFNTHeader*>(storage.get());
if (ATSFontGetTableDirectory(fontID, size, header, &size)) {
return;
}
-
+
fCount = SkEndian_SwapBE16(header->fNumTables);
fData = header;
storage.detach();
}
-
+
~SfntHeader() {
sk_free(fData);
}
-
+
int count() const { return fCount; }
const SkSFNTDirEntry* entries() const {
return reinterpret_cast<const SkSFNTDirEntry*>
(reinterpret_cast<char*>(fData) + sizeof(SkSFNTHeader));
}
-
+
private:
int fCount;
void* fData;
};
-
+
int SkFontHost::CountTables(SkFontID fontID) {
SfntHeader header(fontID, false);
return header.count();
@@ -615,4 +592,3 @@ size_t SkFontHost::GetTableData(SkFontID fontID, SkFontTableTag tag,
}
return length;
}
-
diff --git a/src/ports/SkFontHost_mac_coretext.cpp b/src/ports/SkFontHost_mac_coretext.cpp
index f9eba95..866e196 100644
--- a/src/ports/SkFontHost_mac_coretext.cpp
+++ b/src/ports/SkFontHost_mac_coretext.cpp
@@ -1,20 +1,21 @@
+
/*
- ** Copyright 2006, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
-*/
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include <vector>
-#include <Carbon/Carbon.h>
+#ifdef SK_BUILD_FOR_MAC
+#import <ApplicationServices/ApplicationServices.h>
+#endif
+
+#ifdef SK_BUILD_FOR_IOS
+#include <CoreText/CoreText.h>
+#include <CoreGraphics/CoreGraphics.h>
+#include <CoreFoundation/CoreFoundation.h>
+#endif
#include "SkFontHost.h"
#include "SkDescriptor.h"
@@ -23,15 +24,229 @@
#include "SkPaint.h"
#include "SkString.h"
#include "SkStream.h"
+#include "SkThread.h"
#include "SkTypeface_mac.h"
#include "SkUtils.h"
#include "SkTypefaceCache.h"
-using namespace skia_advanced_typeface_metrics_utils;
+class SkScalerContext_Mac;
+
+// inline versions of these rect helpers
+
+static bool CGRectIsEmpty_inline(const CGRect& rect) {
+ return rect.size.width <= 0 || rect.size.height <= 0;
+}
+
+static void CGRectInset_inline(CGRect* rect, CGFloat dx, CGFloat dy) {
+ rect->origin.x += dx;
+ rect->origin.y += dy;
+ rect->size.width -= dx * 2;
+ rect->size.height -= dy * 2;
+}
+
+static CGFloat CGRectGetMinX_inline(const CGRect& rect) {
+ return rect.origin.x;
+}
+
+static CGFloat CGRectGetMaxX_inline(const CGRect& rect) {
+ return rect.origin.x + rect.size.width;
+}
+
+static CGFloat CGRectGetMinY_inline(const CGRect& rect) {
+ return rect.origin.y;
+}
+
+static CGFloat CGRectGetMaxY_inline(const CGRect& rect) {
+ return rect.origin.y + rect.size.height;
+}
+
+static CGFloat CGRectGetWidth_inline(const CGRect& rect) {
+ return rect.size.width;
+}
+
+static CGFloat CGRectGetHeight(const CGRect& rect) {
+ return rect.size.height;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void sk_memset_rect32(uint32_t* ptr, uint32_t value, size_t width,
+ size_t height, size_t rowBytes) {
+ SkASSERT(width);
+ SkASSERT(width * sizeof(uint32_t) <= rowBytes);
+
+ if (width >= 32) {
+ while (height) {
+ sk_memset32(ptr, value, width);
+ ptr = (uint32_t*)((char*)ptr + rowBytes);
+ height -= 1;
+ }
+ return;
+ }
+
+ rowBytes -= width * sizeof(uint32_t);
+
+ if (width >= 8) {
+ while (height) {
+ int w = width;
+ do {
+ *ptr++ = value; *ptr++ = value;
+ *ptr++ = value; *ptr++ = value;
+ *ptr++ = value; *ptr++ = value;
+ *ptr++ = value; *ptr++ = value;
+ w -= 8;
+ } while (w >= 8);
+ while (--w >= 0) {
+ *ptr++ = value;
+ }
+ ptr = (uint32_t*)((char*)ptr + rowBytes);
+ height -= 1;
+ }
+ } else {
+ while (height) {
+ int w = width;
+ do {
+ *ptr++ = value;
+ } while (--w > 0);
+ ptr = (uint32_t*)((char*)ptr + rowBytes);
+ height -= 1;
+ }
+ }
+}
+
+// Potentially this should be made (1) public (2) optimized when width is small.
+// Also might want 16 and 32 bit version
+//
+static void sk_memset_rect(void* ptr, U8CPU byte, size_t width, size_t height,
+ size_t rowBytes) {
+ uint8_t* dst = (uint8_t*)ptr;
+ while (height) {
+ memset(dst, byte, width);
+ dst += rowBytes;
+ height -= 1;
+ }
+}
+
+#include <sys/utsname.h>
+
+typedef uint32_t CGRGBPixel;
+
+static unsigned CGRGBPixel_getAlpha(CGRGBPixel pixel) {
+ return pixel >> 24;
+}
+
+// The calls to support subpixel are present in 10.5, but are not included in
+// the 10.5 SDK. The needed calls have been extracted from the 10.6 SDK and are
+// included below. To verify that CGContextSetShouldSubpixelQuantizeFonts, for
+// instance, is present in the 10.5 CoreGraphics libary, use:
+// cd /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/
+// cd ApplicationServices.framework/Frameworks/CoreGraphics.framework/
+// nm CoreGraphics | grep CGContextSetShouldSubpixelQuantizeFonts
+
+#if !defined(MAC_OS_X_VERSION_10_6) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
+ CG_EXTERN void CGContextSetAllowsFontSmoothing(CGContextRef context,
+ bool allowsFontSmoothing);
+ CG_EXTERN void CGContextSetAllowsFontSubpixelPositioning(
+ CGContextRef context,
+ bool allowsFontSubpixelPositioning);
+ CG_EXTERN void CGContextSetShouldSubpixelPositionFonts(CGContextRef context,
+ bool shouldSubpixelPositionFonts);
+ CG_EXTERN void CGContextSetAllowsFontSubpixelQuantization(
+ CGContextRef context,
+ bool allowsFontSubpixelQuantization);
+ CG_EXTERN void CGContextSetShouldSubpixelQuantizeFonts(
+ CGContextRef context,
+ bool shouldSubpixelQuantizeFonts);
+#endif
-static const size_t FONT_CACHE_MEMORY_BUDGET = 1024 * 1024;
static const char FONT_DEFAULT_NAME[] = "Lucida Sans";
+// see Source/WebKit/chromium/base/mac/mac_util.mm DarwinMajorVersionInternal
+// for original source
+static int readVersion() {
+ struct utsname info;
+ if (uname(&info) != 0) {
+ SkDebugf("uname failed\n");
+ return 0;
+ }
+ if (strcmp(info.sysname, "Darwin") != 0) {
+ SkDebugf("unexpected uname sysname %s\n", info.sysname);
+ return 0;
+ }
+ char* dot = strchr(info.release, '.');
+ if (!dot) {
+ SkDebugf("expected dot in uname release %s\n", info.release);
+ return 0;
+ }
+ int version = atoi(info.release);
+ if (version == 0) {
+ SkDebugf("could not parse uname release %s\n", info.release);
+ }
+ return version;
+}
+
+static int darwinVersion() {
+ static int darwin_version = readVersion();
+ return darwin_version;
+}
+
+static bool isLeopard() {
+ return darwinVersion() == 9;
+}
+
+static bool isSnowLeopard() {
+ return darwinVersion() == 10;
+}
+
+static bool isLion() {
+ return darwinVersion() == 11;
+}
+
+static bool isLCDFormat(unsigned format) {
+ return SkMask::kLCD16_Format == format || SkMask::kLCD32_Format == format;
+}
+
+static CGFloat ScalarToCG(SkScalar scalar) {
+ if (sizeof(CGFloat) == sizeof(float)) {
+ return SkScalarToFloat(scalar);
+ } else {
+ SkASSERT(sizeof(CGFloat) == sizeof(double));
+ return SkScalarToDouble(scalar);
+ }
+}
+
+static SkScalar CGToScalar(CGFloat cgFloat) {
+ if (sizeof(CGFloat) == sizeof(float)) {
+ return SkFloatToScalar(cgFloat);
+ } else {
+ SkASSERT(sizeof(CGFloat) == sizeof(double));
+ return SkDoubleToScalar(cgFloat);
+ }
+}
+
+static CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix,
+ float sx = 1, float sy = 1) {
+ return CGAffineTransformMake(ScalarToCG(matrix[SkMatrix::kMScaleX]) * sx,
+ -ScalarToCG(matrix[SkMatrix::kMSkewY]) * sy,
+ -ScalarToCG(matrix[SkMatrix::kMSkewX]) * sx,
+ ScalarToCG(matrix[SkMatrix::kMScaleY]) * sy,
+ ScalarToCG(matrix[SkMatrix::kMTransX]) * sx,
+ ScalarToCG(matrix[SkMatrix::kMTransY]) * sy);
+}
+
+static void CGAffineTransformToMatrix(const CGAffineTransform& xform, SkMatrix* matrix) {
+ matrix->setAll(
+ CGToScalar(xform.a), CGToScalar(xform.c), CGToScalar(xform.tx),
+ CGToScalar(xform.b), CGToScalar(xform.d), CGToScalar(xform.ty),
+ 0, 0, SK_Scalar1);
+}
+
+static SkScalar getFontScale(CGFontRef cgFont) {
+ int unitsPerEm = CGFontGetUnitsPerEm(cgFont);
+ return SkScalarInvert(SkIntToScalar(unitsPerEm));
+}
+
//============================================================================
// Macros
//----------------------------------------------------------------------------
@@ -49,6 +264,48 @@ static const char FONT_DEFAULT_NAME[] = "Lucida Sans";
while (false)
#endif
+///////////////////////////////////////////////////////////////////////////////
+
+#define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
+#define BITMAP_INFO_GRAY (kCGImageAlphaNone)
+
+class Offscreen {
+public:
+ Offscreen();
+ ~Offscreen();
+
+ CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
+ bool fgColorIsWhite, CGGlyph glyphID, size_t* rowBytesPtr);
+
+private:
+ enum {
+ kSize = 32 * 32 * sizeof(CGRGBPixel)
+ };
+ SkAutoSMalloc<kSize> fImageStorage;
+ CGColorSpaceRef fRGBSpace;
+
+ // cached state
+ CGContextRef fCG;
+ SkISize fSize;
+ bool fFgColorIsWhite;
+ bool fDoAA;
+ bool fDoLCD;
+
+ static int RoundSize(int dimension) {
+ return SkNextPow2(dimension);
+ }
+};
+
+Offscreen::Offscreen() : fRGBSpace(NULL), fCG(NULL) {
+ fSize.set(0,0);
+}
+
+Offscreen::~Offscreen() {
+ CFSafeRelease(fCG);
+ CFSafeRelease(fRGBSpace);
+}
+
+///////////////////////////////////////////////////////////////////////////////
static SkTypeface::Style computeStyleBits(CTFontRef font, bool* isMonospace) {
unsigned style = SkTypeface::kNormal;
@@ -66,10 +323,51 @@ static SkTypeface::Style computeStyleBits(CTFontRef font, bool* isMonospace) {
return (SkTypeface::Style)style;
}
+class AutoCFDataRelease {
+public:
+ AutoCFDataRelease(CFDataRef obj) : fObj(obj) {}
+ const uint16_t* getShortPtr() {
+ return fObj ? (const uint16_t*) CFDataGetBytePtr(fObj) : NULL;
+ }
+ ~AutoCFDataRelease() { CFSafeRelease(fObj); }
+private:
+ CFDataRef fObj;
+};
+
+static SkFontID CTFontRef_to_SkFontID(CTFontRef fontRef) {
+ ATSFontRef ats = CTFontGetPlatformFont(fontRef, NULL);
+ SkFontID id = (SkFontID)ats;
+ if (id != 0) {
+ id &= 0x3FFFFFFF; // make top two bits 00
+ return id;
+ }
+ // CTFontGetPlatformFont returns NULL if the font is local
+ // (e.g., was created by a CSS3 @font-face rule).
+ CGFontRef cgFont = CTFontCopyGraphicsFont(fontRef, NULL);
+ AutoCFDataRelease headRef(CGFontCopyTableForTag(cgFont, 'head'));
+ const uint16_t* headData = headRef.getShortPtr();
+ if (headData) {
+ id = (SkFontID) (headData[4] | headData[5] << 16); // checksum
+ id = (id & 0x3FFFFFFF) | 0x40000000; // make top two bits 01
+ }
+ // well-formed fonts have checksums, but as a last resort, use the pointer.
+ if (id == 0) {
+ id = (SkFontID) (uintptr_t) fontRef;
+ id = (id & 0x3FFFFFFF) | 0x80000000; // make top two bits 10
+ }
+ CGFontRelease(cgFont);
+ return id;
+}
+
class SkTypeface_Mac : public SkTypeface {
public:
- SkTypeface_Mac(SkTypeface::Style style, SkFontID fontID, bool isMonospace)
- : SkTypeface(style, fontID, isMonospace), fFontRef(0) {}
+ SkTypeface_Mac(SkTypeface::Style style, SkFontID fontID, bool isMonospace,
+ CTFontRef fontRef, const char name[])
+ : SkTypeface(style, fontID, isMonospace) {
+ SkASSERT(fontRef);
+ fFontRef = fontRef; // caller has already called CFRetain for us
+ fName.set(name);
+ }
virtual ~SkTypeface_Mac() { CFRelease(fFontRef); }
@@ -78,14 +376,12 @@ public:
};
static SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[]) {
+ SkASSERT(fontRef);
bool isMonospace;
SkTypeface::Style style = computeStyleBits(fontRef, &isMonospace);
- SkTypeface_Mac* face = new SkTypeface_Mac(style,
- SkTypefaceCache::NewFontID(),
- isMonospace);
- face->fFontRef = fontRef; // we take over ownership of fontRef
- face->fName.set(name);
- return face;
+ SkFontID fontID = CTFontRef_to_SkFontID(fontRef);
+
+ return new SkTypeface_Mac(style, fontID, isMonospace, fontRef, name);
}
static SkTypeface* NewFromName(const char familyName[],
@@ -96,13 +392,13 @@ static SkTypeface* NewFromName(const char familyName[],
CTFontDescriptorRef ctFontDesc;
CFStringRef cfFontName;
CTFontRef ctFont;
-
-
+
+
// Get the state we need
ctFontDesc = NULL;
ctFont = NULL;
ctFontTraits = 0;
-
+
if (theStyle & SkTypeface::kBold) {
ctFontTraits |= kCTFontBoldTrait;
}
@@ -110,27 +406,35 @@ static SkTypeface* NewFromName(const char familyName[],
if (theStyle & SkTypeface::kItalic) {
ctFontTraits |= kCTFontItalicTrait;
}
-
+
// Create the font info
cfFontName = CFStringCreateWithCString(NULL, familyName, kCFStringEncodingUTF8);
cfFontTraits = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits);
cfAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
cfTraits = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-
-
+
+
// Create the font
if (cfFontName != NULL && cfFontTraits != NULL && cfAttributes != NULL && cfTraits != NULL) {
CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits);
-
+
CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontName);
CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute, cfTraits);
-
+
ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes);
if (ctFontDesc != NULL) {
- ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL);
+ if (isLeopard()) {
+ // CTFontCreateWithFontDescriptor on Leopard ignores the name
+ CTFontRef ctNamed = CTFontCreateWithName(cfFontName, 1, NULL);
+ ctFont = CTFontCreateCopyWithAttributes(ctNamed, 1, NULL,
+ ctFontDesc);
+ CFSafeRelease(ctNamed);
+ } else {
+ ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL);
+ }
}
}
-
+
CFSafeRelease(cfFontName);
CFSafeRelease(cfFontTraits);
CFSafeRelease(cfAttributes);
@@ -146,39 +450,35 @@ static CTFontRef GetFontRefFromFontID(SkFontID fontID) {
}
static SkTypeface* GetDefaultFace() {
+ static SkMutex gMutex;
+ SkAutoMutexAcquire ma(gMutex);
+
static SkTypeface* gDefaultFace;
if (NULL == gDefaultFace) {
- gDefaultFace = new SkTypeface_Mac(SkTypeface::kNormal,
- SkTypefaceCache::NewFontID(), false);
+ gDefaultFace = NewFromName(FONT_DEFAULT_NAME, SkTypeface::kNormal);
+ SkTypefaceCache::Add(gDefaultFace, SkTypeface::kNormal);
}
return gDefaultFace;
}
///////////////////////////////////////////////////////////////////////////////
-struct FontRefRec {
- CTFontRef fFontRef;
-};
-
-static bool FindByFontRef(SkTypeface* face, SkTypeface::Style, void* ctx) {
- const SkTypeface_Mac* mface = reinterpret_cast<SkTypeface_Mac*>(face);
- const FontRefRec* rec = reinterpret_cast<const FontRefRec*>(ctx);
-
- return rec->fFontRef == mface->fFontRef;
-}
-
/* This function is visible on the outside. It first searches the cache, and if
* not found, returns a new entry (after adding it to the cache).
*/
SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef fontRef) {
- FontRefRec rec = { fontRef };
- SkTypeface* face = SkTypefaceCache::FindByProc(FindByFontRef, &rec);
+ SkFontID fontID = CTFontRef_to_SkFontID(fontRef);
+ SkTypeface* face = SkTypefaceCache::FindByID(fontID);
if (face) {
face->ref();
} else {
face = NewFromFontRef(fontRef, NULL);
SkTypefaceCache::Add(face, face->style());
+ // NewFromFontRef doesn't retain the parameter, but the typeface it
+ // creates does release it in its destructor, so we balance that with
+ // a retain call here.
+ CFRetain(fontRef);
}
SkASSERT(face->getRefCnt() > 1);
return face;
@@ -193,7 +493,7 @@ static bool FindByNameStyle(SkTypeface* face, SkTypeface::Style style,
void* ctx) {
const SkTypeface_Mac* mface = reinterpret_cast<SkTypeface_Mac*>(face);
const NameStyleRec* rec = reinterpret_cast<const NameStyleRec*>(ctx);
-
+
return rec->fStyle == style && mface->fName.equals(rec->fName);
}
@@ -206,7 +506,7 @@ static const char* map_css_names(const char* name) {
{ "serif", "Times" },
{ "monospace", "Courier" }
};
-
+
for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
if (strcmp(name, gPairs[i].fFrom) == 0) {
return gPairs[i].fTo;
@@ -222,18 +522,18 @@ SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
if (familyName) {
familyName = map_css_names(familyName);
}
-
+
// Clone an existing typeface
// TODO: only clone if style matches the familyFace's style...
if (familyName == NULL && familyFace != NULL) {
familyFace->ref();
return const_cast<SkTypeface*>(familyFace);
}
-
+
if (!familyName || !*familyName) {
familyName = FONT_DEFAULT_NAME;
}
-
+
NameStyleRec rec = { familyName, style };
SkTypeface* face = SkTypefaceCache::FindByProc(FindByNameStyle, &rec);
@@ -251,8 +551,20 @@ SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
return face;
}
+static void flip(SkMatrix* matrix) {
+ matrix->setSkewX(-matrix->getSkewX());
+ matrix->setSkewY(-matrix->getSkewY());
+}
+
///////////////////////////////////////////////////////////////////////////////
+struct GlyphRect {
+ int16_t fMinX;
+ int16_t fMinY;
+ int16_t fMaxX;
+ int16_t fMaxY;
+};
+
class SkScalerContext_Mac : public SkScalerContext {
public:
SkScalerContext_Mac(const SkDescriptor* desc);
@@ -271,63 +583,337 @@ protected:
private:
static void CTPathElement(void *info, const CGPathElement *element);
-
+ uint16_t getAdjustStart();
+ void getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) const;
+ bool generateBBoxes();
private:
- CGColorSpaceRef mColorSpaceGray;
- CGColorSpaceRef mColorSpaceRGB;
- CGAffineTransform mTransform;
-
- CTFontRef mFont;
- uint16_t mGlyphCount;
+ CGAffineTransform fTransform;
+ SkMatrix fUnitMatrix; // without font size
+ SkMatrix fVerticalMatrix; // unit rotated
+ SkMatrix fMatrix; // with font size
+ SkMatrix fAdjustBadMatrix; // lion-specific fix
+ Offscreen fOffscreen;
+ CTFontRef fCTFont;
+ CTFontRef fCTVerticalFont; // for vertical advance
+ CGFontRef fCGFont;
+ GlyphRect* fAdjustBad;
+ uint16_t fAdjustStart;
+ uint16_t fGlyphCount;
+ bool fGeneratedBBoxes;
+ bool fDoSubPosition;
+ bool fVertical;
+
+ friend class Offscreen;
};
SkScalerContext_Mac::SkScalerContext_Mac(const SkDescriptor* desc)
: SkScalerContext(desc)
-{ CFIndex numGlyphs;
- CTFontRef ctFont;
- SkMatrix skMatrix;
-
-
+ , fCTVerticalFont(NULL)
+ , fAdjustBad(NULL)
+ , fAdjustStart(0)
+ , fGeneratedBBoxes(false)
+{
+ CTFontRef ctFont = GetFontRefFromFontID(fRec.fFontID);
+ CFIndex numGlyphs = CTFontGetGlyphCount(ctFont);
// Get the state we need
- fRec.getSingleMatrix(&skMatrix);
+ fRec.getSingleMatrix(&fMatrix);
+ fUnitMatrix = fMatrix;
+
+ // extract the font size out of the matrix, but leave the skewing for italic
+ SkScalar reciprocal = SkScalarInvert(fRec.fTextSize);
+ fUnitMatrix.preScale(reciprocal, reciprocal);
- ctFont = GetFontRefFromFontID(fRec.fFontID);
- numGlyphs = CTFontGetGlyphCount(ctFont);
SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF);
+ fTransform = MatrixToCGAffineTransform(fMatrix);
+
+ CGAffineTransform transform;
+ CGFloat unitFontSize;
+ if (isLeopard()) {
+ // passing 1 for pointSize to Leopard sets the font size to 1 pt.
+ // pass the CoreText size explicitly
+ transform = MatrixToCGAffineTransform(fUnitMatrix);
+ unitFontSize = SkScalarToFloat(fRec.fTextSize);
+ } else {
+ // since our matrix includes everything, we pass 1 for pointSize
+ transform = fTransform;
+ unitFontSize = 1;
+ }
+ flip(&fUnitMatrix); // flip to fix up bounds later
+ fVertical = SkToBool(fRec.fFlags & kVertical_Flag);
+ CTFontDescriptorRef ctFontDesc = NULL;
+ if (fVertical) {
+ CFMutableDictionaryRef cfAttributes = CFDictionaryCreateMutable(
+ kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ if (cfAttributes) {
+ CTFontOrientation ctOrientation = kCTFontVerticalOrientation;
+ CFNumberRef cfVertical = CFNumberCreate(kCFAllocatorDefault,
+ kCFNumberSInt32Type, &ctOrientation);
+ CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute,
+ cfVertical);
+ CFSafeRelease(cfVertical);
+ ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes);
+ CFRelease(cfAttributes);
+ }
+ }
+ fCTFont = CTFontCreateCopyWithAttributes(ctFont, unitFontSize, &transform,
+ ctFontDesc);
+ CFSafeRelease(ctFontDesc);
+ fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL);
+ if (fVertical) {
+ CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0);
+ transform = CGAffineTransformConcat(rotateLeft, transform);
+ fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, unitFontSize,
+ &transform, NULL);
+ fVerticalMatrix = fUnitMatrix;
+ if (isSnowLeopard()) {
+ SkScalar scale = SkScalarMul(fRec.fTextSize, getFontScale(fCGFont));
+ fVerticalMatrix.preScale(scale, scale);
+ } else {
+ fVerticalMatrix.preRotate(SkIntToScalar(90));
+ }
+ fVerticalMatrix.postScale(SK_Scalar1, -SK_Scalar1);
+ }
+ fGlyphCount = SkToU16(numGlyphs);
+ fDoSubPosition = SkToBool(fRec.fFlags & kSubpixelPositioning_Flag);
+}
+
+SkScalerContext_Mac::~SkScalerContext_Mac() {
+ delete[] fAdjustBad;
+ CFSafeRelease(fCTFont);
+ CFSafeRelease(fCTVerticalFont);
+ CFSafeRelease(fCGFont);
+}
+
+CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph,
+ bool fgColorIsWhite, CGGlyph glyphID, size_t* rowBytesPtr) {
+ if (!fRGBSpace) {
+ fRGBSpace = CGColorSpaceCreateDeviceRGB();
+ }
+
+ // default to kBW_Format
+ bool doAA = false;
+ bool doLCD = false;
+
+ switch (glyph.fMaskFormat) {
+ case SkMask::kLCD16_Format:
+ case SkMask::kLCD32_Format:
+ doLCD = true;
+ doAA = true;
+ break;
+ case SkMask::kA8_Format:
+ doLCD = false;
+ doAA = true;
+ break;
+ default:
+ break;
+ }
+
+ size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
+ if (!fCG || fSize.fWidth < glyph.fWidth || fSize.fHeight < glyph.fHeight) {
+ CFSafeRelease(fCG);
+ if (fSize.fWidth < glyph.fWidth) {
+ fSize.fWidth = RoundSize(glyph.fWidth);
+ }
+ if (fSize.fHeight < glyph.fHeight) {
+ fSize.fHeight = RoundSize(glyph.fHeight);
+ }
+
+ rowBytes = fSize.fWidth * sizeof(CGRGBPixel);
+ void* image = fImageStorage.reset(rowBytes * fSize.fHeight);
+ fCG = CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8,
+ rowBytes, fRGBSpace, BITMAP_INFO_RGB);
+
+ // skia handles quantization itself, so we disable this for cg to get
+ // full fractional data from them.
+ CGContextSetAllowsFontSubpixelQuantization(fCG, false);
+ CGContextSetShouldSubpixelQuantizeFonts(fCG, false);
+
+ CGContextSetTextDrawingMode(fCG, kCGTextFill);
+ CGContextSetFont(fCG, context.fCGFont);
+ CGContextSetFontSize(fCG, 1);
+ CGContextSetTextMatrix(fCG, context.fTransform);
+
+ CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition);
+ CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition);
+
+ // force our checks below to happen
+ fDoAA = !doAA;
+ fDoLCD = !doLCD;
+ fFgColorIsWhite = !fgColorIsWhite;
+ }
+
+ if (fDoAA != doAA) {
+ CGContextSetShouldAntialias(fCG, doAA);
+ fDoAA = doAA;
+ }
+ if (fDoLCD != doLCD) {
+ CGContextSetShouldSmoothFonts(fCG, doLCD);
+ fDoLCD = doLCD;
+ }
+ if (fFgColorIsWhite != fgColorIsWhite) {
+ CGContextSetGrayFillColor(fCG, fgColorIsWhite ? 1.0 : 0, 1.0);
+ fFgColorIsWhite = fgColorIsWhite;
+ }
- // Initialise ourselves
- mColorSpaceRGB = CGColorSpaceCreateDeviceRGB();
-// mColorSpaceRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
-// mColorSpaceRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear);
- mColorSpaceGray = CGColorSpaceCreateDeviceGray();
+ CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get();
+ // skip rows based on the glyph's height
+ image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth;
- mTransform = CGAffineTransformMake(SkScalarToFloat(skMatrix[SkMatrix::kMScaleX]),
- -SkScalarToFloat(skMatrix[SkMatrix::kMSkewY]),
- -SkScalarToFloat(skMatrix[SkMatrix::kMSkewX]),
- SkScalarToFloat(skMatrix[SkMatrix::kMScaleY]),
- SkScalarToFloat(skMatrix[SkMatrix::kMTransX]),
- SkScalarToFloat(skMatrix[SkMatrix::kMTransY]));
+ // erase with the "opposite" of the fgColor
+ uint32_t erase = fgColorIsWhite ? 0 : ~0;
+#if 0
+ sk_memset_rect(image, erase, glyph.fWidth * sizeof(CGRGBPixel),
+ glyph.fHeight, rowBytes);
+#else
+ sk_memset_rect32(image, erase, glyph.fWidth, glyph.fHeight, rowBytes);
+#endif
- // since our matrix includes everything, we pass 1 for pointSize
- mFont = CTFontCreateCopyWithAttributes(ctFont, 1, &mTransform, NULL);
- mGlyphCount = (uint16_t) numGlyphs;
+ float subX = 0;
+ float subY = 0;
+ if (context.fDoSubPosition) {
+ subX = SkFixedToFloat(glyph.getSubXFixed());
+ subY = SkFixedToFloat(glyph.getSubYFixed());
+ }
+ if (context.fVertical) {
+ SkIPoint offset;
+ context.getVerticalOffset(glyphID, &offset);
+ subX += offset.fX;
+ subY += offset.fY;
+ }
+ CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX,
+ glyph.fTop + glyph.fHeight - subY,
+ &glyphID, 1);
+
+ SkASSERT(rowBytesPtr);
+ *rowBytesPtr = rowBytes;
+ return image;
}
-SkScalerContext_Mac::~SkScalerContext_Mac(void)
-{
+void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkIPoint* offset) const {
+ CGSize vertOffset;
+ CTFontGetVerticalTranslationsForGlyphs(fCTVerticalFont, &glyphID, &vertOffset, 1);
+ const SkPoint trans = {SkFloatToScalar(vertOffset.width),
+ SkFloatToScalar(vertOffset.height)};
+ SkPoint floatOffset;
+ fVerticalMatrix.mapPoints(&floatOffset, &trans, 1);
+ if (!isSnowLeopard()) {
+ // SnowLeopard fails to apply the font's matrix to the vertical metrics,
+ // but Lion and Leopard do. The unit matrix describes the font's matrix at
+ // point size 1. There may be some way to avoid mapping here by setting up
+ // fVerticalMatrix differently, but this works for now.
+ fUnitMatrix.mapPoints(&floatOffset, 1);
+ }
+ offset->fX = SkScalarRound(floatOffset.fX);
+ offset->fY = SkScalarRound(floatOffset.fY);
+}
+
+/* from http://developer.apple.com/fonts/TTRefMan/RM06/Chap6loca.html
+ * There are two versions of this table, the short and the long. The version
+ * used is specified in the Font Header ('head') table in the indexToLocFormat
+ * field. The choice of long or short offsets is dependent on the maximum
+ * possible offset distance.
+ *
+ * 'loca' short version: The actual local offset divided by 2 is stored.
+ * 'loca' long version: The actual local offset is stored.
+ *
+ * The result is a offset into a table of 2 byte (16 bit) entries.
+ */
+static uint32_t getLocaTableEntry(const uint16_t*& locaPtr, int locaFormat) {
+ uint32_t data = SkEndian_SwapBE16(*locaPtr++); // short
+ if (locaFormat) {
+ data = data << 15 | SkEndian_SwapBE16(*locaPtr++) >> 1; // long
+ }
+ return data;
+}
+
+// see http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html
+static uint16_t getNumLongMetrics(const uint16_t* hheaData) {
+ const int kNumOfLongHorMetrics = 17;
+ return SkEndian_SwapBE16(hheaData[kNumOfLongHorMetrics]);
+}
+
+// see http://developer.apple.com/fonts/TTRefMan/RM06/Chap6head.html
+static int getLocaFormat(const uint16_t* headData) {
+ const int kIndexToLocFormat = 25;
+ return SkEndian_SwapBE16(headData[kIndexToLocFormat]);
+}
- // Clean up
- CFSafeRelease(mColorSpaceGray);
- CFSafeRelease(mColorSpaceRGB);
- CFSafeRelease(mFont);
+uint16_t SkScalerContext_Mac::getAdjustStart() {
+ if (fAdjustStart) {
+ return fAdjustStart;
+ }
+ fAdjustStart = fGlyphCount; // fallback for all fonts
+ AutoCFDataRelease hheaRef(CGFontCopyTableForTag(fCGFont, 'hhea'));
+ const uint16_t* hheaData = hheaRef.getShortPtr();
+ if (hheaData) {
+ fAdjustStart = getNumLongMetrics(hheaData);
+ }
+ return fAdjustStart;
+}
+
+/*
+ * Lion has a bug in CTFontGetBoundingRectsForGlyphs which returns a bad value
+ * in theBounds.origin.x for fonts whose numOfLogHorMetrics is less than its
+ * glyph count. This workaround reads the glyph bounds from the font directly.
+ *
+ * The table is computed only if the font is a TrueType font, if the glyph
+ * value is >= fAdjustStart. (called only if fAdjustStart < fGlyphCount).
+ *
+ * TODO: A future optimization will compute fAdjustBad once per CGFont, and
+ * compute fAdjustBadMatrix once per font context.
+ */
+bool SkScalerContext_Mac::generateBBoxes() {
+ if (fGeneratedBBoxes) {
+ return NULL != fAdjustBad;
+ }
+ fGeneratedBBoxes = true;
+ AutoCFDataRelease headRef(CGFontCopyTableForTag(fCGFont, 'head'));
+ const uint16_t* headData = headRef.getShortPtr();
+ if (!headData) {
+ return false;
+ }
+ AutoCFDataRelease locaRef(CGFontCopyTableForTag(fCGFont, 'loca'));
+ const uint16_t* locaData = locaRef.getShortPtr();
+ if (!locaData) {
+ return false;
+ }
+ AutoCFDataRelease glyfRef(CGFontCopyTableForTag(fCGFont, 'glyf'));
+ const uint16_t* glyfData = glyfRef.getShortPtr();
+ if (!glyfData) {
+ return false;
+ }
+ CFIndex entries = fGlyphCount - fAdjustStart;
+ fAdjustBad = new GlyphRect[entries];
+ int locaFormat = getLocaFormat(headData);
+ const uint16_t* locaPtr = &locaData[fAdjustStart << locaFormat];
+ uint32_t last = getLocaTableEntry(locaPtr, locaFormat);
+ for (CFIndex index = 0; index < entries; ++index) {
+ uint32_t offset = getLocaTableEntry(locaPtr, locaFormat);
+ GlyphRect& rect = fAdjustBad[index];
+ if (offset != last) {
+ rect.fMinX = SkEndian_SwapBE16(glyfData[last + 1]);
+ rect.fMinY = SkEndian_SwapBE16(glyfData[last + 2]);
+ rect.fMaxX = SkEndian_SwapBE16(glyfData[last + 3]);
+ rect.fMaxY = SkEndian_SwapBE16(glyfData[last + 4]);
+ } else {
+ sk_bzero(&rect, sizeof(GlyphRect));
+ }
+ last = offset;
+ }
+ fAdjustBadMatrix = fMatrix;
+ flip(&fAdjustBadMatrix);
+ SkScalar fontScale = getFontScale(fCGFont);
+ fAdjustBadMatrix.preScale(fontScale, fontScale);
+ return true;
}
unsigned SkScalerContext_Mac::generateGlyphCount(void)
{
- return(mGlyphCount);
+ return(fGlyphCount);
}
uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni)
@@ -343,59 +929,166 @@ uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni)
// Get the glyph
theChar = (UniChar) uni;
- if (!CTFontGetGlyphsForCharacters(mFont, &theChar, &cgGlyph, 1))
+ if (!CTFontGetGlyphsForCharacters(fCTFont, &theChar, &cgGlyph, 1))
cgGlyph = 0;
return(cgGlyph);
}
-void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph)
-{
+void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) {
this->generateMetrics(glyph);
}
-void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph)
-{ CGSize theAdvance;
+void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
+ CGSize theAdvance;
CGRect theBounds;
CGGlyph cgGlyph;
-
-
// Get the state we need
cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount);
- CTFontGetBoundingRectsForGlyphs(mFont, kCTFontDefaultOrientation, &cgGlyph, &theBounds, 1);
- CTFontGetAdvancesForGlyphs( mFont, kCTFontDefaultOrientation, &cgGlyph, &theAdvance, 1);
-
+ if (fVertical) {
+ if (!isSnowLeopard()) {
+ // Lion and Leopard respect the vertical font metrics.
+ CTFontGetBoundingRectsForGlyphs(fCTVerticalFont,
+ kCTFontVerticalOrientation,
+ &cgGlyph, &theBounds, 1);
+ } else {
+ // Snow Leopard and earlier respect the vertical font metrics for
+ // advances, but not bounds, so use the default box and adjust it below.
+ CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontDefaultOrientation,
+ &cgGlyph, &theBounds, 1);
+ }
+ CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation,
+ &cgGlyph, &theAdvance, 1);
+ } else {
+ CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontDefaultOrientation,
+ &cgGlyph, &theBounds, 1);
+ CTFontGetAdvancesForGlyphs(fCTFont, kCTFontDefaultOrientation,
+ &cgGlyph, &theAdvance, 1);
+ }
+ // BUG?
+ // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when
+ // it should be empty. So, if we see a zero-advance, we check if it has an
+ // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance
+ // is rare, so we won't incur a big performance cost for this extra check.
+ if (0 == theAdvance.width && 0 == theAdvance.height) {
+ CGPathRef path = CTFontCreatePathForGlyph(fCTFont, cgGlyph, NULL);
+ if (NULL == path || CGPathIsEmpty(path)) {
+ theBounds = CGRectMake(0, 0, 0, 0);
+ }
+ if (path) {
+ CGPathRelease(path);
+ }
+ }
+
+ glyph->zeroMetrics();
+ glyph->fAdvanceX = SkFloatToFixed(theAdvance.width);
+ glyph->fAdvanceY = -SkFloatToFixed(theAdvance.height);
+ if (CGRectIsEmpty_inline(theBounds)) {
+ return;
+ }
+
+ if (isLeopard() && !fVertical) {
+ // Leopard does not consider the matrix skew in its bounds.
+ // Run the bounding rectangle through the skew matrix to determine
+ // the true bounds. However, this doesn't work if the font is vertical.
+ // FIXME (Leopard): If the font has synthetic italic (e.g., matrix skew)
+ // and the font is vertical, the bounds need to be recomputed.
+ SkRect glyphBounds = SkRect::MakeXYWH(
+ theBounds.origin.x, theBounds.origin.y,
+ theBounds.size.width, theBounds.size.height);
+ fUnitMatrix.mapRect(&glyphBounds);
+ theBounds.origin.x = glyphBounds.fLeft;
+ theBounds.origin.y = glyphBounds.fTop;
+ theBounds.size.width = glyphBounds.width();
+ theBounds.size.height = glyphBounds.height();
+ }
// Adjust the bounds
//
// CTFontGetBoundingRectsForGlyphs ignores the font transform, so we need
// to transform the bounding box ourselves.
//
// The bounds are also expanded by 1 pixel, to give CG room for anti-aliasing.
- theBounds = CGRectInset(theBounds, -1, -1);
-
-
+ CGRectInset_inline(&theBounds, -1, -1);
// Get the metrics
- glyph->zeroMetrics();
- glyph->fAdvanceX = SkFloatToFixed(theAdvance.width);
- glyph->fAdvanceY = -SkFloatToFixed(theAdvance.height);
- glyph->fWidth = sk_float_round2int(theBounds.size.width);
- glyph->fHeight = sk_float_round2int(theBounds.size.height);
- glyph->fTop = -sk_float_round2int(CGRectGetMaxY(theBounds));
- glyph->fLeft = sk_float_round2int(CGRectGetMinX(theBounds));
+ bool lionAdjustedMetrics = false;
+ if (isLion()) {
+ if (cgGlyph < fGlyphCount && cgGlyph >= getAdjustStart()
+ && generateBBoxes()) {
+ lionAdjustedMetrics = true;
+ SkRect adjust;
+ const GlyphRect& gRect = fAdjustBad[cgGlyph - fAdjustStart];
+ adjust.set(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect.fMaxY);
+ fAdjustBadMatrix.mapRect(&adjust);
+ theBounds.origin.x = SkScalarToFloat(adjust.fLeft) - 1;
+ theBounds.origin.y = SkScalarToFloat(adjust.fTop) - 1;
+ }
+ // Lion returns fractions in the bounds
+ glyph->fWidth = sk_float_ceil2int(theBounds.size.width);
+ glyph->fHeight = sk_float_ceil2int(theBounds.size.height);
+ } else {
+ glyph->fWidth = sk_float_round2int(theBounds.size.width);
+ glyph->fHeight = sk_float_round2int(theBounds.size.height);
+ }
+ glyph->fTop = -sk_float_round2int(CGRectGetMaxY_inline(theBounds));
+ glyph->fLeft = sk_float_round2int(CGRectGetMinX_inline(theBounds));
+ SkIPoint offset;
+ if (fVertical && (isSnowLeopard() || lionAdjustedMetrics)) {
+ // SnowLeopard doesn't respect vertical metrics, so compute them manually.
+ // Also compute them for Lion when the metrics were computed by hand.
+ getVerticalOffset(cgGlyph, &offset);
+ glyph->fLeft += offset.fX;
+ glyph->fTop += offset.fY;
+ }
}
#include "SkColorPriv.h"
-static void bytes_to_bits(uint8_t dst[], const uint8_t src[], int count) {
+static void build_power_table(uint8_t table[], float ee) {
+ for (int i = 0; i < 256; i++) {
+ float x = i / 255.f;
+ x = powf(x, ee);
+ int xx = SkScalarRound(SkFloatToScalar(x * 255));
+ table[i] = SkToU8(xx);
+ }
+}
+
+static const uint8_t* getInverseTable(bool isWhite) {
+ static uint8_t gWhiteTable[256];
+ static uint8_t gTable[256];
+ static bool gInited;
+ if (!gInited) {
+ build_power_table(gWhiteTable, 1.5f);
+ build_power_table(gTable, 2.2f);
+ gInited = true;
+ }
+ return isWhite ? gWhiteTable : gTable;
+}
+
+static void invertGammaMask(bool isWhite, CGRGBPixel rgb[], int width,
+ int height, size_t rb) {
+ const uint8_t* table = getInverseTable(isWhite);
+ for (int y = 0; y < height; ++y) {
+ for (int x = 0; x < width; ++x) {
+ uint32_t c = rgb[x];
+ int r = (c >> 16) & 0xFF;
+ int g = (c >> 8) & 0xFF;
+ int b = (c >> 0) & 0xFF;
+ rgb[x] = (table[r] << 16) | (table[g] << 8) | table[b];
+ }
+ rgb = (CGRGBPixel*)((char*)rgb + rb);
+ }
+}
+
+static void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) {
while (count > 0) {
uint8_t mask = 0;
for (int i = 7; i >= 0; --i) {
- mask |= (*src++ >> 7) << i;
+ mask |= (CGRGBPixel_getAlpha(*src++) >> 7) << i;
if (0 == --count) {
break;
}
@@ -426,151 +1119,189 @@ static inline int g32_to_16(int x) { return round8to6(x); }
static inline int b32_to_16(int x) { return round8to5(x); }
#endif
-static inline uint16_t rgb_to_lcd16(uint32_t rgb) {
+static inline uint16_t rgb_to_lcd16(CGRGBPixel rgb) {
int r = (rgb >> 16) & 0xFF;
int g = (rgb >> 8) & 0xFF;
int b = (rgb >> 0) & 0xFF;
- // invert, since we draw black-on-white, but we want the original
- // src mask values.
- r = 255 - r;
- g = 255 - g;
- b = 255 - b;
-
return SkPackRGB16(r32_to_16(r), g32_to_16(g), b32_to_16(b));
}
-#define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
-#define BITMAP_INFO_GRAY (kCGImageAlphaNone)
-
-void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
- CGContextRef cgContext;
- CGGlyph cgGlyph;
- CGFontRef cgFont;
+static inline uint32_t rgb_to_lcd32(CGRGBPixel rgb) {
+ int r = (rgb >> 16) & 0xFF;
+ int g = (rgb >> 8) & 0xFF;
+ int b = (rgb >> 0) & 0xFF;
- // Get the state we need
- sk_bzero(glyph.fImage, glyph.fHeight * glyph.rowBytes());
+ return SkPackARGB32(0xFF, r, g, b);
+}
- cgGlyph = (CGGlyph) glyph.getGlyphID(fBaseGlyphCount);
- cgFont = CTFontCopyGraphicsFont(mFont, NULL);
+#define BLACK_LUMINANCE_LIMIT 0x40
+#define WHITE_LUMINANCE_LIMIT 0xA0
- SkAutoSMalloc<1024> storage;
+void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
+ CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID(fBaseGlyphCount);
- CGColorSpaceRef colorspace = mColorSpaceGray;
- uint32_t info = BITMAP_INFO_GRAY;
- void* image = glyph.fImage;
- size_t rowBytes = glyph.rowBytes();
- float grayColor = 1; // white
- bool doAA = true;
+ bool fgColorIsWhite = true;
+ bool isWhite = fRec.getLuminanceByte() >= WHITE_LUMINANCE_LIMIT;
+ bool isBlack = fRec.getLuminanceByte() <= BLACK_LUMINANCE_LIMIT;
+ uint32_t xorMask;
+ bool invertGamma = false;
/* For LCD16, we first create a temp offscreen cg-context in 32bit,
* erase to white, and then draw a black glyph into it. Then we can
* extract the r,g,b values, invert-them, and now we have the original
* src mask components, which we pack into our 16bit mask.
*/
- if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
- colorspace = mColorSpaceRGB;
- info = BITMAP_INFO_RGB;
- // need tmp storage for 32bit RGB offscreen
- rowBytes = glyph.fWidth << 2;
- size_t size = glyph.fHeight * rowBytes;
- image = storage.realloc(size);
- // we draw black-on-white (and invert in rgb_to_lcd16)
- sk_memset32((uint32_t*)image, 0xFFFFFFFF, size >> 2);
- grayColor = 0; // black
- } else if (SkMask::kBW_Format == glyph.fMaskFormat) {
- rowBytes = SkAlign4(glyph.fWidth);
- size_t size = glyph.fHeight * rowBytes;
- image = storage.realloc(size);
- sk_bzero(image, size);
- doAA = false;
- }
-
- cgContext = CGBitmapContextCreate(image, glyph.fWidth, glyph.fHeight, 8,
- rowBytes, colorspace, info);
+ if (isLCDFormat(glyph.fMaskFormat)) {
+ if (isBlack) {
+ xorMask = ~0;
+ fgColorIsWhite = false;
+ } else { /* white or neutral */
+ xorMask = 0;
+ invertGamma = true;
+ }
+ }
+
+ size_t cgRowBytes;
+ CGRGBPixel* cgPixels = fOffscreen.getCG(*this, glyph, fgColorIsWhite, cgGlyph,
+ &cgRowBytes);
// Draw the glyph
- if (cgFont != NULL && cgContext != NULL) {
-#ifdef WE_ARE_RUNNING_ON_10_6_OR_LATER
- CGContextSetAllowsFontSubpixelQuantization(cgContext, true);
- CGContextSetShouldSubpixelQuantizeFonts(cgContext, true);
-#endif
- CGContextSetShouldAntialias(cgContext, doAA);
- CGContextSetGrayFillColor( cgContext, grayColor, 1.0);
- CGContextSetTextDrawingMode(cgContext, kCGTextFill);
- CGContextSetFont( cgContext, cgFont);
- CGContextSetFontSize( cgContext, 1); // cgFont know's its size
- CGContextSetTextMatrix( cgContext, mTransform);
- CGContextShowGlyphsAtPoint( cgContext, -glyph.fLeft, glyph.fTop + glyph.fHeight, &cgGlyph, 1);
-
- if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
- // downsample from rgba to rgb565
- int width = glyph.fWidth;
- const uint32_t* src = (const uint32_t*)image;
- uint16_t* dst = (uint16_t*)glyph.fImage;
- size_t dstRB = glyph.rowBytes();
- for (int y = 0; y < glyph.fHeight; y++) {
- for (int i = 0; i < width; i++) {
- dst[i] = rgb_to_lcd16(src[i]);
+ if (cgPixels != NULL) {
+
+ if (invertGamma) {
+ invertGammaMask(isWhite, (uint32_t*)cgPixels,
+ glyph.fWidth, glyph.fHeight, cgRowBytes);
+ }
+
+ int width = glyph.fWidth;
+ switch (glyph.fMaskFormat) {
+ case SkMask::kLCD32_Format: {
+ uint32_t* dst = (uint32_t*)glyph.fImage;
+ size_t dstRB = glyph.rowBytes();
+ for (int y = 0; y < glyph.fHeight; y++) {
+ for (int i = 0; i < width; i++) {
+ dst[i] = rgb_to_lcd32(cgPixels[i] ^ xorMask);
+ }
+ cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
+ dst = (uint32_t*)((char*)dst + dstRB);
}
- src = (const uint32_t*)((const char*)src + rowBytes);
- dst = (uint16_t*)((char*)dst + dstRB);
- }
- } else if (SkMask::kBW_Format == glyph.fMaskFormat) {
- // downsample from A8 to A1
- const uint8_t* src = (const uint8_t*)image;
- uint8_t* dst = (uint8_t*)glyph.fImage;
- size_t dstRB = glyph.rowBytes();
- for (int y = 0; y < glyph.fHeight; y++) {
- bytes_to_bits(dst, src, glyph.fWidth);
- src += rowBytes;
- dst += dstRB;
- }
+ } break;
+ case SkMask::kLCD16_Format: {
+ // downsample from rgba to rgb565
+ uint16_t* dst = (uint16_t*)glyph.fImage;
+ size_t dstRB = glyph.rowBytes();
+ for (int y = 0; y < glyph.fHeight; y++) {
+ for (int i = 0; i < width; i++) {
+ dst[i] = rgb_to_lcd16(cgPixels[i] ^ xorMask);
+ }
+ cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
+ dst = (uint16_t*)((char*)dst + dstRB);
+ }
+ } break;
+ case SkMask::kA8_Format: {
+ uint8_t* dst = (uint8_t*)glyph.fImage;
+ size_t dstRB = glyph.rowBytes();
+ for (int y = 0; y < glyph.fHeight; y++) {
+ for (int i = 0; i < width; ++i) {
+ dst[i] = CGRGBPixel_getAlpha(cgPixels[i]);
+ }
+ cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
+ dst += dstRB;
+ }
+ } break;
+ case SkMask::kBW_Format: {
+ uint8_t* dst = (uint8_t*)glyph.fImage;
+ size_t dstRB = glyph.rowBytes();
+ for (int y = 0; y < glyph.fHeight; y++) {
+ cgpixels_to_bits(dst, cgPixels, width);
+ cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes);
+ dst += dstRB;
+ }
+ } break;
+ default:
+ SkDEBUGFAIL("unexpected mask format");
+ break;
}
}
-
- // Clean up
- CFSafeRelease(cgFont);
- CFSafeRelease(cgContext);
}
+/*
+ * Our subpixel resolution is only 2 bits in each direction, so a scale of 4
+ * seems sufficient, and possibly even correct, to allow the hinted outline
+ * to be subpixel positioned.
+ */
+#define kScaleForSubPixelPositionHinting 4
+
void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path) {
+ CTFontRef font = fCTFont;
+ float scaleX = 1;
+ float scaleY = 1;
+
+ /*
+ * For subpixel positioning, we want to return an unhinted outline, so it
+ * can be positioned nicely at fractional offsets. However, we special-case
+ * if the baseline of the (horizontal) text is axis-aligned. In those cases
+ * we want to retain hinting in the direction orthogonal to the baseline.
+ * e.g. for horizontal baseline, we want to retain hinting in Y.
+ * The way we remove hinting is to scale the font by some value (4) in that
+ * direction, ask for the path, and then scale the path back down.
+ */
+ if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
+ SkMatrix m;
+ fRec.getSingleMatrix(&m);
+
+ // start out by assuming that we want no hining in X and Y
+ scaleX = scaleY = kScaleForSubPixelPositionHinting;
+ // now see if we need to restore hinting for axis-aligned baselines
+ switch (SkComputeAxisAlignmentForHText(m)) {
+ case kX_SkAxisAlignment:
+ scaleY = 1; // want hinting in the Y direction
+ break;
+ case kY_SkAxisAlignment:
+ scaleX = 1; // want hinting in the X direction
+ break;
+ default:
+ break;
+ }
+
+ CGAffineTransform xform = MatrixToCGAffineTransform(m, scaleX, scaleY);
+ // need to release font when we're done
+ font = CTFontCreateCopyWithAttributes(fCTFont, 1, &xform, NULL);
+ }
+
CGGlyph cgGlyph = (CGGlyph)glyph.getGlyphID(fBaseGlyphCount);
- CGPathRef cgPath = CTFontCreatePathForGlyph(mFont, cgGlyph, NULL);
+ CGPathRef cgPath = CTFontCreatePathForGlyph(font, cgGlyph, NULL);
path->reset();
if (cgPath != NULL) {
CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement);
CFRelease(cgPath);
}
+
+ if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
+ SkMatrix m;
+ m.setScale(SkFloatToScalar(1 / scaleX), SkFloatToScalar(1 / scaleY));
+ path->transform(m);
+ // balance the call to CTFontCreateCopyWithAttributes
+ CFRelease(font);
+ }
}
void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx,
SkPaint::FontMetrics* my) {
- CGRect theBounds = CTFontGetBoundingBox(mFont);
-
- SkPaint::FontMetrics theMetrics;
- theMetrics.fTop = -CGRectGetMaxY(theBounds);
- theMetrics.fAscent = -CTFontGetAscent(mFont);
- theMetrics.fDescent = CTFontGetDescent(mFont);
- theMetrics.fBottom = -CGRectGetMinY(theBounds);
- theMetrics.fLeading = CTFontGetLeading(mFont);
- theMetrics.fAvgCharWidth = CGRectGetWidth(theBounds);
- theMetrics.fXMin = CGRectGetMinX(theBounds);
- theMetrics.fXMax = CGRectGetMaxX(theBounds);
- theMetrics.fXHeight = CTFontGetXHeight(mFont);
-
-#if 0
- SkASSERT(theMetrics.fTop <= 0.0);
- SkASSERT(theMetrics.fAscent <= 0.0);
- SkASSERT(theMetrics.fDescent >= 0.0);
- SkASSERT(theMetrics.fBottom >= 0.0);
- SkASSERT(theMetrics.fLeading >= 0.0);
- SkASSERT(theMetrics.fAvgCharWidth >= 0.0);
- SkASSERT(theMetrics.fXMin <= 0.0);
- SkASSERT(theMetrics.fXMax > 0.0);
- SkASSERT(theMetrics.fXHeight >= 0.0);
-#endif
+ CGRect theBounds = CTFontGetBoundingBox(fCTFont);
+
+ SkPaint::FontMetrics theMetrics;
+ theMetrics.fTop = CGToScalar(-CGRectGetMaxY_inline(theBounds));
+ theMetrics.fAscent = CGToScalar(-CTFontGetAscent(fCTFont));
+ theMetrics.fDescent = CGToScalar( CTFontGetDescent(fCTFont));
+ theMetrics.fBottom = CGToScalar(-CGRectGetMinY_inline(theBounds));
+ theMetrics.fLeading = CGToScalar( CTFontGetLeading(fCTFont));
+ theMetrics.fAvgCharWidth = CGToScalar( CGRectGetWidth_inline(theBounds));
+ theMetrics.fXMin = CGToScalar( CGRectGetMinX_inline(theBounds));
+ theMetrics.fXMax = CGToScalar( CGRectGetMaxX_inline(theBounds));
+ theMetrics.fXHeight = CGToScalar( CTFontGetXHeight(fCTFont));
if (mx != NULL) {
*mx = theMetrics;
@@ -610,7 +1341,7 @@ void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element
break;
default:
- SkASSERT("Unknown path element!");
+ SkDEBUGFAIL("Unknown path element!");
break;
}
}
@@ -620,13 +1351,13 @@ void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element
SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream)
{
-// SkASSERT(!"SkFontHost::CreateTypefaceFromStream unimplemented");
+// SkDEBUGFAIL("SkFontHost::CreateTypefaceFromStream unimplemented");
return SkFontHost::CreateTypeface(NULL, NULL, NULL, NULL, SkTypeface::kNormal);
}
SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[])
{
-// SkASSERT(!"SkFontHost::CreateTypefaceFromFile unimplemented");
+// SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented");
return SkFontHost::CreateTypeface(NULL, NULL, NULL, NULL, SkTypeface::kNormal);
}
@@ -636,6 +1367,9 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[])
static void populate_glyph_to_unicode(CTFontRef ctFont,
const unsigned glyphCount, SkTDArray<SkUnichar>* glyphToUnicode) {
CFCharacterSetRef charSet = CTFontCopyCharacterSet(ctFont);
+ if (!charSet) {
+ return;
+ }
CFDataRef bitmap = CFCharacterSetCreateBitmapRepresentation(
kCFAllocatorDefault, charSet);
if (!bitmap) {
@@ -680,22 +1414,30 @@ static bool getWidthAdvance(CTFontRef ctFont, int gId, int16_t* data) {
CGGlyph glyph = gId;
CTFontGetAdvancesForGlyphs(ctFont, kCTFontHorizontalOrientation, &glyph,
&advance, 1);
- *data = advance.width;
+ *data = sk_float_round2int(advance.width);
return true;
}
// static
SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
uint32_t fontID,
- SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo) {
+ SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
+ const uint32_t* glyphIDs,
+ uint32_t glyphIDsCount) {
CTFontRef ctFont = GetFontRefFromFontID(fontID);
+ ctFont = CTFontCreateCopyWithAttributes(ctFont, CTFontGetUnitsPerEm(ctFont),
+ NULL, NULL);
SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics;
CFStringRef fontName = CTFontCopyPostScriptName(ctFont);
- int length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(fontName),
- kCFStringEncodingUTF8);
- info->fFontName.resize(length);
+ // Reserve enough room for the worst-case string,
+ // plus 1 byte for the trailing null.
+ int length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(
+ fontName), kCFStringEncodingUTF8) + 1;
+ info->fFontName.resize(length);
CFStringGetCString(fontName, info->fFontName.writable_str(), length,
kCFStringEncodingUTF8);
+ // Resize to the actual UTF-8 length used, stripping the null character.
+ info->fFontName.resize(strlen(info->fFontName.c_str()));
info->fMultiMaster = false;
CFIndex glyphCount = CTFontGetGlyphCount(ctFont);
info->fLastGlyphID = SkToU16(glyphCount - 1);
@@ -744,7 +1486,7 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
CGGlyph glyphs[count];
CGRect boundingRects[count];
if (CTFontGetGlyphsForCharacters(ctFont, stem_chars, glyphs, count)) {
- CTFontGetBoundingRectsForGlyphs(ctFont, kCTFontHorizontalOrientation,
+ CTFontGetBoundingRectsForGlyphs(ctFont, kCTFontHorizontalOrientation,
glyphs, boundingRects, count);
for (size_t i = 0; i < count; i++) {
int16_t width = boundingRects[i].size.width;
@@ -760,10 +1502,22 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
} else if (perGlyphInfo &
SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
- info->fGlyphWidths.reset(
- getAdvanceData(ctFont, glyphCount, &getWidthAdvance));
+ if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
+ skia_advanced_typeface_metrics_utils::appendRange(&info->fGlyphWidths, 0);
+ info->fGlyphWidths->fAdvance.append(1, &min_width);
+ skia_advanced_typeface_metrics_utils::finishRange(info->fGlyphWidths.get(), 0,
+ SkAdvancedTypefaceMetrics::WidthRange::kDefault);
+ } else {
+ info->fGlyphWidths.reset(
+ skia_advanced_typeface_metrics_utils::getAdvanceData(ctFont,
+ glyphCount,
+ glyphIDs,
+ glyphIDsCount,
+ &getWidthAdvance));
+ }
}
+ CFSafeRelease(ctFont);
return info;
}
@@ -788,9 +1542,9 @@ struct TableEntry {
uint32_t fLength;
};
-static uint32 CalcTableCheckSum(uint32 *table, uint32 numberOfBytesInTable) {
- uint32 sum = 0;
- uint32 nLongs = (numberOfBytesInTable + 3) / 4;
+static uint32_t CalcTableCheckSum(uint32_t *table, uint32_t numberOfBytesInTable) {
+ uint32_t sum = 0;
+ uint32_t nLongs = (numberOfBytesInTable + 3) / 4;
while (nLongs-- > 0) {
sum += SkEndian_SwapBE32(*table++);
@@ -847,7 +1601,7 @@ SkStream* SkFontHost::OpenStream(SkFontID uniqueID) {
GetTableData(uniqueID, tableTags[index], 0, tableSize, dataPtr);
entry->fTag = SkEndian_SwapBE32(tableTags[index]);
entry->fCheckSum = SkEndian_SwapBE32(CalcTableCheckSum(
- (uint32*)dataPtr, tableSize));
+ (uint32_t*)dataPtr, tableSize));
entry->fOffset = SkEndian_SwapBE32(dataPtr - dataStart);
entry->fLength = SkEndian_SwapBE32(tableSize);
dataPtr += (tableSize + 3) & ~3;
@@ -859,7 +1613,7 @@ SkStream* SkFontHost::OpenStream(SkFontID uniqueID) {
size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
int32_t* index) {
- SkASSERT(!"SkFontHost::GetFileName unimplemented");
+ SkDEBUGFAIL("SkFontHost::GetFileName unimplemented");
return(0);
}
@@ -896,7 +1650,36 @@ SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
return nextFontID;
}
+static bool supports_LCD() {
+ static int gSupportsLCD = -1;
+ if (gSupportsLCD >= 0) {
+ return (bool) gSupportsLCD;
+ }
+ int rgb = 0;
+ CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
+ CGContextRef cgContext = CGBitmapContextCreate(&rgb, 1, 1, 8, 4, colorspace,
+ BITMAP_INFO_RGB);
+ CGContextSelectFont(cgContext, "Helvetica", 16, kCGEncodingMacRoman);
+ CGContextSetShouldSmoothFonts(cgContext, true);
+ CGContextSetShouldAntialias(cgContext, true);
+ CGContextSetTextDrawingMode(cgContext, kCGTextFill);
+ CGContextSetGrayFillColor( cgContext, 1, 1.0);
+ CGContextShowTextAtPoint(cgContext, -1, 0, "|", 1);
+ CFSafeRelease(colorspace);
+ CFSafeRelease(cgContext);
+ int r = (rgb >> 16) & 0xFF;
+ int g = (rgb >> 8) & 0xFF;
+ int b = (rgb >> 0) & 0xFF;
+ gSupportsLCD = r != g || r != b;
+ return (bool) gSupportsLCD;
+}
+
void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
+ unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
+ SkScalerContext::kAutohinting_Flag;
+
+ rec->fFlags &= ~flagsWeDontSupport;
+
// we only support 2 levels of hinting
SkPaint::Hinting h = rec->getHinting();
if (SkPaint::kSlight_Hinting == h) {
@@ -906,28 +1689,29 @@ void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
}
rec->setHinting(h);
- // we don't support LCD text
- if (SkMask::FormatIsLCD((SkMask::Format)rec->fMaskFormat)) {
- rec->fMaskFormat = SkMask::kA8_Format;
+ // for compatibility at the moment, discretize luminance to 3 settings
+ // black, white, gray. This helps with fontcache utilization, since we
+ // won't create multiple entries that in the end map to the same results.
+ {
+ unsigned lum = rec->getLuminanceByte();
+ if (lum <= BLACK_LUMINANCE_LIMIT) {
+ lum = 0;
+ } else if (lum >= WHITE_LUMINANCE_LIMIT) {
+ lum = SkScalerContext::kLuminance_Max;
+ } else {
+ lum = SkScalerContext::kLuminance_Max >> 1;
+ }
+ rec->setLuminanceBits(lum);
}
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
- if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET) {
- return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
+
+ if (SkMask::kLCD16_Format == rec->fMaskFormat
+ || SkMask::kLCD32_Format == rec->fMaskFormat) {
+ if (supports_LCD()) {
+ rec->fMaskFormat = SkMask::kLCD32_Format;
+ } else {
+ rec->fMaskFormat = SkMask::kA8_Format;
+ }
}
- return 0;
-}
-
-int SkFontHost::ComputeGammaFlag(const SkPaint& paint) {
- return 0;
-}
-
-void SkFontHost::GetGammaTables(const uint8_t* tables[2]) {
- tables[0] = NULL; // black gamma (e.g. exp=1.4)
- tables[1] = NULL; // white gamma (e.g. exp= 1/1.4)
}
///////////////////////////////////////////////////////////////////////////
@@ -1027,7 +1811,3 @@ size_t SkFontHost::GetTableData(SkFontID fontID, SkFontTableTag tag,
memcpy(data, CFDataGetBytePtr(cfData) + offset, length);
return(length);
}
-
-
-
-
diff --git a/src/ports/SkFontHost_none.cpp b/src/ports/SkFontHost_none.cpp
index 0593dd5..99df213 100644
--- a/src/ports/SkFontHost_none.cpp
+++ b/src/ports/SkFontHost_none.cpp
@@ -1,17 +1,11 @@
-/* Copyright 2006-2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2008 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkFontHost.h"
@@ -19,17 +13,17 @@ SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
const char famillyName[],
const void* data, size_t bytelength,
SkTypeface::Style style) {
- SkASSERT(!"SkFontHost::FindTypeface unimplemented");
+ SkDEBUGFAIL("SkFontHost::FindTypeface unimplemented");
return NULL;
}
SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream*) {
- SkASSERT(!"SkFontHost::CreateTypeface unimplemented");
+ SkDEBUGFAIL("SkFontHost::CreateTypeface unimplemented");
return NULL;
}
SkTypeface* SkFontHost::CreateTypefaceFromFile(char const*) {
- SkASSERT(!"SkFontHost::CreateTypefaceFromFile unimplemented");
+ SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented");
return NULL;
}
@@ -37,7 +31,7 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(char const*) {
SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
uint32_t fontID,
SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo) {
- SkASSERT(!"SkFontHost::GetAdvancedTypefaceMetrics unimplemented");
+ SkDEBUGFAIL("SkFontHost::GetAdvancedTypefaceMetrics unimplemented");
return NULL;
}
@@ -47,12 +41,12 @@ void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
///////////////////////////////////////////////////////////////////////////////
bool SkFontHost::ValidFontID(uint32_t uniqueID) {
- SkASSERT(!"SkFontHost::ResolveTypeface unimplemented");
+ SkDEBUGFAIL("SkFontHost::ResolveTypeface unimplemented");
return false;
}
SkStream* SkFontHost::OpenStream(uint32_t uniqueID) {
- SkASSERT(!"SkFontHost::OpenStream unimplemented");
+ SkDEBUGFAIL("SkFontHost::OpenStream unimplemented");
return NULL;
}
@@ -65,18 +59,18 @@ size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
///////////////////////////////////////////////////////////////////////////////
void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
- SkASSERT(!"SkFontHost::Serialize unimplemented");
+ SkDEBUGFAIL("SkFontHost::Serialize unimplemented");
}
SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
- SkASSERT(!"SkFontHost::Deserialize unimplemented");
+ SkDEBUGFAIL("SkFontHost::Deserialize unimplemented");
return NULL;
}
///////////////////////////////////////////////////////////////////////////////
SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
- SkASSERT(!"SkFontHost::CreateScalarContext unimplemented");
+ SkDEBUGFAIL("SkFontHost::CreateScalarContext unimplemented");
return NULL;
}
@@ -85,18 +79,3 @@ SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
}
-///////////////////////////////////////////////////////////////////////////////
-
-size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
- return 0; // nothing to do (change me if you want to limit the font cache)
-}
-
-int SkFontHost::ComputeGammaFlag(const SkPaint& paint) {
- return 0;
-}
-
-void SkFontHost::GetGammaTables(const uint8_t* tables[2]) {
- tables[0] = NULL; // black gamma (e.g. exp=1.4)
- tables[1] = NULL; // white gamma (e.g. exp= 1/1.4)
-}
-
diff --git a/src/ports/SkFontHost_sandbox_none.cpp b/src/ports/SkFontHost_sandbox_none.cpp
new file mode 100644
index 0000000..a52bbff
--- /dev/null
+++ b/src/ports/SkFontHost_sandbox_none.cpp
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkFontHost.h"
+#include "SkTypeface.h"
+
+//static
+void SkFontHost::EnsureTypefaceAccessible(const SkTypeface& typeface) {
+ //No sandbox, nothing to do.
+}
diff --git a/src/ports/SkFontHost_simple.cpp b/src/ports/SkFontHost_simple.cpp
index d63aec2..0624d35 100644
--- a/src/ports/SkFontHost_simple.cpp
+++ b/src/ports/SkFontHost_simple.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2011 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkFontHost.h"
#include "SkDescriptor.h"
#include "SkMMapStream.h"
@@ -24,8 +17,6 @@
#include "SkTSearch.h"
#include <stdio.h>
-#define FONT_CACHE_MEMORY_BUDGET (768 * 1024)
-
#ifdef SK_BUILD_FOR_MAC
#define SK_FONT_FILE_PREFIX "/Library/Fonts/"
#else
@@ -107,7 +98,7 @@ static SkTypeface* find_best_face(const FamilyRec* family,
}
}
// should never get here, since the faces list should not be empty
- SkASSERT(!"faces list is empty");
+ SkDEBUGFAIL("faces list is empty");
return NULL;
}
@@ -176,7 +167,7 @@ static void detach_and_delete_family(FamilyRec* family) {
prev = curr;
curr = next;
}
- SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
+ SkDEBUGFAIL("Yikes, couldn't find family in our list to remove/delete");
}
static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
@@ -594,7 +585,7 @@ SkStream* SkFontHost::OpenStream(uint32_t fontID) {
SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
uint32_t fontID,
SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo) {
- SkASSERT(!"SkFontHost::GetAdvancedTypefaceMetrics unimplemented");
+ SkDEBUGFAIL("SkFontHost::GetAdvancedTypefaceMetrics unimplemented");
return NULL;
}
#endif
@@ -660,12 +651,3 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
return face;
}
-///////////////////////////////////////////////////////////////////////////////
-
-size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
- if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
- return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
- else
- return 0; // nothing to do
-}
-
diff --git a/src/ports/SkFontHost_tables.cpp b/src/ports/SkFontHost_tables.cpp
index 5c6b1fc..9878119 100644
--- a/src/ports/SkFontHost_tables.cpp
+++ b/src/ports/SkFontHost_tables.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkEndian.h"
#include "SkFontHost.h"
#include "SkStream.h"
diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp
index 62b0a0c..9d98bcb 100755
--- a/src/ports/SkFontHost_win.cpp
+++ b/src/ports/SkFontHost_win.cpp
@@ -1,22 +1,14 @@
+
/*
- ** Copyright 2006, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
-#include "SkString.h"
-//#include "SkStream.h"
+#include "SkColorFilter.h"
+#include "SkString.h"
#include "SkEndian.h"
#include "SkFontHost.h"
#include "SkDescriptor.h"
@@ -30,21 +22,61 @@
#ifdef WIN32
#include "windows.h"
#include "tchar.h"
-#include "Usp10.h"
+#include "usp10.h"
+
+// always packed xxRRGGBB
+typedef uint32_t SkGdiRGB;
+
+template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) {
+ return (T*)((char*)ptr + byteOffset);
+}
+
+// define this in your Makefile or .gyp to enforce AA requests
+// which GDI ignores at small sizes. This flag guarantees AA
+// for rotated text, regardless of GDI's notions.
+//#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
// client3d has to undefine this for now
#define CAN_USE_LOGFONT_NAME
+static bool isLCD(const SkScalerContext::Rec& rec) {
+ return SkMask::kLCD16_Format == rec.fMaskFormat ||
+ SkMask::kLCD32_Format == rec.fMaskFormat;
+}
+
+static bool bothZero(SkScalar a, SkScalar b) {
+ return 0 == a && 0 == b;
+}
+
+// returns false if there is any non-90-rotation or skew
+static bool isAxisAligned(const SkScalerContext::Rec& rec) {
+ return 0 == rec.fPreSkewX &&
+ (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
+ bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
+}
+
+static bool needToRenderWithSkia(const SkScalerContext::Rec& rec) {
+#ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
+ // What we really want to catch is when GDI will ignore the AA request and give
+ // us BW instead. Smallish rotated text is one heuristic, so this code is just
+ // an approximation. We shouldn't need to do this for larger sizes, but at those
+ // sizes, the quality difference gets less and less between our general
+ // scanconverter and GDI's.
+ if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) {
+ return true;
+ }
+#endif
+ // false means allow GDI to generate the bits
+ return false;
+}
+
using namespace skia_advanced_typeface_metrics_utils;
static const uint16_t BUFFERSIZE = (16384 - 32);
static uint8_t glyphbuf[BUFFERSIZE];
-// Give 1MB font cache budget
-#define FONT_CACHE_MEMORY_BUDGET (1024 * 1024)
-
/**
- * Since LOGFONT wants its textsize as an int, and we support fractional sizes,
+ * Since LOGFONT wants its textsize as an int, and we support fractional sizes,
* and since we have a cache of LOGFONTs for our tyepfaces, we always set the
* lfHeight to a canonical size, and then we use the 2x2 matrix to achieve the
* actual requested size.
@@ -52,12 +84,13 @@ static uint8_t glyphbuf[BUFFERSIZE];
static const int gCanonicalTextSize = 64;
static void make_canonical(LOGFONT* lf) {
- lf->lfHeight = -gCanonicalTextSize;
+ lf->lfHeight = -gCanonicalTextSize;
lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
lf->lfCharSet = DEFAULT_CHARSET;
+// lf->lfClipPrecision = 64;
}
-static SkTypeface::Style getStyle(const LOGFONT& lf) {
+static SkTypeface::Style get_style(const LOGFONT& lf) {
unsigned style = 0;
if (lf.lfWeight >= FW_BOLD) {
style |= SkTypeface::kBold;
@@ -65,7 +98,7 @@ static SkTypeface::Style getStyle(const LOGFONT& lf) {
if (lf.lfItalic) {
style |= SkTypeface::kItalic;
}
- return (SkTypeface::Style)style;
+ return static_cast<SkTypeface::Style>(style);
}
static void setStyle(LOGFONT* lf, SkTypeface::Style style) {
@@ -89,7 +122,7 @@ static unsigned calculateGlyphCount(HDC hdc) {
if (GetFontData(hdc, maxpTag, 4, &glyphs, sizeof(glyphs)) != GDI_ERROR) {
return SkEndian_SwapBE16(glyphs);
}
-
+
// Binary search for glyph count.
static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
int32_t max = SK_MaxU16 + 1;
@@ -108,16 +141,6 @@ static unsigned calculateGlyphCount(HDC hdc) {
return min;
}
-static SkTypeface::Style GetFontStyle(const LOGFONT& lf) {
- int style = SkTypeface::kNormal;
- if (lf.lfWeight == FW_SEMIBOLD || lf.lfWeight == FW_DEMIBOLD || lf.lfWeight == FW_BOLD)
- style |= SkTypeface::kBold;
- if (lf.lfItalic)
- style |= SkTypeface::kItalic;
-
- return (SkTypeface::Style)style;
-}
-
class LogFontTypeface : public SkTypeface {
public:
LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf) :
@@ -126,7 +149,7 @@ public:
LOGFONT fLogFont;
static LogFontTypeface* Create(const LOGFONT& lf) {
- SkTypeface::Style style = GetFontStyle(lf);
+ SkTypeface::Style style = get_style(lf);
SkFontID fontID = SkTypefaceCache::NewFontID();
return new LogFontTypeface(style, fontID, lf);
}
@@ -134,23 +157,6 @@ public:
static const LOGFONT& get_default_font() {
static LOGFONT gDefaultFont;
- // don't hardcode on Windows, Win2000, XP, Vista, and international all have different default
- // and the user could change too
-
-
-// lfMessageFont is garbage on my XP, so skip for now
-#if 0
- if (gDefaultFont.lfFaceName[0] != 0) {
- return gDefaultFont;
- }
-
- NONCLIENTMETRICS ncm;
- ncm.cbSize = sizeof(NONCLIENTMETRICS);
- SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
-
- //memcpy(&gDefaultFont, &(ncm.lfMessageFont), sizeof(LOGFONT));
-#endif
-
return gDefaultFont;
}
@@ -158,7 +164,7 @@ static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, vo
LogFontTypeface* lface = reinterpret_cast<LogFontTypeface*>(face);
const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
- return getStyle(lface->fLogFont) == requestedStyle &&
+ return get_style(lface->fLogFont) == requestedStyle &&
!memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
}
@@ -174,11 +180,22 @@ SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
face->ref();
} else {
face = LogFontTypeface::Create(lf);
- SkTypefaceCache::Add(face, getStyle(lf));
+ SkTypefaceCache::Add(face, get_style(lf));
}
return face;
}
+/**
+ * This guy is public
+ */
+void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) {
+ if (NULL == face) {
+ *lf = get_default_font();
+ } else {
+ *lf = ((const LogFontTypeface*)face)->fLogFont;
+ }
+}
+
SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
// Zero means that we don't have any fallback fonts for this fontID.
// This function is implemented on Android, but doesn't have much
@@ -186,6 +203,11 @@ SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
return 0;
}
+static void ensure_typeface_accessible(SkFontID fontID) {
+ LogFontTypeface* face = (LogFontTypeface*)SkTypefaceCache::FindByID(fontID);
+ SkFontHost::EnsureTypefaceAccessible(*face);
+}
+
static void GetLogFontByID(SkFontID fontID, LOGFONT* lf) {
LogFontTypeface* face = (LogFontTypeface*)SkTypefaceCache::FindByID(fontID);
if (face) {
@@ -247,7 +269,146 @@ static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
}
}
-//////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////
+
+static int alignTo32(int n) {
+ return (n + 31) & ~31;
+}
+
+struct MyBitmapInfo : public BITMAPINFO {
+ RGBQUAD fMoreSpaceForColors[1];
+};
+
+class HDCOffscreen {
+public:
+ HDCOffscreen() {
+ fFont = 0;
+ fDC = 0;
+ fBM = 0;
+ fBits = NULL;
+ fWidth = fHeight = 0;
+ fIsBW = false;
+ fColor = kInvalid_Color;
+ }
+
+ ~HDCOffscreen() {
+ if (fDC) {
+ DeleteDC(fDC);
+ }
+ if (fBM) {
+ DeleteObject(fBM);
+ }
+ }
+
+ void init(HFONT font, const XFORM& xform) {
+ fFont = font;
+ fXform = xform;
+ }
+
+ const void* draw(const SkGlyph&, bool isBW, SkGdiRGB fgColor,
+ size_t* srcRBPtr);
+
+private:
+ HDC fDC;
+ HBITMAP fBM;
+ HFONT fFont;
+ XFORM fXform;
+ void* fBits; // points into fBM
+ COLORREF fColor;
+ int fWidth;
+ int fHeight;
+ bool fIsBW;
+
+ enum {
+ // will always trigger us to reset the color, since we
+ // should only store 0 or 0x00FFFFFF or gray (0x007F7F7F)
+ kInvalid_Color = 12345
+ };
+};
+
+const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW,
+ SkGdiRGB fgColor, size_t* srcRBPtr) {
+ if (0 == fDC) {
+ fDC = CreateCompatibleDC(0);
+ if (0 == fDC) {
+ return NULL;
+ }
+ SetGraphicsMode(fDC, GM_ADVANCED);
+ SetBkMode(fDC, TRANSPARENT);
+ SetTextAlign(fDC, TA_LEFT | TA_BASELINE);
+ SelectObject(fDC, fFont);
+ fColor = kInvalid_Color;
+ }
+
+ if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) {
+ DeleteObject(fBM);
+ fBM = 0;
+ }
+ fIsBW = isBW;
+
+ COLORREF color = fgColor;
+ if (fIsBW) {
+ color = 0xFFFFFF;
+ }
+ if (fColor != color) {
+ fColor = color;
+ COLORREF prev = SetTextColor(fDC, color);
+ SkASSERT(prev != CLR_INVALID);
+ }
+
+ fWidth = SkMax32(fWidth, glyph.fWidth);
+ fHeight = SkMax32(fHeight, glyph.fHeight);
+
+ int biWidth = isBW ? alignTo32(fWidth) : fWidth;
+
+ if (0 == fBM) {
+ MyBitmapInfo info;
+ sk_bzero(&info, sizeof(info));
+ if (isBW) {
+ RGBQUAD blackQuad = { 0, 0, 0, 0 };
+ RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
+ info.bmiColors[0] = blackQuad;
+ info.bmiColors[1] = whiteQuad;
+ }
+ info.bmiHeader.biSize = sizeof(info.bmiHeader);
+ info.bmiHeader.biWidth = biWidth;
+ info.bmiHeader.biHeight = fHeight;
+ info.bmiHeader.biPlanes = 1;
+ info.bmiHeader.biBitCount = isBW ? 1 : 32;
+ info.bmiHeader.biCompression = BI_RGB;
+ if (isBW) {
+ info.bmiHeader.biClrUsed = 2;
+ }
+ fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0);
+ if (0 == fBM) {
+ return NULL;
+ }
+ SelectObject(fDC, fBM);
+ }
+
+ // erase
+ size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2);
+ size_t size = fHeight * srcRB;
+ unsigned bg = (0 == color) ? 0xFF : 0;
+ memset(fBits, bg, size);
+
+ XFORM xform = fXform;
+ xform.eDx = (float)-glyph.fLeft;
+ xform.eDy = (float)-glyph.fTop;
+ SetWorldTransform(fDC, &xform);
+
+ uint16_t glyphID = glyph.getGlyphID();
+ BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, reinterpret_cast<LPCWSTR>(&glyphID), 1, NULL);
+ GdiFlush();
+ if (0 == ret) {
+ return NULL;
+ }
+ *srcRBPtr = srcRB;
+ // offset to the start of the image
+ return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
class SkScalerContext_Windows : public SkScalerContext {
public:
@@ -262,9 +423,10 @@ protected:
virtual void generateImage(const SkGlyph& glyph);
virtual void generatePath(const SkGlyph& glyph, SkPath* path);
virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY);
- //virtual SkDeviceContext getDC() {return ddc;}
+
private:
- SkScalar fScale; // to get from canonical size to real size
+ HDCOffscreen fOffscreen;
+ SkScalar fScale; // to get from canonical size to real size
MAT2 fMat22;
XFORM fXform;
HDC fDDC;
@@ -298,12 +460,24 @@ static bool needHiResMetrics(const SkScalar mat[2][2]) {
return mat[1][0] || mat[0][1];
}
+static BYTE compute_quality(const SkScalerContext::Rec& rec) {
+ switch (rec.fMaskFormat) {
+ case SkMask::kBW_Format:
+ return NONANTIALIASED_QUALITY;
+ case SkMask::kLCD16_Format:
+ case SkMask::kLCD32_Format:
+ return CLEARTYPE_QUALITY;
+ default:
+ return ANTIALIASED_QUALITY;
+ }
+}
+
SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc)
: SkScalerContext(desc), fDDC(0), fFont(0), fSavefont(0), fSC(0)
, fGlyphCount(-1) {
SkAutoMutexAcquire ac(gFTMutex);
- fScale = fRec.fTextSize / gCanonicalTextSize;
+ fScale = fRec.fTextSize / gCanonicalTextSize;
fXform.eM11 = mul2float(fScale, fRec.fPost2x2[0][0]);
fXform.eM12 = mul2float(fScale, fRec.fPost2x2[1][0]);
@@ -326,11 +500,12 @@ SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc)
LOGFONT lf;
GetLogFontByID(fRec.fFontID, &lf);
lf.lfHeight = -gCanonicalTextSize;
+ lf.lfQuality = compute_quality(fRec);
fFont = CreateFontIndirect(&lf);
// if we're rotated, or want fractional widths, create a hires font
fHiResFont = 0;
- if (needHiResMetrics(fRec.fPost2x2) || (fRec.fFlags & kSubpixelPositioning_Flag)) {
+ if (needHiResMetrics(fRec.fPost2x2)) {
lf.lfHeight = -HIRES_TEXTSIZE;
fHiResFont = CreateFontIndirect(&lf);
@@ -343,6 +518,12 @@ SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc)
fHiResMatrix.preScale(scale, scale);
}
fSavefont = (HFONT)SelectObject(fDDC, fFont);
+
+ if (needToRenderWithSkia(fRec)) {
+ this->forceGenerateImageFromPath();
+ }
+
+ fOffscreen.init(fFont, fXform);
}
SkScalerContext_Windows::~SkScalerContext_Windows() {
@@ -410,6 +591,10 @@ void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) {
// Note: need to use GGO_GRAY8_BITMAP instead of GGO_METRICS because GGO_METRICS returns a smaller
// BlackBlox; we need the bigger one in case we need the image. fAdvance is the same.
uint32_t ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
+ if (GDI_ERROR == ret) {
+ ensure_typeface_accessible(fRec.fFontID);
+ ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
+ }
if (GDI_ERROR != ret) {
if (ret == 0) {
@@ -423,15 +608,21 @@ void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) {
glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX);
glyph->fAdvanceY = -SkIntToFixed(gm.gmCellIncY);
- // we outset by 1 in all dimensions, since the lcd image may bleed outside
+ // we outset in all dimensions, since the image may bleed outside
// of the computed bounds returned by GetGlyphOutline.
// This was deduced by trial and error for small text (e.g. 8pt), so there
// maybe a more precise way to make this adjustment...
- if (SkMask::kLCD16_Format == fRec.fMaskFormat) {
- glyph->fWidth += 2;
- glyph->fHeight += 2;
- glyph->fTop -= 1;
- glyph->fLeft -= 1;
+ //
+ // This test shows us clipping the tops of some of the CJK fonts unless we
+ // increase the top of the box by 2, hence the height by 4. This seems to
+ // correspond to an embedded bitmap font, but not sure.
+ // LayoutTests/fast/text/backslash-to-yen-sign-euc.html
+ //
+ if (glyph->fWidth) { // don't outset an empty glyph
+ glyph->fWidth += 4;
+ glyph->fHeight += 4;
+ glyph->fTop -= 2;
+ glyph->fLeft -= 2;
}
if (fHiResFont) {
@@ -462,182 +653,287 @@ void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPa
OUTLINETEXTMETRIC otm;
uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
+ if (GDI_ERROR == ret) {
+ ensure_typeface_accessible(fRec.fFontID);
+ ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
+ }
if (sizeof(otm) != ret) {
return;
}
if (mx) {
mx->fTop = -fScale * otm.otmTextMetrics.tmAscent;
- mx->fAscent = -fScale * otm.otmAscent;
- mx->fDescent = -fScale * otm.otmDescent;
- mx->fBottom = fScale * otm.otmTextMetrics.tmDescent;
- mx->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
- + otm.otmTextMetrics.tmExternalLeading);
+ mx->fAscent = -fScale * otm.otmAscent;
+ mx->fDescent = -fScale * otm.otmDescent;
+ mx->fBottom = fScale * otm.otmTextMetrics.tmDescent;
+ mx->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
+ + otm.otmTextMetrics.tmExternalLeading);
}
if (my) {
- my->fTop = -fScale * otm.otmTextMetrics.tmAscent;
- my->fAscent = -fScale * otm.otmAscent;
- my->fDescent = -fScale * otm.otmDescent;
- my->fBottom = fScale * otm.otmTextMetrics.tmDescent;
- my->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
- + otm.otmTextMetrics.tmExternalLeading);
+ my->fTop = -fScale * otm.otmTextMetrics.tmAscent;
+ my->fAscent = -fScale * otm.otmAscent;
+ my->fDescent = -fScale * otm.otmDescent;
+ my->fBottom = fScale * otm.otmTextMetrics.tmDescent;
+ my->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
+ + otm.otmTextMetrics.tmExternalLeading);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+static void build_power_table(uint8_t table[], float ee) {
+ for (int i = 0; i < 256; i++) {
+ float x = i / 255.f;
+ x = powf(x, ee);
+ int xx = SkScalarRound(SkFloatToScalar(x * 255));
+ table[i] = SkToU8(xx);
}
}
+// This will invert the gamma applied by GDI, so we can sort-of get linear values.
+// Needed when we draw non-black, non-white text, and don't know how to bias it.
+static const uint8_t* getInverseGammaTable() {
+ static bool gInited;
+ static uint8_t gTable[256];
+ if (!gInited) {
+ UINT level = 0;
+ if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) {
+ // can't get the data, so use a default
+ level = 1400;
+ }
+ build_power_table(gTable, level / 1000.0f);
+ gInited = true;
+ }
+ return gTable;
+}
+
#include "SkColorPriv.h"
-static inline uint16_t rgb_to_lcd16(uint32_t rgb) {
+// gdi's bitmap is upside-down, so we reverse dst walking in Y
+// whenever we copy it into skia's buffer
+
+static inline uint8_t rgb_to_a8(SkGdiRGB rgb) {
int r = (rgb >> 16) & 0xFF;
int g = (rgb >> 8) & 0xFF;
int b = (rgb >> 0) & 0xFF;
- // invert, since we draw black-on-white, but we want the original
- // src mask values.
- r = 255 - r;
- g = 255 - g;
- b = 255 - b;
+ return (r * 2 + g * 5 + b) >> 3; // luminance
+}
+
+static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb) {
+ int r = (rgb >> 16) & 0xFF;
+ int g = (rgb >> 8) & 0xFF;
+ int b = (rgb >> 0) & 0xFF;
return SkPackRGB16(SkR32ToR16(r), SkG32ToG16(g), SkB32ToB16(b));
}
-static int alignTo32(int n) {
- return (n + 31) & ~31;
+static inline SkPMColor rgb_to_lcd32(SkGdiRGB rgb) {
+ int r = (rgb >> 16) & 0xFF;
+ int g = (rgb >> 8) & 0xFF;
+ int b = (rgb >> 0) & 0xFF;
+ int a = SkMax32(r, SkMax32(g, b));
+ return SkPackARGB32(a, r, g, b);
}
-struct MyBitmapInfo : public BITMAPINFO {
- RGBQUAD fMoreSpaceForColors[1];
-};
+// Is this GDI color neither black nor white? If so, we have to keep this
+// image as is, rather than smashing it down to a BW mask.
+//
+// returns int instead of bool, since we don't want/have to pay to convert
+// the zero/non-zero value into a bool
+static int is_not_black_or_white(SkGdiRGB c) {
+ // same as (but faster than)
+ // c &= 0x00FFFFFF;
+ // return 0 == c || 0x00FFFFFF == c;
+ return (c + (c & 1)) & 0x00FFFFFF;
+}
-void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
+static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, int srcRB) {
+ for (int y = 0; y < height; ++y) {
+ for (int x = 0; x < width; ++x) {
+ if (is_not_black_or_white(src[x])) {
+ return false;
+ }
+ }
+ src = SkTAddByteOffset(src, srcRB);
+ }
+ return true;
+}
- SkAutoMutexAcquire ac(gFTMutex);
+static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
+ const SkGlyph& glyph, int32_t xorMask) {
+ const int width = glyph.fWidth;
+ const size_t dstRB = (width + 7) >> 3;
+ uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
+
+ int byteCount = width >> 3;
+ int bitCount = width & 7;
+
+ // adjust srcRB to skip the values in our byteCount loop,
+ // since we increment src locally there
+ srcRB -= byteCount * 8 * sizeof(SkGdiRGB);
+
+ for (int y = 0; y < glyph.fHeight; ++y) {
+ if (byteCount > 0) {
+ for (int i = 0; i < byteCount; ++i) {
+ unsigned byte = 0;
+ byte |= (src[0] ^ xorMask) & (1 << 7);
+ byte |= (src[1] ^ xorMask) & (1 << 6);
+ byte |= (src[2] ^ xorMask) & (1 << 5);
+ byte |= (src[3] ^ xorMask) & (1 << 4);
+ byte |= (src[4] ^ xorMask) & (1 << 3);
+ byte |= (src[5] ^ xorMask) & (1 << 2);
+ byte |= (src[6] ^ xorMask) & (1 << 1);
+ byte |= (src[7] ^ xorMask) & (1 << 0);
+ dst[i] = byte;
+ src += 8;
+ }
+ }
+ if (bitCount > 0) {
+ unsigned byte = 0;
+ unsigned mask = 0x80;
+ for (int i = 0; i < bitCount; i++) {
+ byte |= (src[i] ^ xorMask) & mask;
+ mask >>= 1;
+ }
+ dst[byteCount] = byte;
+ }
+ src = SkTAddByteOffset(src, srcRB);
+ dst -= dstRB;
+ }
+}
- SkASSERT(fDDC);
+static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
+ const SkGlyph& glyph, int32_t xorMask) {
+ const size_t dstRB = glyph.rowBytes();
+ const int width = glyph.fWidth;
+ uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
- const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
- if ((SkMask::kLCD16_Format == fRec.fMaskFormat) || isBW) {
- HDC dc = CreateCompatibleDC(0);
- void* bits = 0;
- int biWidth = isBW ? alignTo32(glyph.fWidth) : glyph.fWidth;
- MyBitmapInfo info;
- sk_bzero(&info, sizeof(info));
- if (isBW) {
- RGBQUAD blackQuad = { 0, 0, 0, 0 };
- RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
- info.bmiColors[0] = blackQuad;
- info.bmiColors[1] = whiteQuad;
- }
- info.bmiHeader.biSize = sizeof(info.bmiHeader);
- info.bmiHeader.biWidth = biWidth;
- info.bmiHeader.biHeight = glyph.fHeight;
- info.bmiHeader.biPlanes = 1;
- info.bmiHeader.biBitCount = isBW ? 1 : 32;
- info.bmiHeader.biCompression = BI_RGB;
- if (isBW) {
- info.bmiHeader.biClrUsed = 2;
+ for (int y = 0; y < glyph.fHeight; y++) {
+ for (int i = 0; i < width; i++) {
+ dst[i] = rgb_to_a8(src[i] ^ xorMask);
}
- HBITMAP bm = CreateDIBSection(dc, &info, DIB_RGB_COLORS, &bits, 0, 0);
- SelectObject(dc, bm);
-
- // erase to white
- size_t srcRB = isBW ? (biWidth >> 3) : (glyph.fWidth << 2);
- size_t size = glyph.fHeight * srcRB;
- memset(bits, isBW ? 0 : 0xFF, size);
-
- SetGraphicsMode(dc, GM_ADVANCED);
- SetBkMode(dc, TRANSPARENT);
- SetTextAlign(dc, TA_LEFT | TA_BASELINE);
-
- XFORM xform = fXform;
- xform.eDx = (float)-glyph.fLeft;
- xform.eDy = (float)-glyph.fTop;
- SetWorldTransform(dc, &xform);
-
- HGDIOBJ prevFont = SelectObject(dc, fFont);
- COLORREF color = SetTextColor(dc, isBW ? 0xFFFFFF : 0);
- SkASSERT(color != CLR_INVALID);
- uint16_t glyphID = glyph.getGlyphID();
-#if defined(UNICODE)
- ExtTextOut(dc, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCWSTR)&glyphID, 1, NULL);
-#else
- ExtTextOut(dc, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&glyphID, 1, NULL);
-#endif
- GdiFlush();
+ src = SkTAddByteOffset(src, srcRB);
+ dst -= dstRB;
+ }
+}
- // downsample from rgba to rgb565
- int width = glyph.fWidth;
- size_t dstRB = glyph.rowBytes();
- if (isBW) {
- const uint8_t* src = (const uint8_t*)bits;
- // gdi's bitmap is upside-down, so we reverse dst walking in Y
- uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
- for (int y = 0; y < glyph.fHeight; y++) {
- memcpy(dst, src, dstRB);
- src += srcRB;
- dst -= dstRB;
- }
- } else { // LCD16
- const uint32_t* src = (const uint32_t*)bits;
- // gdi's bitmap is upside-down, so we reverse dst walking in Y
- uint16_t* dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
- for (int y = 0; y < glyph.fHeight; y++) {
- for (int i = 0; i < width; i++) {
- dst[i] = rgb_to_lcd16(src[i]);
- }
- src = (const uint32_t*)((const char*)src + srcRB);
- dst = (uint16_t*)((char*)dst - dstRB);
- }
+static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
+ const SkGlyph& glyph, int32_t xorMask) {
+ const size_t dstRB = glyph.rowBytes();
+ const int width = glyph.fWidth;
+ uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
+
+ for (int y = 0; y < glyph.fHeight; y++) {
+ for (int i = 0; i < width; i++) {
+ dst[i] = rgb_to_lcd16(src[i] ^ xorMask);
}
+ src = SkTAddByteOffset(src, srcRB);
+ dst = (uint16_t*)((char*)dst - dstRB);
+ }
+}
- DeleteDC(dc);
- DeleteObject(bm);
- return;
+static void rgb_to_lcd32(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
+ const SkGlyph& glyph, int32_t xorMask) {
+ const size_t dstRB = glyph.rowBytes();
+ const int width = glyph.fWidth;
+ SkPMColor* SK_RESTRICT dst = (SkPMColor*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
+
+ for (int y = 0; y < glyph.fHeight; y++) {
+ for (int i = 0; i < width; i++) {
+ dst[i] = rgb_to_lcd32(src[i] ^ xorMask);
+ }
+ src = SkTAddByteOffset(src, srcRB);
+ dst = (SkPMColor*)((char*)dst - dstRB);
}
+}
- GLYPHMETRICS gm;
- memset(&gm, 0, sizeof(gm));
- uint32_t bytecount = 0;
- uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
- if (GDI_ERROR != total_size && total_size > 0) {
- uint8_t *pBuff = new uint8_t[total_size];
- if (NULL != pBuff) {
- total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, total_size, pBuff, &fMat22);
-
- SkASSERT(total_size != GDI_ERROR);
-
- SkASSERT(glyph.fWidth == gm.gmBlackBoxX);
- SkASSERT(glyph.fHeight == gm.gmBlackBoxY);
-
- uint8_t* dst = (uint8_t*)glyph.fImage;
- uint32_t pitch = (gm.gmBlackBoxX + 3) & ~0x3;
- if (pitch != glyph.rowBytes()) {
- SkASSERT(false); // glyph.fImage has different rowsize!?
- }
+static inline unsigned clamp255(unsigned x) {
+ SkASSERT(x <= 256);
+ return x - (x >> 8);
+}
- for (int32_t y = gm.gmBlackBoxY - 1; y >= 0; y--) {
- uint8_t* src = pBuff + pitch * y;
+#define WHITE_LUMINANCE_LIMIT 0xA0
+#define BLACK_LUMINANCE_LIMIT 0x40
- for (uint32_t x = 0; x < gm.gmBlackBoxX; x++) {
- if (*src > 63) {
- *dst = 0xFF;
- }
- else {
- *dst = *src << 2; // scale to 0-255
- }
- dst++;
- src++;
- bytecount++;
- }
- memset(dst, 0, glyph.rowBytes() - glyph.fWidth);
- dst += glyph.rowBytes() - glyph.fWidth;
- }
+void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
+ SkAutoMutexAcquire ac(gFTMutex);
+
+ SkASSERT(fDDC);
- delete[] pBuff;
+ const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
+ const bool isAA = !isLCD(fRec);
+ bool isWhite = fRec.getLuminanceByte() >= WHITE_LUMINANCE_LIMIT;
+ bool isBlack = fRec.getLuminanceByte() <= BLACK_LUMINANCE_LIMIT;
+
+ SkGdiRGB fgColor;
+ uint32_t rgbXOR;
+ const uint8_t* table = NULL;
+ if (isBW || isWhite) {
+ fgColor = 0x00FFFFFF;
+ rgbXOR = 0;
+ } else if (isBlack) {
+ fgColor = 0;
+ rgbXOR = ~0;
+ } else {
+ table = getInverseGammaTable();
+ fgColor = 0x00FFFFFF;
+ rgbXOR = 0;
+ }
+
+ size_t srcRB;
+ const void* bits = fOffscreen.draw(glyph, isBW, fgColor, &srcRB);
+ if (NULL == bits) {
+ ensure_typeface_accessible(fRec.fFontID);
+ bits = fOffscreen.draw(glyph, isBW, fgColor, &srcRB);
+ if (NULL == bits) {
+ sk_bzero(glyph.fImage, glyph.computeImageSize());
+ return;
}
}
- SkASSERT(GDI_ERROR != total_size && total_size >= 0);
+ if (table) {
+ SkGdiRGB* addr = (SkGdiRGB*)bits;
+ for (int y = 0; y < glyph.fHeight; ++y) {
+ for (int x = 0; x < glyph.fWidth; ++x) {
+ int r = (addr[x] >> 16) & 0xFF;
+ int g = (addr[x] >> 8) & 0xFF;
+ int b = (addr[x] >> 0) & 0xFF;
+ addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
+ }
+ addr = SkTAddByteOffset(addr, srcRB);
+ }
+ }
+ int width = glyph.fWidth;
+ size_t dstRB = glyph.rowBytes();
+ if (isBW) {
+ const uint8_t* src = (const uint8_t*)bits;
+ uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
+ for (int y = 0; y < glyph.fHeight; y++) {
+ memcpy(dst, src, dstRB);
+ src += srcRB;
+ dst -= dstRB;
+ }
+ } else if (isAA) {
+ // since the caller may require A8 for maskfilters, we can't check for BW
+ // ... until we have the caller tell us that explicitly
+ const SkGdiRGB* src = (const SkGdiRGB*)bits;
+ rgb_to_a8(src, srcRB, glyph, rgbXOR);
+ } else { // LCD16
+ const SkGdiRGB* src = (const SkGdiRGB*)bits;
+ if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) {
+ rgb_to_bw(src, srcRB, glyph, rgbXOR);
+ ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format;
+ } else {
+ if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
+ rgb_to_lcd16(src, srcRB, glyph, rgbXOR);
+ } else {
+ SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
+ rgb_to_lcd32(src, srcRB, glyph, rgbXOR);
+ }
+ }
+ }
}
void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) {
@@ -657,6 +953,10 @@ void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) {
GLYPHMETRICS gm;
uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22);
+ if (GDI_ERROR == total_size) {
+ ensure_typeface_accessible(fRec.fFontID);
+ total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22);
+ }
if (GDI_ERROR != total_size) {
@@ -708,11 +1008,11 @@ void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) {
}
void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
- SkASSERT(!"SkFontHost::Serialize unimplemented");
+ SkDEBUGFAIL("SkFontHost::Serialize unimplemented");
}
SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
- SkASSERT(!"SkFontHost::Deserialize unimplemented");
+ SkDEBUGFAIL("SkFontHost::Deserialize unimplemented");
return NULL;
}
@@ -733,7 +1033,9 @@ static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) {
// static
SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
uint32_t fontID,
- SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo) {
+ SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
+ const uint32_t* glyphIDs,
+ uint32_t glyphIDsCount) {
LOGFONT lf;
GetLogFontByID(fontID, &lf);
SkAdvancedTypefaceMetrics* info = NULL;
@@ -743,11 +1045,19 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
HFONT savefont = (HFONT)SelectObject(hdc, font);
HFONT designFont = NULL;
+ const char stem_chars[] = {'i', 'I', '!', '1'};
+ int16_t min_width;
+ unsigned glyphCount;
+
// To request design units, create a logical font whose height is specified
// as unitsPerEm.
OUTLINETEXTMETRIC otm;
- if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm) ||
- !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
+ unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
+ if (0 == otmRet) {
+ ensure_typeface_accessible(fontID);
+ otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
+ }
+ if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
goto Error;
}
lf.lfHeight = -SkToS32(otm.otmEMSquare);
@@ -756,7 +1066,7 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
goto Error;
}
- const unsigned glyphCount = calculateGlyphCount(hdc);
+ glyphCount = calculateGlyphCount(hdc);
info = new SkAdvancedTypefaceMetrics;
info->fEmSize = otm.otmEMSquare;
@@ -794,7 +1104,7 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
info->fBBox = SkIRect::MakeEmpty();
return info;
}
-
+
// If this bit is clear the font is a fixed pitch font.
if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
@@ -825,9 +1135,8 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
// Figure out a good guess for StemV - Min width of i, I, !, 1.
// This probably isn't very good with an italic font.
- int16_t min_width = SHRT_MAX;
+ min_width = SHRT_MAX;
info->fStemV = 0;
- char stem_chars[] = {'i', 'I', '!', '1'};
for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
ABC abcWidths;
if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
@@ -846,8 +1155,19 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
} else if (perGlyphInfo &
SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
- info->fGlyphWidths.reset(
- getAdvanceData(hdc, glyphCount, &getWidthAdvance));
+ if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
+ appendRange(&info->fGlyphWidths, 0);
+ info->fGlyphWidths->fAdvance.append(1, &min_width);
+ finishRange(info->fGlyphWidths.get(), 0,
+ SkAdvancedTypefaceMetrics::WidthRange::kDefault);
+ } else {
+ info->fGlyphWidths.reset(
+ getAdvanceData(hdc,
+ glyphCount,
+ glyphIDs,
+ glyphIDsCount,
+ &getWidthAdvance));
+ }
}
Error:
@@ -880,6 +1200,10 @@ SkStream* SkFontHost::OpenStream(SkFontID uniqueID) {
DWORD tables[2] = {kTTCTag, 0};
for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) {
size_t bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
+ if (bufferSize == GDI_ERROR) {
+ ensure_typeface_accessible(uniqueID);
+ bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
+ }
if (bufferSize != GDI_ERROR) {
stream = new SkMemoryStream(bufferSize);
if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(),
@@ -906,8 +1230,8 @@ SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
/** Return the closest matching typeface given either an existing family
(specified by a typeface in that family) or by a familyName, and a
requested style.
- 1) If familyFace is null, use famillyName.
- 2) If famillyName is null, use familyFace.
+ 1) If familyFace is null, use familyName.
+ 2) If familyName is null, use familyFace.
3) If both are null, return the default font that best matches style
This MUST not return NULL.
*/
@@ -945,39 +1269,71 @@ SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
return SkCreateTypefaceFromLOGFONT(lf);
}
-size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
- if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
- return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
- else
- return 0; // nothing to do
-}
-
-int SkFontHost::ComputeGammaFlag(const SkPaint& paint) {
- return 0;
-}
-
-void SkFontHost::GetGammaTables(const uint8_t* tables[2]) {
- tables[0] = NULL; // black gamma (e.g. exp=1.4)
- tables[1] = NULL; // white gamma (e.g. exp= 1/1.4)
-}
-
SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
printf("SkFontHost::CreateTypefaceFromFile unimplemented");
return NULL;
}
void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
- // We don't control the hinting nor ClearType settings here
- rec->setHinting(SkPaint::kNormal_Hinting);
-
- // we do support LCD16
- if (SkMask::kLCD16_Format == rec->fMaskFormat) {
- return;
+ unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
+ SkScalerContext::kAutohinting_Flag |
+ SkScalerContext::kEmbeddedBitmapText_Flag |
+ SkScalerContext::kEmbolden_Flag |
+ SkScalerContext::kSubpixelPositioning_Flag |
+ SkScalerContext::kLCD_BGROrder_Flag |
+ SkScalerContext::kLCD_Vertical_Flag;
+ rec->fFlags &= ~flagsWeDontSupport;
+
+ SkPaint::Hinting h = rec->getHinting();
+
+ // I think we can support no-hinting, if we get hires outlines and just
+ // use skia to rasterize into a gray-scale mask...
+#if 0
+ switch (h) {
+ case SkPaint::kNo_Hinting:
+ case SkPaint::kSlight_Hinting:
+ h = SkPaint::kNo_Hinting;
+ break;
+ case SkPaint::kNormal_Hinting:
+ case SkPaint::kFull_Hinting:
+ h = SkPaint::kNormal_Hinting;
+ break;
+ default:
+ SkDEBUGFAIL("unknown hinting");
+ }
+#else
+ h = SkPaint::kNormal_Hinting;
+#endif
+ rec->setHinting(h);
+
+ // for compatibility at the moment, discretize luminance to 3 settings
+ // black, white, gray. This helps with fontcache utilization, since we
+ // won't create multiple entries that in the end map to the same results.
+ {
+ unsigned lum = rec->getLuminanceByte();
+ if (lum <= BLACK_LUMINANCE_LIMIT) {
+ lum = 0;
+ } else if (lum >= WHITE_LUMINANCE_LIMIT) {
+ lum = SkScalerContext::kLuminance_Max;
+ } else {
+ lum = SkScalerContext::kLuminance_Max >> 1;
+ }
+ rec->setLuminanceBits(lum);
}
- if (SkMask::FormatIsLCD((SkMask::Format)rec->fMaskFormat)) {
+// turn this off since GDI might turn A8 into BW! Need a bigger fix.
+#if 0
+ // Disable LCD when rotated, since GDI's output is ugly
+ if (isLCD(*rec) && !isAxisAligned(*rec)) {
rec->fMaskFormat = SkMask::kA8_Format;
}
+#endif
+
+#if 0
+ if (SkMask::kLCD16_Format == rec->fMaskFormat) {
+ rec->fMaskFormat = SkMask::kLCD32_Format;
+ }
+#endif
}
#endif // WIN32
diff --git a/src/ports/SkGlobalInitialization_chromium.cpp b/src/ports/SkGlobalInitialization_chromium.cpp
new file mode 100644
index 0000000..6a7b213
--- /dev/null
+++ b/src/ports/SkGlobalInitialization_chromium.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmapProcShader.h"
+#include "SkBlurImageFilter.h"
+#include "SkBlurMaskFilter.h"
+#include "SkColorFilter.h"
+#include "SkCornerPathEffect.h"
+#include "SkDashPathEffect.h"
+#include "SkGradientShader.h"
+#include "SkLayerDrawLooper.h"
+#include "SkMallocPixelRef.h"
+#include "SkXfermode.h"
+
+void SkFlattenable::InitializeFlattenables() {
+ SkBitmapProcShader::Init();
+ SkBlurImageFilter::Init();
+ SkBlurMaskFilter::Init();
+ SkColorFilter::Init();
+ SkCornerPathEffect::Init();
+ SkDashPathEffect::Init();
+ SkGradientShader::Init();
+ SkLayerDrawLooper::Init();
+ SkXfermode::Init();
+}
+
+void SkPixelRef::InitializeFlattenables() {
+ SkMallocPixelRef::Init();
+}
diff --git a/src/ports/SkGlobalInitialization_default.cpp b/src/ports/SkGlobalInitialization_default.cpp
new file mode 100644
index 0000000..6be776a
--- /dev/null
+++ b/src/ports/SkGlobalInitialization_default.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTypes.h"
+
+#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+
+#include "SkBitmapProcShader.h"
+#include "SkEffects.h"
+#include "SkFlipPixelRef.h"
+#include "SkImageRef_ashmem.h"
+#include "SkImageRef_GlobalPool.h"
+#include "SkMallocPixelRef.h"
+#include "SkPathEffect.h"
+#include "SkPixelRef.h"
+#include "SkShape.h"
+#include "SkXfermode.h"
+
+void SkFlattenable::InitializeFlattenables() {
+ SkBitmapProcShader::Init();
+ SkEffects::Init();
+ SkPathEffect::Init();
+ SkShape::Init();
+ SkXfermode::Init();
+}
+
+void SkPixelRef::InitializeFlattenables() {
+ SkFlipPixelRef::Init();
+ SkImageRef_GlobalPool::Init();
+ SkMallocPixelRef::Init();
+}
+
+#endif
diff --git a/src/ports/SkGlobals_global.cpp b/src/ports/SkGlobals_global.cpp
deleted file mode 100644
index d87568b..0000000
--- a/src/ports/SkGlobals_global.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/* libs/graphics/ports/SkGlobals_global.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include "SkGlobals.h"
-#include "SkThread.h"
-
-static SkGlobals::BootStrap gBootStrap;
-
-SkGlobals::BootStrap& SkGlobals::GetBootStrap()
-{
- return gBootStrap;
-}
-
-
diff --git a/src/ports/SkHarfBuzzFont.cpp b/src/ports/SkHarfBuzzFont.cpp
index bb229a1..12f37f5 100644
--- a/src/ports/SkHarfBuzzFont.cpp
+++ b/src/ports/SkHarfBuzzFont.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2009 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkHarfBuzzFont.h"
#include "SkFontHost.h"
#include "SkPaint.h"
diff --git a/src/ports/SkImageDecoder_CG.cpp b/src/ports/SkImageDecoder_CG.cpp
index 4fca143..81c6b37 100644
--- a/src/ports/SkImageDecoder_CG.cpp
+++ b/src/ports/SkImageDecoder_CG.cpp
@@ -1,19 +1,12 @@
-/* Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <Carbon/Carbon.h>
+
+/*
+ * Copyright 2008 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
#include "SkImageDecoder.h"
#include "SkImageEncoder.h"
#include "SkMovie.h"
@@ -21,6 +14,14 @@
#include "SkTemplates.h"
#include "SkCGUtils.h"
+#ifdef SK_BUILD_FOR_MAC
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
+#ifdef SK_BUILD_FOR_IOS
+#include <CoreGraphics/CoreGraphics.h>
+#endif
+
static void malloc_release_proc(void* info, const void* data, size_t size) {
sk_free(info);
}
@@ -76,12 +77,12 @@ bool SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
bm->lockPixels();
bm->eraseColor(0);
- CGColorSpaceRef cs = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+ // use the same colorspace, so we don't change the pixels at all
+ CGColorSpaceRef cs = CGImageGetColorSpace(image);
CGContextRef cg = CGBitmapContextCreate(bm->getPixels(), width, height,
8, bm->rowBytes(), cs, BITMAP_INFO);
CGContextDrawImage(cg, CGRectMake(0, 0, width, height), image);
CGContextRelease(cg);
- CGColorSpaceRelease(cs);
bm->unlockPixels();
return true;
diff --git a/src/ports/SkImageDecoder_WIC.cpp b/src/ports/SkImageDecoder_WIC.cpp
new file mode 100644
index 0000000..a69ed4a
--- /dev/null
+++ b/src/ports/SkImageDecoder_WIC.cpp
@@ -0,0 +1,307 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <wincodec.h>
+#include "SkAutoCoInitialize.h"
+#include "SkImageDecoder.h"
+#include "SkImageEncoder.h"
+#include "SkIStream.h"
+#include "SkMovie.h"
+#include "SkStream.h"
+#include "SkTScopedComPtr.h"
+
+class SkImageDecoder_WIC : public SkImageDecoder {
+protected:
+ virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode);
+};
+
+bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
+ //Initialize COM.
+ SkAutoCoInitialize scopedCo;
+ if (!scopedCo.succeeded()) {
+ return false;
+ }
+
+ HRESULT hr = S_OK;
+
+ //Create Windows Imaging Component ImagingFactory.
+ SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
+ if (SUCCEEDED(hr)) {
+ hr = CoCreateInstance(
+ CLSID_WICImagingFactory
+ , NULL
+ , CLSCTX_INPROC_SERVER
+ , IID_PPV_ARGS(&piImagingFactory)
+ );
+ }
+
+ //Convert SkStream to IStream.
+ SkTScopedComPtr<IStream> piStream;
+ if (SUCCEEDED(hr)) {
+ hr = SkIStream::CreateFromSkStream(stream, false, &piStream);
+ }
+
+ //Make sure we're at the beginning of the stream.
+ if (SUCCEEDED(hr)) {
+ LARGE_INTEGER liBeginning = { 0 };
+ hr = piStream->Seek(liBeginning, STREAM_SEEK_SET, NULL);
+ }
+
+ //Create the decoder from the stream content.
+ SkTScopedComPtr<IWICBitmapDecoder> piBitmapDecoder;
+ if (SUCCEEDED(hr)) {
+ hr = piImagingFactory->CreateDecoderFromStream(
+ piStream.get() //Image to be decoded
+ , NULL //No particular vendor
+ , WICDecodeMetadataCacheOnDemand //Cache metadata when needed
+ , &piBitmapDecoder //Pointer to the decoder
+ );
+ }
+
+ //Get the first frame from the decoder.
+ SkTScopedComPtr<IWICBitmapFrameDecode> piBitmapFrameDecode;
+ if (SUCCEEDED(hr)) {
+ hr = piBitmapDecoder->GetFrame(0, &piBitmapFrameDecode);
+ }
+
+ //Get the BitmapSource interface of the frame.
+ SkTScopedComPtr<IWICBitmapSource> piBitmapSourceOriginal;
+ if (SUCCEEDED(hr)) {
+ hr = piBitmapFrameDecode->QueryInterface(
+ IID_PPV_ARGS(&piBitmapSourceOriginal)
+ );
+ }
+
+ //Get the size of the bitmap.
+ UINT width;
+ UINT height;
+ if (SUCCEEDED(hr)) {
+ hr = piBitmapSourceOriginal->GetSize(&width, &height);
+ }
+
+ //Exit early if we're only looking for the bitmap bounds.
+ if (SUCCEEDED(hr)) {
+ bm->setConfig(SkBitmap::kARGB_8888_Config, width, height);
+ if (SkImageDecoder::kDecodeBounds_Mode == mode) {
+ return true;
+ }
+ if (!this->allocPixelRef(bm, NULL)) {
+ return false;
+ }
+ }
+
+ //Create a format converter.
+ SkTScopedComPtr<IWICFormatConverter> piFormatConverter;
+ if (SUCCEEDED(hr)) {
+ hr = piImagingFactory->CreateFormatConverter(&piFormatConverter);
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = piFormatConverter->Initialize(
+ piBitmapSourceOriginal.get() //Input bitmap to convert
+ , GUID_WICPixelFormat32bppPBGRA //Destination pixel format
+ , WICBitmapDitherTypeNone //Specified dither patterm
+ , NULL //Specify a particular palette
+ , 0.f //Alpha threshold
+ , WICBitmapPaletteTypeCustom //Palette translation type
+ );
+ }
+
+ //Get the BitmapSource interface of the format converter.
+ SkTScopedComPtr<IWICBitmapSource> piBitmapSourceConverted;
+ if (SUCCEEDED(hr)) {
+ hr = piFormatConverter->QueryInterface(
+ IID_PPV_ARGS(&piBitmapSourceConverted)
+ );
+ }
+
+ //Copy the pixels into the bitmap.
+ if (SUCCEEDED(hr)) {
+ SkAutoLockPixels alp(*bm);
+ bm->eraseColor(0);
+ const int stride = bm->rowBytes();
+ hr = piBitmapSourceConverted->CopyPixels(
+ NULL, //Get all the pixels
+ stride,
+ stride * height,
+ reinterpret_cast<BYTE *>(bm->getPixels())
+ );
+ }
+
+ return SUCCEEDED(hr);
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+SkImageDecoder* SkImageDecoder::Factory(SkStream* stream) {
+ return SkNEW(SkImageDecoder_WIC);
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+SkMovie* SkMovie::DecodeStream(SkStream* stream) {
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+class SkImageEncoder_WIC : public SkImageEncoder {
+public:
+ SkImageEncoder_WIC(Type t) : fType(t) {}
+
+protected:
+ virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
+
+private:
+ Type fType;
+};
+
+bool SkImageEncoder_WIC::onEncode(SkWStream* stream
+ , const SkBitmap& bitmapOrig
+ , int quality)
+{
+ GUID type;
+ switch (fType) {
+ case kJPEG_Type:
+ type = GUID_ContainerFormatJpeg;
+ break;
+ case kPNG_Type:
+ type = GUID_ContainerFormatPng;
+ break;
+ default:
+ return false;
+ }
+
+ //Convert to 8888 if needed.
+ const SkBitmap* bitmap;
+ SkBitmap bitmapCopy;
+ if (SkBitmap::kARGB_8888_Config == bitmapOrig.config()) {
+ bitmap = &bitmapOrig;
+ } else {
+ if (!bitmapOrig.copyTo(&bitmapCopy, SkBitmap::kARGB_8888_Config)) {
+ return false;
+ }
+ bitmap = &bitmapCopy;
+ }
+
+ //Initialize COM.
+ SkAutoCoInitialize scopedCo;
+ if (!scopedCo.succeeded()) {
+ return false;
+ }
+
+ HRESULT hr = S_OK;
+
+ //Create Windows Imaging Component ImagingFactory.
+ SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
+ if (SUCCEEDED(hr)) {
+ hr = CoCreateInstance(
+ CLSID_WICImagingFactory
+ , NULL
+ , CLSCTX_INPROC_SERVER
+ , IID_PPV_ARGS(&piImagingFactory)
+ );
+ }
+
+ //Convert the SkWStream to an IStream.
+ SkTScopedComPtr<IStream> piStream;
+ if (SUCCEEDED(hr)) {
+ hr = SkWIStream::CreateFromSkWStream(stream, &piStream);
+ }
+
+ //Create an encode of the appropriate type.
+ SkTScopedComPtr<IWICBitmapEncoder> piEncoder;
+ if (SUCCEEDED(hr)) {
+ hr = piImagingFactory->CreateEncoder(type, NULL, &piEncoder);
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache);
+ }
+
+ //Create a the frame.
+ SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode;
+ SkTScopedComPtr<IPropertyBag2> piPropertybag;
+ if (SUCCEEDED(hr)) {
+ hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag);
+ }
+
+ if (SUCCEEDED(hr)) {
+ PROPBAG2 name = { 0 };
+ name.dwType = PROPBAG2_TYPE_DATA;
+ name.vt = VT_R4;
+ name.pstrName = L"ImageQuality";
+
+ VARIANT value;
+ VariantInit(&value);
+ value.vt = VT_R4;
+ value.fltVal = (FLOAT)(quality / 100.0);
+
+ //Ignore result code.
+ // This returns E_FAIL if the named property is not in the bag.
+ //TODO(bungeman) enumerate the properties,
+ // write and set hr iff property exists.
+ piPropertybag->Write(1, &name, &value);
+ }
+ if (SUCCEEDED(hr)) {
+ hr = piBitmapFrameEncode->Initialize(piPropertybag.get());
+ }
+
+ //Set the size of the frame.
+ const UINT width = bitmap->width();
+ const UINT height = bitmap->height();
+ if (SUCCEEDED(hr)) {
+ hr = piBitmapFrameEncode->SetSize(width, height);
+ }
+
+ //Set the pixel format of the frame.
+ const WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA;
+ WICPixelFormatGUID formatGUID = formatDesired;
+ if (SUCCEEDED(hr)) {
+ hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID);
+ }
+ if (SUCCEEDED(hr)) {
+ //Be sure the image format is the one requested.
+ hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL;
+ }
+
+ //Write the pixels into the frame.
+ if (SUCCEEDED(hr)) {
+ SkAutoLockPixels alp(*bitmap);
+ hr = piBitmapFrameEncode->WritePixels(
+ height
+ , bitmap->rowBytes()
+ , bitmap->rowBytes()*height
+ , reinterpret_cast<BYTE*>(bitmap->getPixels()));
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = piBitmapFrameEncode->Commit();
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = piEncoder->Commit();
+ }
+
+ return SUCCEEDED(hr);
+}
+
+SkImageEncoder* SkImageEncoder::Create(Type t) {
+ switch (t) {
+ case kJPEG_Type:
+ case kPNG_Type:
+ break;
+ default:
+ return NULL;
+ }
+ return SkNEW_ARGS(SkImageEncoder_WIC, (t));
+}
+
diff --git a/src/ports/SkImageDecoder_empty.cpp b/src/ports/SkImageDecoder_empty.cpp
index 740af7d..e4079d0 100644
--- a/src/ports/SkImageDecoder_empty.cpp
+++ b/src/ports/SkImageDecoder_empty.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/ports/SkImageDecoder_Factory.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkImageDecoder.h"
#include "SkMovie.h"
diff --git a/src/ports/SkImageRef_ashmem.cpp b/src/ports/SkImageRef_ashmem.cpp
index 539d768..f9c6aff 100644
--- a/src/ports/SkImageRef_ashmem.cpp
+++ b/src/ports/SkImageRef_ashmem.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkImageRef_ashmem.h"
#include "SkImageDecoder.h"
#include "SkFlattenable.h"
@@ -84,15 +91,17 @@ public:
int err = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE);
if (err) {
- SkDebugf("------ ashmem_set_prot_region(%d) failed %d %d\n",
- fd, err, errno);
+ SkDebugf("------ ashmem_set_prot_region(%d) failed %d\n",
+ fd, err);
+ close(fd);
return false;
}
addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
if (-1 == (long)addr) {
- SkDebugf("---------- mmap failed for imageref_ashmem size=%d err=%d\n",
- size, errno);
+ SkDebugf("---------- mmap failed for imageref_ashmem size=%d\n",
+ size);
+ close(fd);
return false;
}
@@ -171,8 +180,7 @@ void* SkImageRef_ashmem::onLockPixels(SkColorTable** ct) {
SkDebugf("===== ashmem purged %d\n", fBitmap.getSize());
#endif
} else {
- SkDebugf("===== ashmem pin_region(%d) returned %d, treating as error %d\n",
- fRec.fFD, pin, errno);
+ SkDebugf("===== ashmem pin_region(%d) returned %d\n", fRec.fFD, pin);
// return null result for failure
if (ct) {
*ct = NULL;
@@ -233,5 +241,4 @@ SkPixelRef* SkImageRef_ashmem::Create(SkFlattenableReadBuffer& buffer) {
return SkNEW_ARGS(SkImageRef_ashmem, (buffer));
}
-static SkPixelRef::Registrar reg("SkImageRef_ashmem",
- SkImageRef_ashmem::Create);
+SK_DEFINE_PIXEL_REF_REGISTRAR(SkImageRef_ashmem)
diff --git a/src/ports/SkImageRef_ashmem.h b/src/ports/SkImageRef_ashmem.h
index 2c485e3..f50ea80 100644
--- a/src/ports/SkImageRef_ashmem.h
+++ b/src/ports/SkImageRef_ashmem.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkImageRef_ashmem_DEFINED
#define SkImageRef_ashmem_DEFINED
@@ -22,6 +29,7 @@ public:
}
static SkPixelRef* Create(SkFlattenableReadBuffer&);
+ SK_DECLARE_PIXEL_REF_REGISTRAR()
protected:
virtual bool onDecode(SkImageDecoder* codec, SkStream* stream,
SkBitmap* bitmap, SkBitmap::Config config,
diff --git a/src/ports/SkMemory_brew.cpp b/src/ports/SkMemory_brew.cpp
index fe73d5b..96af702 100644
--- a/src/ports/SkMemory_brew.cpp
+++ b/src/ports/SkMemory_brew.cpp
@@ -1,20 +1,11 @@
/* libs/graphics/ports/SkMemory_brew.cpp
-**
-** Copyright 2009, The Android Open Source Project
-** Copyright 2009, Company 100, Inc.
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+ *
+ * Copyright 2009, The Android Open Source Project
+ * Copyright 2009, Company 100, Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkTypes.h"
@@ -23,12 +14,12 @@
#include <AEEStdLib.h>
void sk_throw() {
- SkASSERT(!"sk_throw");
+ SkDEBUGFAIL("sk_throw");
abort();
}
void sk_out_of_memory(void) {
- SkASSERT(!"sk_out_of_memory");
+ SkDEBUGFAIL("sk_out_of_memory");
abort();
}
@@ -62,4 +53,3 @@ void* sk_malloc_flags(size_t size, unsigned flags) {
}
#endif
-
diff --git a/src/ports/SkMemory_malloc.cpp b/src/ports/SkMemory_malloc.cpp
index b10ef70..44e43ad 100644
--- a/src/ports/SkMemory_malloc.cpp
+++ b/src/ports/SkMemory_malloc.cpp
@@ -1,14 +1,21 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkTypes.h"
#include <stdio.h>
#include <stdlib.h>
void sk_throw() {
- SkASSERT(!"sk_throw");
+ SkDEBUGFAIL("sk_throw");
abort();
}
void sk_out_of_memory(void) {
- SkASSERT(!"sk_out_of_memory");
+ SkDEBUGFAIL("sk_out_of_memory");
abort();
}
diff --git a/src/ports/SkOSEvent_android.cpp b/src/ports/SkOSEvent_android.cpp
deleted file mode 100644
index 59d6191..0000000
--- a/src/ports/SkOSEvent_android.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/* libs/graphics/ports/SkOSEvent_android.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#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, NULL);
-
- // 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/src/ports/SkOSEvent_dummy.cpp b/src/ports/SkOSEvent_dummy.cpp
deleted file mode 100644
index f061b6e..0000000
--- a/src/ports/SkOSEvent_dummy.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/* libs/graphics/ports/SkOSEvent_dummy.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include "SkEvent.h"
-
-void SkEvent::SignalNonEmptyQueue()
-{
-
-}
-
-void SkEvent::SignalQueueTimer(SkMSec delay)
-{
-
-}
diff --git a/src/ports/SkOSFile_brew.cpp b/src/ports/SkOSFile_brew.cpp
index 9c7c072..50e133f 100644
--- a/src/ports/SkOSFile_brew.cpp
+++ b/src/ports/SkOSFile_brew.cpp
@@ -1,20 +1,12 @@
/* libs/graphics/ports/SkOSFile_brew.cpp
-**
-** Copyright 2006, The Android Open Source Project
-** Copyright 2009, Company 100, Inc.
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+ *
+ * Copyright 2006, The Android Open Source Project
+ * Copyright 2009, Company 100, Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkOSFile.h"
@@ -96,4 +88,3 @@ void sk_fclose(SkFILE* f)
}
#endif
-
diff --git a/src/ports/SkOSFile_stdio.cpp b/src/ports/SkOSFile_stdio.cpp
index f6fa818..764b466 100644
--- a/src/ports/SkOSFile_stdio.cpp
+++ b/src/ports/SkOSFile_stdio.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/ports/SkOSFile_stdio.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkOSFile.h"
diff --git a/src/ports/SkThread_none.cpp b/src/ports/SkThread_none.cpp
index 37a3834..e70acde 100644
--- a/src/ports/SkThread_none.cpp
+++ b/src/ports/SkThread_none.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/ports/SkThread_none.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkThread.h"
diff --git a/src/ports/SkThread_pthread.cpp b/src/ports/SkThread_pthread.cpp
index 4ee857d..51c0859 100644
--- a/src/ports/SkThread_pthread.cpp
+++ b/src/ports/SkThread_pthread.cpp
@@ -1,8 +1,46 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkThread.h"
#include <pthread.h>
#include <errno.h>
+#ifndef SK_BUILD_FOR_ANDROID
+
+/**
+ We prefer the GCC intrinsic implementation of the atomic operations over the
+ SkMutex-based implementation. The SkMutex version suffers from static
+ destructor ordering problems.
+ Note clang also defines the GCC version macros and implements the intrinsics.
+ TODO: Verify that gcc-style __sync_* intrinsics work on ARM
+ According to this the intrinsics are supported on ARM in LLVM 2.7+
+ http://llvm.org/releases/2.7/docs/ReleaseNotes.html
+*/
+#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || __GNUC__ > 4
+ #if (defined(__x86_64) || defined(__i386__))
+ #define GCC_INTRINSIC
+ #endif
+#endif
+
+#if defined(GCC_INTRINSIC)
+
+int32_t sk_atomic_inc(int32_t* addr)
+{
+ return __sync_fetch_and_add(addr, 1);
+}
+
+int32_t sk_atomic_dec(int32_t* addr)
+{
+ return __sync_fetch_and_add(addr, -1);
+}
+
+#else
+
SkMutex gAtomicMutex;
int32_t sk_atomic_inc(int32_t* addr)
@@ -23,6 +61,10 @@ int32_t sk_atomic_dec(int32_t* addr)
return value;
}
+#endif
+
+#endif // SK_BUILD_FOR_ANDROID
+
//////////////////////////////////////////////////////////////////////////////
static void print_pthread_error(int status)
@@ -47,7 +89,7 @@ SkMutex::SkMutex(bool isGlobal) : fIsGlobal(isGlobal)
if (sizeof(pthread_mutex_t) > sizeof(fStorage))
{
SkDEBUGF(("pthread mutex size = %d\n", sizeof(pthread_mutex_t)));
- SkASSERT(!"mutex storage is too small");
+ SkDEBUGFAIL("mutex storage is too small");
}
int status;
diff --git a/src/ports/SkThread_win.cpp b/src/ports/SkThread_win.cpp
index cb3aa37..5fa58dd 100644
--- a/src/ports/SkThread_win.cpp
+++ b/src/ports/SkThread_win.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/ports/SkThread_none.cpp
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2008 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include <windows.h>
#include "SkThread.h"
diff --git a/src/ports/SkTime_Unix.cpp b/src/ports/SkTime_Unix.cpp
index 1bf3a76..f519a69 100644
--- a/src/ports/SkTime_Unix.cpp
+++ b/src/ports/SkTime_Unix.cpp
@@ -1,23 +1,14 @@
-/* libs/graphics/ports/SkTime_Unix.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTime.h"
-#if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_MAC)
#include <sys/time.h>
#include <time.h>
@@ -46,5 +37,3 @@ SkMSec SkTime::GetMSecs()
gettimeofday(&tv, NULL);
return (SkMSec) (tv.tv_sec * 1000 + tv.tv_usec / 1000 ); // microseconds to milliseconds
}
-
-#endif
diff --git a/src/ports/SkTime_win.cpp b/src/ports/SkTime_win.cpp
index 49bb37d..37af9f2 100644
--- a/src/ports/SkTime_win.cpp
+++ b/src/ports/SkTime_win.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/ports/SkTime_Unix.cpp
-**
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2009 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTime.h"
diff --git a/src/ports/SkXMLParser_empty.cpp b/src/ports/SkXMLParser_empty.cpp
index 9a27306..09b222e 100644
--- a/src/ports/SkXMLParser_empty.cpp
+++ b/src/ports/SkXMLParser_empty.cpp
@@ -1,22 +1,10 @@
-/* libs/graphics/ports/SkXMLParser_empty.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
-// Copyright Skia Inc. 2004 - 2005
-//
#include "SkXMLParser.h"
bool SkXMLParser::parse(SkStream& docStream)
@@ -33,4 +21,3 @@ void SkXMLParser::GetNativeErrorString(int error, SkString* str)
{
}
-
diff --git a/src/ports/SkXMLParser_expat.cpp b/src/ports/SkXMLParser_expat.cpp
index 7694d50..c78dc35 100644
--- a/src/ports/SkXMLParser_expat.cpp
+++ b/src/ports/SkXMLParser_expat.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/ports/SkXMLParser_expat.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkXMLParser.h"
#include "SkString.h"
diff --git a/src/ports/SkXMLParser_tinyxml.cpp b/src/ports/SkXMLParser_tinyxml.cpp
index 7f57b80..2e308aa 100644
--- a/src/ports/SkXMLParser_tinyxml.cpp
+++ b/src/ports/SkXMLParser_tinyxml.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/ports/SkXMLParser_tinyxml.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkXMLParser.h"
#include "SkStream.h"
diff --git a/src/ports/SkXMLPullParser_expat.cpp b/src/ports/SkXMLPullParser_expat.cpp
index 949c7a9..06cdc65 100644
--- a/src/ports/SkXMLPullParser_expat.cpp
+++ b/src/ports/SkXMLPullParser_expat.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/ports/SkXMLParser_expat.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkXMLParser.h"
#include "SkChunkAlloc.h"
diff --git a/src/ports/ports_files.mk b/src/ports/ports_files.mk
deleted file mode 100644
index 563f20b..0000000
--- a/src/ports/ports_files.mk
+++ /dev/null
@@ -1,6 +0,0 @@
-SOURCE := \
- SkDebug_stdio.cpp \
- SkGlobals_global.cpp \
- SkOSFile_stdio.cpp \
- SkThread_pthread.cpp \
- SkTime_Unix.cpp
diff --git a/src/ports/sk_predefined_gamma.h b/src/ports/sk_predefined_gamma.h
index 0818b30..d363594 100644
--- a/src/ports/sk_predefined_gamma.h
+++ b/src/ports/sk_predefined_gamma.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SK_PREDEFINED_GAMMA_H
#define SK_PREDEFINED_GAMMA_H
diff --git a/src/svg/SkSVG.cpp b/src/svg/SkSVG.cpp
index bcd62bf..fdfc13a 100644
--- a/src/svg/SkSVG.cpp
+++ b/src/svg/SkSVG.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVG.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVG.h"
#include 'SkSVGParser.h"
diff --git a/src/svg/SkSVGCircle.cpp b/src/svg/SkSVGCircle.cpp
index d27521d..2f282bd 100644
--- a/src/svg/SkSVGCircle.cpp
+++ b/src/svg/SkSVGCircle.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGCircle.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGCircle.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGCircle.h b/src/svg/SkSVGCircle.h
index 343a367..1185162 100644
--- a/src/svg/SkSVGCircle.h
+++ b/src/svg/SkSVGCircle.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGCircle.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGCircle_DEFINED
#define SkSVGCircle_DEFINED
diff --git a/src/svg/SkSVGClipPath.cpp b/src/svg/SkSVGClipPath.cpp
index bd71429..0a41764 100644
--- a/src/svg/SkSVGClipPath.cpp
+++ b/src/svg/SkSVGClipPath.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGClipPath.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGClipPath.h"
#include "SkSVGParser.h"
@@ -36,7 +28,7 @@ void SkSVGClipPath::translate(SkSVGParser& parser, bool defState) {
SkSVGElement* child = *fChildren.begin();
SkASSERT(child->getType() == SkSVGType_Use);
SkSVGUse* use = (SkSVGUse*) child;
- SkSVGElement* ref;
+ SkSVGElement* ref = NULL;
const char* refStr = &use->f_xlink_href.c_str()[1];
SkASSERT(parser.getIDs().find(refStr, &ref));
SkASSERT(ref);
diff --git a/src/svg/SkSVGClipPath.h b/src/svg/SkSVGClipPath.h
index 6fa17b8..9ba4fbc 100644
--- a/src/svg/SkSVGClipPath.h
+++ b/src/svg/SkSVGClipPath.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGClipPath.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGClipPath_DEFINED
#define SkSVGClipPath_DEFINED
diff --git a/src/svg/SkSVGDefs.cpp b/src/svg/SkSVGDefs.cpp
index 0499075..3b9bc20 100644
--- a/src/svg/SkSVGDefs.cpp
+++ b/src/svg/SkSVGDefs.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGDefs.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGDefs.h"
diff --git a/src/svg/SkSVGDefs.h b/src/svg/SkSVGDefs.h
index 45f0106..daa6894 100644
--- a/src/svg/SkSVGDefs.h
+++ b/src/svg/SkSVGDefs.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGDefs.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGDefs_DEFINED
#define SkSVGDefs_DEFINED
diff --git a/src/svg/SkSVGElements.cpp b/src/svg/SkSVGElements.cpp
index 8e195c7..0096fc0 100644
--- a/src/svg/SkSVGElements.cpp
+++ b/src/svg/SkSVGElements.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGElements.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGElements.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGElements.h b/src/svg/SkSVGElements.h
index ed3f921..d00e434 100644
--- a/src/svg/SkSVGElements.h
+++ b/src/svg/SkSVGElements.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGElements.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGElements_DEFINED
#define SkSVGElements_DEFINED
diff --git a/src/svg/SkSVGEllipse.cpp b/src/svg/SkSVGEllipse.cpp
index 3752b83..e239565 100644
--- a/src/svg/SkSVGEllipse.cpp
+++ b/src/svg/SkSVGEllipse.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGEllipse.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGEllipse.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGEllipse.h b/src/svg/SkSVGEllipse.h
index 566f16c..c039c83 100644
--- a/src/svg/SkSVGEllipse.h
+++ b/src/svg/SkSVGEllipse.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGEllipse.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGEllipse_DEFINED
#define SkSVGEllipse_DEFINED
diff --git a/src/svg/SkSVGFeColorMatrix.cpp b/src/svg/SkSVGFeColorMatrix.cpp
index a758704..4e2d32a 100644
--- a/src/svg/SkSVGFeColorMatrix.cpp
+++ b/src/svg/SkSVGFeColorMatrix.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGFeColorMatrix.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGFeColorMatrix.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGFeColorMatrix.h b/src/svg/SkSVGFeColorMatrix.h
index 431d532..389995a 100644
--- a/src/svg/SkSVGFeColorMatrix.h
+++ b/src/svg/SkSVGFeColorMatrix.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGFeColorMatrix.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGFeColorMatrix_DEFINED
#define SkSVGFeColorMatrix_DEFINED
diff --git a/src/svg/SkSVGFilter.cpp b/src/svg/SkSVGFilter.cpp
index 1d32e56..207f176 100644
--- a/src/svg/SkSVGFilter.cpp
+++ b/src/svg/SkSVGFilter.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGFilter.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGFilter.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGFilter.h b/src/svg/SkSVGFilter.h
index 6ec9bd5..5891237 100644
--- a/src/svg/SkSVGFilter.h
+++ b/src/svg/SkSVGFilter.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGFilter.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGFilter_DEFINED
#define SkSVGFilter_DEFINED
diff --git a/src/svg/SkSVGG.cpp b/src/svg/SkSVGG.cpp
index f73b8b8..21a7aa8 100644
--- a/src/svg/SkSVGG.cpp
+++ b/src/svg/SkSVGG.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGG.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGG.h"
diff --git a/src/svg/SkSVGG.h b/src/svg/SkSVGG.h
index 4c5c68a..4fa27d2 100644
--- a/src/svg/SkSVGG.h
+++ b/src/svg/SkSVGG.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGG.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGG_DEFINED
#define SkSVGG_DEFINED
diff --git a/src/svg/SkSVGGradient.cpp b/src/svg/SkSVGGradient.cpp
index c89bdc9..27964e7 100644
--- a/src/svg/SkSVGGradient.cpp
+++ b/src/svg/SkSVGGradient.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGGradient.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGGradient.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGGradient.h b/src/svg/SkSVGGradient.h
index 873b258..286ff18 100644
--- a/src/svg/SkSVGGradient.h
+++ b/src/svg/SkSVGGradient.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGGradient.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGGradient_DEFINED
#define SkSVGGradient_DEFINED
diff --git a/src/svg/SkSVGGroup.cpp b/src/svg/SkSVGGroup.cpp
index 069aa56..420179d 100644
--- a/src/svg/SkSVGGroup.cpp
+++ b/src/svg/SkSVGGroup.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGGroup.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGGroup.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGGroup.h b/src/svg/SkSVGGroup.h
index 2e34cbb..f579a98 100644
--- a/src/svg/SkSVGGroup.h
+++ b/src/svg/SkSVGGroup.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGGroup.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGGroup_DEFINED
#define SkSVGGroup_DEFINED
diff --git a/src/svg/SkSVGImage.cpp b/src/svg/SkSVGImage.cpp
index b641c9f..97b8df8 100644
--- a/src/svg/SkSVGImage.cpp
+++ b/src/svg/SkSVGImage.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGImage.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGImage.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGImage.h b/src/svg/SkSVGImage.h
index 2f73b0d..b63beef 100644
--- a/src/svg/SkSVGImage.h
+++ b/src/svg/SkSVGImage.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGImage.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGImage_DEFINED
#define SkSVGImage_DEFINED
diff --git a/src/svg/SkSVGLine.cpp b/src/svg/SkSVGLine.cpp
index 105822a..9158c99 100644
--- a/src/svg/SkSVGLine.cpp
+++ b/src/svg/SkSVGLine.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGLine.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGLine.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGLine.h b/src/svg/SkSVGLine.h
index f2cfce9..3e437e0 100644
--- a/src/svg/SkSVGLine.h
+++ b/src/svg/SkSVGLine.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGLine.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGLine_DEFINED
#define SkSVGLine_DEFINED
diff --git a/src/svg/SkSVGLinearGradient.cpp b/src/svg/SkSVGLinearGradient.cpp
index a474d15..f89ee53 100644
--- a/src/svg/SkSVGLinearGradient.cpp
+++ b/src/svg/SkSVGLinearGradient.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGLinearGradient.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGLinearGradient.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGLinearGradient.h b/src/svg/SkSVGLinearGradient.h
index 85e28e7..8eda065 100644
--- a/src/svg/SkSVGLinearGradient.h
+++ b/src/svg/SkSVGLinearGradient.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGLinearGradient.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGLinearGradient_DEFINED
#define SkSVGLinearGradient_DEFINED
diff --git a/src/svg/SkSVGMask.cpp b/src/svg/SkSVGMask.cpp
index eb93118..7526d18 100644
--- a/src/svg/SkSVGMask.cpp
+++ b/src/svg/SkSVGMask.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGMask.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGMask.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGMask.h b/src/svg/SkSVGMask.h
index 6e349b4..2e1fd50 100644
--- a/src/svg/SkSVGMask.h
+++ b/src/svg/SkSVGMask.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGMask.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGMask_DEFINED
#define SkSVGMask_DEFINED
diff --git a/src/svg/SkSVGMetadata.cpp b/src/svg/SkSVGMetadata.cpp
index 7c9e6ba..0f8850e 100644
--- a/src/svg/SkSVGMetadata.cpp
+++ b/src/svg/SkSVGMetadata.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGMetadata.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGMetadata.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGMetadata.h b/src/svg/SkSVGMetadata.h
index f3b5b6c..2dcb3a2 100644
--- a/src/svg/SkSVGMetadata.h
+++ b/src/svg/SkSVGMetadata.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGMetadata.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGMetadata_DEFINED
#define SkSVGMetadata_DEFINED
diff --git a/src/svg/SkSVGPaintState.cpp b/src/svg/SkSVGPaintState.cpp
index f3c65e7..1a30cb8 100644
--- a/src/svg/SkSVGPaintState.cpp
+++ b/src/svg/SkSVGPaintState.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGPaintState.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGPaintState.h"
#include "SkSVGElements.h"
diff --git a/src/svg/SkSVGParser.cpp b/src/svg/SkSVGParser.cpp
index f4ad198..c8712b4 100644
--- a/src/svg/SkSVGParser.cpp
+++ b/src/svg/SkSVGParser.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGParser.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGParser.h"
#include "SkSVGCircle.h"
@@ -90,6 +82,7 @@ int SkSVGParser::findAttribute(SkSVGBase* element, const char* attrValue,
return -1;
}
+#if 0
const char* SkSVGParser::getFinal() {
_startElement("screenplay");
// generate defs
@@ -114,6 +107,7 @@ const char* SkSVGParser::getFinal() {
fStream.write("", 1);
return fStream.getStream();
}
+#endif
SkString& SkSVGParser::getPaintLast(SkSVGPaint::Field field) {
SkSVGPaint* state = fHead;
diff --git a/src/svg/SkSVGPath.cpp b/src/svg/SkSVGPath.cpp
index a916c30..92f5b14 100644
--- a/src/svg/SkSVGPath.cpp
+++ b/src/svg/SkSVGPath.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGPath.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGPath.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGPath.h b/src/svg/SkSVGPath.h
index 8a0c210..de325a7 100644
--- a/src/svg/SkSVGPath.h
+++ b/src/svg/SkSVGPath.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGPath.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGPath_DEFINED
#define SkSVGPath_DEFINED
diff --git a/src/svg/SkSVGPolygon.cpp b/src/svg/SkSVGPolygon.cpp
index 283422c..97cf5e0 100644
--- a/src/svg/SkSVGPolygon.cpp
+++ b/src/svg/SkSVGPolygon.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGPolygon.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGPolygon.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGPolygon.h b/src/svg/SkSVGPolygon.h
index 1f27c5c..d353764 100644
--- a/src/svg/SkSVGPolygon.h
+++ b/src/svg/SkSVGPolygon.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGPolygon.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGPolygon_DEFINED
#define SkSVGPolygon_DEFINED
diff --git a/src/svg/SkSVGPolyline.cpp b/src/svg/SkSVGPolyline.cpp
index 8432c95..fe83c04 100644
--- a/src/svg/SkSVGPolyline.cpp
+++ b/src/svg/SkSVGPolyline.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGPolyline.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGPolyline.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGPolyline.h b/src/svg/SkSVGPolyline.h
index 7f25129..62dc417 100644
--- a/src/svg/SkSVGPolyline.h
+++ b/src/svg/SkSVGPolyline.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGPolyline.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGPolyline_DEFINED
#define SkSVGPolyline_DEFINED
diff --git a/src/svg/SkSVGRadialGradient.cpp b/src/svg/SkSVGRadialGradient.cpp
index bba8b94..4fdf432 100644
--- a/src/svg/SkSVGRadialGradient.cpp
+++ b/src/svg/SkSVGRadialGradient.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGRadialGradient.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGRadialGradient.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGRadialGradient.h b/src/svg/SkSVGRadialGradient.h
index 5b04186..8eba3f5 100644
--- a/src/svg/SkSVGRadialGradient.h
+++ b/src/svg/SkSVGRadialGradient.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGRadialGradient.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGRadialGradient_DEFINED
#define SkSVGRadialGradient_DEFINED
diff --git a/src/svg/SkSVGRect.cpp b/src/svg/SkSVGRect.cpp
index 8765d1d..32a7f99 100644
--- a/src/svg/SkSVGRect.cpp
+++ b/src/svg/SkSVGRect.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGRect.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGRect.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGRect.h b/src/svg/SkSVGRect.h
index d06372b..4ae820c 100644
--- a/src/svg/SkSVGRect.h
+++ b/src/svg/SkSVGRect.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGRect.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGRect_DEFINED
#define SkSVGRect_DEFINED
diff --git a/src/svg/SkSVGSVG.cpp b/src/svg/SkSVGSVG.cpp
index 9423c3a..a072d09 100644
--- a/src/svg/SkSVGSVG.cpp
+++ b/src/svg/SkSVGSVG.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGSVG.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGSVG.h"
#include "SkParse.h"
diff --git a/src/svg/SkSVGSVG.h b/src/svg/SkSVGSVG.h
index 257c136..7d1e16a 100644
--- a/src/svg/SkSVGSVG.h
+++ b/src/svg/SkSVGSVG.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGSVG.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGSVG_DEFINED
#define SkSVGSVG_DEFINED
diff --git a/src/svg/SkSVGStop.cpp b/src/svg/SkSVGStop.cpp
index 0d1d76c..0630f61 100644
--- a/src/svg/SkSVGStop.cpp
+++ b/src/svg/SkSVGStop.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGStop.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGStop.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGStop.h b/src/svg/SkSVGStop.h
index dd11d18..e55936b 100644
--- a/src/svg/SkSVGStop.h
+++ b/src/svg/SkSVGStop.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGStop.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGStop_DEFINED
#define SkSVGStop_DEFINED
diff --git a/src/svg/SkSVGSymbol.cpp b/src/svg/SkSVGSymbol.cpp
index f8729d7..a988467 100644
--- a/src/svg/SkSVGSymbol.cpp
+++ b/src/svg/SkSVGSymbol.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGSymbol.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGSymbol.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGSymbol.h b/src/svg/SkSVGSymbol.h
index c1439dc..80fd61a 100644
--- a/src/svg/SkSVGSymbol.h
+++ b/src/svg/SkSVGSymbol.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGSymbol.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGSymbol_DEFINED
#define SkSVGSymbol_DEFINED
diff --git a/src/svg/SkSVGText.cpp b/src/svg/SkSVGText.cpp
index 1c18a74..dfaba08 100644
--- a/src/svg/SkSVGText.cpp
+++ b/src/svg/SkSVGText.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGText.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGText.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGText.h b/src/svg/SkSVGText.h
index 98b0155..5ac2fbd 100644
--- a/src/svg/SkSVGText.h
+++ b/src/svg/SkSVGText.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGText.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGText_DEFINED
#define SkSVGText_DEFINED
diff --git a/src/svg/SkSVGUse.cpp b/src/svg/SkSVGUse.cpp
index ba7b256..0496d98 100644
--- a/src/svg/SkSVGUse.cpp
+++ b/src/svg/SkSVGUse.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGUse.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkSVGUse.h"
#include "SkSVGParser.h"
diff --git a/src/svg/SkSVGUse.h b/src/svg/SkSVGUse.h
index ff85ce6..b907189 100644
--- a/src/svg/SkSVGUse.h
+++ b/src/svg/SkSVGUse.h
@@ -1,19 +1,11 @@
-/* libs/graphics/svg/SkSVGUse.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkSVGUse_DEFINED
#define SkSVGUse_DEFINED
diff --git a/src/text/SkTextLayout.cpp b/src/text/SkTextLayout.cpp
index 09b3acd..fda4b2f 100644
--- a/src/text/SkTextLayout.cpp
+++ b/src/text/SkTextLayout.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkTextLayout.h"
SkTextStyle::SkTextStyle() {
diff --git a/src/utils/SkBoundaryPatch.cpp b/src/utils/SkBoundaryPatch.cpp
index cdbc877..37f59b4 100644
--- a/src/utils/SkBoundaryPatch.cpp
+++ b/src/utils/SkBoundaryPatch.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBoundaryPatch.h"
SkBoundaryPatch::SkBoundaryPatch() : fBoundary(NULL) {}
diff --git a/src/utils/SkCamera.cpp b/src/utils/SkCamera.cpp
index 3e7315b..a387257 100644
--- a/src/utils/SkCamera.cpp
+++ b/src/utils/SkCamera.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/effects/SkCamera.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkCamera.h"
@@ -370,7 +362,7 @@ void Sk3DView::restore() {
fRec = next;
}
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
void Sk3DView::setCameraLocation(SkScalar x, SkScalar y, SkScalar z) {
// the camera location is passed in inches, set in pt
SkScalar lz = z * SkFloatToScalar(72.0f);
diff --git a/src/utils/SkColorMatrix.cpp b/src/utils/SkColorMatrix.cpp
index e61c1cc..cb77de1 100644
--- a/src/utils/SkColorMatrix.cpp
+++ b/src/utils/SkColorMatrix.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkColorMatrix.h"
#define kRScale 0
diff --git a/src/utils/SkCubicInterval.cpp b/src/utils/SkCubicInterval.cpp
index 7a6084c..6c6b0a9 100644
--- a/src/utils/SkCubicInterval.cpp
+++ b/src/utils/SkCubicInterval.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkCubicInterval.h"
static SkScalar eval_cubic(SkScalar c1, SkScalar c2, SkScalar c3,
diff --git a/src/utils/SkCullPoints.cpp b/src/utils/SkCullPoints.cpp
index c8d58c1..a903075 100644
--- a/src/utils/SkCullPoints.cpp
+++ b/src/utils/SkCullPoints.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/effects/SkCullPoints.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkCullPoints.h"
#include "Sk64.h"
diff --git a/src/utils/SkDebugTrace.h b/src/utils/SkDebugTrace.h
new file mode 100644
index 0000000..447418e
--- /dev/null
+++ b/src/utils/SkDebugTrace.h
@@ -0,0 +1,26 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkUserTrace_DEFINED
+#define SkUserTrace_DEFINED
+
+/* Sample implementation of SkUserTrace that routes all of the
+ trace macros to debug output stream.
+ To use this, redefine SK_USER_TRACE_INCLUDE_FILE in
+ include/config/SkUserConfig.h to point to this file
+*/
+#define SK_TRACE_EVENT0(event) \
+ SkDebugf("Trace: %s\n", event)
+#define SK_TRACE_EVENT1(event, name1, value1) \
+ SkDebugf("Trace: %s (%s=%s)\n", event, name1, value1)
+#define SK_TRACE_EVENT2(event, name1, value1, name2, value2) \
+ SkDebugf("Trace: %s (%s=%s, %s=%s)\n", event, name1, value1, name2, value2)
+
+#endif
+
+
diff --git a/src/utils/SkDumpCanvas.cpp b/src/utils/SkDumpCanvas.cpp
index 223a4f7..db62498 100644
--- a/src/utils/SkDumpCanvas.cpp
+++ b/src/utils/SkDumpCanvas.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkDumpCanvas.h"
#include "SkPicture.h"
#include "SkPixelRef.h"
@@ -226,18 +233,24 @@ void SkDumpCanvas::setMatrix(const SkMatrix& matrix) {
///////////////////////////////////////////////////////////////////////////////
-bool SkDumpCanvas::clipRect(const SkRect& rect, SkRegion::Op op) {
+static const char* bool_to_aastring(bool doAA) {
+ return doAA ? "AA" : "BW";
+}
+
+bool SkDumpCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
SkString str;
toString(rect, &str);
- this->dump(kClip_Verb, NULL, "clipRect(%s %s)", str.c_str(), toString(op));
- return this->INHERITED::clipRect(rect, op);
+ this->dump(kClip_Verb, NULL, "clipRect(%s %s %s)", str.c_str(), toString(op),
+ bool_to_aastring(doAA));
+ return this->INHERITED::clipRect(rect, op, doAA);
}
-bool SkDumpCanvas::clipPath(const SkPath& path, SkRegion::Op op) {
+bool SkDumpCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
SkString str;
toString(path, &str);
- this->dump(kClip_Verb, NULL, "clipPath(%s %s)", str.c_str(), toString(op));
- return this->INHERITED::clipPath(path, op);
+ this->dump(kClip_Verb, NULL, "clipPath(%s %s %s)", str.c_str(), toString(op),
+ bool_to_aastring(doAA));
+ return this->INHERITED::clipPath(path, op, doAA);
}
bool SkDumpCanvas::clipRegion(const SkRegion& deviceRgn, SkRegion::Op op) {
@@ -351,14 +364,6 @@ void SkDumpCanvas::drawTextOnPath(const void* text, size_t byteLength,
str.c_str(), byteLength);
}
-void SkDumpCanvas::drawShape(SkShape* shape) {
- this->dump(kDrawShape_Verb, NULL, "drawShape(%p)", shape);
- fNestLevel += 1;
- this->INHERITED::drawShape(shape);
- fNestLevel -= 1;
- this->dump(kDrawShape_Verb, NULL, "endShape(%p)", shape);
-}
-
void SkDumpCanvas::drawPicture(SkPicture& picture) {
this->dump(kDrawPicture_Verb, NULL, "drawPicture(%p) %d:%d", &picture,
picture.width(), picture.height());
diff --git a/src/utils/SkEGLContext_none.cpp b/src/utils/SkEGLContext_none.cpp
deleted file mode 100644
index cb08f40..0000000
--- a/src/utils/SkEGLContext_none.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "SkEGLContext.h"
-
-SkEGLContext::SkEGLContext() {
-}
-
-SkEGLContext::~SkEGLContext() {
-}
-
-bool SkEGLContext::init(int width, int height) {
- return false;
-}
diff --git a/src/utils/SkInterpolator.cpp b/src/utils/SkInterpolator.cpp
index c5bb448..d43792f 100644
--- a/src/utils/SkInterpolator.cpp
+++ b/src/utils/SkInterpolator.cpp
@@ -1,19 +1,12 @@
+
/*
- * Copyright (C) 2006-2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Copyright 2008 The Android Open Source Project
*
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkInterpolator.h"
#include "SkMath.h"
#include "SkTSearch.h"
diff --git a/src/utils/SkJSON.cpp b/src/utils/SkJSON.cpp
new file mode 100644
index 0000000..c55d464
--- /dev/null
+++ b/src/utils/SkJSON.cpp
@@ -0,0 +1,637 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkJSON.h"
+#include "SkString.h"
+
+#ifdef SK_DEBUG
+// #define TRACE_SKJSON_LEAKS
+#endif
+
+#ifdef TRACE_SKJSON_LEAKS
+ static int gStringCount;
+ static int gSlotCount;
+ static int gObjectCount;
+ static int gArrayCount;
+ #define LEAK_CODE(code) code
+#else
+ #define LEAK_CODE(code)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+static char* alloc_string(size_t len) {
+ LEAK_CODE(SkDebugf(" string[%d]\n", gStringCount++);)
+ char* str = (char*)sk_malloc_throw(len + 1);
+ str[len] = 0;
+ return str;
+}
+
+static char* dup_string(const char src[]) {
+ if (NULL == src) {
+ return NULL;
+ }
+ size_t len = strlen(src);
+ char* dst = alloc_string(len);
+ memcpy(dst, src, len);
+ return dst;
+}
+
+static void free_string(char* str) {
+ if (str) {
+ sk_free(str);
+ LEAK_CODE(SkASSERT(gStringCount > 0); SkDebugf("~string[%d]\n", --gStringCount);)
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct SkJSON::Object::Slot {
+ Slot(const char name[], Type type) {
+ LEAK_CODE(SkDebugf(" slot[%d]\n", gSlotCount++);)
+ SkASSERT(name);
+
+ fNext = NULL;
+
+ size_t len = strlen(name);
+ // extra 1 for str[0] which stores the type
+ char* str = alloc_string(1 + len);
+ str[0] = (char)type;
+ // str[1] skips the type, len+1 includes the terminating 0 byte.
+ memcpy(&str[1], name, len + 1);
+ fName = str;
+
+ // fValue is uninitialized
+ }
+ ~Slot();
+
+ Type type() const { return (Type)fName[0]; }
+ const char* name() const { return &fName[1]; }
+
+ Slot* fNext;
+ char* fName; // fName[0] is the type, &fName[1] is the "name"
+ union {
+ Object* fObject;
+ Array* fArray;
+ char* fString;
+ int32_t fInt;
+ float fFloat;
+ bool fBool;
+ } fValue;
+};
+
+SkJSON::Object::Slot::~Slot() {
+ free_string(fName);
+ switch (this->type()) {
+ case kObject:
+ delete fValue.fObject;
+ break;
+ case kArray:
+ delete fValue.fArray;
+ break;
+ case kString:
+ free_string(fValue.fString);
+ break;
+ default:
+ break;
+ }
+ LEAK_CODE(SkASSERT(gSlotCount > 0); SkDebugf("~slot[%d]\n", --gSlotCount);)
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkJSON::Object::Iter::Iter(const Object& obj) : fSlot(obj.fHead) {}
+
+bool SkJSON::Object::Iter::done() const {
+ return NULL == fSlot;
+}
+
+void SkJSON::Object::Iter::next() {
+ SkASSERT(fSlot);
+ fSlot = fSlot->fNext;
+}
+
+SkJSON::Type SkJSON::Object::Iter::type() const {
+ SkASSERT(fSlot);
+ return fSlot->type();
+}
+
+const char* SkJSON::Object::Iter::name() const {
+ SkASSERT(fSlot);
+ return fSlot->name();
+}
+
+SkJSON::Object* SkJSON::Object::Iter::objectValue() const {
+ SkASSERT(fSlot);
+ SkASSERT(kObject == fSlot->type());
+ return fSlot->fValue.fObject;
+}
+
+SkJSON::Array* SkJSON::Object::Iter::arrayValue() const {
+ SkASSERT(fSlot);
+ SkASSERT(kArray == fSlot->type());
+ return fSlot->fValue.fArray;
+}
+
+const char* SkJSON::Object::Iter::stringValue() const {
+ SkASSERT(fSlot);
+ SkASSERT(kString == fSlot->type());
+ return fSlot->fValue.fString;
+}
+
+int32_t SkJSON::Object::Iter::intValue() const {
+ SkASSERT(fSlot);
+ SkASSERT(kInt == fSlot->type());
+ return fSlot->fValue.fInt;
+}
+
+float SkJSON::Object::Iter::floatValue() const {
+ SkASSERT(fSlot);
+ SkASSERT(kFloat == fSlot->type());
+ return fSlot->fValue.fFloat;
+}
+
+bool SkJSON::Object::Iter::boolValue() const {
+ SkASSERT(fSlot);
+ SkASSERT(kBool == fSlot->type());
+ return fSlot->fValue.fBool;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkJSON::Object::Object() : fHead(NULL), fTail(NULL) {
+ LEAK_CODE(SkDebugf(" object[%d]\n", gObjectCount++);)
+}
+
+SkJSON::Object::Object(const Object& other) : fHead(NULL), fTail(NULL) {
+ LEAK_CODE(SkDebugf(" object[%d]\n", gObjectCount++);)
+
+ Iter iter(other);
+ while (!iter.done()) {
+ switch (iter.type()) {
+ case kObject:
+ this->addObject(iter.name(), new Object(*iter.objectValue()));
+ break;
+ case kArray:
+ this->addArray(iter.name(), new Array(*iter.arrayValue()));
+ break;
+ case kString:
+ this->addString(iter.name(), dup_string(iter.stringValue()));
+ break;
+ case kInt:
+ this->addInt(iter.name(), iter.intValue());
+ break;
+ case kFloat:
+ this->addFloat(iter.name(), iter.floatValue());
+ break;
+ case kBool:
+ this->addBool(iter.name(), iter.boolValue());
+ break;
+ }
+ iter.next();
+ }
+}
+
+SkJSON::Object::~Object() {
+ Slot* slot = fHead;
+ while (slot) {
+ Slot* next = slot->fNext;
+ delete slot;
+ slot = next;
+ }
+ LEAK_CODE(SkASSERT(gObjectCount > 0); SkDebugf("~object[%d]\n", --gObjectCount);)
+}
+
+int SkJSON::Object::count() const {
+ int n = 0;
+ for (const Slot* slot = fHead; slot; slot = slot->fNext) {
+ n += 1;
+ }
+ return n;
+}
+
+SkJSON::Object::Slot* SkJSON::Object::addSlot(Slot* slot) {
+ SkASSERT(NULL == slot->fNext);
+ if (NULL == fHead) {
+ SkASSERT(NULL == fTail);
+ fHead = fTail = slot;
+ } else {
+ SkASSERT(fTail);
+ SkASSERT(NULL == fTail->fNext);
+ fTail->fNext = slot;
+ fTail = slot;
+ }
+ return slot;
+}
+
+void SkJSON::Object::addObject(const char name[], SkJSON::Object* value) {
+ this->addSlot(new Slot(name, kObject))->fValue.fObject = value;
+}
+
+void SkJSON::Object::addArray(const char name[], SkJSON::Array* value) {
+ this->addSlot(new Slot(name, kArray))->fValue.fArray = value;
+}
+
+void SkJSON::Object::addString(const char name[], const char value[]) {
+ this->addSlot(new Slot(name, kString))->fValue.fString = dup_string(value);
+}
+
+void SkJSON::Object::addInt(const char name[], int32_t value) {
+ this->addSlot(new Slot(name, kInt))->fValue.fInt = value;
+}
+
+void SkJSON::Object::addFloat(const char name[], float value) {
+ this->addSlot(new Slot(name, kFloat))->fValue.fFloat = value;
+}
+
+void SkJSON::Object::addBool(const char name[], bool value) {
+ this->addSlot(new Slot(name, kBool))->fValue.fBool = value;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+const SkJSON::Object::Slot* SkJSON::Object::findSlot(const char name[],
+ Type t) const {
+ for (const Slot* slot = fHead; slot; slot = slot->fNext) {
+ if (t == slot->type() && !strcmp(slot->name(), name)) {
+ return slot;
+ }
+ }
+ return NULL;
+}
+
+bool SkJSON::Object::find(const char name[], Type t) const {
+ return this->findSlot(name, t) != NULL;
+}
+
+bool SkJSON::Object::findObject(const char name[], SkJSON::Object** value) const {
+ const Slot* slot = this->findSlot(name, kObject);
+ if (slot) {
+ if (value) {
+ *value = slot->fValue.fObject;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool SkJSON::Object::findArray(const char name[], SkJSON::Array** value) const {
+ const Slot* slot = this->findSlot(name, kArray);
+ if (slot) {
+ if (value) {
+ *value = slot->fValue.fArray;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool SkJSON::Object::findString(const char name[], SkString* value) const {
+ const Slot* slot = this->findSlot(name, kString);
+ if (slot) {
+ if (value) {
+ value->set(slot->fValue.fString);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool SkJSON::Object::findInt(const char name[], int32_t* value) const {
+ const Slot* slot = this->findSlot(name, kInt);
+ if (slot) {
+ if (value) {
+ *value = slot->fValue.fInt;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool SkJSON::Object::findFloat(const char name[], float* value) const {
+ const Slot* slot = this->findSlot(name, kFloat);
+ if (slot) {
+ if (value) {
+ *value = slot->fValue.fFloat;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool SkJSON::Object::findBool(const char name[], bool* value) const {
+ const Slot* slot = this->findSlot(name, kBool);
+ if (slot) {
+ if (value) {
+ *value = slot->fValue.fBool;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool SkJSON::Object::remove(const char name[], Type t) {
+ SkDEBUGCODE(int count = this->count();)
+ Slot* prev = NULL;
+ Slot* slot = fHead;
+ while (slot) {
+ Slot* next = slot->fNext;
+ if (t == slot->type() && !strcmp(slot->name(), name)) {
+ if (prev) {
+ SkASSERT(fHead != slot);
+ prev->fNext = next;
+ } else {
+ SkASSERT(fHead == slot);
+ fHead = next;
+ }
+ if (fTail == slot) {
+ fTail = prev;
+ }
+ delete slot;
+ SkASSERT(count - 1 == this->count());
+ return true;
+ }
+ prev = slot;
+ slot = next;
+ }
+ SkASSERT(count == this->count());
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void tabForLevel(int level) {
+ for (int i = 0; i < level; ++i) {
+ SkDebugf(" ");
+ }
+}
+
+void SkJSON::Object::toDebugf() const {
+ SkDebugf("{\n");
+ this->dumpLevel(0);
+ SkDebugf("}\n");
+}
+
+void SkJSON::Object::dumpLevel(int level) const {
+ for (Slot* slot = fHead; slot; slot = slot->fNext) {
+ Type t = slot->type();
+ tabForLevel(level + 1);
+ SkDebugf("\"%s\" : ", slot->name());
+ switch (slot->type()) {
+ case kObject:
+ if (slot->fValue.fObject) {
+ SkDebugf("{\n");
+ slot->fValue.fObject->dumpLevel(level + 1);
+ tabForLevel(level + 1);
+ SkDebugf("}");
+ } else {
+ SkDebugf("null");
+ }
+ break;
+ case kArray:
+ if (slot->fValue.fArray) {
+ SkDebugf("[");
+ slot->fValue.fArray->dumpLevel(level + 1);
+ SkDebugf("]");
+ } else {
+ SkDebugf("null");
+ }
+ break;
+ case kString:
+ SkDebugf("\"%s\"", slot->fValue.fString);
+ break;
+ case kInt:
+ SkDebugf("%d", slot->fValue.fInt);
+ break;
+ case kFloat:
+ SkDebugf("%g", slot->fValue.fFloat);
+ break;
+ case kBool:
+ SkDebugf("%s", slot->fValue.fBool ? "true" : "false");
+ break;
+ default:
+ SkASSERT(!"how did I get here");
+ break;
+ }
+ if (slot->fNext) {
+ SkDebugf(",");
+ }
+ SkDebugf("\n");
+ }
+}
+
+void SkJSON::Array::dumpLevel(int level) const {
+ if (0 == fCount) {
+ return;
+ }
+ int last = fCount - 1;
+
+ switch (this->type()) {
+ case kObject: {
+ SkDebugf("\n");
+ for (int i = 0; i <= last; ++i) {
+ Object* obj = fArray.fObjects[i];
+ tabForLevel(level + 1);
+ if (obj) {
+ SkDebugf("{\n");
+ obj->dumpLevel(level + 1);
+ tabForLevel(level + 1);
+ SkDebugf(i < last ? "}," : "}");
+ } else {
+ SkDebugf(i < last ? "null," : "null");
+ }
+ SkDebugf("\n");
+ }
+ } break;
+ case kArray: {
+ SkDebugf("\n");
+ for (int i = 0; i <= last; ++i) {
+ Array* array = fArray.fArrays[i];
+ tabForLevel(level + 1);
+ if (array) {
+ SkDebugf("[");
+ array->dumpLevel(level + 1);
+ tabForLevel(level + 1);
+ SkDebugf(i < last ? "]," : "]");
+ } else {
+ SkDebugf(i < last ? "null," : "null");
+ }
+ SkDebugf("\n");
+ }
+ } break;
+ case kString: {
+ for (int i = 0; i < last; ++i) {
+ const char* str = fArray.fStrings[i];
+ SkDebugf(str ? " \"%s\"," : " null,", str);
+ }
+ const char* str = fArray.fStrings[last];
+ SkDebugf(str ? " \"%s\" " : " null ", str);
+ } break;
+ case kInt: {
+ for (int i = 0; i < last; ++i) {
+ SkDebugf(" %d,", fArray.fInts[i]);
+ }
+ SkDebugf(" %d ", fArray.fInts[last]);
+ } break;
+ case kFloat: {
+ for (int i = 0; i < last; ++i) {
+ SkDebugf(" %g,", fArray.fFloats[i]);
+ }
+ SkDebugf(" %g ", fArray.fFloats[last]);
+ } break;
+ case kBool: {
+ for (int i = 0; i < last; ++i) {
+ SkDebugf(" %s,", fArray.fBools[i] ? "true" : "false");
+ }
+ SkDebugf(" %s ", fArray.fInts[last] ? "true" : "false");
+ } break;
+ default:
+ SkASSERT(!"unsupported array type");
+ break;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static const uint8_t gBytesPerType[] = {
+ sizeof(SkJSON::Object*),
+ sizeof(SkJSON::Array*),
+ sizeof(char*),
+ sizeof(int32_t),
+ sizeof(float),
+ sizeof(bool)
+};
+
+typedef void* (*DupProc)(const void*);
+
+static void* dup_object(const void* src) {
+ return SkNEW_ARGS(SkJSON::Object, (*(SkJSON::Object*)src));
+}
+
+static void* dup_array(const void* src) {
+ return SkNEW_ARGS(SkJSON::Array, (*(SkJSON::Array*)src));
+}
+
+static const DupProc gDupProcs[] = {
+ dup_object, // Object
+ dup_array, // Array
+ (DupProc)dup_string, // String
+ NULL, // int
+ NULL, // float
+ NULL, // bool
+};
+
+void SkJSON::Array::init(Type type, int count, const void* src) {
+ LEAK_CODE(SkDebugf(" array[%d]\n", gArrayCount++);)
+
+ SkASSERT((unsigned)type < SK_ARRAY_COUNT(gBytesPerType));
+
+ if (count < 0) {
+ count = 0;
+ }
+ size_t size = count * gBytesPerType[type];
+
+ fCount = count;
+ fType = type;
+ fArray.fVoids = sk_malloc_throw(size);
+ if (src) {
+ DupProc proc = gDupProcs[fType];
+ if (!proc) {
+ memcpy(fArray.fVoids, src, size);
+ } else {
+ void** srcPtr = (void**)src;
+ void** dstPtr = (void**)fArray.fVoids;
+ for (int i = 0; i < fCount; ++i) {
+ dstPtr[i] = proc(srcPtr[i]);
+ }
+ }
+ } else {
+ sk_bzero(fArray.fVoids, size);
+ }
+}
+
+SkJSON::Array::Array(Type type, int count) {
+ this->init(type, count, NULL);
+}
+
+SkJSON::Array::Array(const int32_t values[], int count) {
+ this->init(kInt, count, values);
+}
+
+SkJSON::Array::Array(const float values[], int count) {
+ this->init(kFloat, count, values);
+}
+
+SkJSON::Array::Array(const bool values[], int count) {
+ this->init(kBool, count, values);
+}
+
+SkJSON::Array::Array(const Array& other) {
+ this->init(other.type(), other.count(), other.fArray.fVoids);
+}
+
+typedef void (*FreeProc)(void*);
+
+static void free_object(void* obj) {
+ delete (SkJSON::Object*)obj;
+}
+
+static void free_array(void* array) {
+ delete (SkJSON::Array*)array;
+}
+
+static const FreeProc gFreeProcs[] = {
+ free_object, // Object
+ free_array, // Array
+ (FreeProc)free_string, // String
+ NULL, // int
+ NULL, // float
+ NULL, // bool
+};
+
+SkJSON::Array::~Array() {
+ FreeProc proc = gFreeProcs[fType];
+ if (proc) {
+ void** ptr = (void**)fArray.fVoids;
+ for (int i = 0; i < fCount; ++i) {
+ proc(ptr[i]);
+ }
+ }
+ sk_free(fArray.fVoids);
+
+ LEAK_CODE(SkASSERT(gArrayCount > 0); SkDebugf("~array[%d]\n", --gArrayCount);)
+}
+
+void SkJSON::Array::setObject(int index, Object* object) {
+ SkASSERT((unsigned)index < (unsigned)fCount);
+ Object*& prev = fArray.fObjects[index];
+ if (prev != object) {
+ delete prev;
+ prev = object;
+ }
+}
+
+void SkJSON::Array::setArray(int index, Array* array) {
+ SkASSERT((unsigned)index < (unsigned)fCount);
+ Array*& prev = fArray.fArrays[index];
+ if (prev != array) {
+ delete prev;
+ prev = array;
+ }
+}
+
+void SkJSON::Array::setString(int index, const char str[]) {
+ SkASSERT((unsigned)index < (unsigned)fCount);
+ char*& prev = fArray.fStrings[index];
+ if (prev != str) {
+ free_string(prev);
+ prev = dup_string(str);
+ }
+}
+
+
+
diff --git a/src/utils/SkLayer.cpp b/src/utils/SkLayer.cpp
index 1c484bd..aaca786 100644
--- a/src/utils/SkLayer.cpp
+++ b/src/utils/SkLayer.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkLayer.h"
#include "SkCanvas.h"
diff --git a/src/utils/SkMatrix44.cpp b/src/utils/SkMatrix44.cpp
new file mode 100644
index 0000000..f00e399
--- /dev/null
+++ b/src/utils/SkMatrix44.cpp
@@ -0,0 +1,393 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+
+#include "SkMatrix44.h"
+
+SkMatrix44::SkMatrix44() {
+ this->setIdentity();
+}
+
+SkMatrix44::SkMatrix44(const SkMatrix44& src) {
+ memcpy(this, &src, sizeof(src));
+}
+
+SkMatrix44::SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) {
+ this->setConcat(a, b);
+}
+
+SkMScalar SkMatrix44::get(int row, int col) const {
+ SkASSERT(row <= 3 && row >= 0);
+ SkASSERT(col <= 3 && col >= 0);
+ return fMat[col][row];
+}
+
+void SkMatrix44::set(int row, int col, const SkMScalar& value) {
+ SkASSERT(row <= 3 && row >= 0);
+ SkASSERT(col <= 3 && col >= 0);
+ fMat[col][row] = value;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkMatrix44::asColMajorf(float dst[]) const {
+ const SkMScalar* src = &fMat[0][0];
+#ifdef SK_MSCALAR_IS_DOUBLE
+ for (int i = 0; i < 16; ++i) {
+ dst[i] = SkMScalarToFloat(src[i]);
+ }
+#else
+ memcpy(dst, src, 16 * sizeof(float));
+#endif
+}
+
+void SkMatrix44::asColMajord(double dst[]) const {
+ const SkMScalar* src = &fMat[0][0];
+#ifdef SK_MSCALAR_IS_DOUBLE
+ memcpy(dst, src, 16 * sizeof(double));
+#else
+ for (int i = 0; i < 16; ++i) {
+ dst[i] = SkMScalarToDouble(src[i]);
+ }
+#endif
+}
+
+void SkMatrix44::asRowMajorf(float dst[]) const {
+ const SkMScalar* src = &fMat[0][0];
+ for (int i = 0; i < 4; ++i) {
+ dst[0] = SkMScalarToFloat(src[0]);
+ dst[4] = SkMScalarToFloat(src[1]);
+ dst[8] = SkMScalarToFloat(src[2]);
+ dst[12] = SkMScalarToFloat(src[3]);
+ src += 4;
+ dst += 1;
+ }
+}
+
+void SkMatrix44::asRowMajord(double dst[]) const {
+ const SkMScalar* src = &fMat[0][0];
+ for (int i = 0; i < 4; ++i) {
+ dst[0] = SkMScalarToDouble(src[0]);
+ dst[4] = SkMScalarToDouble(src[1]);
+ dst[8] = SkMScalarToDouble(src[2]);
+ dst[12] = SkMScalarToDouble(src[3]);
+ src += 4;
+ dst += 1;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool SkMatrix44::isIdentity() const {
+ static const SkMScalar sIdentityMat[4][4] = {
+ { 1, 0, 0, 0 },
+ { 0, 1, 0, 0 },
+ { 0, 0, 1, 0 },
+ { 0, 0, 0, 1 },
+ };
+ return !memcmp(fMat, sIdentityMat, sizeof(fMat));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkMatrix44::setIdentity() {
+ sk_bzero(fMat, sizeof(fMat));
+ fMat[0][0] = fMat[1][1] = fMat[2][2] = fMat[3][3] = 1;
+}
+
+void SkMatrix44::set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
+ SkMScalar m10, SkMScalar m11, SkMScalar m12,
+ SkMScalar m20, SkMScalar m21, SkMScalar m22) {
+ sk_bzero(fMat, sizeof(fMat));
+ fMat[0][0] = m00; fMat[0][1] = m01; fMat[0][2] = m02; fMat[0][3] = 0;
+ fMat[1][0] = m10; fMat[1][1] = m11; fMat[1][2] = m12; fMat[1][3] = 0;
+ fMat[2][0] = m20; fMat[2][1] = m21; fMat[2][2] = m22; fMat[2][3] = 0;
+ fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkMatrix44::setTranslate(SkMScalar tx, SkMScalar ty, SkMScalar tz) {
+ this->setIdentity();
+ fMat[3][0] = tx;
+ fMat[3][1] = ty;
+ fMat[3][2] = tz;
+ fMat[3][3] = 1;
+}
+
+void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
+ SkMatrix44 mat;
+ mat.setTranslate(dx, dy, dz);
+ this->preConcat(mat);
+}
+
+void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
+ fMat[3][0] += dx;
+ fMat[3][1] += dy;
+ fMat[3][2] += dz;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
+ sk_bzero(fMat, sizeof(fMat));
+ fMat[0][0] = sx;
+ fMat[1][1] = sy;
+ fMat[2][2] = sz;
+ fMat[3][3] = 1;
+}
+
+void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
+ SkMatrix44 tmp;
+ tmp.setScale(sx, sy, sz);
+ this->preConcat(tmp);
+}
+
+void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
+ for (int i = 0; i < 4; i++) {
+ fMat[i][0] *= sx;
+ fMat[i][1] *= sy;
+ fMat[i][2] *= sz;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
+ SkMScalar radians) {
+ double len2 = x * x + y * y + z * z;
+ if (len2 != 1) {
+ if (len2 == 0) {
+ this->setIdentity();
+ return;
+ }
+ double scale = 1 / sqrt(len2);
+ x = SkDoubleToMScalar(x * scale);
+ y = SkDoubleToMScalar(y * scale);
+ z = SkDoubleToMScalar(z * scale);
+ }
+ this->setRotateAboutUnit(x, y, z, radians);
+}
+
+void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
+ SkMScalar radians) {
+ double c = cos(radians);
+ double s = sin(radians);
+ double C = 1 - c;
+ double xs = x * s;
+ double ys = y * s;
+ double zs = z * s;
+ double xC = x * C;
+ double yC = y * C;
+ double zC = z * C;
+ double xyC = x * yC;
+ double yzC = y * zC;
+ double zxC = z * xC;
+
+ // if you're looking at wikipedia, remember that we're column major.
+ this->set3x3(SkDoubleToMScalar(x * xC + c), // scale x
+ SkDoubleToMScalar(xyC + zs), // skew x
+ SkDoubleToMScalar(zxC - ys), // trans x
+
+ SkDoubleToMScalar(xyC - zs), // skew y
+ SkDoubleToMScalar(y * yC + c), // scale y
+ SkDoubleToMScalar(yzC + xs), // trans y
+
+ SkDoubleToMScalar(zxC + ys), // persp x
+ SkDoubleToMScalar(yzC - xs), // persp y
+ SkDoubleToMScalar(z * zC + c)); // persp 2
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
+ SkMScalar result[4][4];
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ double value = 0;
+ for (int k = 0; k < 4; k++) {
+ value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
+ }
+ result[j][i] = SkDoubleToMScalar(value);
+ }
+ }
+ memcpy(fMat, result, sizeof(result));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
+ return SkDoubleToMScalar(m00 * m11 - m10 * m01);
+}
+
+static inline double det3x3(double m00, double m01, double m02,
+ double m10, double m11, double m12,
+ double m20, double m21, double m22) {
+ return m00 * det2x2(m11, m12, m21, m22) -
+ m10 * det2x2(m01, m02, m21, m22) +
+ m20 * det2x2(m01, m02, m11, m12);
+}
+
+/** We always perform the calculation in doubles, to avoid prematurely losing
+ precision along the way. This relies on the compiler automatically
+ promoting our SkMScalar values to double (if needed).
+ */
+double SkMatrix44::determinant() const {
+ return fMat[0][0] * det3x3(fMat[1][1], fMat[1][2], fMat[1][3],
+ fMat[2][1], fMat[2][2], fMat[2][3],
+ fMat[3][1], fMat[3][2], fMat[3][3]) -
+ fMat[1][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
+ fMat[2][1], fMat[2][2], fMat[2][3],
+ fMat[3][1], fMat[3][2], fMat[3][3]) +
+ fMat[2][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
+ fMat[1][1], fMat[1][2], fMat[1][3],
+ fMat[3][1], fMat[3][2], fMat[3][3]) -
+ fMat[3][0] * det3x3(fMat[0][1], fMat[0][2], fMat[0][3],
+ fMat[1][1], fMat[1][2], fMat[1][3],
+ fMat[2][1], fMat[2][2], fMat[2][3]);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+// just picked a small value. not sure how to pick the "right" one
+#define TOO_SMALL_FOR_DETERMINANT (1.e-8)
+
+static inline double dabs(double x) {
+ if (x < 0) {
+ x = -x;
+ }
+ return x;
+}
+
+bool SkMatrix44::invert(SkMatrix44* inverse) const {
+ double det = this->determinant();
+ if (dabs(det) < TOO_SMALL_FOR_DETERMINANT) {
+ return false;
+ }
+ if (NULL == inverse) {
+ return true;
+ }
+
+ // we explicitly promote to doubles to keep the intermediate values in
+ // higher precision (assuming SkMScalar isn't already a double)
+ double m00 = fMat[0][0];
+ double m01 = fMat[0][1];
+ double m02 = fMat[0][2];
+ double m03 = fMat[0][3];
+ double m10 = fMat[1][0];
+ double m11 = fMat[1][1];
+ double m12 = fMat[1][2];
+ double m13 = fMat[1][3];
+ double m20 = fMat[2][0];
+ double m21 = fMat[2][1];
+ double m22 = fMat[2][2];
+ double m23 = fMat[2][3];
+ double m30 = fMat[3][0];
+ double m31 = fMat[3][1];
+ double m32 = fMat[3][2];
+ double m33 = fMat[3][3];
+
+ double tmp[4][4];
+
+ tmp[0][0] = m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - m11*m23*m32 - m12*m21*m33 + m11*m22*m33;
+ tmp[0][1] = m03*m22*m31 - m02*m23*m31 - m03*m21*m32 + m01*m23*m32 + m02*m21*m33 - m01*m22*m33;
+ tmp[0][2] = m02*m13*m31 - m03*m12*m31 + m03*m11*m32 - m01*m13*m32 - m02*m11*m33 + m01*m12*m33;
+ tmp[0][3] = m03*m12*m21 - m02*m13*m21 - m03*m11*m22 + m01*m13*m22 + m02*m11*m23 - m01*m12*m23;
+ tmp[1][0] = m13*m22*m30 - m12*m23*m30 - m13*m20*m32 + m10*m23*m32 + m12*m20*m33 - m10*m22*m33;
+ tmp[1][1] = m02*m23*m30 - m03*m22*m30 + m03*m20*m32 - m00*m23*m32 - m02*m20*m33 + m00*m22*m33;
+ tmp[1][2] = m03*m12*m30 - m02*m13*m30 - m03*m10*m32 + m00*m13*m32 + m02*m10*m33 - m00*m12*m33;
+ tmp[1][3] = m02*m13*m20 - m03*m12*m20 + m03*m10*m22 - m00*m13*m22 - m02*m10*m23 + m00*m12*m23;
+ tmp[2][0] = m11*m23*m30 - m13*m21*m30 + m13*m20*m31 - m10*m23*m31 - m11*m20*m33 + m10*m21*m33;
+ tmp[2][1] = m03*m21*m30 - m01*m23*m30 - m03*m20*m31 + m00*m23*m31 + m01*m20*m33 - m00*m21*m33;
+ tmp[2][2] = m01*m13*m30 - m03*m11*m30 + m03*m10*m31 - m00*m13*m31 - m01*m10*m33 + m00*m11*m33;
+ tmp[2][3] = m03*m11*m20 - m01*m13*m20 - m03*m10*m21 + m00*m13*m21 + m01*m10*m23 - m00*m11*m23;
+ tmp[3][0] = m12*m21*m30 - m11*m22*m30 - m12*m20*m31 + m10*m22*m31 + m11*m20*m32 - m10*m21*m32;
+ tmp[3][1] = m01*m22*m30 - m02*m21*m30 + m02*m20*m31 - m00*m22*m31 - m01*m20*m32 + m00*m21*m32;
+ tmp[3][2] = m02*m11*m30 - m01*m12*m30 - m02*m10*m31 + m00*m12*m31 + m01*m10*m32 - m00*m11*m32;
+ tmp[3][3] = m01*m12*m20 - m02*m11*m20 + m02*m10*m21 - m00*m12*m21 - m01*m10*m22 + m00*m11*m22;
+
+ double invDet = 1.0 / det;
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ inverse->fMat[i][j] = SkDoubleToMScalar(tmp[i][j] * invDet);
+ }
+ }
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkMatrix44::map(const SkScalar src[4], SkScalar dst[4]) const {
+ SkScalar result[4];
+ for (int i = 0; i < 4; i++) {
+ SkMScalar value = 0;
+ for (int j = 0; j < 4; j++) {
+ value += fMat[j][i] * src[j];
+ }
+ result[i] = SkMScalarToScalar(value);
+ }
+ memcpy(dst, result, sizeof(result));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkMatrix44::dump() const {
+ static const char* format =
+ "[%g %g %g %g][%g %g %g %g][%g %g %g %g][%g %g %g %g]\n";
+#if 0
+ SkDebugf(format,
+ fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
+ fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
+ fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
+ fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
+#else
+ SkDebugf(format,
+ fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
+ fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
+ fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
+ fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
+#endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
+ sk_bzero(dst, 16 * sizeof(SkMScalar));
+ dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
+ dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
+ dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
+ dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
+ dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
+ dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
+ dst[2][2] = dst[3][3] = 1;
+}
+
+SkMatrix44::SkMatrix44(const SkMatrix& src) {
+ initFromMatrix(fMat, src);
+}
+
+SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
+ initFromMatrix(fMat, src);
+ return *this;
+}
+
+SkMatrix44::operator SkMatrix() const {
+ SkMatrix dst;
+ dst.reset(); // setup our perspective correctly for identity
+
+ dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
+ dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
+ dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
+
+ dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
+ dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
+ dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
+
+ return dst;
+}
diff --git a/src/utils/SkMeshUtils.cpp b/src/utils/SkMeshUtils.cpp
index 0385b99..f7af383 100644
--- a/src/utils/SkMeshUtils.cpp
+++ b/src/utils/SkMeshUtils.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkMeshUtils.h"
#include "SkCanvas.h"
#include "SkPaint.h"
diff --git a/src/utils/SkNWayCanvas.cpp b/src/utils/SkNWayCanvas.cpp
index d3c84a1..24c992d 100644
--- a/src/utils/SkNWayCanvas.cpp
+++ b/src/utils/SkNWayCanvas.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkNWayCanvas.h"
SkNWayCanvas::SkNWayCanvas() {}
@@ -122,20 +129,20 @@ void SkNWayCanvas::setMatrix(const SkMatrix& matrix) {
this->INHERITED::setMatrix(matrix);
}
-bool SkNWayCanvas::clipRect(const SkRect& rect, SkRegion::Op op) {
+bool SkNWayCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
Iter iter(fList);
while (iter.next()) {
- iter->clipRect(rect, op);
+ iter->clipRect(rect, op, doAA);
}
- return this->INHERITED::clipRect(rect, op);
+ return this->INHERITED::clipRect(rect, op, doAA);
}
-bool SkNWayCanvas::clipPath(const SkPath& path, SkRegion::Op op) {
+bool SkNWayCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
Iter iter(fList);
while (iter.next()) {
- iter->clipPath(path, op);
+ iter->clipPath(path, op, doAA);
}
- return this->INHERITED::clipPath(path, op);
+ return this->INHERITED::clipPath(path, op, doAA);
}
bool SkNWayCanvas::clipRegion(const SkRegion& deviceRgn, SkRegion::Op op) {
@@ -248,13 +255,6 @@ void SkNWayCanvas::drawPicture(SkPicture& picture) {
}
}
-void SkNWayCanvas::drawShape(SkShape* shape) {
- Iter iter(fList);
- while (iter.next()) {
- iter->drawShape(shape);
- }
-}
-
void SkNWayCanvas::drawVertices(VertexMode vmode, int vertexCount,
const SkPoint vertices[], const SkPoint texs[],
const SkColor colors[], SkXfermode* xmode,
diff --git a/src/utils/SkNinePatch.cpp b/src/utils/SkNinePatch.cpp
index c416fa6..26ae8eb 100644
--- a/src/utils/SkNinePatch.cpp
+++ b/src/utils/SkNinePatch.cpp
@@ -1,18 +1,11 @@
+
/*
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkNinePatch.h"
#include "SkCanvas.h"
@@ -220,13 +213,21 @@ void SkNinePatch::DrawMesh(SkCanvas* canvas, const SkRect& bounds,
stretchX, bitmap.width());
verts += numXDivs + 2;
texs += numXDivs + 2;
-
- SkScalar prev = 0;
for (int y = 0; y < numYDivs; y++) {
const SkScalar ty = SkIntToScalar(yDivs[y]);
- vy += computeVertexDelta(y & 1, ty, prev, stretchY);
- prev = ty;
-
+ if (stretchY >= 0) {
+ if (y & 1) {
+ vy += stretchY;
+ } else {
+ vy += ty;
+ }
+ } else { // shrink fixed sections, and collaps stretchy sections
+ if (y & 1) {
+ ;// do nothing
+ } else {
+ vy += SkScalarMul(ty, -stretchY);
+ }
+ }
fillRow(verts, texs, vy, ty, bounds, xDivs, numXDivs,
stretchX, bitmap.width());
verts += numXDivs + 2;
diff --git a/src/utils/SkOSFile.cpp b/src/utils/SkOSFile.cpp
index c1b6943..7c2b024 100644
--- a/src/utils/SkOSFile.cpp
+++ b/src/utils/SkOSFile.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkOSFile.h"
#ifdef SK_BUILD_FOR_WIN
@@ -125,7 +132,7 @@ bool SkOSFile::Iter::next(SkString* name, bool getDir)
return fHandle != (HANDLE)~0 && get_the_file(fHandle, name, dataPtr, getDir);
}
-#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
+#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
#if 0
OSStatus FSPathMakeRef (
diff --git a/src/utils/SkParse.cpp b/src/utils/SkParse.cpp
index 69808a3..cb265c3 100644
--- a/src/utils/SkParse.cpp
+++ b/src/utils/SkParse.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/xml/SkParse.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkParse.h"
@@ -138,7 +130,7 @@ const char* SkParse::FindHex(const char str[], uint32_t* value)
*value = n;
return str;
}
- return false;
+ return NULL;
}
const char* SkParse::FindS32(const char str[], int32_t* value)
diff --git a/src/utils/SkParseColor.cpp b/src/utils/SkParseColor.cpp
index 43d0737..db47aae 100644
--- a/src/utils/SkParseColor.cpp
+++ b/src/utils/SkParseColor.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/xml/SkParseColor.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkParse.h"
diff --git a/src/utils/SkParsePath.cpp b/src/utils/SkParsePath.cpp
index e08e84c..6030493 100644
--- a/src/utils/SkParsePath.cpp
+++ b/src/utils/SkParsePath.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkParse.h"
#include "SkParsePath.h"
diff --git a/src/utils/SkProxyCanvas.cpp b/src/utils/SkProxyCanvas.cpp
index 05823ea..bc21d52 100644
--- a/src/utils/SkProxyCanvas.cpp
+++ b/src/utils/SkProxyCanvas.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkProxyCanvas.h"
SkProxyCanvas::SkProxyCanvas(SkCanvas* proxy) : fProxy(proxy) {
@@ -51,12 +58,12 @@ void SkProxyCanvas::setMatrix(const SkMatrix& matrix) {
fProxy->setMatrix(matrix);
}
-bool SkProxyCanvas::clipRect(const SkRect& rect, SkRegion::Op op) {
- return fProxy->clipRect(rect, op);
+bool SkProxyCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
+ return fProxy->clipRect(rect, op, doAA);
}
-bool SkProxyCanvas::clipPath(const SkPath& path, SkRegion::Op op) {
- return fProxy->clipPath(path, op);
+bool SkProxyCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
+ return fProxy->clipPath(path, op, doAA);
}
bool SkProxyCanvas::clipRegion(const SkRegion& deviceRgn, SkRegion::Op op) {
@@ -126,10 +133,6 @@ void SkProxyCanvas::drawPicture(SkPicture& picture) {
fProxy->drawPicture(picture);
}
-void SkProxyCanvas::drawShape(SkShape* shape) {
- fProxy->drawShape(shape);
-}
-
void SkProxyCanvas::drawVertices(VertexMode vmode, int vertexCount,
const SkPoint vertices[], const SkPoint texs[],
const SkColor colors[], SkXfermode* xmode,
@@ -151,8 +154,3 @@ SkDrawFilter* SkProxyCanvas::setDrawFilter(SkDrawFilter* filter) {
return fProxy->setDrawFilter(filter);
}
-SkDevice* SkProxyCanvas::createDevice(SkBitmap::Config config, int width, int height,
- bool isOpaque, bool isForLayer) {
- return fProxy->createDevice(config, width, height, isOpaque, isForLayer);
-}
-
diff --git a/src/utils/SkSfntUtils.cpp b/src/utils/SkSfntUtils.cpp
index ba9f3f6..54f7cc3 100644
--- a/src/utils/SkSfntUtils.cpp
+++ b/src/utils/SkSfntUtils.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkEndian.h"
#include "SkSfntUtils.h"
diff --git a/src/utils/SkUnitMappers.cpp b/src/utils/SkUnitMappers.cpp
index 2a4aaa7..583d091 100644
--- a/src/utils/SkUnitMappers.cpp
+++ b/src/utils/SkUnitMappers.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkUnitMappers.h"
SkDiscreteMapper::SkDiscreteMapper(int segments) {
diff --git a/src/utils/mac/SkBitmap_Mac.cpp b/src/utils/mac/SkBitmap_Mac.cpp
deleted file mode 100644
index 06c2b27..0000000
--- a/src/utils/mac/SkBitmap_Mac.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-#include "SkBitmap.h"
-#include "SkColorPriv.h"
-#include "SkMath.h"
-
-#if defined(SK_BUILD_FOR_MAC) && !defined(SK_USE_WXWIDGETS)
-
-#include <ApplicationServices/ApplicationServices.h>
-
-#ifndef __ppc__
- #define SWAP_16BIT
-#endif
-
-static void convertGL32_to_Mac32(uint32_t dst[], const SkBitmap& bm) {
- memcpy(dst, bm.getPixels(), bm.getSize());
- return;
-
- uint32_t* stop = dst + (bm.getSize() >> 2);
- const uint8_t* src = (const uint8_t*)bm.getPixels();
- while (dst < stop) {
- *dst++ = src[2] << 24 | src[1] << 16 | src[0] << 8 | src[3] << 0;
- src += sizeof(uint32_t);
- }
-}
-
-static void convert565_to_32(uint32_t dst[], const SkBitmap& bm) {
- for (int y = 0; y < bm.height(); y++) {
- const uint16_t* src = bm.getAddr16(0, y);
- const uint16_t* stop = src + bm.width();
- while (src < stop) {
- unsigned c = *src++;
- unsigned r = SkPacked16ToR32(c);
- unsigned g = SkPacked16ToG32(c);
- unsigned b = SkPacked16ToB32(c);
-
- *dst++ = (b << 24) | (g << 16) | (r << 8) | 0xFF;
- }
- }
-}
-
-static void convert4444_to_555(uint16_t dst[], const uint16_t src[], int count)
-{
- const uint16_t* stop = src + count;
-
- while (src < stop)
- {
- unsigned c = *src++;
-
- unsigned r = SkGetPackedR4444(c);
- unsigned g = SkGetPackedG4444(c);
- unsigned b = SkGetPackedB4444(c);
- // convert to 5 bits
- r = (r << 1) | (r >> 3);
- g = (g << 1) | (g >> 3);
- b = (b << 1) | (b >> 3);
- // build the 555
- c = (r << 10) | (g << 5) | b;
-
-#ifdef SWAP_16BIT
- c = (c >> 8) | (c << 8);
-#endif
- *dst++ = c;
- }
-}
-
-#include "SkTemplates.h"
-
-static CGImageRef bitmap2imageref(const SkBitmap& bm) {
- size_t bitsPerComp;
- size_t bitsPerPixel;
- CGBitmapInfo info;
- CGColorSpaceRef cs = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
- CGDataProviderRef data = CGDataProviderCreateWithData(NULL,
- bm.getPixels(),
- bm.getSize(),
- NULL);
- SkAutoTCallVProc<CGDataProvider, CGDataProviderRelease> acp(data);
- SkAutoTCallVProc<CGColorSpace, CGColorSpaceRelease> acp2(cs);
-
- switch (bm.config()) {
- case SkBitmap::kARGB_8888_Config:
- bitsPerComp = 8;
- bitsPerPixel = 32;
- info = kCGImageAlphaPremultipliedLast;
- break;
- case SkBitmap::kARGB_4444_Config:
- bitsPerComp = 4;
- bitsPerPixel = 16;
- info = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder16Little;
- break;
-#if 0 // not supported by quartz !!!
- case SkBitmap::kRGB_565_Config:
- bitsPerComp = 5;
- bitsPerPixel = 16;
- info = kCGImageAlphaNone | kCGBitmapByteOrder16Little;
- break;
-#endif
- default:
- return NULL;
- }
-
- return CGImageCreate(bm.width(), bm.height(), bitsPerComp, bitsPerPixel,
- bm.rowBytes(), cs, info, data,
- NULL, false, kCGRenderingIntentDefault);
-}
-
-void SkBitmap::drawToPort(WindowRef wind, CGContextRef cg) const {
- if (fPixels == NULL || fWidth == 0 || fHeight == 0) {
- return;
- }
-
- bool useQD = false;
- if (NULL == cg) {
- SetPortWindowPort(wind);
- QDBeginCGContext(GetWindowPort(wind), &cg);
- useQD = true;
- }
-
- SkBitmap bm;
- if (this->config() == kRGB_565_Config) {
- this->copyTo(&bm, kARGB_8888_Config);
- } else {
- bm = *this;
- }
- bm.lockPixels();
-
- CGImageRef image = bitmap2imageref(bm);
- if (image) {
- CGRect rect;
- rect.origin.x = rect.origin.y = 0;
- rect.size.width = bm.width();
- rect.size.height = bm.height();
-
- CGContextDrawImage(cg, rect, image);
- CGImageRelease(image);
- }
-
- if (useQD) {
- QDEndCGContext(GetWindowPort(wind), &cg);
- }
-}
-
-#endif
diff --git a/src/utils/mac/SkCreateCGImageRef.cpp b/src/utils/mac/SkCreateCGImageRef.cpp
deleted file mode 100644
index f4bda45..0000000
--- a/src/utils/mac/SkCreateCGImageRef.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-#include "SkCGUtils.h"
-#include "SkBitmap.h"
-#include "SkColorPriv.h"
-
-static void SkBitmap_ReleaseInfo(void* info, const void* pixelData, size_t size) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(info);
- delete bitmap;
-}
-
-#define HAS_ARGB_SHIFTS(a, r, g, b) \
- (SK_A32_SHIFT == (a) && SK_R32_SHIFT == (r) \
- && SK_G32_SHIFT == (g) && SK_B32_SHIFT == (b))
-
-static SkBitmap* prepareForImageRef(const SkBitmap& bm,
- size_t* bitsPerComponent,
- CGBitmapInfo* info) {
- bool upscaleTo32 = false;
-
- switch (bm.config()) {
- case SkBitmap::kRGB_565_Config:
- upscaleTo32 = true;
- // fall through
- case SkBitmap::kARGB_8888_Config:
- *bitsPerComponent = 8;
-#if defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 0, 8, 16) \
- || defined(SK_CPU_BENDIAN) && HAS_ARGB_SHIFTS(0, 24, 16, 8)
- *info = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast;
-#elif defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0) \
- || defined(SK_CPU_BENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0)
- // Matches the CGBitmapInfo that Apple recommends for best
- // performance, used by google chrome.
- *info = kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst;
-#else
-// ...add more formats as required...
-#warning Cannot convert SkBitmap to CGImageRef with these shiftmasks. \
- This will probably not work.
- // Legacy behavior. Perhaps turn this into an error at some
- // point.
- *info = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast;
-#endif
- break;
-#if 0
- case SkBitmap::kRGB_565_Config:
- // doesn't see quite right. Are they thinking 1555?
- *bitsPerComponent = 5;
- *info = kCGBitmapByteOrder16Little;
- break;
-#endif
- case SkBitmap::kARGB_4444_Config:
- *bitsPerComponent = 4;
- *info = kCGBitmapByteOrder16Little | kCGImageAlphaPremultipliedLast;
- break;
- default:
- return NULL;
- }
-
- SkBitmap* copy;
- if (upscaleTo32) {
- copy = new SkBitmap;
- // here we make a ceep copy of the pixels, since CG won't take our
- // 565 directly
- bm.copyTo(copy, SkBitmap::kARGB_8888_Config);
- } else {
- copy = new SkBitmap(bm);
- }
- return copy;
-}
-
-#undef HAS_ARGB_SHIFTS
-
-CGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm,
- CGColorSpaceRef colorSpace) {
- size_t bitsPerComponent SK_INIT_TO_AVOID_WARNING;
- CGBitmapInfo info SK_INIT_TO_AVOID_WARNING;
-
- SkBitmap* bitmap = prepareForImageRef(bm, &bitsPerComponent, &info);
- if (NULL == bitmap) {
- return NULL;
- }
-
- const int w = bitmap->width();
- const int h = bitmap->height();
- const size_t s = bitmap->getSize();
-
- // our provider "owns" the bitmap*, and will take care of deleting it
- // we initially lock it, so we can access the pixels. The bitmap will be deleted in the release
- // proc, which will in turn unlock the pixels
- bitmap->lockPixels();
- CGDataProviderRef dataRef = CGDataProviderCreateWithData(bitmap, bitmap->getPixels(), s,
- SkBitmap_ReleaseInfo);
-
- bool releaseColorSpace = false;
- if (NULL == colorSpace) {
- colorSpace = CGColorSpaceCreateDeviceRGB();
- releaseColorSpace = true;
- }
-
- CGImageRef ref = CGImageCreate(w, h, bitsPerComponent,
- bitmap->bytesPerPixel() * 8,
- bitmap->rowBytes(), colorSpace, info, dataRef,
- NULL, false, kCGRenderingIntentDefault);
-
- if (releaseColorSpace) {
- CGColorSpaceRelease(colorSpace);
- }
- CGDataProviderRelease(dataRef);
- return ref;
-}
-
-void SkCGDrawBitmap(CGContextRef cg, const SkBitmap& bm, float x, float y) {
- CGImageRef img = SkCreateCGImageRef(bm);
-
- if (img) {
- CGRect r = CGRectMake(0, 0, bm.width(), bm.height());
-
- CGContextSaveGState(cg);
- CGContextTranslateCTM(cg, x, r.size.height + y);
- CGContextScaleCTM(cg, 1, -1);
-
- CGContextDrawImage(cg, r, img);
-
- CGContextRestoreGState(cg);
-
- CGImageRelease(img);
- }
-}
-
-
-
diff --git a/src/utils/mac/SkEGLContext_mac.cpp b/src/utils/mac/SkEGLContext_mac.cpp
deleted file mode 100644
index e601f35..0000000
--- a/src/utils/mac/SkEGLContext_mac.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-#include "SkEGLContext.h"
-//#include "SkTypes.h"
-#include <AGL/agl.h>
-
-SkEGLContext::SkEGLContext() : context(NULL) {
-}
-
-SkEGLContext::~SkEGLContext() {
- if (this->context) {
- aglDestroyContext(this->context);
- }
-}
-
-bool SkEGLContext::init(int width, int height) {
- GLint major, minor;
- AGLContext ctx;
-
- aglGetVersion(&major, &minor);
- //SkDebugf("---- agl version %d %d\n", major, minor);
-
- const GLint pixelAttrs[] = {
- AGL_RGBA,
- AGL_STENCIL_SIZE, 8,
-/*
- AGL_SAMPLE_BUFFERS_ARB, 1,
- AGL_MULTISAMPLE,
- AGL_SAMPLES_ARB, 2,
-*/
- AGL_ACCELERATED,
- AGL_NONE
- };
- AGLPixelFormat format = aglChoosePixelFormat(NULL, 0, pixelAttrs);
- //AGLPixelFormat format = aglCreatePixelFormat(pixelAttrs);
- //SkDebugf("----- agl format %p\n", format);
- ctx = aglCreateContext(format, NULL);
- //SkDebugf("----- agl context %p\n", ctx);
- aglDestroyPixelFormat(format);
-
-/*
- static const GLint interval = 1;
- aglSetInteger(ctx, AGL_SWAP_INTERVAL, &interval);
-*/
-
- aglSetCurrentContext(ctx);
- this->context = ctx;
-
- // Now create our FBO render target
-
- GLuint fboID;
- GLuint cbID;
- GLuint dsID;
- glGenFramebuffersEXT(1, &fboID);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboID);
- glGenRenderbuffers(1, &cbID);
- glBindRenderbuffer(GL_RENDERBUFFER, cbID);
- glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, width, height);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, cbID);
- glGenRenderbuffers(1, &dsID);
- glBindRenderbuffer(GL_RENDERBUFFER, dsID);
- glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, width, height);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, dsID);
- glViewport(0, 0, width, height);
- glClearStencil(0);
- glClear(GL_STENCIL_BUFFER_BIT);
-
- GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- return GL_FRAMEBUFFER_COMPLETE == status;
-}
diff --git a/src/utils/mac/SkOSWindow_Mac.cpp b/src/utils/mac/SkOSWindow_Mac.cpp
deleted file mode 100644
index f1a2926..0000000
--- a/src/utils/mac/SkOSWindow_Mac.cpp
+++ /dev/null
@@ -1,534 +0,0 @@
-#include "SkTypes.h"
-
-#if defined(SK_BUILD_FOR_MAC) && !defined(SK_USE_WXWIDGETS)
-
-#include <AGL/agl.h>
-
-#include <Carbon/Carbon.h>
-#include "SkCGUtils.h"
-
-#include "SkWindow.h"
-#include "SkCanvas.h"
-#include "SkOSMenu.h"
-#include "SkTime.h"
-
-#include "SkGraphics.h"
-#include <new.h>
-
-static void (*gPrevNewHandler)();
-
-extern "C" {
- static void sk_new_handler()
- {
- if (SkGraphics::SetFontCacheUsed(0))
- return;
- if (gPrevNewHandler)
- gPrevNewHandler();
- else
- sk_throw();
- }
-}
-
-static SkOSWindow* gCurrOSWin;
-static EventTargetRef gEventTarget;
-static EventQueueRef gCurrEventQ;
-
-static OSStatus MyDrawEventHandler(EventHandlerCallRef myHandler,
- EventRef event, void *userData) {
- // NOTE: GState is save/restored by the HIView system doing the callback,
- // so the draw handler doesn't need to do it
-
- OSStatus status = noErr;
- CGContextRef context;
- HIRect bounds;
-
- // Get the CGContextRef
- status = GetEventParameter (event, kEventParamCGContextRef,
- typeCGContextRef, NULL,
- sizeof (CGContextRef),
- NULL,
- &context);
-
- if (status != noErr) {
- SkDebugf("Got error %d getting the context!\n", status);
- return status;
- }
-
- // Get the bounding rectangle
- HIViewGetBounds ((HIViewRef) userData, &bounds);
-
- gCurrOSWin->doPaint(context);
- return status;
-}
-
-#define SK_MacEventClass FOUR_CHAR_CODE('SKec')
-#define SK_MacEventKind FOUR_CHAR_CODE('SKek')
-#define SK_MacEventParamName FOUR_CHAR_CODE('SKev')
-#define SK_MacEventSinkIDParamName FOUR_CHAR_CODE('SKes')
-
-static void set_bindingside(HISideBinding* side, HIViewRef parent, HIBindingKind kind) {
- side->toView = parent;
- side->kind = kind;
- side->offset = 0;
-}
-
-static void set_axisscale(HIAxisScale* axis, HIViewRef parent) {
- axis->toView = parent;
- axis->kind = kHILayoutScaleAbsolute;
- axis->ratio = 1;
-}
-
-static void set_axisposition(HIAxisPosition* pos, HIViewRef parent, HIPositionKind kind) {
- pos->toView = parent;
- pos->kind = kind;
- pos->offset = 0;
-}
-
-SkOSWindow::SkOSWindow(void* hWnd) : fHWND(hWnd), fAGLCtx(NULL)
-{
- OSStatus result;
- WindowRef wr = (WindowRef)hWnd;
-
- HIViewRef imageView, parent;
- HIViewRef rootView = HIViewGetRoot(wr);
- HIViewFindByID(rootView, kHIViewWindowContentID, &parent);
- result = HIImageViewCreate(NULL, &imageView);
- SkASSERT(result == noErr);
-
- result = HIViewAddSubview(parent, imageView);
- SkASSERT(result == noErr);
-
- fHVIEW = imageView;
-
- HIViewSetVisible(imageView, true);
- HIViewPlaceInSuperviewAt(imageView, 0, 0);
-
- if (true) {
- HILayoutInfo layout;
- layout.version = kHILayoutInfoVersionZero;
- set_bindingside(&layout.binding.left, parent, kHILayoutBindLeft);
- set_bindingside(&layout.binding.top, parent, kHILayoutBindTop);
- set_bindingside(&layout.binding.right, parent, kHILayoutBindRight);
- set_bindingside(&layout.binding.bottom, parent, kHILayoutBindBottom);
- set_axisscale(&layout.scale.x, parent);
- set_axisscale(&layout.scale.y, parent);
- set_axisposition(&layout.position.x, parent, kHILayoutPositionLeft);
- set_axisposition(&layout.position.y, rootView, kHILayoutPositionTop);
- HIViewSetLayoutInfo(imageView, &layout);
- }
-
- HIImageViewSetOpaque(imageView, true);
- HIImageViewSetScaleToFit(imageView, false);
-
- static const EventTypeSpec gTypes[] = {
- { kEventClassKeyboard, kEventRawKeyDown },
- { kEventClassKeyboard, kEventRawKeyUp },
- { kEventClassMouse, kEventMouseDown },
- { kEventClassMouse, kEventMouseDragged },
- { kEventClassMouse, kEventMouseMoved },
- { kEventClassMouse, kEventMouseUp },
- { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
- { kEventClassWindow, kEventWindowBoundsChanged },
-// { kEventClassWindow, kEventWindowDrawContent },
- { SK_MacEventClass, SK_MacEventKind }
- };
-
- EventHandlerUPP handlerUPP = NewEventHandlerUPP(SkOSWindow::EventHandler);
- int count = SK_ARRAY_COUNT(gTypes);
-
- result = InstallEventHandler(GetWindowEventTarget(wr), handlerUPP,
- count, gTypes, this, nil);
- SkASSERT(result == noErr);
-
- gCurrOSWin = this;
- gCurrEventQ = GetCurrentEventQueue();
- gEventTarget = GetWindowEventTarget(wr);
-
- static bool gOnce = true;
- if (gOnce) {
- gOnce = false;
- gPrevNewHandler = set_new_handler(sk_new_handler);
- }
-}
-
-void SkOSWindow::doPaint(void* ctx)
-{
-#if 0
- this->update(NULL);
-
- const SkBitmap& bm = this->getBitmap();
- CGImageRef img = SkCreateCGImageRef(bm);
-
- if (img) {
- CGRect r = CGRectMake(0, 0, bm.width(), bm.height());
-
- CGContextRef cg = reinterpret_cast<CGContextRef>(ctx);
-
- CGContextSaveGState(cg);
- CGContextTranslateCTM(cg, 0, r.size.height);
- CGContextScaleCTM(cg, 1, -1);
-
- CGContextDrawImage(cg, r, img);
-
- CGContextRestoreGState(cg);
-
- CGImageRelease(img);
- }
-#endif
-}
-
-void SkOSWindow::updateSize()
-{
- Rect r;
-
- GetWindowBounds((WindowRef)fHWND, kWindowContentRgn, &r);
- this->resize(r.right - r.left, r.bottom - r.top);
-
-#if 0
- HIRect frame;
- HIViewRef imageView = (HIViewRef)getHVIEW();
- HIViewRef parent = HIViewGetSuperview(imageView);
-
- HIViewGetBounds(imageView, &frame);
- SkDebugf("------ %d bounds %g %g %g %g\n", r.right - r.left,
- frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
-#endif
-}
-
-void SkOSWindow::onHandleInval(const SkIRect& r)
-{
- SkEvent* evt = new SkEvent("inval-imageview");
- evt->post(this->getSinkID());
-}
-
-bool SkOSWindow::onEvent(const SkEvent& evt) {
- if (evt.isType("inval-imageview")) {
- this->update(NULL);
-
- const SkBitmap& bm = this->getBitmap();
-
- CGImageRef img = SkCreateCGImageRef(bm);
- HIImageViewSetImage((HIViewRef)getHVIEW(), img);
- CGImageRelease(img);
- return true;
- }
- return INHERITED::onEvent(evt);
-}
-
-void SkOSWindow::onSetTitle(const char title[])
-{
- CFStringRef str = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
- SetWindowTitleWithCFString((WindowRef)fHWND, str);
- CFRelease(str);
-}
-
-void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu)
-{
-}
-
-static void getparam(EventRef inEvent, OSType name, OSType type, UInt32 size, void* data)
-{
- EventParamType actualType;
- UInt32 actualSize;
- OSStatus status;
-
- status = GetEventParameter(inEvent, name, type, &actualType, size, &actualSize, data);
- SkASSERT(status == noErr);
- SkASSERT(actualType == type);
- SkASSERT(actualSize == size);
-}
-
-enum {
- SK_MacReturnKey = 36,
- SK_MacDeleteKey = 51,
- SK_MacEndKey = 119,
- SK_MacLeftKey = 123,
- SK_MacRightKey = 124,
- SK_MacDownKey = 125,
- SK_MacUpKey = 126,
-
- SK_Mac0Key = 0x52,
- SK_Mac1Key = 0x53,
- SK_Mac2Key = 0x54,
- SK_Mac3Key = 0x55,
- SK_Mac4Key = 0x56,
- SK_Mac5Key = 0x57,
- SK_Mac6Key = 0x58,
- SK_Mac7Key = 0x59,
- SK_Mac8Key = 0x5b,
- SK_Mac9Key = 0x5c
-};
-
-static SkKey raw2key(UInt32 raw)
-{
- static const struct {
- UInt32 fRaw;
- SkKey fKey;
- } gKeys[] = {
- { SK_MacUpKey, kUp_SkKey },
- { SK_MacDownKey, kDown_SkKey },
- { SK_MacLeftKey, kLeft_SkKey },
- { SK_MacRightKey, kRight_SkKey },
- { SK_MacReturnKey, kOK_SkKey },
- { SK_MacDeleteKey, kBack_SkKey },
- { SK_MacEndKey, kEnd_SkKey },
- { SK_Mac0Key, k0_SkKey },
- { SK_Mac1Key, k1_SkKey },
- { SK_Mac2Key, k2_SkKey },
- { SK_Mac3Key, k3_SkKey },
- { SK_Mac4Key, k4_SkKey },
- { SK_Mac5Key, k5_SkKey },
- { SK_Mac6Key, k6_SkKey },
- { SK_Mac7Key, k7_SkKey },
- { SK_Mac8Key, k8_SkKey },
- { SK_Mac9Key, k9_SkKey }
- };
-
- for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++)
- if (gKeys[i].fRaw == raw)
- return gKeys[i].fKey;
- return kNONE_SkKey;
-}
-
-static void post_skmacevent()
-{
- EventRef ref;
- OSStatus status = CreateEvent(nil, SK_MacEventClass, SK_MacEventKind, 0, 0, &ref);
- SkASSERT(status == noErr);
-
-#if 0
- status = SetEventParameter(ref, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt);
- SkASSERT(status == noErr);
- status = SetEventParameter(ref, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID);
- SkASSERT(status == noErr);
-#endif
-
- EventTargetRef target = gEventTarget;
- SetEventParameter(ref, kEventParamPostTarget, typeEventTargetRef, sizeof(target), &target);
- SkASSERT(status == noErr);
-
- status = PostEventToQueue(gCurrEventQ, ref, kEventPriorityStandard);
- SkASSERT(status == noErr);
-
- ReleaseEvent(ref);
-}
-
-pascal OSStatus SkOSWindow::EventHandler( EventHandlerCallRef inHandler, EventRef inEvent, void* userData )
-{
- SkOSWindow* win = (SkOSWindow*)userData;
- OSStatus result = eventNotHandledErr;
- UInt32 wClass = GetEventClass(inEvent);
- UInt32 wKind = GetEventKind(inEvent);
-
- gCurrOSWin = win; // will need to be in TLS. Set this so PostEvent will work
-
- switch (wClass) {
- case kEventClassMouse: {
- Point pt;
- getparam(inEvent, kEventParamMouseLocation, typeQDPoint, sizeof(pt), &pt);
- SetPortWindowPort((WindowRef)win->getHWND());
- GlobalToLocal(&pt);
-
- switch (wKind) {
- case kEventMouseDown:
- if (win->handleClick(pt.h, pt.v, Click::kDown_State)) {
- result = noErr;
- }
- break;
- case kEventMouseMoved:
- // fall through
- case kEventMouseDragged:
- (void)win->handleClick(pt.h, pt.v, Click::kMoved_State);
- // result = noErr;
- break;
- case kEventMouseUp:
- (void)win->handleClick(pt.h, pt.v, Click::kUp_State);
- // result = noErr;
- break;
- default:
- break;
- }
- break;
- }
- case kEventClassKeyboard:
- if (wKind == kEventRawKeyDown) {
- UInt32 raw;
- getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw);
- SkKey key = raw2key(raw);
- if (key != kNONE_SkKey)
- (void)win->handleKey(key);
- } else if (wKind == kEventRawKeyUp) {
- UInt32 raw;
- getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw);
- SkKey key = raw2key(raw);
- if (key != kNONE_SkKey)
- (void)win->handleKeyUp(key);
- }
- break;
- case kEventClassTextInput:
- if (wKind == kEventTextInputUnicodeForKeyEvent) {
- UInt16 uni;
- getparam(inEvent, kEventParamTextInputSendText, typeUnicodeText, sizeof(uni), &uni);
- win->handleChar(uni);
- }
- break;
- case kEventClassWindow:
- switch (wKind) {
- case kEventWindowBoundsChanged:
- win->updateSize();
- break;
- case kEventWindowDrawContent: {
- CGContextRef cg;
- result = GetEventParameter(inEvent,
- kEventParamCGContextRef,
- typeCGContextRef,
- NULL,
- sizeof (CGContextRef),
- NULL,
- &cg);
- if (result != 0) {
- cg = NULL;
- }
- win->doPaint(cg);
- break;
- }
- default:
- break;
- }
- break;
- case SK_MacEventClass: {
- SkASSERT(wKind == SK_MacEventKind);
- if (SkEvent::ProcessEvent()) {
- post_skmacevent();
- }
- #if 0
- SkEvent* evt;
- SkEventSinkID sinkID;
- getparam(inEvent, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt);
- getparam(inEvent, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID);
- #endif
- result = noErr;
- break;
- }
- default:
- break;
- }
- if (result == eventNotHandledErr) {
- result = CallNextEventHandler(inHandler, inEvent);
- }
- return result;
-}
-
-///////////////////////////////////////////////////////////////////////////////////////
-
-void SkEvent::SignalNonEmptyQueue()
-{
- post_skmacevent();
-// SkDebugf("signal nonempty\n");
-}
-
-static TMTask gTMTaskRec;
-static TMTask* gTMTaskPtr;
-
-static void sk_timer_proc(TMTask* rec)
-{
- SkEvent::ServiceQueueTimer();
-// SkDebugf("timer task fired\n");
-}
-
-void SkEvent::SignalQueueTimer(SkMSec delay)
-{
- if (gTMTaskPtr)
- {
- RemoveTimeTask((QElem*)gTMTaskPtr);
- DisposeTimerUPP(gTMTaskPtr->tmAddr);
- gTMTaskPtr = nil;
- }
- if (delay)
- {
- gTMTaskPtr = &gTMTaskRec;
- memset(gTMTaskPtr, 0, sizeof(gTMTaskRec));
- gTMTaskPtr->tmAddr = NewTimerUPP(sk_timer_proc);
- OSErr err = InstallTimeTask((QElem*)gTMTaskPtr);
-// SkDebugf("installtimetask of %d returned %d\n", delay, err);
- PrimeTimeTask((QElem*)gTMTaskPtr, delay);
- }
-}
-
-#define USE_MSAA 0
-
-AGLContext create_gl(WindowRef wref)
-{
- GLint major, minor;
- AGLContext ctx;
-
- aglGetVersion(&major, &minor);
- SkDebugf("---- agl version %d %d\n", major, minor);
-
- const GLint pixelAttrs[] = {
- AGL_RGBA,
- AGL_STENCIL_SIZE, 8,
-#if USE_MSAA
- AGL_SAMPLE_BUFFERS_ARB, 1,
- AGL_MULTISAMPLE,
- AGL_SAMPLES_ARB, 8,
-#endif
- AGL_ACCELERATED,
- AGL_DOUBLEBUFFER,
- AGL_NONE
- };
- AGLPixelFormat format = aglChoosePixelFormat(NULL, 0, pixelAttrs);
- //AGLPixelFormat format = aglCreatePixelFormat(pixelAttrs);
- SkDebugf("----- agl format %p\n", format);
- ctx = aglCreateContext(format, NULL);
- SkDebugf("----- agl context %p\n", ctx);
- aglDestroyPixelFormat(format);
-
- static const GLint interval = 1;
- aglSetInteger(ctx, AGL_SWAP_INTERVAL, &interval);
- aglSetCurrentContext(ctx);
- return ctx;
-}
-
-bool SkOSWindow::attachGL()
-{
- if (NULL == fAGLCtx) {
- fAGLCtx = create_gl((WindowRef)fHWND);
- if (NULL == fAGLCtx) {
- return false;
- }
- }
-
- GLboolean success = true;
-
- int width, height;
-
- success = aglSetWindowRef((AGLContext)fAGLCtx, (WindowRef)fHWND);
- width = this->width();
- height = this->height();
-
- GLenum err = aglGetError();
- if (err) {
- SkDebugf("---- aglSetWindowRef %d %d %s [%d %d]\n", success, err,
- aglErrorString(err), width, height);
- }
-
- if (success) {
- glViewport(0, 0, width, height);
- glClearColor(0, 0, 0, 0);
- glClearStencil(0);
- glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
- }
- return success;
-}
-
-void SkOSWindow::detachGL() {
- aglSetWindowRef((AGLContext)fAGLCtx, NULL);
-}
-
-void SkOSWindow::presentGL() {
- aglSwapBuffers((AGLContext)fAGLCtx);
-}
-
-#endif
-
diff --git a/src/utils/mac/skia_mac.cpp b/src/utils/mac/skia_mac.cpp
deleted file mode 100644
index a1345cf..0000000
--- a/src/utils/mac/skia_mac.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <Carbon/Carbon.h>
-#include "SkApplication.h"
-#include "SkWindow.h"
-
-int main(int argc, char* argv[])
-{
- WindowRef window;
- OSStatus err = noErr;
-
- Rect bounds = {100, 100, 500, 500};
- WindowAttributes attrs = kWindowStandardHandlerAttribute |
- kWindowLiveResizeAttribute |
- kWindowInWindowMenuAttribute |
- kWindowCompositingAttribute |
- kWindowAsyncDragAttribute |
- kWindowFullZoomAttribute |
- kWindowFrameworkScaledAttribute;
- //kWindowDoesNotCycleAttribute;
- CreateNewWindow(kDocumentWindowClass, attrs, &bounds, &window);
-
- MenuRef menu;
- CreateNewMenu(0, 0, &menu);
-
- // if we get here, we can start our normal Skia sequence
- {
- application_init();
- (void)create_sk_window(window);
- SizeWindow(window, 640, 480, false);
- }
-
- // The window was created hidden so show it.
- ShowWindow( window );
-
- // Call the event loop
- RunApplicationEventLoop();
-
- application_term();
-
-CantCreateWindow:
-CantGetNibRef:
- return err;
-}
-
diff --git a/src/utils/mesa/SkEGLContext_Mesa.cpp b/src/utils/mesa/SkEGLContext_Mesa.cpp
deleted file mode 100644
index ed1b7cd..0000000
--- a/src/utils/mesa/SkEGLContext_Mesa.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-#include "SkEGLContext.h"
-#include "SkTypes.h"
-
-#include "GL/osmesa.h"
-#include "GL/glu.h"
-
-#define SK_GL_DECL_PROC(T, F) T F ## _func = NULL;
-#define SK_GL_GET_PROC(T, F) F ## _func = (T)OSMesaGetProcAddress(#F);
-#define SK_GL_GET_EXT_PROC(T, F) F ## _func = (T)OSMesaGetProcAddress(#F "EXT");
-
-SkEGLContext::SkEGLContext() : context(NULL), image(NULL) {
-}
-
-SkEGLContext::~SkEGLContext() {
- if (this->image)
- free(this->image);
-
- if (this->context)
- OSMesaDestroyContext(this->context);
-}
-
-#if SK_B32_SHIFT < SK_G32_SHIFT &&\
- SK_G32_SHIFT < SK_R32_SHIFT &&\
- SK_R32_SHIFT < SK_A32_SHIFT
- #define SK_OSMESA_COLOR_ORDER OSMESA_BGRA
-#elif SK_R32_SHIFT < SK_G32_SHIFT &&\
- SK_G32_SHIFT < SK_B32_SHIFT &&\
- SK_B32_SHIFT < SK_A32_SHIFT
- #define SK_OSMESA_COLOR_ORDER OSMESA_RGBA
-#elif SK_A32_SHIFT < SK_R32_SHIFT && \
- SK_R32_SHIFT < SK_G32_SHIFT && \
- SK_G32_SHIFT < SK_B32_SHIFT
- #define SK_OSMESA_COLOR_ORDER OSMESA_ARGB
-#else
- //Color order (rgba) SK_R32_SHIFT SK_G32_SHIFT SK_B32_SHIFT SK_A32_SHIFT
- #define SK_OSMESA_COLOR_ORDER OSMESA_RGBA
-#endif
-
-bool SkEGLContext::init(const int width, const int height) {
- /* Create an RGBA-mode context */
-#if OSMESA_MAJOR_VERSION * 100 + OSMESA_MINOR_VERSION >= 305
- /* specify Z, stencil, accum sizes */
- OSMesaContext ctx = OSMesaCreateContextExt(SK_OSMESA_COLOR_ORDER, 16, 0, 0, NULL);
-#else
- OSMesaContext ctx = OSMesaCreateContext(SK_OSMESA_COLOR_ORDER, NULL);
-#endif
- if (!ctx) {
- SkDebugf("OSMesaCreateContext failed!\n");
- return false;
- }
- this->context = ctx;
-
- // Allocate the image buffer
- GLfloat *buffer = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
- if (!buffer) {
- SkDebugf("Alloc image buffer failed!\n");
- return false;
- }
- this->image = buffer;
-
- // Bind the buffer to the context and make it current
- if (!OSMesaMakeCurrent(ctx, buffer, GL_FLOAT, width, height)) {
- SkDebugf("OSMesaMakeCurrent failed!\n");
- return false;
- }
-
- //Setup the framebuffers
- SK_GL_DECL_PROC(PFNGLGENFRAMEBUFFERSEXTPROC, glGenFramebuffers)
- SK_GL_DECL_PROC(PFNGLBINDFRAMEBUFFEREXTPROC, glBindFramebuffer)
- SK_GL_DECL_PROC(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers)
- SK_GL_DECL_PROC(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer)
- SK_GL_DECL_PROC(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage)
- SK_GL_DECL_PROC(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer)
- SK_GL_DECL_PROC(PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC, glCheckFramebufferStatus)
-
- const GLubyte* glExts = glGetString(GL_EXTENSIONS);
- if (gluCheckExtension(
- reinterpret_cast<const GLubyte*>("GL_ARB_framebuffer_object")
- , glExts))
- {
- SK_GL_GET_PROC(PFNGLGENFRAMEBUFFERSEXTPROC, glGenFramebuffers)
- SK_GL_GET_PROC(PFNGLBINDFRAMEBUFFEREXTPROC, glBindFramebuffer)
- SK_GL_GET_PROC(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers)
- SK_GL_GET_PROC(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer)
- SK_GL_GET_PROC(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage)
- SK_GL_GET_PROC(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer)
- SK_GL_GET_PROC(PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC, glCheckFramebufferStatus)
-
- //osmesa on mac currently only supports EXT
- } else if (gluCheckExtension(
- reinterpret_cast<const GLubyte*>("GL_EXT_framebuffer_object")
- , glExts))
- {
- SK_GL_GET_EXT_PROC(PFNGLGENFRAMEBUFFERSEXTPROC, glGenFramebuffers)
- SK_GL_GET_EXT_PROC(PFNGLBINDFRAMEBUFFEREXTPROC, glBindFramebuffer)
- SK_GL_GET_EXT_PROC(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers)
- SK_GL_GET_EXT_PROC(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer)
- SK_GL_GET_EXT_PROC(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage)
- SK_GL_GET_EXT_PROC(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer)
- SK_GL_GET_EXT_PROC(PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC, glCheckFramebufferStatus)
- } else {
- SkDebugf("GL_ARB_framebuffer_object not found.\n");
- return false;
- }
-
- GLuint fboID;
- GLuint cbID;
- GLuint dsID;
- glGenFramebuffers_func(1, &fboID);
- glBindFramebuffer_func(GL_FRAMEBUFFER, fboID);
-
- glGenRenderbuffers_func(1, &cbID);
- glBindRenderbuffer_func(GL_RENDERBUFFER, cbID);
- glRenderbufferStorage_func(GL_RENDERBUFFER, OSMESA_RGBA, width, height);
- glFramebufferRenderbuffer_func(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, cbID);
-
- glGenRenderbuffers_func(1, &dsID);
- glBindRenderbuffer_func(GL_RENDERBUFFER_EXT, dsID);
- glRenderbufferStorage_func(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
- glFramebufferRenderbuffer_func(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, dsID);
-
- glViewport(0, 0, width, height);
- glClearStencil(0);
- glClear(GL_STENCIL_BUFFER_BIT);
-
- GLenum status = glCheckFramebufferStatus_func(GL_FRAMEBUFFER);
- return GL_FRAMEBUFFER_COMPLETE == status;
-}
diff --git a/src/utils/unix/SkOSWindow_Unix.cpp b/src/utils/unix/SkOSWindow_Unix.cpp
index 652a1ae..b4b0f17 100644
--- a/src/utils/unix/SkOSWindow_Unix.cpp
+++ b/src/utils/unix/SkOSWindow_Unix.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
@@ -25,7 +32,7 @@ const int HEIGHT = 500;
const long EVENT_MASK = StructureNotifyMask|ButtonPressMask|ButtonReleaseMask
|ExposureMask|PointerMotionMask|KeyPressMask|KeyReleaseMask;
-SkOSWindow::SkOSWindow(void* unused) : fGLAttached(false), fVi(0)
+SkOSWindow::SkOSWindow(void* unused) : INHERITED(), fGLAttached(false), fVi(0)
{
fUnixWindow.fDisplay = XOpenDisplay(NULL);
Display* dsp = fUnixWindow.fDisplay;
@@ -84,6 +91,7 @@ void SkOSWindow::post_linuxevent()
event.data.l[0] = 0;
XSendEvent(fUnixWindow.fDisplay, fUnixWindow.fWin, false, 0,
(XEvent*) &event);
+ XFlush(fUnixWindow.fDisplay);
}
void SkOSWindow::loop()
@@ -214,10 +222,8 @@ void SkOSWindow::onSetTitle(const char title[])
XSetWMName(fUnixWindow.fDisplay, fUnixWindow.fWin, &textProp);
}
-void SkOSWindow::onHandleInval(const SkIRect&)
-{
- SkEvent* evt = new SkEvent("inval-imageview");
- evt->post(getSinkID());
+void SkOSWindow::onHandleInval(const SkIRect&) {
+ (new SkEvent("inval-imageview", this->getSinkID()))->post();
}
bool SkOSWindow::onEvent(const SkEvent& evt)
diff --git a/src/utils/utils_files.mk b/src/utils/utils_files.mk
deleted file mode 100644
index 37d0b65..0000000
--- a/src/utils/utils_files.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-SOURCE := \
- SkCamera.cpp \
- SkColorMatrix.cpp \
- SkCullPoints.cpp \
- SkDumpCanvas.cpp \
- SkInterpolator.cpp \
- SkLayer.cpp \
- SkNinePatch.cpp \
- SkNWayCanvas.cpp \
- SkOSFile.cpp \
- SkParse.cpp \
- SkParseColor.cpp \
- SkParsePath.cpp \
- SkProxyCanvas.cpp \
- SkSfntUtils.cpp \
- SkUnitMappers.cpp
diff --git a/src/views/SkBGViewArtist.cpp b/src/views/SkBGViewArtist.cpp
index 07da123..d9a45b8 100644
--- a/src/views/SkBGViewArtist.cpp
+++ b/src/views/SkBGViewArtist.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBGViewArtist.h"
#include "SkCanvas.h"
#include "SkParsePaint.h"
diff --git a/src/views/SkBorderView.cpp b/src/views/SkBorderView.cpp
index 74a2477..cc1c08b 100644
--- a/src/views/SkBorderView.cpp
+++ b/src/views/SkBorderView.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBorderView.h"
#include "SkAnimator.h"
#include "SkWidgetViews.h"
diff --git a/src/views/SkEvent.cpp b/src/views/SkEvent.cpp
index ec4a7b4..0149215 100644
--- a/src/views/SkEvent.cpp
+++ b/src/views/SkEvent.cpp
@@ -1,37 +1,30 @@
-/* libs/graphics/views/SkEvent.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkEvent.h"
-void SkEvent::initialize(const char* type, size_t typeLen) {
+void SkEvent::initialize(const char* type, size_t typeLen,
+ SkEventSinkID targetID) {
fType = NULL;
setType(type, typeLen);
f32 = 0;
+ fTargetID = targetID;
+ fTargetProc = NULL;
#ifdef SK_DEBUG
- fTargetID = 0;
fTime = 0;
fNextEvent = NULL;
#endif
- SkDEBUGCODE(fDebugTrace = false;)
}
SkEvent::SkEvent()
{
- initialize("", 0);
+ initialize("", 0, 0);
}
SkEvent::SkEvent(const SkEvent& src)
@@ -41,15 +34,15 @@ SkEvent::SkEvent(const SkEvent& src)
setType(src.fType);
}
-SkEvent::SkEvent(const SkString& type)
+SkEvent::SkEvent(const SkString& type, SkEventSinkID targetID)
{
- initialize(type.c_str(), type.size());
+ initialize(type.c_str(), type.size(), targetID);
}
-SkEvent::SkEvent(const char type[])
+SkEvent::SkEvent(const char type[], SkEventSinkID targetID)
{
SkASSERT(type);
- initialize(type, strlen(type));
+ initialize(type, strlen(type), targetID);
}
SkEvent::~SkEvent()
@@ -66,20 +59,6 @@ static size_t makeCharArray(char* buffer, size_t compact)
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)
@@ -259,7 +238,7 @@ void SkEvent::inflate(const SkDOM& dom, const SkDOM::Node* node)
}
break;
default:
- SkASSERT(!"unknown metadata type returned from iterator");
+ SkDEBUGFAIL("unknown metadata type returned from iterator");
break;
}
}
@@ -286,101 +265,75 @@ void SkEvent::inflate(const SkDOM& dom, const SkDOM::Node* node)
#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 {
+class SkEvent_Globals {
public:
+ SkEvent_Globals() {
+ fEventQHead = NULL;
+ fEventQTail = NULL;
+ fDelayQHead = NULL;
+ SkDEBUGCODE(fEventCounter = 0;)
+ }
+
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;
+static SkEvent_Globals& getGlobals() {
+ // leak this, so we don't incure any shutdown perf hit
+ static SkEvent_Globals* gGlobals = new SkEvent_Globals;
+ return *gGlobals;
}
-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());
+void SkEvent::postDelay(SkMSec delay) {
+ if (!fTargetID && !fTargetProc) {
+ delete this;
+ return;
}
-#endif
+
+ if (delay) {
+ this->postTime(SkTime::GetMSecs() + delay);
+ return;
+ }
+
+ SkEvent_Globals& globals = getGlobals();
globals.fEventMutex.acquire();
- bool wasEmpty = SkEvent::Enqueue(evt);
+ bool wasEmpty = SkEvent::Enqueue(this);
globals.fEventMutex.release();
-
+
// call outside of us holding the mutex
- if (wasEmpty)
+ 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());
+void SkEvent::postTime(SkMSec time) {
+ if (!fTargetID && !fTargetProc) {
+ delete this;
+ return;
}
-#endif
+ SkEvent_Globals& globals = getGlobals();
+
globals.fEventMutex.acquire();
- SkMSec queueDelay = SkEvent::EnqueueTime(evt, time);
+ SkMSec queueDelay = SkEvent::EnqueueTime(this, time);
globals.fEventMutex.release();
-
+
// call outside of us holding the mutex
- if ((int32_t)queueDelay != ~0)
+ 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);
+bool SkEvent::Enqueue(SkEvent* evt) {
+ SkEvent_Globals& globals = getGlobals();
// gEventMutex acquired by caller
SkASSERT(evt);
@@ -395,38 +348,30 @@ bool SkEvent::Enqueue(SkEvent* 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);
+SkEvent* SkEvent::Dequeue() {
+ SkEvent_Globals& globals = getGlobals();
globals.fEventMutex.acquire();
SkEvent* evt = globals.fEventQHead;
- if (evt)
- {
+ if (evt) {
SkDEBUGCODE(--globals.fEventCounter);
- if (sinkID)
- *sinkID = evt->fTargetID;
-
globals.fEventQHead = evt->fNextEvent;
- if (globals.fEventQHead == NULL)
+ 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);
+bool SkEvent::QHasEvents() {
+ SkEvent_Globals& globals = getGlobals();
// this is not thread accurate, need a semaphore for that
return globals.fEventQHead != NULL;
@@ -436,60 +381,49 @@ bool SkEvent::QHasEvents()
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);
+SkMSec SkEvent::EnqueueTime(SkEvent* evt, SkMSec time) {
+ SkEvent_Globals& globals = getGlobals();
// gEventMutex acquired by caller
SkEvent* curr = globals.fDelayQHead;
SkEvent* prev = NULL;
- while (curr)
- {
- if (SkMSec_LT(time, curr->fTime))
+ while (curr) {
+ if (SkMSec_LT(time, curr->fTime)) {
break;
+ }
prev = curr;
curr = curr->fNextEvent;
}
evt->fTime = time;
evt->fNextEvent = curr;
- if (prev == NULL)
+ if (prev == NULL) {
globals.fDelayQHead = evt;
- else
+ } else {
prev->fNextEvent = evt;
+ }
SkMSec delay = globals.fDelayQHead->fTime - SkTime::GetMSecs();
- if ((int32_t)delay <= 0)
+ if ((int32_t)delay <= 0) {
delay = 1;
+ }
return delay;
}
-//////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
#include "SkEventSink.h"
-bool SkEvent::ProcessEvent()
-{
- SkEventSinkID sinkID;
- SkEvent* evt = SkEvent::Dequeue(&sinkID);
+bool SkEvent::ProcessEvent() {
+ SkEvent* evt = SkEvent::Dequeue();
SkAutoTDelete<SkEvent> autoDelete(evt);
- bool again = false;
+ bool again = false;
EVENT_LOGN("ProcessEvent", (int32_t)evt);
- if (evt)
- {
- (void)SkEventSink::DoEvent(*evt, sinkID);
+ if (evt) {
+ (void)SkEventSink::DoEvent(*evt);
again = SkEvent::QHasEvents();
}
return again;
@@ -497,7 +431,7 @@ bool SkEvent::ProcessEvent()
void SkEvent::ServiceQueueTimer()
{
- SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+ SkEvent_Globals& globals = getGlobals();
globals.fEventMutex.acquire();
@@ -537,7 +471,7 @@ void SkEvent::ServiceQueueTimer()
}
int SkEvent::CountEventsOnQueue() {
- SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+ SkEvent_Globals& globals = getGlobals();
globals.fEventMutex.acquire();
int count = 0;
@@ -551,27 +485,22 @@ int SkEvent::CountEventsOnQueue() {
return count;
}
-////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
-void SkEvent::Init()
-{
-}
+void SkEvent::Init() {}
-void SkEvent::Term()
-{
- SkEvent_Globals& globals = *(SkEvent_Globals*)SkGlobals::Find(SK_Event_GlobalsTag, create_globals);
+void SkEvent::Term() {
+ SkEvent_Globals& globals = getGlobals();
SkEvent* evt = globals.fEventQHead;
- while (evt)
- {
+ while (evt) {
SkEvent* next = evt->fNextEvent;
delete evt;
evt = next;
}
evt = globals.fDelayQHead;
- while (evt)
- {
+ while (evt) {
SkEvent* next = evt->fNextEvent;
delete evt;
evt = next;
diff --git a/src/views/SkEventSink.cpp b/src/views/SkEventSink.cpp
index c8fe35c..0b01669 100644
--- a/src/views/SkEventSink.cpp
+++ b/src/views/SkEventSink.cpp
@@ -1,48 +1,39 @@
-/* libs/graphics/views/SkEventSink.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#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 {
+class SkEventSink_Globals {
public:
+ SkEventSink_Globals() {
+ fNextSinkID = 0;
+ fSinkHead = NULL;
+ }
+
SkMutex fSinkMutex;
SkEventSinkID fNextSinkID;
SkEventSink* fSinkHead;
};
-static SkGlobals::Rec* create_globals()
-{
- SkEventSink_Globals* rec = new SkEventSink_Globals;
- rec->fNextSinkID = 0;
- rec->fSinkHead = NULL;
- return rec;
+static SkEventSink_Globals& getGlobals() {
+ // leak this, so we don't incur any shutdown perf hit
+ static SkEventSink_Globals* gGlobals = new SkEventSink_Globals;
+ return *gGlobals;
}
-SkEventSink::SkEventSink() : fTagHead(NULL)
-{
- SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
+SkEventSink::SkEventSink() : fTagHead(NULL) {
+ SkEventSink_Globals& globals = getGlobals();
globals.fSinkMutex.acquire();
@@ -53,9 +44,8 @@ SkEventSink::SkEventSink() : fTagHead(NULL)
globals.fSinkMutex.release();
}
-SkEventSink::~SkEventSink()
-{
- SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
+SkEventSink::~SkEventSink() {
+ SkEventSink_Globals& globals = getGlobals();
if (fTagHead)
SkTagList::DeleteAll(fTagHead);
@@ -65,15 +55,14 @@ SkEventSink::~SkEventSink()
SkEventSink* sink = globals.fSinkHead;
SkEventSink* prev = NULL;
- for (;;)
- {
+ for (;;) {
SkEventSink* next = sink->fNextSink;
- if (sink == this)
- {
- if (prev)
+ if (sink == this) {
+ if (prev) {
prev->fNextSink = next;
- else
+ } else {
globals.fSinkHead = next;
+ }
break;
}
prev = sink;
@@ -82,36 +71,30 @@ SkEventSink::~SkEventSink()
globals.fSinkMutex.release();
}
-bool SkEventSink::doEvent(const SkEvent& evt)
-{
+bool SkEventSink::doEvent(const SkEvent& evt) {
return this->onEvent(evt);
}
-bool SkEventSink::doQuery(SkEvent* evt)
-{
+bool SkEventSink::doQuery(SkEvent* evt) {
SkASSERT(evt);
return this->onQuery(evt);
}
-bool SkEventSink::onEvent(const SkEvent&)
-{
+bool SkEventSink::onEvent(const SkEvent&) {
return false;
}
-bool SkEventSink::onQuery(SkEvent*)
-{
+bool SkEventSink::onQuery(SkEvent*) {
return false;
}
///////////////////////////////////////////////////////////////////////////////
-SkTagList* SkEventSink::findTagList(U8CPU tag) const
-{
+SkTagList* SkEventSink::findTagList(U8CPU tag) const {
return fTagHead ? SkTagList::Find(fTagHead, tag) : NULL;
}
-void SkEventSink::addTagList(SkTagList* rec)
-{
+void SkEventSink::addTagList(SkTagList* rec) {
SkASSERT(rec);
SkASSERT(fTagHead == NULL || SkTagList::Find(fTagHead, rec->fTag) == NULL);
@@ -119,10 +102,10 @@ void SkEventSink::addTagList(SkTagList* rec)
fTagHead = rec;
}
-void SkEventSink::removeTagList(U8CPU tag)
-{
- if (fTagHead)
+void SkEventSink::removeTagList(U8CPU tag) {
+ if (fTagHead) {
SkTagList::DeleteTag(&fTagHead, tag);
+ }
}
///////////////////////////////////////////////////////////////////////////////
@@ -221,58 +204,33 @@ bool SkEventSink::hasListeners() const
return this->findTagList(kListeners_SkTagList) != NULL;
}
-void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay)
-{
+void SkEventSink::postToListeners(const SkEvent& evt, SkMSec delay) {
SkListenersTagList* list = (SkListenersTagList*)this->findTagList(kListeners_SkTagList);
- if (list)
- {
+ 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);
+ while (iter < stop) {
+ SkEvent* copy = SkNEW_ARGS(SkEvent, (evt));
+ copy->setTargetID(*iter++)->postDelay(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
+SkEventSink::EventResult SkEventSink::DoEvent(const SkEvent& evt) {
+ SkEvent::Proc proc = evt.getTargetProc();
+ if (proc) {
+ return proc(evt) ? kHandled_EventResult : kNotHandled_EventResult;
+ }
+
+ SkEventSink* sink = SkEventSink::FindSink(evt.getTargetID());
+ if (sink) {
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;
- }
+ return kSinkNotFound_EventResult;
}
SkEventSink* SkEventSink::FindSink(SkEventSinkID sinkID)
@@ -280,7 +238,7 @@ SkEventSink* SkEventSink::FindSink(SkEventSinkID sinkID)
if (sinkID == 0)
return 0;
- SkEventSink_Globals& globals = *(SkEventSink_Globals*)SkGlobals::Find(SK_EventSink_GlobalsTag, create_globals);
+ SkEventSink_Globals& globals = getGlobals();
SkAutoMutexAcquire ac(globals.fSinkMutex);
SkEventSink* sink = globals.fSinkHead;
diff --git a/src/views/SkImageView.cpp b/src/views/SkImageView.cpp
index 9c358c7..8924dd3 100644
--- a/src/views/SkImageView.cpp
+++ b/src/views/SkImageView.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkImageView.h"
#include "SkAnimator.h"
#include "SkBitmap.h"
diff --git a/src/views/SkListView.cpp b/src/views/SkListView.cpp
index ba4f02a..20747a2 100644
--- a/src/views/SkListView.cpp
+++ b/src/views/SkListView.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkWidget.h"
#include "SkCanvas.h"
#include "SkEvent.h"
diff --git a/src/views/SkListWidget.cpp b/src/views/SkListWidget.cpp
index 89008e7..4d95e0f 100644
--- a/src/views/SkListWidget.cpp
+++ b/src/views/SkListWidget.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkWidgetViews.h"
#include "SkAnimator.h"
diff --git a/src/views/SkOSMenu.cpp b/src/views/SkOSMenu.cpp
index 3760ddd..ed37541 100644
--- a/src/views/SkOSMenu.cpp
+++ b/src/views/SkOSMenu.cpp
@@ -1,53 +1,263 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include <stdarg.h>
#include "SkOSMenu.h"
+#include "SkThread.h"
static int gOSMenuCmd = 7000;
-SkOSMenu::SkOSMenu(const char title[])
-{
- fTitle = title;
+SkOSMenu::SkOSMenu(const char title[]) {
+ fTitle.set(title);
}
-SkOSMenu::~SkOSMenu()
-{
+SkOSMenu::~SkOSMenu() {
+ this->reset();
}
-int SkOSMenu::countItems() const
-{
- return fItems.count();
+void SkOSMenu::reset() {
+ fItems.deleteAll();
+ fTitle.reset();
}
-void SkOSMenu::appendItem(const char title[], const char eventType[], int32_t eventData)
-{
- Item* item = fItems.append();
+const SkOSMenu::Item* SkOSMenu::getItemByID(int itemID) const {
+ for (int i = 0; i < fItems.count(); ++i) {
+ if (itemID == fItems[i]->getID())
+ return fItems[i];
+ }
+ return NULL;
+}
+
+void SkOSMenu::getItems(const SkOSMenu::Item* items[]) const {
+ if (NULL != items) {
+ for (int i = 0; i < fItems.count(); ++i) {
+ items[i] = fItems[i];
+ }
+ }
+}
+
+void SkOSMenu::assignKeyEquivalentToItem(int itemID, SkUnichar key) {
+ for (int i = 0; i < fItems.count(); ++i) {
+ if (itemID == fItems[i]->getID())
+ fItems[i]->setKeyEquivalent(key);
+ }
+}
+
+bool SkOSMenu::handleKeyEquivalent(SkUnichar key) {
+ int value = 0, size = 0;
+ bool state;
+ SkOSMenu::TriState tristate;
+ for (int i = 0; i < fItems.count(); ++i) {
+ Item* item = fItems[i];
+ if (item->getKeyEquivalent()== key) {
+ SkString list;
+ switch (item->getType()) {
+ case kList_Type:
+ SkOSMenu::FindListItemCount(*item->getEvent(), &size);
+ SkOSMenu::FindListIndex(*item->getEvent(), item->getSlotName(), &value);
+ value = (value + 1) % size;
+ item->setInt(value);
+ break;
+ case kSwitch_Type:
+ SkOSMenu::FindSwitchState(*item->getEvent(), item->getSlotName(), &state);
+ item->setBool(!state);
+ break;
+ case kTriState_Type:
+ SkOSMenu::FindTriState(*item->getEvent(), item->getSlotName(), &tristate);
+ if (kOnState == tristate)
+ tristate = kMixedState;
+ else
+ tristate = (SkOSMenu::TriState)((int)tristate + 1);
+ item->setTriState(tristate);
+ break;
+ case kAction_Type:
+ case kCustom_Type:
+ case kSlider_Type:
+ case kTextField_Type:
+ default:
+ break;
+ }
+ item->postEvent();
+ return true;
+ }
+ }
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+SkOSMenu::Item::Item(const char label[], SkOSMenu::Type type,
+ const char slotName[], SkEvent* evt) {
+ fLabel.set(label);
+ fSlotName.set(slotName);
+ fType = type;
+ fEvent = evt;
+ fKey = 0;
+ fID = sk_atomic_inc(&gOSMenuCmd);
+}
+
+void SkOSMenu::Item::setBool(bool value) const {
+ SkASSERT(SkOSMenu::kSwitch_Type == fType);
+ fEvent->setBool(fSlotName.c_str(), value);
+}
+
+void SkOSMenu::Item::setScalar(SkScalar value) const {
+ SkASSERT(SkOSMenu::kSlider_Type == fType);
+ fEvent->setScalar(fSlotName.c_str(), value);
+}
+
+void SkOSMenu::Item::setInt(int value) const {
+ SkASSERT(SkOSMenu::kList_Type == fType);
+ fEvent->setS32(fSlotName.c_str(), value);
+}
+
+void SkOSMenu::Item::setTriState(TriState value) const {
+ SkASSERT(SkOSMenu::kTriState_Type == fType);
+ fEvent->setS32(fSlotName.c_str(), value);
+}
+
+void SkOSMenu::Item::setString(const char value[]) const {
+ SkASSERT(SkOSMenu::kTextField_Type == fType);
+ fEvent->setString(fSlotName.c_str(), value);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static const char* gMenuEventType = "SkOSMenuEventType";
+static const char* gSlider_Min_Scalar = "SkOSMenuSlider_Min";
+static const char* gSlider_Max_Scalar = "SkOSMenuSlider_Max";
+static const char* gDelimiter = "|";
+static const char* gList_Items_Str = "SkOSMenuList_Items";
+static const char* gList_ItemCount_S32 = "SkOSMenuList_ItemCount";
+
+int SkOSMenu::appendItem(const char label[], Type type, const char slotName[],
+ SkEvent* evt) {
+ SkOSMenu::Item* item = new Item(label, type, slotName, evt);
+ fItems.append(1, &item);
+ return item->getID();
+}
- item->fTitle = title;
- item->fEventType = eventType;
- item->fEventData = eventData;
- item->fOSCmd = ++gOSMenuCmd;
+int SkOSMenu::appendAction(const char label[], SkEventSinkID target) {
+ SkEvent* evt = new SkEvent(gMenuEventType, target);
+ //Store label in event so it can be used to identify the action later
+ evt->setString(label, label);
+ return appendItem(label, SkOSMenu::kAction_Type, "", evt);
}
-SkEvent* SkOSMenu::createEvent(uint32_t os_cmd)
-{
- const Item* iter = fItems.begin();
- const Item* stop = fItems.end();
+int SkOSMenu::appendList(const char label[], const char slotName[],
+ SkEventSinkID target, int index, const char option[], ...) {
+ SkEvent* evt = new SkEvent(gMenuEventType, target);
+ va_list args;
+ if (option) {
+ SkString str(option);
+ va_start(args, option);
+ int count = 1;
+ for (const char* arg = va_arg(args, const char*); arg != NULL; arg = va_arg(args, const char*)) {
+ str += gDelimiter;
+ str += arg;
+ ++count;
+ }
+ va_end(args);
+ evt->setString(gList_Items_Str, str);
+ evt->setS32(gList_ItemCount_S32, count);
+ evt->setS32(slotName, index);
+ }
+ return appendItem(label, SkOSMenu::kList_Type, slotName, evt);
+}
+
+int SkOSMenu::appendSlider(const char label[], const char slotName[],
+ SkEventSinkID target, SkScalar min, SkScalar max,
+ SkScalar defaultValue) {
+ SkEvent* evt = new SkEvent(gMenuEventType, target);
+ evt->setScalar(gSlider_Min_Scalar, min);
+ evt->setScalar(gSlider_Max_Scalar, max);
+ evt->setScalar(slotName, defaultValue);
+ return appendItem(label, SkOSMenu::kSlider_Type, slotName, evt);
+}
+
+int SkOSMenu::appendSwitch(const char label[], const char slotName[],
+ SkEventSinkID target, bool defaultState) {
+ SkEvent* evt = new SkEvent(gMenuEventType, target);
+ evt->setBool(slotName, defaultState);
+ return appendItem(label, SkOSMenu::kSwitch_Type, slotName, evt);
+}
+
+int SkOSMenu::appendTriState(const char label[], const char slotName[],
+ SkEventSinkID target, SkOSMenu::TriState defaultState) {
+ SkEvent* evt = new SkEvent(gMenuEventType, target);
+ evt->setS32(slotName, defaultState);
+ return appendItem(label, SkOSMenu::kTriState_Type, slotName, evt);
+}
+
+int SkOSMenu::appendTextField(const char label[], const char slotName[],
+ SkEventSinkID target, const char placeholder[]) {
+ SkEvent* evt = new SkEvent(gMenuEventType, target);
+ evt->setString(slotName, placeholder);
+ return appendItem(label, SkOSMenu::kTextField_Type, slotName, evt);
+}
+
+bool SkOSMenu::FindListItemCount(const SkEvent& evt, int* count) {
+ return evt.isType(gMenuEventType) && evt.findS32(gList_ItemCount_S32, count);
+}
+
+bool SkOSMenu::FindListItems(const SkEvent& evt, SkString items[]) {
+ if (evt.isType(gMenuEventType) && NULL != items) {
+ const char* text = evt.findString(gList_Items_Str);
+ if (text != NULL) {
+ SkString temp(text);
+ char* token = strtok((char*)temp.c_str(), gDelimiter);
+ int index = 0;
+ while (token != NULL) {
+ items[index].set(token, strlen(token));
+ token = strtok (NULL, gDelimiter);
+ ++index;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool SkOSMenu::FindSliderMin(const SkEvent& evt, SkScalar* min) {
+ return evt.isType(gMenuEventType) && evt.findScalar(gSlider_Min_Scalar, min);
+}
+
+bool SkOSMenu::FindSliderMax(const SkEvent& evt, SkScalar* max) {
+ return evt.isType(gMenuEventType) && evt.findScalar(gSlider_Max_Scalar, max);
+}
+
+bool SkOSMenu::FindAction(const SkEvent& evt, const char label[]) {
+ return evt.isType(gMenuEventType) && evt.findString(label);
+}
+
+bool SkOSMenu::FindListIndex(const SkEvent& evt, const char slotName[], int* value) {
+ return evt.isType(gMenuEventType) && evt.findS32(slotName, value);
+}
- while (iter < stop)
- {
- if (iter->fOSCmd == os_cmd)
- {
- SkEvent* evt = new SkEvent(iter->fEventType);
- evt->setFast32(iter->fEventData);
- return evt;
- }
- iter++;
- }
- return NULL;
+bool SkOSMenu::FindSliderValue(const SkEvent& evt, const char slotName[], SkScalar* value) {
+ return evt.isType(gMenuEventType) && evt.findScalar(slotName, value);
}
-const char* SkOSMenu::getItem(int index, uint32_t* cmdID) const
-{
- if (cmdID)
- *cmdID = fItems[index].fOSCmd;
- return fItems[index].fTitle;
+bool SkOSMenu::FindSwitchState(const SkEvent& evt, const char slotName[], bool* value) {
+ return evt.isType(gMenuEventType) && evt.findBool(slotName, value);
}
+bool SkOSMenu::FindTriState(const SkEvent& evt, const char slotName[], SkOSMenu::TriState* value) {
+ return evt.isType(gMenuEventType) && evt.findS32(slotName, (int*)value);
+}
+
+bool SkOSMenu::FindText(const SkEvent& evt, const char slotName[], SkString* value) {
+ if (evt.isType(gMenuEventType)) {
+ const char* text = evt.findString(slotName);
+ if (!text || !*text)
+ return false;
+ else {
+ value->set(text);
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/views/SkParsePaint.cpp b/src/views/SkParsePaint.cpp
index a79f30c..4839439 100644
--- a/src/views/SkParsePaint.cpp
+++ b/src/views/SkParsePaint.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkParsePaint.h"
#include "SkTSearch.h"
#include "SkParse.h"
diff --git a/src/views/SkProgressBarView.cpp b/src/views/SkProgressBarView.cpp
index a9fd516..ce26ac4 100644
--- a/src/views/SkProgressBarView.cpp
+++ b/src/views/SkProgressBarView.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkProgressBarView.h"
#include "SkAnimator.h"
#include "SkWidgetViews.h"
diff --git a/src/views/SkProgressView.cpp b/src/views/SkProgressView.cpp
index 0c81bcc..d82b48e 100644
--- a/src/views/SkProgressView.cpp
+++ b/src/views/SkProgressView.cpp
@@ -1,5 +1,13 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkWidget.h"
#include "SkCanvas.h"
+#include "SkMath.h"
#include "SkShader.h"
#include "SkInterpolator.h"
#include "SkTime.h"
diff --git a/src/views/SkScrollBarView.cpp b/src/views/SkScrollBarView.cpp
index 2e087bd..98288f5 100644
--- a/src/views/SkScrollBarView.cpp
+++ b/src/views/SkScrollBarView.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkScrollBarView.h"
#include "SkAnimator.h"
#include "SkWidgetViews.h"
diff --git a/src/views/SkStackViewLayout.cpp b/src/views/SkStackViewLayout.cpp
index ae2e9e8..bf6f363 100644
--- a/src/views/SkStackViewLayout.cpp
+++ b/src/views/SkStackViewLayout.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkStackViewLayout.h"
SkStackViewLayout::SkStackViewLayout()
@@ -195,8 +202,9 @@ void SkStackViewLayout::onInflate(const SkDOM& dom, const SkDOM::Node* node)
if ((index = dom.findList(node, "orient", "horizontal,vertical")) >= 0)
this->setOrient((Orient)index);
- else
+ else {
assert_no_attr(dom, node, "orient");
+ }
if (dom.findScalars(node, "margin", value, 4))
{
@@ -204,23 +212,27 @@ void SkStackViewLayout::onInflate(const SkDOM& dom, const SkDOM::Node* node)
margin.set(value[0], value[1], value[2], value[3]);
this->setMargin(margin);
}
- else
+ else {
assert_no_attr(dom, node, "margin");
+ }
if (dom.findScalar(node, "spacer", value))
this->setSpacer(value[0]);
- else
+ else {
assert_no_attr(dom, node, "spacer");
+ }
if ((index = dom.findList(node, "pack", "start,center,end")) >= 0)
this->setPack((Pack)index);
- else
+ else {
assert_no_attr(dom, node, "pack");
+ }
if ((index = dom.findList(node, "align", "start,center,end,stretch")) >= 0)
this->setAlign((Align)index);
- else
+ else {
assert_no_attr(dom, node, "align");
+ }
}
///////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/views/SkStaticTextView.cpp b/src/views/SkStaticTextView.cpp
index 8fb8bc1..2fd04a7 100644
--- a/src/views/SkStaticTextView.cpp
+++ b/src/views/SkStaticTextView.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkWidgetViews.h"
#include "SkTextBox.h"
diff --git a/src/views/SkTagList.cpp b/src/views/SkTagList.cpp
index 4576ce6..e1b1662 100644
--- a/src/views/SkTagList.cpp
+++ b/src/views/SkTagList.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/views/SkTagList.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTagList.h"
diff --git a/src/views/SkTagList.h b/src/views/SkTagList.h
index 5f428e4..47294e3 100644
--- a/src/views/SkTagList.h
+++ b/src/views/SkTagList.h
@@ -1,19 +1,11 @@
-/* libs/graphics/views/SkTagList.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkTagList_DEFINED
#define SkTagList_DEFINED
diff --git a/src/views/SkTextBox.cpp b/src/views/SkTextBox.cpp
index 0e31ac6..6a88c6c 100644
--- a/src/views/SkTextBox.cpp
+++ b/src/views/SkTextBox.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/views/SkTextBox.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkTextBox.h"
#include "../core/SkGlyphCache.h"
diff --git a/src/views/SkTouchGesture.cpp b/src/views/SkTouchGesture.cpp
index 1732176..31adc74 100644
--- a/src/views/SkTouchGesture.cpp
+++ b/src/views/SkTouchGesture.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2010 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkTouchGesture.h"
#include "SkMatrix.h"
#include "SkTime.h"
@@ -35,8 +28,8 @@ static double getseconds() {
}
// returns +1 or -1, depending on the sign of x
-// returns +1 if x is zero
-static SkScalar SkScalarSign(SkScalar x) {
+// returns +1 if z is zero
+static SkScalar SkScalarSignNonZero(SkScalar x) {
SkScalar sign = SK_Scalar1;
if (x < 0) {
sign = -sign;
@@ -48,9 +41,9 @@ static void unit_axis_align(SkVector* unit) {
const SkScalar TOLERANCE = SkDoubleToScalar(0.15);
if (SkScalarAbs(unit->fX) < TOLERANCE) {
unit->fX = 0;
- unit->fY = SkScalarSign(unit->fY);
+ unit->fY = SkScalarSignNonZero(unit->fY);
} else if (SkScalarAbs(unit->fY) < TOLERANCE) {
- unit->fX = SkScalarSign(unit->fX);
+ unit->fX = SkScalarSignNonZero(unit->fX);
unit->fY = 0;
}
}
diff --git a/src/views/SkView.cpp b/src/views/SkView.cpp
index 1cd6339..fc1ddfb 100644
--- a/src/views/SkView.cpp
+++ b/src/views/SkView.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkView.h"
#include "SkCanvas.h"
@@ -8,7 +15,7 @@ SkView::SkView(uint32_t flags) : fFlags(SkToU8(flags))
fWidth = fHeight = 0;
fLoc.set(0, 0);
fParent = fFirstChild = fNextSibling = fPrevSibling = NULL;
-
+ fMatrix.setIdentity();
fContainsFocus = 0;
}
@@ -75,7 +82,7 @@ void SkView::setLoc(SkScalar x, SkScalar y)
{
this->inval(NULL);
fLoc.set(x, y);
- this->inval(NULL);
+ this->inval(NULL);
}
}
@@ -85,6 +92,13 @@ void SkView::offset(SkScalar dx, SkScalar dy)
this->setLoc(fLoc.fX + dx, fLoc.fY + dy);
}
+void SkView::setLocalMatrix(const SkMatrix& matrix)
+{
+ this->inval(NULL);
+ fMatrix = matrix;
+ this->inval(NULL);
+}
+
void SkView::draw(SkCanvas* canvas)
{
if (fWidth && fHeight && this->isVisible())
@@ -101,8 +115,10 @@ void SkView::draw(SkCanvas* canvas)
if (this->isClipToBounds()) {
canvas->clipRect(r);
}
- canvas->translate(fLoc.fX, fLoc.fY);
-
+
+ canvas->translate(fLoc.fX, fLoc.fY);
+ canvas->concat(fMatrix);
+
if (fParent) {
fParent->beforeChild(this, canvas);
}
@@ -296,10 +312,11 @@ void SkView::onFocusChange(bool gainFocusP)
SkView::Click::Click(SkView* target)
{
- SkASSERT(target);
- fTargetID = target->getSinkID();
- fType = NULL;
- fWeOwnTheType = false;
+ SkASSERT(target);
+ fTargetID = target->getSinkID();
+ fType = NULL;
+ fWeOwnTheType = false;
+ fOwner = NULL;
}
SkView::Click::~Click()
@@ -355,17 +372,20 @@ void SkView::Click::copyType(const char type[])
SkView::Click* SkView::findClickHandler(SkScalar x, SkScalar y)
{
if (x < 0 || y < 0 || x >= fWidth || y >= fHeight) {
- return false;
+ return NULL;
}
if (this->onSendClickToChildren(x, y)) {
F2BIter iter(this);
SkView* child;
-
+
while ((child = iter.next()) != NULL)
{
- Click* click = child->findClickHandler(x - child->fLoc.fX,
- y - child->fLoc.fY);
+ SkPoint p;
+ child->globalToLocal(x, y, &p);
+
+ Click* click = child->findClickHandler(p.fX, p.fY);
+
if (click) {
return click;
}
@@ -586,20 +606,30 @@ void SkView::detachAllChildren()
fFirstChild->detachFromParent_NoLayout();
}
+void SkView::localToGlobal(SkMatrix* matrix) const
+{
+ if (matrix) {
+ matrix->reset();
+ const SkView* view = this;
+ while (view)
+ {
+ matrix->preConcat(view->getLocalMatrix());
+ matrix->preTranslate(-view->fLoc.fX, -view->fLoc.fY);
+ view = view->fParent;
+ }
+ }
+}
void SkView::globalToLocal(SkScalar x, SkScalar y, SkPoint* local) const
{
SkASSERT(this);
-
if (local)
{
- const SkView* view = this;
- while (view)
- {
- x -= view->fLoc.fX;
- y -= view->fLoc.fY;
- view = view->fParent;
- }
- local->set(x, y);
+ SkMatrix m;
+ this->localToGlobal(&m);
+ SkPoint p;
+ m.invert(&m);
+ m.mapXY(x, y, &p);
+ local->set(p.fX, p.fY);
}
}
diff --git a/src/views/SkViewInflate.cpp b/src/views/SkViewInflate.cpp
index 8f5489d..184e540 100644
--- a/src/views/SkViewInflate.cpp
+++ b/src/views/SkViewInflate.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkViewInflate.h"
#include "SkView.h"
#include <stdio.h>
diff --git a/src/views/SkViewPriv.cpp b/src/views/SkViewPriv.cpp
index b03ca8c..ad15f3f 100644
--- a/src/views/SkViewPriv.cpp
+++ b/src/views/SkViewPriv.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkViewPriv.h"
//////////////////////////////////////////////////////////////////////
diff --git a/src/views/SkViewPriv.h b/src/views/SkViewPriv.h
index 06ce59b..d8cf966 100644
--- a/src/views/SkViewPriv.h
+++ b/src/views/SkViewPriv.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkViewPriv_DEFINED
#define SkViewPriv_DEFINED
diff --git a/src/views/SkWidget.cpp b/src/views/SkWidget.cpp
index 4d055c4..104429d 100644
--- a/src/views/SkWidget.cpp
+++ b/src/views/SkWidget.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkWidget.h"
#include "SkCanvas.h"
#include "SkInterpolator.h"
diff --git a/src/views/SkWidgetViews.cpp b/src/views/SkWidgetViews.cpp
index 2705307..2803d93 100644
--- a/src/views/SkWidgetViews.cpp
+++ b/src/views/SkWidgetViews.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkWidgetViews.h"
#include "SkAnimator.h"
#include "SkCanvas.h"
@@ -398,7 +405,7 @@ SkView* SkWidgetFactory(SkWidgetEnum sw)
case kText_WidgetEnum:
return new SkStaticTextView;
default:
- SkASSERT(!"unknown enum passed to SkWidgetFactory");
+ SkDEBUGFAIL("unknown enum passed to SkWidgetFactory");
break;
}
return NULL;
diff --git a/src/views/SkWidgets.cpp b/src/views/SkWidgets.cpp
index dba9ab3..69d755b 100644
--- a/src/views/SkWidgets.cpp
+++ b/src/views/SkWidgets.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkWidget.h"
#include "SkCanvas.h"
#include "SkKey.h"
diff --git a/src/views/SkWindow.cpp b/src/views/SkWindow.cpp
index db4faee..c952a61 100644
--- a/src/views/SkWindow.cpp
+++ b/src/views/SkWindow.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkWindow.h"
#include "SkCanvas.h"
#include "SkDevice.h"
@@ -41,13 +48,13 @@ private:
SkWindow::SkWindow() : fFocusView(NULL)
{
- fClick = NULL;
- fWaitingOnInval = false;
+ fClicks.reset();
+ fWaitingOnInval = false;
#ifdef SK_BUILD_FOR_WINCE
- fConfig = SkBitmap::kRGB_565_Config;
+ fConfig = SkBitmap::kRGB_565_Config;
#else
- fConfig = SkBitmap::kARGB_8888_Config;
+ fConfig = SkBitmap::kARGB_8888_Config;
#endif
fMatrix.reset();
@@ -55,9 +62,8 @@ SkWindow::SkWindow() : fFocusView(NULL)
SkWindow::~SkWindow()
{
- delete fClick;
-
- fMenus.deleteAll();
+ fClicks.deleteAll();
+ fMenus.deleteAll();
}
void SkWindow::setMatrix(const SkMatrix& matrix) {
@@ -168,15 +174,11 @@ bool SkWindow::update(SkIRect* updateArea, SkCanvas* canvas)
#endif
SkCanvas rasterCanvas;
- SkDevice* device;
if (NULL == canvas) {
canvas = &rasterCanvas;
- device = new SkDevice(canvas, bm, false);
- canvas->setDevice(device)->unref();
- } else {
- canvas->setBitmapDevice(bm);
}
+ canvas->setBitmapDevice(bm);
canvas->clipRegion(fDirtyRgn);
if (updateArea)
@@ -287,8 +289,7 @@ bool SkWindow::handleKeyUp(SkKey key)
return false;
}
-void SkWindow::addMenu(SkOSMenu* menu)
-{
+void SkWindow::addMenu(SkOSMenu* menu) {
*fMenus.append() = menu;
this->onAddMenu(menu);
}
@@ -301,20 +302,6 @@ void SkWindow::setTitle(const char title[]) {
this->onSetTitle(title);
}
-bool SkWindow::handleMenu(uint32_t cmd)
-{
- for (int i = 0; i < fMenus.count(); i++)
- {
- SkEvent* evt = fMenus[i]->createEvent(cmd);
- if (evt)
- {
- evt->post(this->getSinkID());
- return true;
- }
- }
- return false;
-}
-
//////////////////////////////////////////////////////////////////////
bool SkWindow::onEvent(const SkEvent& evt)
@@ -372,40 +359,57 @@ bool SkWindow::onHandleKeyUp(SkKey key)
return false;
}
-bool SkWindow::handleClick(int x, int y, Click::State state) {
- return this->onDispatchClick(x, y, state);
+bool SkWindow::handleClick(int x, int y, Click::State state, void *owner) {
+ return this->onDispatchClick(x, y, state, owner);
}
-bool SkWindow::onDispatchClick(int x, int y, Click::State state) {
+bool SkWindow::onDispatchClick(int x, int y, Click::State state,
+ void* owner) {
bool handled = false;
+ // First, attempt to find an existing click with this owner.
+ int index = -1;
+ for (int i = 0; i < fClicks.count(); i++) {
+ if (owner == fClicks[i]->fOwner) {
+ index = i;
+ break;
+ }
+ }
+
switch (state) {
- case Click::kDown_State:
- if (fClick)
- delete fClick;
- fClick = this->findClickHandler(SkIntToScalar(x), SkIntToScalar(y));
- if (fClick)
- {
- SkView::DoClickDown(fClick, x, y);
- handled = true;
- }
- break;
- case Click::kMoved_State:
- if (fClick)
- {
- SkView::DoClickMoved(fClick, x, y);
- handled = true;
- }
- break;
- case Click::kUp_State:
- if (fClick)
- {
- SkView::DoClickUp(fClick, x, y);
- delete fClick;
- fClick = NULL;
- handled = true;
- }
- break;
+ case Click::kDown_State: {
+ if (index != -1) {
+ delete fClicks[index];
+ fClicks.remove(index);
+ }
+ Click* click = this->findClickHandler(SkIntToScalar(x),
+ SkIntToScalar(y));
+
+ if (click) {
+ click->fOwner = owner;
+ *fClicks.append() = click;
+ SkView::DoClickDown(click, x, y);
+ handled = true;
+ }
+ break;
+ }
+ case Click::kMoved_State:
+ if (index != -1) {
+ SkView::DoClickMoved(fClicks[index], x, y);
+ handled = true;
+ }
+ break;
+ case Click::kUp_State:
+ if (index != -1) {
+ SkView::DoClickUp(fClicks[index], x, y);
+ delete fClicks[index];
+ fClicks.remove(index);
+ handled = true;
+ }
+ break;
+ default:
+ // Do nothing
+ break;
}
return handled;
}
diff --git a/src/xml/SkBML_Verbs.h b/src/xml/SkBML_Verbs.h
index 86bfede..709764d 100644
--- a/src/xml/SkBML_Verbs.h
+++ b/src/xml/SkBML_Verbs.h
@@ -1,19 +1,11 @@
-/* libs/graphics/xml/SkBML_Verbs.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#ifndef SkBML_Verbs_DEFINED
#define SkBML_Verbs_DEFINED
diff --git a/src/xml/SkBML_XMLParser.cpp b/src/xml/SkBML_XMLParser.cpp
index 53b7f61..dbdfe4b 100644
--- a/src/xml/SkBML_XMLParser.cpp
+++ b/src/xml/SkBML_XMLParser.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/xml/SkBML_XMLParser.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkBML_XMLParser.h"
#include "SkBML_Verbs.h"
@@ -120,7 +112,7 @@ static void rattr(unsigned verb, SkStream& s, BMLW& rec, SkXMLWriter& writer)
valueIndex = rbyte(s);
break;
default:
- SkASSERT(!"bad verb");
+ SkDEBUGFAIL("bad verb");
return;
}
writer.addAttribute(rec.fNames[nameIndex], rec.fValues[valueIndex]);
@@ -164,7 +156,7 @@ static void relem(unsigned verb, SkStream& s, BMLW& rec, SkXMLWriter& writer)
writer.endElement();
return;
default:
- SkASSERT(!"bad verb");
+ SkDEBUGFAIL("bad verb");
}
}
}
diff --git a/src/xml/SkDOM.cpp b/src/xml/SkDOM.cpp
index a9fc31e..474c291 100644
--- a/src/xml/SkDOM.cpp
+++ b/src/xml/SkDOM.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/xml/SkDOM.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkDOM.h"
diff --git a/src/xml/SkJS.cpp b/src/xml/SkJS.cpp
index 03ccba6..f2e7a83 100644
--- a/src/xml/SkJS.cpp
+++ b/src/xml/SkJS.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/xml/SkJS.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include <jsapi.h>
diff --git a/src/xml/SkJSDisplayable.cpp b/src/xml/SkJSDisplayable.cpp
index 848b9f9..0e14fde 100644
--- a/src/xml/SkJSDisplayable.cpp
+++ b/src/xml/SkJSDisplayable.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/xml/SkJSDisplayable.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include <jsapi.h>
#include "SkJS.h"
diff --git a/src/xml/SkXMLParser.cpp b/src/xml/SkXMLParser.cpp
index da33307..17329be 100644
--- a/src/xml/SkXMLParser.cpp
+++ b/src/xml/SkXMLParser.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/xml/SkXMLParser.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkXMLParser.h"
diff --git a/src/xml/SkXMLPullParser.cpp b/src/xml/SkXMLPullParser.cpp
index 5df75b7..03fed42 100644
--- a/src/xml/SkXMLPullParser.cpp
+++ b/src/xml/SkXMLPullParser.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkXMLParser.h"
#include "SkStream.h"
diff --git a/src/xml/SkXMLWriter.cpp b/src/xml/SkXMLWriter.cpp
index 4685d81..935745d 100644
--- a/src/xml/SkXMLWriter.cpp
+++ b/src/xml/SkXMLWriter.cpp
@@ -1,19 +1,11 @@
-/* libs/graphics/xml/SkXMLWriter.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkXMLWriter.h"
#include "SkStream.h"
diff --git a/tests/AAClipTest.cpp b/tests/AAClipTest.cpp
new file mode 100644
index 0000000..b3051fd
--- /dev/null
+++ b/tests/AAClipTest.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#include "SkAAClip.h"
+#include "SkCanvas.h"
+#include "SkMask.h"
+#include "SkPath.h"
+#include "SkRandom.h"
+
+static bool operator==(const SkMask& a, const SkMask& b) {
+ if (a.fFormat != b.fFormat || a.fBounds != b.fBounds) {
+ return false;
+ }
+ if (!a.fImage && !b.fImage) {
+ return true;
+ }
+ if (!a.fImage || !b.fImage) {
+ return false;
+ }
+
+ size_t wbytes = a.fBounds.width();
+ switch (a.fFormat) {
+ case SkMask::kBW_Format:
+ wbytes = (wbytes + 7) >> 3;
+ break;
+ case SkMask::kA8_Format:
+ case SkMask::k3D_Format:
+ break;
+ case SkMask::kLCD16_Format:
+ wbytes <<= 1;
+ break;
+ case SkMask::kLCD32_Format:
+ case SkMask::kARGB32_Format:
+ wbytes <<= 2;
+ break;
+ default:
+ SkASSERT(!"unknown mask format");
+ return false;
+ }
+
+ const int h = a.fBounds.height();
+ const char* aptr = (const char*)a.fImage;
+ const char* bptr = (const char*)b.fImage;
+ for (int y = 0; y < h; ++y) {
+ if (memcmp(aptr, bptr, wbytes)) {
+ return false;
+ }
+ aptr += wbytes;
+ bptr += wbytes;
+ }
+ return true;
+}
+
+static void copyToMask(const SkRegion& rgn, SkMask* mask) {
+ mask->fFormat = SkMask::kA8_Format;
+
+ if (rgn.isEmpty()) {
+ mask->fBounds.setEmpty();
+ mask->fRowBytes = 0;
+ mask->fImage = NULL;
+ return;
+ }
+
+ mask->fBounds = rgn.getBounds();
+ mask->fRowBytes = mask->fBounds.width();
+ mask->fImage = SkMask::AllocImage(mask->computeImageSize());
+ sk_bzero(mask->fImage, mask->computeImageSize());
+
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kA8_Config, mask->fBounds.width(),
+ mask->fBounds.height(), mask->fRowBytes);
+ bitmap.setPixels(mask->fImage);
+
+ // canvas expects its coordinate system to always be 0,0 in the top/left
+ // so we translate the rgn to match that before drawing into the mask.
+ //
+ SkRegion tmpRgn(rgn);
+ tmpRgn.translate(-rgn.getBounds().fLeft, -rgn.getBounds().fTop);
+
+ SkCanvas canvas(bitmap);
+ canvas.clipRegion(tmpRgn);
+ canvas.drawColor(SK_ColorBLACK);
+}
+
+static SkIRect rand_rect(SkRandom& rand, int n) {
+ int x = rand.nextS() % n;
+ int y = rand.nextS() % n;
+ int w = rand.nextU() % n;
+ int h = rand.nextU() % n;
+ return SkIRect::MakeXYWH(x, y, w, h);
+}
+
+static void make_rand_rgn(SkRegion* rgn, SkRandom& rand) {
+ int count = rand.nextU() % 20;
+ for (int i = 0; i < count; ++i) {
+ rgn->op(rand_rect(rand, 100), SkRegion::kXOR_Op);
+ }
+}
+
+static bool operator==(const SkRegion& rgn, const SkAAClip& aaclip) {
+ SkMask mask0, mask1;
+
+ copyToMask(rgn, &mask0);
+ aaclip.copyToMask(&mask1);
+ bool eq = (mask0 == mask1);
+
+ SkMask::FreeImage(mask0.fImage);
+ SkMask::FreeImage(mask1.fImage);
+ return eq;
+}
+
+static bool equalsAAClip(const SkRegion& rgn) {
+ SkAAClip aaclip;
+ aaclip.setRegion(rgn);
+ return rgn == aaclip;
+}
+
+static void setRgnToPath(SkRegion* rgn, const SkPath& path) {
+ SkIRect ir;
+ path.getBounds().round(&ir);
+ rgn->setPath(path, SkRegion(ir));
+}
+
+// aaclip.setRegion should create idential masks to the region
+static void test_rgn(skiatest::Reporter* reporter) {
+ SkRandom rand;
+ for (int i = 0; i < 1000; i++) {
+ SkRegion rgn;
+ make_rand_rgn(&rgn, rand);
+ REPORTER_ASSERT(reporter, equalsAAClip(rgn));
+ }
+
+ {
+ SkRegion rgn;
+ SkPath path;
+ path.addCircle(0, 0, SkIntToScalar(30));
+ setRgnToPath(&rgn, path);
+ REPORTER_ASSERT(reporter, equalsAAClip(rgn));
+
+ path.reset();
+ path.moveTo(0, 0);
+ path.lineTo(SkIntToScalar(100), 0);
+ path.lineTo(SkIntToScalar(100 - 20), SkIntToScalar(20));
+ path.lineTo(SkIntToScalar(20), SkIntToScalar(20));
+ setRgnToPath(&rgn, path);
+ REPORTER_ASSERT(reporter, equalsAAClip(rgn));
+ }
+}
+
+static const SkRegion::Op gRgnOps[] = {
+ SkRegion::kDifference_Op,
+ SkRegion::kIntersect_Op,
+ SkRegion::kUnion_Op,
+ SkRegion::kXOR_Op,
+ SkRegion::kReverseDifference_Op,
+ SkRegion::kReplace_Op
+};
+
+static const char* gRgnOpNames[] = {
+ "DIFF", "INTERSECT", "UNION", "XOR", "REVERSE_DIFF", "REPLACE"
+};
+
+static void imoveTo(SkPath& path, int x, int y) {
+ path.moveTo(SkIntToScalar(x), SkIntToScalar(y));
+}
+
+static void icubicTo(SkPath& path, int x0, int y0, int x1, int y1, int x2, int y2) {
+ path.cubicTo(SkIntToScalar(x0), SkIntToScalar(y0),
+ SkIntToScalar(x1), SkIntToScalar(y1),
+ SkIntToScalar(x2), SkIntToScalar(y2));
+}
+
+static void test_path_bounds(skiatest::Reporter* reporter) {
+ SkPath path;
+ SkAAClip clip;
+ const int height = 40;
+ const SkScalar sheight = SkIntToScalar(height);
+
+ path.addOval(SkRect::MakeWH(sheight, sheight));
+ REPORTER_ASSERT(reporter, sheight == path.getBounds().height());
+ clip.setPath(path, NULL, true);
+ REPORTER_ASSERT(reporter, height == clip.getBounds().height());
+
+ // this is the trimmed height of this cubic (with aa). The critical thing
+ // for this test is that it is less than height, which represents just
+ // the bounds of the path's control-points.
+ //
+ // This used to fail until we tracked the MinY in the BuilderBlitter.
+ //
+ const int teardrop_height = 12;
+ path.reset();
+ imoveTo(path, 0, 20);
+ icubicTo(path, 40, 40, 40, 0, 0, 20);
+ REPORTER_ASSERT(reporter, sheight == path.getBounds().height());
+ clip.setPath(path, NULL, true);
+ REPORTER_ASSERT(reporter, teardrop_height == clip.getBounds().height());
+}
+
+static void test_empty(skiatest::Reporter* reporter) {
+ SkAAClip clip0, clip1;
+
+ REPORTER_ASSERT(reporter, clip0.isEmpty());
+ REPORTER_ASSERT(reporter, clip0.getBounds().isEmpty());
+ REPORTER_ASSERT(reporter, clip1 == clip0);
+
+ clip0.translate(10, 10); // should have no effect on empty
+ REPORTER_ASSERT(reporter, clip0.isEmpty());
+ REPORTER_ASSERT(reporter, clip0.getBounds().isEmpty());
+ REPORTER_ASSERT(reporter, clip1 == clip0);
+
+ SkIRect r = { 10, 10, 40, 50 };
+ clip0.setRect(r);
+ REPORTER_ASSERT(reporter, !clip0.isEmpty());
+ REPORTER_ASSERT(reporter, !clip0.getBounds().isEmpty());
+ REPORTER_ASSERT(reporter, clip0 != clip1);
+ REPORTER_ASSERT(reporter, clip0.getBounds() == r);
+
+ clip0.setEmpty();
+ REPORTER_ASSERT(reporter, clip0.isEmpty());
+ REPORTER_ASSERT(reporter, clip0.getBounds().isEmpty());
+ REPORTER_ASSERT(reporter, clip1 == clip0);
+
+ SkMask mask;
+ mask.fImage = NULL;
+ clip0.copyToMask(&mask);
+ REPORTER_ASSERT(reporter, NULL == mask.fImage);
+ REPORTER_ASSERT(reporter, mask.fBounds.isEmpty());
+}
+
+static void rand_irect(SkIRect* r, int N, SkRandom& rand) {
+ r->setXYWH(0, 0, rand.nextU() % N, rand.nextU() % N);
+ int dx = rand.nextU() % (2*N);
+ int dy = rand.nextU() % (2*N);
+ // use int dx,dy to make the subtract be signed
+ r->offset(N - dx, N - dy);
+}
+
+static void test_irect(skiatest::Reporter* reporter) {
+ SkRandom rand;
+
+ for (int i = 0; i < 10000; i++) {
+ SkAAClip clip0, clip1;
+ SkRegion rgn0, rgn1;
+ SkIRect r0, r1;
+
+ rand_irect(&r0, 10, rand);
+ rand_irect(&r1, 10, rand);
+ clip0.setRect(r0);
+ clip1.setRect(r1);
+ rgn0.setRect(r0);
+ rgn1.setRect(r1);
+ for (size_t j = 0; j < SK_ARRAY_COUNT(gRgnOps); ++j) {
+ SkRegion::Op op = gRgnOps[j];
+ SkAAClip clip2;
+ SkRegion rgn2;
+ bool nonEmptyAA = clip2.op(clip0, clip1, op);
+ bool nonEmptyBW = rgn2.op(rgn0, rgn1, op);
+ if (nonEmptyAA != nonEmptyBW || clip2.getBounds() != rgn2.getBounds()) {
+ SkDebugf("[%d %d %d %d] %s [%d %d %d %d] = BW:[%d %d %d %d] AA:[%d %d %d %d]\n",
+ r0.fLeft, r0.fTop, r0.right(), r0.bottom(),
+ gRgnOpNames[j],
+ r1.fLeft, r1.fTop, r1.right(), r1.bottom(),
+ rgn2.getBounds().fLeft, rgn2.getBounds().fTop,
+ rgn2.getBounds().right(), rgn2.getBounds().bottom(),
+ clip2.getBounds().fLeft, clip2.getBounds().fTop,
+ clip2.getBounds().right(), clip2.getBounds().bottom());
+ }
+ REPORTER_ASSERT(reporter, nonEmptyAA == nonEmptyBW);
+ REPORTER_ASSERT(reporter, clip2.getBounds() == rgn2.getBounds());
+ }
+ }
+}
+
+static void TestAAClip(skiatest::Reporter* reporter) {
+ test_empty(reporter);
+ test_path_bounds(reporter);
+ test_irect(reporter);
+ test_rgn(reporter);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("AAClip", AAClipTestClass, TestAAClip)
diff --git a/tests/Android.mk b/tests/Android.mk
index 4db6c75..14d23f8 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -3,23 +3,32 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AAClipTest.cpp \
BitmapCopyTest.cpp \
BitmapGetColorTest.cpp \
BlitRowTest.cpp \
+ BlurTest.cpp \
+ CanvasTest.cpp \
ClampRangeTest.cpp \
ClipCubicTest.cpp \
ClipStackTest.cpp \
ClipperTest.cpp \
ColorFilterTest.cpp \
ColorTest.cpp \
+ DataRefTest.cpp \
DequeTest.cpp \
DrawBitmapRectTest.cpp \
+ EmptyPathTest.cpp \
FillPathTest.cpp \
FlateTest.cpp \
GeometryTest.cpp \
+ GLInterfaceValidation.cpp \
+ GLProgramsTest.cpp \
InfRectTest.cpp \
MathTest.cpp \
MatrixTest.cpp \
+ Matrix44Test.cpp \
+ MemsetTest.cpp \
MetaDataTest.cpp \
PackBitsTest.cpp \
PaintTest.cpp \
@@ -27,37 +36,53 @@ LOCAL_SRC_FILES:= \
PathCoverageTest.cpp \
PathMeasureTest.cpp \
PathTest.cpp \
+ PointTest.cpp \
+ QuickRejectTest.cpp \
Reader32Test.cpp \
+ ReadPixelsTest.cpp \
RefDictTest.cpp \
RegionTest.cpp \
+ ScalarTest.cpp \
+ ShaderOpacityTest.cpp \
Sk64Test.cpp \
+ skia_test.cpp \
SortTest.cpp \
SrcOverTest.cpp \
StreamTest.cpp \
StringTest.cpp \
Test.cpp \
+ Test.h \
TestSize.cpp \
+ UnicodeTest.cpp \
UtilsTest.cpp \
+ WArrayTest.cpp \
+ WritePixelsTest.cpp \
Writer32Test.cpp \
XfermodeTest.cpp
-# The name of the file with a main function must
-# match native test's naming rule: xxx_test.cpp.
-LOCAL_SRC_FILES += \
- skia_test.cpp
+# TODO: tests that currently are causing build problems
+#LOCAL_SRC_FILES += \
+# BitSetTest.cpp \
+# PDFPrimitivesTest.cpp \
+# ToUnicode.cpp
LOCAL_MODULE:= skia_test
LOCAL_C_INCLUDES := \
- external/skia/include/core \
- external/skia/include/effects \
- external/skia/include/images \
- external/skia/include/ports \
- external/skia/include/utils \
- external/skia/src/core
+ external/freetype/include \
+ external/skia/include/core \
+ external/skia/include/config \
+ external/skia/include/effects \
+ external/skia/include/gpu \
+ external/skia/include/images \
+ external/skia/include/pdf \
+ external/skia/include/ports \
+ external/skia/include/utils \
+ external/skia/src/core \
+ external/skia/src/gpu
-LOCAL_SHARED_LIBRARIES := \
- libskia libcutils
+LOCAL_SHARED_LIBRARIES := libcutils libskia libGLESv2 libEGL
+LOCAL_STATIC_LIBRARIES := libskiagpu
LOCAL_MODULE_TAGS := eng tests
diff --git a/tests/BitSetTest.cpp b/tests/BitSetTest.cpp
new file mode 100644
index 0000000..7139495
--- /dev/null
+++ b/tests/BitSetTest.cpp
@@ -0,0 +1,79 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "Test.h"
+#include "SkBitSet.h"
+
+static void TestBitSet(skiatest::Reporter* reporter) {
+ SkBitSet set0(65536);
+ REPORTER_ASSERT(reporter, set0.isBitSet(0) == false);
+ REPORTER_ASSERT(reporter, set0.isBitSet(32767) == false);
+ REPORTER_ASSERT(reporter, set0.isBitSet(65535) == false);
+
+ SkBitSet set1(65536);
+ REPORTER_ASSERT(reporter, set0 == set1);
+
+ set0.setBit(22, true);
+ REPORTER_ASSERT(reporter, set0.isBitSet(22) == true);
+ set0.setBit(24, true);
+ REPORTER_ASSERT(reporter, set0.isBitSet(24) == true);
+ set0.setBit(35, true); // on a different DWORD
+ REPORTER_ASSERT(reporter, set0.isBitSet(35) == true);
+ set0.setBit(22, false);
+ REPORTER_ASSERT(reporter, set0.isBitSet(22) == false);
+ REPORTER_ASSERT(reporter, set0.isBitSet(24) == true);
+ REPORTER_ASSERT(reporter, set0.isBitSet(35) == true);
+
+ SkTDArray<unsigned int> data;
+ set0.exportTo(&data);
+ REPORTER_ASSERT(reporter, data.count() == 2);
+ REPORTER_ASSERT(reporter, data[0] == 24);
+ REPORTER_ASSERT(reporter, data[1] == 35);
+
+ set1.setBit(12345, true);
+ set1.orBits(set0);
+ REPORTER_ASSERT(reporter, set0.isBitSet(12345) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(12345) == true);
+ REPORTER_ASSERT(reporter, set1.isBitSet(22) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(24) == true);
+ REPORTER_ASSERT(reporter, set0.isBitSet(35) == true);
+ REPORTER_ASSERT(reporter, set1 != set0);
+
+ set1.clearAll();
+ REPORTER_ASSERT(reporter, set0.isBitSet(12345) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(12345) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(22) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(24) == false);
+ REPORTER_ASSERT(reporter, set1.isBitSet(35) == false);
+
+ set1.orBits(set0);
+ REPORTER_ASSERT(reporter, set1 == set0);
+
+ SkBitSet set2(1);
+ SkBitSet set3(1);
+ SkBitSet set4(4);
+ SkBitSet set5(33);
+
+ REPORTER_ASSERT(reporter, set2 == set3);
+ REPORTER_ASSERT(reporter, set2 != set4);
+ REPORTER_ASSERT(reporter, set2 != set5);
+
+ set2.setBit(0, true);
+ REPORTER_ASSERT(reporter, set2 != set5);
+ set5.setBit(0, true);
+ REPORTER_ASSERT(reporter, set2 != set5);
+ REPORTER_ASSERT(reporter, set2 != set3);
+ set3.setBit(0, true);
+ REPORTER_ASSERT(reporter, set2 == set3);
+ set3.clearAll();
+ set3 = set2;
+ set2 = set2;
+ REPORTER_ASSERT(reporter, set2 == set3);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("BitSet", BitSetTest, TestBitSet)
diff --git a/tests/BitmapCopyTest.cpp b/tests/BitmapCopyTest.cpp
index 6ddb548..b8d16bf 100644
--- a/tests/BitmapCopyTest.cpp
+++ b/tests/BitmapCopyTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkBitmap.h"
#include "SkRect.h"
@@ -543,6 +550,7 @@ static void TestBitmapCopy(skiatest::Reporter* reporter) {
reportCopyVerification(subset, bufBm, coords,
"copyPixelsTo(buf, bufSize, rowBytes()-1)", reporter);
+#if 0 // copyPixelsFrom is gone
// Test #5 ////////////////////////////////////////////
// Tests the case where the source stride is too small
// for the source configuration.
@@ -577,6 +585,7 @@ static void TestBitmapCopy(skiatest::Reporter* reporter) {
false);
delete [] buf;
+#endif
}
}
} // for (size_t copyCase ...
diff --git a/tests/BitmapGetColorTest.cpp b/tests/BitmapGetColorTest.cpp
index 81cf412..4204ddf 100644
--- a/tests/BitmapGetColorTest.cpp
+++ b/tests/BitmapGetColorTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkBitmap.h"
diff --git a/tests/BlitRowTest.cpp b/tests/BlitRowTest.cpp
index d18cb8a..b37b47e 100644
--- a/tests/BlitRowTest.cpp
+++ b/tests/BlitRowTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
diff --git a/tests/BlurTest.cpp b/tests/BlurTest.cpp
new file mode 100644
index 0000000..c0d16f8
--- /dev/null
+++ b/tests/BlurTest.cpp
@@ -0,0 +1,162 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "Test.h"
+#include "SkBlurMaskFilter.h"
+#include "SkCanvas.h"
+#include "SkMath.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+#define ILLEGAL_MODE ((SkXfermode::Mode)-1)
+
+static const int outset = 100;
+static const SkColor bgColor = SK_ColorWHITE;
+static const int strokeWidth = 4;
+
+static void create(SkBitmap* bm, SkIRect bound, SkBitmap::Config config) {
+ bm->setConfig(config, bound.width(), bound.height());
+ bm->allocPixels();
+}
+
+static void drawBG(SkCanvas* canvas) {
+ canvas->drawColor(bgColor);
+}
+
+
+struct BlurTest {
+ void (*addPath)(SkPath*);
+ int viewLen;
+ SkIRect views[9];
+};
+
+//Path Draw Procs
+//Beware that paths themselves my draw differently depending on the clip.
+static void draw50x50Rect(SkPath* path) {
+ path->addRect(0, 0, SkIntToScalar(50), SkIntToScalar(50));
+}
+
+//Tests
+static BlurTest tests[] = {
+ { draw50x50Rect, 3, {
+ //inner half of blur
+ { 0, 0, 50, 50 },
+ //blur, but no path.
+ { 50 + strokeWidth/2, 50 + strokeWidth/2, 100, 100 },
+ //just an edge
+ { 40, strokeWidth, 60, 50 - strokeWidth },
+ }},
+};
+
+/** Assumes that the ref draw was completely inside ref canvas --
+ implies that everything outside is "bgColor".
+ Checks that all overlap is the same and that all non-overlap on the
+ ref is "bgColor".
+ */
+static bool compare(const SkBitmap& ref, const SkIRect& iref,
+ const SkBitmap& test, const SkIRect& itest)
+{
+ const int xOff = itest.fLeft - iref.fLeft;
+ const int yOff = itest.fTop - iref.fTop;
+
+ SkAutoLockPixels alpRef(ref);
+ SkAutoLockPixels alpTest(test);
+
+ for (int y = 0; y < test.height(); ++y) {
+ for (int x = 0; x < test.width(); ++x) {
+ SkColor testColor = test.getColor(x, y);
+ int refX = x + xOff;
+ int refY = y + yOff;
+ SkColor refColor;
+ if (refX >= 0 && refX < ref.width() &&
+ refY >= 0 && refY < ref.height())
+ {
+ refColor = ref.getColor(refX, refY);
+ } else {
+ refColor = bgColor;
+ }
+ if (refColor != testColor) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static void test_blur(skiatest::Reporter* reporter) {
+
+ SkPaint paint;
+ paint.setColor(SK_ColorGRAY);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkIntToScalar(strokeWidth));
+
+ SkScalar radius = SkIntToScalar(5);
+ for (int style = 0; style < SkBlurMaskFilter::kBlurStyleCount; ++style) {
+ SkBlurMaskFilter::BlurStyle blurStyle =
+ static_cast<SkBlurMaskFilter::BlurStyle>(style);
+
+ const uint32_t flagPermutations = SkBlurMaskFilter::kAll_BlurFlag;
+ for (uint32_t flags = 0; flags < flagPermutations; ++flags) {
+ SkMaskFilter* filter;
+ filter = SkBlurMaskFilter::Create(radius, blurStyle, flags);
+
+ SkMaskFilter::BlurInfo info;
+ sk_bzero(&info, sizeof(info));
+ SkMaskFilter::BlurType type = filter->asABlur(&info);
+
+ REPORTER_ASSERT(reporter, type ==
+ static_cast<SkMaskFilter::BlurType>(style + 1));
+ REPORTER_ASSERT(reporter, info.fRadius == radius);
+ REPORTER_ASSERT(reporter, info.fIgnoreTransform ==
+ SkToBool(flags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag));
+ REPORTER_ASSERT(reporter, info.fHighQuality ==
+ SkToBool(flags & SkBlurMaskFilter::kHighQuality_BlurFlag));
+
+ paint.setMaskFilter(filter);
+ filter->unref();
+
+ for (size_t test = 0; test < SK_ARRAY_COUNT(tests); ++test) {
+ SkPath path;
+ tests[test].addPath(&path);
+ SkPath strokedPath;
+ paint.getFillPath(path, &strokedPath);
+ SkRect refBound = strokedPath.getBounds();
+ SkIRect iref;
+ refBound.roundOut(&iref);
+ iref.inset(-outset, -outset);
+ SkBitmap refBitmap;
+ create(&refBitmap, iref, SkBitmap::kARGB_8888_Config);
+
+ SkCanvas refCanvas(refBitmap);
+ refCanvas.translate(SkIntToScalar(-iref.fLeft),
+ SkIntToScalar(-iref.fTop));
+ drawBG(&refCanvas);
+ refCanvas.drawPath(path, paint);
+
+ for (int view = 0; view < tests[test].viewLen; ++view) {
+ SkIRect itest = tests[test].views[view];
+ SkBitmap testBitmap;
+ create(&testBitmap, itest, SkBitmap::kARGB_8888_Config);
+
+ SkCanvas testCanvas(testBitmap);
+ testCanvas.translate(SkIntToScalar(-itest.fLeft),
+ SkIntToScalar(-itest.fTop));
+ drawBG(&testCanvas);
+ testCanvas.drawPath(path, paint);
+
+ REPORTER_ASSERT(reporter,
+ compare(refBitmap, iref, testBitmap, itest));
+ }
+ }
+ }
+ }
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("BlurMaskFilter", BlurTestClass, test_blur)
diff --git a/tests/CanvasTest.cpp b/tests/CanvasTest.cpp
new file mode 100644
index 0000000..da1fafd
--- /dev/null
+++ b/tests/CanvasTest.cpp
@@ -0,0 +1,67 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "Test.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+
+static void test_isDrawingToLayer(skiatest::Reporter* reporter) {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, 256, 256);
+ bm.allocPixels();
+
+ SkCanvas canvas(bm);
+
+ REPORTER_ASSERT(reporter, !canvas.isDrawingToLayer());
+ canvas.save();
+ REPORTER_ASSERT(reporter, !canvas.isDrawingToLayer());
+
+ const SkRect* bounds = NULL; // null means include entire bounds
+ const SkPaint* paint = NULL;
+
+ canvas.saveLayer(bounds, paint);
+ REPORTER_ASSERT(reporter, canvas.isDrawingToLayer());
+ canvas.restore();
+ REPORTER_ASSERT(reporter, !canvas.isDrawingToLayer());
+
+ canvas.saveLayer(bounds, paint);
+ canvas.saveLayer(bounds, paint);
+ REPORTER_ASSERT(reporter, canvas.isDrawingToLayer());
+ canvas.restore();
+ REPORTER_ASSERT(reporter, canvas.isDrawingToLayer());
+ canvas.restore();
+ // now layer count should be 0
+ REPORTER_ASSERT(reporter, !canvas.isDrawingToLayer());
+}
+
+static void TestCanvas(skiatest::Reporter* reporter) {
+ SkBitmap bm;
+ bm.setConfig(SkBitmap::kARGB_8888_Config, 256, 256);
+ bm.allocPixels();
+
+ SkCanvas canvas(bm);
+ int n;
+
+ REPORTER_ASSERT(reporter, 1 == canvas.getSaveCount());
+ n = canvas.save();
+ REPORTER_ASSERT(reporter, 1 == n);
+ REPORTER_ASSERT(reporter, 2 == canvas.getSaveCount());
+ canvas.save();
+ canvas.save();
+ REPORTER_ASSERT(reporter, 4 == canvas.getSaveCount());
+ canvas.restoreToCount(2);
+ REPORTER_ASSERT(reporter, 2 == canvas.getSaveCount());
+
+ // should this pin to 1, or be a no-op, or crash?
+ canvas.restoreToCount(0);
+ REPORTER_ASSERT(reporter, 1 == canvas.getSaveCount());
+
+ test_isDrawingToLayer(reporter);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("Canvas", TestCanvasClass, TestCanvas)
diff --git a/tests/ClampRangeTest.cpp b/tests/ClampRangeTest.cpp
index be9c6ec..226d030 100644
--- a/tests/ClampRangeTest.cpp
+++ b/tests/ClampRangeTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkClampRange.h"
#include "SkRandom.h"
diff --git a/tests/ClipCubicTest.cpp b/tests/ClipCubicTest.cpp
index e38a22f..931b61e 100644
--- a/tests/ClipCubicTest.cpp
+++ b/tests/ClipCubicTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkCubicClipper.h"
diff --git a/tests/ClipStackTest.cpp b/tests/ClipStackTest.cpp
index eafdd69..40738df 100644
--- a/tests/ClipStackTest.cpp
+++ b/tests/ClipStackTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkClipStack.h"
#include "SkPath.h"
@@ -5,6 +12,7 @@
static void test_assign_and_comparison(skiatest::Reporter* reporter) {
SkClipStack s;
+ bool doAA = false;
// Build up a clip stack with a path, an empty clip, and a rect.
s.save();
@@ -13,17 +21,17 @@ static void test_assign_and_comparison(skiatest::Reporter* reporter) {
p.lineTo(7, 8);
p.lineTo(5, 9);
p.close();
- s.clipDevPath(p);
+ s.clipDevPath(p, SkRegion::kIntersect_Op, doAA);
s.save();
SkRect r = SkRect::MakeLTRB(1, 2, 3, 4);
- s.clipDevRect(r);
+ s.clipDevRect(r, SkRegion::kIntersect_Op, doAA);
r = SkRect::MakeLTRB(10, 11, 12, 13);
- s.clipDevRect(r);
+ s.clipDevRect(r, SkRegion::kIntersect_Op, doAA);
s.save();
r = SkRect::MakeLTRB(14, 15, 16, 17);
- s.clipDevRect(r, SkRegion::kUnion_Op);
+ s.clipDevRect(r, SkRegion::kUnion_Op, doAA);
// Test that assignment works.
SkClipStack copy = s;
@@ -36,14 +44,14 @@ static void test_assign_and_comparison(skiatest::Reporter* reporter) {
// Test that an equal, but not copied version is equal.
s.save();
r = SkRect::MakeLTRB(14, 15, 16, 17);
- s.clipDevRect(r, SkRegion::kUnion_Op);
+ s.clipDevRect(r, SkRegion::kUnion_Op, doAA);
REPORTER_ASSERT(reporter, s == copy);
// Test that a different op on one level triggers not equal.
s.restore();
s.save();
r = SkRect::MakeLTRB(14, 15, 16, 17);
- s.clipDevRect(r);
+ s.clipDevRect(r, SkRegion::kIntersect_Op, doAA);
REPORTER_ASSERT(reporter, s != copy);
// Test that different state (clip type) triggers not equal.
@@ -51,14 +59,14 @@ static void test_assign_and_comparison(skiatest::Reporter* reporter) {
s.save();
SkPath rp;
rp.addRect(r);
- s.clipDevPath(rp, SkRegion::kUnion_Op);
+ s.clipDevPath(rp, SkRegion::kUnion_Op, doAA);
REPORTER_ASSERT(reporter, s != copy);
// Test that different rects triggers not equal.
s.restore();
s.save();
r = SkRect::MakeLTRB(24, 25, 26, 27);
- s.clipDevRect(r, SkRegion::kUnion_Op);
+ s.clipDevRect(r, SkRegion::kUnion_Op, doAA);
REPORTER_ASSERT(reporter, s != copy);
// Sanity check
@@ -73,7 +81,7 @@ static void test_assign_and_comparison(skiatest::Reporter* reporter) {
s.restore();
s.save();
p.addRect(r);
- s.clipDevPath(p);
+ s.clipDevPath(p, SkRegion::kIntersect_Op, doAA);
REPORTER_ASSERT(reporter, s != copy);
}
@@ -101,7 +109,7 @@ static void TestClipStack(skiatest::Reporter* reporter) {
{ 0, 0, 75, 75 }
};
for (size_t i = 0; i < SK_ARRAY_COUNT(gRects); i++) {
- stack.clipDevRect(gRects[i]);
+ stack.clipDevRect(gRects[i], SkRegion::kIntersect_Op);
}
// all of the above rects should have been intersected, leaving only 1 rect
diff --git a/tests/ClipperTest.cpp b/tests/ClipperTest.cpp
index 66301fc..7bb2254 100644
--- a/tests/ClipperTest.cpp
+++ b/tests/ClipperTest.cpp
@@ -1,8 +1,33 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkPath.h"
#include "SkLineClipper.h"
#include "SkEdgeClipper.h"
+static void test_edgeclipper(skiatest::Reporter* reporter) {
+ SkEdgeClipper clipper;
+
+ const SkPoint pts[] = {
+ { SkFloatToScalar(3.0995476e+010), SkFloatToScalar(42.929779) },
+ { SkFloatToScalar(-3.0995163e+010), SkFloatToScalar(51.050385) },
+ { SkFloatToScalar(-3.0995157e+010), SkFloatToScalar(51.050392) },
+ { SkFloatToScalar(-3.0995134e+010), SkFloatToScalar(51.050400) },
+ };
+
+ const SkRect clip = { 0, 0, SkIntToScalar(300), SkIntToScalar(200) };
+
+ // this should not assert, even though our choppers do a poor numerical
+ // job when computing their t values.
+ // http://code.google.com/p/skia/issues/detail?id=444
+ clipper.clipCubic(pts, clip);
+}
+
static void test_intersectline(skiatest::Reporter* reporter) {
static const SkScalar L = 0;
static const SkScalar T = 0;
@@ -83,6 +108,7 @@ static void test_intersectline(skiatest::Reporter* reporter) {
void TestClipper(skiatest::Reporter* reporter) {
test_intersectline(reporter);
+ test_edgeclipper(reporter);
}
#include "TestClassDef.h"
diff --git a/tests/ColorFilterTest.cpp b/tests/ColorFilterTest.cpp
index 77575eb..f98deb0 100644
--- a/tests/ColorFilterTest.cpp
+++ b/tests/ColorFilterTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkColor.h"
#include "SkColorFilter.h"
diff --git a/tests/ColorTest.cpp b/tests/ColorTest.cpp
index ef4b0b6..0efb892 100644
--- a/tests/ColorTest.cpp
+++ b/tests/ColorTest.cpp
@@ -1,5 +1,13 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkColor.h"
+#include "SkMath.h"
#include "SkUnPreMultiply.h"
static void test_premul(skiatest::Reporter* reporter) {
diff --git a/tests/DataRefTest.cpp b/tests/DataRefTest.cpp
new file mode 100644
index 0000000..6a42485
--- /dev/null
+++ b/tests/DataRefTest.cpp
@@ -0,0 +1,61 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "Test.h"
+#include "SkData.h"
+
+static void* gGlobal;
+
+static void delete_int_proc(const void* ptr, size_t len, void* context) {
+ int* data = (int*)ptr;
+ SkASSERT(context == gGlobal);
+ delete[] data;
+}
+
+static void assert_len(skiatest::Reporter* reporter, SkData* ref, size_t len) {
+ REPORTER_ASSERT(reporter, ref->size() == len);
+}
+
+static void assert_data(skiatest::Reporter* reporter, SkData* ref,
+ const void* data, size_t len) {
+ REPORTER_ASSERT(reporter, ref->size() == len);
+ REPORTER_ASSERT(reporter, !memcmp(ref->data(), data, len));
+}
+
+void TestDataRef(skiatest::Reporter* reporter) {
+ const char* str = "We the people, in order to form a more perfect union.";
+ const int N = 10;
+
+ SkData* r0 = SkData::NewEmpty();
+ SkData* r1 = SkData::NewWithCopy(str, strlen(str));
+ SkData* r2 = SkData::NewWithProc(new int[N], N*sizeof(int),
+ delete_int_proc, gGlobal);
+ SkData* r3 = SkData::NewSubset(r1, 7, 6);
+
+ SkAutoUnref aur0(r0);
+ SkAutoUnref aur1(r1);
+ SkAutoUnref aur2(r2);
+ SkAutoUnref aur3(r3);
+
+ assert_len(reporter, r0, 0);
+ assert_len(reporter, r1, strlen(str));
+ assert_len(reporter, r2, N * sizeof(int));
+ assert_len(reporter, r3, 6);
+
+ assert_data(reporter, r1, str, strlen(str));
+ assert_data(reporter, r3, "people", 6);
+
+ SkData* tmp = SkData::NewSubset(r1, strlen(str), 10);
+ assert_len(reporter, tmp, 0);
+ tmp->unref();
+ tmp = SkData::NewSubset(r1, 0, 0);
+ assert_len(reporter, tmp, 0);
+ tmp->unref();
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("DataRef", DataRefTestClass, TestDataRef)
diff --git a/tests/DequeTest.cpp b/tests/DequeTest.cpp
index e74fd28..4e1c1b7 100644
--- a/tests/DequeTest.cpp
+++ b/tests/DequeTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkDeque.h"
diff --git a/tests/DrawBitmapRectTest.cpp b/tests/DrawBitmapRectTest.cpp
index fc382ce..843feb5 100644
--- a/tests/DrawBitmapRectTest.cpp
+++ b/tests/DrawBitmapRectTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
diff --git a/tests/EmptyPathTest.cpp b/tests/EmptyPathTest.cpp
new file mode 100644
index 0000000..b126076
--- /dev/null
+++ b/tests/EmptyPathTest.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#include "SkPath.h"
+#include "SkCanvas.h"
+
+static void appendStr(SkString* str, const SkPaint& paint) {
+ str->appendf(" style[%d] cap[%d] join[%d] antialias[%d]",
+ paint.getStyle(), paint.getStrokeCap(),
+ paint.getStrokeJoin(), paint.isAntiAlias());
+}
+
+static void appendStr(SkString* str, const SkPath& path) {
+ str->appendf(" filltype[%d] ptcount[%d]",
+ path.getFillType(), path.countPoints());
+}
+
+#define DIMENSION 32
+
+static void drawAndTest(skiatest::Reporter* reporter, const SkPath& path,
+ const SkPaint& paint, bool shouldDraw) {
+ SkBitmap bm;
+ // explicitly specify a trim rowbytes, so we have no padding on each row
+ bm.setConfig(SkBitmap::kARGB_8888_Config, DIMENSION, DIMENSION, DIMENSION*4);
+ bm.allocPixels();
+ bm.eraseColor(0);
+
+ SkCanvas canvas(bm);
+ SkPaint p(paint);
+ p.setColor(SK_ColorWHITE);
+
+ canvas.drawPath(path, p);
+
+ size_t count = DIMENSION * DIMENSION;
+ const SkPMColor* ptr = bm.getAddr32(0, 0);
+
+ SkPMColor andValue = ~0;
+ SkPMColor orValue = 0;
+ for (size_t i = 0; i < count; ++i) {
+ SkPMColor c = ptr[i];
+ andValue &= c;
+ orValue |= c;
+ }
+
+ // success means we drew everywhere or nowhere (depending on shouldDraw)
+ bool success = shouldDraw ? (~0U == andValue) : (0 == orValue);
+
+ if (!success) {
+ SkString str;
+ if (shouldDraw) {
+ str.set("Path expected to draw everywhere, but didn't. ");
+ } else {
+ str.set("Path expected to draw nowhere, but did. ");
+ }
+ appendStr(&str, paint);
+ appendStr(&str, path);
+ reporter->report(str.c_str(), skiatest::Reporter::kFailed);
+
+// uncomment this if you want to step in to see the failure
+// canvas.drawPath(path, p);
+ }
+}
+
+static void iter_paint(skiatest::Reporter* reporter, const SkPath& path, bool shouldDraw) {
+ static const SkPaint::Cap gCaps[] = {
+ SkPaint::kButt_Cap,
+ SkPaint::kRound_Cap,
+ SkPaint::kSquare_Cap
+ };
+ static const SkPaint::Join gJoins[] = {
+ SkPaint::kMiter_Join,
+ SkPaint::kRound_Join,
+ SkPaint::kBevel_Join
+ };
+ static const SkPaint::Style gStyles[] = {
+ SkPaint::kFill_Style,
+ SkPaint::kStroke_Style,
+ SkPaint::kStrokeAndFill_Style
+ };
+ for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
+ for (size_t join = 0; join < SK_ARRAY_COUNT(gJoins); ++join) {
+ for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
+ SkPaint paint;
+ paint.setStrokeWidth(SkIntToScalar(10));
+
+ paint.setStrokeCap(gCaps[cap]);
+ paint.setStrokeJoin(gJoins[join]);
+ paint.setStyle(gStyles[style]);
+
+ paint.setAntiAlias(false);
+ drawAndTest(reporter, path, paint, shouldDraw);
+ paint.setAntiAlias(true);
+ drawAndTest(reporter, path, paint, shouldDraw);
+ }
+ }
+ }
+}
+
+#define CX (SkIntToScalar(DIMENSION) / 2)
+#define CY (SkIntToScalar(DIMENSION) / 2)
+
+static void make_empty(SkPath* path) {}
+static void make_M(SkPath* path) { path->moveTo(CX, CY); }
+static void make_MM(SkPath* path) { path->moveTo(CX, CY); path->moveTo(CX, CY); }
+static void make_MZM(SkPath* path) { path->moveTo(CX, CY); path->close(); path->moveTo(CX, CY); }
+static void make_L(SkPath* path) { path->moveTo(CX, CY); path->lineTo(CX, CY); }
+static void make_Q(SkPath* path) { path->moveTo(CX, CY); path->quadTo(CX, CY, CX, CY); }
+static void make_C(SkPath* path) { path->moveTo(CX, CY); path->cubicTo(CX, CY, CX, CY, CX, CY); }
+
+/* Two invariants are tested: How does an empty/degenerate path draw?
+ * - if the path is drawn inverse, it should draw everywhere
+ * - if the path is drawn non-inverse, it should draw nowhere
+ *
+ * Things to iterate on:
+ * - path (empty, degenerate line/quad/cubic w/ and w/o close
+ * - paint style
+ * - path filltype
+ * - path stroke variants (e.g. caps, joins, width)
+ */
+static void test_emptydrawing(skiatest::Reporter* reporter) {
+ static void (*gMakeProc[])(SkPath*) = {
+ make_empty, make_M, make_MM, make_MZM, make_L, make_Q, make_C
+ };
+ static SkPath::FillType gFills[] = {
+ SkPath::kWinding_FillType,
+ SkPath::kEvenOdd_FillType,
+ SkPath::kInverseWinding_FillType,
+ SkPath::kInverseEvenOdd_FillType
+ };
+ for (int doClose = 0; doClose < 2; ++doClose) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gMakeProc); ++i) {
+ SkPath path;
+ gMakeProc[i](&path);
+ if (doClose) {
+ path.close();
+ }
+ for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
+ path.setFillType(gFills[fill]);
+ bool shouldDraw = path.isInverseFillType();
+ iter_paint(reporter, path, shouldDraw);
+ }
+ }
+ }
+}
+
+static void TestEmptyPath(skiatest::Reporter* reporter) {
+ test_emptydrawing(reporter);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("EmptyPath", TestEmptyPathClass, TestEmptyPath)
diff --git a/tests/FillPathTest.cpp b/tests/FillPathTest.cpp
index ffc9f8e..8271851 100644
--- a/tests/FillPathTest.cpp
+++ b/tests/FillPathTest.cpp
@@ -1,17 +1,8 @@
/*
- * Copyright (C) 2010 The Chromium Authors. All rights reserved.
+ * Copyright 2010 Google Inc.
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
#include "Test.h"
@@ -41,12 +32,12 @@ struct FakeBlitter : public SkBlitter {
// but skipped after tessellation, should be cleared by the blitter.
static void TestFillPathInverse(skiatest::Reporter* reporter) {
FakeBlitter blitter;
- SkRegion clip;
+ SkIRect clip;
SkPath path;
int height = 100;
int width = 200;
int expected_lines = 5;
- clip.setRect(0, height - expected_lines, width, height);
+ clip.set(0, height - expected_lines, width, height);
path.moveTo(0.0, 0.0);
path.quadTo(width/2, height, width, 0.0);
path.close();
diff --git a/tests/FlateTest.cpp b/tests/FlateTest.cpp
index fe2bb4a..8697df9 100644
--- a/tests/FlateTest.cpp
+++ b/tests/FlateTest.cpp
@@ -1,23 +1,17 @@
+
/*
- * Copyright (C) 2011 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2011 Google Inc.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include <stdlib.h>
#include <string.h>
#include "Test.h"
+#include "SkData.h"
#include "SkFlate.h"
#include "SkStream.h"
@@ -67,7 +61,9 @@ static void TestFlate(skiatest::Reporter* reporter, SkMemoryStream* testStream,
else
REPORTER_ASSERT(reporter, compressed.getOffset() > 1024);
- testStream->setMemory(compressed.getStream(), compressed.getOffset(), true);
+ SkAutoDataUnref data1(compressed.copyToData());
+
+ testStream->setData(data1.get())->unref();
SkDynamicMemoryWStream uncompressed;
status = SkFlate::Inflate(testStream, &uncompressed);
REPORTER_ASSERT(reporter, status);
@@ -76,15 +72,14 @@ static void TestFlate(skiatest::Reporter* reporter, SkMemoryStream* testStream,
inputSize = testStream->getLength();
if (inputSize == 0)
inputSize = testStream->read(NULL, SkZeroSizeMemStream::kGetSizeKey);
- REPORTER_ASSERT(reporter, compressed.getOffset() == inputSize);
+ REPORTER_ASSERT(reporter, data1.size() == inputSize);
REPORTER_ASSERT(reporter, memcmp(testStream->getMemoryBase(),
- compressed.getStream(),
- compressed.getOffset()) == 0);
+ data1.data(), data1.size()) == 0);
// Check that the uncompressed data matches the source data.
+ SkAutoDataUnref data2(uncompressed.copyToData());
REPORTER_ASSERT(reporter, testData.getLength() == uncompressed.getOffset());
- REPORTER_ASSERT(reporter, memcmp(testData.getMemoryBase(),
- uncompressed.getStream(),
+ REPORTER_ASSERT(reporter, memcmp(testData.getMemoryBase(), data2.data(),
testData.getLength()) == 0);
}
diff --git a/tests/GLInterfaceValidation.cpp b/tests/GLInterfaceValidation.cpp
new file mode 100755
index 0000000..2be13f0
--- /dev/null
+++ b/tests/GLInterfaceValidation.cpp
@@ -0,0 +1,64 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#include "SkNativeGLContext.h"
+#include "SkMesaGLContext.h"
+
+static void GLInterfaceValidationTest(skiatest::Reporter* reporter) {
+ typedef const GrGLInterface* (*interfaceFactory)();
+ struct {
+ interfaceFactory fFactory;
+ const char* fName;
+ } interfaceFactories[] = {
+ {GrGLCreateNativeInterface, "Native"},
+#if SK_MESA
+ {GrGLCreateMesaInterface, "Mesa"},
+#endif
+ {GrGLCreateNullInterface, "Null"},
+ };
+
+ // On some platforms GrGLCreateNativeInterface will fail unless an OpenGL
+ // context has been created. Also, preserve the current context that may
+ // be in use by outer test harness.
+ SkNativeGLContext::AutoContextRestore nglacr;
+ SkNativeGLContext nglctx;
+ static const int gBOGUS_SIZE = 16;
+ bool nativeContextInit = nglctx.init(gBOGUS_SIZE, gBOGUS_SIZE);
+ REPORTER_ASSERT(reporter, nativeContextInit);
+ if (!nativeContextInit) {
+ return;
+ }
+#if SK_MESA
+ // We must have a current OSMesa context to initialize an OSMesa
+ // GrGLInterface
+ SkMesaGLContext::AutoContextRestore mglacr;
+ SkMesaGLContext mglctx;
+ bool mesaContextInit = mglctx.init(gBOGUS_SIZE, gBOGUS_SIZE);
+ REPORTER_ASSERT(reporter, mesaContextInit);
+ if(!mesaContextInit) {
+ return;
+ }
+#endif
+
+ SkAutoTUnref<const GrGLInterface> iface;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(interfaceFactories); ++i) {
+ iface.reset(interfaceFactories[i].fFactory());
+ REPORTER_ASSERT(reporter, NULL != iface.get());
+ if (iface.get()) {
+ REPORTER_ASSERT(reporter, iface.get()->validate());
+ }
+ }
+}
+
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("GLInterfaceValidation",
+ GLInterfaceValidationTestClass,
+ GLInterfaceValidationTest)
+
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
new file mode 100644
index 0000000..5cacade
--- /dev/null
+++ b/tests/GLProgramsTest.cpp
@@ -0,0 +1,21 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#include "GrContext.h"
+#include "GrGpuGLShaders.h"
+
+static void GLProgramsTest(skiatest::Reporter* reporter, GrContext* context) {
+ GrGpuGLShaders* shadersGpu = (GrGpuGLShaders*) context->getGpu();
+ REPORTER_ASSERT(reporter, shadersGpu->programUnitTest());
+}
+
+
+#include "TestClassDef.h"
+DEFINE_GPUTESTCLASS("GLPrograms", GLProgramsTestClass, GLProgramsTest)
+
diff --git a/tests/GeometryTest.cpp b/tests/GeometryTest.cpp
index 5b05952..6158a20 100644
--- a/tests/GeometryTest.cpp
+++ b/tests/GeometryTest.cpp
@@ -1,6 +1,17 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkGeometry.h"
+static bool nearly_equal(const SkPoint& a, const SkPoint& b) {
+ return SkScalarNearlyEqual(a.fX, b.fX) && SkScalarNearlyEqual(a.fY, b.fY);
+}
+
static void TestGeometry(skiatest::Reporter* reporter) {
SkPoint pts[3], dst[5];
@@ -10,6 +21,20 @@ static void TestGeometry(skiatest::Reporter* reporter) {
int count = SkChopQuadAtMaxCurvature(pts, dst);
REPORTER_ASSERT(reporter, count == 1 || count == 2);
+
+ pts[0].set(0, 0);
+ pts[1].set(SkIntToScalar(3), 0);
+ pts[2].set(SkIntToScalar(3), SkIntToScalar(3));
+ SkConvertQuadToCubic(pts, dst);
+ const SkPoint cubic[] = {
+ { 0, 0, },
+ { SkIntToScalar(2), 0, },
+ { SkIntToScalar(3), SkIntToScalar(1), },
+ { SkIntToScalar(3), SkIntToScalar(3) },
+ };
+ for (int i = 0; i < 4; ++i) {
+ REPORTER_ASSERT(reporter, nearly_equal(cubic[i], dst[i]));
+ }
}
#include "TestClassDef.h"
diff --git a/tests/InfRectTest.cpp b/tests/InfRectTest.cpp
index 1e15023..12356d9 100644
--- a/tests/InfRectTest.cpp
+++ b/tests/InfRectTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkRect.h"
@@ -11,10 +18,10 @@ static void check_invalid(skiatest::Reporter* reporter,
SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
SkRect rect;
rect.set(l, t, r, b);
- REPORTER_ASSERT(reporter, !rect.hasValidCoordinates());
+ REPORTER_ASSERT(reporter, !rect.isFinite());
}
-// Tests that hasValidCoordinates() will reject any rect with +/-inf values
+// Tests that isFinite() will reject any rect with +/-inf values
// as one of its coordinates.
static void TestInfRect(skiatest::Reporter* reporter) {
#ifdef SK_SCALAR_IS_FLOAT
@@ -26,7 +33,7 @@ static void TestInfRect(skiatest::Reporter* reporter) {
SkScalar big = SkIntToScalar(100);
SkRect rect = SkRect::MakeXYWH(small, small, big, big);
- REPORTER_ASSERT(reporter, rect.hasValidCoordinates());
+ REPORTER_ASSERT(reporter, rect.isFinite());
check_invalid(reporter, small, small, big, invalid);
check_invalid(reporter, small, small, invalid, big);
diff --git a/tests/MathTest.cpp b/tests/MathTest.cpp
index efdad3a..fef93cd 100644
--- a/tests/MathTest.cpp
+++ b/tests/MathTest.cpp
@@ -1,41 +1,97 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkFloatingPoint.h"
+#include "SkMath.h"
#include "SkPoint.h"
#include "SkRandom.h"
+#include "SkColorPriv.h"
-#if 0
-static U8CPU premul_fast(U8CPU a, U8CPU x) {
- return a * x * 32897 >> 23;
+static float float_blend(int src, int dst, float unit) {
+ return dst + (src - dst) * unit;
}
-static U8CPU premul_trunc(U8CPU a, U8CPU x) {
- double result = a * x;
- result /= 255.0;
- return (unsigned)floor(result + 0.0);
+static int blend31(int src, int dst, int a31) {
+ return dst + ((src - dst) * a31 * 2114 >> 16);
+ // return dst + ((src - dst) * a31 * 33 >> 10);
}
-static U8CPU premul_round(U8CPU a, U8CPU x) {
- double result = a * x;
- result /= 255.0;
- return (unsigned)floor(result + 0.5);
+static int blend31_slow(int src, int dst, int a31) {
+ int prod = src * a31 + (31 - a31) * dst + 16;
+ prod = (prod + (prod >> 5)) >> 5;
+ return prod;
}
-static void test_premul(skiatest::Reporter* reporter) {
- for (int a = 0; a <= 255; a++) {
- for (int x = 0; x <= 255; x++) {
- unsigned curr_trunc = SkMulDiv255Trunc(a, x);
- unsigned curr_round = SkMulDiv255Round(a, x);
- unsigned fast = premul_fast(a, x);
- unsigned slow_round = premul_round(a, x);
- unsigned slow_trunc = premul_trunc(a, x);
- if (fast != slow || curr != fast) {
- SkDebugf("---- premul(%d %d) curr=%d fast=%d slow=%d\n", a, x,
- curr, fast, slow);
+static int blend31_round(int src, int dst, int a31) {
+ int prod = (src - dst) * a31 + 16;
+ prod = (prod + (prod >> 5)) >> 5;
+ return dst + prod;
+}
+
+static int blend31_old(int src, int dst, int a31) {
+ a31 += a31 >> 4;
+ return dst + ((src - dst) * a31 >> 5);
+}
+
+static void test_blend31() {
+ int failed = 0;
+ int death = 0;
+ for (int src = 0; src <= 255; src++) {
+ for (int dst = 0; dst <= 255; dst++) {
+ for (int a = 0; a <= 31; a++) {
+// int r0 = blend31(src, dst, a);
+// int r0 = blend31_round(src, dst, a);
+// int r0 = blend31_old(src, dst, a);
+ int r0 = blend31_slow(src, dst, a);
+
+ float f = float_blend(src, dst, a / 31.f);
+ int r1 = (int)f;
+ int r2 = SkScalarRoundToInt(SkFloatToScalar(f));
+
+ if (r0 != r1 && r0 != r2) {
+ printf("src:%d dst:%d a:%d result:%d float:%g\n",
+ src, dst, a, r0, f);
+ failed += 1;
+ }
+ if (r0 > 255) {
+ death += 1;
+ printf("death src:%d dst:%d a:%d result:%d float:%g\n",
+ src, dst, a, r0, f);
+ }
}
}
}
+ SkDebugf("---- failed %d death %d\n", failed, death);
}
+
+static void test_blend(skiatest::Reporter* reporter) {
+ for (int src = 0; src <= 255; src++) {
+ for (int dst = 0; dst <= 255; dst++) {
+ for (int a = 0; a <= 255; a++) {
+ int r0 = SkAlphaBlend255(src, dst, a);
+ float f1 = float_blend(src, dst, a / 255.f);
+ int r1 = SkScalarRoundToInt(SkFloatToScalar(f1));
+
+ if (r0 != r1) {
+ float diff = sk_float_abs(f1 - r1);
+ diff = sk_float_abs(diff - 0.5f);
+ if (diff > (1 / 255.f)) {
+#ifdef SK_DEBUG
+ SkDebugf("src:%d dst:%d a:%d result:%d float:%g\n",
+ src, dst, a, r0, f1);
#endif
+ REPORTER_ASSERT(reporter, false);
+ }
+ }
+ }
+ }
+ }
+}
#if defined(SkLONGLONG)
static int symmetric_fixmul(int a, int b) {
@@ -493,7 +549,12 @@ static void TestMath(skiatest::Reporter* reporter) {
SkDebugf("SinCos: maximum error = %d\n", maxDiff);
#endif
-// test_premul(reporter);
+#ifdef SK_SCALAR_IS_FLOAT
+ test_blend(reporter);
+#endif
+
+ // disable for now
+// test_blend31();
}
#include "TestClassDef.h"
diff --git a/tests/Matrix44Test.cpp b/tests/Matrix44Test.cpp
index 8755bd3..485b38b 100644
--- a/tests/Matrix44Test.cpp
+++ b/tests/Matrix44Test.cpp
@@ -1,7 +1,14 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkMatrix44.h"
-static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
+static bool nearly_equal_scalar(SkMScalar a, SkMScalar b) {
// Note that we get more compounded error for multiple operations when
// SK_SCALAR_IS_FIXED.
#ifdef SK_SCALAR_IS_FLOAT
@@ -13,11 +20,37 @@ static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
return SkScalarAbs(a - b) <= tolerance;
}
+template <typename T> void assert16(skiatest::Reporter* reporter, const T data[],
+ T m0, T m1, T m2, T m3,
+ T m4, T m5, T m6, T m7,
+ T m8, T m9, T m10, T m11,
+ T m12, T m13, T m14, T m15) {
+ REPORTER_ASSERT(reporter, data[0] == m0);
+ REPORTER_ASSERT(reporter, data[1] == m1);
+ REPORTER_ASSERT(reporter, data[2] == m2);
+ REPORTER_ASSERT(reporter, data[3] == m3);
+
+ REPORTER_ASSERT(reporter, data[4] == m4);
+ REPORTER_ASSERT(reporter, data[5] == m5);
+ REPORTER_ASSERT(reporter, data[6] == m6);
+ REPORTER_ASSERT(reporter, data[7] == m7);
+
+ REPORTER_ASSERT(reporter, data[8] == m8);
+ REPORTER_ASSERT(reporter, data[9] == m9);
+ REPORTER_ASSERT(reporter, data[10] == m10);
+ REPORTER_ASSERT(reporter, data[11] == m11);
+
+ REPORTER_ASSERT(reporter, data[12] == m12);
+ REPORTER_ASSERT(reporter, data[13] == m13);
+ REPORTER_ASSERT(reporter, data[14] == m14);
+ REPORTER_ASSERT(reporter, data[15] == m15);
+}
+
static bool nearly_equal(const SkMatrix44& a, const SkMatrix44& b) {
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
if (!nearly_equal_scalar(a.get(i, j), b.get(i, j))) {
- printf("not equal %g %g\n", (float)a.get(i, j), (float)b.get(i, j));
+ printf("not equal %g %g\n", a.get(i, j), b.get(i, j));
return false;
}
}
@@ -31,8 +64,20 @@ static bool is_identity(const SkMatrix44& m) {
return nearly_equal(m, identity);
}
+static void test_common_angles(skiatest::Reporter* reporter) {
+ SkMatrix44 rot;
+ // Test precision of rotation in common cases
+ int common_angles[] = { 0, 90, -90, 180, -180, 270, -270, 360, -360 };
+ for (int i = 0; i < 9; ++i) {
+ rot.setRotateDegreesAbout(0, 0, -1, common_angles[i]);
+
+ SkMatrix rot3x3 = rot;
+ REPORTER_ASSERT(reporter, rot3x3.rectStaysRect());
+ }
+}
void TestMatrix44(skiatest::Reporter* reporter) {
+#ifdef SK_SCALAR_IS_FLOAT
SkMatrix44 mat, inverse, iden1, iden2, rot;
mat.reset();
@@ -64,6 +109,40 @@ void TestMatrix44(skiatest::Reporter* reporter) {
REPORTER_ASSERT(reporter, is_identity(iden1));
iden2.setConcat(inverse, mat);
REPORTER_ASSERT(reporter, is_identity(iden2));
+
+ // test rol/col Major getters
+ {
+ mat.setTranslate(2, 3, 4);
+ float dataf[16];
+ double datad[16];
+
+ mat.asColMajorf(dataf);
+ assert16<float>(reporter, dataf,
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 2, 3, 4, 1);
+ mat.asColMajord(datad);
+ assert16<double>(reporter, datad, 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 2, 3, 4, 1);
+ mat.asRowMajorf(dataf);
+ assert16<float>(reporter, dataf, 1, 0, 0, 2,
+ 0, 1, 0, 3,
+ 0, 0, 1, 4,
+ 0, 0, 0, 1);
+ mat.asRowMajord(datad);
+ assert16<double>(reporter, datad, 1, 0, 0, 2,
+ 0, 1, 0, 3,
+ 0, 0, 1, 4,
+ 0, 0, 0, 1);
+ }
+
+#if 0 // working on making this pass
+ test_common_angles(reporter);
+#endif
+#endif
}
#include "TestClassDef.h"
diff --git a/tests/MatrixTest.cpp b/tests/MatrixTest.cpp
index 4125f9f..c9a696c 100644
--- a/tests/MatrixTest.cpp
+++ b/tests/MatrixTest.cpp
@@ -1,5 +1,14 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
+#include "SkMath.h"
#include "SkMatrix.h"
+#include "SkRandom.h"
static bool nearly_equal_scalar(SkScalar a, SkScalar b) {
// Note that we get more compounded error for multiple operations when
@@ -48,6 +57,94 @@ static void test_flatten(skiatest::Reporter* reporter, const SkMatrix& m) {
REPORTER_ASSERT(reporter, memcmp(buffer, buffer2, size1) == 0);
}
+void test_matrix_max_stretch(skiatest::Reporter* reporter) {
+ SkMatrix identity;
+ identity.reset();
+ REPORTER_ASSERT(reporter, SK_Scalar1 == identity.getMaxStretch());
+
+ SkMatrix scale;
+ scale.setScale(SK_Scalar1 * 2, SK_Scalar1 * 4);
+ REPORTER_ASSERT(reporter, SK_Scalar1 * 4 == scale.getMaxStretch());
+
+ SkMatrix rot90Scale;
+ rot90Scale.setRotate(90 * SK_Scalar1);
+ rot90Scale.postScale(SK_Scalar1 / 4, SK_Scalar1 / 2);
+ REPORTER_ASSERT(reporter, SK_Scalar1 / 2 == rot90Scale.getMaxStretch());
+
+ SkMatrix rotate;
+ rotate.setRotate(128 * SK_Scalar1);
+ REPORTER_ASSERT(reporter, SkScalarAbs(SK_Scalar1 - rotate.getMaxStretch()) <= SK_ScalarNearlyZero);
+
+ SkMatrix translate;
+ translate.setTranslate(10 * SK_Scalar1, -5 * SK_Scalar1);
+ REPORTER_ASSERT(reporter, SK_Scalar1 == translate.getMaxStretch());
+
+ SkMatrix perspX;
+ perspX.reset();
+ perspX.setPerspX(SkScalarToPersp(SK_Scalar1 / 1000));
+ REPORTER_ASSERT(reporter, -SK_Scalar1 == perspX.getMaxStretch());
+
+ SkMatrix perspY;
+ perspY.reset();
+ perspY.setPerspX(SkScalarToPersp(-SK_Scalar1 / 500));
+ REPORTER_ASSERT(reporter, -SK_Scalar1 == perspY.getMaxStretch());
+
+ SkMatrix baseMats[] = {scale, rot90Scale, rotate,
+ translate, perspX, perspY};
+ SkMatrix mats[2*SK_ARRAY_COUNT(baseMats)];
+ for (size_t i = 0; i < SK_ARRAY_COUNT(baseMats); ++i) {
+ mats[i] = baseMats[i];
+ bool invertable = mats[i].invert(&mats[i + SK_ARRAY_COUNT(baseMats)]);
+ REPORTER_ASSERT(reporter, invertable);
+ }
+ SkRandom rand;
+ for (int m = 0; m < 1000; ++m) {
+ SkMatrix mat;
+ mat.reset();
+ for (int i = 0; i < 4; ++i) {
+ int x = rand.nextU() % SK_ARRAY_COUNT(mats);
+ mat.postConcat(mats[x]);
+ }
+ SkScalar stretch = mat.getMaxStretch();
+
+ if ((stretch < 0) != mat.hasPerspective()) {
+ stretch = mat.getMaxStretch();
+ }
+
+ REPORTER_ASSERT(reporter, (stretch < 0) == mat.hasPerspective());
+
+ if (mat.hasPerspective()) {
+ m -= 1; // try another non-persp matrix
+ continue;
+ }
+
+ // test a bunch of vectors. None should be scaled by more than stretch
+ // (modulo some error) and we should find a vector that is scaled by
+ // almost stretch.
+ static const SkScalar gStretchTol = (105 * SK_Scalar1) / 100;
+ static const SkScalar gMaxStretchTol = (97 * SK_Scalar1) / 100;
+ SkScalar max = 0;
+ SkVector vectors[1000];
+ for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) {
+ vectors[i].fX = rand.nextSScalar1();
+ vectors[i].fY = rand.nextSScalar1();
+ if (!vectors[i].normalize()) {
+ i -= 1;
+ continue;
+ }
+ }
+ mat.mapVectors(vectors, SK_ARRAY_COUNT(vectors));
+ for (size_t i = 0; i < SK_ARRAY_COUNT(vectors); ++i) {
+ SkScalar d = vectors[i].length();
+ REPORTER_ASSERT(reporter, SkScalarDiv(d, stretch) < gStretchTol);
+ if (max < d) {
+ max = d;
+ }
+ }
+ REPORTER_ASSERT(reporter, SkScalarDiv(max, stretch) >= gMaxStretchTol);
+ }
+}
+
void TestMatrix(skiatest::Reporter* reporter) {
SkMatrix mat, inverse, iden1, iden2;
@@ -117,6 +214,30 @@ void TestMatrix(skiatest::Reporter* reporter) {
m.rectStaysRect() == gRectStaysRectSamples[i].mStaysRect);
}
}
+
+ mat.reset();
+ mat.set(SkMatrix::kMScaleX, SkIntToScalar(1));
+ mat.set(SkMatrix::kMSkewX, SkIntToScalar(2));
+ mat.set(SkMatrix::kMTransX, SkIntToScalar(3));
+ mat.set(SkMatrix::kMSkewY, SkIntToScalar(4));
+ mat.set(SkMatrix::kMScaleY, SkIntToScalar(5));
+ mat.set(SkMatrix::kMTransY, SkIntToScalar(6));
+ SkScalar affine[6];
+ REPORTER_ASSERT(reporter, mat.asAffine(affine));
+
+ #define affineEqual(e) affine[SkMatrix::kA##e] == mat.get(SkMatrix::kM##e)
+ REPORTER_ASSERT(reporter, affineEqual(ScaleX));
+ REPORTER_ASSERT(reporter, affineEqual(SkewY));
+ REPORTER_ASSERT(reporter, affineEqual(SkewX));
+ REPORTER_ASSERT(reporter, affineEqual(ScaleY));
+ REPORTER_ASSERT(reporter, affineEqual(TransX));
+ REPORTER_ASSERT(reporter, affineEqual(TransY));
+ #undef affineEqual
+
+ mat.set(SkMatrix::kMPersp1, SkScalarToPersp(SK_Scalar1 / 2));
+ REPORTER_ASSERT(reporter, !mat.asAffine(affine));
+
+ test_matrix_max_stretch(reporter);
}
#include "TestClassDef.h"
diff --git a/tests/MemsetTest.cpp b/tests/MemsetTest.cpp
new file mode 100644
index 0000000..9c1fc92
--- /dev/null
+++ b/tests/MemsetTest.cpp
@@ -0,0 +1,91 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "Test.h"
+#include "SkUtils.h"
+
+static void set_zero(void* dst, size_t bytes) {
+ char* ptr = (char*)dst;
+ for (size_t i = 0; i < bytes; ++i) {
+ ptr[i] = 0;
+ }
+}
+
+#define MAX_ALIGNMENT 64
+#define MAX_COUNT ((MAX_ALIGNMENT) * 32)
+#define PAD 32
+#define TOTAL (PAD + MAX_ALIGNMENT + MAX_COUNT + PAD)
+
+#define VALUE16 0x1234
+#define VALUE32 0x12345678
+
+static bool compare16(const uint16_t base[], uint16_t value, int count) {
+ for (int i = 0; i < count; ++i) {
+ if (base[i] != value) {
+ SkDebugf("[%d] expected %x found %x\n", i, value, base[i]);
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool compare32(const uint32_t base[], uint32_t value, int count) {
+ for (int i = 0; i < count; ++i) {
+ if (base[i] != value) {
+ SkDebugf("[%d] expected %x found %x\n", i, value, base[i]);
+ return false;
+ }
+ }
+ return true;
+}
+
+static void test_16(skiatest::Reporter* reporter) {
+ uint16_t buffer[TOTAL];
+
+ for (int count = 0; count < MAX_COUNT; ++count) {
+ for (int alignment = 0; alignment < MAX_ALIGNMENT; ++alignment) {
+ set_zero(buffer, sizeof(buffer));
+
+ uint16_t* base = &buffer[PAD + alignment];
+ sk_memset16(base, VALUE16, count);
+
+ compare16(buffer, 0, PAD + alignment);
+ compare16(base, VALUE16, count);
+ compare16(base + count, 0, TOTAL - count - PAD - alignment);
+ }
+ }
+}
+
+static void test_32(skiatest::Reporter* reporter) {
+ uint32_t buffer[TOTAL];
+
+ for (int count = 0; count < MAX_COUNT; ++count) {
+ for (int alignment = 0; alignment < MAX_ALIGNMENT; ++alignment) {
+ set_zero(buffer, sizeof(buffer));
+
+ uint32_t* base = &buffer[PAD + alignment];
+ sk_memset32(base, VALUE32, count);
+
+ compare32(buffer, 0, PAD + alignment);
+ compare32(base, VALUE32, count);
+ compare32(base + count, 0, TOTAL - count - PAD - alignment);
+ }
+ }
+}
+
+/**
+ * Test sk_memset16 and sk_memset32.
+ * For performance considerations, implementations may take different paths
+ * depending on the alignment of the dst, and/or the size of the count.
+ */
+static void TestMemset(skiatest::Reporter* reporter) {
+ test_16(reporter);
+ test_32(reporter);
+};
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("Memset", TestMemsetClass, TestMemset)
diff --git a/tests/MetaDataTest.cpp b/tests/MetaDataTest.cpp
index 70829d4..1cc3cca 100644
--- a/tests/MetaDataTest.cpp
+++ b/tests/MetaDataTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkMetaData.h"
diff --git a/tests/PDFPrimitivesTest.cpp b/tests/PDFPrimitivesTest.cpp
index 9a58fa6..82686ef 100644
--- a/tests/PDFPrimitivesTest.cpp
+++ b/tests/PDFPrimitivesTest.cpp
@@ -1,39 +1,67 @@
+
/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * Copyright 2010 The Android Open Source Project
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include <string>
#include "Test.h"
+#include "SkData.h"
+#include "SkFlate.h"
#include "SkPDFCatalog.h"
#include "SkPDFStream.h"
#include "SkPDFTypes.h"
#include "SkScalar.h"
#include "SkStream.h"
+#include "SkTypes.h"
+
+class SkPDFTestDict : public SkPDFDict {
+public:
+ void getResources(SkTDArray<SkPDFObject*>* resourceList) {
+ resourceList->setReserve(resourceList->count() + fResources.count());
+ for (int i = 0; i < fResources.count(); i++) {
+ resourceList->push(fResources[i]);
+ fResources[i]->ref();
+ }
+ }
+
+ void addResource(SkPDFObject* object) {
+ fResources.append(1, &object);
+ }
+
+private:
+ SkTDArray<SkPDFObject*> fResources;
+};
+
+static bool stream_equals(const SkDynamicMemoryWStream& stream, size_t offset,
+ const void* buffer, size_t len) {
+ SkAutoDataUnref data(stream.copyToData());
+ if (offset + len > data.size()) {
+ return false;
+ }
+ return memcmp(data.bytes() + offset, buffer, len) == 0;
+}
static void CheckObjectOutput(skiatest::Reporter* reporter, SkPDFObject* obj,
- const std::string& representation,
- bool indirect) {
- size_t directSize = obj->getOutputSize(NULL, false);
- REPORTER_ASSERT(reporter, directSize == representation.size());
+ const char* expectedData, size_t expectedSize,
+ bool indirect, bool compression) {
+ SkPDFDocument::Flags docFlags = (SkPDFDocument::Flags) 0;
+ if (!compression) {
+ docFlags = SkTBitOr(docFlags, SkPDFDocument::kNoCompression_Flag);
+ }
+ SkPDFCatalog catalog(docFlags);
+ size_t directSize = obj->getOutputSize(&catalog, false);
+ REPORTER_ASSERT(reporter, directSize == expectedSize);
SkDynamicMemoryWStream buffer;
- obj->emitObject(&buffer, NULL, false);
+ obj->emit(&buffer, &catalog, false);
REPORTER_ASSERT(reporter, directSize == buffer.getOffset());
- REPORTER_ASSERT(reporter, memcmp(buffer.getStream(), representation.c_str(),
- directSize) == 0);
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedData,
+ directSize));
if (indirect) {
// Indirect output.
@@ -42,7 +70,6 @@ static void CheckObjectOutput(skiatest::Reporter* reporter, SkPDFObject* obj,
static char footer[] = "\nendobj\n";
static size_t footerLen = strlen(footer);
- SkPDFCatalog catalog;
catalog.addObject(obj, false);
size_t indirectSize = obj->getOutputSize(&catalog, true);
@@ -50,21 +77,77 @@ static void CheckObjectOutput(skiatest::Reporter* reporter, SkPDFObject* obj,
indirectSize == directSize + headerLen + footerLen);
buffer.reset();
- obj->emitObject(&buffer, &catalog, true);
+ obj->emit(&buffer, &catalog, true);
REPORTER_ASSERT(reporter, indirectSize == buffer.getOffset());
- REPORTER_ASSERT(reporter, memcmp(buffer.getStream(), header,
- headerLen) == 0);
- REPORTER_ASSERT(reporter,
- memcmp(buffer.getStream() + headerLen,
- representation.c_str(), directSize) == 0);
- REPORTER_ASSERT(reporter,
- memcmp(buffer.getStream() + headerLen + directSize,
- footer, footerLen) == 0);
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, header, headerLen));
+ REPORTER_ASSERT(reporter, stream_equals(buffer, headerLen, expectedData,
+ directSize));
+ REPORTER_ASSERT(reporter, stream_equals(buffer, headerLen + directSize,
+ footer, footerLen));
+ }
+}
+
+static void SimpleCheckObjectOutput(skiatest::Reporter* reporter,
+ SkPDFObject* obj,
+ const std::string& expectedResult) {
+ CheckObjectOutput(reporter, obj, expectedResult.c_str(),
+ expectedResult.length(), true, false);
+}
+
+static void TestPDFStream(skiatest::Reporter* reporter) {
+ char streamBytes[] = "Test\nFoo\tBar";
+ SkRefPtr<SkMemoryStream> streamData = new SkMemoryStream(
+ streamBytes, strlen(streamBytes), true);
+ streamData->unref(); // SkRefPtr and new both took a reference.
+ SkRefPtr<SkPDFStream> stream = new SkPDFStream(streamData.get());
+ stream->unref(); // SkRefPtr and new both took a reference.
+ SimpleCheckObjectOutput(
+ reporter, stream.get(),
+ "<</Length 12\n>> stream\nTest\nFoo\tBar\nendstream");
+ stream->insert("Attribute", new SkPDFInt(42))->unref();
+ SimpleCheckObjectOutput(reporter, stream.get(),
+ "<</Length 12\n/Attribute 42\n>> stream\n"
+ "Test\nFoo\tBar\nendstream");
+
+ if (SkFlate::HaveFlate()) {
+ char streamBytes2[] = "This is a longer string, so that compression "
+ "can do something with it. With shorter strings, "
+ "the short circuit logic cuts in and we end up "
+ "with an uncompressed string.";
+ SkAutoDataUnref streamData2(SkData::NewWithCopy(streamBytes2,
+ strlen(streamBytes2)));
+ SkRefPtr<SkPDFStream> stream = new SkPDFStream(streamData2.get());
+ stream->unref(); // SkRefPtr and new both took a reference.
+
+ SkDynamicMemoryWStream compressedByteStream;
+ SkFlate::Deflate(streamData2.get(), &compressedByteStream);
+ SkAutoDataUnref compressedData(compressedByteStream.copyToData());
+
+ // Check first without compression.
+ SkDynamicMemoryWStream expectedResult1;
+ expectedResult1.writeText("<</Length 167\n>> stream\n");
+ expectedResult1.writeText(streamBytes2);
+ expectedResult1.writeText("\nendstream");
+ SkAutoDataUnref expectedResultData1(expectedResult1.copyToData());
+ CheckObjectOutput(reporter, stream.get(),
+ (const char*) expectedResultData1.data(),
+ expectedResultData1.size(), true, false);
+
+ // Then again with compression.
+ SkDynamicMemoryWStream expectedResult2;
+ expectedResult2.writeText("<</Filter /FlateDecode\n/Length 116\n"
+ ">> stream\n");
+ expectedResult2.write(compressedData.data(), compressedData.size());
+ expectedResult2.writeText("\nendstream");
+ SkAutoDataUnref expectedResultData2(expectedResult2.copyToData());
+ CheckObjectOutput(reporter, stream.get(),
+ (const char*) expectedResultData2.data(),
+ expectedResultData2.size(), true, true);
}
}
static void TestCatalog(skiatest::Reporter* reporter) {
- SkPDFCatalog catalog;
+ SkPDFCatalog catalog((SkPDFDocument::Flags)0);
SkRefPtr<SkPDFInt> int1 = new SkPDFInt(1);
int1->unref(); // SkRefPtr and new both took a reference.
SkRefPtr<SkPDFInt> int2 = new SkPDFInt(2);
@@ -87,8 +170,8 @@ static void TestCatalog(skiatest::Reporter* reporter) {
catalog.emitObjectNumber(&buffer, int3.get());
catalog.emitObjectNumber(&buffer, int1Again.get());
char expectedResult[] = "1 02 03 01 0";
- REPORTER_ASSERT(reporter, memcmp(buffer.getStream(), expectedResult,
- strlen(expectedResult)) == 0);
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
+ strlen(expectedResult)));
}
static void TestObjectRef(skiatest::Reporter* reporter) {
@@ -99,7 +182,7 @@ static void TestObjectRef(skiatest::Reporter* reporter) {
SkRefPtr<SkPDFObjRef> int2ref = new SkPDFObjRef(int2.get());
int2ref->unref(); // SkRefPtr and new both took a reference.
- SkPDFCatalog catalog;
+ SkPDFCatalog catalog((SkPDFDocument::Flags)0);
catalog.addObject(int1.get(), false);
catalog.addObject(int2.get(), false);
REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int1.get()) == 3);
@@ -109,101 +192,128 @@ static void TestObjectRef(skiatest::Reporter* reporter) {
SkDynamicMemoryWStream buffer;
int2ref->emitObject(&buffer, &catalog, false);
REPORTER_ASSERT(reporter, buffer.getOffset() == strlen(expectedResult));
- REPORTER_ASSERT(reporter, memcmp(buffer.getStream(), expectedResult,
- buffer.getOffset()) == 0);
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
+ buffer.getOffset()));
+}
+
+static void TestSubstitute(skiatest::Reporter* reporter) {
+ SkRefPtr<SkPDFTestDict> proxy = new SkPDFTestDict();
+ proxy->unref(); // SkRefPtr and new both took a reference.
+ SkRefPtr<SkPDFTestDict> stub = new SkPDFTestDict();
+ stub->unref(); // SkRefPtr and new both took a reference.
+ SkRefPtr<SkPDFInt> int33 = new SkPDFInt(33);
+ int33->unref(); // SkRefPtr and new both took a reference.
+ SkRefPtr<SkPDFDict> stubResource = new SkPDFDict();
+ stubResource->unref(); // SkRefPtr and new both took a reference.
+ SkRefPtr<SkPDFInt> int44 = new SkPDFInt(44);
+ int44->unref(); // SkRefPtr and new both took a reference.
+
+ stub->insert("Value", int33.get());
+ stubResource->insert("InnerValue", int44.get());
+ stub->addResource(stubResource.get());
+
+ SkPDFCatalog catalog((SkPDFDocument::Flags)0);
+ catalog.addObject(proxy.get(), false);
+ catalog.setSubstitute(proxy.get(), stub.get());
+
+ SkDynamicMemoryWStream buffer;
+ proxy->emit(&buffer, &catalog, false);
+ catalog.emitSubstituteResources(&buffer, false);
+
+ char objectResult[] = "2 0 obj\n<</Value 33\n>>\nendobj\n";
+ REPORTER_ASSERT(
+ reporter,
+ catalog.setFileOffset(proxy.get(), 0) == strlen(objectResult));
+
+ char expectedResult[] =
+ "<</Value 33\n>>1 0 obj\n<</InnerValue 44\n>>\nendobj\n";
+ REPORTER_ASSERT(reporter, buffer.getOffset() == strlen(expectedResult));
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
+ buffer.getOffset()));
}
static void TestPDFPrimitives(skiatest::Reporter* reporter) {
SkRefPtr<SkPDFInt> int42 = new SkPDFInt(42);
int42->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, int42.get(), "42", true);
+ SimpleCheckObjectOutput(reporter, int42.get(), "42");
SkRefPtr<SkPDFScalar> realHalf = new SkPDFScalar(SK_ScalarHalf);
realHalf->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, realHalf.get(), "0.5", true);
+ SimpleCheckObjectOutput(reporter, realHalf.get(), "0.5");
#if defined(SK_SCALAR_IS_FLOAT)
SkRefPtr<SkPDFScalar> bigScalar = new SkPDFScalar(110999.75);
bigScalar->unref(); // SkRefPtr and new both took a reference.
#if !defined(SK_ALLOW_LARGE_PDF_SCALARS)
- CheckObjectOutput(reporter, bigScalar.get(), "111000", true);
+ SimpleCheckObjectOutput(reporter, bigScalar.get(), "111000");
#else
- CheckObjectOutput(reporter, bigScalar.get(), "110999.75", true);
+ SimpleCheckObjectOutput(reporter, bigScalar.get(), "110999.75");
SkRefPtr<SkPDFScalar> biggerScalar = new SkPDFScalar(50000000.1);
biggerScalar->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, biggerScalar.get(), "50000000", true);
+ SimpleCheckObjectOutput(reporter, biggerScalar.get(), "50000000");
SkRefPtr<SkPDFScalar> smallestScalar = new SkPDFScalar(1.0/65536);
smallestScalar->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, smallestScalar.get(), "0.00001526", true);
+ SimpleCheckObjectOutput(reporter, smallestScalar.get(), "0.00001526");
#endif
#endif
SkRefPtr<SkPDFString> stringSimple = new SkPDFString("test ) string ( foo");
stringSimple->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, stringSimple.get(), "(test \\) string \\( foo)",
- true);
+ SimpleCheckObjectOutput(reporter, stringSimple.get(),
+ "(test \\) string \\( foo)");
SkRefPtr<SkPDFString> stringComplex =
new SkPDFString("\ttest ) string ( foo");
stringComplex->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, stringComplex.get(),
- "<0974657374202920737472696E67202820666F6F>", true);
+ SimpleCheckObjectOutput(reporter, stringComplex.get(),
+ "<0974657374202920737472696E67202820666F6F>");
SkRefPtr<SkPDFName> name = new SkPDFName("Test name\twith#tab");
name->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, name.get(), "/Test#20name#09with#23tab", false);
+ const char expectedResult[] = "/Test#20name#09with#23tab";
+ CheckObjectOutput(reporter, name.get(), expectedResult,
+ strlen(expectedResult), false, false);
SkRefPtr<SkPDFArray> array = new SkPDFArray;
array->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, array.get(), "[]", true);
+ SimpleCheckObjectOutput(reporter, array.get(), "[]");
array->append(int42.get());
- CheckObjectOutput(reporter, array.get(), "[42]", true);
+ SimpleCheckObjectOutput(reporter, array.get(), "[42]");
array->append(realHalf.get());
- CheckObjectOutput(reporter, array.get(), "[42 0.5]", true);
+ SimpleCheckObjectOutput(reporter, array.get(), "[42 0.5]");
SkRefPtr<SkPDFInt> int0 = new SkPDFInt(0);
int0->unref(); // SkRefPtr and new both took a reference.
array->append(int0.get());
- CheckObjectOutput(reporter, array.get(), "[42 0.5 0]", true);
+ SimpleCheckObjectOutput(reporter, array.get(), "[42 0.5 0]");
SkRefPtr<SkPDFInt> int1 = new SkPDFInt(1);
int1->unref(); // SkRefPtr and new both took a reference.
array->setAt(0, int1.get());
- CheckObjectOutput(reporter, array.get(), "[1 0.5 0]", true);
+ SimpleCheckObjectOutput(reporter, array.get(), "[1 0.5 0]");
SkRefPtr<SkPDFDict> dict = new SkPDFDict;
dict->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, dict.get(), "<<>>", true);
+ SimpleCheckObjectOutput(reporter, dict.get(), "<<>>");
SkRefPtr<SkPDFName> n1 = new SkPDFName("n1");
n1->unref(); // SkRefPtr and new both took a reference.
dict->insert(n1.get(), int42.get());
- CheckObjectOutput(reporter, dict.get(), "<</n1 42\n>>", true);
+ SimpleCheckObjectOutput(reporter, dict.get(), "<</n1 42\n>>");
SkRefPtr<SkPDFName> n2 = new SkPDFName("n2");
n2->unref(); // SkRefPtr and new both took a reference.
SkRefPtr<SkPDFName> n3 = new SkPDFName("n3");
n3->unref(); // SkRefPtr and new both took a reference.
dict->insert(n2.get(), realHalf.get());
dict->insert(n3.get(), array.get());
- CheckObjectOutput(reporter, dict.get(),
- "<</n1 42\n/n2 0.5\n/n3 [1 0.5 0]\n>>", true);
+ SimpleCheckObjectOutput(reporter, dict.get(),
+ "<</n1 42\n/n2 0.5\n/n3 [1 0.5 0]\n>>");
- char streamBytes[] = "Test\nFoo\tBar";
- SkRefPtr<SkMemoryStream> streamData = new SkMemoryStream(
- streamBytes, strlen(streamBytes), true);
- streamData->unref(); // SkRefPtr and new both took a reference.
- SkRefPtr<SkPDFStream> stream = new SkPDFStream(streamData.get());
- stream->unref(); // SkRefPtr and new both took a reference.
- CheckObjectOutput(reporter, stream.get(),
- "<</Length 12\n>> stream\nTest\nFoo\tBar\nendstream",
- true);
- stream->insert(n1.get(), int42.get());
- CheckObjectOutput(reporter, stream.get(),
- "<</Length 12\n/n1 42\n>> stream\nTest\nFoo\tBar"
- "\nendstream",
- true);
+ TestPDFStream(reporter);
TestCatalog(reporter);
TestObjectRef(reporter);
+
+ TestSubstitute(reporter);
}
#include "TestClassDef.h"
diff --git a/tests/PackBitsTest.cpp b/tests/PackBitsTest.cpp
index a22590c..f7d4b8e 100644
--- a/tests/PackBitsTest.cpp
+++ b/tests/PackBitsTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkPackBits.h"
diff --git a/tests/PaintTest.cpp b/tests/PaintTest.cpp
index 5b19090..6350eb5 100644
--- a/tests/PaintTest.cpp
+++ b/tests/PaintTest.cpp
@@ -1,6 +1,67 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkPath.h"
#include "SkPaint.h"
+#include "SkLayerDrawLooper.h"
+#include "SkBlurMaskFilter.h"
+
+static void test_copy(skiatest::Reporter* reporter) {
+ SkPaint paint;
+ // set a few member variables
+ paint.setStyle(SkPaint::kStrokeAndFill_Style);
+ paint.setTextAlign(SkPaint::kLeft_Align);
+ paint.setStrokeWidth(SkIntToScalar(2));
+ // set a few pointers
+ SkLayerDrawLooper* looper = new SkLayerDrawLooper();
+ paint.setLooper(looper)->unref();
+ SkMaskFilter* mask = SkBlurMaskFilter::Create(1, SkBlurMaskFilter::kNormal_BlurStyle);
+ paint.setMaskFilter(mask)->unref();
+
+ // copy the paint using the copy constructor and check they are the same
+ SkPaint copiedPaint = paint;
+ REPORTER_ASSERT(reporter, paint == copiedPaint);
+
+#ifdef SK_BUILD_FOR_ANDROID
+ // the copy constructor should preserve the Generation ID
+ int32_t paintGenID = paint.getGenerationID();
+ int32_t copiedPaintGenID = copiedPaint.getGenerationID();
+ REPORTER_ASSERT(reporter, paintGenID == copiedPaintGenID);
+ REPORTER_ASSERT(reporter, !memcmp(&paint, &copiedPaint, sizeof(paint)));
+#endif
+
+ // copy the paint using the equal operator and check they are the same
+ copiedPaint = paint;
+ REPORTER_ASSERT(reporter, paint == copiedPaint);
+
+#ifdef SK_BUILD_FOR_ANDROID
+ // the equals operator should increment the Generation ID
+ REPORTER_ASSERT(reporter, paint.getGenerationID() == paintGenID);
+ REPORTER_ASSERT(reporter, copiedPaint.getGenerationID() != copiedPaintGenID);
+ copiedPaintGenID = copiedPaint.getGenerationID(); // reset to the new value
+ REPORTER_ASSERT(reporter, memcmp(&paint, &copiedPaint, sizeof(paint)));
+#endif
+
+ // clean the paint and check they are back to their initial states
+ SkPaint cleanPaint;
+ paint.reset();
+ copiedPaint.reset();
+ REPORTER_ASSERT(reporter, cleanPaint == paint);
+ REPORTER_ASSERT(reporter, cleanPaint == copiedPaint);
+
+#ifdef SK_BUILD_FOR_ANDROID
+ // the reset function should increment the Generation ID
+ REPORTER_ASSERT(reporter, paint.getGenerationID() != paintGenID);
+ REPORTER_ASSERT(reporter, copiedPaint.getGenerationID() != copiedPaintGenID);
+ REPORTER_ASSERT(reporter, memcmp(&cleanPaint, &paint, sizeof(cleanPaint)));
+ REPORTER_ASSERT(reporter, memcmp(&cleanPaint, &copiedPaint, sizeof(cleanPaint)));
+#endif
+}
// found and fixed for webkit: mishandling when we hit recursion limit on
// mostly degenerate cubic flatness test
@@ -38,6 +99,7 @@ static void regression_cubic(skiatest::Reporter* reporter) {
static void TestPaint(skiatest::Reporter* reporter) {
// TODO add general paint tests
+ test_copy(reporter);
// regression tests
regression_cubic(reporter);
diff --git a/tests/ParsePathTest.cpp b/tests/ParsePathTest.cpp
index 917b0cb..831cd8e 100644
--- a/tests/ParsePathTest.cpp
+++ b/tests/ParsePathTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkParsePath.h"
diff --git a/tests/PathCoverageTest.cpp b/tests/PathCoverageTest.cpp
index 8676029..91de178 100644
--- a/tests/PathCoverageTest.cpp
+++ b/tests/PathCoverageTest.cpp
@@ -1,15 +1,30 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkMath.h"
#include "SkPoint.h"
#include "SkScalar.h"
#include "Test.h"
/*
Duplicates lots of code from gpu/src/GrPathUtils.cpp
- It'd be nice not to do so, but that code's set up currently to only have a single implementation.
+ It'd be nice not to do so, but that code's set up currently to only have
+ a single implementation.
*/
+// Sk uses 6, Gr (implicitly) used 10, both apparently arbitrarily.
#define MAX_COEFF_SHIFT 6
static const uint32_t MAX_POINTS_PER_CURVE = 1 << MAX_COEFF_SHIFT;
+// max + 0.5 min has error [0.0, 0.12]
+// max + 0.375 min has error [-.03, 0.07]
+// 0.96043387 max + 0.397824735 min has error [-.06, +.05]
+// For determining the maximum possible number of points to use in
+// drawing a quadratic, we want to err on the high side.
static inline int cheap_distance(SkScalar dx, SkScalar dy) {
int idx = SkAbs32(SkScalarRound(dx));
int idy = SkAbs32(SkScalarRound(dy));
@@ -21,30 +36,27 @@ static inline int cheap_distance(SkScalar dx, SkScalar dy) {
return idx;
}
-static inline int diff_to_shift(SkScalar dx, SkScalar dy) {
- int dist = cheap_distance(dx, dy);
- return (32 - SkCLZ(dist));
+static inline int estimate_distance(const SkPoint points[]) {
+ return cheap_distance(points[1].fX * 2 - points[2].fX - points[0].fX,
+ points[1].fY * 2 - points[2].fY - points[0].fY);
}
-uint32_t estimatedQuadraticPointCount(const SkPoint points[], SkScalar tol) {
- int shift = diff_to_shift(points[1].fX * 2 - points[2].fX - points[0].fX,
- points[1].fY * 2 - points[2].fY - points[0].fY);
- SkASSERT(shift >= 0);
- //SkDebugf("Quad shift %d;", shift);
- // bias to more closely approximate exact value, then clamp to zero
- shift -= 2;
- shift &= ~(shift>>31);
+static inline SkScalar compute_distance(const SkPoint points[]) {
+ return points[1].distanceToLineSegmentBetween(points[0], points[2]);
+}
+static inline uint32_t estimate_pointCount(int distance) {
+ // Includes -2 bias because this estimator runs 4x high?
+ int shift = 30 - SkCLZ(distance);
+ // Clamp to zero if above subtraction went negative.
+ shift &= ~(shift>>31);
if (shift > MAX_COEFF_SHIFT) {
shift = MAX_COEFF_SHIFT;
}
- uint32_t count = 1 << shift;
- //SkDebugf(" biased shift %d, scale %u\n", shift, count);
- return count;
+ return 1 << shift;
}
-uint32_t computedQuadraticPointCount(const SkPoint points[], SkScalar tol) {
- SkScalar d = points[1].distanceToLineSegmentBetween(points[0], points[2]);
+static inline uint32_t compute_pointCount(SkScalar d, SkScalar tol) {
if (d < tol) {
return 1;
} else {
@@ -54,6 +66,26 @@ uint32_t computedQuadraticPointCount(const SkPoint points[], SkScalar tol) {
}
}
+uint32_t quadraticPointCount_EE(const SkPoint points[], SkScalar tol) {
+ int distance = estimate_distance(points);
+ return estimate_pointCount(distance);
+}
+
+uint32_t quadraticPointCount_EC(const SkPoint points[], SkScalar tol) {
+ int distance = estimate_distance(points);
+ return compute_pointCount(SkIntToScalar(distance), tol);
+}
+
+uint32_t quadraticPointCount_CE(const SkPoint points[], SkScalar tol) {
+ SkScalar distance = compute_distance(points);
+ return estimate_pointCount(SkScalarRound(distance));
+}
+
+uint32_t quadraticPointCount_CC(const SkPoint points[], SkScalar tol) {
+ SkScalar distance = compute_distance(points);
+ return compute_pointCount(distance, tol);
+}
+
// Curve from samplecode/SampleSlides.cpp
static const int gXY[] = {
4, 0, 0, -4, 8, -4, 12, 0, 8, 4, 0, 4
@@ -82,18 +114,21 @@ static bool one_d_pe(const int* array, const unsigned int count,
path[1] = SkPoint::Make(SkIntToScalar(array[0]), SkIntToScalar(array[1]));
path[2] = SkPoint::Make(SkIntToScalar(array[2]), SkIntToScalar(array[3]));
int numErrors = 0;
- for (unsigned i = 4; i < (count); i += 2) {
+ for (unsigned i = 4; i < count; i += 2) {
path[0] = path[1];
path[1] = path[2];
path[2] = SkPoint::Make(SkIntToScalar(array[i]),
SkIntToScalar(array[i+1]));
uint32_t computedCount =
- computedQuadraticPointCount(path, SkIntToScalar(1));
+ quadraticPointCount_CC(path, SkIntToScalar(1));
uint32_t estimatedCount =
- estimatedQuadraticPointCount(path, SkIntToScalar(1));
- // Allow estimated to be off by a factor of two, but no more.
- if ((estimatedCount > 2 * computedCount) ||
- (computedCount > estimatedCount * 2)) {
+ quadraticPointCount_EE(path, SkIntToScalar(1));
+ // Allow estimated to be high by a factor of two, but no less than
+ // the computed value.
+ bool isAccurate = (estimatedCount >= computedCount) &&
+ (estimatedCount <= 2 * computedCount);
+
+ if (!isAccurate) {
SkString errorDescription;
errorDescription.printf(
"Curve from %.2f %.2f through %.2f %.2f to %.2f %.2f "
@@ -105,8 +140,6 @@ static bool one_d_pe(const int* array, const unsigned int count,
}
}
- if (numErrors > 0)
- printf("%d curve segments differ\n", numErrors);
return (numErrors == 0);
}
diff --git a/tests/PathMeasureTest.cpp b/tests/PathMeasureTest.cpp
index de18764..d454e37 100644
--- a/tests/PathMeasureTest.cpp
+++ b/tests/PathMeasureTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkPathMeasure.h"
diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp
index 7e4e6bc..fadb0d9 100644
--- a/tests/PathTest.cpp
+++ b/tests/PathTest.cpp
@@ -1,7 +1,221 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
+#include "SkPaint.h"
#include "SkPath.h"
#include "SkParse.h"
+#include "SkParsePath.h"
+#include "SkRandom.h"
+#include "SkReader32.h"
#include "SkSize.h"
+#include "SkWriter32.h"
+
+static void test_direction(skiatest::Reporter* reporter) {
+ size_t i;
+ SkPath path;
+ REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
+ REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCW_Direction));
+ REPORTER_ASSERT(reporter, !path.cheapIsDirection(SkPath::kCCW_Direction));
+
+ static const char* gDegen[] = {
+ "M 10 10",
+ "M 10 10 M 20 20",
+ "M 10 10 L 20 20",
+ "M 10 10 L 10 10 L 10 10",
+ "M 10 10 Q 10 10 10 10",
+ "M 10 10 C 10 10 10 10 10 10",
+ };
+ for (i = 0; i < SK_ARRAY_COUNT(gDegen); ++i) {
+ path.reset();
+ bool valid = SkParsePath::FromSVGString(gDegen[i], &path);
+ REPORTER_ASSERT(reporter, valid);
+ REPORTER_ASSERT(reporter, !path.cheapComputeDirection(NULL));
+ }
+
+ static const char* gCW[] = {
+ "M 10 10 L 10 10 Q 20 10 20 20",
+ "M 10 10 C 20 10 20 20 20 20",
+ };
+ for (i = 0; i < SK_ARRAY_COUNT(gCW); ++i) {
+ path.reset();
+ bool valid = SkParsePath::FromSVGString(gCW[i], &path);
+ REPORTER_ASSERT(reporter, valid);
+ REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCW_Direction));
+ }
+
+ static const char* gCCW[] = {
+ "M 10 10 L 10 10 Q 20 10 20 -20",
+ "M 10 10 C 20 10 20 -20 20 -20",
+ };
+ for (i = 0; i < SK_ARRAY_COUNT(gCCW); ++i) {
+ path.reset();
+ bool valid = SkParsePath::FromSVGString(gCCW[i], &path);
+ REPORTER_ASSERT(reporter, valid);
+ REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCCW_Direction));
+ }
+}
+
+static void add_rect(SkPath* path, const SkRect& r) {
+ path->moveTo(r.fLeft, r.fTop);
+ path->lineTo(r.fRight, r.fTop);
+ path->lineTo(r.fRight, r.fBottom);
+ path->lineTo(r.fLeft, r.fBottom);
+ path->close();
+}
+
+static void test_bounds(skiatest::Reporter* reporter) {
+ static const SkRect rects[] = {
+ { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(160) },
+ { SkIntToScalar(610), SkIntToScalar(160), SkIntToScalar(610), SkIntToScalar(199) },
+ { SkIntToScalar(10), SkIntToScalar(198), SkIntToScalar(610), SkIntToScalar(199) },
+ { SkIntToScalar(10), SkIntToScalar(160), SkIntToScalar(10), SkIntToScalar(199) },
+ };
+
+ SkPath path0, path1;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(rects); ++i) {
+ path0.addRect(rects[i]);
+ add_rect(&path1, rects[i]);
+ }
+
+ REPORTER_ASSERT(reporter, path0.getBounds() == path1.getBounds());
+}
+
+static void stroke_cubic(const SkPoint pts[4]) {
+ SkPath path;
+ path.moveTo(pts[0]);
+ path.cubicTo(pts[1], pts[2], pts[3]);
+
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SK_Scalar1 * 2);
+
+ SkPath fill;
+ paint.getFillPath(path, &fill);
+}
+
+// just ensure this can run w/o any SkASSERTS firing in the debug build
+// we used to assert due to differences in how we determine a degenerate vector
+// but that was fixed with the introduction of SkPoint::CanNormalize
+static void stroke_tiny_cubic() {
+ SkPoint p0[] = {
+ { 372.0f, 92.0f },
+ { 372.0f, 92.0f },
+ { 372.0f, 92.0f },
+ { 372.0f, 92.0f },
+ };
+
+ stroke_cubic(p0);
+
+ SkPoint p1[] = {
+ { 372.0f, 92.0f },
+ { 372.0007f, 92.000755f },
+ { 371.99927f, 92.003922f },
+ { 371.99826f, 92.003899f },
+ };
+
+ stroke_cubic(p1);
+}
+
+static void check_close(skiatest::Reporter* reporter, const SkPath& path) {
+ for (int i = 0; i < 2; ++i) {
+ SkPath::Iter iter(path, (bool)i);
+ SkPoint mv;
+ SkPoint pts[4];
+ SkPath::Verb v;
+ int nMT = 0;
+ int nCL = 0;
+ mv.set(0, 0);
+ while (SkPath::kDone_Verb != (v = iter.next(pts))) {
+ switch (v) {
+ case SkPath::kMove_Verb:
+ mv = pts[0];
+ ++nMT;
+ break;
+ case SkPath::kClose_Verb:
+ REPORTER_ASSERT(reporter, mv == pts[0]);
+ ++nCL;
+ break;
+ default:
+ break;
+ }
+ }
+ // if we force a close on the interator we should have a close
+ // for every moveTo
+ REPORTER_ASSERT(reporter, !i || nMT == nCL);
+ }
+}
+
+static void test_close(skiatest::Reporter* reporter) {
+ SkPath closePt;
+ closePt.moveTo(0, 0);
+ closePt.close();
+ check_close(reporter, closePt);
+
+ SkPath openPt;
+ openPt.moveTo(0, 0);
+ check_close(reporter, openPt);
+
+ SkPath empty;
+ check_close(reporter, empty);
+ empty.close();
+ check_close(reporter, empty);
+
+ SkPath rect;
+ rect.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
+ check_close(reporter, rect);
+ rect.close();
+ check_close(reporter, rect);
+
+ SkPath quad;
+ quad.quadTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
+ check_close(reporter, quad);
+ quad.close();
+ check_close(reporter, quad);
+
+ SkPath cubic;
+ quad.cubicTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1,
+ 10*SK_Scalar1, 20 * SK_Scalar1, 20*SK_Scalar1);
+ check_close(reporter, cubic);
+ cubic.close();
+ check_close(reporter, cubic);
+
+ SkPath line;
+ line.moveTo(SK_Scalar1, SK_Scalar1);
+ line.lineTo(10 * SK_Scalar1, 10*SK_Scalar1);
+ check_close(reporter, line);
+ line.close();
+ check_close(reporter, line);
+
+ SkPath rect2;
+ rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
+ rect2.close();
+ rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1);
+ check_close(reporter, rect2);
+ rect2.close();
+ check_close(reporter, rect2);
+
+ SkPath oval3;
+ oval3.addOval(SkRect::MakeWH(SK_Scalar1*100,SK_Scalar1*100));
+ oval3.close();
+ oval3.addOval(SkRect::MakeWH(SK_Scalar1*200,SK_Scalar1*200));
+ check_close(reporter, oval3);
+ oval3.close();
+ check_close(reporter, oval3);
+
+ SkPath moves;
+ moves.moveTo(SK_Scalar1, SK_Scalar1);
+ moves.moveTo(5 * SK_Scalar1, SK_Scalar1);
+ moves.moveTo(SK_Scalar1, 10 * SK_Scalar1);
+ moves.moveTo(10 *SK_Scalar1, SK_Scalar1);
+ check_close(reporter, moves);
+
+ stroke_tiny_cubic();
+}
static void check_convexity(skiatest::Reporter* reporter, const SkPath& path,
SkPath::Convexity expected) {
@@ -16,30 +230,30 @@ static void test_convexity2(skiatest::Reporter* reporter) {
check_convexity(reporter, pt, SkPath::kConvex_Convexity);
SkPath line;
- line.moveTo(12, 20);
- line.lineTo(-12, -20);
+ line.moveTo(12*SK_Scalar1, 20*SK_Scalar1);
+ line.lineTo(-12*SK_Scalar1, -20*SK_Scalar1);
line.close();
check_convexity(reporter, pt, SkPath::kConvex_Convexity);
SkPath triLeft;
triLeft.moveTo(0, 0);
- triLeft.lineTo(1, 0);
- triLeft.lineTo(1, 1);
+ triLeft.lineTo(SK_Scalar1, 0);
+ triLeft.lineTo(SK_Scalar1, SK_Scalar1);
triLeft.close();
check_convexity(reporter, triLeft, SkPath::kConvex_Convexity);
SkPath triRight;
triRight.moveTo(0, 0);
- triRight.lineTo(-1, 0);
- triRight.lineTo(1, 1);
+ triRight.lineTo(-SK_Scalar1, 0);
+ triRight.lineTo(SK_Scalar1, SK_Scalar1);
triRight.close();
check_convexity(reporter, triRight, SkPath::kConvex_Convexity);
SkPath square;
square.moveTo(0, 0);
- square.lineTo(1, 0);
- square.lineTo(1, 1);
- square.lineTo(0, 1);
+ square.lineTo(SK_Scalar1, 0);
+ square.lineTo(SK_Scalar1, SK_Scalar1);
+ square.lineTo(0, SK_Scalar1);
square.close();
check_convexity(reporter, square, SkPath::kConvex_Convexity);
@@ -47,15 +261,15 @@ static void test_convexity2(skiatest::Reporter* reporter) {
redundantSquare.moveTo(0, 0);
redundantSquare.lineTo(0, 0);
redundantSquare.lineTo(0, 0);
- redundantSquare.lineTo(1, 0);
- redundantSquare.lineTo(1, 0);
- redundantSquare.lineTo(1, 0);
- redundantSquare.lineTo(1, 1);
- redundantSquare.lineTo(1, 1);
- redundantSquare.lineTo(1, 1);
- redundantSquare.lineTo(0, 1);
- redundantSquare.lineTo(0, 1);
- redundantSquare.lineTo(0, 1);
+ redundantSquare.lineTo(SK_Scalar1, 0);
+ redundantSquare.lineTo(SK_Scalar1, 0);
+ redundantSquare.lineTo(SK_Scalar1, 0);
+ redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
+ redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
+ redundantSquare.lineTo(SK_Scalar1, SK_Scalar1);
+ redundantSquare.lineTo(0, SK_Scalar1);
+ redundantSquare.lineTo(0, SK_Scalar1);
+ redundantSquare.lineTo(0, SK_Scalar1);
redundantSquare.close();
check_convexity(reporter, redundantSquare, SkPath::kConvex_Convexity);
@@ -63,35 +277,35 @@ static void test_convexity2(skiatest::Reporter* reporter) {
bowTie.moveTo(0, 0);
bowTie.lineTo(0, 0);
bowTie.lineTo(0, 0);
- bowTie.lineTo(1, 1);
- bowTie.lineTo(1, 1);
- bowTie.lineTo(1, 1);
- bowTie.lineTo(1, 0);
- bowTie.lineTo(1, 0);
- bowTie.lineTo(1, 0);
- bowTie.lineTo(0, 1);
- bowTie.lineTo(0, 1);
- bowTie.lineTo(0, 1);
+ bowTie.lineTo(SK_Scalar1, SK_Scalar1);
+ bowTie.lineTo(SK_Scalar1, SK_Scalar1);
+ bowTie.lineTo(SK_Scalar1, SK_Scalar1);
+ bowTie.lineTo(SK_Scalar1, 0);
+ bowTie.lineTo(SK_Scalar1, 0);
+ bowTie.lineTo(SK_Scalar1, 0);
+ bowTie.lineTo(0, SK_Scalar1);
+ bowTie.lineTo(0, SK_Scalar1);
+ bowTie.lineTo(0, SK_Scalar1);
bowTie.close();
check_convexity(reporter, bowTie, SkPath::kConcave_Convexity);
SkPath spiral;
spiral.moveTo(0, 0);
- spiral.lineTo(100, 0);
- spiral.lineTo(100, 100);
- spiral.lineTo(0, 100);
- spiral.lineTo(0, 50);
- spiral.lineTo(50, 50);
- spiral.lineTo(50, 75);
+ spiral.lineTo(100*SK_Scalar1, 0);
+ spiral.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
+ spiral.lineTo(0, 100*SK_Scalar1);
+ spiral.lineTo(0, 50*SK_Scalar1);
+ spiral.lineTo(50*SK_Scalar1, 50*SK_Scalar1);
+ spiral.lineTo(50*SK_Scalar1, 75*SK_Scalar1);
spiral.close();
check_convexity(reporter, spiral, SkPath::kConcave_Convexity);
SkPath dent;
- dent.moveTo(SkIntToScalar(0), SkIntToScalar(0));
- dent.lineTo(SkIntToScalar(100), SkIntToScalar(100));
- dent.lineTo(SkIntToScalar(0), SkIntToScalar(100));
- dent.lineTo(SkIntToScalar(-50), SkIntToScalar(200));
- dent.lineTo(SkIntToScalar(-200), SkIntToScalar(100));
+ dent.moveTo(0, 0);
+ dent.lineTo(100*SK_Scalar1, 100*SK_Scalar1);
+ dent.lineTo(0, 100*SK_Scalar1);
+ dent.lineTo(-50*SK_Scalar1, 200*SK_Scalar1);
+ dent.lineTo(-200*SK_Scalar1, 100*SK_Scalar1);
dent.close();
check_convexity(reporter, dent, SkPath::kConcave_Convexity);
}
@@ -137,16 +351,18 @@ static void test_convexity(skiatest::Reporter* reporter) {
SkPath path;
REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
- path.addCircle(0, 0, 10);
+ path.addCircle(0, 0, SkIntToScalar(10));
REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
- path.addCircle(0, 0, 10); // 2nd circle
+ path.addCircle(0, 0, SkIntToScalar(10)); // 2nd circle
REPORTER_ASSERT(reporter, C == SkPath::ComputeConvexity(path));
path.reset();
- path.addRect(0, 0, 10, 10, SkPath::kCCW_Direction);
+ path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCCW_Direction);
REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
+ REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCCW_Direction));
path.reset();
- path.addRect(0, 0, 10, 10, SkPath::kCW_Direction);
+ path.addRect(0, 0, SkIntToScalar(10), SkIntToScalar(10), SkPath::kCW_Direction);
REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path));
+ REPORTER_ASSERT(reporter, path.cheapIsDirection(SkPath::kCW_Direction));
static const struct {
const char* fPathStr;
@@ -170,6 +386,631 @@ static void test_convexity(skiatest::Reporter* reporter) {
}
}
+// Simple isRect test is inline TestPath, below.
+// test_isRect provides more extensive testing.
+static void test_isRect(skiatest::Reporter* reporter) {
+ // passing tests (all moveTo / lineTo...
+ SkPoint r1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
+ SkPoint r2[] = {{1, 0}, {1, 1}, {0, 1}, {0, 0}};
+ SkPoint r3[] = {{1, 1}, {0, 1}, {0, 0}, {1, 0}};
+ SkPoint r4[] = {{0, 1}, {0, 0}, {1, 0}, {1, 1}};
+ SkPoint r5[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
+ SkPoint r6[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
+ SkPoint r7[] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
+ SkPoint r8[] = {{1, 0}, {0, 0}, {0, 1}, {1, 1}};
+ SkPoint r9[] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
+ SkPoint ra[] = {{0, 0}, {0, .5f}, {0, 1}, {.5f, 1}, {1, 1}, {1, .5f},
+ {1, 0}, {.5f, 0}};
+ SkPoint rb[] = {{0, 0}, {.5f, 0}, {1, 0}, {1, .5f}, {1, 1}, {.5f, 1},
+ {0, 1}, {0, .5f}};
+ SkPoint rc[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}};
+ SkPoint rd[] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0}};
+ SkPoint re[] = {{0, 0}, {1, 0}, {1, 0}, {1, 1}, {0, 1}};
+
+ // failing tests
+ SkPoint f1[] = {{0, 0}, {1, 0}, {1, 1}}; // too few points
+ SkPoint f2[] = {{0, 0}, {1, 1}, {0, 1}, {1, 0}}; // diagonal
+ SkPoint f3[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}, {1, 0}}; // wraps
+ SkPoint f4[] = {{0, 0}, {1, 0}, {0, 0}, {1, 0}, {1, 1}, {0, 1}}; // backs up
+ SkPoint f5[] = {{0, 0}, {1, 0}, {1, 1}, {2, 0}}; // end overshoots
+ SkPoint f6[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 2}}; // end overshoots
+ SkPoint f7[] = {{0, 0}, {1, 0}, {1, 1}, {0, 2}}; // end overshoots
+ SkPoint f8[] = {{0, 0}, {1, 0}, {1, 1}, {1, 0}}; // 'L'
+
+ // failing, no close
+ SkPoint c1[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; // close doesn't match
+ SkPoint c2[] = {{0, 0}, {1, 0}, {1, 2}, {0, 2}, {0, 1}}; // ditto
+
+ size_t testLen[] = {
+ sizeof(r1), sizeof(r2), sizeof(r3), sizeof(r4), sizeof(r5), sizeof(r6),
+ sizeof(r7), sizeof(r8), sizeof(r9), sizeof(ra), sizeof(rb), sizeof(rc),
+ sizeof(rd), sizeof(re),
+ sizeof(f1), sizeof(f2), sizeof(f3), sizeof(f4), sizeof(f5), sizeof(f6),
+ sizeof(f7), sizeof(f8),
+ sizeof(c1), sizeof(c2)
+ };
+ SkPoint* tests[] = {
+ r1, r2, r3, r4, r5, r6, r7, r8, r9, ra, rb, rc, rd, re,
+ f1, f2, f3, f4, f5, f6, f7, f8,
+ c1, c2
+ };
+ SkPoint* lastPass = re;
+ SkPoint* lastClose = f8;
+ bool fail = false;
+ bool close = true;
+ const size_t testCount = sizeof(tests) / sizeof(tests[0]);
+ size_t index;
+ for (size_t testIndex = 0; testIndex < testCount; ++testIndex) {
+ SkPath path;
+ path.moveTo(tests[testIndex][0].fX, tests[testIndex][0].fY);
+ for (index = 1; index < testLen[testIndex] / sizeof(SkPoint); ++index) {
+ path.lineTo(tests[testIndex][index].fX, tests[testIndex][index].fY);
+ }
+ if (close) {
+ path.close();
+ }
+ REPORTER_ASSERT(reporter, fail ^ path.isRect(0));
+ if (tests[testIndex] == lastPass) {
+ fail = true;
+ }
+ if (tests[testIndex] == lastClose) {
+ close = false;
+ }
+ }
+
+ // fail, close then line
+ SkPath path1;
+ path1.moveTo(r1[0].fX, r1[0].fY);
+ for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ path1.lineTo(1, 0);
+ REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
+
+ // fail, move in the middle
+ path1.reset();
+ path1.moveTo(r1[0].fX, r1[0].fY);
+ for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
+ if (index == 2) {
+ path1.moveTo(1, .5f);
+ }
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
+
+ // fail, move on the edge
+ path1.reset();
+ for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
+ path1.moveTo(r1[index - 1].fX, r1[index - 1].fY);
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
+
+ // fail, quad
+ path1.reset();
+ path1.moveTo(r1[0].fX, r1[0].fY);
+ for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
+ if (index == 2) {
+ path1.quadTo(1, .5f, 1, .5f);
+ }
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
+
+ // fail, cubic
+ path1.reset();
+ path1.moveTo(r1[0].fX, r1[0].fY);
+ for (index = 1; index < testLen[0] / sizeof(SkPoint); ++index) {
+ if (index == 2) {
+ path1.cubicTo(1, .5f, 1, .5f, 1, .5f);
+ }
+ path1.lineTo(r1[index].fX, r1[index].fY);
+ }
+ path1.close();
+ REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
+}
+
+static void test_flattening(skiatest::Reporter* reporter) {
+ SkPath p;
+
+ static const SkPoint pts[] = {
+ { 0, 0 },
+ { SkIntToScalar(10), SkIntToScalar(10) },
+ { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
+ { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
+ };
+ p.moveTo(pts[0]);
+ p.lineTo(pts[1]);
+ p.quadTo(pts[2], pts[3]);
+ p.cubicTo(pts[4], pts[5], pts[6]);
+
+ SkWriter32 writer(100);
+ p.flatten(writer);
+ size_t size = writer.size();
+ SkAutoMalloc storage(size);
+ writer.flatten(storage.get());
+ SkReader32 reader(storage.get(), size);
+
+ SkPath p1;
+ REPORTER_ASSERT(reporter, p1 != p);
+ p1.unflatten(reader);
+ REPORTER_ASSERT(reporter, p1 == p);
+}
+
+static void test_transform(skiatest::Reporter* reporter) {
+ SkPath p, p1;
+
+ static const SkPoint pts[] = {
+ { 0, 0 },
+ { SkIntToScalar(10), SkIntToScalar(10) },
+ { SkIntToScalar(20), SkIntToScalar(10) }, { SkIntToScalar(20), 0 },
+ { 0, 0 }, { 0, SkIntToScalar(10) }, { SkIntToScalar(1), SkIntToScalar(10) }
+ };
+ p.moveTo(pts[0]);
+ p.lineTo(pts[1]);
+ p.quadTo(pts[2], pts[3]);
+ p.cubicTo(pts[4], pts[5], pts[6]);
+
+ SkMatrix matrix;
+ matrix.reset();
+ p.transform(matrix, &p1);
+ REPORTER_ASSERT(reporter, p == p1);
+
+ matrix.setScale(SK_Scalar1 * 2, SK_Scalar1 * 3);
+ p.transform(matrix, &p1);
+ SkPoint pts1[7];
+ int count = p1.getPoints(pts1, 7);
+ REPORTER_ASSERT(reporter, 7 == count);
+ for (int i = 0; i < count; ++i) {
+ SkPoint newPt = SkPoint::Make(pts[i].fX * 2, pts[i].fY * 3);
+ REPORTER_ASSERT(reporter, newPt == pts1[i]);
+ }
+}
+
+static void test_zero_length_paths(skiatest::Reporter* reporter) {
+ SkPath p;
+ SkPoint pt;
+ SkRect bounds;
+
+ // Lone moveTo case
+ p.moveTo(SK_Scalar1, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 1 == p.countPoints());
+ p.getLastPt(&pt);
+ REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1);
+ REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
+ bounds.set(0, 0, 0, 0);
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // MoveTo-MoveTo case
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 2 == p.countPoints());
+ p.getLastPt(&pt);
+ REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1*2);
+ REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
+ bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1);
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-close case
+ p.reset();
+ p.moveTo(SK_Scalar1, SK_Scalar1);
+ p.close();
+ bounds.set(0, 0, 0, 0);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 1 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-close-moveTo-close case
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ p.close();
+ bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 2 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-line case
+ p.reset();
+ p.moveTo(SK_Scalar1, SK_Scalar1);
+ p.lineTo(SK_Scalar1, SK_Scalar1);
+ bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 2 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-lineTo-moveTo-lineTo case
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ p.lineTo(SK_Scalar1*2, SK_Scalar1);
+ bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 4 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-line-close case
+ p.reset();
+ p.moveTo(SK_Scalar1, SK_Scalar1);
+ p.lineTo(SK_Scalar1, SK_Scalar1);
+ p.close();
+ bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 2 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-line-close-moveTo-line-close case
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ p.lineTo(SK_Scalar1*2, SK_Scalar1);
+ p.close();
+ bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 4 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-quadTo case
+ p.reset();
+ p.moveTo(SK_Scalar1, SK_Scalar1);
+ p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 3 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-quadTo-close case
+ p.close();
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 3 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-quadTo-moveTo-quadTo case
+ p.reset();
+ p.moveTo(SK_Scalar1, SK_Scalar1);
+ p.quadTo(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ p.quadTo(SK_Scalar1*2, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
+ bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 6 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-cubicTo case
+ p.reset();
+ p.moveTo(SK_Scalar1, SK_Scalar1);
+ p.cubicTo(SK_Scalar1, SK_Scalar1,
+ SK_Scalar1, SK_Scalar1,
+ SK_Scalar1, SK_Scalar1);
+ bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 4 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-quadTo-close case
+ p.close();
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 4 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+
+ // moveTo-quadTo-moveTo-quadTo case
+ p.reset();
+ p.moveTo(SK_Scalar1, SK_Scalar1);
+ p.cubicTo(SK_Scalar1, SK_Scalar1,
+ SK_Scalar1, SK_Scalar1,
+ SK_Scalar1, SK_Scalar1);
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ p.cubicTo(SK_Scalar1*2, SK_Scalar1,
+ SK_Scalar1*2, SK_Scalar1,
+ SK_Scalar1*2, SK_Scalar1);
+ bounds.set(SK_Scalar1, SK_Scalar1, SK_Scalar1*2, SK_Scalar1);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ REPORTER_ASSERT(reporter, 8 == p.countPoints());
+ REPORTER_ASSERT(reporter, bounds == p.getBounds());
+}
+
+struct SegmentInfo {
+ SkPath fPath;
+ int fPointCount;
+};
+
+#define kCurveSegmentMask (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)
+
+static void test_segment_masks(skiatest::Reporter* reporter) {
+ SkPath p;
+ p.moveTo(0, 0);
+ p.quadTo(100, 100, 200, 200);
+ REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == p.getSegmentMasks());
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ p.cubicTo(100, 100, 200, 200, 300, 300);
+ REPORTER_ASSERT(reporter, kCurveSegmentMask == p.getSegmentMasks());
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+ p.reset();
+ p.moveTo(0, 0);
+ p.cubicTo(100, 100, 200, 200, 300, 300);
+ REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == p.getSegmentMasks());
+ REPORTER_ASSERT(reporter, !p.isEmpty());
+}
+
+static void test_iter(skiatest::Reporter* reporter) {
+ SkPath p;
+ SkPoint pts[4];
+
+ // Test an iterator with no path
+ SkPath::Iter noPathIter;
+ REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
+ // Test that setting an empty path works
+ noPathIter.setPath(p, false);
+ REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
+ // Test that close path makes no difference for an empty path
+ noPathIter.setPath(p, true);
+ REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
+
+ // Test an iterator with an initial empty path
+ SkPath::Iter iter(p, false);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // Test that close path makes no difference
+ SkPath::Iter forceCloseIter(p, true);
+ REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
+
+ // Test that a move-only path produces nothing when iterated.
+ p.moveTo(SK_Scalar1, 0);
+ iter.setPath(p, false);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // No matter how many moves we add, we should still get nothing back.
+ p.moveTo(SK_Scalar1*2, 0);
+ p.moveTo(SK_Scalar1*3, 0);
+ p.moveTo(SK_Scalar1*4, 0);
+ p.moveTo(SK_Scalar1*5, 0);
+ iter.setPath(p, false);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // Nor should force closing
+ forceCloseIter.setPath(p, true);
+ REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
+
+ // Initial closes should be ignored
+ p.reset();
+ p.close();
+ iter.setPath(p, false);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+ // Even if force closed
+ forceCloseIter.setPath(p, true);
+ REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
+
+ // Move/close sequences should also be ignored
+ p.reset();
+ p.close();
+ p.moveTo(SK_Scalar1, 0);
+ p.close();
+ p.close();
+ p.moveTo(SK_Scalar1*2, 0);
+ p.close();
+ p.moveTo(SK_Scalar1*3, 0);
+ p.moveTo(SK_Scalar1*4, 0);
+ p.close();
+ iter.setPath(p, false);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+ // Even if force closed
+ forceCloseIter.setPath(p, true);
+ REPORTER_ASSERT(reporter, forceCloseIter.next(pts) == SkPath::kDone_Verb);
+
+ // The GM degeneratesegments.cpp test is more extensive
+}
+
+static void test_raw_iter(skiatest::Reporter* reporter) {
+ SkPath p;
+ SkPoint pts[4];
+
+ // Test an iterator with no path
+ SkPath::RawIter noPathIter;
+ REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
+ // Test that setting an empty path works
+ noPathIter.setPath(p);
+ REPORTER_ASSERT(reporter, noPathIter.next(pts) == SkPath::kDone_Verb);
+
+ // Test an iterator with an initial empty path
+ SkPath::RawIter iter(p);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // Test that a move-only path returns the move.
+ p.moveTo(SK_Scalar1, 0);
+ iter.setPath(p);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
+ REPORTER_ASSERT(reporter, pts[0].fY == 0);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // No matter how many moves we add, we should get them all back
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
+ iter.setPath(p);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
+ REPORTER_ASSERT(reporter, pts[0].fY == 0);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // Initial close is never ever stored
+ p.reset();
+ p.close();
+ iter.setPath(p);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // Move/close sequences
+ p.reset();
+ p.close(); // Not stored, no purpose
+ p.moveTo(SK_Scalar1, 0);
+ p.close();
+ p.close(); // Not stored, no purpose
+ p.moveTo(SK_Scalar1*2, SK_Scalar1);
+ p.close();
+ p.moveTo(SK_Scalar1*3, SK_Scalar1*2);
+ p.moveTo(SK_Scalar1*4, SK_Scalar1*3);
+ p.close();
+ iter.setPath(p);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
+ REPORTER_ASSERT(reporter, pts[0].fY == 0);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1);
+ REPORTER_ASSERT(reporter, pts[0].fY == 0);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*2);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*3);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*2);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kMove_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kClose_Verb);
+ REPORTER_ASSERT(reporter, pts[0].fX == SK_Scalar1*4);
+ REPORTER_ASSERT(reporter, pts[0].fY == SK_Scalar1*3);
+ REPORTER_ASSERT(reporter, iter.next(pts) == SkPath::kDone_Verb);
+
+ // Generate random paths and verify
+ SkPoint randomPts[25];
+ for (int i = 0; i < 5; ++i) {
+ for (int j = 0; j < 5; ++j) {
+ randomPts[i*5+j].set(SK_Scalar1*i, SK_Scalar1*j);
+ }
+ }
+
+ // Max of 10 segments, max 3 points per segment
+ SkRandom rand(9876543);
+ SkPoint expectedPts[31]; // May have leading moveTo
+ SkPath::Verb expectedVerbs[11]; // May have leading moveTo
+ SkPath::Verb nextVerb;
+ for (int i = 0; i < 500; ++i) {
+ p.reset();
+ bool lastWasClose = true;
+ bool haveMoveTo = false;
+ int numPoints = 0;
+ int numVerbs = (rand.nextU() >> 16) % 10;
+ int numIterVerbs = 0;
+ for (int j = 0; j < numVerbs; ++j) {
+ do {
+ nextVerb = static_cast<SkPath::Verb>((rand.nextU() >> 16) % SkPath::kDone_Verb);
+ } while (lastWasClose && nextVerb == SkPath::kClose_Verb);
+ int numRequiredPts;
+ switch (nextVerb) {
+ case SkPath::kMove_Verb:
+ expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
+ p.moveTo(expectedPts[numPoints]);
+ numPoints += 1;
+ lastWasClose = false;
+ haveMoveTo = true;
+ break;
+ case SkPath::kLine_Verb:
+ if (!haveMoveTo) {
+ expectedPts[numPoints++].set(0, 0);
+ expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
+ haveMoveTo = true;
+ }
+ expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
+ p.lineTo(expectedPts[numPoints]);
+ numPoints += 1;
+ lastWasClose = false;
+ break;
+ case SkPath::kQuad_Verb:
+ if (!haveMoveTo) {
+ expectedPts[numPoints++].set(0, 0);
+ expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
+ haveMoveTo = true;
+ }
+ expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
+ expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
+ p.quadTo(expectedPts[numPoints], expectedPts[numPoints + 1]);
+ numPoints += 2;
+ lastWasClose = false;
+ break;
+ case SkPath::kCubic_Verb:
+ if (!haveMoveTo) {
+ expectedPts[numPoints++].set(0, 0);
+ expectedVerbs[numIterVerbs++] = SkPath::kMove_Verb;
+ haveMoveTo = true;
+ }
+ expectedPts[numPoints] = randomPts[(rand.nextU() >> 16) % 25];
+ expectedPts[numPoints + 1] = randomPts[(rand.nextU() >> 16) % 25];
+ expectedPts[numPoints + 2] = randomPts[(rand.nextU() >> 16) % 25];
+ p.cubicTo(expectedPts[numPoints], expectedPts[numPoints + 1],
+ expectedPts[numPoints + 2]);
+ numPoints += 3;
+ lastWasClose = false;
+ break;
+ case SkPath::kClose_Verb:
+ p.close();
+ lastWasClose = true;
+ break;
+ default:;
+ }
+ expectedVerbs[numIterVerbs++] = nextVerb;
+ }
+
+ iter.setPath(p);
+ numVerbs = numIterVerbs;
+ numIterVerbs = 0;
+ int numIterPts = 0;
+ SkPoint lastMoveTo;
+ SkPoint lastPt;
+ lastMoveTo.set(0, 0);
+ lastPt.set(0, 0);
+ while ((nextVerb = iter.next(pts)) != SkPath::kDone_Verb) {
+ REPORTER_ASSERT(reporter, nextVerb == expectedVerbs[numIterVerbs]);
+ numIterVerbs++;
+ switch (nextVerb) {
+ case SkPath::kMove_Verb:
+ REPORTER_ASSERT(reporter, numIterPts < numPoints);
+ REPORTER_ASSERT(reporter, pts[0] == expectedPts[numIterPts]);
+ lastPt = lastMoveTo = pts[0];
+ numIterPts += 1;
+ break;
+ case SkPath::kLine_Verb:
+ REPORTER_ASSERT(reporter, numIterPts < numPoints + 1);
+ REPORTER_ASSERT(reporter, pts[0] == lastPt);
+ REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
+ lastPt = pts[1];
+ numIterPts += 1;
+ break;
+ case SkPath::kQuad_Verb:
+ REPORTER_ASSERT(reporter, numIterPts < numPoints + 2);
+ REPORTER_ASSERT(reporter, pts[0] == lastPt);
+ REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
+ REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
+ lastPt = pts[2];
+ numIterPts += 2;
+ break;
+ case SkPath::kCubic_Verb:
+ REPORTER_ASSERT(reporter, numIterPts < numPoints + 3);
+ REPORTER_ASSERT(reporter, pts[0] == lastPt);
+ REPORTER_ASSERT(reporter, pts[1] == expectedPts[numIterPts]);
+ REPORTER_ASSERT(reporter, pts[2] == expectedPts[numIterPts + 1]);
+ REPORTER_ASSERT(reporter, pts[3] == expectedPts[numIterPts + 2]);
+ lastPt = pts[3];
+ numIterPts += 3;
+ break;
+ case SkPath::kClose_Verb:
+ REPORTER_ASSERT(reporter, pts[0] == lastMoveTo);
+ lastPt = lastMoveTo;
+ break;
+ default:;
+ }
+ }
+ REPORTER_ASSERT(reporter, numIterPts == numPoints);
+ REPORTER_ASSERT(reporter, numIterVerbs == numVerbs);
+ }
+}
+
void TestPath(skiatest::Reporter* reporter);
void TestPath(skiatest::Reporter* reporter) {
{
@@ -186,6 +1027,8 @@ void TestPath(skiatest::Reporter* reporter) {
SkRect bounds, bounds2;
REPORTER_ASSERT(reporter, p.isEmpty());
+ REPORTER_ASSERT(reporter, 0 == p.countPoints());
+ REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
REPORTER_ASSERT(reporter, p.isConvex());
REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType);
REPORTER_ASSERT(reporter, !p.isInverseFillType());
@@ -198,14 +1041,24 @@ void TestPath(skiatest::Reporter* reporter) {
p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1);
check_convex_bounds(reporter, p, bounds);
+ // we have quads or cubics
+ REPORTER_ASSERT(reporter, p.getSegmentMasks() & kCurveSegmentMask);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
p.reset();
+ REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
+ REPORTER_ASSERT(reporter, p.isEmpty());
+
p.addOval(bounds);
check_convex_bounds(reporter, p, bounds);
+ REPORTER_ASSERT(reporter, !p.isEmpty());
p.reset();
p.addRect(bounds);
check_convex_bounds(reporter, p, bounds);
+ // we have only lines
+ REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == p.getSegmentMasks());
+ REPORTER_ASSERT(reporter, !p.isEmpty());
REPORTER_ASSERT(reporter, p != p2);
REPORTER_ASSERT(reporter, !(p == p2));
@@ -222,9 +1075,8 @@ void TestPath(skiatest::Reporter* reporter) {
p.offset(SK_Scalar1*3, SK_Scalar1*4);
REPORTER_ASSERT(reporter, bounds == p.getBounds());
-#if 0 // isRect needs to be implemented
REPORTER_ASSERT(reporter, p.isRect(NULL));
- bounds.setEmpty();
+ bounds2.setEmpty();
REPORTER_ASSERT(reporter, p.isRect(&bounds2));
REPORTER_ASSERT(reporter, bounds == bounds2);
@@ -232,16 +1084,19 @@ void TestPath(skiatest::Reporter* reporter) {
bounds.set(0, 0, SK_Scalar1/2, SK_Scalar1/2);
p.addRect(bounds);
REPORTER_ASSERT(reporter, !p.isRect(NULL));
-#endif
-
- SkPoint pt;
-
- p.moveTo(SK_Scalar1, 0);
- p.getLastPt(&pt);
- REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1);
+ test_isRect(reporter);
+ test_zero_length_paths(reporter);
+ test_direction(reporter);
test_convexity(reporter);
test_convexity2(reporter);
+ test_close(reporter);
+ test_segment_masks(reporter);
+ test_flattening(reporter);
+ test_transform(reporter);
+ test_bounds(reporter);
+ test_iter(reporter);
+ test_raw_iter(reporter);
}
#include "TestClassDef.h"
diff --git a/tests/PointTest.cpp b/tests/PointTest.cpp
new file mode 100644
index 0000000..876a272
--- /dev/null
+++ b/tests/PointTest.cpp
@@ -0,0 +1,46 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+// Unit tests for src/core/SkPoint.cpp and its header
+
+#include "SkPoint.h"
+#include "Test.h"
+
+// Tests that SkPoint::length() and SkPoint::Length() both return
+// approximately expectedLength for this (x,y).
+static void test_length(skiatest::Reporter* reporter, SkScalar x, SkScalar y,
+ SkScalar expectedLength) {
+ SkPoint point;
+ point.set(x, y);
+ SkScalar s1 = point.length();
+ SkScalar s2 = SkPoint::Length(x, y);
+ REPORTER_ASSERT(reporter, s1 == s2);
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(s1, expectedLength));
+}
+
+// Tests SkPoint::Normalize() for this (x,y)
+static void test_Normalize(skiatest::Reporter* reporter,
+ SkScalar x, SkScalar y) {
+ SkPoint point;
+ point.set(x, y);
+ SkScalar oldLength = point.length();
+ SkScalar returned = SkPoint::Normalize(&point);
+ SkScalar newLength = point.length();
+ REPORTER_ASSERT(reporter, returned == oldLength);
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(newLength, SK_Scalar1));
+}
+
+void PointTest(skiatest::Reporter* reporter) {
+ test_length(reporter, SkIntToScalar(3), SkIntToScalar(4), SkIntToScalar(5));
+ test_length(reporter, SkFloatToScalar(0.6), SkFloatToScalar(0.8),
+ SK_Scalar1);
+ test_Normalize(reporter, SkIntToScalar(3), SkIntToScalar(4));
+ test_Normalize(reporter, SkFloatToScalar(0.6), SkFloatToScalar(0.8));
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("Point", PointTestClass, PointTest)
diff --git a/tests/QuickRejectTest.cpp b/tests/QuickRejectTest.cpp
new file mode 100644
index 0000000..8cde327
--- /dev/null
+++ b/tests/QuickRejectTest.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCanvas.h"
+#include "SkDrawLooper.h"
+#include "Test.h"
+
+/*
+ * Subclass of looper that just draws once, with an offset in X.
+ */
+class TestLooper : public SkDrawLooper {
+public:
+ bool fOnce;
+
+ virtual void init(SkCanvas*) SK_OVERRIDE {
+ fOnce = true;
+ }
+
+ virtual bool next(SkCanvas* canvas, SkPaint*) SK_OVERRIDE {
+ if (fOnce) {
+ fOnce = false;
+ canvas->translate(SkIntToScalar(10), 0);
+ return true;
+ }
+ return false;
+ }
+
+ virtual Factory getFactory() SK_OVERRIDE {
+ return NULL;
+ }
+};
+
+static void test_drawBitmap(skiatest::Reporter* reporter) {
+ SkBitmap src;
+ src.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
+ src.allocPixels();
+ src.eraseColor(SK_ColorWHITE);
+
+ SkBitmap dst;
+ dst.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
+ dst.allocPixels();
+ dst.eraseColor(0);
+
+ SkCanvas canvas(dst);
+ SkPaint paint;
+
+ // we are initially transparent
+ REPORTER_ASSERT(reporter, 0 == *dst.getAddr32(5, 5));
+
+ // we see the bitmap drawn
+ canvas.drawBitmap(src, 0, 0, &paint);
+ REPORTER_ASSERT(reporter, 0xFFFFFFFF == *dst.getAddr32(5, 5));
+
+ // reverify we are clear again
+ dst.eraseColor(0);
+ REPORTER_ASSERT(reporter, 0 == *dst.getAddr32(5, 5));
+
+ // if the bitmap is clipped out, we don't draw it
+ canvas.drawBitmap(src, SkIntToScalar(-10), 0, &paint);
+ REPORTER_ASSERT(reporter, 0 == *dst.getAddr32(5, 5));
+
+ // now install our looper, which will draw, since it internally translates
+ // to the left. The test is to ensure that canvas' quickReject machinary
+ // allows us through, even though sans-looper we would look like we should
+ // be clipped out.
+ paint.setLooper(new TestLooper)->unref();
+ canvas.drawBitmap(src, SkIntToScalar(-10), 0, &paint);
+ REPORTER_ASSERT(reporter, 0xFFFFFFFF == *dst.getAddr32(5, 5));
+}
+
+static void test(skiatest::Reporter* reporter) {
+ test_drawBitmap(reporter);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("QuickReject", QuickRejectClass, test)
diff --git a/tests/ReadPixelsTest.cpp b/tests/ReadPixelsTest.cpp
new file mode 100644
index 0000000..b531e92
--- /dev/null
+++ b/tests/ReadPixelsTest.cpp
@@ -0,0 +1,391 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#include "SkCanvas.h"
+#include "SkRegion.h"
+#include "SkGpuDevice.h"
+
+
+static const int DEV_W = 100, DEV_H = 100;
+static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H);
+static const SkRect DEV_RECT_S = SkRect::MakeWH(DEV_W * SK_Scalar1,
+ DEV_H * SK_Scalar1);
+
+namespace {
+SkPMColor getCanvasColor(int x, int y) {
+ SkASSERT(x >= 0 && x < DEV_W);
+ SkASSERT(y >= 0 && y < DEV_H);
+
+ U8CPU r = x;
+ U8CPU g = y;
+ U8CPU b = 0xc;
+
+ U8CPU a = 0xff;
+ switch ((x+y) % 5) {
+ case 0:
+ a = 0xff;
+ break;
+ case 1:
+ a = 0x80;
+ break;
+ case 2:
+ a = 0xCC;
+ break;
+ case 4:
+ a = 0x01;
+ break;
+ case 3:
+ a = 0x00;
+ break;
+ }
+ return SkPremultiplyARGBInline(a, r, g, b);
+}
+
+SkPMColor getBitmapColor(int x, int y, int w, int h) {
+ int n = y * w + x;
+
+ U8CPU b = n & 0xff;
+ U8CPU g = (n >> 8) & 0xff;
+ U8CPU r = (n >> 16) & 0xff;
+ return SkPackARGB32(0xff, r, g , b);
+}
+
+SkPMColor convertConfig8888ToPMColor(SkCanvas::Config8888 config8888,
+ uint32_t color,
+ bool* premul) {
+ const uint8_t* c = reinterpret_cast<uint8_t*>(&color);
+ U8CPU a,r,g,b;
+ *premul = false;
+ switch (config8888) {
+ case SkCanvas::kNative_Premul_Config8888:
+ return color;
+ case SkCanvas::kNative_Unpremul_Config8888:
+ *premul = true;
+ a = SkGetPackedA32(color);
+ r = SkGetPackedR32(color);
+ g = SkGetPackedG32(color);
+ b = SkGetPackedB32(color);
+ break;
+ case SkCanvas::kBGRA_Unpremul_Config8888:
+ *premul = true; // fallthru
+ case SkCanvas::kBGRA_Premul_Config8888:
+ a = static_cast<U8CPU>(c[3]);
+ r = static_cast<U8CPU>(c[2]);
+ g = static_cast<U8CPU>(c[1]);
+ b = static_cast<U8CPU>(c[0]);
+ break;
+ case SkCanvas::kRGBA_Unpremul_Config8888:
+ *premul = true; // fallthru
+ case SkCanvas::kRGBA_Premul_Config8888:
+ a = static_cast<U8CPU>(c[3]);
+ r = static_cast<U8CPU>(c[0]);
+ g = static_cast<U8CPU>(c[1]);
+ b = static_cast<U8CPU>(c[2]);
+ break;
+ }
+ if (*premul) {
+ r = SkMulDiv255Ceiling(r, a);
+ g = SkMulDiv255Ceiling(g, a);
+ b = SkMulDiv255Ceiling(b, a);
+ }
+ return SkPackARGB32(a, r, g, b);
+}
+
+void fillCanvas(SkCanvas* canvas) {
+ static SkBitmap bmp;
+ if (bmp.isNull()) {
+ bmp.setConfig(SkBitmap::kARGB_8888_Config, DEV_W, DEV_H);
+ bool alloc = bmp.allocPixels();
+ SkASSERT(alloc);
+ SkAutoLockPixels alp(bmp);
+ intptr_t pixels = reinterpret_cast<intptr_t>(bmp.getPixels());
+ for (int y = 0; y < DEV_H; ++y) {
+ for (int x = 0; x < DEV_W; ++x) {
+ SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bmp.rowBytes() + x * bmp.bytesPerPixel());
+ *pixel = getCanvasColor(x, y);
+ }
+ }
+ }
+ canvas->save();
+ canvas->setMatrix(SkMatrix::I());
+ canvas->clipRect(DEV_RECT_S, SkRegion::kReplace_Op);
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ canvas->drawBitmap(bmp, 0, 0, &paint);
+ canvas->restore();
+}
+
+void fillBitmap(SkBitmap* bitmap) {
+ SkASSERT(bitmap->lockPixelsAreWritable());
+ SkAutoLockPixels alp(*bitmap);
+ int w = bitmap->width();
+ int h = bitmap->height();
+ intptr_t pixels = reinterpret_cast<intptr_t>(bitmap->getPixels());
+ for (int y = 0; y < h; ++y) {
+ for (int x = 0; x < w; ++x) {
+ SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel());
+ *pixel = getBitmapColor(x, y, w, h);
+ }
+ }
+}
+
+bool checkPixel(SkPMColor a, SkPMColor b, bool didPremulConversion) {
+ if (!didPremulConversion) {
+ return a == b;
+ }
+ int32_t aA = static_cast<int32_t>(SkGetPackedA32(a));
+ int32_t aR = static_cast<int32_t>(SkGetPackedR32(a));
+ int32_t aG = static_cast<int32_t>(SkGetPackedG32(a));
+ int32_t aB = SkGetPackedB32(a);
+
+ int32_t bA = static_cast<int32_t>(SkGetPackedA32(b));
+ int32_t bR = static_cast<int32_t>(SkGetPackedR32(b));
+ int32_t bG = static_cast<int32_t>(SkGetPackedG32(b));
+ int32_t bB = static_cast<int32_t>(SkGetPackedB32(b));
+
+ return aA == bA &&
+ SkAbs32(aR - bR) <= 1 &&
+ SkAbs32(aG - bG) <= 1 &&
+ SkAbs32(aB - bB) <= 1;
+}
+
+// checks the bitmap contains correct pixels after the readPixels
+// if the bitmap was prefilled with pixels it checks that these weren't
+// overwritten in the area outside the readPixels.
+bool checkRead(skiatest::Reporter* reporter,
+ const SkBitmap& bitmap,
+ int x, int y,
+ bool checkCanvasPixels,
+ bool checkBitmapPixels,
+ SkCanvas::Config8888 config8888) {
+ SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
+ SkASSERT(!bitmap.isNull());
+ SkASSERT(checkCanvasPixels || checkBitmapPixels);
+
+ int bw = bitmap.width();
+ int bh = bitmap.height();
+
+ SkIRect srcRect = SkIRect::MakeXYWH(x, y, bw, bh);
+ SkIRect clippedSrcRect = DEV_RECT;
+ if (!clippedSrcRect.intersect(srcRect)) {
+ clippedSrcRect.setEmpty();
+ }
+ bool failed = false;
+ SkAutoLockPixels alp(bitmap);
+ intptr_t pixels = reinterpret_cast<intptr_t>(bitmap.getPixels());
+ for (int by = 0; by < bh; ++by) {
+ for (int bx = 0; bx < bw; ++bx) {
+ int devx = bx + srcRect.fLeft;
+ int devy = by + srcRect.fTop;
+
+ uint32_t pixel = *reinterpret_cast<SkPMColor*>(pixels + by * bitmap.rowBytes() + bx * bitmap.bytesPerPixel());
+
+ if (clippedSrcRect.contains(devx, devy)) {
+ if (checkCanvasPixels) {
+ SkPMColor canvasPixel = getCanvasColor(devx, devy);
+ bool didPremul;
+ SkPMColor pmPixel = convertConfig8888ToPMColor(config8888, pixel, &didPremul);
+ bool check;
+ REPORTER_ASSERT(reporter, check = checkPixel(pmPixel, canvasPixel, didPremul));
+ if (!check) {
+ failed = true;
+ }
+ }
+ } else if (checkBitmapPixels) {
+ REPORTER_ASSERT(reporter, getBitmapColor(bx, by, bw, bh) == pixel);
+ if (getBitmapColor(bx, by, bw, bh) != pixel) {
+ failed = true;
+ }
+ }
+ }
+ }
+ return !failed;
+}
+
+enum BitmapInit {
+ kFirstBitmapInit = 0,
+
+ kNoPixels_BitmapInit = kFirstBitmapInit,
+ kTight_BitmapInit,
+ kRowBytes_BitmapInit,
+
+ kBitmapInitCnt
+};
+
+BitmapInit nextBMI(BitmapInit bmi) {
+ int x = bmi;
+ return static_cast<BitmapInit>(++x);
+}
+
+
+void init_bitmap(SkBitmap* bitmap, const SkIRect& rect, BitmapInit init) {
+ int w = rect.width();
+ int h = rect.height();
+ int rowBytes = 0;
+ bool alloc = true;
+ switch (init) {
+ case kNoPixels_BitmapInit:
+ alloc = false;
+ case kTight_BitmapInit:
+ break;
+ case kRowBytes_BitmapInit:
+ rowBytes = w * sizeof(SkPMColor) + 16 * sizeof(SkPMColor);
+ break;
+ default:
+ SkASSERT(0);
+ break;
+ }
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config, w, h, rowBytes);
+ if (alloc) {
+ bitmap->allocPixels();
+ }
+}
+
+void ReadPixelsTest(skiatest::Reporter* reporter, GrContext* context) {
+ SkCanvas canvas;
+
+ const SkIRect testRects[] = {
+ // entire thing
+ DEV_RECT,
+ // larger on all sides
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H + 10),
+ // fully contained
+ SkIRect::MakeLTRB(DEV_W / 4, DEV_H / 4, 3 * DEV_W / 4, 3 * DEV_H / 4),
+ // outside top left
+ SkIRect::MakeLTRB(-10, -10, -1, -1),
+ // touching top left corner
+ SkIRect::MakeLTRB(-10, -10, 0, 0),
+ // overlapping top left corner
+ SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H / 4),
+ // overlapping top left and top right corners
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H / 4),
+ // touching entire top edge
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, 0),
+ // overlapping top right corner
+ SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H / 4),
+ // contained in x, overlapping top edge
+ SkIRect::MakeLTRB(DEV_W / 4, -10, 3 * DEV_W / 4, DEV_H / 4),
+ // outside top right corner
+ SkIRect::MakeLTRB(DEV_W + 1, -10, DEV_W + 10, -1),
+ // touching top right corner
+ SkIRect::MakeLTRB(DEV_W, -10, DEV_W + 10, 0),
+ // overlapping top left and bottom left corners
+ SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H + 10),
+ // touching entire left edge
+ SkIRect::MakeLTRB(-10, -10, 0, DEV_H + 10),
+ // overlapping bottom left corner
+ SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W / 4, DEV_H + 10),
+ // contained in y, overlapping left edge
+ SkIRect::MakeLTRB(-10, DEV_H / 4, DEV_W / 4, 3 * DEV_H / 4),
+ // outside bottom left corner
+ SkIRect::MakeLTRB(-10, DEV_H + 1, -1, DEV_H + 10),
+ // touching bottom left corner
+ SkIRect::MakeLTRB(-10, DEV_H, 0, DEV_H + 10),
+ // overlapping bottom left and bottom right corners
+ SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
+ // touching entire left edge
+ SkIRect::MakeLTRB(0, DEV_H, DEV_W, DEV_H + 10),
+ // overlapping bottom right corner
+ SkIRect::MakeLTRB(3 * DEV_W / 4, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
+ // overlapping top right and bottom right corners
+ SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10),
+ };
+
+ for (int dtype = 1; dtype < 2; ++dtype) {
+
+ if (0 == dtype) {
+ canvas.setDevice(new SkDevice(SkBitmap::kARGB_8888_Config,
+ DEV_W,
+ DEV_H,
+ false))->unref();
+ } else {
+#if SK_SCALAR_IS_FIXED
+ // GPU device known not to work in the fixed pt build.
+ continue;
+#endif
+ canvas.setDevice(new SkGpuDevice(context,
+ SkBitmap::kARGB_8888_Config,
+ DEV_W,
+ DEV_H))->unref();
+ }
+ fillCanvas(&canvas);
+
+ static const SkCanvas::Config8888 gReadConfigs[] = {
+ SkCanvas::kNative_Premul_Config8888,
+ SkCanvas::kNative_Unpremul_Config8888,
+/**
+ * There is a bug in Ganesh (http://code.google.com/p/skia/issues/detail?id=438)
+ * that causes the readback of pixels from BGRA canvas to an RGBA bitmap to
+ * fail. This should be removed as soon as the issue above is resolved.
+ */
+#if !defined(SK_BUILD_FOR_ANDROID)
+ SkCanvas::kBGRA_Premul_Config8888,
+ SkCanvas::kBGRA_Unpremul_Config8888,
+#endif
+ SkCanvas::kRGBA_Premul_Config8888,
+ SkCanvas::kRGBA_Unpremul_Config8888,
+ };
+ for (size_t rect = 0; rect < SK_ARRAY_COUNT(testRects); ++rect) {
+ const SkIRect& srcRect = testRects[rect];
+ for (BitmapInit bmi = kFirstBitmapInit;
+ bmi < kBitmapInitCnt;
+ bmi = nextBMI(bmi)) {
+ for (size_t c = 0; c < SK_ARRAY_COUNT(gReadConfigs); ++c) {
+ SkCanvas::Config8888 config8888 = gReadConfigs[c];
+ SkBitmap bmp;
+ init_bitmap(&bmp, srcRect, bmi);
+
+ // if the bitmap has pixels allocated before the readPixels,
+ // note that and fill them with pattern
+ bool startsWithPixels = !bmp.isNull();
+ if (startsWithPixels) {
+ fillBitmap(&bmp);
+ }
+
+ bool success =
+ canvas.readPixels(&bmp, srcRect.fLeft,
+ srcRect.fTop, config8888);
+
+ // we expect to succeed when the read isn't fully clipped
+ // out.
+ bool expectSuccess = SkIRect::Intersects(srcRect, DEV_RECT);
+ // determine whether we expected the read to succeed.
+ REPORTER_ASSERT(reporter, success == expectSuccess);
+
+ if (success || startsWithPixels) {
+ checkRead(reporter, bmp, srcRect.fLeft, srcRect.fTop,
+ success, startsWithPixels, config8888);
+ } else {
+ // if we had no pixels beforehand and the readPixels
+ // failed then our bitmap should still not have pixels
+ REPORTER_ASSERT(reporter, bmp.isNull());
+ }
+ }
+ // check the old webkit version of readPixels that clips the
+ // bitmap size
+ SkBitmap wkbmp;
+ bool success = canvas.readPixels(srcRect, &wkbmp);
+ SkIRect clippedRect = DEV_RECT;
+ if (clippedRect.intersect(srcRect)) {
+ REPORTER_ASSERT(reporter, success);
+ checkRead(reporter, wkbmp, clippedRect.fLeft,
+ clippedRect.fTop, true, false,
+ SkCanvas::kNative_Premul_Config8888);
+ } else {
+ REPORTER_ASSERT(reporter, !success);
+ }
+ }
+ }
+ }
+}
+}
+
+#include "TestClassDef.h"
+DEFINE_GPUTESTCLASS("ReadPixels", ReadPixelsTestClass, ReadPixelsTest)
+
diff --git a/tests/Reader32Test.cpp b/tests/Reader32Test.cpp
index cad2d33..13f2fc4 100644
--- a/tests/Reader32Test.cpp
+++ b/tests/Reader32Test.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkReader32.h"
#include "Test.h"
diff --git a/tests/RefDictTest.cpp b/tests/RefDictTest.cpp
index f52541b..83d1aef 100644
--- a/tests/RefDictTest.cpp
+++ b/tests/RefDictTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkRefDict.h"
diff --git a/tests/RegionTest.cpp b/tests/RegionTest.cpp
index ee34d8b..a1bf699 100644
--- a/tests/RegionTest.cpp
+++ b/tests/RegionTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkRegion.h"
#include "SkRandom.h"
diff --git a/tests/ScalarTest.cpp b/tests/ScalarTest.cpp
new file mode 100644
index 0000000..d2c05ab
--- /dev/null
+++ b/tests/ScalarTest.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#include "SkFloatingPoint.h"
+#include "SkMath.h"
+#include "SkPoint.h"
+#include "SkRandom.h"
+
+#ifdef SK_CAN_USE_FLOAT
+
+static bool isFinite_int(float x) {
+ uint32_t bits = SkFloat2Bits(x); // need unsigned for our shifts
+ int exponent = bits << 1 >> 24;
+ return exponent != 0xFF;
+}
+
+static bool isFinite_float(float x) {
+ return sk_float_isfinite(x);
+}
+
+static bool isFinite_mulzero(float x) {
+ float y = x * 0;
+ return y == y;
+}
+
+// return true if the float is finite
+typedef bool (*IsFiniteProc1)(float);
+
+static bool isFinite2_and(float x, float y, IsFiniteProc1 proc) {
+ return proc(x) && proc(y);
+}
+
+static bool isFinite2_mulzeroadd(float x, float y, IsFiniteProc1 proc) {
+ return proc(x * 0 + y * 0);
+}
+
+// return true if both floats are finite
+typedef bool (*IsFiniteProc2)(float, float, IsFiniteProc1);
+
+#endif
+
+enum FloatClass {
+ kFinite,
+ kInfinite,
+ kNaN
+};
+
+static void test_floatclass(skiatest::Reporter* reporter, float value, FloatClass fc) {
+ // our sk_float_is... function may return int instead of bool,
+ // hence the double ! to turn it into a bool
+ REPORTER_ASSERT(reporter, !!sk_float_isfinite(value) == (fc == kFinite));
+ REPORTER_ASSERT(reporter, !!sk_float_isinf(value) == (fc == kInfinite));
+ REPORTER_ASSERT(reporter, !!sk_float_isnan(value) == (fc == kNaN));
+}
+
+static void test_isfinite(skiatest::Reporter* reporter) {
+#ifdef SK_CAN_USE_FLOAT
+ struct Rec {
+ float fValue;
+ bool fIsFinite;
+ };
+
+ float max = 3.402823466e+38f;
+ float inf = max * max;
+ float nan = inf * 0;
+
+ test_floatclass(reporter, 0, kFinite);
+ test_floatclass(reporter, max, kFinite);
+ test_floatclass(reporter, -max, kFinite);
+ test_floatclass(reporter, inf, kInfinite);
+ test_floatclass(reporter, -inf, kInfinite);
+ test_floatclass(reporter, nan, kNaN);
+ test_floatclass(reporter, -nan, kNaN);
+
+ const Rec data[] = {
+ { 0, true },
+ { 1, true },
+ { -1, true },
+ { max * 0.75, true },
+ { max, true },
+ { -max * 0.75, true },
+ { -max, true },
+ { inf, false },
+ { -inf, false },
+ { nan, false },
+ };
+
+ const IsFiniteProc1 gProc1[] = {
+ isFinite_int,
+ isFinite_float,
+ isFinite_mulzero
+ };
+ const IsFiniteProc2 gProc2[] = {
+ isFinite2_and,
+ isFinite2_mulzeroadd
+ };
+
+ size_t i, n = SK_ARRAY_COUNT(data);
+
+ for (i = 0; i < n; ++i) {
+ for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) {
+ const Rec& rec = data[i];
+ bool finite = gProc1[k](rec.fValue);
+ REPORTER_ASSERT(reporter, rec.fIsFinite == finite);
+ }
+ }
+
+ for (i = 0; i < n; ++i) {
+ const Rec& rec0 = data[i];
+ for (size_t j = 0; j < n; ++j) {
+ const Rec& rec1 = data[j];
+ for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) {
+ IsFiniteProc1 proc1 = gProc1[k];
+
+ for (size_t m = 0; m < SK_ARRAY_COUNT(gProc2); ++m) {
+ bool finite = gProc2[m](rec0.fValue, rec1.fValue, proc1);
+ bool finite2 = rec0.fIsFinite && rec1.fIsFinite;
+ REPORTER_ASSERT(reporter, finite2 == finite);
+ }
+ }
+ }
+ }
+#endif
+}
+
+static void TestScalar(skiatest::Reporter* reporter) {
+ test_isfinite(reporter);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("Scalar", TestScalarClass, TestScalar)
+
diff --git a/tests/ShaderOpacityTest.cpp b/tests/ShaderOpacityTest.cpp
new file mode 100644
index 0000000..a8177ee
--- /dev/null
+++ b/tests/ShaderOpacityTest.cpp
@@ -0,0 +1,119 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "Test.h"
+#include "SkShader.h"
+#include "SkGradientShader.h"
+#include "SkColorShader.h"
+
+static void test_bitmap(skiatest::Reporter* reporter) {
+ SkBitmap bmp;
+ bmp.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
+
+ // test 1: bitmap without pixel data
+ SkShader* shader = SkShader::CreateBitmapShader(bmp,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ REPORTER_ASSERT(reporter, shader);
+ REPORTER_ASSERT(reporter, !shader->isOpaque());
+ shader->unref();
+
+ // From this point on, we have pixels
+ bmp.allocPixels();
+
+ // test 2: not opaque by default
+ shader = SkShader::CreateBitmapShader(bmp,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ REPORTER_ASSERT(reporter, shader);
+ REPORTER_ASSERT(reporter, !shader->isOpaque());
+ shader->unref();
+
+ // test 3: explicitly opaque
+ bmp.setIsOpaque(true);
+ shader = SkShader::CreateBitmapShader(bmp,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ REPORTER_ASSERT(reporter, shader);
+ REPORTER_ASSERT(reporter, shader->isOpaque());
+ shader->unref();
+
+ // test 4: explicitly not opaque
+ bmp.setIsOpaque(false);
+ shader = SkShader::CreateBitmapShader(bmp,
+ SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ REPORTER_ASSERT(reporter, shader);
+ REPORTER_ASSERT(reporter, !shader->isOpaque());
+ shader->unref();
+
+}
+
+static void test_gradient(skiatest::Reporter* reporter)
+{
+ SkPoint pts[2];
+ pts[0].iset(0, 0);
+ pts[1].iset(1, 0);
+ SkColor colors[2];
+ SkScalar pos[2] = {SkIntToScalar(0), SkIntToScalar(1)};
+ int count = 2;
+ SkShader::TileMode mode = SkShader::kClamp_TileMode;
+
+ // test 1: all opaque
+ colors[0] = SkColorSetARGB(0xFF, 0, 0, 0);
+ colors[1] = SkColorSetARGB(0xFF, 0, 0, 0);
+ SkShader* grad = SkGradientShader::CreateLinear(pts, colors, pos, count,
+ mode);
+ REPORTER_ASSERT(reporter, grad);
+ REPORTER_ASSERT(reporter, grad->isOpaque());
+ grad->unref();
+
+ // test 2: all 0 alpha
+ colors[0] = SkColorSetARGB(0, 0, 0, 0);
+ colors[1] = SkColorSetARGB(0, 0, 0, 0);
+ grad = SkGradientShader::CreateLinear(pts, colors, pos, count, mode);
+ REPORTER_ASSERT(reporter, grad);
+ REPORTER_ASSERT(reporter, !grad->isOpaque());
+ grad->unref();
+
+ // test 3: one opaque, one transparent
+ colors[0] = SkColorSetARGB(0xFF, 0, 0, 0);
+ colors[1] = SkColorSetARGB(0x40, 0, 0, 0);
+ grad = SkGradientShader::CreateLinear(pts, colors, pos, count, mode);
+ REPORTER_ASSERT(reporter, grad);
+ REPORTER_ASSERT(reporter, !grad->isOpaque());
+ grad->unref();
+
+ // test 4: test 3, swapped
+ colors[0] = SkColorSetARGB(0x40, 0, 0, 0);
+ colors[1] = SkColorSetARGB(0xFF, 0, 0, 0);
+ grad = SkGradientShader::CreateLinear(pts, colors, pos, count, mode);
+ REPORTER_ASSERT(reporter, grad);
+ REPORTER_ASSERT(reporter, !grad->isOpaque());
+ grad->unref();
+}
+
+static void test_color(skiatest::Reporter* reporter)
+{
+ SkColorShader colorShader1(SkColorSetARGB(0,0,0,0));
+ REPORTER_ASSERT(reporter, !colorShader1.isOpaque());
+ SkColorShader colorShader2(SkColorSetARGB(0xFF,0,0,0));
+ REPORTER_ASSERT(reporter, colorShader2.isOpaque());
+ SkColorShader colorShader3(SkColorSetARGB(0x7F,0,0,0));
+ REPORTER_ASSERT(reporter, !colorShader3.isOpaque());
+
+ // with inherrited color, shader must declare itself as opaque,
+ // since lack of opacity will depend solely on the paint
+ SkColorShader colorShader4;
+ REPORTER_ASSERT(reporter, colorShader4.isOpaque());
+}
+
+static void test_shader_opacity(skiatest::Reporter* reporter)
+{
+ test_gradient(reporter);
+ test_color(reporter);
+ test_bitmap(reporter);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("ShaderOpacity", ShaderOpacityTestClass, test_shader_opacity)
diff --git a/tests/Sk64Test.cpp b/tests/Sk64Test.cpp
index 9fb49eb..64eef75 100644
--- a/tests/Sk64Test.cpp
+++ b/tests/Sk64Test.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkRandom.h"
#include <math.h>
diff --git a/tests/SortTest.cpp b/tests/SortTest.cpp
index 2ca5553..9b4642f 100644
--- a/tests/SortTest.cpp
+++ b/tests/SortTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkRandom.h"
#include "SkTSearch.h"
diff --git a/tests/SrcOverTest.cpp b/tests/SrcOverTest.cpp
index e95485b..d1e65a9 100644
--- a/tests/SrcOverTest.cpp
+++ b/tests/SrcOverTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkColorPriv.h"
#include "SkXfermode.h"
diff --git a/tests/StreamTest.cpp b/tests/StreamTest.cpp
index e62f2ed..85b1b2e 100644
--- a/tests/StreamTest.cpp
+++ b/tests/StreamTest.cpp
@@ -1,6 +1,14 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkRandom.h"
#include "SkStream.h"
+#include "SkData.h"
#define MAX_SIZE (256 * 1024)
@@ -81,13 +89,51 @@ static void TestWStream(skiatest::Reporter* reporter) {
for (i = 0; i < 100; i++) {
REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0);
}
- REPORTER_ASSERT(reporter, memcmp(dst, ds.getStream(), 100*26) == 0);
+
+ {
+ SkData* data = ds.copyToData();
+ REPORTER_ASSERT(reporter, 100 * 26 == data->size());
+ REPORTER_ASSERT(reporter, memcmp(dst, data->data(), data->size()) == 0);
+ data->unref();
+ }
delete[] dst;
}
+static void TestPackedUInt(skiatest::Reporter* reporter) {
+ // we know that packeduint tries to write 1, 2 or 4 bytes for the length,
+ // so we test values around each of those transitions (and a few others)
+ const size_t sizes[] = {
+ 0, 1, 2, 0xFC, 0xFD, 0xFE, 0xFF, 0x100, 0x101, 32767, 32768, 32769,
+ 0xFFFD, 0xFFFE, 0xFFFF, 0x10000, 0x10001,
+ 0xFFFFFD, 0xFFFFFE, 0xFFFFFF, 0x1000000, 0x1000001,
+ 0x7FFFFFFE, 0x7FFFFFFF, 0x80000000, 0x80000001, 0xFFFFFFFE, 0xFFFFFFFF
+ };
+
+
+ size_t i;
+ char buffer[sizeof(sizes) * 4];
+
+ SkMemoryWStream wstream(buffer, sizeof(buffer));
+ for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
+ bool success = wstream.writePackedUInt(sizes[i]);
+ REPORTER_ASSERT(reporter, success);
+ }
+ wstream.flush();
+
+ SkMemoryStream rstream(buffer, sizeof(buffer));
+ for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
+ size_t n = rstream.readPackedUInt();
+ if (sizes[i] != n) {
+ SkDebugf("-- %d: sizes:%x n:%x\n", i, sizes[i], n);
+ }
+ REPORTER_ASSERT(reporter, sizes[i] == n);
+ }
+}
+
static void TestStreams(skiatest::Reporter* reporter) {
TestRStream(reporter);
TestWStream(reporter);
+ TestPackedUInt(reporter);
}
#include "TestClassDef.h"
diff --git a/tests/StringTest.cpp b/tests/StringTest.cpp
index 270ccfd..52a038d 100644
--- a/tests/StringTest.cpp
+++ b/tests/StringTest.cpp
@@ -1,5 +1,38 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkString.h"
+#include <stdarg.h>
+
+
+// Windows vsnprintf doesn't 0-terminate safely), but is so far
+// encapsulated in SkString that we can't test it directly.
+
+#ifdef SK_BUILD_FOR_WIN
+ #define VSNPRINTF(buffer, size, format, args) \
+ vsnprintf_s(buffer, size, _TRUNCATE, format, args)
+#else
+ #define VSNPRINTF vsnprintf
+#endif
+
+#define ARGS_TO_BUFFER(format, buffer, size) \
+ do { \
+ va_list args; \
+ va_start(args, format); \
+ VSNPRINTF(buffer, size, format, args); \
+ va_end(args); \
+ } while (0)
+
+void printfAnalog(char* buffer, int size, const char format[], ...) {
+ ARGS_TO_BUFFER(format, buffer, size);
+}
+
+
static void TestString(skiatest::Reporter* reporter) {
SkString a;
@@ -74,8 +107,13 @@ static void TestString(skiatest::Reporter* reporter) {
{ -SK_Scalar1, "-1" },
{ SK_Scalar1/2, "0.5" },
#ifdef SK_SCALAR_IS_FLOAT
+ #ifdef SK_BUILD_FOR_WIN
+ { 3.4028234e38f, "3.4028235e+038" },
+ { -3.4028234e38f, "-3.4028235e+038" },
+ #else
{ 3.4028234e38f, "3.4028235e+38" },
{ -3.4028234e38f, "-3.4028235e+38" },
+ #endif
#endif
};
for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
@@ -85,6 +123,19 @@ static void TestString(skiatest::Reporter* reporter) {
// SkDebugf(" received <%s> expected <%s>\n", a.c_str(), gRec[i].fString);
REPORTER_ASSERT(reporter, a.equals(gRec[i].fString));
}
+
+ REPORTER_ASSERT(reporter, SkStringPrintf("%i", 0).equals("0"));
+
+ char buffer [40];
+ memset(buffer, 'a', 40);
+ REPORTER_ASSERT(reporter, buffer[18] == 'a');
+ REPORTER_ASSERT(reporter, buffer[19] == 'a');
+ REPORTER_ASSERT(reporter, buffer[20] == 'a');
+ printfAnalog(buffer, 20, "%30d", 0);
+ REPORTER_ASSERT(reporter, buffer[18] == ' ');
+ REPORTER_ASSERT(reporter, buffer[19] == 0);
+ REPORTER_ASSERT(reporter, buffer[20] == 'a');
+
}
#include "TestClassDef.h"
diff --git a/tests/Test.cpp b/tests/Test.cpp
index 2bcd3e0..1c3b691 100644
--- a/tests/Test.cpp
+++ b/tests/Test.cpp
@@ -1,5 +1,16 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
+#include "GrContext.h"
+#include "SkNativeGLContext.h"
+#include "SkTLazy.h"
+
using namespace skiatest;
Reporter::Reporter() {
@@ -63,3 +74,24 @@ bool Test::run() {
return fReporter->getCurrSuccess();
}
+///////////////////////////////////////////////////////////////////////////////
+
+
+GrContext* GpuTest::GetContext() {
+ // preserve this order, we want gGrContext destroyed after gEGLContext
+ static SkTLazy<SkNativeGLContext> gGLContext;
+ static SkAutoTUnref<GrContext> gGrContext;
+
+ if (NULL == gGrContext.get()) {
+ gGLContext.init();
+ if (gGLContext.get()->init(800, 600)) {
+ GrPlatform3DContext ctx = reinterpret_cast<GrPlatform3DContext>(gGLContext.get()->gl());
+ gGrContext.reset(GrContext::Create(kOpenGL_Shaders_GrEngine, ctx));
+ }
+ }
+ if (gGLContext.get()) {
+ gGLContext.get()->makeCurrent();
+ }
+ return gGrContext.get();
+}
+
diff --git a/tests/Test.h b/tests/Test.h
index de51801..8728040 100644
--- a/tests/Test.h
+++ b/tests/Test.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef skiatest_Test_DEFINED
#define skiatest_Test_DEFINED
@@ -5,6 +12,9 @@
#include "SkString.h"
#include "SkTRegistry.h"
+class GrContext;
+class SkGLContext;
+
namespace skiatest {
class Test;
@@ -87,6 +97,17 @@ namespace skiatest {
SkString fName;
};
+ class GpuTest : public Test{
+ public:
+ GpuTest() : Test() {
+ fContext = GetContext();
+ }
+ protected:
+ GrContext* fContext;
+ private:
+ static GrContext* GetContext();
+ };
+
typedef SkTRegistry<Test*, void*> TestRegistry;
}
diff --git a/tests/TestClassDef.h b/tests/TestClassDef.h
index 0773f5a..ffef2a1 100644
--- a/tests/TestClassDef.h
+++ b/tests/TestClassDef.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
/* This file is meant to be included by .cpp files, so it can spew out a
customized class + global definition.
@@ -22,3 +29,18 @@
static TestRegistry gReg(classname::Factory); \
}
+#define DEFINE_GPUTESTCLASS(uiname, classname, function) \
+ namespace skiatest { \
+ class classname : public GpuTest { \
+ public: \
+ static Test* Factory(void*) { return SkNEW(classname); } \
+ protected: \
+ virtual void onGetName(SkString* name) { name->set(uiname); } \
+ virtual void onRun(Reporter* reporter) { \
+ if (fContext) { \
+ function(reporter, fContext); \
+ } \
+ } \
+ }; \
+ static TestRegistry gReg(classname::Factory); \
+ }
diff --git a/tests/TestSize.cpp b/tests/TestSize.cpp
index 9e0aaaa..97a6668 100644
--- a/tests/TestSize.cpp
+++ b/tests/TestSize.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkSize.h"
diff --git a/tests/ToUnicode.cpp b/tests/ToUnicode.cpp
new file mode 100644
index 0000000..c0a945a
--- /dev/null
+++ b/tests/ToUnicode.cpp
@@ -0,0 +1,133 @@
+
+/*
+ * Copyright 2010 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include <string>
+
+#include "Test.h"
+#include "SkData.h"
+#include "SkPDFTypes.h"
+#include "SkPDFFont.h"
+#include "SkStream.h"
+
+static bool stream_equals(const SkDynamicMemoryWStream& stream, size_t offset,
+ const char* buffer, size_t len) {
+ SkAutoDataUnref data(stream.copyToData());
+ if (offset + len > data.size()) {
+ return false;
+ }
+ if (len != strlen(buffer)) {
+ return false;
+ }
+ return memcmp(data.bytes() + offset, buffer, len) == 0;
+}
+
+void append_cmap_sections(const SkTDArray<SkUnichar>& glyphToUnicode,
+ const SkPDFGlyphSet* subset,
+ SkDynamicMemoryWStream* cmap);
+
+static void TestToUnicode(skiatest::Reporter* reporter) {
+ SkTDArray<SkUnichar> glyphToUnicode;
+ SkTDArray<uint16_t> glyphsInSubset;
+ SkPDFGlyphSet subset;
+
+ glyphToUnicode.push(0); // 0
+ glyphToUnicode.push(0); // 1
+ glyphToUnicode.push(0); // 2
+ glyphsInSubset.push(3);
+ glyphToUnicode.push(0x20); // 3
+ glyphsInSubset.push(4);
+ glyphToUnicode.push(0x25); // 4
+ glyphsInSubset.push(5);
+ glyphToUnicode.push(0x27); // 5
+ glyphsInSubset.push(6);
+ glyphToUnicode.push(0x28); // 6
+ glyphsInSubset.push(7);
+ glyphToUnicode.push(0x29); // 7
+ glyphsInSubset.push(8);
+ glyphToUnicode.push(0x2F); // 8
+ glyphsInSubset.push(9);
+ glyphToUnicode.push(0x33); // 9
+ glyphToUnicode.push(0); // 10
+ glyphsInSubset.push(11);
+ glyphToUnicode.push(0x35); // 11
+ glyphsInSubset.push(12);
+ glyphToUnicode.push(0x36); // 12
+ for (uint16_t i = 13; i < 0xFE; ++i) {
+ glyphToUnicode.push(0); // Zero from index 0x9 to 0xFD
+ }
+ glyphsInSubset.push(0xFE);
+ glyphToUnicode.push(0x1010);
+ glyphsInSubset.push(0xFF);
+ glyphToUnicode.push(0x1011);
+ glyphsInSubset.push(0x100);
+ glyphToUnicode.push(0x1012);
+ glyphsInSubset.push(0x101);
+ glyphToUnicode.push(0x1013);
+
+ SkDynamicMemoryWStream buffer;
+ subset.set(glyphsInSubset.begin(), glyphsInSubset.count());
+ append_cmap_sections(glyphToUnicode, &subset, &buffer);
+
+ char expectedResult[] =
+"4 beginbfchar\n\
+<0003> <0020>\n\
+<0004> <0025>\n\
+<0008> <002F>\n\
+<0009> <0033>\n\
+endbfchar\n\
+4 beginbfrange\n\
+<0005> <0007> <0027>\n\
+<000B> <000C> <0035>\n\
+<00FE> <00FF> <1010>\n\
+<0100> <0101> <1012>\n\
+endbfrange\n";
+
+ REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
+ buffer.getOffset()));
+
+ glyphToUnicode.reset();
+ glyphsInSubset.reset();
+ SkPDFGlyphSet subset2;
+
+ // Test mapping:
+ // I n s t a l
+ // Glyph id 2c 51 56 57 44 4f
+ // Unicode 49 6e 73 74 61 6c
+ for (size_t i = 0; i < 100; ++i) {
+ glyphToUnicode.push(i + 29);
+ }
+
+ glyphsInSubset.push(0x2C);
+ glyphsInSubset.push(0x44);
+ glyphsInSubset.push(0x4F);
+ glyphsInSubset.push(0x51);
+ glyphsInSubset.push(0x56);
+ glyphsInSubset.push(0x57);
+
+ SkDynamicMemoryWStream buffer2;
+ subset2.set(glyphsInSubset.begin(), glyphsInSubset.count());
+ append_cmap_sections(glyphToUnicode, &subset2, &buffer2);
+
+ char expectedResult2[] =
+"4 beginbfchar\n\
+<002C> <0049>\n\
+<0044> <0061>\n\
+<004F> <006C>\n\
+<0051> <006E>\n\
+endbfchar\n\
+1 beginbfrange\n\
+<0056> <0057> <0073>\n\
+endbfrange\n";
+
+ REPORTER_ASSERT(reporter, stream_equals(buffer2, 0, expectedResult2,
+ buffer2.getOffset()));
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("ToUnicode", ToUnicodeTestClass, TestToUnicode)
diff --git a/tests/TriangulationTest.cpp b/tests/TriangulationTest.cpp
index 9d47181..8d692c7 100644
--- a/tests/TriangulationTest.cpp
+++ b/tests/TriangulationTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "../../src/core/SkConcaveToTriangles.h"
#include "SkGeometry.h"
diff --git a/tests/UnicodeTest.cpp b/tests/UnicodeTest.cpp
new file mode 100644
index 0000000..602ff81
--- /dev/null
+++ b/tests/UnicodeTest.cpp
@@ -0,0 +1,45 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "Test.h"
+#include "SkUtils.h"
+
+// Unicode Variation Selector ranges: inclusive
+#define UVS_MIN0 0x180B
+#define UVS_MAX0 0x180D
+#define UVS_MIN1 0xFE00
+#define UVS_MAX1 0xFE0F
+#define UVS_MIN2 0xE0100
+#define UVS_MAX2 0xE01EF
+
+static bool isUVS(SkUnichar uni) {
+ return (uni >= UVS_MIN0 && uni <= UVS_MAX0) ||
+ (uni >= UVS_MIN1 && uni <= UVS_MAX1) ||
+ (uni >= UVS_MIN2 && uni <= UVS_MAX2);
+}
+
+static void test_uvs(skiatest::Reporter* reporter) {
+ // [min, max], [min, max] ... inclusive
+ static const SkUnichar gRanges[] = {
+ UVS_MIN0, UVS_MAX0, UVS_MIN1, UVS_MAX1, UVS_MIN2, UVS_MAX2
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gRanges); i += 2) {
+ for (SkUnichar uni = gRanges[i] - 8; uni <= gRanges[i+1] + 8; ++uni) {
+ bool uvs0 = isUVS(uni);
+ bool uvs1 = SkUnichar_IsVariationSelector(uni);
+ REPORTER_ASSERT(reporter, uvs0 == uvs1);
+ }
+ }
+}
+
+static void TestUnicode(skiatest::Reporter* reporter) {
+ test_uvs(reporter);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("Unicode", TestUnicodeClass, TestUnicode)
diff --git a/tests/UtilsTest.cpp b/tests/UtilsTest.cpp
index 4f36afe..f1b1ea9 100644
--- a/tests/UtilsTest.cpp
+++ b/tests/UtilsTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkRandom.h"
#include "SkRefCnt.h"
diff --git a/tests/WArrayTest.cpp b/tests/WArrayTest.cpp
new file mode 100644
index 0000000..428ca5f
--- /dev/null
+++ b/tests/WArrayTest.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+
+// Include the implementation so we can make an appropriate template instance.
+#include "SkAdvancedTypefaceMetrics.cpp"
+
+using namespace skia_advanced_typeface_metrics_utils;
+
+namespace {
+
+// Negative values and zeros in a range plus trailing zeros.
+// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
+const int16_t data1[] = {-1, 0, -3, 4, 5, 6, 7, 0, 0, 0, 8, 0, 0, 0, 0};
+const char* expected1 = "0[-1 0 -3 4 5 6 7 0 0 0 8]";
+
+// Run with leading and trailing zeros.
+// Test rules: d 0 1 2 3 4 5 6 7 8 9 10 11
+const int16_t data2[] = {0, 0, 0, 100, 100, 100, 100, 100, 100, 100, 0, 0};
+const char* expected2 = "3 9 100";
+
+// Removing 0's from a range.
+// Test rules: a 0 1 2 3 4 5 6 7 8 9 10 11
+const int16_t data3[] = {1, 2, 0, 0, 0, 3, 4, 0, 0, 0, 0, 5};
+const char* expected3 = "0[1 2 0 0 0 3 4] 11[5]";
+
+// Removing 0's from a run/range and between runs.
+// Test rules: a, b 0 1 2 3 4 5 6 7 8 9 10 11 12 14 15
+const int16_t data4[] = {1, 0, 0, 0, 1, 2, 2, 2, 3, 0, 0, 0, 0, 3, 4};
+const char* expected4 = "0[1 0 0 0 1] 5 7 2 8[3] 13[3 4]";
+
+// Runs that starts outside a range.
+// Test rules: a, e 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
+const int16_t data5[] = {1, 1, 2, 3, 0, 0, 0, 0, 5, 5, 6, 7, 0, 0, 0, 0, 8, 0};
+const char* expected5 = "0 1 1 2[2 3] 8 9 5 10[6 7] 16[8]";
+
+// Zeros and runs that should be broken out.
+// Test rules: a, b, e 0 1 2 3 4 5 6 7 8 9 10 11 12 13
+const int16_t data6[] = {1, 0, 0, 0, 0, 1, 2, 3, 3, 4, 5, 5, 5, 6};
+const char* expected6 = "0[1] 5[1 2 3 3 4] 10 12 5 13[6]";
+
+// Don't cares that aren't enough to break out a run.
+// Test rules: c 0 1 2 3 4 5
+const int16_t data7[] = {1, 2, 10, 11, 2, 3};
+const char* expected7 = "0[1 2 10 11 2 3]";
+const uint32_t subset7[] = {0, 1, 4, 5};
+const char* expectedSubset7 = "0[1 2 0 0 2 3]";
+
+// Don't cares that are enough to break out a run.
+// Test rules: c 0 1 2 3 4 5 6
+const int16_t data8[] = {1, 2, 10, 11, 12, 2, 3};
+const char* expected8 = "0[1 2 10 11 12 2 3]";
+const uint32_t subset8[] = {0, 1, 5, 6};
+const char* expectedSubset8 = "0[1] 1 5 2 6[3]";
+
+// Leading don't cares.
+// Test rules: d 0 1 2 3 4
+const int16_t data9[] = {1, 1, 10, 2, 3};
+const char* expected9 = "0 1 1 2[10 2 3]";
+const uint32_t subset9[] = {0, 1, 3, 4};
+const char* expectedSubset9 = "0 1 1 3[2 3]";
+
+// Almost run of don't cares inside a range.
+// Test rules: c 0 1 2 3 4 5
+const int16_t data10[] = {1, 2, 10, 11, 12, 3};
+const char* expected10 = "0[1 2 10 11 12 3]";
+const uint32_t subset10[] = {0, 1, 5};
+const char* expectedSubset10 = "0[1 2 0 0 0 3]";
+
+// Run of don't cares inside a range.
+// Test rules: c 0 1 2 3 4 5 6
+const int16_t data11[] = {1, 2, 10, 11, 12, 13, 3};
+const char* expected11 = "0[1 2 10 11 12 13 3]";
+const uint32_t subset11[] = {0, 1, 6};
+const char* expectedSubset11 = "0[1 2] 6[3]";
+
+// Almost run within a range with leading don't cares.
+// Test rules: c 0 1 2 3 4 5 6
+const int16_t data12[] = {1, 10, 11, 2, 12, 13, 3};
+const char* expected12 = "0[1 10 11 2 12 13 3]";
+const uint32_t subset12[] = {0, 3, 6};
+const char* expectedSubset12 = "0[1 0 0 2 0 0 3]";
+
+// Run within a range with leading don't cares.
+// Test rules: c 0 1 2 3 4 5 6 7
+const int16_t data13[] = {1, 10, 11, 2, 2, 12, 13, 3};
+const char* expected13 = "0[1 10 11 2 2 12 13 3]";
+const uint32_t subset13[] = {0, 3, 4, 7};
+const char* expectedSubset13 = "0[1] 1 6 2 7[3]";
+
+// Enough don't cares to breakup something.
+// Test rules: a 0 1 2 3 4 5
+const int16_t data14[] = {1, 0, 0, 0, 0, 2};
+const char* expected14 = "0[1] 5[2]";
+const uint32_t subset14[] = {0, 5};
+const char* expectedSubset14 = "0[1] 5[2]";
+
+}
+
+static SkString stringify_advance_data(
+ SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>* data) {
+ SkString result;
+ bool leadingSpace = false;
+ while (data != NULL) {
+ if (leadingSpace) {
+ result.appendf(" ");
+ } else {
+ leadingSpace = true;
+ }
+ switch(data->fType) {
+ case SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>::kRun:
+ result.appendf("%d %d %d", data->fStartId, data->fEndId,
+ data->fAdvance[0]);
+ break;
+ case SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>::kRange:
+ result.appendf("%d[", data->fStartId);
+ for (int i = 0; i < data->fAdvance.count(); ++i) {
+ if (i > 0) {
+ result.appendf(" ");
+ }
+ result.appendf("%d", data->fAdvance[i]);
+ }
+ result.appendf("]");
+ break;
+ case SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t>::kDefault:
+ result.appendf("<Default=%d>", data->fAdvance[0]);
+ break;
+ }
+ data = data->fNext.get();
+ }
+ return result;
+}
+
+class TestWData {
+ public:
+ TestWData(skiatest::Reporter* reporter,
+ const int16_t advances[],
+ int advanceLen,
+ const uint32_t subset[],
+ int subsetLen,
+ const char* expected)
+ : fAdvances(advances)
+ , fAdvancesLen(advanceLen)
+ , fSubset(subset)
+ , fSubsetLen(subsetLen)
+ , fExpected(expected) {
+ REPORTER_ASSERT(reporter, RunTest());
+ }
+
+ private:
+ const int16_t* fAdvances;
+ const int fAdvancesLen;
+ const uint32_t* fSubset;
+ const int fSubsetLen;
+ const char* fExpected;
+
+ static bool getAdvance(TestWData* testCase, int gId, int16_t* advance) {
+ if (gId >= 0 && gId < testCase->fAdvancesLen) {
+ *advance = testCase->fAdvances[gId];
+ return true;
+ }
+ return false;
+ }
+
+ bool RunTest() {
+ SkTScopedPtr<SkAdvancedTypefaceMetrics::AdvanceMetric<int16_t> > result;
+ result.reset(getAdvanceData(this, fAdvancesLen, fSubset, fSubsetLen,
+ getAdvance));
+
+ SkString stringResult = stringify_advance_data(result.get());
+ if (!stringResult.equals(fExpected)) {
+ printf("Expected: %s\n Result: %s\n", fExpected,
+ stringResult.c_str());
+ return false;
+ }
+ return true;
+ }
+};
+
+static void TestWArray(skiatest::Reporter* reporter) {
+ TestWData(reporter, data1, SK_ARRAY_COUNT(data1), NULL, 0, expected1);
+ TestWData(reporter, data2, SK_ARRAY_COUNT(data2), NULL, 0, expected2);
+ TestWData(reporter, data3, SK_ARRAY_COUNT(data3), NULL, 0, expected3);
+ TestWData(reporter, data4, SK_ARRAY_COUNT(data4), NULL, 0, expected4);
+ TestWData(reporter, data5, SK_ARRAY_COUNT(data5), NULL, 0, expected5);
+ TestWData(reporter, data6, SK_ARRAY_COUNT(data6), NULL, 0, expected6);
+ TestWData(reporter, data7, SK_ARRAY_COUNT(data7), NULL, 0, expected7);
+ TestWData(reporter, data7, SK_ARRAY_COUNT(data7), subset7,
+ SK_ARRAY_COUNT(subset7), expectedSubset7);
+ TestWData(reporter, data8, SK_ARRAY_COUNT(data8), NULL, 0, expected8);
+ TestWData(reporter, data8, SK_ARRAY_COUNT(data8), subset8,
+ SK_ARRAY_COUNT(subset8), expectedSubset8);
+ TestWData(reporter, data9, SK_ARRAY_COUNT(data9), NULL, 0, expected9);
+ TestWData(reporter, data9, SK_ARRAY_COUNT(data9), subset9,
+ SK_ARRAY_COUNT(subset9), expectedSubset9);
+ TestWData(reporter, data10, SK_ARRAY_COUNT(data10), NULL, 0, expected10);
+ TestWData(reporter, data10, SK_ARRAY_COUNT(data10), subset10,
+ SK_ARRAY_COUNT(subset10), expectedSubset10);
+ TestWData(reporter, data11, SK_ARRAY_COUNT(data11), NULL, 0, expected11);
+ TestWData(reporter, data11, SK_ARRAY_COUNT(data11), subset11,
+ SK_ARRAY_COUNT(subset11), expectedSubset11);
+ TestWData(reporter, data12, SK_ARRAY_COUNT(data12), NULL, 0, expected12);
+ TestWData(reporter, data12, SK_ARRAY_COUNT(data12), subset12,
+ SK_ARRAY_COUNT(subset12), expectedSubset12);
+ TestWData(reporter, data13, SK_ARRAY_COUNT(data13), NULL, 0, expected13);
+ TestWData(reporter, data13, SK_ARRAY_COUNT(data13), subset13,
+ SK_ARRAY_COUNT(subset13), expectedSubset13);
+ TestWData(reporter, data14, SK_ARRAY_COUNT(data14), NULL, 0, expected14);
+ TestWData(reporter, data14, SK_ARRAY_COUNT(data14), subset14,
+ SK_ARRAY_COUNT(subset14), expectedSubset14);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("WArray", WArrayTest, TestWArray)
diff --git a/tests/WritePixelsTest.cpp b/tests/WritePixelsTest.cpp
new file mode 100644
index 0000000..0c5b7b9
--- /dev/null
+++ b/tests/WritePixelsTest.cpp
@@ -0,0 +1,419 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+#include "SkCanvas.h"
+#include "SkRegion.h"
+#include "SkGpuDevice.h"
+
+static const int DEV_W = 100, DEV_H = 100;
+static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H);
+static const SkRect DEV_RECT_S = SkRect::MakeWH(DEV_W * SK_Scalar1,
+ DEV_H * SK_Scalar1);
+static const U8CPU DEV_PAD = 0xee;
+
+namespace {
+SkPMColor getCanvasColor(int x, int y) {
+ SkASSERT(x >= 0 && x < DEV_W);
+ SkASSERT(y >= 0 && y < DEV_H);
+
+ U8CPU r = x;
+ U8CPU g = y;
+ U8CPU b = 0xc;
+
+ U8CPU a = 0x0;
+ switch ((x+y) % 5) {
+ case 0:
+ a = 0xff;
+ break;
+ case 1:
+ a = 0x80;
+ break;
+ case 2:
+ a = 0xCC;
+ break;
+ case 3:
+ a = 0x00;
+ break;
+ case 4:
+ a = 0x01;
+ break;
+ }
+ return SkPremultiplyARGBInline(a, r, g, b);
+}
+
+bool config8888IsPremul(SkCanvas::Config8888 config8888) {
+ switch (config8888) {
+ case SkCanvas::kNative_Premul_Config8888:
+ case SkCanvas::kBGRA_Premul_Config8888:
+ case SkCanvas::kRGBA_Premul_Config8888:
+ return true;
+ case SkCanvas::kNative_Unpremul_Config8888:
+ case SkCanvas::kBGRA_Unpremul_Config8888:
+ case SkCanvas::kRGBA_Unpremul_Config8888:
+ return false;
+ default:
+ SkASSERT(0);
+ return false;
+ }
+}
+
+// assumes any premu/.unpremul has been applied
+uint32_t packConfig8888(SkCanvas::Config8888 config8888,
+ U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
+ uint32_t r32;
+ uint8_t* result = reinterpret_cast<uint8_t*>(&r32);
+ switch (config8888) {
+ case SkCanvas::kNative_Premul_Config8888:
+ case SkCanvas::kNative_Unpremul_Config8888:
+ r32 = SkPackARGB32NoCheck(a, r, g, b);
+ break;
+ case SkCanvas::kBGRA_Premul_Config8888:
+ case SkCanvas::kBGRA_Unpremul_Config8888:
+ result[0] = b;
+ result[1] = g;
+ result[2] = r;
+ result[3] = a;
+ break;
+ case SkCanvas::kRGBA_Premul_Config8888:
+ case SkCanvas::kRGBA_Unpremul_Config8888:
+ result[0] = r;
+ result[1] = g;
+ result[2] = b;
+ result[3] = a;
+ break;
+ default:
+ SkASSERT(0);
+ return 0;
+ }
+ return r32;
+}
+
+uint32_t getBitmapColor(int x, int y, int w, int h, SkCanvas::Config8888 config8888) {
+ int n = y * w + x;
+ U8CPU b = n & 0xff;
+ U8CPU g = (n >> 8) & 0xff;
+ U8CPU r = (n >> 16) & 0xff;
+ U8CPU a = 0;
+ switch ((x+y) % 5) {
+ case 4:
+ a = 0xff;
+ break;
+ case 3:
+ a = 0x80;
+ break;
+ case 2:
+ a = 0xCC;
+ break;
+ case 1:
+ a = 0x01;
+ break;
+ case 0:
+ a = 0x00;
+ break;
+ }
+ if (config8888IsPremul(config8888)) {
+ r = SkMulDiv255Ceiling(r, a);
+ g = SkMulDiv255Ceiling(g, a);
+ b = SkMulDiv255Ceiling(b, a);
+ }
+ return packConfig8888(config8888, a, r, g , b);
+}
+
+void fillCanvas(SkCanvas* canvas) {
+ static SkBitmap bmp;
+ if (bmp.isNull()) {
+ bmp.setConfig(SkBitmap::kARGB_8888_Config, DEV_W, DEV_H);
+ bool alloc = bmp.allocPixels();
+ SkASSERT(alloc);
+ SkAutoLockPixels alp(bmp);
+ intptr_t pixels = reinterpret_cast<intptr_t>(bmp.getPixels());
+ for (int y = 0; y < DEV_H; ++y) {
+ for (int x = 0; x < DEV_W; ++x) {
+ SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bmp.rowBytes() + x * bmp.bytesPerPixel());
+ *pixel = getCanvasColor(x, y);
+ }
+ }
+ }
+ canvas->save();
+ canvas->setMatrix(SkMatrix::I());
+ canvas->clipRect(DEV_RECT_S, SkRegion::kReplace_Op);
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ canvas->drawBitmap(bmp, 0, 0, &paint);
+ canvas->restore();
+}
+
+SkPMColor convertConfig8888ToPMColor(SkCanvas::Config8888 config8888,
+ uint32_t color,
+ bool* premul) {
+ const uint8_t* c = reinterpret_cast<uint8_t*>(&color);
+ U8CPU a,r,g,b;
+ *premul = false;
+ switch (config8888) {
+ case SkCanvas::kNative_Premul_Config8888:
+ return color;
+ case SkCanvas::kNative_Unpremul_Config8888:
+ *premul = true;
+ a = SkGetPackedA32(color);
+ r = SkGetPackedR32(color);
+ g = SkGetPackedG32(color);
+ b = SkGetPackedB32(color);
+ break;
+ case SkCanvas::kBGRA_Unpremul_Config8888:
+ *premul = true; // fallthru
+ case SkCanvas::kBGRA_Premul_Config8888:
+ a = static_cast<U8CPU>(c[3]);
+ r = static_cast<U8CPU>(c[2]);
+ g = static_cast<U8CPU>(c[1]);
+ b = static_cast<U8CPU>(c[0]);
+ break;
+ case SkCanvas::kRGBA_Unpremul_Config8888:
+ *premul = true; // fallthru
+ case SkCanvas::kRGBA_Premul_Config8888:
+ a = static_cast<U8CPU>(c[3]);
+ r = static_cast<U8CPU>(c[0]);
+ g = static_cast<U8CPU>(c[1]);
+ b = static_cast<U8CPU>(c[2]);
+ break;
+ default:
+ GrCrash("Unexpected Config8888");
+ }
+ if (*premul) {
+ r = SkMulDiv255Ceiling(r, a);
+ g = SkMulDiv255Ceiling(g, a);
+ b = SkMulDiv255Ceiling(b, a);
+ }
+ return SkPackARGB32(a, r, g, b);
+}
+
+bool checkPixel(SkPMColor a, SkPMColor b, bool didPremulConversion) {
+ if (!didPremulConversion) {
+ return a == b;
+ }
+ int32_t aA = static_cast<int32_t>(SkGetPackedA32(a));
+ int32_t aR = static_cast<int32_t>(SkGetPackedR32(a));
+ int32_t aG = static_cast<int32_t>(SkGetPackedG32(a));
+ int32_t aB = SkGetPackedB32(a);
+
+ int32_t bA = static_cast<int32_t>(SkGetPackedA32(b));
+ int32_t bR = static_cast<int32_t>(SkGetPackedR32(b));
+ int32_t bG = static_cast<int32_t>(SkGetPackedG32(b));
+ int32_t bB = static_cast<int32_t>(SkGetPackedB32(b));
+
+ return aA == bA &&
+ SkAbs32(aR - bR) <= 1 &&
+ SkAbs32(aG - bG) <= 1 &&
+ SkAbs32(aB - bB) <= 1;
+}
+
+bool checkWrite(skiatest::Reporter* reporter,
+ SkCanvas* canvas,
+ const SkBitmap& bitmap,
+ int writeX, int writeY,
+ SkCanvas::Config8888 config8888) {
+ SkDevice* dev = canvas->getDevice();
+ if (!dev) {
+ return false;
+ }
+ SkBitmap devBmp = dev->accessBitmap(false);
+ if (devBmp.width() != DEV_W ||
+ devBmp.height() != DEV_H ||
+ devBmp.config() != SkBitmap::kARGB_8888_Config ||
+ devBmp.isNull()) {
+ return false;
+ }
+ SkAutoLockPixels alp(devBmp);
+
+ intptr_t canvasPixels = reinterpret_cast<intptr_t>(devBmp.getPixels());
+ size_t canvasRowBytes = devBmp.rowBytes();
+ SkIRect writeRect = SkIRect::MakeXYWH(writeX, writeY, bitmap.width(), bitmap.height());
+ for (int cy = 0; cy < DEV_H; ++cy) {
+ const SkPMColor* canvasRow = reinterpret_cast<const SkPMColor*>(canvasPixels);
+ for (int cx = 0; cx < DEV_W; ++cx) {
+ SkPMColor canvasPixel = canvasRow[cx];
+ if (writeRect.contains(cx, cy)) {
+ int bx = cx - writeX;
+ int by = cy - writeY;
+ uint32_t bmpColor8888 = getBitmapColor(bx, by, bitmap.width(), bitmap.height(), config8888);
+ bool mul;
+ SkPMColor bmpPMColor = convertConfig8888ToPMColor(config8888, bmpColor8888, &mul);
+ bool check;
+ REPORTER_ASSERT(reporter, check = checkPixel(bmpPMColor, canvasPixel, mul));
+ if (!check) {
+ return false;
+ }
+ } else {
+ bool check;
+ SkPMColor testColor = getCanvasColor(cx, cy);
+ REPORTER_ASSERT(reporter, check = (canvasPixel == testColor));
+ if (!check) {
+ return false;
+ }
+ }
+ }
+ if (cy != DEV_H -1) {
+ const char* pad = reinterpret_cast<const char*>(canvasPixels + 4 * DEV_W);
+ for (size_t px = 0; px < canvasRowBytes - 4 * DEV_W; ++px) {
+ bool check;
+ REPORTER_ASSERT(reporter, check = (pad[px] == static_cast<char>(DEV_PAD)));
+ if (!check) {
+ return false;
+ }
+ }
+ }
+ canvasPixels += canvasRowBytes;
+ }
+
+ return true;
+}
+
+enum DevType {
+ kRaster_DevType,
+ kGpu_DevType,
+};
+
+struct CanvasConfig {
+ DevType fDevType;
+ bool fTightRowBytes;
+};
+
+static const CanvasConfig gCanvasConfigs[] = {
+ {kRaster_DevType, true},
+ {kRaster_DevType, false},
+#ifdef SK_SCALAR_IS_FLOAT
+ {kGpu_DevType, true}, // row bytes has no meaning on gpu devices
+#endif
+};
+
+bool setupCanvas(SkCanvas* canvas, const CanvasConfig& c, GrContext* grCtx) {
+ switch (c.fDevType) {
+ case kRaster_DevType: {
+ SkBitmap bmp;
+ size_t rowBytes = c.fTightRowBytes ? 0 : 4 * DEV_W + 100;
+ bmp.setConfig(SkBitmap::kARGB_8888_Config, DEV_W, DEV_H, rowBytes);
+ if (!bmp.allocPixels()) {
+ return false;
+ }
+ // if rowBytes isn't tight then set the padding to a known value
+ if (rowBytes) {
+ SkAutoLockPixels alp(bmp);
+ memset(bmp.getPixels(), DEV_PAD, bmp.getSafeSize());
+ }
+ canvas->setDevice(new SkDevice(bmp))->unref();
+ } break;
+ case kGpu_DevType:
+ canvas->setDevice(new SkGpuDevice(grCtx,
+ SkBitmap::kARGB_8888_Config,
+ DEV_W, DEV_H))->unref();
+ break;
+ }
+ return true;
+}
+
+bool setupBitmap(SkBitmap* bitmap,
+ SkCanvas::Config8888 config8888,
+ int w, int h,
+ bool tightRowBytes) {
+ size_t rowBytes = tightRowBytes ? 0 : 4 * w + 60;
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config, w, h, rowBytes);
+ if (!bitmap->allocPixels()) {
+ return false;
+ }
+ SkAutoLockPixels alp(*bitmap);
+ intptr_t pixels = reinterpret_cast<intptr_t>(bitmap->getPixels());
+ for (int y = 0; y < h; ++y) {
+ for (int x = 0; x < w; ++x) {
+ uint32_t* pixel = reinterpret_cast<uint32_t*>(pixels + y * bitmap->rowBytes() + x * 4);
+ *pixel = getBitmapColor(x, y, w, h, config8888);
+ }
+ }
+ return true;
+}
+
+void WritePixelsTest(skiatest::Reporter* reporter, GrContext* context) {
+ SkCanvas canvas;
+
+ const SkIRect testRects[] = {
+ // entire thing
+ DEV_RECT,
+ // larger on all sides
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H + 10),
+ // fully contained
+ SkIRect::MakeLTRB(DEV_W / 4, DEV_H / 4, 3 * DEV_W / 4, 3 * DEV_H / 4),
+ // outside top left
+ SkIRect::MakeLTRB(-10, -10, -1, -1),
+ // touching top left corner
+ SkIRect::MakeLTRB(-10, -10, 0, 0),
+ // overlapping top left corner
+ SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H / 4),
+ // overlapping top left and top right corners
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H / 4),
+ // touching entire top edge
+ SkIRect::MakeLTRB(-10, -10, DEV_W + 10, 0),
+ // overlapping top right corner
+ SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H / 4),
+ // contained in x, overlapping top edge
+ SkIRect::MakeLTRB(DEV_W / 4, -10, 3 * DEV_W / 4, DEV_H / 4),
+ // outside top right corner
+ SkIRect::MakeLTRB(DEV_W + 1, -10, DEV_W + 10, -1),
+ // touching top right corner
+ SkIRect::MakeLTRB(DEV_W, -10, DEV_W + 10, 0),
+ // overlapping top left and bottom left corners
+ SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H + 10),
+ // touching entire left edge
+ SkIRect::MakeLTRB(-10, -10, 0, DEV_H + 10),
+ // overlapping bottom left corner
+ SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W / 4, DEV_H + 10),
+ // contained in y, overlapping left edge
+ SkIRect::MakeLTRB(-10, DEV_H / 4, DEV_W / 4, 3 * DEV_H / 4),
+ // outside bottom left corner
+ SkIRect::MakeLTRB(-10, DEV_H + 1, -1, DEV_H + 10),
+ // touching bottom left corner
+ SkIRect::MakeLTRB(-10, DEV_H, 0, DEV_H + 10),
+ // overlapping bottom left and bottom right corners
+ SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
+ // touching entire left edge
+ SkIRect::MakeLTRB(0, DEV_H, DEV_W, DEV_H + 10),
+ // overlapping bottom right corner
+ SkIRect::MakeLTRB(3 * DEV_W / 4, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
+ // overlapping top right and bottom right corners
+ SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10),
+ };
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gCanvasConfigs); ++i) {
+ REPORTER_ASSERT(reporter, setupCanvas(&canvas, gCanvasConfigs[i], context));
+
+ static const SkCanvas::Config8888 gReadConfigs[] = {
+ SkCanvas::kNative_Premul_Config8888,
+ SkCanvas::kNative_Unpremul_Config8888,
+ SkCanvas::kBGRA_Premul_Config8888,
+ SkCanvas::kBGRA_Unpremul_Config8888,
+ SkCanvas::kRGBA_Premul_Config8888,
+ SkCanvas::kRGBA_Unpremul_Config8888,
+ };
+ for (size_t r = 0; r < SK_ARRAY_COUNT(testRects); ++r) {
+ const SkIRect& rect = testRects[r];
+ for (int tightBmp = 0; tightBmp < 2; ++tightBmp) {
+ for (size_t c = 0; c < SK_ARRAY_COUNT(gReadConfigs); ++c) {
+ fillCanvas(&canvas);
+ SkCanvas::Config8888 config8888 = gReadConfigs[c];
+ SkBitmap bmp;
+ REPORTER_ASSERT(reporter, setupBitmap(&bmp, config8888, rect.width(), rect.height(), SkToBool(tightBmp)));
+ canvas.writePixels(bmp, rect.fLeft, rect.fTop, config8888);
+ REPORTER_ASSERT(reporter, checkWrite(reporter, &canvas, bmp, rect.fLeft, rect.fTop, config8888));
+ }
+ }
+ }
+ }
+}
+}
+
+#include "TestClassDef.h"
+DEFINE_GPUTESTCLASS("WritePixels", WritePixelsTestClass, WritePixelsTest)
+
diff --git a/tests/Writer32Test.cpp b/tests/Writer32Test.cpp
index 63b1209..a9a07ad 100644
--- a/tests/Writer32Test.cpp
+++ b/tests/Writer32Test.cpp
@@ -1,20 +1,13 @@
-/*
- Copyright 2011 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
*/
+
#include "SkReader32.h"
#include "SkWriter32.h"
#include "Test.h"
diff --git a/tests/XfermodeTest.cpp b/tests/XfermodeTest.cpp
index b552ce0..966da51 100644
--- a/tests/XfermodeTest.cpp
+++ b/tests/XfermodeTest.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "Test.h"
#include "SkColor.h"
#include "SkXfermode.h"
@@ -39,5 +46,27 @@ static void test_asMode(skiatest::Reporter* reporter) {
bogusXfer->unref();
}
+static void test_IsMode(skiatest::Reporter* reporter) {
+ REPORTER_ASSERT(reporter, SkXfermode::IsMode(NULL,
+ SkXfermode::kSrcOver_Mode));
+
+ for (int i = 0; i <= SkXfermode::kLastMode; ++i) {
+ SkXfermode::Mode mode = (SkXfermode::Mode)i;
+
+ SkXfermode* xfer = SkXfermode::Create(mode);
+ REPORTER_ASSERT(reporter, SkXfermode::IsMode(xfer, mode));
+ SkSafeUnref(xfer);
+
+ if (SkXfermode::kSrcOver_Mode != mode) {
+ REPORTER_ASSERT(reporter, !SkXfermode::IsMode(NULL, mode));
+ }
+ }
+}
+
+static void test_xfermodes(skiatest::Reporter* reporter) {
+ test_asMode(reporter);
+ test_IsMode(reporter);
+}
+
#include "TestClassDef.h"
-DEFINE_TESTCLASS("Xfermode", XfermodeTestClass, test_asMode)
+DEFINE_TESTCLASS("Xfermode", XfermodeTestClass, test_xfermodes)
diff --git a/tests/skia_test.cpp b/tests/skia_test.cpp
index f931d62..b740590 100644
--- a/tests/skia_test.cpp
+++ b/tests/skia_test.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkGraphics.h"
#include "Test.h"
@@ -97,11 +104,40 @@ private:
int main (int argc, char * const argv[]) {
SkAutoGraphics ag;
-
+
bool androidMode = false;
- for (int i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-android")) {
+ const char* matchStr = NULL;
+
+ char* const* stop = argv + argc;
+ for (++argv; argv < stop; ++argv) {
+ if (strcmp(*argv, "-android") == 0) {
androidMode = true;
+
+ } else if (strcmp(*argv, "--match") == 0) {
+ ++argv;
+ if (argv < stop && **argv) {
+ matchStr = *argv;
+ }
+ }
+ }
+
+ {
+ SkString header("Skia UnitTests:");
+ if (matchStr) {
+ header.appendf(" --match %s", matchStr);
+ }
+#ifdef SK_DEBUG
+ header.append(" SK_DEBUG");
+#else
+ header.append(" SK_RELEASE");
+#endif
+#ifdef SK_SCALAR_IS_FIXED
+ header.append(" SK_SCALAR_IS_FIXED");
+#else
+ header.append(" SK_SCALAR_IS_FLOAT");
+#endif
+ if (!androidMode) {
+ SkDebugf("%s\n", header.c_str());
}
}
@@ -111,17 +147,24 @@ int main (int argc, char * const argv[]) {
const int count = Iter::Count();
int index = 0;
- int successCount = 0;
+ int failCount = 0;
+ int skipCount = 0;
while ((test = iter.next()) != NULL) {
reporter.setIndexOfTotal(index, count);
- successCount += test->run();
+ if (NULL != matchStr && !strstr(test->getName(), matchStr)) {
+ ++skipCount;
+ } else {
+ if (!test->run()) {
+ ++failCount;
+ }
+ }
SkDELETE(test);
index += 1;
}
if (!androidMode) {
- SkDebugf("Finished %d tests, %d failures.\n", count,
- count - successCount);
+ SkDebugf("Finished %d tests, %d failures, %d skipped.\n",
+ count, failCount, skipCount);
}
- return (count == successCount) ? 0 : 1;
+ return (failCount == 0) ? 0 : 1;
}
diff --git a/tests/tests_files.mk b/tests/tests_files.mk
deleted file mode 100644
index 667c9b5..0000000
--- a/tests/tests_files.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-SOURCE := \
- BitmapCopyTest.cpp \
- BitmapGetColorTest.cpp \
- BlitRowTest.cpp \
- ClampRangeTest.cpp \
- ClipCubicTest.cpp \
- ClipStackTest.cpp \
- ClipperTest.cpp \
- ColorFilterTest.cpp \
- ColorTest.cpp \
- DequeTest.cpp \
- DrawBitmapRectTest.cpp \
- FillPathTest.cpp \
- FlateTest.cpp \
- GeometryTest.cpp \
- InfRectTest.cpp \
- MathTest.cpp \
- MatrixTest.cpp \
- MetaDataTest.cpp \
- PackBitsTest.cpp \
- PaintTest.cpp \
- ParsePathTest.cpp \
- PathCoverageTest.cpp \
- PathMeasureTest.cpp \
- PathTest.cpp \
- Reader32Test.cpp \
- RefDictTest.cpp \
- RegionTest.cpp \
- Sk64Test.cpp \
- skia_test.cpp \
- SortTest.cpp \
- SrcOverTest.cpp \
- StreamTest.cpp \
- StringTest.cpp \
- Test.cpp \
- TestSize.cpp \
- UtilsTest.cpp \
- Writer32Test.cpp \
- XfermodeTest.cpp
diff --git a/third_party/glu/LICENSE.txt b/third_party/glu/LICENSE.txt
new file mode 100644
index 0000000..e58ae38
--- /dev/null
+++ b/third_party/glu/LICENSE.txt
@@ -0,0 +1,31 @@
+SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+
+Copyright (C) [dates of first publication] Silicon Graphics, Inc. All
+Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice including the dates of first publication
+and either this permission notice or a reference to HYPERLINK
+"http://oss.sgi.com/projects/FreeB/"http://oss.sgi.com/projects/FreeB/
+shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of Silicon Graphics,
+Inc. shall not be used in advertising or otherwise to promote the
+sale, use or other dealings in this Software without prior written
+authorization from Silicon Graphics, Inc.
diff --git a/third_party/glu/README.skia b/third_party/glu/README.skia
new file mode 100644
index 0000000..0b6b624
--- /dev/null
+++ b/third_party/glu/README.skia
@@ -0,0 +1,41 @@
+This is a nearly verbatim copy of the GLU tessellator source code from
+SGI's OpenGL Sample Implementation at
+http://oss.sgi.com/projects/ogl-sample/ . Per
+http://oss.sgi.com/projects/FreeB/ , the code is covered under the SGI
+Free Software License B, version 2.0, a copy of which is in
+LICENSE.txt in this directory.
+
+The following changes were made in order to incorporate this code:
+
+ - The addition of a simplified gluos.h to eliminate operating system
+ dependencies. The entry points to the tessellator were prefixed with
+ Sk_ to avoid symbol collisions with any host OS version of GLU via
+ #defines in gluos.h.
+
+ - The removal of inclusion of GL/glu.h and replacement with an
+ include of sk_glu.h.
+
+ - In tess.c, the obsolete entry points gluBeginPolygon,
+ gluNextContour and gluEndPolygon in tess.c were #if 0'd out.
+ Default branches were added to the switch statements in GotoState.
+
+ - In memalloc.h, the include of malloc.h was changed to an include
+ of stdlib.h.
+
+ - In normal.c, an unused variable "w" was removed from
+ __gl_projectPolygon. #if guards were placed around the definition
+ of the unused Normalize function.
+
+ - In priorityq-heap.c, an #include of <limits.h> was added.
+
+ - In sweep.c, IsWindingInside() was given a return value to silence a
+ warning-as-error in release builds.
+
+ - In sweep.c, DoneEdgeDict()'s fixedEdges was wrapped in #indef NDEBUG, to
+ silence a warning-as-error in release builds.
+
+ - In priorityq.c, render.c, and others: the construct "if(1)...else" was
+ replaced with "do{...}while(1)" to silence a warning-as-error in Mac builds.
+
+ - rename all __gl_ functions to Sk__gl_ to avoid conflicting with other
+ static linkers of this library.
diff --git a/third_party/glu/gluos.h b/third_party/glu/gluos.h
new file mode 100644
index 0000000..5da46a5
--- /dev/null
+++ b/third_party/glu/gluos.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2010, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GLUOS_H_
+#define GLUOS_H_
+
+// This header provides the minimal definitions needed to compile the
+// GLU tessellator sources.
+#define GLAPIENTRY
+
+typedef unsigned char GLboolean;
+typedef double GLdouble;
+typedef unsigned int GLenum;
+typedef float GLfloat;
+typedef void GLvoid;
+
+#define gluNewTess Sk_gluNewTess
+#define gluDeleteTess Sk_gluDeleteTess
+#define gluTessProperty Sk_gluTessProperty
+#define gluGetTessProperty Sk_gluGetTessProperty
+#define gluTessNormal Sk_gluTessNormal
+#define gluTessCallback Sk_gluTessCallback
+#define gluTessVertex Sk_gluTessVertex
+#define gluTessBeginPolygon Sk_gluTessBeginPolygon
+#define gluTessBeginContour Sk_gluTessBeginContour
+#define gluTessEndContour Sk_gluTessEndContour
+#define gluTessEndPolygon Sk_gluTessEndPolygon
+
+#define __gl_noBeginData Sk__gl_noBeginData
+#define __gl_noEdgeFlagData Sk__gl_noEdgeFlagData
+#define __gl_noVertexData Sk__gl_noVertexData
+#define __gl_noEndData Sk__gl_noEndData
+#define __gl_noErrorData Sk__gl_noErrorData
+#define __gl_noCombineData Sk__gl_noCombineData
+#define __gl_computeInterior Sk__gl_computeInterior
+#define __gl_dictListDelete Sk__gl_dictListDelete
+#define __gl_dictListDeleteDict Sk__gl_dictListDeleteDict
+#define __gl_dictListInsertBefore Sk__gl_dictListInsertBefore
+#define __gl_dictListNewDict Sk__gl_dictListNewDict
+#define __gl_dictListSearch Sk__gl_dictListSearch
+#define __gl_edgeEval Sk__gl_edgeEval
+#define __gl_edgeIntersect Sk__gl_edgeIntersect
+#define __gl_edgeSign Sk__gl_edgeSign
+#define __gl_memInit Sk__gl_memInit
+#define __gl_meshAddEdgeVertex Sk__gl_meshAddEdgeVertex
+#define __gl_meshCheckMesh Sk__gl_meshCheckMesh
+#define __gl_meshConnect Sk__gl_meshConnect
+#define __gl_meshDelete Sk__gl_meshDelete
+#define __gl_meshDeleteMesh Sk__gl_meshDeleteMesh
+#define __gl_meshDiscardExterior Sk__gl_meshDiscardExterior
+#define __gl_meshMakeEdge Sk__gl_meshMakeEdge
+#define __gl_meshNewMesh Sk__gl_meshNewMesh
+#define __gl_meshSetWindingNumber Sk__gl_meshSetWindingNumber
+#define __gl_meshSplice Sk__gl_meshSplice
+#define __gl_meshSplitEdge Sk__gl_meshSplitEdge
+#define __gl_meshTessellateInterior Sk__gl_meshTessellateInterior
+#define __gl_meshTessellateMonoRegion Sk__gl_meshTessellateMonoRegion
+#define __gl_meshUnion Sk__gl_meshUnion
+#define __gl_meshZapFace Sk__gl_meshZapFace
+#define __gl_pqHeapDelete Sk__gl_pqHeapDelete
+#define __gl_pqHeapDeletePriorityQ Sk__gl_pqHeapDeletePriorityQ
+#define __gl_pqHeapExtractMin Sk__gl_pqHeapExtractMin
+#define __gl_pqHeapInit Sk__gl_pqHeapInit
+#define __gl_pqHeapInsert Sk__gl_pqHeapInsert
+#define __gl_pqHeapNewPriorityQ Sk__gl_pqHeapNewPriorityQ
+#define __gl_pqSortDelete Sk__gl_pqSortDelete
+#define __gl_pqSortDeletePriorityQ Sk__gl_pqSortDeletePriorityQ
+#define __gl_pqSortExtractMin Sk__gl_pqSortExtractMin
+#define __gl_pqSortInit Sk__gl_pqSortInit
+#define __gl_pqSortInsert Sk__gl_pqSortInsert
+#define __gl_pqSortIsEmpty Sk__gl_pqSortIsEmpty
+#define __gl_pqSortMinimum Sk__gl_pqSortMinimum
+#define __gl_pqSortNewPriorityQ Sk__gl_pqSortNewPriorityQ
+#define __gl_projectPolygon Sk__gl_projectPolygon
+#define __gl_renderBoundary Sk__gl_renderBoundary
+#define __gl_renderCache Sk__gl_renderCache
+#define __gl_renderMesh Sk__gl_renderMesh
+#define __gl_transEval Sk__gl_transEval
+#define __gl_transSign Sk__gl_transSign
+#define __gl_vertCCW Sk__gl_vertCCW
+#define __gl_vertLeq Sk__gl_vertLeq
+
+
+#undef MIN
+#undef MAX
+
+#endif // GLUOS_H_
diff --git a/third_party/glu/libtess/GNUmakefile b/third_party/glu/libtess/GNUmakefile
new file mode 100644
index 0000000..0ae859f
--- /dev/null
+++ b/third_party/glu/libtess/GNUmakefile
@@ -0,0 +1,110 @@
+#!gmake
+#
+# License Applicability. Except to the extent portions of this file are
+# made subject to an alternative license as permitted in the SGI Free
+# Software License B, Version 1.1 (the "License"), the contents of this
+# file are subject only to the provisions of the License. You may not use
+# this file except in compliance with the License. You may obtain a copy
+# of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+# Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+#
+# http://oss.sgi.com/projects/FreeB
+#
+# Note that, as provided in the License, the Software is distributed on an
+# "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+# DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+# CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+# PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+#
+# Original Code. The Original Code is: OpenGL Sample Implementation,
+# Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+# Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+# Copyright in any portions created by third parties is as indicated
+# elsewhere herein. All Rights Reserved.
+#
+# Additional Notice Provisions: The application programming interfaces
+# established by SGI in conjunction with the Original Code are The
+# OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+# April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+# 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+# Window System(R) (Version 1.3), released October 19, 1998. This software
+# was created using the OpenGL(R) version 1.2.1 Sample Implementation
+# published by SGI, but has not been independently verified as being
+# compliant with the OpenGL(R) version 1.2.1 Specification.
+#
+# $Date$ $Revision$
+# $Header: //depot/main/gfx/lib/glu/libtess/GNUmakefile#9 $
+
+OBJECT_STYLE = N32
+
+include $(ROOT)/usr/include/make/commondefs
+
+TARGET = libtess.a
+
+TARGETS = $(TARGET)
+
+LCINCS = -I../include
+
+# Compilation flags:
+#
+# -DNDEBUG is for the production code; it removes all assertion checks
+# (note that <assert.h> looks at this symbol).
+#
+# -DNO_MALLOPT uses regular malloc instead of the mallopt() version.
+# ***** Unless you use this flag, you must use "-lmalloc" to link
+# ***** your application!
+#
+# -DMEMORY_DEBUG turns on the M_DEBUG option of mallopt; this can
+# increase the running time a LOT.
+#
+# -DGLU_TESS_API_FLOAT compiles a single-precision version of the library.
+#
+# -float prevents automatic promotion to double precision; this will produce
+# faster code when compiled with -DGLU_TESS_API_FLOAT.
+#
+# -DNO_BRANCH_CONDITIONS uses & and | instead of && and || on a couple
+# of heavily-used tests (VertEq and VertLeq); some compilers can generate
+# better code with these (use special instructions to avoid branching).
+#
+# -DFOR_TRITE_TEST_PROGRAM is *only* for use with the test program called
+# "trite". It uses some variables which are defined by the test program,
+# so you won't be able to link it with anything else.
+
+HFILES = \
+ dict.h \
+ dict-list.h \
+ geom.h \
+ memalloc.h \
+ mesh.h \
+ normal.h \
+ priorityq-heap.h \
+ priorityq-heap.c \
+ priorityq-sort.h \
+ priorityq.h \
+ render.h \
+ sweep.h \
+ tess.h \
+ tessmono.h \
+ $(NULL)
+
+CFILES = \
+ dict.c \
+ geom.c \
+ memalloc.c \
+ mesh.c \
+ normal.c \
+ priorityq.c \
+ render.c \
+ sweep.c \
+ tess.c \
+ tessmono.c \
+ $(NULL)
+
+default libs libs_install install: $(TARGET)
+
+headers headers_install apps:
+
+$(TARGET): $(OBJECTS)
+ $(AR) crl $@ $(OBJECTS);
+
+include $(COMMONRULES)
diff --git a/third_party/glu/libtess/Imakefile b/third_party/glu/libtess/Imakefile
new file mode 100644
index 0000000..fb99ce2
--- /dev/null
+++ b/third_party/glu/libtess/Imakefile
@@ -0,0 +1,61 @@
+XCOMM License Applicability. Except to the extent portions of this file are
+XCOMM made subject to an alternative license as permitted in the SGI Free
+XCOMM Software License B, Version 1.1 (the "License"), the contents of this
+XCOMM file are subject only to the provisions of the License. You may not use
+XCOMM this file except in compliance with the License. You may obtain a copy
+XCOMM of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+XCOMM Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+XCOMM
+XCOMM http://oss.sgi.com/projects/FreeB
+XCOMM
+XCOMM Note that, as provided in the License, the Software is distributed on an
+XCOMM "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+XCOMM DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+XCOMM CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+XCOMM PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+XCOMM
+XCOMM Original Code. The Original Code is: OpenGL Sample Implementation,
+XCOMM Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+XCOMM Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+XCOMM Copyright in any portions created by third parties is as indicated
+XCOMM elsewhere herein. All Rights Reserved.
+XCOMM
+XCOMM Additional Notice Provisions: The application programming interfaces
+XCOMM established by SGI in conjunction with the Original Code are The
+XCOMM OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+XCOMM April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+XCOMM 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+XCOMM Window System(R) (Version 1.3), released October 19, 1998. This software
+XCOMM was created using the OpenGL(R) version 1.2.1 Sample Implementation
+XCOMM published by SGI, but has not been independently verified as being
+XCOMM compliant with the OpenGL(R) version 1.2.1 Specification.
+XCOMM
+
+#include <Library.tmpl>
+
+OBJS = \
+ dict.o \
+ geom.o \
+ memalloc.o \
+ mesh.o \
+ normal.o \
+ priorityq.o \
+ render.o \
+ sweep.o \
+ tess.o \
+ tessmono.o
+
+INCLUDES = \
+ -I../include \
+ -I$(TOP)/include \
+ -I$(TOP)/include/GL
+
+DEFINES = \
+ -DNDEBUG
+
+NormalLibraryObjectRule()
+
+NormalLibraryTarget(tess, $(OBJS))
+
+DependTarget()
+CleanTarget()
diff --git a/third_party/glu/libtess/README b/third_party/glu/libtess/README
new file mode 100644
index 0000000..59f4ff2
--- /dev/null
+++ b/third_party/glu/libtess/README
@@ -0,0 +1,447 @@
+/*
+** $Header: /cvs/projects/ogl-sample/main/gfx/lib/glu/libtess/README,v 1.1 2000/04/26 05:53:59 ljp Exp $
+*/
+
+General Polygon Tesselation
+---------------------------
+
+ This note describes a tesselator for polygons consisting of one or
+ more closed contours. It is backward-compatible with the current
+ OpenGL Utilities tesselator, and is intended to replace it. Here is
+ a summary of the major differences:
+
+ - input contours can be intersecting, self-intersecting, or degenerate.
+
+ - supports a choice of several winding rules for determining which parts
+ of the polygon are on the "interior". This makes it possible to do
+ CSG operations on polygons.
+
+ - boundary extraction: instead of tesselating the polygon, returns a
+ set of closed contours which separate the interior from the exterior.
+
+ - returns the output as a small number of triangle fans and strips,
+ rather than a list of independent triangles (when possible).
+
+ - output is available as an explicit mesh (a quad-edge structure),
+ in addition to the normal callback interface.
+
+ - the algorithm used is extremely robust.
+
+
+The interface
+-------------
+
+ The tesselator state is maintained in a "tesselator object".
+ These are allocated and destroyed using
+
+ GLUtesselator *gluNewTess( void );
+ void gluDeleteTess( GLUtesselator *tess );
+
+ Several tesselator objects may be used simultaneously.
+
+ Inputs
+ ------
+
+ The input contours are specified with the following routines:
+
+ void gluTessBeginPolygon( GLUtesselator *tess );
+ void gluTessBeginContour( GLUtesselator *tess );
+ void gluTessVertex( GLUtesselator *tess, GLUcoord coords[3], void *data );
+ void gluTessEndContour( GLUtesselator *tess );
+ void gluTessEndPolygon( GLUtesselator *tess );
+
+ Within each BeginPolygon/EndPolygon pair, there can be zero or more
+ calls to BeginContour/EndContour. Within each contour, there are zero
+ or more calls to gluTessVertex(). The vertices specify a closed
+ contour (the last vertex of each contour is automatically linked to
+ the first).
+
+ "coords" give the coordinates of the vertex in 3-space. For useful
+ results, all vertices should lie in some plane, since the vertices
+ are projected onto a plane before tesselation. "data" is a pointer
+ to a user-defined vertex structure, which typically contains other
+ information such as color, texture coordinates, normal, etc. It is
+ used to refer to the vertex during rendering.
+
+ The library can be compiled in single- or double-precision; the type
+ GLUcoord represents either "float" or "double" accordingly. The GLU
+ version will be available in double-precision only. Compile with
+ GLU_TESS_API_FLOAT defined to get the single-precision version.
+
+ When EndPolygon is called, the tesselation algorithm determines
+ which regions are interior to the given contours, according to one
+ of several "winding rules" described below. The interior regions
+ are then tesselated, and the output is provided as callbacks.
+
+
+ Rendering Callbacks
+ -------------------
+
+ Callbacks are specified by the client using
+
+ void gluTessCallback( GLUtesselator *tess, GLenum which, void (*fn)());
+
+ If "fn" is NULL, any previously defined callback is discarded.
+
+ The callbacks used to provide output are: /* which == */
+
+ void begin( GLenum type ); /* GLU_TESS_BEGIN */
+ void edgeFlag( GLboolean flag ); /* GLU_TESS_EDGE_FLAG */
+ void vertex( void *data ); /* GLU_TESS_VERTEX */
+ void end( void ); /* GLU_TESS_END */
+
+ Any of the callbacks may be left undefined; if so, the corresponding
+ information will not be supplied during rendering.
+
+ The "begin" callback indicates the start of a primitive; type is one
+ of GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, or GL_TRIANGLES (but see the
+ notes on "boundary extraction" below).
+
+ It is followed by any number of "vertex" callbacks, which supply the
+ vertices in the same order as expected by the corresponding glBegin()
+ call. After the last vertex of a given primitive, there is a callback
+ to "end".
+
+ If the "edgeFlag" callback is provided, no triangle fans or strips
+ will be used. When edgeFlag is called, if "flag" is GL_TRUE then each
+ vertex which follows begins an edge which lies on the polygon boundary
+ (ie. an edge which separates an interior region from an exterior one).
+ If "flag" is GL_FALSE, each vertex which follows begins an edge which lies
+ in the polygon interior. "edgeFlag" will be called before the first
+ call to "vertex".
+
+ Other Callbacks
+ ---------------
+
+ void mesh( GLUmesh *mesh ); /* GLU_TESS_MESH */
+
+ - Returns an explicit mesh, represented using the quad-edge structure
+ (Guibas/Stolfi '85). Other implementations of this interface might
+ use a different mesh structure, so this is available only only as an
+ SGI extension. When the mesh is no longer needed, it should be freed
+ using
+
+ void gluDeleteMesh( GLUmesh *mesh );
+
+ There is a brief description of this data structure in the include
+ file "mesh.h". For the full details, see L. Guibas and J. Stolfi,
+ Primitives for the manipulation of general subdivisions and the
+ computation of Voronoi diagrams, ACM Transactions on Graphics,
+ 4(2):74-123, April 1985. For an introduction, see the course notes
+ for CS348a, "Mathematical Foundations of Computer Graphics",
+ available at the Stanford bookstore (and taught during the fall
+ quarter).
+
+ void error( GLenum errno ); /* GLU_TESS_ERROR */
+
+ - errno is one of GLU_TESS_MISSING_BEGIN_POLYGON,
+ GLU_TESS_MISSING_END_POLYGON,
+ GLU_TESS_MISSING_BEGIN_CONTOUR,
+ GLU_TESS_MISSING_END_CONTOUR,
+ GLU_TESS_COORD_TOO_LARGE,
+ GLU_TESS_NEED_COMBINE_CALLBACK
+
+ The first four are obvious. The interface recovers from these
+ errors by inserting the missing call(s).
+
+ GLU_TESS_COORD_TOO_LARGE says that some vertex coordinate exceeded
+ the predefined constant GLU_TESS_MAX_COORD in absolute value, and
+ that the value has been clamped. (Coordinate values must be small
+ enough so that two can be multiplied together without overflow.)
+
+ GLU_TESS_NEED_COMBINE_CALLBACK says that the algorithm detected an
+ intersection between two edges in the input data, and the "combine"
+ callback (below) was not provided. No output will be generated.
+
+
+ void combine( GLUcoord coords[3], void *data[4], /* GLU_TESS_COMBINE */
+ GLUcoord weight[4], void **outData );
+
+ - When the algorithm detects an intersection, or wishes to merge
+ features, it needs to create a new vertex. The vertex is defined
+ as a linear combination of up to 4 existing vertices, referenced
+ by data[0..3]. The coefficients of the linear combination are
+ given by weight[0..3]; these weights always sum to 1.0. All vertex
+ pointers are valid even when some of the weights are zero.
+ "coords" gives the location of the new vertex.
+
+ The user must allocate another vertex, interpolate parameters
+ using "data" and "weights", and return the new vertex pointer in
+ "outData". This handle is supplied during rendering callbacks.
+ For example, if the polygon lies in an arbitrary plane in 3-space,
+ and we associate a color with each vertex, the combine callback might
+ look like this:
+
+ void myCombine( GLUcoord coords[3], VERTEX *d[4],
+ GLUcoord w[4], VERTEX **dataOut )
+ {
+ VERTEX *new = new_vertex();
+
+ new->x = coords[0];
+ new->y = coords[1];
+ new->z = coords[2];
+ new->r = w[0]*d[0]->r + w[1]*d[1]->r + w[2]*d[2]->r + w[3]*d[3]->r;
+ new->g = w[0]*d[0]->g + w[1]*d[1]->g + w[2]*d[2]->g + w[3]*d[3]->g;
+ new->b = w[0]*d[0]->b + w[1]*d[1]->b + w[2]*d[2]->b + w[3]*d[3]->b;
+ new->a = w[0]*d[0]->a + w[1]*d[1]->a + w[2]*d[2]->a + w[3]*d[3]->a;
+ *dataOut = new;
+ }
+
+ If the algorithm detects an intersection, then the "combine" callback
+ must be defined, and must write a non-NULL pointer into "dataOut".
+ Otherwise the GLU_TESS_NEED_COMBINE_CALLBACK error occurs, and no
+ output is generated. This is the only error that can occur during
+ tesselation and rendering.
+
+
+ Control over Tesselation
+ ------------------------
+
+ void gluTessProperty( GLUtesselator *tess, GLenum which, GLUcoord value );
+
+ Properties defined:
+
+ - GLU_TESS_WINDING_RULE. Possible values:
+
+ GLU_TESS_WINDING_ODD
+ GLU_TESS_WINDING_NONZERO
+ GLU_TESS_WINDING_POSITIVE
+ GLU_TESS_WINDING_NEGATIVE
+ GLU_TESS_WINDING_ABS_GEQ_TWO
+
+ The input contours parition the plane into regions. A winding
+ rule determines which of these regions are inside the polygon.
+
+ For a single contour C, the winding number of a point x is simply
+ the signed number of revolutions we make around x as we travel
+ once around C (where CCW is positive). When there are several
+ contours, the individual winding numbers are summed. This
+ procedure associates a signed integer value with each point x in
+ the plane. Note that the winding number is the same for all
+ points in a single region.
+
+ The winding rule classifies a region as "inside" if its winding
+ number belongs to the chosen category (odd, nonzero, positive,
+ negative, or absolute value of at least two). The current GLU
+ tesselator implements the "odd" rule. The "nonzero" rule is another
+ common way to define the interior. The other three rules are
+ useful for polygon CSG operations (see below).
+
+ - GLU_TESS_BOUNDARY_ONLY. Values: TRUE (non-zero) or FALSE (zero).
+
+ If TRUE, returns a set of closed contours which separate the
+ polygon interior and exterior (rather than a tesselation).
+ Exterior contours are oriented CCW with respect to the normal,
+ interior contours are oriented CW. The GLU_TESS_BEGIN callback
+ uses the type GL_LINE_LOOP for each contour.
+
+ - GLU_TESS_TOLERANCE. Value: a real number between 0.0 and 1.0.
+
+ This specifies a tolerance for merging features to reduce the size
+ of the output. For example, two vertices which are very close to
+ each other might be replaced by a single vertex. The tolerance
+ is multiplied by the largest coordinate magnitude of any input vertex;
+ this specifies the maximum distance that any feature can move as the
+ result of a single merge operation. If a single feature takes part
+ in several merge operations, the total distance moved could be larger.
+
+ Feature merging is completely optional; the tolerance is only a hint.
+ The implementation is free to merge in some cases and not in others,
+ or to never merge features at all. The default tolerance is zero.
+
+ The current implementation merges vertices only if they are exactly
+ coincident, regardless of the current tolerance. A vertex is
+ spliced into an edge only if the implementation is unable to
+ distinguish which side of the edge the vertex lies on.
+ Two edges are merged only when both endpoints are identical.
+
+
+ void gluTessNormal( GLUtesselator *tess,
+ GLUcoord x, GLUcoord y, GLUcoord z )
+
+ - Lets the user supply the polygon normal, if known. All input data
+ is projected into a plane perpendicular to the normal before
+ tesselation. All output triangles are oriented CCW with
+ respect to the normal (CW orientation can be obtained by
+ reversing the sign of the supplied normal). For example, if
+ you know that all polygons lie in the x-y plane, call
+ "gluTessNormal(tess, 0.0, 0.0, 1.0)" before rendering any polygons.
+
+ - If the supplied normal is (0,0,0) (the default value), the
+ normal is determined as follows. The direction of the normal,
+ up to its sign, is found by fitting a plane to the vertices,
+ without regard to how the vertices are connected. It is
+ expected that the input data lies approximately in plane;
+ otherwise projection perpendicular to the computed normal may
+ substantially change the geometry. The sign of the normal is
+ chosen so that the sum of the signed areas of all input contours
+ is non-negative (where a CCW contour has positive area).
+
+ - The supplied normal persists until it is changed by another
+ call to gluTessNormal.
+
+
+ Backward compatibility with the GLU tesselator
+ ----------------------------------------------
+
+ The preferred interface is the one described above. The following
+ routines are obsolete, and are provided only for backward compatibility:
+
+ typedef GLUtesselator GLUtriangulatorObj; /* obsolete name */
+
+ void gluBeginPolygon( GLUtesselator *tess );
+ void gluNextContour( GLUtesselator *tess, GLenum type );
+ void gluEndPolygon( GLUtesselator *tess );
+
+ "type" is one of GLU_EXTERIOR, GLU_INTERIOR, GLU_CCW, GLU_CW, or
+ GLU_UNKNOWN. It is ignored by the current GLU tesselator.
+
+ GLU_BEGIN, GLU_VERTEX, GLU_END, GLU_ERROR, and GLU_EDGE_FLAG are defined
+ as synonyms for GLU_TESS_BEGIN, GLU_TESS_VERTEX, GLU_TESS_END,
+ GLU_TESS_ERROR, and GLU_TESS_EDGE_FLAG.
+
+
+Polygon CSG operations
+----------------------
+
+ The features of the tesselator make it easy to find the union, difference,
+ or intersection of several polygons.
+
+ First, assume that each polygon is defined so that the winding number
+ is 0 for each exterior region, and 1 for each interior region. Under
+ this model, CCW contours define the outer boundary of the polygon, and
+ CW contours define holes. Contours may be nested, but a nested
+ contour must be oriented oppositely from the contour that contains it.
+
+ If the original polygons do not satisfy this description, they can be
+ converted to this form by first running the tesselator with the
+ GLU_TESS_BOUNDARY_ONLY property turned on. This returns a list of
+ contours satisfying the restriction above. By allocating two
+ tesselator objects, the callbacks from one tesselator can be fed
+ directly to the input of another.
+
+ Given two or more polygons of the form above, CSG operations can be
+ implemented as follows:
+
+ Union
+ Draw all the input contours as a single polygon. The winding number
+ of each resulting region is the number of original polygons
+ which cover it. The union can be extracted using the
+ GLU_TESS_WINDING_NONZERO or GLU_TESS_WINDING_POSITIVE winding rules.
+ Note that with the nonzero rule, we would get the same result if
+ all contour orientations were reversed.
+
+ Intersection (two polygons at a time only)
+ Draw a single polygon using the contours from both input polygons.
+ Extract the result using GLU_TESS_WINDING_ABS_GEQ_TWO. (Since this
+ winding rule looks at the absolute value, reversing all contour
+ orientations does not change the result.)
+
+ Difference
+
+ Suppose we want to compute A \ (B union C union D). Draw a single
+ polygon consisting of the unmodified contours from A, followed by
+ the contours of B,C,D with the vertex order reversed (this changes
+ the winding number of the interior regions to -1). To extract the
+ result, use the GLU_TESS_WINDING_POSITIVE rule.
+
+ If B,C,D are the result of a GLU_TESS_BOUNDARY_ONLY call, an
+ alternative to reversing the vertex order is to reverse the sign of
+ the supplied normal. For example in the x-y plane, call
+ gluTessNormal( tess, 0.0, 0.0, -1.0 ).
+
+
+Performance
+-----------
+
+ The tesselator is not intended for immediate-mode rendering; when
+ possible the output should be cached in a user structure or display
+ list. General polygon tesselation is an inherently difficult problem,
+ especially given the goal of extreme robustness.
+
+ The implementation makes an effort to output a small number of fans
+ and strips; this should improve the rendering performance when the
+ output is used in a display list.
+
+ Single-contour input polygons are first tested to see whether they can
+ be rendered as a triangle fan with respect to the first vertex (to
+ avoid running the full decomposition algorithm on convex polygons).
+ Non-convex polygons may be rendered by this "fast path" as well, if
+ the algorithm gets lucky in its choice of a starting vertex.
+
+ For best performance follow these guidelines:
+
+ - supply the polygon normal, if available, using gluTessNormal().
+ This represents about 10% of the computation time. For example,
+ if all polygons lie in the x-y plane, use gluTessNormal(tess,0,0,1).
+
+ - render many polygons using the same tesselator object, rather than
+ allocating a new tesselator for each one. (In a multi-threaded,
+ multi-processor environment you may get better performance using
+ several tesselators.)
+
+
+Comparison with the GLU tesselator
+----------------------------------
+
+ On polygons which make it through the "fast path", the tesselator is
+ 3 to 5 times faster than the GLU tesselator.
+
+ On polygons which don't make it through the fast path (but which don't
+ have self-intersections or degeneracies), it is about 2 times slower.
+
+ On polygons with self-intersections or degeneraces, there is nothing
+ to compare against.
+
+ The new tesselator generates many more fans and strips, reducing the
+ number of vertices that need to be sent to the hardware.
+
+ Key to the statistics:
+
+ vert number of input vertices on all contours
+ cntr number of input contours
+ tri number of triangles in all output primitives
+ strip number of triangle strips
+ fan number of triangle fans
+ ind number of independent triangles
+ ms number of milliseconds for tesselation
+ (on a 150MHz R4400 Indy)
+
+ Convex polygon examples:
+
+New: 3 vert, 1 cntr, 1 tri, 0 strip, 0 fan, 1 ind, 0.0459 ms
+Old: 3 vert, 1 cntr, 1 tri, 0 strip, 0 fan, 1 ind, 0.149 ms
+New: 4 vert, 1 cntr, 2 tri, 0 strip, 1 fan, 0 ind, 0.0459 ms
+Old: 4 vert, 1 cntr, 2 tri, 0 strip, 0 fan, 2 ind, 0.161 ms
+New: 36 vert, 1 cntr, 34 tri, 0 strip, 1 fan, 0 ind, 0.153 ms
+Old: 36 vert, 1 cntr, 34 tri, 0 strip, 0 fan, 34 ind, 0.621 ms
+
+ Concave single-contour polygons:
+
+New: 5 vert, 1 cntr, 3 tri, 0 strip, 1 fan, 0 ind, 0.052 ms
+Old: 5 vert, 1 cntr, 3 tri, 0 strip, 0 fan, 3 ind, 0.252 ms
+New: 19 vert, 1 cntr, 17 tri, 2 strip, 2 fan, 1 ind, 0.911 ms
+Old: 19 vert, 1 cntr, 17 tri, 0 strip, 0 fan, 17 ind, 0.529 ms
+New: 151 vert, 1 cntr, 149 tri, 13 strip, 18 fan, 3 ind, 6.82 ms
+Old: 151 vert, 1 cntr, 149 tri, 0 strip, 3 fan, 143 ind, 2.7 ms
+New: 574 vert, 1 cntr, 572 tri, 59 strip, 54 fan, 11 ind, 26.6 ms
+Old: 574 vert, 1 cntr, 572 tri, 0 strip, 31 fan, 499 ind, 12.4 ms
+
+ Multiple contours, but no intersections:
+
+New: 7 vert, 2 cntr, 7 tri, 1 strip, 0 fan, 0 ind, 0.527 ms
+Old: 7 vert, 2 cntr, 7 tri, 0 strip, 0 fan, 7 ind, 0.274 ms
+New: 81 vert, 6 cntr, 89 tri, 9 strip, 7 fan, 6 ind, 3.88 ms
+Old: 81 vert, 6 cntr, 89 tri, 0 strip, 13 fan, 61 ind, 2.2 ms
+New: 391 vert, 19 cntr, 413 tri, 37 strip, 32 fan, 26 ind, 20.2 ms
+Old: 391 vert, 19 cntr, 413 tri, 0 strip, 25 fan, 363 ind, 8.68 ms
+
+ Self-intersecting and degenerate examples:
+
+Bowtie: 4 vert, 1 cntr, 2 tri, 0 strip, 0 fan, 2 ind, 0.483 ms
+Star: 5 vert, 1 cntr, 5 tri, 0 strip, 0 fan, 5 ind, 0.91 ms
+Random: 24 vert, 7 cntr, 46 tri, 2 strip, 12 fan, 7 ind, 5.32 ms
+Font: 333 vert, 2 cntr, 331 tri, 32 strip, 16 fan, 3 ind, 14.1 ms
+: 167 vert, 35 cntr, 254 tri, 8 strip, 56 fan, 52 ind, 46.3 ms
+: 78 vert, 1 cntr, 2675 tri, 148 strip, 207 fan, 180 ind, 243 ms
+: 12480 vert, 2 cntr, 12478 tri, 736 strip,1275 fan, 5 ind, 1010 ms
diff --git a/third_party/glu/libtess/alg-outline b/third_party/glu/libtess/alg-outline
new file mode 100644
index 0000000..91ed7f3
--- /dev/null
+++ b/third_party/glu/libtess/alg-outline
@@ -0,0 +1,229 @@
+/*
+** $Header: /cvs/projects/ogl-sample/main/gfx/lib/glu/libtess/alg-outline,v 1.1 2000/04/26 05:53:59 ljp Exp $
+*/
+
+This is only a very brief overview. There is quite a bit of
+additional documentation in the source code itself.
+
+
+Goals of robust tesselation
+---------------------------
+
+The tesselation algorithm is fundamentally a 2D algorithm. We
+initially project all data into a plane; our goal is to robustly
+tesselate the projected data. The same topological tesselation is
+then applied to the input data.
+
+Topologically, the output should always be a tesselation. If the
+input is even slightly non-planar, then some triangles will
+necessarily be back-facing when viewed from some angles, but the goal
+is to minimize this effect.
+
+The algorithm needs some capability of cleaning up the input data as
+well as the numerical errors in its own calculations. One way to do
+this is to specify a tolerance as defined above, and clean up the
+input and output during the line sweep process. At the very least,
+the algorithm must handle coincident vertices, vertices incident to an
+edge, and coincident edges.
+
+
+Phases of the algorithm
+-----------------------
+
+1. Find the polygon normal N.
+2. Project the vertex data onto a plane. It does not need to be
+ perpendicular to the normal, eg. we can project onto the plane
+ perpendicular to the coordinate axis whose dot product with N
+ is largest.
+3. Using a line-sweep algorithm, partition the plane into x-monotone
+ regions. Any vertical line intersects an x-monotone region in
+ at most one interval.
+4. Triangulate the x-monotone regions.
+5. Group the triangles into strips and fans.
+
+
+Finding the normal vector
+-------------------------
+
+A common way to find a polygon normal is to compute the signed area
+when the polygon is projected along the three coordinate axes. We
+can't do this, since contours can have zero area without being
+degenerate (eg. a bowtie).
+
+We fit a plane to the vertex data, ignoring how they are connected
+into contours. Ideally this would be a least-squares fit; however for
+our purpose the accuracy of the normal is not important. Instead we
+find three vertices which are widely separated, and compute the normal
+to the triangle they form. The vertices are chosen so that the
+triangle has an area at least 1/sqrt(3) times the largest area of any
+triangle formed using the input vertices.
+
+The contours do affect the orientation of the normal; after computing
+the normal, we check that the sum of the signed contour areas is
+non-negative, and reverse the normal if necessary.
+
+
+Projecting the vertices
+-----------------------
+
+We project the vertices onto a plane perpendicular to one of the three
+coordinate axes. This helps numerical accuracy by removing a
+transformation step between the original input data and the data
+processed by the algorithm. The projection also compresses the input
+data; the 2D distance between vertices after projection may be smaller
+than the original 2D distance. However by choosing the coordinate
+axis whose dot product with the normal is greatest, the compression
+factor is at most 1/sqrt(3).
+
+Even though the *accuracy* of the normal is not that important (since
+we are projecting perpendicular to a coordinate axis anyway), the
+*robustness* of the computation is important. For example, if there
+are many vertices which lie almost along a line, and one vertex V
+which is well-separated from the line, then our normal computation
+should involve V otherwise the results will be garbage.
+
+The advantage of projecting perpendicular to the polygon normal is
+that computed intersection points will be as close as possible to
+their ideal locations. To get this behavior, define TRUE_PROJECT.
+
+
+The Line Sweep
+--------------
+
+There are three data structures: the mesh, the event queue, and the
+edge dictionary.
+
+The mesh is a "quad-edge" data structure which records the topology of
+the current decomposition; for details see the include file "mesh.h".
+
+The event queue simply holds all vertices (both original and computed
+ones), organized so that we can quickly extract the vertex with the
+minimum x-coord (and among those, the one with the minimum y-coord).
+
+The edge dictionary describes the current intersection of the sweep
+line with the regions of the polygon. This is just an ordering of the
+edges which intersect the sweep line, sorted by their current order of
+intersection. For each pair of edges, we store some information about
+the monotone region between them -- these are call "active regions"
+(since they are crossed by the current sweep line).
+
+The basic algorithm is to sweep from left to right, processing each
+vertex. The processed portion of the mesh (left of the sweep line) is
+a planar decomposition. As we cross each vertex, we update the mesh
+and the edge dictionary, then we check any newly adjacent pairs of
+edges to see if they intersect.
+
+A vertex can have any number of edges. Vertices with many edges can
+be created as vertices are merged and intersection points are
+computed. For unprocessed vertices (right of the sweep line), these
+edges are in no particular order around the vertex; for processed
+vertices, the topological ordering should match the geometric ordering.
+
+The vertex processing happens in two phases: first we process are the
+left-going edges (all these edges are currently in the edge
+dictionary). This involves:
+
+ - deleting the left-going edges from the dictionary;
+ - relinking the mesh if necessary, so that the order of these edges around
+ the event vertex matches the order in the dictionary;
+ - marking any terminated regions (regions which lie between two left-going
+ edges) as either "inside" or "outside" according to their winding number.
+
+When there are no left-going edges, and the event vertex is in an
+"interior" region, we need to add an edge (to split the region into
+monotone pieces). To do this we simply join the event vertex to the
+rightmost left endpoint of the upper or lower edge of the containing
+region.
+
+Then we process the right-going edges. This involves:
+
+ - inserting the edges in the edge dictionary;
+ - computing the winding number of any newly created active regions.
+ We can compute this incrementally using the winding of each edge
+ that we cross as we walk through the dictionary.
+ - relinking the mesh if necessary, so that the order of these edges around
+ the event vertex matches the order in the dictionary;
+ - checking any newly adjacent edges for intersection and/or merging.
+
+If there are no right-going edges, again we need to add one to split
+the containing region into monotone pieces. In our case it is most
+convenient to add an edge to the leftmost right endpoint of either
+containing edge; however we may need to change this later (see the
+code for details).
+
+
+Invariants
+----------
+
+These are the most important invariants maintained during the sweep.
+We define a function VertLeq(v1,v2) which defines the order in which
+vertices cross the sweep line, and a function EdgeLeq(e1,e2; loc)
+which says whether e1 is below e2 at the sweep event location "loc".
+This function is defined only at sweep event locations which lie
+between the rightmost left endpoint of {e1,e2}, and the leftmost right
+endpoint of {e1,e2}.
+
+Invariants for the Edge Dictionary.
+
+ - Each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2)
+ at any valid location of the sweep event.
+ - If EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2
+ share a common endpoint.
+ - For each e in the dictionary, e->Dst has been processed but not e->Org.
+ - Each edge e satisfies VertLeq(e->Dst,event) && VertLeq(event,e->Org)
+ where "event" is the current sweep line event.
+ - No edge e has zero length.
+ - No two edges have identical left and right endpoints.
+
+Invariants for the Mesh (the processed portion).
+
+ - The portion of the mesh left of the sweep line is a planar graph,
+ ie. there is *some* way to embed it in the plane.
+ - No processed edge has zero length.
+ - No two processed vertices have identical coordinates.
+ - Each "inside" region is monotone, ie. can be broken into two chains
+ of monotonically increasing vertices according to VertLeq(v1,v2)
+ - a non-invariant: these chains may intersect (slightly) due to
+ numerical errors, but this does not affect the algorithm's operation.
+
+Invariants for the Sweep.
+
+ - If a vertex has any left-going edges, then these must be in the edge
+ dictionary at the time the vertex is processed.
+ - If an edge is marked "fixUpperEdge" (it is a temporary edge introduced
+ by ConnectRightVertex), then it is the only right-going edge from
+ its associated vertex. (This says that these edges exist only
+ when it is necessary.)
+
+
+Robustness
+----------
+
+The key to the robustness of the algorithm is maintaining the
+invariants above, especially the correct ordering of the edge
+dictionary. We achieve this by:
+
+ 1. Writing the numerical computations for maximum precision rather
+ than maximum speed.
+
+ 2. Making no assumptions at all about the results of the edge
+ intersection calculations -- for sufficiently degenerate inputs,
+ the computed location is not much better than a random number.
+
+ 3. When numerical errors violate the invariants, restore them
+ by making *topological* changes when necessary (ie. relinking
+ the mesh structure).
+
+
+Triangulation and Grouping
+--------------------------
+
+We finish the line sweep before doing any triangulation. This is
+because even after a monotone region is complete, there can be further
+changes to its vertex data because of further vertex merging.
+
+After triangulating all monotone regions, we want to group the
+triangles into fans and strips. We do this using a greedy approach.
+The triangulation itself is not optimized to reduce the number of
+primitives; we just try to get a reasonable decomposition of the
+computed triangulation.
diff --git a/third_party/glu/libtess/dict-list.h b/third_party/glu/libtess/dict-list.h
new file mode 100644
index 0000000..9c67c49
--- /dev/null
+++ b/third_party/glu/libtess/dict-list.h
@@ -0,0 +1,107 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/dict-list.h#5 $
+*/
+
+#ifndef __dict_list_h_
+#define __dict_list_h_
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define DictKey DictListKey
+#define Dict DictList
+#define DictNode DictListNode
+
+#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq)
+#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict)
+
+#define dictSearch(dict,key) __gl_dictListSearch(dict,key)
+#define dictInsert(dict,key) __gl_dictListInsert(dict,key)
+#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key)
+#define dictDelete(dict,node) __gl_dictListDelete(dict,node)
+
+#define dictKey(n) __gl_dictListKey(n)
+#define dictSucc(n) __gl_dictListSucc(n)
+#define dictPred(n) __gl_dictListPred(n)
+#define dictMin(d) __gl_dictListMin(d)
+#define dictMax(d) __gl_dictListMax(d)
+
+
+
+typedef void *DictKey;
+typedef struct Dict Dict;
+typedef struct DictNode DictNode;
+
+Dict *dictNewDict(
+ void *frame,
+ int (*leq)(void *frame, DictKey key1, DictKey key2) );
+
+void dictDeleteDict( Dict *dict );
+
+/* Search returns the node with the smallest key greater than or equal
+ * to the given key. If there is no such key, returns a node whose
+ * key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc.
+ */
+DictNode *dictSearch( Dict *dict, DictKey key );
+DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key );
+void dictDelete( Dict *dict, DictNode *node );
+
+#define __gl_dictListKey(n) ((n)->key)
+#define __gl_dictListSucc(n) ((n)->next)
+#define __gl_dictListPred(n) ((n)->prev)
+#define __gl_dictListMin(d) ((d)->head.next)
+#define __gl_dictListMax(d) ((d)->head.prev)
+#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k)))
+
+
+/*** Private data structures ***/
+
+struct DictNode {
+ DictKey key;
+ DictNode *next;
+ DictNode *prev;
+};
+
+struct Dict {
+ DictNode head;
+ void *frame;
+ int (*leq)(void *frame, DictKey key1, DictKey key2);
+};
+
+#endif
diff --git a/third_party/glu/libtess/dict.c b/third_party/glu/libtess/dict.c
new file mode 100644
index 0000000..e149fd5
--- /dev/null
+++ b/third_party/glu/libtess/dict.c
@@ -0,0 +1,117 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/dict.c#5 $
+*/
+
+#include <stddef.h>
+#include "dict-list.h"
+#include "memalloc.h"
+
+/* really __gl_dictListNewDict */
+Dict *dictNewDict( void *frame,
+ int (*leq)(void *frame, DictKey key1, DictKey key2) )
+{
+ Dict *dict = (Dict *) memAlloc( sizeof( Dict ));
+ DictNode *head;
+
+ if (dict == NULL) return NULL;
+
+ head = &dict->head;
+
+ head->key = NULL;
+ head->next = head;
+ head->prev = head;
+
+ dict->frame = frame;
+ dict->leq = leq;
+
+ return dict;
+}
+
+/* really __gl_dictListDeleteDict */
+void dictDeleteDict( Dict *dict )
+{
+ DictNode *node;
+
+ for( node = dict->head.next; node != &dict->head; node = node->next ) {
+ memFree( node );
+ }
+ memFree( dict );
+}
+
+/* really __gl_dictListInsertBefore */
+DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key )
+{
+ DictNode *newNode;
+
+ do {
+ node = node->prev;
+ } while( node->key != NULL && ! (*dict->leq)(dict->frame, node->key, key));
+
+ newNode = (DictNode *) memAlloc( sizeof( DictNode ));
+ if (newNode == NULL) return NULL;
+
+ newNode->key = key;
+ newNode->next = node->next;
+ node->next->prev = newNode;
+ newNode->prev = node;
+ node->next = newNode;
+
+ return newNode;
+}
+
+/* really __gl_dictListDelete */
+void dictDelete( Dict *dict, DictNode *node ) /*ARGSUSED*/
+{
+ node->next->prev = node->prev;
+ node->prev->next = node->next;
+ memFree( node );
+}
+
+/* really __gl_dictListSearch */
+DictNode *dictSearch( Dict *dict, DictKey key )
+{
+ DictNode *node = &dict->head;
+
+ do {
+ node = node->next;
+ } while( node->key != NULL && ! (*dict->leq)(dict->frame, key, node->key));
+
+ return node;
+}
diff --git a/third_party/glu/libtess/dict.h b/third_party/glu/libtess/dict.h
new file mode 100644
index 0000000..fee0769
--- /dev/null
+++ b/third_party/glu/libtess/dict.h
@@ -0,0 +1,109 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/dict.h#5 $
+*/
+
+#ifndef __dict_list_h_
+#define __dict_list_h_
+
+#include <sk_glu.h>
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define DictKey DictListKey
+#define Dict DictList
+#define DictNode DictListNode
+
+#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq)
+#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict)
+
+#define dictSearch(dict,key) __gl_dictListSearch(dict,key)
+#define dictInsert(dict,key) __gl_dictListInsert(dict,key)
+#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key)
+#define dictDelete(dict,node) __gl_dictListDelete(dict,node)
+
+#define dictKey(n) __gl_dictListKey(n)
+#define dictSucc(n) __gl_dictListSucc(n)
+#define dictPred(n) __gl_dictListPred(n)
+#define dictMin(d) __gl_dictListMin(d)
+#define dictMax(d) __gl_dictListMax(d)
+
+
+
+typedef void *DictKey;
+typedef struct Dict Dict;
+typedef struct DictNode DictNode;
+
+Dict *dictNewDict(
+ void *frame,
+ int (*leq)(void *frame, DictKey key1, DictKey key2) );
+
+void dictDeleteDict( Dict *dict );
+
+/* Search returns the node with the smallest key greater than or equal
+ * to the given key. If there is no such key, returns a node whose
+ * key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc.
+ */
+DictNode *dictSearch( Dict *dict, DictKey key );
+DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key );
+void dictDelete( Dict *dict, DictNode *node );
+
+#define __gl_dictListKey(n) ((n)->key)
+#define __gl_dictListSucc(n) ((n)->next)
+#define __gl_dictListPred(n) ((n)->prev)
+#define __gl_dictListMin(d) ((d)->head.next)
+#define __gl_dictListMax(d) ((d)->head.prev)
+#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k)))
+
+
+/*** Private data structures ***/
+
+struct DictNode {
+ DictKey key;
+ DictNode *next;
+ DictNode *prev;
+};
+
+struct Dict {
+ DictNode head;
+ void *frame;
+ int (*leq)(void *frame, DictKey key1, DictKey key2);
+};
+
+#endif
diff --git a/third_party/glu/libtess/geom.c b/third_party/glu/libtess/geom.c
new file mode 100644
index 0000000..461d8b4
--- /dev/null
+++ b/third_party/glu/libtess/geom.c
@@ -0,0 +1,271 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/geom.c#5 $
+*/
+
+#include "gluos.h"
+#include <assert.h>
+#include "mesh.h"
+#include "geom.h"
+
+int __gl_vertLeq( GLUvertex *u, GLUvertex *v )
+{
+ /* Returns TRUE if u is lexicographically <= v. */
+
+ return VertLeq( u, v );
+}
+
+GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w),
+ * evaluates the t-coord of the edge uw at the s-coord of the vertex v.
+ * Returns v->t - (uw)(v->s), ie. the signed distance from uw to v.
+ * If uw is vertical (and thus passes thru v), the result is zero.
+ *
+ * The calculation is extremely accurate and stable, even when v
+ * is very close to u or w. In particular if we set v->t = 0 and
+ * let r be the negated result (this evaluates (uw)(v->s)), then
+ * r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t).
+ */
+ GLdouble gapL, gapR;
+
+ assert( VertLeq( u, v ) && VertLeq( v, w ));
+
+ gapL = v->s - u->s;
+ gapR = w->s - v->s;
+
+ if( gapL + gapR > 0 ) {
+ if( gapL < gapR ) {
+ return (v->t - u->t) + (u->t - w->t) * (gapL / (gapL + gapR));
+ } else {
+ return (v->t - w->t) + (w->t - u->t) * (gapR / (gapL + gapR));
+ }
+ }
+ /* vertical line */
+ return 0;
+}
+
+GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* Returns a number whose sign matches EdgeEval(u,v,w) but which
+ * is cheaper to evaluate. Returns > 0, == 0 , or < 0
+ * as v is above, on, or below the edge uw.
+ */
+ GLdouble gapL, gapR;
+
+ assert( VertLeq( u, v ) && VertLeq( v, w ));
+
+ gapL = v->s - u->s;
+ gapR = w->s - v->s;
+
+ if( gapL + gapR > 0 ) {
+ return (v->t - w->t) * gapL + (v->t - u->t) * gapR;
+ }
+ /* vertical line */
+ return 0;
+}
+
+
+/***********************************************************************
+ * Define versions of EdgeSign, EdgeEval with s and t transposed.
+ */
+
+GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w),
+ * evaluates the t-coord of the edge uw at the s-coord of the vertex v.
+ * Returns v->s - (uw)(v->t), ie. the signed distance from uw to v.
+ * If uw is vertical (and thus passes thru v), the result is zero.
+ *
+ * The calculation is extremely accurate and stable, even when v
+ * is very close to u or w. In particular if we set v->s = 0 and
+ * let r be the negated result (this evaluates (uw)(v->t)), then
+ * r is guaranteed to satisfy MIN(u->s,w->s) <= r <= MAX(u->s,w->s).
+ */
+ GLdouble gapL, gapR;
+
+ assert( TransLeq( u, v ) && TransLeq( v, w ));
+
+ gapL = v->t - u->t;
+ gapR = w->t - v->t;
+
+ if( gapL + gapR > 0 ) {
+ if( gapL < gapR ) {
+ return (v->s - u->s) + (u->s - w->s) * (gapL / (gapL + gapR));
+ } else {
+ return (v->s - w->s) + (w->s - u->s) * (gapR / (gapL + gapR));
+ }
+ }
+ /* vertical line */
+ return 0;
+}
+
+GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* Returns a number whose sign matches TransEval(u,v,w) but which
+ * is cheaper to evaluate. Returns > 0, == 0 , or < 0
+ * as v is above, on, or below the edge uw.
+ */
+ GLdouble gapL, gapR;
+
+ assert( TransLeq( u, v ) && TransLeq( v, w ));
+
+ gapL = v->t - u->t;
+ gapR = w->t - v->t;
+
+ if( gapL + gapR > 0 ) {
+ return (v->s - w->s) * gapL + (v->s - u->s) * gapR;
+ }
+ /* vertical line */
+ return 0;
+}
+
+
+int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* For almost-degenerate situations, the results are not reliable.
+ * Unless the floating-point arithmetic can be performed without
+ * rounding errors, *any* implementation will give incorrect results
+ * on some degenerate inputs, so the client must have some way to
+ * handle this situation.
+ */
+ return (u->s*(v->t - w->t) + v->s*(w->t - u->t) + w->s*(u->t - v->t)) >= 0;
+}
+
+/* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b),
+ * or (x+y)/2 if a==b==0. It requires that a,b >= 0, and enforces
+ * this in the rare case that one argument is slightly negative.
+ * The implementation is extremely stable numerically.
+ * In particular it guarantees that the result r satisfies
+ * MIN(x,y) <= r <= MAX(x,y), and the results are very accurate
+ * even when a and b differ greatly in magnitude.
+ */
+#define RealInterpolate(a,x,b,y) \
+ (a = (a < 0) ? 0 : a, b = (b < 0) ? 0 : b, \
+ ((a <= b) ? ((b == 0) ? ((x+y) / 2) \
+ : (x + (y-x) * (a/(a+b)))) \
+ : (y + (x-y) * (b/(a+b)))))
+
+#ifndef FOR_TRITE_TEST_PROGRAM
+#define Interpolate(a,x,b,y) RealInterpolate(a,x,b,y)
+#else
+
+/* Claim: the ONLY property the sweep algorithm relies on is that
+ * MIN(x,y) <= r <= MAX(x,y). This is a nasty way to test that.
+ */
+#include <stdlib.h>
+extern int RandomInterpolate;
+
+GLdouble Interpolate( GLdouble a, GLdouble x, GLdouble b, GLdouble y)
+{
+printf("*********************%d\n",RandomInterpolate);
+ if( RandomInterpolate ) {
+ a = 1.2 * drand48() - 0.1;
+ a = (a < 0) ? 0 : ((a > 1) ? 1 : a);
+ b = 1.0 - a;
+ }
+ return RealInterpolate(a,x,b,y);
+}
+
+#endif
+
+#define Swap(a,b) do { GLUvertex *t = a; a = b; b = t; } while(0)
+
+void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1,
+ GLUvertex *o2, GLUvertex *d2,
+ GLUvertex *v )
+/* Given edges (o1,d1) and (o2,d2), compute their point of intersection.
+ * The computed point is guaranteed to lie in the intersection of the
+ * bounding rectangles defined by each edge.
+ */
+{
+ GLdouble z1, z2;
+
+ /* This is certainly not the most efficient way to find the intersection
+ * of two line segments, but it is very numerically stable.
+ *
+ * Strategy: find the two middle vertices in the VertLeq ordering,
+ * and interpolate the intersection s-value from these. Then repeat
+ * using the TransLeq ordering to find the intersection t-value.
+ */
+
+ if( ! VertLeq( o1, d1 )) { Swap( o1, d1 ); }
+ if( ! VertLeq( o2, d2 )) { Swap( o2, d2 ); }
+ if( ! VertLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
+
+ if( ! VertLeq( o2, d1 )) {
+ /* Technically, no intersection -- do our best */
+ v->s = (o2->s + d1->s) / 2;
+ } else if( VertLeq( d1, d2 )) {
+ /* Interpolate between o2 and d1 */
+ z1 = EdgeEval( o1, o2, d1 );
+ z2 = EdgeEval( o2, d1, d2 );
+ if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+ v->s = Interpolate( z1, o2->s, z2, d1->s );
+ } else {
+ /* Interpolate between o2 and d2 */
+ z1 = EdgeSign( o1, o2, d1 );
+ z2 = -EdgeSign( o1, d2, d1 );
+ if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+ v->s = Interpolate( z1, o2->s, z2, d2->s );
+ }
+
+ /* Now repeat the process for t */
+
+ if( ! TransLeq( o1, d1 )) { Swap( o1, d1 ); }
+ if( ! TransLeq( o2, d2 )) { Swap( o2, d2 ); }
+ if( ! TransLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
+
+ if( ! TransLeq( o2, d1 )) {
+ /* Technically, no intersection -- do our best */
+ v->t = (o2->t + d1->t) / 2;
+ } else if( TransLeq( d1, d2 )) {
+ /* Interpolate between o2 and d1 */
+ z1 = TransEval( o1, o2, d1 );
+ z2 = TransEval( o2, d1, d2 );
+ if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+ v->t = Interpolate( z1, o2->t, z2, d1->t );
+ } else {
+ /* Interpolate between o2 and d2 */
+ z1 = TransSign( o1, o2, d1 );
+ z2 = -TransSign( o1, d2, d1 );
+ if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+ v->t = Interpolate( z1, o2->t, z2, d2->t );
+ }
+}
diff --git a/third_party/glu/libtess/geom.h b/third_party/glu/libtess/geom.h
new file mode 100644
index 0000000..b4d0c66
--- /dev/null
+++ b/third_party/glu/libtess/geom.h
@@ -0,0 +1,90 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/geom.h#5 $
+*/
+
+#ifndef __geom_h_
+#define __geom_h_
+
+#include "mesh.h"
+
+#ifdef NO_BRANCH_CONDITIONS
+/* MIPS architecture has special instructions to evaluate boolean
+ * conditions -- more efficient than branching, IF you can get the
+ * compiler to generate the right instructions (SGI compiler doesn't)
+ */
+#define VertEq(u,v) (((u)->s == (v)->s) & ((u)->t == (v)->t))
+#define VertLeq(u,v) (((u)->s < (v)->s) | \
+ ((u)->s == (v)->s & (u)->t <= (v)->t))
+#else
+#define VertEq(u,v) ((u)->s == (v)->s && (u)->t == (v)->t)
+#define VertLeq(u,v) (((u)->s < (v)->s) || \
+ ((u)->s == (v)->s && (u)->t <= (v)->t))
+#endif
+
+#define EdgeEval(u,v,w) __gl_edgeEval(u,v,w)
+#define EdgeSign(u,v,w) __gl_edgeSign(u,v,w)
+
+/* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */
+
+#define TransLeq(u,v) (((u)->t < (v)->t) || \
+ ((u)->t == (v)->t && (u)->s <= (v)->s))
+#define TransEval(u,v,w) __gl_transEval(u,v,w)
+#define TransSign(u,v,w) __gl_transSign(u,v,w)
+
+
+#define EdgeGoesLeft(e) VertLeq( (e)->Dst, (e)->Org )
+#define EdgeGoesRight(e) VertLeq( (e)->Org, (e)->Dst )
+
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+#define VertL1dist(u,v) (ABS(u->s - v->s) + ABS(u->t - v->t))
+
+#define VertCCW(u,v,w) __gl_vertCCW(u,v,w)
+
+int __gl_vertLeq( GLUvertex *u, GLUvertex *v );
+GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1,
+ GLUvertex *o2, GLUvertex *d2,
+ GLUvertex *v );
+
+#endif
diff --git a/third_party/glu/libtess/memalloc.c b/third_party/glu/libtess/memalloc.c
new file mode 100644
index 0000000..bd5b4ac
--- /dev/null
+++ b/third_party/glu/libtess/memalloc.c
@@ -0,0 +1,62 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/memalloc.c#5 $
+*/
+
+#include "memalloc.h"
+#include "string.h"
+
+int __gl_memInit( size_t maxFast )
+{
+#ifndef NO_MALLOPT
+/* mallopt( M_MXFAST, maxFast );*/
+#ifdef MEMORY_DEBUG
+ mallopt( M_DEBUG, 1 );
+#endif
+#endif
+ return 1;
+}
+
+#ifdef MEMORY_DEBUG
+void *__gl_memAlloc( size_t n )
+{
+ return memset( malloc( n ), 0xa5, n );
+}
+#endif
+
diff --git a/third_party/glu/libtess/memalloc.h b/third_party/glu/libtess/memalloc.h
new file mode 100644
index 0000000..7133ada
--- /dev/null
+++ b/third_party/glu/libtess/memalloc.h
@@ -0,0 +1,62 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/memalloc.h#5 $
+*/
+
+#ifndef __memalloc_simple_h_
+#define __memalloc_simple_h_
+
+#include <sk_glu.h>
+#include <stdlib.h>
+
+#define memRealloc realloc
+#define memFree free
+
+#define memInit __gl_memInit
+/*extern void __gl_memInit( size_t );*/
+extern int __gl_memInit( size_t );
+
+#ifndef MEMORY_DEBUG
+#define memAlloc malloc
+#else
+#define memAlloc __gl_memAlloc
+extern void * __gl_memAlloc( size_t );
+#endif
+
+#endif
diff --git a/third_party/glu/libtess/mesh.c b/third_party/glu/libtess/mesh.c
new file mode 100644
index 0000000..7305fab
--- /dev/null
+++ b/third_party/glu/libtess/mesh.c
@@ -0,0 +1,796 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/mesh.c#6 $
+*/
+
+#include "gluos.h"
+#include <stddef.h>
+#include <assert.h>
+#include "mesh.h"
+#include "memalloc.h"
+
+#define TRUE 1
+#define FALSE 0
+
+static GLUvertex *allocVertex()
+{
+ return (GLUvertex *)memAlloc( sizeof( GLUvertex ));
+}
+
+static GLUface *allocFace()
+{
+ return (GLUface *)memAlloc( sizeof( GLUface ));
+}
+
+/************************ Utility Routines ************************/
+
+/* Allocate and free half-edges in pairs for efficiency.
+ * The *only* place that should use this fact is allocation/free.
+ */
+typedef struct { GLUhalfEdge e, eSym; } EdgePair;
+
+/* MakeEdge creates a new pair of half-edges which form their own loop.
+ * No vertex or face structures are allocated, but these must be assigned
+ * before the current edge operation is completed.
+ */
+static GLUhalfEdge *MakeEdge( GLUhalfEdge *eNext )
+{
+ GLUhalfEdge *e;
+ GLUhalfEdge *eSym;
+ GLUhalfEdge *ePrev;
+ EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair ));
+ if (pair == NULL) return NULL;
+
+ e = &pair->e;
+ eSym = &pair->eSym;
+
+ /* Make sure eNext points to the first edge of the edge pair */
+ if( eNext->Sym < eNext ) { eNext = eNext->Sym; }
+
+ /* Insert in circular doubly-linked list before eNext.
+ * Note that the prev pointer is stored in Sym->next.
+ */
+ ePrev = eNext->Sym->next;
+ eSym->next = ePrev;
+ ePrev->Sym->next = e;
+ e->next = eNext;
+ eNext->Sym->next = eSym;
+
+ e->Sym = eSym;
+ e->Onext = e;
+ e->Lnext = eSym;
+ e->Org = NULL;
+ e->Lface = NULL;
+ e->winding = 0;
+ e->activeRegion = NULL;
+
+ eSym->Sym = e;
+ eSym->Onext = eSym;
+ eSym->Lnext = e;
+ eSym->Org = NULL;
+ eSym->Lface = NULL;
+ eSym->winding = 0;
+ eSym->activeRegion = NULL;
+
+ return e;
+}
+
+/* Splice( a, b ) is best described by the Guibas/Stolfi paper or the
+ * CS348a notes (see mesh.h). Basically it modifies the mesh so that
+ * a->Onext and b->Onext are exchanged. This can have various effects
+ * depending on whether a and b belong to different face or vertex rings.
+ * For more explanation see __gl_meshSplice() below.
+ */
+static void Splice( GLUhalfEdge *a, GLUhalfEdge *b )
+{
+ GLUhalfEdge *aOnext = a->Onext;
+ GLUhalfEdge *bOnext = b->Onext;
+
+ aOnext->Sym->Lnext = b;
+ bOnext->Sym->Lnext = a;
+ a->Onext = bOnext;
+ b->Onext = aOnext;
+}
+
+/* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the
+ * origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives
+ * a place to insert the new vertex in the global vertex list. We insert
+ * the new vertex *before* vNext so that algorithms which walk the vertex
+ * list will not see the newly created vertices.
+ */
+static void MakeVertex( GLUvertex *newVertex,
+ GLUhalfEdge *eOrig, GLUvertex *vNext )
+{
+ GLUhalfEdge *e;
+ GLUvertex *vPrev;
+ GLUvertex *vNew = newVertex;
+
+ assert(vNew != NULL);
+
+ /* insert in circular doubly-linked list before vNext */
+ vPrev = vNext->prev;
+ vNew->prev = vPrev;
+ vPrev->next = vNew;
+ vNew->next = vNext;
+ vNext->prev = vNew;
+
+ vNew->anEdge = eOrig;
+ vNew->data = NULL;
+ /* leave coords, s, t undefined */
+
+ /* fix other edges on this vertex loop */
+ e = eOrig;
+ do {
+ e->Org = vNew;
+ e = e->Onext;
+ } while( e != eOrig );
+}
+
+/* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left
+ * face of all edges in the face loop to which eOrig belongs. "fNext" gives
+ * a place to insert the new face in the global face list. We insert
+ * the new face *before* fNext so that algorithms which walk the face
+ * list will not see the newly created faces.
+ */
+static void MakeFace( GLUface *newFace, GLUhalfEdge *eOrig, GLUface *fNext )
+{
+ GLUhalfEdge *e;
+ GLUface *fPrev;
+ GLUface *fNew = newFace;
+
+ assert(fNew != NULL);
+
+ /* insert in circular doubly-linked list before fNext */
+ fPrev = fNext->prev;
+ fNew->prev = fPrev;
+ fPrev->next = fNew;
+ fNew->next = fNext;
+ fNext->prev = fNew;
+
+ fNew->anEdge = eOrig;
+ fNew->data = NULL;
+ fNew->trail = NULL;
+ fNew->marked = FALSE;
+
+ /* The new face is marked "inside" if the old one was. This is a
+ * convenience for the common case where a face has been split in two.
+ */
+ fNew->inside = fNext->inside;
+
+ /* fix other edges on this face loop */
+ e = eOrig;
+ do {
+ e->Lface = fNew;
+ e = e->Lnext;
+ } while( e != eOrig );
+}
+
+/* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym),
+ * and removes from the global edge list.
+ */
+static void KillEdge( GLUhalfEdge *eDel )
+{
+ GLUhalfEdge *ePrev, *eNext;
+
+ /* Half-edges are allocated in pairs, see EdgePair above */
+ if( eDel->Sym < eDel ) { eDel = eDel->Sym; }
+
+ /* delete from circular doubly-linked list */
+ eNext = eDel->next;
+ ePrev = eDel->Sym->next;
+ eNext->Sym->next = ePrev;
+ ePrev->Sym->next = eNext;
+
+ memFree( eDel );
+}
+
+
+/* KillVertex( vDel ) destroys a vertex and removes it from the global
+ * vertex list. It updates the vertex loop to point to a given new vertex.
+ */
+static void KillVertex( GLUvertex *vDel, GLUvertex *newOrg )
+{
+ GLUhalfEdge *e, *eStart = vDel->anEdge;
+ GLUvertex *vPrev, *vNext;
+
+ /* change the origin of all affected edges */
+ e = eStart;
+ do {
+ e->Org = newOrg;
+ e = e->Onext;
+ } while( e != eStart );
+
+ /* delete from circular doubly-linked list */
+ vPrev = vDel->prev;
+ vNext = vDel->next;
+ vNext->prev = vPrev;
+ vPrev->next = vNext;
+
+ memFree( vDel );
+}
+
+/* KillFace( fDel ) destroys a face and removes it from the global face
+ * list. It updates the face loop to point to a given new face.
+ */
+static void KillFace( GLUface *fDel, GLUface *newLface )
+{
+ GLUhalfEdge *e, *eStart = fDel->anEdge;
+ GLUface *fPrev, *fNext;
+
+ /* change the left face of all affected edges */
+ e = eStart;
+ do {
+ e->Lface = newLface;
+ e = e->Lnext;
+ } while( e != eStart );
+
+ /* delete from circular doubly-linked list */
+ fPrev = fDel->prev;
+ fNext = fDel->next;
+ fNext->prev = fPrev;
+ fPrev->next = fNext;
+
+ memFree( fDel );
+}
+
+
+/****************** Basic Edge Operations **********************/
+
+/* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
+ * The loop consists of the two new half-edges.
+ */
+GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh )
+{
+ GLUvertex *newVertex1= allocVertex();
+ GLUvertex *newVertex2= allocVertex();
+ GLUface *newFace= allocFace();
+ GLUhalfEdge *e;
+
+ /* if any one is null then all get freed */
+ if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) {
+ if (newVertex1 != NULL) memFree(newVertex1);
+ if (newVertex2 != NULL) memFree(newVertex2);
+ if (newFace != NULL) memFree(newFace);
+ return NULL;
+ }
+
+ e = MakeEdge( &mesh->eHead );
+ if (e == NULL) return NULL;
+
+ MakeVertex( newVertex1, e, &mesh->vHead );
+ MakeVertex( newVertex2, e->Sym, &mesh->vHead );
+ MakeFace( newFace, e, &mesh->fHead );
+ return e;
+}
+
+
+/* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
+ * mesh connectivity and topology. It changes the mesh so that
+ * eOrg->Onext <- OLD( eDst->Onext )
+ * eDst->Onext <- OLD( eOrg->Onext )
+ * where OLD(...) means the value before the meshSplice operation.
+ *
+ * This can have two effects on the vertex structure:
+ * - if eOrg->Org != eDst->Org, the two vertices are merged together
+ * - if eOrg->Org == eDst->Org, the origin is split into two vertices
+ * In both cases, eDst->Org is changed and eOrg->Org is untouched.
+ *
+ * Similarly (and independently) for the face structure,
+ * - if eOrg->Lface == eDst->Lface, one loop is split into two
+ * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
+ * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
+ *
+ * Some special cases:
+ * If eDst == eOrg, the operation has no effect.
+ * If eDst == eOrg->Lnext, the new face will have a single edge.
+ * If eDst == eOrg->Lprev, the old face will have a single edge.
+ * If eDst == eOrg->Onext, the new vertex will have a single edge.
+ * If eDst == eOrg->Oprev, the old vertex will have a single edge.
+ */
+int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
+{
+ int joiningLoops = FALSE;
+ int joiningVertices = FALSE;
+
+ if( eOrg == eDst ) return 1;
+
+ if( eDst->Org != eOrg->Org ) {
+ /* We are merging two disjoint vertices -- destroy eDst->Org */
+ joiningVertices = TRUE;
+ KillVertex( eDst->Org, eOrg->Org );
+ }
+ if( eDst->Lface != eOrg->Lface ) {
+ /* We are connecting two disjoint loops -- destroy eDst->Lface */
+ joiningLoops = TRUE;
+ KillFace( eDst->Lface, eOrg->Lface );
+ }
+
+ /* Change the edge structure */
+ Splice( eDst, eOrg );
+
+ if( ! joiningVertices ) {
+ GLUvertex *newVertex= allocVertex();
+ if (newVertex == NULL) return 0;
+
+ /* We split one vertex into two -- the new vertex is eDst->Org.
+ * Make sure the old vertex points to a valid half-edge.
+ */
+ MakeVertex( newVertex, eDst, eOrg->Org );
+ eOrg->Org->anEdge = eOrg;
+ }
+ if( ! joiningLoops ) {
+ GLUface *newFace= allocFace();
+ if (newFace == NULL) return 0;
+
+ /* We split one loop into two -- the new loop is eDst->Lface.
+ * Make sure the old face points to a valid half-edge.
+ */
+ MakeFace( newFace, eDst, eOrg->Lface );
+ eOrg->Lface->anEdge = eOrg;
+ }
+
+ return 1;
+}
+
+
+/* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
+ * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
+ * eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
+ * the newly created loop will contain eDel->Dst. If the deletion of eDel
+ * would create isolated vertices, those are deleted as well.
+ *
+ * This function could be implemented as two calls to __gl_meshSplice
+ * plus a few calls to memFree, but this would allocate and delete
+ * unnecessary vertices and faces.
+ */
+int __gl_meshDelete( GLUhalfEdge *eDel )
+{
+ GLUhalfEdge *eDelSym = eDel->Sym;
+ int joiningLoops = FALSE;
+
+ /* First step: disconnect the origin vertex eDel->Org. We make all
+ * changes to get a consistent mesh in this "intermediate" state.
+ */
+ if( eDel->Lface != eDel->Rface ) {
+ /* We are joining two loops into one -- remove the left face */
+ joiningLoops = TRUE;
+ KillFace( eDel->Lface, eDel->Rface );
+ }
+
+ if( eDel->Onext == eDel ) {
+ KillVertex( eDel->Org, NULL );
+ } else {
+ /* Make sure that eDel->Org and eDel->Rface point to valid half-edges */
+ eDel->Rface->anEdge = eDel->Oprev;
+ eDel->Org->anEdge = eDel->Onext;
+
+ Splice( eDel, eDel->Oprev );
+ if( ! joiningLoops ) {
+ GLUface *newFace= allocFace();
+ if (newFace == NULL) return 0;
+
+ /* We are splitting one loop into two -- create a new loop for eDel. */
+ MakeFace( newFace, eDel, eDel->Lface );
+ }
+ }
+
+ /* Claim: the mesh is now in a consistent state, except that eDel->Org
+ * may have been deleted. Now we disconnect eDel->Dst.
+ */
+ if( eDelSym->Onext == eDelSym ) {
+ KillVertex( eDelSym->Org, NULL );
+ KillFace( eDelSym->Lface, NULL );
+ } else {
+ /* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */
+ eDel->Lface->anEdge = eDelSym->Oprev;
+ eDelSym->Org->anEdge = eDelSym->Onext;
+ Splice( eDelSym, eDelSym->Oprev );
+ }
+
+ /* Any isolated vertices or faces have already been freed. */
+ KillEdge( eDel );
+
+ return 1;
+}
+
+
+/******************** Other Edge Operations **********************/
+
+/* All these routines can be implemented with the basic edge
+ * operations above. They are provided for convenience and efficiency.
+ */
+
+
+/* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
+ * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
+ * eOrg and eNew will have the same left face.
+ */
+GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg )
+{
+ GLUhalfEdge *eNewSym;
+ GLUhalfEdge *eNew = MakeEdge( eOrg );
+ if (eNew == NULL) return NULL;
+
+ eNewSym = eNew->Sym;
+
+ /* Connect the new edge appropriately */
+ Splice( eNew, eOrg->Lnext );
+
+ /* Set the vertex and face information */
+ eNew->Org = eOrg->Dst;
+ {
+ GLUvertex *newVertex= allocVertex();
+ if (newVertex == NULL) return NULL;
+
+ MakeVertex( newVertex, eNewSym, eNew->Org );
+ }
+ eNew->Lface = eNewSym->Lface = eOrg->Lface;
+
+ return eNew;
+}
+
+
+/* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
+ * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
+ * eOrg and eNew will have the same left face.
+ */
+GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg )
+{
+ GLUhalfEdge *eNew;
+ GLUhalfEdge *tempHalfEdge= __gl_meshAddEdgeVertex( eOrg );
+ if (tempHalfEdge == NULL) return NULL;
+
+ eNew = tempHalfEdge->Sym;
+
+ /* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */
+ Splice( eOrg->Sym, eOrg->Sym->Oprev );
+ Splice( eOrg->Sym, eNew );
+
+ /* Set the vertex and face information */
+ eOrg->Dst = eNew->Org;
+ eNew->Dst->anEdge = eNew->Sym; /* may have pointed to eOrg->Sym */
+ eNew->Rface = eOrg->Rface;
+ eNew->winding = eOrg->winding; /* copy old winding information */
+ eNew->Sym->winding = eOrg->Sym->winding;
+
+ return eNew;
+}
+
+
+/* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
+ * to eDst->Org, and returns the corresponding half-edge eNew.
+ * If eOrg->Lface == eDst->Lface, this splits one loop into two,
+ * and the newly created loop is eNew->Lface. Otherwise, two disjoint
+ * loops are merged into one, and the loop eDst->Lface is destroyed.
+ *
+ * If (eOrg == eDst), the new face will have only two edges.
+ * If (eOrg->Lnext == eDst), the old face is reduced to a single edge.
+ * If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges.
+ */
+GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
+{
+ GLUhalfEdge *eNewSym;
+ int joiningLoops = FALSE;
+ GLUhalfEdge *eNew = MakeEdge( eOrg );
+ if (eNew == NULL) return NULL;
+
+ eNewSym = eNew->Sym;
+
+ if( eDst->Lface != eOrg->Lface ) {
+ /* We are connecting two disjoint loops -- destroy eDst->Lface */
+ joiningLoops = TRUE;
+ KillFace( eDst->Lface, eOrg->Lface );
+ }
+
+ /* Connect the new edge appropriately */
+ Splice( eNew, eOrg->Lnext );
+ Splice( eNewSym, eDst );
+
+ /* Set the vertex and face information */
+ eNew->Org = eOrg->Dst;
+ eNewSym->Org = eDst->Org;
+ eNew->Lface = eNewSym->Lface = eOrg->Lface;
+
+ /* Make sure the old face points to a valid half-edge */
+ eOrg->Lface->anEdge = eNewSym;
+
+ if( ! joiningLoops ) {
+ GLUface *newFace= allocFace();
+ if (newFace == NULL) return NULL;
+
+ /* We split one loop into two -- the new loop is eNew->Lface */
+ MakeFace( newFace, eNew, eOrg->Lface );
+ }
+ return eNew;
+}
+
+
+/******************** Other Operations **********************/
+
+/* __gl_meshZapFace( fZap ) destroys a face and removes it from the
+ * global face list. All edges of fZap will have a NULL pointer as their
+ * left face. Any edges which also have a NULL pointer as their right face
+ * are deleted entirely (along with any isolated vertices this produces).
+ * An entire mesh can be deleted by zapping its faces, one at a time,
+ * in any order. Zapped faces cannot be used in further mesh operations!
+ */
+void __gl_meshZapFace( GLUface *fZap )
+{
+ GLUhalfEdge *eStart = fZap->anEdge;
+ GLUhalfEdge *e, *eNext, *eSym;
+ GLUface *fPrev, *fNext;
+
+ /* walk around face, deleting edges whose right face is also NULL */
+ eNext = eStart->Lnext;
+ do {
+ e = eNext;
+ eNext = e->Lnext;
+
+ e->Lface = NULL;
+ if( e->Rface == NULL ) {
+ /* delete the edge -- see __gl_MeshDelete above */
+
+ if( e->Onext == e ) {
+ KillVertex( e->Org, NULL );
+ } else {
+ /* Make sure that e->Org points to a valid half-edge */
+ e->Org->anEdge = e->Onext;
+ Splice( e, e->Oprev );
+ }
+ eSym = e->Sym;
+ if( eSym->Onext == eSym ) {
+ KillVertex( eSym->Org, NULL );
+ } else {
+ /* Make sure that eSym->Org points to a valid half-edge */
+ eSym->Org->anEdge = eSym->Onext;
+ Splice( eSym, eSym->Oprev );
+ }
+ KillEdge( e );
+ }
+ } while( e != eStart );
+
+ /* delete from circular doubly-linked list */
+ fPrev = fZap->prev;
+ fNext = fZap->next;
+ fNext->prev = fPrev;
+ fPrev->next = fNext;
+
+ memFree( fZap );
+}
+
+
+/* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
+ * and no loops (what we usually call a "face").
+ */
+GLUmesh *__gl_meshNewMesh( void )
+{
+ GLUvertex *v;
+ GLUface *f;
+ GLUhalfEdge *e;
+ GLUhalfEdge *eSym;
+ GLUmesh *mesh = (GLUmesh *)memAlloc( sizeof( GLUmesh ));
+ if (mesh == NULL) {
+ return NULL;
+ }
+
+ v = &mesh->vHead;
+ f = &mesh->fHead;
+ e = &mesh->eHead;
+ eSym = &mesh->eHeadSym;
+
+ v->next = v->prev = v;
+ v->anEdge = NULL;
+ v->data = NULL;
+
+ f->next = f->prev = f;
+ f->anEdge = NULL;
+ f->data = NULL;
+ f->trail = NULL;
+ f->marked = FALSE;
+ f->inside = FALSE;
+
+ e->next = e;
+ e->Sym = eSym;
+ e->Onext = NULL;
+ e->Lnext = NULL;
+ e->Org = NULL;
+ e->Lface = NULL;
+ e->winding = 0;
+ e->activeRegion = NULL;
+
+ eSym->next = eSym;
+ eSym->Sym = e;
+ eSym->Onext = NULL;
+ eSym->Lnext = NULL;
+ eSym->Org = NULL;
+ eSym->Lface = NULL;
+ eSym->winding = 0;
+ eSym->activeRegion = NULL;
+
+ return mesh;
+}
+
+
+/* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
+ * both meshes, and returns the new mesh (the old meshes are destroyed).
+ */
+GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 )
+{
+ GLUface *f1 = &mesh1->fHead;
+ GLUvertex *v1 = &mesh1->vHead;
+ GLUhalfEdge *e1 = &mesh1->eHead;
+ GLUface *f2 = &mesh2->fHead;
+ GLUvertex *v2 = &mesh2->vHead;
+ GLUhalfEdge *e2 = &mesh2->eHead;
+
+ /* Add the faces, vertices, and edges of mesh2 to those of mesh1 */
+ if( f2->next != f2 ) {
+ f1->prev->next = f2->next;
+ f2->next->prev = f1->prev;
+ f2->prev->next = f1;
+ f1->prev = f2->prev;
+ }
+
+ if( v2->next != v2 ) {
+ v1->prev->next = v2->next;
+ v2->next->prev = v1->prev;
+ v2->prev->next = v1;
+ v1->prev = v2->prev;
+ }
+
+ if( e2->next != e2 ) {
+ e1->Sym->next->Sym->next = e2->next;
+ e2->next->Sym->next = e1->Sym->next;
+ e2->Sym->next->Sym->next = e1;
+ e1->Sym->next = e2->Sym->next;
+ }
+
+ memFree( mesh2 );
+ return mesh1;
+}
+
+
+#ifdef DELETE_BY_ZAPPING
+
+/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ */
+void __gl_meshDeleteMesh( GLUmesh *mesh )
+{
+ GLUface *fHead = &mesh->fHead;
+
+ while( fHead->next != fHead ) {
+ __gl_meshZapFace( fHead->next );
+ }
+ assert( mesh->vHead.next == &mesh->vHead );
+
+ memFree( mesh );
+}
+
+#else
+
+/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ */
+void __gl_meshDeleteMesh( GLUmesh *mesh )
+{
+ GLUface *f, *fNext;
+ GLUvertex *v, *vNext;
+ GLUhalfEdge *e, *eNext;
+
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
+ fNext = f->next;
+ memFree( f );
+ }
+
+ for( v = mesh->vHead.next; v != &mesh->vHead; v = vNext ) {
+ vNext = v->next;
+ memFree( v );
+ }
+
+ for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
+ /* One call frees both e and e->Sym (see EdgePair above) */
+ eNext = e->next;
+ memFree( e );
+ }
+
+ memFree( mesh );
+}
+
+#endif
+
+#ifndef NDEBUG
+
+/* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
+ */
+void __gl_meshCheckMesh( GLUmesh *mesh )
+{
+ GLUface *fHead = &mesh->fHead;
+ GLUvertex *vHead = &mesh->vHead;
+ GLUhalfEdge *eHead = &mesh->eHead;
+ GLUface *f, *fPrev;
+ GLUvertex *v, *vPrev;
+ GLUhalfEdge *e, *ePrev;
+
+ fPrev = fHead;
+ for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) {
+ assert( f->prev == fPrev );
+ e = f->anEdge;
+ do {
+ assert( e->Sym != e );
+ assert( e->Sym->Sym == e );
+ assert( e->Lnext->Onext->Sym == e );
+ assert( e->Onext->Sym->Lnext == e );
+ assert( e->Lface == f );
+ e = e->Lnext;
+ } while( e != f->anEdge );
+ }
+ assert( f->prev == fPrev && f->anEdge == NULL && f->data == NULL );
+
+ vPrev = vHead;
+ for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) {
+ assert( v->prev == vPrev );
+ e = v->anEdge;
+ do {
+ assert( e->Sym != e );
+ assert( e->Sym->Sym == e );
+ assert( e->Lnext->Onext->Sym == e );
+ assert( e->Onext->Sym->Lnext == e );
+ assert( e->Org == v );
+ e = e->Onext;
+ } while( e != v->anEdge );
+ }
+ assert( v->prev == vPrev && v->anEdge == NULL && v->data == NULL );
+
+ ePrev = eHead;
+ for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) {
+ assert( e->Sym->next == ePrev->Sym );
+ assert( e->Sym != e );
+ assert( e->Sym->Sym == e );
+ assert( e->Org != NULL );
+ assert( e->Dst != NULL );
+ assert( e->Lnext->Onext->Sym == e );
+ assert( e->Onext->Sym->Lnext == e );
+ }
+ assert( e->Sym->next == ePrev->Sym
+ && e->Sym == &mesh->eHeadSym
+ && e->Sym->Sym == e
+ && e->Org == NULL && e->Dst == NULL
+ && e->Lface == NULL && e->Rface == NULL );
+}
+
+#endif
diff --git a/third_party/glu/libtess/mesh.h b/third_party/glu/libtess/mesh.h
new file mode 100644
index 0000000..da149d7
--- /dev/null
+++ b/third_party/glu/libtess/mesh.h
@@ -0,0 +1,273 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/mesh.h#5 $
+*/
+
+#ifndef __mesh_h_
+#define __mesh_h_
+
+#include <sk_glu.h>
+
+typedef struct GLUmesh GLUmesh;
+
+typedef struct GLUvertex GLUvertex;
+typedef struct GLUface GLUface;
+typedef struct GLUhalfEdge GLUhalfEdge;
+
+typedef struct ActiveRegion ActiveRegion; /* Internal data */
+
+/* The mesh structure is similar in spirit, notation, and operations
+ * to the "quad-edge" structure (see L. Guibas and J. Stolfi, Primitives
+ * for the manipulation of general subdivisions and the computation of
+ * Voronoi diagrams, ACM Transactions on Graphics, 4(2):74-123, April 1985).
+ * For a simplified description, see the course notes for CS348a,
+ * "Mathematical Foundations of Computer Graphics", available at the
+ * Stanford bookstore (and taught during the fall quarter).
+ * The implementation also borrows a tiny subset of the graph-based approach
+ * use in Mantyla's Geometric Work Bench (see M. Mantyla, An Introduction
+ * to Sold Modeling, Computer Science Press, Rockville, Maryland, 1988).
+ *
+ * The fundamental data structure is the "half-edge". Two half-edges
+ * go together to make an edge, but they point in opposite directions.
+ * Each half-edge has a pointer to its mate (the "symmetric" half-edge Sym),
+ * its origin vertex (Org), the face on its left side (Lface), and the
+ * adjacent half-edges in the CCW direction around the origin vertex
+ * (Onext) and around the left face (Lnext). There is also a "next"
+ * pointer for the global edge list (see below).
+ *
+ * The notation used for mesh navigation:
+ * Sym = the mate of a half-edge (same edge, but opposite direction)
+ * Onext = edge CCW around origin vertex (keep same origin)
+ * Dnext = edge CCW around destination vertex (keep same dest)
+ * Lnext = edge CCW around left face (dest becomes new origin)
+ * Rnext = edge CCW around right face (origin becomes new dest)
+ *
+ * "prev" means to substitute CW for CCW in the definitions above.
+ *
+ * The mesh keeps global lists of all vertices, faces, and edges,
+ * stored as doubly-linked circular lists with a dummy header node.
+ * The mesh stores pointers to these dummy headers (vHead, fHead, eHead).
+ *
+ * The circular edge list is special; since half-edges always occur
+ * in pairs (e and e->Sym), each half-edge stores a pointer in only
+ * one direction. Starting at eHead and following the e->next pointers
+ * will visit each *edge* once (ie. e or e->Sym, but not both).
+ * e->Sym stores a pointer in the opposite direction, thus it is
+ * always true that e->Sym->next->Sym->next == e.
+ *
+ * Each vertex has a pointer to next and previous vertices in the
+ * circular list, and a pointer to a half-edge with this vertex as
+ * the origin (NULL if this is the dummy header). There is also a
+ * field "data" for client data.
+ *
+ * Each face has a pointer to the next and previous faces in the
+ * circular list, and a pointer to a half-edge with this face as
+ * the left face (NULL if this is the dummy header). There is also
+ * a field "data" for client data.
+ *
+ * Note that what we call a "face" is really a loop; faces may consist
+ * of more than one loop (ie. not simply connected), but there is no
+ * record of this in the data structure. The mesh may consist of
+ * several disconnected regions, so it may not be possible to visit
+ * the entire mesh by starting at a half-edge and traversing the edge
+ * structure.
+ *
+ * The mesh does NOT support isolated vertices; a vertex is deleted along
+ * with its last edge. Similarly when two faces are merged, one of the
+ * faces is deleted (see __gl_meshDelete below). For mesh operations,
+ * all face (loop) and vertex pointers must not be NULL. However, once
+ * mesh manipulation is finished, __gl_MeshZapFace can be used to delete
+ * faces of the mesh, one at a time. All external faces can be "zapped"
+ * before the mesh is returned to the client; then a NULL face indicates
+ * a region which is not part of the output polygon.
+ */
+
+struct GLUvertex {
+ GLUvertex *next; /* next vertex (never NULL) */
+ GLUvertex *prev; /* previous vertex (never NULL) */
+ GLUhalfEdge *anEdge; /* a half-edge with this origin */
+ void *data; /* client's data */
+
+ /* Internal data (keep hidden) */
+ GLdouble coords[3]; /* vertex location in 3D */
+ GLdouble s, t; /* projection onto the sweep plane */
+ long pqHandle; /* to allow deletion from priority queue */
+};
+
+struct GLUface {
+ GLUface *next; /* next face (never NULL) */
+ GLUface *prev; /* previous face (never NULL) */
+ GLUhalfEdge *anEdge; /* a half edge with this left face */
+ void *data; /* room for client's data */
+
+ /* Internal data (keep hidden) */
+ GLUface *trail; /* "stack" for conversion to strips */
+ GLboolean marked; /* flag for conversion to strips */
+ GLboolean inside; /* this face is in the polygon interior */
+};
+
+struct GLUhalfEdge {
+ GLUhalfEdge *next; /* doubly-linked list (prev==Sym->next) */
+ GLUhalfEdge *Sym; /* same edge, opposite direction */
+ GLUhalfEdge *Onext; /* next edge CCW around origin */
+ GLUhalfEdge *Lnext; /* next edge CCW around left face */
+ GLUvertex *Org; /* origin vertex (Overtex too long) */
+ GLUface *Lface; /* left face */
+
+ /* Internal data (keep hidden) */
+ ActiveRegion *activeRegion; /* a region with this upper edge (sweep.c) */
+ int winding; /* change in winding number when crossing
+ from the right face to the left face */
+};
+
+#define Rface Sym->Lface
+#define Dst Sym->Org
+
+#define Oprev Sym->Lnext
+#define Lprev Onext->Sym
+#define Dprev Lnext->Sym
+#define Rprev Sym->Onext
+#define Dnext Rprev->Sym /* 3 pointers */
+#define Rnext Oprev->Sym /* 3 pointers */
+
+
+struct GLUmesh {
+ GLUvertex vHead; /* dummy header for vertex list */
+ GLUface fHead; /* dummy header for face list */
+ GLUhalfEdge eHead; /* dummy header for edge list */
+ GLUhalfEdge eHeadSym; /* and its symmetric counterpart */
+};
+
+/* The mesh operations below have three motivations: completeness,
+ * convenience, and efficiency. The basic mesh operations are MakeEdge,
+ * Splice, and Delete. All the other edge operations can be implemented
+ * in terms of these. The other operations are provided for convenience
+ * and/or efficiency.
+ *
+ * When a face is split or a vertex is added, they are inserted into the
+ * global list *before* the existing vertex or face (ie. e->Org or e->Lface).
+ * This makes it easier to process all vertices or faces in the global lists
+ * without worrying about processing the same data twice. As a convenience,
+ * when a face is split, the "inside" flag is copied from the old face.
+ * Other internal data (v->data, v->activeRegion, f->data, f->marked,
+ * f->trail, e->winding) is set to zero.
+ *
+ * ********************** Basic Edge Operations **************************
+ *
+ * __gl_meshMakeEdge( mesh ) creates one edge, two vertices, and a loop.
+ * The loop (face) consists of the two new half-edges.
+ *
+ * __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
+ * mesh connectivity and topology. It changes the mesh so that
+ * eOrg->Onext <- OLD( eDst->Onext )
+ * eDst->Onext <- OLD( eOrg->Onext )
+ * where OLD(...) means the value before the meshSplice operation.
+ *
+ * This can have two effects on the vertex structure:
+ * - if eOrg->Org != eDst->Org, the two vertices are merged together
+ * - if eOrg->Org == eDst->Org, the origin is split into two vertices
+ * In both cases, eDst->Org is changed and eOrg->Org is untouched.
+ *
+ * Similarly (and independently) for the face structure,
+ * - if eOrg->Lface == eDst->Lface, one loop is split into two
+ * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
+ * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
+ *
+ * __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
+ * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
+ * eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
+ * the newly created loop will contain eDel->Dst. If the deletion of eDel
+ * would create isolated vertices, those are deleted as well.
+ *
+ * ********************** Other Edge Operations **************************
+ *
+ * __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
+ * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
+ * eOrg and eNew will have the same left face.
+ *
+ * __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
+ * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
+ * eOrg and eNew will have the same left face.
+ *
+ * __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
+ * to eDst->Org, and returns the corresponding half-edge eNew.
+ * If eOrg->Lface == eDst->Lface, this splits one loop into two,
+ * and the newly created loop is eNew->Lface. Otherwise, two disjoint
+ * loops are merged into one, and the loop eDst->Lface is destroyed.
+ *
+ * ************************ Other Operations *****************************
+ *
+ * __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
+ * and no loops (what we usually call a "face").
+ *
+ * __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
+ * both meshes, and returns the new mesh (the old meshes are destroyed).
+ *
+ * __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ *
+ * __gl_meshZapFace( fZap ) destroys a face and removes it from the
+ * global face list. All edges of fZap will have a NULL pointer as their
+ * left face. Any edges which also have a NULL pointer as their right face
+ * are deleted entirely (along with any isolated vertices this produces).
+ * An entire mesh can be deleted by zapping its faces, one at a time,
+ * in any order. Zapped faces cannot be used in further mesh operations!
+ *
+ * __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
+ */
+
+GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh );
+int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst );
+int __gl_meshDelete( GLUhalfEdge *eDel );
+
+GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg );
+GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg );
+GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst );
+
+GLUmesh *__gl_meshNewMesh( void );
+GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 );
+void __gl_meshDeleteMesh( GLUmesh *mesh );
+void __gl_meshZapFace( GLUface *fZap );
+
+#ifdef NDEBUG
+#define __gl_meshCheckMesh( mesh )
+#else
+void __gl_meshCheckMesh( GLUmesh *mesh );
+#endif
+
+#endif
diff --git a/third_party/glu/libtess/normal.c b/third_party/glu/libtess/normal.c
new file mode 100644
index 0000000..8fb22f1
--- /dev/null
+++ b/third_party/glu/libtess/normal.c
@@ -0,0 +1,259 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/normal.c#5 $
+*/
+
+#include "gluos.h"
+#include "mesh.h"
+#include "tess.h"
+#include "normal.h"
+#include <math.h>
+#include <assert.h>
+
+#define TRUE 1
+#define FALSE 0
+
+#define Dot(u,v) (u[0]*v[0] + u[1]*v[1] + u[2]*v[2])
+
+#if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT)
+static void Normalize( GLdouble v[3] )
+{
+ GLdouble len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+
+ assert( len > 0 );
+ len = sqrt( len );
+ v[0] /= len;
+ v[1] /= len;
+ v[2] /= len;
+}
+#endif
+
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+
+static int LongAxis( GLdouble v[3] )
+{
+ int i = 0;
+
+ if( ABS(v[1]) > ABS(v[0]) ) { i = 1; }
+ if( ABS(v[2]) > ABS(v[i]) ) { i = 2; }
+ return i;
+}
+
+static void ComputeNormal( GLUtesselator *tess, GLdouble norm[3] )
+{
+ GLUvertex *v, *v1, *v2;
+ GLdouble c, tLen2, maxLen2;
+ GLdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3];
+ GLUvertex *maxVert[3], *minVert[3];
+ GLUvertex *vHead = &tess->mesh->vHead;
+ int i;
+
+ maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD;
+ minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD;
+
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ for( i = 0; i < 3; ++i ) {
+ c = v->coords[i];
+ if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; }
+ if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; }
+ }
+ }
+
+ /* Find two vertices separated by at least 1/sqrt(3) of the maximum
+ * distance between any two vertices
+ */
+ i = 0;
+ if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; }
+ if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; }
+ if( minVal[i] >= maxVal[i] ) {
+ /* All vertices are the same -- normal doesn't matter */
+ norm[0] = 0; norm[1] = 0; norm[2] = 1;
+ return;
+ }
+
+ /* Look for a third vertex which forms the triangle with maximum area
+ * (Length of normal == twice the triangle area)
+ */
+ maxLen2 = 0;
+ v1 = minVert[i];
+ v2 = maxVert[i];
+ d1[0] = v1->coords[0] - v2->coords[0];
+ d1[1] = v1->coords[1] - v2->coords[1];
+ d1[2] = v1->coords[2] - v2->coords[2];
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ d2[0] = v->coords[0] - v2->coords[0];
+ d2[1] = v->coords[1] - v2->coords[1];
+ d2[2] = v->coords[2] - v2->coords[2];
+ tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1];
+ tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2];
+ tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0];
+ tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2];
+ if( tLen2 > maxLen2 ) {
+ maxLen2 = tLen2;
+ norm[0] = tNorm[0];
+ norm[1] = tNorm[1];
+ norm[2] = tNorm[2];
+ }
+ }
+
+ if( maxLen2 <= 0 ) {
+ /* All points lie on a single line -- any decent normal will do */
+ norm[0] = norm[1] = norm[2] = 0;
+ norm[LongAxis(d1)] = 1;
+ }
+}
+
+
+static void CheckOrientation( GLUtesselator *tess )
+{
+ GLdouble area;
+ GLUface *f, *fHead = &tess->mesh->fHead;
+ GLUvertex *v, *vHead = &tess->mesh->vHead;
+ GLUhalfEdge *e;
+
+ /* When we compute the normal automatically, we choose the orientation
+ * so that the the sum of the signed areas of all contours is non-negative.
+ */
+ area = 0;
+ for( f = fHead->next; f != fHead; f = f->next ) {
+ e = f->anEdge;
+ if( e->winding <= 0 ) continue;
+ do {
+ area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t);
+ e = e->Lnext;
+ } while( e != f->anEdge );
+ }
+ if( area < 0 ) {
+ /* Reverse the orientation by flipping all the t-coordinates */
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ v->t = - v->t;
+ }
+ tess->tUnit[0] = - tess->tUnit[0];
+ tess->tUnit[1] = - tess->tUnit[1];
+ tess->tUnit[2] = - tess->tUnit[2];
+ }
+}
+
+#ifdef FOR_TRITE_TEST_PROGRAM
+#include <stdlib.h>
+extern int RandomSweep;
+#define S_UNIT_X (RandomSweep ? (2*drand48()-1) : 1.0)
+#define S_UNIT_Y (RandomSweep ? (2*drand48()-1) : 0.0)
+#else
+#if defined(SLANTED_SWEEP)
+/* The "feature merging" is not intended to be complete. There are
+ * special cases where edges are nearly parallel to the sweep line
+ * which are not implemented. The algorithm should still behave
+ * robustly (ie. produce a reasonable tesselation) in the presence
+ * of such edges, however it may miss features which could have been
+ * merged. We could minimize this effect by choosing the sweep line
+ * direction to be something unusual (ie. not parallel to one of the
+ * coordinate axes).
+ */
+#define S_UNIT_X 0.50941539564955385 /* Pre-normalized */
+#define S_UNIT_Y 0.86052074622010633
+#else
+#define S_UNIT_X 1.0
+#define S_UNIT_Y 0.0
+#endif
+#endif
+
+/* Determine the polygon normal and project vertices onto the plane
+ * of the polygon.
+ */
+void __gl_projectPolygon( GLUtesselator *tess )
+{
+ GLUvertex *v, *vHead = &tess->mesh->vHead;
+ GLdouble norm[3];
+ GLdouble *sUnit, *tUnit;
+ int i, computedNormal = FALSE;
+
+ norm[0] = tess->normal[0];
+ norm[1] = tess->normal[1];
+ norm[2] = tess->normal[2];
+ if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
+ ComputeNormal( tess, norm );
+ computedNormal = TRUE;
+ }
+ sUnit = tess->sUnit;
+ tUnit = tess->tUnit;
+ i = LongAxis( norm );
+
+#if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT)
+ /* Choose the initial sUnit vector to be approximately perpendicular
+ * to the normal.
+ */
+ Normalize( norm );
+
+ sUnit[i] = 0;
+ sUnit[(i+1)%3] = S_UNIT_X;
+ sUnit[(i+2)%3] = S_UNIT_Y;
+
+ /* Now make it exactly perpendicular */
+ w = Dot( sUnit, norm );
+ sUnit[0] -= w * norm[0];
+ sUnit[1] -= w * norm[1];
+ sUnit[2] -= w * norm[2];
+ Normalize( sUnit );
+
+ /* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */
+ tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1];
+ tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2];
+ tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0];
+ Normalize( tUnit );
+#else
+ /* Project perpendicular to a coordinate axis -- better numerically */
+ sUnit[i] = 0;
+ sUnit[(i+1)%3] = S_UNIT_X;
+ sUnit[(i+2)%3] = S_UNIT_Y;
+
+ tUnit[i] = 0;
+ tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y;
+ tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X;
+#endif
+
+ /* Project the vertices onto the sweep plane */
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ v->s = Dot( v->coords, sUnit );
+ v->t = Dot( v->coords, tUnit );
+ }
+ if( computedNormal ) {
+ CheckOrientation( tess );
+ }
+}
diff --git a/third_party/glu/libtess/normal.h b/third_party/glu/libtess/normal.h
new file mode 100644
index 0000000..5a68747
--- /dev/null
+++ b/third_party/glu/libtess/normal.h
@@ -0,0 +1,52 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/normal.h#5 $
+*/
+
+#ifndef __normal_h_
+#define __normal_h_
+
+#include "tess.h"
+
+/* __gl_projectPolygon( tess ) determines the polygon normal
+ * and project vertices onto the plane of the polygon.
+ */
+void __gl_projectPolygon( GLUtesselator *tess );
+
+#endif
diff --git a/third_party/glu/libtess/priorityq-heap.c b/third_party/glu/libtess/priorityq-heap.c
new file mode 100644
index 0000000..163bde6
--- /dev/null
+++ b/third_party/glu/libtess/priorityq-heap.c
@@ -0,0 +1,260 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/priorityq-heap.c#5 $
+*/
+
+#include <stddef.h>
+#include <assert.h>
+#include <limits.h>
+#include "priorityq-heap.h"
+#include "memalloc.h"
+
+#define INIT_SIZE 32
+
+#define TRUE 1
+#define FALSE 0
+
+#ifdef FOR_TRITE_TEST_PROGRAM
+#define LEQ(x,y) (*pq->leq)(x,y)
+#else
+/* Violates modularity, but a little faster */
+#include "geom.h"
+#define LEQ(x,y) VertLeq((GLUvertex *)x, (GLUvertex *)y)
+#endif
+
+/* really __gl_pqHeapNewPriorityQ */
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
+{
+ PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
+ if (pq == NULL) return NULL;
+
+ pq->size = 0;
+ pq->max = INIT_SIZE;
+ pq->nodes = (PQnode *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->nodes[0]) );
+ if (pq->nodes == NULL) {
+ memFree(pq);
+ return NULL;
+ }
+
+ pq->handles = (PQhandleElem *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->handles[0]) );
+ if (pq->handles == NULL) {
+ memFree(pq->nodes);
+ memFree(pq);
+ return NULL;
+ }
+
+ pq->initialized = FALSE;
+ pq->freeList = 0;
+ pq->leq = leq;
+
+ pq->nodes[1].handle = 1; /* so that Minimum() returns NULL */
+ pq->handles[1].key = NULL;
+ return pq;
+}
+
+/* really __gl_pqHeapDeletePriorityQ */
+void pqDeletePriorityQ( PriorityQ *pq )
+{
+ memFree( pq->handles );
+ memFree( pq->nodes );
+ memFree( pq );
+}
+
+
+static void FloatDown( PriorityQ *pq, long curr )
+{
+ PQnode *n = pq->nodes;
+ PQhandleElem *h = pq->handles;
+ PQhandle hCurr, hChild;
+ long child;
+
+ hCurr = n[curr].handle;
+ for( ;; ) {
+ child = curr << 1;
+ if( child < pq->size && LEQ( h[n[child+1].handle].key,
+ h[n[child].handle].key )) {
+ ++child;
+ }
+
+ assert(child <= pq->max);
+
+ hChild = n[child].handle;
+ if( child > pq->size || LEQ( h[hCurr].key, h[hChild].key )) {
+ n[curr].handle = hCurr;
+ h[hCurr].node = curr;
+ break;
+ }
+ n[curr].handle = hChild;
+ h[hChild].node = curr;
+ curr = child;
+ }
+}
+
+
+static void FloatUp( PriorityQ *pq, long curr )
+{
+ PQnode *n = pq->nodes;
+ PQhandleElem *h = pq->handles;
+ PQhandle hCurr, hParent;
+ long parent;
+
+ hCurr = n[curr].handle;
+ for( ;; ) {
+ parent = curr >> 1;
+ hParent = n[parent].handle;
+ if( parent == 0 || LEQ( h[hParent].key, h[hCurr].key )) {
+ n[curr].handle = hCurr;
+ h[hCurr].node = curr;
+ break;
+ }
+ n[curr].handle = hParent;
+ h[hParent].node = curr;
+ curr = parent;
+ }
+}
+
+/* really __gl_pqHeapInit */
+void pqInit( PriorityQ *pq )
+{
+ long i;
+
+ /* This method of building a heap is O(n), rather than O(n lg n). */
+
+ for( i = pq->size; i >= 1; --i ) {
+ FloatDown( pq, i );
+ }
+ pq->initialized = TRUE;
+}
+
+/* really __gl_pqHeapInsert */
+/* returns LONG_MAX iff out of memory */
+PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
+{
+ long curr;
+ PQhandle free;
+
+ curr = ++ pq->size;
+ if( (curr*2) > pq->max ) {
+ PQnode *saveNodes= pq->nodes;
+ PQhandleElem *saveHandles= pq->handles;
+
+ /* If the heap overflows, double its size. */
+ pq->max <<= 1;
+ pq->nodes = (PQnode *)memRealloc( pq->nodes,
+ (size_t)
+ ((pq->max + 1) * sizeof( pq->nodes[0] )));
+ if (pq->nodes == NULL) {
+ pq->nodes = saveNodes; /* restore ptr to free upon return */
+ return LONG_MAX;
+ }
+ pq->handles = (PQhandleElem *)memRealloc( pq->handles,
+ (size_t)
+ ((pq->max + 1) *
+ sizeof( pq->handles[0] )));
+ if (pq->handles == NULL) {
+ pq->handles = saveHandles; /* restore ptr to free upon return */
+ return LONG_MAX;
+ }
+ }
+
+ if( pq->freeList == 0 ) {
+ free = curr;
+ } else {
+ free = pq->freeList;
+ pq->freeList = pq->handles[free].node;
+ }
+
+ pq->nodes[curr].handle = free;
+ pq->handles[free].node = curr;
+ pq->handles[free].key = keyNew;
+
+ if( pq->initialized ) {
+ FloatUp( pq, curr );
+ }
+ assert(free != LONG_MAX);
+ return free;
+}
+
+/* really __gl_pqHeapExtractMin */
+PQkey pqExtractMin( PriorityQ *pq )
+{
+ PQnode *n = pq->nodes;
+ PQhandleElem *h = pq->handles;
+ PQhandle hMin = n[1].handle;
+ PQkey min = h[hMin].key;
+
+ if( pq->size > 0 ) {
+ n[1].handle = n[pq->size].handle;
+ h[n[1].handle].node = 1;
+
+ h[hMin].key = NULL;
+ h[hMin].node = pq->freeList;
+ pq->freeList = hMin;
+
+ if( -- pq->size > 0 ) {
+ FloatDown( pq, 1 );
+ }
+ }
+ return min;
+}
+
+/* really __gl_pqHeapDelete */
+void pqDelete( PriorityQ *pq, PQhandle hCurr )
+{
+ PQnode *n = pq->nodes;
+ PQhandleElem *h = pq->handles;
+ long curr;
+
+ assert( hCurr >= 1 && hCurr <= pq->max && h[hCurr].key != NULL );
+
+ curr = h[hCurr].node;
+ n[curr].handle = n[pq->size].handle;
+ h[n[curr].handle].node = curr;
+
+ if( curr <= -- pq->size ) {
+ if( curr <= 1 || LEQ( h[n[curr>>1].handle].key, h[n[curr].handle].key )) {
+ FloatDown( pq, curr );
+ } else {
+ FloatUp( pq, curr );
+ }
+ }
+ h[hCurr].key = NULL;
+ h[hCurr].node = pq->freeList;
+ pq->freeList = hCurr;
+}
diff --git a/third_party/glu/libtess/priorityq-heap.h b/third_party/glu/libtess/priorityq-heap.h
new file mode 100644
index 0000000..02e4434
--- /dev/null
+++ b/third_party/glu/libtess/priorityq-heap.h
@@ -0,0 +1,114 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/priorityq-heap.h#5 $
+*/
+
+#ifndef __priorityq_heap_h_
+#define __priorityq_heap_h_
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define PQkey PQHeapKey
+#define PQhandle PQHeapHandle
+#define PriorityQ PriorityQHeap
+
+#define pqNewPriorityQ(leq) __gl_pqHeapNewPriorityQ(leq)
+#define pqDeletePriorityQ(pq) __gl_pqHeapDeletePriorityQ(pq)
+
+/* The basic operations are insertion of a new key (pqInsert),
+ * and examination/extraction of a key whose value is minimum
+ * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
+ * for this purpose pqInsert returns a "handle" which is supplied
+ * as the argument.
+ *
+ * An initial heap may be created efficiently by calling pqInsert
+ * repeatedly, then calling pqInit. In any case pqInit must be called
+ * before any operations other than pqInsert are used.
+ *
+ * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
+ * This may also be tested with pqIsEmpty.
+ */
+#define pqInit(pq) __gl_pqHeapInit(pq)
+#define pqInsert(pq,key) __gl_pqHeapInsert(pq,key)
+#define pqMinimum(pq) __gl_pqHeapMinimum(pq)
+#define pqExtractMin(pq) __gl_pqHeapExtractMin(pq)
+#define pqDelete(pq,handle) __gl_pqHeapDelete(pq,handle)
+#define pqIsEmpty(pq) __gl_pqHeapIsEmpty(pq)
+
+
+/* Since we support deletion the data structure is a little more
+ * complicated than an ordinary heap. "nodes" is the heap itself;
+ * active nodes are stored in the range 1..pq->size. When the
+ * heap exceeds its allocated size (pq->max), its size doubles.
+ * The children of node i are nodes 2i and 2i+1.
+ *
+ * Each node stores an index into an array "handles". Each handle
+ * stores a key, plus a pointer back to the node which currently
+ * represents that key (ie. nodes[handles[i].node].handle == i).
+ */
+
+typedef void *PQkey;
+typedef long PQhandle;
+typedef struct PriorityQ PriorityQ;
+
+typedef struct { PQhandle handle; } PQnode;
+typedef struct { PQkey key; PQhandle node; } PQhandleElem;
+
+struct PriorityQ {
+ PQnode *nodes;
+ PQhandleElem *handles;
+ long size, max;
+ PQhandle freeList;
+ int initialized;
+ int (*leq)(PQkey key1, PQkey key2);
+};
+
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
+void pqDeletePriorityQ( PriorityQ *pq );
+
+void pqInit( PriorityQ *pq );
+PQhandle pqInsert( PriorityQ *pq, PQkey key );
+PQkey pqExtractMin( PriorityQ *pq );
+void pqDelete( PriorityQ *pq, PQhandle handle );
+
+
+#define __gl_pqHeapMinimum(pq) ((pq)->handles[(pq)->nodes[1].handle].key)
+#define __gl_pqHeapIsEmpty(pq) ((pq)->size == 0)
+
+#endif
diff --git a/third_party/glu/libtess/priorityq-sort.h b/third_party/glu/libtess/priorityq-sort.h
new file mode 100644
index 0000000..12c2f0d
--- /dev/null
+++ b/third_party/glu/libtess/priorityq-sort.h
@@ -0,0 +1,124 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/priorityq-sort.h#5 $
+*/
+
+#ifndef __priorityq_sort_h_
+#define __priorityq_sort_h_
+
+#include "priorityq-heap.h"
+
+#undef PQkey
+#undef PQhandle
+#undef PriorityQ
+#undef pqNewPriorityQ
+#undef pqDeletePriorityQ
+#undef pqInit
+#undef pqInsert
+#undef pqMinimum
+#undef pqExtractMin
+#undef pqDelete
+#undef pqIsEmpty
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define PQkey PQSortKey
+#define PQhandle PQSortHandle
+#define PriorityQ PriorityQSort
+
+#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq)
+#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq)
+
+/* The basic operations are insertion of a new key (pqInsert),
+ * and examination/extraction of a key whose value is minimum
+ * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
+ * for this purpose pqInsert returns a "handle" which is supplied
+ * as the argument.
+ *
+ * An initial heap may be created efficiently by calling pqInsert
+ * repeatedly, then calling pqInit. In any case pqInit must be called
+ * before any operations other than pqInsert are used.
+ *
+ * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
+ * This may also be tested with pqIsEmpty.
+ */
+#define pqInit(pq) __gl_pqSortInit(pq)
+#define pqInsert(pq,key) __gl_pqSortInsert(pq,key)
+#define pqMinimum(pq) __gl_pqSortMinimum(pq)
+#define pqExtractMin(pq) __gl_pqSortExtractMin(pq)
+#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle)
+#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq)
+
+
+/* Since we support deletion the data structure is a little more
+ * complicated than an ordinary heap. "nodes" is the heap itself;
+ * active nodes are stored in the range 1..pq->size. When the
+ * heap exceeds its allocated size (pq->max), its size doubles.
+ * The children of node i are nodes 2i and 2i+1.
+ *
+ * Each node stores an index into an array "handles". Each handle
+ * stores a key, plus a pointer back to the node which currently
+ * represents that key (ie. nodes[handles[i].node].handle == i).
+ */
+
+typedef PQHeapKey PQkey;
+typedef PQHeapHandle PQhandle;
+typedef struct PriorityQ PriorityQ;
+
+struct PriorityQ {
+ PriorityQHeap *heap;
+ PQkey *keys;
+ PQkey **order;
+ PQhandle size, max;
+ int initialized;
+ int (*leq)(PQkey key1, PQkey key2);
+};
+
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
+void pqDeletePriorityQ( PriorityQ *pq );
+
+int pqInit( PriorityQ *pq );
+PQhandle pqInsert( PriorityQ *pq, PQkey key );
+PQkey pqExtractMin( PriorityQ *pq );
+void pqDelete( PriorityQ *pq, PQhandle handle );
+
+PQkey pqMinimum( PriorityQ *pq );
+int pqIsEmpty( PriorityQ *pq );
+
+#endif
diff --git a/third_party/glu/libtess/priorityq.c b/third_party/glu/libtess/priorityq.c
new file mode 100644
index 0000000..4b9e1ae
--- /dev/null
+++ b/third_party/glu/libtess/priorityq.c
@@ -0,0 +1,267 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/priorityq.c#5 $
+*/
+
+#include "gluos.h"
+#include <stddef.h>
+#include <assert.h>
+#include <limits.h> /* LONG_MAX */
+#include "memalloc.h"
+
+/* Include all the code for the regular heap-based queue here. */
+
+#include "priorityq-heap.c"
+
+/* Now redefine all the function names to map to their "Sort" versions. */
+
+#include "priorityq-sort.h"
+
+/* really __gl_pqSortNewPriorityQ */
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
+{
+ PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
+ if (pq == NULL) return NULL;
+
+ pq->heap = __gl_pqHeapNewPriorityQ( leq );
+ if (pq->heap == NULL) {
+ memFree(pq);
+ return NULL;
+ }
+
+ pq->keys = (PQHeapKey *)memAlloc( INIT_SIZE * sizeof(pq->keys[0]) );
+ if (pq->keys == NULL) {
+ __gl_pqHeapDeletePriorityQ(pq->heap);
+ memFree(pq);
+ return NULL;
+ }
+
+ pq->size = 0;
+ pq->max = INIT_SIZE;
+ pq->initialized = FALSE;
+ pq->leq = leq;
+ return pq;
+}
+
+/* really __gl_pqSortDeletePriorityQ */
+void pqDeletePriorityQ( PriorityQ *pq )
+{
+ assert(pq != NULL);
+ if (pq->heap != NULL) __gl_pqHeapDeletePriorityQ( pq->heap );
+ if (pq->order != NULL) memFree( pq->order );
+ if (pq->keys != NULL) memFree( pq->keys );
+ memFree( pq );
+}
+
+
+#define LT(x,y) (! LEQ(y,x))
+#define GT(x,y) (! LEQ(x,y))
+#define Swap(a,b) do{PQkey *tmp = *a; *a = *b; *b = tmp;}while(0)
+
+/* really __gl_pqSortInit */
+int pqInit( PriorityQ *pq )
+{
+ PQkey **p, **r, **i, **j, *piv;
+ struct { PQkey **p, **r; } Stack[50], *top = Stack;
+ unsigned long seed = 2016473283;
+
+ /* Create an array of indirect pointers to the keys, so that we
+ * the handles we have returned are still valid.
+ */
+/*
+ pq->order = (PQHeapKey **)memAlloc( (size_t)
+ (pq->size * sizeof(pq->order[0])) );
+*/
+ pq->order = (PQHeapKey **)memAlloc( (size_t)
+ ((pq->size+1) * sizeof(pq->order[0])) );
+/* the previous line is a patch to compensate for the fact that IBM */
+/* machines return a null on a malloc of zero bytes (unlike SGI), */
+/* so we have to put in this defense to guard against a memory */
+/* fault four lines down. from fossum@austin.ibm.com. */
+ if (pq->order == NULL) return 0;
+
+ p = pq->order;
+ r = p + pq->size - 1;
+ for( piv = pq->keys, i = p; i <= r; ++piv, ++i ) {
+ *i = piv;
+ }
+
+ /* Sort the indirect pointers in descending order,
+ * using randomized Quicksort
+ */
+ top->p = p; top->r = r; ++top;
+ while( --top >= Stack ) {
+ p = top->p;
+ r = top->r;
+ while( r > p + 10 ) {
+ seed = seed * 1539415821 + 1;
+ i = p + seed % (r - p + 1);
+ piv = *i;
+ *i = *p;
+ *p = piv;
+ i = p - 1;
+ j = r + 1;
+ do {
+ do { ++i; } while( GT( **i, *piv ));
+ do { --j; } while( LT( **j, *piv ));
+ Swap( i, j );
+ } while( i < j );
+ Swap( i, j ); /* Undo last swap */
+ if( i - p < r - j ) {
+ top->p = j+1; top->r = r; ++top;
+ r = i-1;
+ } else {
+ top->p = p; top->r = i-1; ++top;
+ p = j+1;
+ }
+ }
+ /* Insertion sort small lists */
+ for( i = p+1; i <= r; ++i ) {
+ piv = *i;
+ for( j = i; j > p && LT( **(j-1), *piv ); --j ) {
+ *j = *(j-1);
+ }
+ *j = piv;
+ }
+ }
+ pq->max = pq->size;
+ pq->initialized = TRUE;
+ __gl_pqHeapInit( pq->heap ); /* always succeeds */
+
+#ifndef NDEBUG
+ p = pq->order;
+ r = p + pq->size - 1;
+ for( i = p; i < r; ++i ) {
+ assert( LEQ( **(i+1), **i ));
+ }
+#endif
+
+ return 1;
+}
+
+/* really __gl_pqSortInsert */
+/* returns LONG_MAX iff out of memory */
+PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
+{
+ long curr;
+
+ if( pq->initialized ) {
+ return __gl_pqHeapInsert( pq->heap, keyNew );
+ }
+ curr = pq->size;
+ if( ++ pq->size >= pq->max ) {
+ PQkey *saveKey= pq->keys;
+
+ /* If the heap overflows, double its size. */
+ pq->max <<= 1;
+ pq->keys = (PQHeapKey *)memRealloc( pq->keys,
+ (size_t)
+ (pq->max * sizeof( pq->keys[0] )));
+ if (pq->keys == NULL) {
+ pq->keys = saveKey; /* restore ptr to free upon return */
+ return LONG_MAX;
+ }
+ }
+ assert(curr != LONG_MAX);
+ pq->keys[curr] = keyNew;
+
+ /* Negative handles index the sorted array. */
+ return -(curr+1);
+}
+
+/* really __gl_pqSortExtractMin */
+PQkey pqExtractMin( PriorityQ *pq )
+{
+ PQkey sortMin, heapMin;
+
+ if( pq->size == 0 ) {
+ return __gl_pqHeapExtractMin( pq->heap );
+ }
+ sortMin = *(pq->order[pq->size-1]);
+ if( ! __gl_pqHeapIsEmpty( pq->heap )) {
+ heapMin = __gl_pqHeapMinimum( pq->heap );
+ if( LEQ( heapMin, sortMin )) {
+ return __gl_pqHeapExtractMin( pq->heap );
+ }
+ }
+ do {
+ -- pq->size;
+ } while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL );
+ return sortMin;
+}
+
+/* really __gl_pqSortMinimum */
+PQkey pqMinimum( PriorityQ *pq )
+{
+ PQkey sortMin, heapMin;
+
+ if( pq->size == 0 ) {
+ return __gl_pqHeapMinimum( pq->heap );
+ }
+ sortMin = *(pq->order[pq->size-1]);
+ if( ! __gl_pqHeapIsEmpty( pq->heap )) {
+ heapMin = __gl_pqHeapMinimum( pq->heap );
+ if( LEQ( heapMin, sortMin )) {
+ return heapMin;
+ }
+ }
+ return sortMin;
+}
+
+/* really __gl_pqSortIsEmpty */
+int pqIsEmpty( PriorityQ *pq )
+{
+ return (pq->size == 0) && __gl_pqHeapIsEmpty( pq->heap );
+}
+
+/* really __gl_pqSortDelete */
+void pqDelete( PriorityQ *pq, PQhandle curr )
+{
+ if( curr >= 0 ) {
+ __gl_pqHeapDelete( pq->heap, curr );
+ return;
+ }
+ curr = -(curr+1);
+ assert( curr < pq->max && pq->keys[curr] != NULL );
+
+ pq->keys[curr] = NULL;
+ while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ) {
+ -- pq->size;
+ }
+}
diff --git a/third_party/glu/libtess/priorityq.h b/third_party/glu/libtess/priorityq.h
new file mode 100644
index 0000000..3ae6b0c
--- /dev/null
+++ b/third_party/glu/libtess/priorityq.h
@@ -0,0 +1,124 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/priorityq.h#5 $
+*/
+
+#ifndef __priorityq_sort_h_
+#define __priorityq_sort_h_
+
+#include "priorityq-heap.h"
+
+#undef PQkey
+#undef PQhandle
+#undef PriorityQ
+#undef pqNewPriorityQ
+#undef pqDeletePriorityQ
+#undef pqInit
+#undef pqInsert
+#undef pqMinimum
+#undef pqExtractMin
+#undef pqDelete
+#undef pqIsEmpty
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define PQkey PQSortKey
+#define PQhandle PQSortHandle
+#define PriorityQ PriorityQSort
+
+#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq)
+#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq)
+
+/* The basic operations are insertion of a new key (pqInsert),
+ * and examination/extraction of a key whose value is minimum
+ * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
+ * for this purpose pqInsert returns a "handle" which is supplied
+ * as the argument.
+ *
+ * An initial heap may be created efficiently by calling pqInsert
+ * repeatedly, then calling pqInit. In any case pqInit must be called
+ * before any operations other than pqInsert are used.
+ *
+ * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
+ * This may also be tested with pqIsEmpty.
+ */
+#define pqInit(pq) __gl_pqSortInit(pq)
+#define pqInsert(pq,key) __gl_pqSortInsert(pq,key)
+#define pqMinimum(pq) __gl_pqSortMinimum(pq)
+#define pqExtractMin(pq) __gl_pqSortExtractMin(pq)
+#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle)
+#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq)
+
+
+/* Since we support deletion the data structure is a little more
+ * complicated than an ordinary heap. "nodes" is the heap itself;
+ * active nodes are stored in the range 1..pq->size. When the
+ * heap exceeds its allocated size (pq->max), its size doubles.
+ * The children of node i are nodes 2i and 2i+1.
+ *
+ * Each node stores an index into an array "handles". Each handle
+ * stores a key, plus a pointer back to the node which currently
+ * represents that key (ie. nodes[handles[i].node].handle == i).
+ */
+
+typedef PQHeapKey PQkey;
+typedef PQHeapHandle PQhandle;
+typedef struct PriorityQ PriorityQ;
+
+struct PriorityQ {
+ PriorityQHeap *heap;
+ PQkey *keys;
+ PQkey **order;
+ PQhandle size, max;
+ int initialized;
+ int (*leq)(PQkey key1, PQkey key2);
+};
+
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
+void pqDeletePriorityQ( PriorityQ *pq );
+
+int pqInit( PriorityQ *pq );
+PQhandle pqInsert( PriorityQ *pq, PQkey key );
+PQkey pqExtractMin( PriorityQ *pq );
+void pqDelete( PriorityQ *pq, PQhandle handle );
+
+PQkey pqMinimum( PriorityQ *pq );
+int pqIsEmpty( PriorityQ *pq );
+
+#endif
diff --git a/third_party/glu/libtess/render.c b/third_party/glu/libtess/render.c
new file mode 100644
index 0000000..aff1298
--- /dev/null
+++ b/third_party/glu/libtess/render.c
@@ -0,0 +1,505 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/render.c#5 $
+*/
+
+#include "gluos.h"
+#include <assert.h>
+#include <stddef.h>
+#include "mesh.h"
+#include "tess.h"
+#include "render.h"
+
+#define TRUE 1
+#define FALSE 0
+
+/* This structure remembers the information we need about a primitive
+ * to be able to render it later, once we have determined which
+ * primitive is able to use the most triangles.
+ */
+struct FaceCount {
+ long size; /* number of triangles used */
+ GLUhalfEdge *eStart; /* edge where this primitive starts */
+ void (*render)(GLUtesselator *, GLUhalfEdge *, long);
+ /* routine to render this primitive */
+};
+
+static struct FaceCount MaximumFan( GLUhalfEdge *eOrig );
+static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig );
+
+static void RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
+static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
+static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart,
+ long size );
+
+static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig );
+static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *head );
+
+
+
+/************************ Strips and Fans decomposition ******************/
+
+/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
+ * fans, strips, and separate triangles. A substantial effort is made
+ * to use as few rendering primitives as possible (ie. to make the fans
+ * and strips as large as possible).
+ *
+ * The rendering output is provided as callbacks (see the api).
+ */
+void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh )
+{
+ GLUface *f;
+
+ /* Make a list of separate triangles so we can render them all at once */
+ tess->lonelyTriList = NULL;
+
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
+ f->marked = FALSE;
+ }
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
+
+ /* We examine all faces in an arbitrary order. Whenever we find
+ * an unprocessed face F, we output a group of faces including F
+ * whose size is maximum.
+ */
+ if( f->inside && ! f->marked ) {
+ RenderMaximumFaceGroup( tess, f );
+ assert( f->marked );
+ }
+ }
+ if( tess->lonelyTriList != NULL ) {
+ RenderLonelyTriangles( tess, tess->lonelyTriList );
+ tess->lonelyTriList = NULL;
+ }
+}
+
+
+static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig )
+{
+ /* We want to find the largest triangle fan or strip of unmarked faces
+ * which includes the given face fOrig. There are 3 possible fans
+ * passing through fOrig (one centered at each vertex), and 3 possible
+ * strips (one for each CCW permutation of the vertices). Our strategy
+ * is to try all of these, and take the primitive which uses the most
+ * triangles (a greedy approach).
+ */
+ GLUhalfEdge *e = fOrig->anEdge;
+ struct FaceCount max, newFace;
+
+ max.size = 1;
+ max.eStart = e;
+ max.render = &RenderTriangle;
+
+ if( ! tess->flagBoundary ) {
+ newFace = MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; }
+ newFace = MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
+ newFace = MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
+
+ newFace = MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; }
+ newFace = MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
+ newFace = MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
+ }
+ (*(max.render))( tess, max.eStart, max.size );
+}
+
+
+/* Macros which keep track of faces we have marked temporarily, and allow
+ * us to backtrack when necessary. With triangle fans, this is not
+ * really necessary, since the only awkward case is a loop of triangles
+ * around a single origin vertex. However with strips the situation is
+ * more complicated, and we need a general tracking method like the
+ * one here.
+ */
+#define Marked(f) (! (f)->inside || (f)->marked)
+
+#define AddToTrail(f,t) ((f)->trail = (t), (t) = (f), (f)->marked = TRUE)
+
+#define FreeTrail(t) do { \
+ while( (t) != NULL ) { \
+ (t)->marked = FALSE; t = (t)->trail; \
+ } \
+ } while(0) /* absorb trailing semicolon */
+
+
+
+static struct FaceCount MaximumFan( GLUhalfEdge *eOrig )
+{
+ /* eOrig->Lface is the face we want to render. We want to find the size
+ * of a maximal fan around eOrig->Org. To do this we just walk around
+ * the origin vertex as far as possible in both directions.
+ */
+ struct FaceCount newFace = { 0, NULL, &RenderFan };
+ GLUface *trail = NULL;
+ GLUhalfEdge *e;
+
+ for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) {
+ AddToTrail( e->Lface, trail );
+ ++newFace.size;
+ }
+ for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) {
+ AddToTrail( e->Rface, trail );
+ ++newFace.size;
+ }
+ newFace.eStart = e;
+ /*LINTED*/
+ FreeTrail( trail );
+ return newFace;
+}
+
+
+#define IsEven(n) (((n) & 1) == 0)
+
+static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig )
+{
+ /* Here we are looking for a maximal strip that contains the vertices
+ * eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the
+ * reverse, such that all triangles are oriented CCW).
+ *
+ * Again we walk forward and backward as far as possible. However for
+ * strips there is a twist: to get CCW orientations, there must be
+ * an *even* number of triangles in the strip on one side of eOrig.
+ * We walk the strip starting on a side with an even number of triangles;
+ * if both side have an odd number, we are forced to shorten one side.
+ */
+ struct FaceCount newFace = { 0, NULL, &RenderStrip };
+ long headSize = 0, tailSize = 0;
+ GLUface *trail = NULL;
+ GLUhalfEdge *e, *eTail, *eHead;
+
+ for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) {
+ AddToTrail( e->Lface, trail );
+ ++tailSize;
+ e = e->Dprev;
+ if( Marked( e->Lface )) break;
+ AddToTrail( e->Lface, trail );
+ }
+ eTail = e;
+
+ for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) {
+ AddToTrail( e->Rface, trail );
+ ++headSize;
+ e = e->Oprev;
+ if( Marked( e->Rface )) break;
+ AddToTrail( e->Rface, trail );
+ }
+ eHead = e;
+
+ newFace.size = tailSize + headSize;
+ if( IsEven( tailSize )) {
+ newFace.eStart = eTail->Sym;
+ } else if( IsEven( headSize )) {
+ newFace.eStart = eHead;
+ } else {
+ /* Both sides have odd length, we must shorten one of them. In fact,
+ * we must start from eHead to guarantee inclusion of eOrig->Lface.
+ */
+ --newFace.size;
+ newFace.eStart = eHead->Onext;
+ }
+ /*LINTED*/
+ FreeTrail( trail );
+ return newFace;
+}
+
+
+static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size )
+{
+ /* Just add the triangle to a triangle list, so we can render all
+ * the separate triangles at once.
+ */
+ assert( size == 1 );
+ AddToTrail( e->Lface, tess->lonelyTriList );
+}
+
+
+static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *f )
+{
+ /* Now we render all the separate triangles which could not be
+ * grouped into a triangle fan or strip.
+ */
+ GLUhalfEdge *e;
+ int newState;
+ int edgeState = -1; /* force edge state output for first vertex */
+
+ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLES );
+
+ for( ; f != NULL; f = f->trail ) {
+ /* Loop once for each edge (there will always be 3 edges) */
+
+ e = f->anEdge;
+ do {
+ if( tess->flagBoundary ) {
+ /* Set the "edge state" to TRUE just before we output the
+ * first vertex of each edge on the polygon boundary.
+ */
+ newState = ! e->Rface->inside;
+ if( edgeState != newState ) {
+ edgeState = newState;
+ CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState );
+ }
+ }
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+
+ e = e->Lnext;
+ } while( e != f->anEdge );
+ }
+ CALL_END_OR_END_DATA();
+}
+
+
+static void RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size )
+{
+ /* Render as many CCW triangles as possible in a fan starting from
+ * edge "e". The fan *should* contain exactly "size" triangles
+ * (otherwise we've goofed up somewhere).
+ */
+ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_FAN );
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+ CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
+
+ while( ! Marked( e->Lface )) {
+ e->Lface->marked = TRUE;
+ --size;
+ e = e->Onext;
+ CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
+ }
+
+ assert( size == 0 );
+ CALL_END_OR_END_DATA();
+}
+
+
+static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size )
+{
+ /* Render as many CCW triangles as possible in a strip starting from
+ * edge "e". The strip *should* contain exactly "size" triangles
+ * (otherwise we've goofed up somewhere).
+ */
+ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_STRIP );
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+ CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
+
+ while( ! Marked( e->Lface )) {
+ e->Lface->marked = TRUE;
+ --size;
+ e = e->Dprev;
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+ if( Marked( e->Lface )) break;
+
+ e->Lface->marked = TRUE;
+ --size;
+ e = e->Onext;
+ CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
+ }
+
+ assert( size == 0 );
+ CALL_END_OR_END_DATA();
+}
+
+
+/************************ Boundary contour decomposition ******************/
+
+/* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one
+ * contour for each face marked "inside". The rendering output is
+ * provided as callbacks (see the api).
+ */
+void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh )
+{
+ GLUface *f;
+ GLUhalfEdge *e;
+
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
+ if( f->inside ) {
+ CALL_BEGIN_OR_BEGIN_DATA( GL_LINE_LOOP );
+ e = f->anEdge;
+ do {
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+ e = e->Lnext;
+ } while( e != f->anEdge );
+ CALL_END_OR_END_DATA();
+ }
+ }
+}
+
+
+/************************ Quick-and-dirty decomposition ******************/
+
+#define SIGN_INCONSISTENT 2
+
+static int ComputeNormal( GLUtesselator *tess, GLdouble norm[3], int check )
+/*
+ * If check==FALSE, we compute the polygon normal and place it in norm[].
+ * If check==TRUE, we check that each triangle in the fan from v0 has a
+ * consistent orientation with respect to norm[]. If triangles are
+ * consistently oriented CCW, return 1; if CW, return -1; if all triangles
+ * are degenerate return 0; otherwise (no consistent orientation) return
+ * SIGN_INCONSISTENT.
+ */
+{
+ CachedVertex *v0 = tess->cache;
+ CachedVertex *vn = v0 + tess->cacheCount;
+ CachedVertex *vc;
+ GLdouble dot, xc, yc, zc, xp, yp, zp, n[3];
+ int sign = 0;
+
+ /* Find the polygon normal. It is important to get a reasonable
+ * normal even when the polygon is self-intersecting (eg. a bowtie).
+ * Otherwise, the computed normal could be very tiny, but perpendicular
+ * to the true plane of the polygon due to numerical noise. Then all
+ * the triangles would appear to be degenerate and we would incorrectly
+ * decompose the polygon as a fan (or simply not render it at all).
+ *
+ * We use a sum-of-triangles normal algorithm rather than the more
+ * efficient sum-of-trapezoids method (used in CheckOrientation()
+ * in normal.c). This lets us explicitly reverse the signed area
+ * of some triangles to get a reasonable normal in the self-intersecting
+ * case.
+ */
+ if( ! check ) {
+ norm[0] = norm[1] = norm[2] = 0.0;
+ }
+
+ vc = v0 + 1;
+ xc = vc->coords[0] - v0->coords[0];
+ yc = vc->coords[1] - v0->coords[1];
+ zc = vc->coords[2] - v0->coords[2];
+ while( ++vc < vn ) {
+ xp = xc; yp = yc; zp = zc;
+ xc = vc->coords[0] - v0->coords[0];
+ yc = vc->coords[1] - v0->coords[1];
+ zc = vc->coords[2] - v0->coords[2];
+
+ /* Compute (vp - v0) cross (vc - v0) */
+ n[0] = yp*zc - zp*yc;
+ n[1] = zp*xc - xp*zc;
+ n[2] = xp*yc - yp*xc;
+
+ dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2];
+ if( ! check ) {
+ /* Reverse the contribution of back-facing triangles to get
+ * a reasonable normal for self-intersecting polygons (see above)
+ */
+ if( dot >= 0 ) {
+ norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2];
+ } else {
+ norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2];
+ }
+ } else if( dot != 0 ) {
+ /* Check the new orientation for consistency with previous triangles */
+ if( dot > 0 ) {
+ if( sign < 0 ) return SIGN_INCONSISTENT;
+ sign = 1;
+ } else {
+ if( sign > 0 ) return SIGN_INCONSISTENT;
+ sign = -1;
+ }
+ }
+ }
+ return sign;
+}
+
+/* __gl_renderCache( tess ) takes a single contour and tries to render it
+ * as a triangle fan. This handles convex polygons, as well as some
+ * non-convex polygons if we get lucky.
+ *
+ * Returns TRUE if the polygon was successfully rendered. The rendering
+ * output is provided as callbacks (see the api).
+ */
+GLboolean __gl_renderCache( GLUtesselator *tess )
+{
+ CachedVertex *v0 = tess->cache;
+ CachedVertex *vn = v0 + tess->cacheCount;
+ CachedVertex *vc;
+ GLdouble norm[3];
+ int sign;
+
+ if( tess->cacheCount < 3 ) {
+ /* Degenerate contour -- no output */
+ return TRUE;
+ }
+
+ norm[0] = tess->normal[0];
+ norm[1] = tess->normal[1];
+ norm[2] = tess->normal[2];
+ if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
+ ComputeNormal( tess, norm, FALSE );
+ }
+
+ sign = ComputeNormal( tess, norm, TRUE );
+ if( sign == SIGN_INCONSISTENT ) {
+ /* Fan triangles did not have a consistent orientation */
+ return FALSE;
+ }
+ if( sign == 0 ) {
+ /* All triangles were degenerate */
+ return TRUE;
+ }
+
+ /* Make sure we do the right thing for each winding rule */
+ switch( tess->windingRule ) {
+ case GLU_TESS_WINDING_ODD:
+ case GLU_TESS_WINDING_NONZERO:
+ break;
+ case GLU_TESS_WINDING_POSITIVE:
+ if( sign < 0 ) return TRUE;
+ break;
+ case GLU_TESS_WINDING_NEGATIVE:
+ if( sign > 0 ) return TRUE;
+ break;
+ case GLU_TESS_WINDING_ABS_GEQ_TWO:
+ return TRUE;
+ }
+
+ CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GL_LINE_LOOP
+ : (tess->cacheCount > 3) ? GL_TRIANGLE_FAN
+ : GL_TRIANGLES );
+
+ CALL_VERTEX_OR_VERTEX_DATA( v0->data );
+ if( sign > 0 ) {
+ for( vc = v0+1; vc < vn; ++vc ) {
+ CALL_VERTEX_OR_VERTEX_DATA( vc->data );
+ }
+ } else {
+ for( vc = vn-1; vc > v0; --vc ) {
+ CALL_VERTEX_OR_VERTEX_DATA( vc->data );
+ }
+ }
+ CALL_END_OR_END_DATA();
+ return TRUE;
+}
diff --git a/third_party/glu/libtess/render.h b/third_party/glu/libtess/render.h
new file mode 100644
index 0000000..598423e
--- /dev/null
+++ b/third_party/glu/libtess/render.h
@@ -0,0 +1,59 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/render.h#5 $
+*/
+
+#ifndef __render_h_
+#define __render_h_
+
+#include "mesh.h"
+
+/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
+ * fans, strips, and separate triangles. A substantial effort is made
+ * to use as few rendering primitives as possible (ie. to make the fans
+ * and strips as large as possible).
+ *
+ * The rendering output is provided as callbacks (see the api).
+ */
+void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh );
+void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh );
+
+GLboolean __gl_renderCache( GLUtesselator *tess );
+
+#endif
diff --git a/third_party/glu/libtess/sweep.c b/third_party/glu/libtess/sweep.c
new file mode 100644
index 0000000..6fe8a47
--- /dev/null
+++ b/third_party/glu/libtess/sweep.c
@@ -0,0 +1,1362 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/sweep.c#5 $
+*/
+
+#include "gluos.h"
+#include <assert.h>
+#include <stddef.h>
+#include <setjmp.h> /* longjmp */
+#include <limits.h> /* LONG_MAX */
+
+#include "mesh.h"
+#include "geom.h"
+#include "tess.h"
+#include "dict.h"
+#include "priorityq.h"
+#include "memalloc.h"
+#include "sweep.h"
+
+#define TRUE 1
+#define FALSE 0
+
+#ifdef FOR_TRITE_TEST_PROGRAM
+extern void DebugEvent( GLUtesselator *tess );
+#else
+#define DebugEvent( tess )
+#endif
+
+/*
+ * Invariants for the Edge Dictionary.
+ * - each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2)
+ * at any valid location of the sweep event
+ * - if EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2
+ * share a common endpoint
+ * - for each e, e->Dst has been processed, but not e->Org
+ * - each edge e satisfies VertLeq(e->Dst,event) && VertLeq(event,e->Org)
+ * where "event" is the current sweep line event.
+ * - no edge e has zero length
+ *
+ * Invariants for the Mesh (the processed portion).
+ * - the portion of the mesh left of the sweep line is a planar graph,
+ * ie. there is *some* way to embed it in the plane
+ * - no processed edge has zero length
+ * - no two processed vertices have identical coordinates
+ * - each "inside" region is monotone, ie. can be broken into two chains
+ * of monotonically increasing vertices according to VertLeq(v1,v2)
+ * - a non-invariant: these chains may intersect (very slightly)
+ *
+ * Invariants for the Sweep.
+ * - if none of the edges incident to the event vertex have an activeRegion
+ * (ie. none of these edges are in the edge dictionary), then the vertex
+ * has only right-going edges.
+ * - if an edge is marked "fixUpperEdge" (it is a temporary edge introduced
+ * by ConnectRightVertex), then it is the only right-going edge from
+ * its associated vertex. (This says that these edges exist only
+ * when it is necessary.)
+ */
+
+#define MAX(x,y) ((x) >= (y) ? (x) : (y))
+#define MIN(x,y) ((x) <= (y) ? (x) : (y))
+
+/* When we merge two edges into one, we need to compute the combined
+ * winding of the new edge.
+ */
+#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \
+ eDst->Sym->winding += eSrc->Sym->winding)
+
+static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent );
+static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp );
+static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp );
+
+static int EdgeLeq( GLUtesselator *tess, ActiveRegion *reg1,
+ ActiveRegion *reg2 )
+/*
+ * Both edges must be directed from right to left (this is the canonical
+ * direction for the upper edge of each region).
+ *
+ * The strategy is to evaluate a "t" value for each edge at the
+ * current sweep line position, given by tess->event. The calculations
+ * are designed to be very stable, but of course they are not perfect.
+ *
+ * Special case: if both edge destinations are at the sweep event,
+ * we sort the edges by slope (they would otherwise compare equally).
+ */
+{
+ GLUvertex *event = tess->event;
+ GLUhalfEdge *e1, *e2;
+ GLdouble t1, t2;
+
+ e1 = reg1->eUp;
+ e2 = reg2->eUp;
+
+ if( e1->Dst == event ) {
+ if( e2->Dst == event ) {
+ /* Two edges right of the sweep line which meet at the sweep event.
+ * Sort them by slope.
+ */
+ if( VertLeq( e1->Org, e2->Org )) {
+ return EdgeSign( e2->Dst, e1->Org, e2->Org ) <= 0;
+ }
+ return EdgeSign( e1->Dst, e2->Org, e1->Org ) >= 0;
+ }
+ return EdgeSign( e2->Dst, event, e2->Org ) <= 0;
+ }
+ if( e2->Dst == event ) {
+ return EdgeSign( e1->Dst, event, e1->Org ) >= 0;
+ }
+
+ /* General case - compute signed distance *from* e1, e2 to event */
+ t1 = EdgeEval( e1->Dst, event, e1->Org );
+ t2 = EdgeEval( e2->Dst, event, e2->Org );
+ return (t1 >= t2);
+}
+
+
+static void DeleteRegion( GLUtesselator *tess, ActiveRegion *reg )
+{
+ if( reg->fixUpperEdge ) {
+ /* It was created with zero winding number, so it better be
+ * deleted with zero winding number (ie. it better not get merged
+ * with a real edge).
+ */
+ assert( reg->eUp->winding == 0 );
+ }
+ reg->eUp->activeRegion = NULL;
+ dictDelete( tess->dict, reg->nodeUp ); /* __gl_dictListDelete */
+ memFree( reg );
+}
+
+
+static int FixUpperEdge( ActiveRegion *reg, GLUhalfEdge *newEdge )
+/*
+ * Replace an upper edge which needs fixing (see ConnectRightVertex).
+ */
+{
+ assert( reg->fixUpperEdge );
+ if ( !__gl_meshDelete( reg->eUp ) ) return 0;
+ reg->fixUpperEdge = FALSE;
+ reg->eUp = newEdge;
+ newEdge->activeRegion = reg;
+
+ return 1;
+}
+
+static ActiveRegion *TopLeftRegion( ActiveRegion *reg )
+{
+ GLUvertex *org = reg->eUp->Org;
+ GLUhalfEdge *e;
+
+ /* Find the region above the uppermost edge with the same origin */
+ do {
+ reg = RegionAbove( reg );
+ } while( reg->eUp->Org == org );
+
+ /* If the edge above was a temporary edge introduced by ConnectRightVertex,
+ * now is the time to fix it.
+ */
+ if( reg->fixUpperEdge ) {
+ e = __gl_meshConnect( RegionBelow(reg)->eUp->Sym, reg->eUp->Lnext );
+ if (e == NULL) return NULL;
+ if ( !FixUpperEdge( reg, e ) ) return NULL;
+ reg = RegionAbove( reg );
+ }
+ return reg;
+}
+
+static ActiveRegion *TopRightRegion( ActiveRegion *reg )
+{
+ GLUvertex *dst = reg->eUp->Dst;
+
+ /* Find the region above the uppermost edge with the same destination */
+ do {
+ reg = RegionAbove( reg );
+ } while( reg->eUp->Dst == dst );
+ return reg;
+}
+
+static ActiveRegion *AddRegionBelow( GLUtesselator *tess,
+ ActiveRegion *regAbove,
+ GLUhalfEdge *eNewUp )
+/*
+ * Add a new active region to the sweep line, *somewhere* below "regAbove"
+ * (according to where the new edge belongs in the sweep-line dictionary).
+ * The upper edge of the new region will be "eNewUp".
+ * Winding number and "inside" flag are not updated.
+ */
+{
+ ActiveRegion *regNew = (ActiveRegion *)memAlloc( sizeof( ActiveRegion ));
+ if (regNew == NULL) longjmp(tess->env,1);
+
+ regNew->eUp = eNewUp;
+ /* __gl_dictListInsertBefore */
+ regNew->nodeUp = dictInsertBefore( tess->dict, regAbove->nodeUp, regNew );
+ if (regNew->nodeUp == NULL) longjmp(tess->env,1);
+ regNew->fixUpperEdge = FALSE;
+ regNew->sentinel = FALSE;
+ regNew->dirty = FALSE;
+
+ eNewUp->activeRegion = regNew;
+ return regNew;
+}
+
+static GLboolean IsWindingInside( GLUtesselator *tess, int n )
+{
+ switch( tess->windingRule ) {
+ case GLU_TESS_WINDING_ODD:
+ return (n & 1);
+ case GLU_TESS_WINDING_NONZERO:
+ return (n != 0);
+ case GLU_TESS_WINDING_POSITIVE:
+ return (n > 0);
+ case GLU_TESS_WINDING_NEGATIVE:
+ return (n < 0);
+ case GLU_TESS_WINDING_ABS_GEQ_TWO:
+ return (n >= 2) || (n <= -2);
+ }
+ /*LINTED*/
+ assert( FALSE );
+ /*NOTREACHED*/
+ return 0;
+}
+
+
+static void ComputeWinding( GLUtesselator *tess, ActiveRegion *reg )
+{
+ reg->windingNumber = RegionAbove(reg)->windingNumber + reg->eUp->winding;
+ reg->inside = IsWindingInside( tess, reg->windingNumber );
+}
+
+
+static void FinishRegion( GLUtesselator *tess, ActiveRegion *reg )
+/*
+ * Delete a region from the sweep line. This happens when the upper
+ * and lower chains of a region meet (at a vertex on the sweep line).
+ * The "inside" flag is copied to the appropriate mesh face (we could
+ * not do this before -- since the structure of the mesh is always
+ * changing, this face may not have even existed until now).
+ */
+{
+ GLUhalfEdge *e = reg->eUp;
+ GLUface *f = e->Lface;
+
+ f->inside = reg->inside;
+ f->anEdge = e; /* optimization for __gl_meshTessellateMonoRegion() */
+ DeleteRegion( tess, reg );
+}
+
+
+static GLUhalfEdge *FinishLeftRegions( GLUtesselator *tess,
+ ActiveRegion *regFirst, ActiveRegion *regLast )
+/*
+ * We are given a vertex with one or more left-going edges. All affected
+ * edges should be in the edge dictionary. Starting at regFirst->eUp,
+ * we walk down deleting all regions where both edges have the same
+ * origin vOrg. At the same time we copy the "inside" flag from the
+ * active region to the face, since at this point each face will belong
+ * to at most one region (this was not necessarily true until this point
+ * in the sweep). The walk stops at the region above regLast; if regLast
+ * is NULL we walk as far as possible. At the same time we relink the
+ * mesh if necessary, so that the ordering of edges around vOrg is the
+ * same as in the dictionary.
+ */
+{
+ ActiveRegion *reg, *regPrev;
+ GLUhalfEdge *e, *ePrev;
+
+ regPrev = regFirst;
+ ePrev = regFirst->eUp;
+ while( regPrev != regLast ) {
+ regPrev->fixUpperEdge = FALSE; /* placement was OK */
+ reg = RegionBelow( regPrev );
+ e = reg->eUp;
+ if( e->Org != ePrev->Org ) {
+ if( ! reg->fixUpperEdge ) {
+ /* Remove the last left-going edge. Even though there are no further
+ * edges in the dictionary with this origin, there may be further
+ * such edges in the mesh (if we are adding left edges to a vertex
+ * that has already been processed). Thus it is important to call
+ * FinishRegion rather than just DeleteRegion.
+ */
+ FinishRegion( tess, regPrev );
+ break;
+ }
+ /* If the edge below was a temporary edge introduced by
+ * ConnectRightVertex, now is the time to fix it.
+ */
+ e = __gl_meshConnect( ePrev->Lprev, e->Sym );
+ if (e == NULL) longjmp(tess->env,1);
+ if ( !FixUpperEdge( reg, e ) ) longjmp(tess->env,1);
+ }
+
+ /* Relink edges so that ePrev->Onext == e */
+ if( ePrev->Onext != e ) {
+ if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( ePrev, e ) ) longjmp(tess->env,1);
+ }
+ FinishRegion( tess, regPrev ); /* may change reg->eUp */
+ ePrev = reg->eUp;
+ regPrev = reg;
+ }
+ return ePrev;
+}
+
+
+static void AddRightEdges( GLUtesselator *tess, ActiveRegion *regUp,
+ GLUhalfEdge *eFirst, GLUhalfEdge *eLast, GLUhalfEdge *eTopLeft,
+ GLboolean cleanUp )
+/*
+ * Purpose: insert right-going edges into the edge dictionary, and update
+ * winding numbers and mesh connectivity appropriately. All right-going
+ * edges share a common origin vOrg. Edges are inserted CCW starting at
+ * eFirst; the last edge inserted is eLast->Oprev. If vOrg has any
+ * left-going edges already processed, then eTopLeft must be the edge
+ * such that an imaginary upward vertical segment from vOrg would be
+ * contained between eTopLeft->Oprev and eTopLeft; otherwise eTopLeft
+ * should be NULL.
+ */
+{
+ ActiveRegion *reg, *regPrev;
+ GLUhalfEdge *e, *ePrev;
+ int firstTime = TRUE;
+
+ /* Insert the new right-going edges in the dictionary */
+ e = eFirst;
+ do {
+ assert( VertLeq( e->Org, e->Dst ));
+ AddRegionBelow( tess, regUp, e->Sym );
+ e = e->Onext;
+ } while ( e != eLast );
+
+ /* Walk *all* right-going edges from e->Org, in the dictionary order,
+ * updating the winding numbers of each region, and re-linking the mesh
+ * edges to match the dictionary ordering (if necessary).
+ */
+ if( eTopLeft == NULL ) {
+ eTopLeft = RegionBelow( regUp )->eUp->Rprev;
+ }
+ regPrev = regUp;
+ ePrev = eTopLeft;
+ for( ;; ) {
+ reg = RegionBelow( regPrev );
+ e = reg->eUp->Sym;
+ if( e->Org != ePrev->Org ) break;
+
+ if( e->Onext != ePrev ) {
+ /* Unlink e from its current position, and relink below ePrev */
+ if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( ePrev->Oprev, e ) ) longjmp(tess->env,1);
+ }
+ /* Compute the winding number and "inside" flag for the new regions */
+ reg->windingNumber = regPrev->windingNumber - e->winding;
+ reg->inside = IsWindingInside( tess, reg->windingNumber );
+
+ /* Check for two outgoing edges with same slope -- process these
+ * before any intersection tests (see example in __gl_computeInterior).
+ */
+ regPrev->dirty = TRUE;
+ if( ! firstTime && CheckForRightSplice( tess, regPrev )) {
+ AddWinding( e, ePrev );
+ DeleteRegion( tess, regPrev );
+ if ( !__gl_meshDelete( ePrev ) ) longjmp(tess->env,1);
+ }
+ firstTime = FALSE;
+ regPrev = reg;
+ ePrev = e;
+ }
+ regPrev->dirty = TRUE;
+ assert( regPrev->windingNumber - e->winding == reg->windingNumber );
+
+ if( cleanUp ) {
+ /* Check for intersections between newly adjacent edges. */
+ WalkDirtyRegions( tess, regPrev );
+ }
+}
+
+
+static void CallCombine( GLUtesselator *tess, GLUvertex *isect,
+ void *data[4], GLfloat weights[4], int needed )
+{
+ GLdouble coords[3];
+
+ /* Copy coord data in case the callback changes it. */
+ coords[0] = isect->coords[0];
+ coords[1] = isect->coords[1];
+ coords[2] = isect->coords[2];
+
+ isect->data = NULL;
+ CALL_COMBINE_OR_COMBINE_DATA( coords, data, weights, &isect->data );
+ if( isect->data == NULL ) {
+ if( ! needed ) {
+ isect->data = data[0];
+ } else if( ! tess->fatalError ) {
+ /* The only way fatal error is when two edges are found to intersect,
+ * but the user has not provided the callback necessary to handle
+ * generated intersection points.
+ */
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_NEED_COMBINE_CALLBACK );
+ tess->fatalError = TRUE;
+ }
+ }
+}
+
+static void SpliceMergeVertices( GLUtesselator *tess, GLUhalfEdge *e1,
+ GLUhalfEdge *e2 )
+/*
+ * Two vertices with idential coordinates are combined into one.
+ * e1->Org is kept, while e2->Org is discarded.
+ */
+{
+ void *data[4] = { NULL, NULL, NULL, NULL };
+ GLfloat weights[4] = { 0.5, 0.5, 0.0, 0.0 };
+
+ data[0] = e1->Org->data;
+ data[1] = e2->Org->data;
+ CallCombine( tess, e1->Org, data, weights, FALSE );
+ if ( !__gl_meshSplice( e1, e2 ) ) longjmp(tess->env,1);
+}
+
+static void VertexWeights( GLUvertex *isect, GLUvertex *org, GLUvertex *dst,
+ GLfloat *weights )
+/*
+ * Find some weights which describe how the intersection vertex is
+ * a linear combination of "org" and "dest". Each of the two edges
+ * which generated "isect" is allocated 50% of the weight; each edge
+ * splits the weight between its org and dst according to the
+ * relative distance to "isect".
+ */
+{
+ GLdouble t1 = VertL1dist( org, isect );
+ GLdouble t2 = VertL1dist( dst, isect );
+
+ weights[0] = 0.5 * t2 / (t1 + t2);
+ weights[1] = 0.5 * t1 / (t1 + t2);
+ isect->coords[0] += weights[0]*org->coords[0] + weights[1]*dst->coords[0];
+ isect->coords[1] += weights[0]*org->coords[1] + weights[1]*dst->coords[1];
+ isect->coords[2] += weights[0]*org->coords[2] + weights[1]*dst->coords[2];
+}
+
+
+static void GetIntersectData( GLUtesselator *tess, GLUvertex *isect,
+ GLUvertex *orgUp, GLUvertex *dstUp,
+ GLUvertex *orgLo, GLUvertex *dstLo )
+/*
+ * We've computed a new intersection point, now we need a "data" pointer
+ * from the user so that we can refer to this new vertex in the
+ * rendering callbacks.
+ */
+{
+ void *data[4];
+ GLfloat weights[4];
+
+ data[0] = orgUp->data;
+ data[1] = dstUp->data;
+ data[2] = orgLo->data;
+ data[3] = dstLo->data;
+
+ isect->coords[0] = isect->coords[1] = isect->coords[2] = 0;
+ VertexWeights( isect, orgUp, dstUp, &weights[0] );
+ VertexWeights( isect, orgLo, dstLo, &weights[2] );
+
+ CallCombine( tess, isect, data, weights, TRUE );
+}
+
+static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * Check the upper and lower edge of "regUp", to make sure that the
+ * eUp->Org is above eLo, or eLo->Org is below eUp (depending on which
+ * origin is leftmost).
+ *
+ * The main purpose is to splice right-going edges with the same
+ * dest vertex and nearly identical slopes (ie. we can't distinguish
+ * the slopes numerically). However the splicing can also help us
+ * to recover from numerical errors. For example, suppose at one
+ * point we checked eUp and eLo, and decided that eUp->Org is barely
+ * above eLo. Then later, we split eLo into two edges (eg. from
+ * a splice operation like this one). This can change the result of
+ * our test so that now eUp->Org is incident to eLo, or barely below it.
+ * We must correct this condition to maintain the dictionary invariants.
+ *
+ * One possibility is to check these edges for intersection again
+ * (ie. CheckForIntersect). This is what we do if possible. However
+ * CheckForIntersect requires that tess->event lies between eUp and eLo,
+ * so that it has something to fall back on when the intersection
+ * calculation gives us an unusable answer. So, for those cases where
+ * we can't check for intersection, this routine fixes the problem
+ * by just splicing the offending vertex into the other edge.
+ * This is a guaranteed solution, no matter how degenerate things get.
+ * Basically this is a combinatorial solution to a numerical problem.
+ */
+{
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp = regUp->eUp;
+ GLUhalfEdge *eLo = regLo->eUp;
+
+ if( VertLeq( eUp->Org, eLo->Org )) {
+ if( EdgeSign( eLo->Dst, eUp->Org, eLo->Org ) > 0 ) return FALSE;
+
+ /* eUp->Org appears to be below eLo */
+ if( ! VertEq( eUp->Org, eLo->Org )) {
+ /* Splice eUp->Org into eLo */
+ if ( __gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eUp, eLo->Oprev ) ) longjmp(tess->env,1);
+ regUp->dirty = regLo->dirty = TRUE;
+
+ } else if( eUp->Org != eLo->Org ) {
+ /* merge the two vertices, discarding eUp->Org */
+ pqDelete( tess->pq, eUp->Org->pqHandle ); /* __gl_pqSortDelete */
+ SpliceMergeVertices( tess, eLo->Oprev, eUp );
+ }
+ } else {
+ if( EdgeSign( eUp->Dst, eLo->Org, eUp->Org ) < 0 ) return FALSE;
+
+ /* eLo->Org appears to be above eUp, so splice eLo->Org into eUp */
+ RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
+ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1);
+ }
+ return TRUE;
+}
+
+static int CheckForLeftSplice( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * Check the upper and lower edge of "regUp", to make sure that the
+ * eUp->Dst is above eLo, or eLo->Dst is below eUp (depending on which
+ * destination is rightmost).
+ *
+ * Theoretically, this should always be true. However, splitting an edge
+ * into two pieces can change the results of previous tests. For example,
+ * suppose at one point we checked eUp and eLo, and decided that eUp->Dst
+ * is barely above eLo. Then later, we split eLo into two edges (eg. from
+ * a splice operation like this one). This can change the result of
+ * the test so that now eUp->Dst is incident to eLo, or barely below it.
+ * We must correct this condition to maintain the dictionary invariants
+ * (otherwise new edges might get inserted in the wrong place in the
+ * dictionary, and bad stuff will happen).
+ *
+ * We fix the problem by just splicing the offending vertex into the
+ * other edge.
+ */
+{
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp = regUp->eUp;
+ GLUhalfEdge *eLo = regLo->eUp;
+ GLUhalfEdge *e;
+
+ assert( ! VertEq( eUp->Dst, eLo->Dst ));
+
+ if( VertLeq( eUp->Dst, eLo->Dst )) {
+ if( EdgeSign( eUp->Dst, eLo->Dst, eUp->Org ) < 0 ) return FALSE;
+
+ /* eLo->Dst is above eUp, so splice eLo->Dst into eUp */
+ RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
+ e = __gl_meshSplitEdge( eUp );
+ if (e == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eLo->Sym, e ) ) longjmp(tess->env,1);
+ e->Lface->inside = regUp->inside;
+ } else {
+ if( EdgeSign( eLo->Dst, eUp->Dst, eLo->Org ) > 0 ) return FALSE;
+
+ /* eUp->Dst is below eLo, so splice eUp->Dst into eLo */
+ regUp->dirty = regLo->dirty = TRUE;
+ e = __gl_meshSplitEdge( eLo );
+ if (e == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eUp->Lnext, eLo->Sym ) ) longjmp(tess->env,1);
+ e->Rface->inside = regUp->inside;
+ }
+ return TRUE;
+}
+
+
+static int CheckForIntersect( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * Check the upper and lower edges of the given region to see if
+ * they intersect. If so, create the intersection and add it
+ * to the data structures.
+ *
+ * Returns TRUE if adding the new intersection resulted in a recursive
+ * call to AddRightEdges(); in this case all "dirty" regions have been
+ * checked for intersections, and possibly regUp has been deleted.
+ */
+{
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp = regUp->eUp;
+ GLUhalfEdge *eLo = regLo->eUp;
+ GLUvertex *orgUp = eUp->Org;
+ GLUvertex *orgLo = eLo->Org;
+ GLUvertex *dstUp = eUp->Dst;
+ GLUvertex *dstLo = eLo->Dst;
+ GLdouble tMinUp, tMaxLo;
+ GLUvertex isect, *orgMin;
+ GLUhalfEdge *e;
+
+ assert( ! VertEq( dstLo, dstUp ));
+ assert( EdgeSign( dstUp, tess->event, orgUp ) <= 0 );
+ assert( EdgeSign( dstLo, tess->event, orgLo ) >= 0 );
+ assert( orgUp != tess->event && orgLo != tess->event );
+ assert( ! regUp->fixUpperEdge && ! regLo->fixUpperEdge );
+
+ if( orgUp == orgLo ) return FALSE; /* right endpoints are the same */
+
+ tMinUp = MIN( orgUp->t, dstUp->t );
+ tMaxLo = MAX( orgLo->t, dstLo->t );
+ if( tMinUp > tMaxLo ) return FALSE; /* t ranges do not overlap */
+
+ if( VertLeq( orgUp, orgLo )) {
+ if( EdgeSign( dstLo, orgUp, orgLo ) > 0 ) return FALSE;
+ } else {
+ if( EdgeSign( dstUp, orgLo, orgUp ) < 0 ) return FALSE;
+ }
+
+ /* At this point the edges intersect, at least marginally */
+ DebugEvent( tess );
+
+ __gl_edgeIntersect( dstUp, orgUp, dstLo, orgLo, &isect );
+ /* The following properties are guaranteed: */
+ assert( MIN( orgUp->t, dstUp->t ) <= isect.t );
+ assert( isect.t <= MAX( orgLo->t, dstLo->t ));
+ assert( MIN( dstLo->s, dstUp->s ) <= isect.s );
+ assert( isect.s <= MAX( orgLo->s, orgUp->s ));
+
+ if( VertLeq( &isect, tess->event )) {
+ /* The intersection point lies slightly to the left of the sweep line,
+ * so move it until it''s slightly to the right of the sweep line.
+ * (If we had perfect numerical precision, this would never happen
+ * in the first place). The easiest and safest thing to do is
+ * replace the intersection by tess->event.
+ */
+ isect.s = tess->event->s;
+ isect.t = tess->event->t;
+ }
+ /* Similarly, if the computed intersection lies to the right of the
+ * rightmost origin (which should rarely happen), it can cause
+ * unbelievable inefficiency on sufficiently degenerate inputs.
+ * (If you have the test program, try running test54.d with the
+ * "X zoom" option turned on).
+ */
+ orgMin = VertLeq( orgUp, orgLo ) ? orgUp : orgLo;
+ if( VertLeq( orgMin, &isect )) {
+ isect.s = orgMin->s;
+ isect.t = orgMin->t;
+ }
+
+ if( VertEq( &isect, orgUp ) || VertEq( &isect, orgLo )) {
+ /* Easy case -- intersection at one of the right endpoints */
+ (void) CheckForRightSplice( tess, regUp );
+ return FALSE;
+ }
+
+ if( (! VertEq( dstUp, tess->event )
+ && EdgeSign( dstUp, tess->event, &isect ) >= 0)
+ || (! VertEq( dstLo, tess->event )
+ && EdgeSign( dstLo, tess->event, &isect ) <= 0 ))
+ {
+ /* Very unusual -- the new upper or lower edge would pass on the
+ * wrong side of the sweep event, or through it. This can happen
+ * due to very small numerical errors in the intersection calculation.
+ */
+ if( dstLo == tess->event ) {
+ /* Splice dstLo into eUp, and process the new region(s) */
+ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eLo->Sym, eUp ) ) longjmp(tess->env,1);
+ regUp = TopLeftRegion( regUp );
+ if (regUp == NULL) longjmp(tess->env,1);
+ eUp = RegionBelow(regUp)->eUp;
+ FinishLeftRegions( tess, RegionBelow(regUp), regLo );
+ AddRightEdges( tess, regUp, eUp->Oprev, eUp, eUp, TRUE );
+ return TRUE;
+ }
+ if( dstUp == tess->event ) {
+ /* Splice dstUp into eLo, and process the new region(s) */
+ if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eUp->Lnext, eLo->Oprev ) ) longjmp(tess->env,1);
+ regLo = regUp;
+ regUp = TopRightRegion( regUp );
+ e = RegionBelow(regUp)->eUp->Rprev;
+ regLo->eUp = eLo->Oprev;
+ eLo = FinishLeftRegions( tess, regLo, NULL );
+ AddRightEdges( tess, regUp, eLo->Onext, eUp->Rprev, e, TRUE );
+ return TRUE;
+ }
+ /* Special case: called from ConnectRightVertex. If either
+ * edge passes on the wrong side of tess->event, split it
+ * (and wait for ConnectRightVertex to splice it appropriately).
+ */
+ if( EdgeSign( dstUp, tess->event, &isect ) >= 0 ) {
+ RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
+ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+ eUp->Org->s = tess->event->s;
+ eUp->Org->t = tess->event->t;
+ }
+ if( EdgeSign( dstLo, tess->event, &isect ) <= 0 ) {
+ regUp->dirty = regLo->dirty = TRUE;
+ if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+ eLo->Org->s = tess->event->s;
+ eLo->Org->t = tess->event->t;
+ }
+ /* leave the rest for ConnectRightVertex */
+ return FALSE;
+ }
+
+ /* General case -- split both edges, splice into new vertex.
+ * When we do the splice operation, the order of the arguments is
+ * arbitrary as far as correctness goes. However, when the operation
+ * creates a new face, the work done is proportional to the size of
+ * the new face. We expect the faces in the processed part of
+ * the mesh (ie. eUp->Lface) to be smaller than the faces in the
+ * unprocessed original contours (which will be eLo->Oprev->Lface).
+ */
+ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+ if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1);
+ eUp->Org->s = isect.s;
+ eUp->Org->t = isect.t;
+ eUp->Org->pqHandle = pqInsert( tess->pq, eUp->Org ); /* __gl_pqSortInsert */
+ if (eUp->Org->pqHandle == LONG_MAX) {
+ pqDeletePriorityQ(tess->pq); /* __gl_pqSortDeletePriorityQ */
+ tess->pq = NULL;
+ longjmp(tess->env,1);
+ }
+ GetIntersectData( tess, eUp->Org, orgUp, dstUp, orgLo, dstLo );
+ RegionAbove(regUp)->dirty = regUp->dirty = regLo->dirty = TRUE;
+ return FALSE;
+}
+
+static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * When the upper or lower edge of any region changes, the region is
+ * marked "dirty". This routine walks through all the dirty regions
+ * and makes sure that the dictionary invariants are satisfied
+ * (see the comments at the beginning of this file). Of course
+ * new dirty regions can be created as we make changes to restore
+ * the invariants.
+ */
+{
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp, *eLo;
+
+ for( ;; ) {
+ /* Find the lowest dirty region (we walk from the bottom up). */
+ while( regLo->dirty ) {
+ regUp = regLo;
+ regLo = RegionBelow(regLo);
+ }
+ if( ! regUp->dirty ) {
+ regLo = regUp;
+ regUp = RegionAbove( regUp );
+ if( regUp == NULL || ! regUp->dirty ) {
+ /* We've walked all the dirty regions */
+ return;
+ }
+ }
+ regUp->dirty = FALSE;
+ eUp = regUp->eUp;
+ eLo = regLo->eUp;
+
+ if( eUp->Dst != eLo->Dst ) {
+ /* Check that the edge ordering is obeyed at the Dst vertices. */
+ if( CheckForLeftSplice( tess, regUp )) {
+
+ /* If the upper or lower edge was marked fixUpperEdge, then
+ * we no longer need it (since these edges are needed only for
+ * vertices which otherwise have no right-going edges).
+ */
+ if( regLo->fixUpperEdge ) {
+ DeleteRegion( tess, regLo );
+ if ( !__gl_meshDelete( eLo ) ) longjmp(tess->env,1);
+ regLo = RegionBelow( regUp );
+ eLo = regLo->eUp;
+ } else if( regUp->fixUpperEdge ) {
+ DeleteRegion( tess, regUp );
+ if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1);
+ regUp = RegionAbove( regLo );
+ eUp = regUp->eUp;
+ }
+ }
+ }
+ if( eUp->Org != eLo->Org ) {
+ if( eUp->Dst != eLo->Dst
+ && ! regUp->fixUpperEdge && ! regLo->fixUpperEdge
+ && (eUp->Dst == tess->event || eLo->Dst == tess->event) )
+ {
+ /* When all else fails in CheckForIntersect(), it uses tess->event
+ * as the intersection location. To make this possible, it requires
+ * that tess->event lie between the upper and lower edges, and also
+ * that neither of these is marked fixUpperEdge (since in the worst
+ * case it might splice one of these edges into tess->event, and
+ * violate the invariant that fixable edges are the only right-going
+ * edge from their associated vertex).
+ */
+ if( CheckForIntersect( tess, regUp )) {
+ /* WalkDirtyRegions() was called recursively; we're done */
+ return;
+ }
+ } else {
+ /* Even though we can't use CheckForIntersect(), the Org vertices
+ * may violate the dictionary edge ordering. Check and correct this.
+ */
+ (void) CheckForRightSplice( tess, regUp );
+ }
+ }
+ if( eUp->Org == eLo->Org && eUp->Dst == eLo->Dst ) {
+ /* A degenerate loop consisting of only two edges -- delete it. */
+ AddWinding( eLo, eUp );
+ DeleteRegion( tess, regUp );
+ if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1);
+ regUp = RegionAbove( regLo );
+ }
+ }
+}
+
+
+static void ConnectRightVertex( GLUtesselator *tess, ActiveRegion *regUp,
+ GLUhalfEdge *eBottomLeft )
+/*
+ * Purpose: connect a "right" vertex vEvent (one where all edges go left)
+ * to the unprocessed portion of the mesh. Since there are no right-going
+ * edges, two regions (one above vEvent and one below) are being merged
+ * into one. "regUp" is the upper of these two regions.
+ *
+ * There are two reasons for doing this (adding a right-going edge):
+ * - if the two regions being merged are "inside", we must add an edge
+ * to keep them separated (the combined region would not be monotone).
+ * - in any case, we must leave some record of vEvent in the dictionary,
+ * so that we can merge vEvent with features that we have not seen yet.
+ * For example, maybe there is a vertical edge which passes just to
+ * the right of vEvent; we would like to splice vEvent into this edge.
+ *
+ * However, we don't want to connect vEvent to just any vertex. We don''t
+ * want the new edge to cross any other edges; otherwise we will create
+ * intersection vertices even when the input data had no self-intersections.
+ * (This is a bad thing; if the user's input data has no intersections,
+ * we don't want to generate any false intersections ourselves.)
+ *
+ * Our eventual goal is to connect vEvent to the leftmost unprocessed
+ * vertex of the combined region (the union of regUp and regLo).
+ * But because of unseen vertices with all right-going edges, and also
+ * new vertices which may be created by edge intersections, we don''t
+ * know where that leftmost unprocessed vertex is. In the meantime, we
+ * connect vEvent to the closest vertex of either chain, and mark the region
+ * as "fixUpperEdge". This flag says to delete and reconnect this edge
+ * to the next processed vertex on the boundary of the combined region.
+ * Quite possibly the vertex we connected to will turn out to be the
+ * closest one, in which case we won''t need to make any changes.
+ */
+{
+ GLUhalfEdge *eNew;
+ GLUhalfEdge *eTopLeft = eBottomLeft->Onext;
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp = regUp->eUp;
+ GLUhalfEdge *eLo = regLo->eUp;
+ int degenerate = FALSE;
+
+ if( eUp->Dst != eLo->Dst ) {
+ (void) CheckForIntersect( tess, regUp );
+ }
+
+ /* Possible new degeneracies: upper or lower edge of regUp may pass
+ * through vEvent, or may coincide with new intersection vertex
+ */
+ if( VertEq( eUp->Org, tess->event )) {
+ if ( !__gl_meshSplice( eTopLeft->Oprev, eUp ) ) longjmp(tess->env,1);
+ regUp = TopLeftRegion( regUp );
+ if (regUp == NULL) longjmp(tess->env,1);
+ eTopLeft = RegionBelow( regUp )->eUp;
+ FinishLeftRegions( tess, RegionBelow(regUp), regLo );
+ degenerate = TRUE;
+ }
+ if( VertEq( eLo->Org, tess->event )) {
+ if ( !__gl_meshSplice( eBottomLeft, eLo->Oprev ) ) longjmp(tess->env,1);
+ eBottomLeft = FinishLeftRegions( tess, regLo, NULL );
+ degenerate = TRUE;
+ }
+ if( degenerate ) {
+ AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE );
+ return;
+ }
+
+ /* Non-degenerate situation -- need to add a temporary, fixable edge.
+ * Connect to the closer of eLo->Org, eUp->Org.
+ */
+ if( VertLeq( eLo->Org, eUp->Org )) {
+ eNew = eLo->Oprev;
+ } else {
+ eNew = eUp;
+ }
+ eNew = __gl_meshConnect( eBottomLeft->Lprev, eNew );
+ if (eNew == NULL) longjmp(tess->env,1);
+
+ /* Prevent cleanup, otherwise eNew might disappear before we've even
+ * had a chance to mark it as a temporary edge.
+ */
+ AddRightEdges( tess, regUp, eNew, eNew->Onext, eNew->Onext, FALSE );
+ eNew->Sym->activeRegion->fixUpperEdge = TRUE;
+ WalkDirtyRegions( tess, regUp );
+}
+
+/* Because vertices at exactly the same location are merged together
+ * before we process the sweep event, some degenerate cases can't occur.
+ * However if someone eventually makes the modifications required to
+ * merge features which are close together, the cases below marked
+ * TOLERANCE_NONZERO will be useful. They were debugged before the
+ * code to merge identical vertices in the main loop was added.
+ */
+#define TOLERANCE_NONZERO FALSE
+
+static void ConnectLeftDegenerate( GLUtesselator *tess,
+ ActiveRegion *regUp, GLUvertex *vEvent )
+/*
+ * The event vertex lies exacty on an already-processed edge or vertex.
+ * Adding the new vertex involves splicing it into the already-processed
+ * part of the mesh.
+ */
+{
+ GLUhalfEdge *e, *eTopLeft, *eTopRight, *eLast;
+ ActiveRegion *reg;
+
+ e = regUp->eUp;
+ if( VertEq( e->Org, vEvent )) {
+ /* e->Org is an unprocessed vertex - just combine them, and wait
+ * for e->Org to be pulled from the queue
+ */
+ assert( TOLERANCE_NONZERO );
+ SpliceMergeVertices( tess, e, vEvent->anEdge );
+ return;
+ }
+
+ if( ! VertEq( e->Dst, vEvent )) {
+ /* General case -- splice vEvent into edge e which passes through it */
+ if (__gl_meshSplitEdge( e->Sym ) == NULL) longjmp(tess->env,1);
+ if( regUp->fixUpperEdge ) {
+ /* This edge was fixable -- delete unused portion of original edge */
+ if ( !__gl_meshDelete( e->Onext ) ) longjmp(tess->env,1);
+ regUp->fixUpperEdge = FALSE;
+ }
+ if ( !__gl_meshSplice( vEvent->anEdge, e ) ) longjmp(tess->env,1);
+ SweepEvent( tess, vEvent ); /* recurse */
+ return;
+ }
+
+ /* vEvent coincides with e->Dst, which has already been processed.
+ * Splice in the additional right-going edges.
+ */
+ assert( TOLERANCE_NONZERO );
+ regUp = TopRightRegion( regUp );
+ reg = RegionBelow( regUp );
+ eTopRight = reg->eUp->Sym;
+ eTopLeft = eLast = eTopRight->Onext;
+ if( reg->fixUpperEdge ) {
+ /* Here e->Dst has only a single fixable edge going right.
+ * We can delete it since now we have some real right-going edges.
+ */
+ assert( eTopLeft != eTopRight ); /* there are some left edges too */
+ DeleteRegion( tess, reg );
+ if ( !__gl_meshDelete( eTopRight ) ) longjmp(tess->env,1);
+ eTopRight = eTopLeft->Oprev;
+ }
+ if ( !__gl_meshSplice( vEvent->anEdge, eTopRight ) ) longjmp(tess->env,1);
+ if( ! EdgeGoesLeft( eTopLeft )) {
+ /* e->Dst had no left-going edges -- indicate this to AddRightEdges() */
+ eTopLeft = NULL;
+ }
+ AddRightEdges( tess, regUp, eTopRight->Onext, eLast, eTopLeft, TRUE );
+}
+
+
+static void ConnectLeftVertex( GLUtesselator *tess, GLUvertex *vEvent )
+/*
+ * Purpose: connect a "left" vertex (one where both edges go right)
+ * to the processed portion of the mesh. Let R be the active region
+ * containing vEvent, and let U and L be the upper and lower edge
+ * chains of R. There are two possibilities:
+ *
+ * - the normal case: split R into two regions, by connecting vEvent to
+ * the rightmost vertex of U or L lying to the left of the sweep line
+ *
+ * - the degenerate case: if vEvent is close enough to U or L, we
+ * merge vEvent into that edge chain. The subcases are:
+ * - merging with the rightmost vertex of U or L
+ * - merging with the active edge of U or L
+ * - merging with an already-processed portion of U or L
+ */
+{
+ ActiveRegion *regUp, *regLo, *reg;
+ GLUhalfEdge *eUp, *eLo, *eNew;
+ ActiveRegion tmp;
+
+ /* assert( vEvent->anEdge->Onext->Onext == vEvent->anEdge ); */
+
+ /* Get a pointer to the active region containing vEvent */
+ tmp.eUp = vEvent->anEdge->Sym;
+ /* __GL_DICTLISTKEY */ /* __gl_dictListSearch */
+ regUp = (ActiveRegion *)dictKey( dictSearch( tess->dict, &tmp ));
+ regLo = RegionBelow( regUp );
+ eUp = regUp->eUp;
+ eLo = regLo->eUp;
+
+ /* Try merging with U or L first */
+ if( EdgeSign( eUp->Dst, vEvent, eUp->Org ) == 0 ) {
+ ConnectLeftDegenerate( tess, regUp, vEvent );
+ return;
+ }
+
+ /* Connect vEvent to rightmost processed vertex of either chain.
+ * e->Dst is the vertex that we will connect to vEvent.
+ */
+ reg = VertLeq( eLo->Dst, eUp->Dst ) ? regUp : regLo;
+
+ if( regUp->inside || reg->fixUpperEdge) {
+ if( reg == regUp ) {
+ eNew = __gl_meshConnect( vEvent->anEdge->Sym, eUp->Lnext );
+ if (eNew == NULL) longjmp(tess->env,1);
+ } else {
+ GLUhalfEdge *tempHalfEdge= __gl_meshConnect( eLo->Dnext, vEvent->anEdge);
+ if (tempHalfEdge == NULL) longjmp(tess->env,1);
+
+ eNew = tempHalfEdge->Sym;
+ }
+ if( reg->fixUpperEdge ) {
+ if ( !FixUpperEdge( reg, eNew ) ) longjmp(tess->env,1);
+ } else {
+ ComputeWinding( tess, AddRegionBelow( tess, regUp, eNew ));
+ }
+ SweepEvent( tess, vEvent );
+ } else {
+ /* The new vertex is in a region which does not belong to the polygon.
+ * We don''t need to connect this vertex to the rest of the mesh.
+ */
+ AddRightEdges( tess, regUp, vEvent->anEdge, vEvent->anEdge, NULL, TRUE );
+ }
+}
+
+
+static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent )
+/*
+ * Does everything necessary when the sweep line crosses a vertex.
+ * Updates the mesh and the edge dictionary.
+ */
+{
+ ActiveRegion *regUp, *reg;
+ GLUhalfEdge *e, *eTopLeft, *eBottomLeft;
+
+ tess->event = vEvent; /* for access in EdgeLeq() */
+ DebugEvent( tess );
+
+ /* Check if this vertex is the right endpoint of an edge that is
+ * already in the dictionary. In this case we don't need to waste
+ * time searching for the location to insert new edges.
+ */
+ e = vEvent->anEdge;
+ while( e->activeRegion == NULL ) {
+ e = e->Onext;
+ if( e == vEvent->anEdge ) {
+ /* All edges go right -- not incident to any processed edges */
+ ConnectLeftVertex( tess, vEvent );
+ return;
+ }
+ }
+
+ /* Processing consists of two phases: first we "finish" all the
+ * active regions where both the upper and lower edges terminate
+ * at vEvent (ie. vEvent is closing off these regions).
+ * We mark these faces "inside" or "outside" the polygon according
+ * to their winding number, and delete the edges from the dictionary.
+ * This takes care of all the left-going edges from vEvent.
+ */
+ regUp = TopLeftRegion( e->activeRegion );
+ if (regUp == NULL) longjmp(tess->env,1);
+ reg = RegionBelow( regUp );
+ eTopLeft = reg->eUp;
+ eBottomLeft = FinishLeftRegions( tess, reg, NULL );
+
+ /* Next we process all the right-going edges from vEvent. This
+ * involves adding the edges to the dictionary, and creating the
+ * associated "active regions" which record information about the
+ * regions between adjacent dictionary edges.
+ */
+ if( eBottomLeft->Onext == eTopLeft ) {
+ /* No right-going edges -- add a temporary "fixable" edge */
+ ConnectRightVertex( tess, regUp, eBottomLeft );
+ } else {
+ AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE );
+ }
+}
+
+
+/* Make the sentinel coordinates big enough that they will never be
+ * merged with real input features. (Even with the largest possible
+ * input contour and the maximum tolerance of 1.0, no merging will be
+ * done with coordinates larger than 3 * GLU_TESS_MAX_COORD).
+ */
+#define SENTINEL_COORD (4 * GLU_TESS_MAX_COORD)
+
+static void AddSentinel( GLUtesselator *tess, GLdouble t )
+/*
+ * We add two sentinel edges above and below all other edges,
+ * to avoid special cases at the top and bottom.
+ */
+{
+ GLUhalfEdge *e;
+ ActiveRegion *reg = (ActiveRegion *)memAlloc( sizeof( ActiveRegion ));
+ if (reg == NULL) longjmp(tess->env,1);
+
+ e = __gl_meshMakeEdge( tess->mesh );
+ if (e == NULL) longjmp(tess->env,1);
+
+ e->Org->s = SENTINEL_COORD;
+ e->Org->t = t;
+ e->Dst->s = -SENTINEL_COORD;
+ e->Dst->t = t;
+ tess->event = e->Dst; /* initialize it */
+
+ reg->eUp = e;
+ reg->windingNumber = 0;
+ reg->inside = FALSE;
+ reg->fixUpperEdge = FALSE;
+ reg->sentinel = TRUE;
+ reg->dirty = FALSE;
+ reg->nodeUp = dictInsert( tess->dict, reg ); /* __gl_dictListInsertBefore */
+ if (reg->nodeUp == NULL) longjmp(tess->env,1);
+}
+
+
+static void InitEdgeDict( GLUtesselator *tess )
+/*
+ * We maintain an ordering of edge intersections with the sweep line.
+ * This order is maintained in a dynamic dictionary.
+ */
+{
+ /* __gl_dictListNewDict */
+ tess->dict = dictNewDict( tess, (int (*)(void *, DictKey, DictKey)) EdgeLeq );
+ if (tess->dict == NULL) longjmp(tess->env,1);
+
+ AddSentinel( tess, -SENTINEL_COORD );
+ AddSentinel( tess, SENTINEL_COORD );
+}
+
+
+static void DoneEdgeDict( GLUtesselator *tess )
+{
+ ActiveRegion *reg;
+#ifndef NDEBUG
+ int fixedEdges = 0;
+#endif
+
+ /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */
+ while( (reg = (ActiveRegion *)dictKey( dictMin( tess->dict ))) != NULL ) {
+ /*
+ * At the end of all processing, the dictionary should contain
+ * only the two sentinel edges, plus at most one "fixable" edge
+ * created by ConnectRightVertex().
+ */
+ if( ! reg->sentinel ) {
+ assert( reg->fixUpperEdge );
+ assert( ++fixedEdges == 1 );
+ }
+ assert( reg->windingNumber == 0 );
+ DeleteRegion( tess, reg );
+/* __gl_meshDelete( reg->eUp );*/
+ }
+ dictDeleteDict( tess->dict ); /* __gl_dictListDeleteDict */
+}
+
+
+static void RemoveDegenerateEdges( GLUtesselator *tess )
+/*
+ * Remove zero-length edges, and contours with fewer than 3 vertices.
+ */
+{
+ GLUhalfEdge *e, *eNext, *eLnext;
+ GLUhalfEdge *eHead = &tess->mesh->eHead;
+
+ /*LINTED*/
+ for( e = eHead->next; e != eHead; e = eNext ) {
+ eNext = e->next;
+ eLnext = e->Lnext;
+
+ if( VertEq( e->Org, e->Dst ) && e->Lnext->Lnext != e ) {
+ /* Zero-length edge, contour has at least 3 edges */
+
+ SpliceMergeVertices( tess, eLnext, e ); /* deletes e->Org */
+ if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1); /* e is a self-loop */
+ e = eLnext;
+ eLnext = e->Lnext;
+ }
+ if( eLnext->Lnext == e ) {
+ /* Degenerate contour (one or two edges) */
+
+ if( eLnext != e ) {
+ if( eLnext == eNext || eLnext == eNext->Sym ) { eNext = eNext->next; }
+ if ( !__gl_meshDelete( eLnext ) ) longjmp(tess->env,1);
+ }
+ if( e == eNext || e == eNext->Sym ) { eNext = eNext->next; }
+ if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1);
+ }
+ }
+}
+
+static int InitPriorityQ( GLUtesselator *tess )
+/*
+ * Insert all vertices into the priority queue which determines the
+ * order in which vertices cross the sweep line.
+ */
+{
+ PriorityQ *pq;
+ GLUvertex *v, *vHead;
+
+ /* __gl_pqSortNewPriorityQ */
+ pq = tess->pq = pqNewPriorityQ( (int (*)(PQkey, PQkey)) __gl_vertLeq );
+ if (pq == NULL) return 0;
+
+ vHead = &tess->mesh->vHead;
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ v->pqHandle = pqInsert( pq, v ); /* __gl_pqSortInsert */
+ if (v->pqHandle == LONG_MAX) break;
+ }
+ if (v != vHead || !pqInit( pq ) ) { /* __gl_pqSortInit */
+ pqDeletePriorityQ(tess->pq); /* __gl_pqSortDeletePriorityQ */
+ tess->pq = NULL;
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static void DonePriorityQ( GLUtesselator *tess )
+{
+ pqDeletePriorityQ( tess->pq ); /* __gl_pqSortDeletePriorityQ */
+}
+
+
+static int RemoveDegenerateFaces( GLUmesh *mesh )
+/*
+ * Delete any degenerate faces with only two edges. WalkDirtyRegions()
+ * will catch almost all of these, but it won't catch degenerate faces
+ * produced by splice operations on already-processed edges.
+ * The two places this can happen are in FinishLeftRegions(), when
+ * we splice in a "temporary" edge produced by ConnectRightVertex(),
+ * and in CheckForLeftSplice(), where we splice already-processed
+ * edges to ensure that our dictionary invariants are not violated
+ * by numerical errors.
+ *
+ * In both these cases it is *very* dangerous to delete the offending
+ * edge at the time, since one of the routines further up the stack
+ * will sometimes be keeping a pointer to that edge.
+ */
+{
+ GLUface *f, *fNext;
+ GLUhalfEdge *e;
+
+ /*LINTED*/
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
+ fNext = f->next;
+ e = f->anEdge;
+ assert( e->Lnext != e );
+
+ if( e->Lnext->Lnext == e ) {
+ /* A face with only two edges */
+ AddWinding( e->Onext, e );
+ if ( !__gl_meshDelete( e ) ) return 0;
+ }
+ }
+ return 1;
+}
+
+int __gl_computeInterior( GLUtesselator *tess )
+/*
+ * __gl_computeInterior( tess ) computes the planar arrangement specified
+ * by the given contours, and further subdivides this arrangement
+ * into regions. Each region is marked "inside" if it belongs
+ * to the polygon, according to the rule given by tess->windingRule.
+ * Each interior region is guaranteed be monotone.
+ */
+{
+ GLUvertex *v, *vNext;
+
+ tess->fatalError = FALSE;
+
+ /* Each vertex defines an event for our sweep line. Start by inserting
+ * all the vertices in a priority queue. Events are processed in
+ * lexicographic order, ie.
+ *
+ * e1 < e2 iff e1.x < e2.x || (e1.x == e2.x && e1.y < e2.y)
+ */
+ RemoveDegenerateEdges( tess );
+ if ( !InitPriorityQ( tess ) ) return 0; /* if error */
+ InitEdgeDict( tess );
+
+ /* __gl_pqSortExtractMin */
+ while( (v = (GLUvertex *)pqExtractMin( tess->pq )) != NULL ) {
+ for( ;; ) {
+ vNext = (GLUvertex *)pqMinimum( tess->pq ); /* __gl_pqSortMinimum */
+ if( vNext == NULL || ! VertEq( vNext, v )) break;
+
+ /* Merge together all vertices at exactly the same location.
+ * This is more efficient than processing them one at a time,
+ * simplifies the code (see ConnectLeftDegenerate), and is also
+ * important for correct handling of certain degenerate cases.
+ * For example, suppose there are two identical edges A and B
+ * that belong to different contours (so without this code they would
+ * be processed by separate sweep events). Suppose another edge C
+ * crosses A and B from above. When A is processed, we split it
+ * at its intersection point with C. However this also splits C,
+ * so when we insert B we may compute a slightly different
+ * intersection point. This might leave two edges with a small
+ * gap between them. This kind of error is especially obvious
+ * when using boundary extraction (GLU_TESS_BOUNDARY_ONLY).
+ */
+ vNext = (GLUvertex *)pqExtractMin( tess->pq ); /* __gl_pqSortExtractMin*/
+ SpliceMergeVertices( tess, v->anEdge, vNext->anEdge );
+ }
+ SweepEvent( tess, v );
+ }
+
+ /* Set tess->event for debugging purposes */
+ /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */
+ tess->event = ((ActiveRegion *) dictKey( dictMin( tess->dict )))->eUp->Org;
+ DebugEvent( tess );
+ DoneEdgeDict( tess );
+ DonePriorityQ( tess );
+
+ if ( !RemoveDegenerateFaces( tess->mesh ) ) return 0;
+ __gl_meshCheckMesh( tess->mesh );
+
+ return 1;
+}
diff --git a/third_party/glu/libtess/sweep.h b/third_party/glu/libtess/sweep.h
new file mode 100644
index 0000000..75d3e64
--- /dev/null
+++ b/third_party/glu/libtess/sweep.h
@@ -0,0 +1,84 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/sweep.h#5 $
+*/
+
+#ifndef __sweep_h_
+#define __sweep_h_
+
+#include "mesh.h"
+
+/* __gl_computeInterior( tess ) computes the planar arrangement specified
+ * by the given contours, and further subdivides this arrangement
+ * into regions. Each region is marked "inside" if it belongs
+ * to the polygon, according to the rule given by tess->windingRule.
+ * Each interior region is guaranteed be monotone.
+ */
+int __gl_computeInterior( GLUtesselator *tess );
+
+
+/* The following is here *only* for access by debugging routines */
+
+#include "dict.h"
+
+/* For each pair of adjacent edges crossing the sweep line, there is
+ * an ActiveRegion to represent the region between them. The active
+ * regions are kept in sorted order in a dynamic dictionary. As the
+ * sweep line crosses each vertex, we update the affected regions.
+ */
+
+struct ActiveRegion {
+ GLUhalfEdge *eUp; /* upper edge, directed right to left */
+ DictNode *nodeUp; /* dictionary node corresponding to eUp */
+ int windingNumber; /* used to determine which regions are
+ * inside the polygon */
+ GLboolean inside; /* is this region inside the polygon? */
+ GLboolean sentinel; /* marks fake edges at t = +/-infinity */
+ GLboolean dirty; /* marks regions where the upper or lower
+ * edge has changed, but we haven't checked
+ * whether they intersect yet */
+ GLboolean fixUpperEdge; /* marks temporary edges introduced when
+ * we process a "right vertex" (one without
+ * any edges leaving to the right) */
+};
+
+#define RegionBelow(r) ((ActiveRegion *) dictKey(dictPred((r)->nodeUp)))
+#define RegionAbove(r) ((ActiveRegion *) dictKey(dictSucc((r)->nodeUp)))
+
+#endif
diff --git a/third_party/glu/libtess/tess.c b/third_party/glu/libtess/tess.c
new file mode 100644
index 0000000..c59a178
--- /dev/null
+++ b/third_party/glu/libtess/tess.c
@@ -0,0 +1,638 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/tess.c#7 $
+*/
+
+#include "gluos.h"
+#include <stddef.h>
+#include <assert.h>
+#include <setjmp.h>
+#include "memalloc.h"
+#include "tess.h"
+#include "mesh.h"
+#include "normal.h"
+#include "sweep.h"
+#include "tessmono.h"
+#include "render.h"
+
+#define GLU_TESS_DEFAULT_TOLERANCE 0.0
+#define GLU_TESS_MESH 100112 /* void (*)(GLUmesh *mesh) */
+
+#define TRUE 1
+#define FALSE 0
+
+/*ARGSUSED*/ static void GLAPIENTRY noBegin( GLenum type ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noEdgeFlag( GLboolean boundaryEdge ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noVertex( void *data ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noEnd( void ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noError( GLenum errnum ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noCombine( GLdouble coords[3], void *data[4],
+ GLfloat weight[4], void **dataOut ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noMesh( GLUmesh *mesh ) {}
+
+
+/*ARGSUSED*/ void GLAPIENTRY __gl_noBeginData( GLenum type,
+ void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge,
+ void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noVertexData( void *data,
+ void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noEndData( void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noErrorData( GLenum errnum,
+ void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noCombineData( GLdouble coords[3],
+ void *data[4],
+ GLfloat weight[4],
+ void **outData,
+ void *polygonData ) {}
+
+/* Half-edges are allocated in pairs (see mesh.c) */
+typedef struct { GLUhalfEdge e, eSym; } EdgePair;
+
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define MAX_FAST_ALLOC (MAX(sizeof(EdgePair), \
+ MAX(sizeof(GLUvertex),sizeof(GLUface))))
+
+
+GLUtesselator * GLAPIENTRY
+gluNewTess( void )
+{
+ GLUtesselator *tess;
+
+ /* Only initialize fields which can be changed by the api. Other fields
+ * are initialized where they are used.
+ */
+
+ if (memInit( MAX_FAST_ALLOC ) == 0) {
+ return 0; /* out of memory */
+ }
+ tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator ));
+ if (tess == NULL) {
+ return 0; /* out of memory */
+ }
+
+ tess->state = T_DORMANT;
+
+ tess->normal[0] = 0;
+ tess->normal[1] = 0;
+ tess->normal[2] = 0;
+
+ tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE;
+ tess->windingRule = GLU_TESS_WINDING_ODD;
+ tess->flagBoundary = FALSE;
+ tess->boundaryOnly = FALSE;
+
+ tess->callBegin = &noBegin;
+ tess->callEdgeFlag = &noEdgeFlag;
+ tess->callVertex = &noVertex;
+ tess->callEnd = &noEnd;
+
+ tess->callError = &noError;
+ tess->callCombine = &noCombine;
+ tess->callMesh = &noMesh;
+
+ tess->callBeginData= &__gl_noBeginData;
+ tess->callEdgeFlagData= &__gl_noEdgeFlagData;
+ tess->callVertexData= &__gl_noVertexData;
+ tess->callEndData= &__gl_noEndData;
+ tess->callErrorData= &__gl_noErrorData;
+ tess->callCombineData= &__gl_noCombineData;
+
+ tess->polygonData= NULL;
+
+ return tess;
+}
+
+static void MakeDormant( GLUtesselator *tess )
+{
+ /* Return the tessellator to its original dormant state. */
+
+ if( tess->mesh != NULL ) {
+ __gl_meshDeleteMesh( tess->mesh );
+ }
+ tess->state = T_DORMANT;
+ tess->lastEdge = NULL;
+ tess->mesh = NULL;
+}
+
+#define RequireState( tess, s ) if( tess->state != s ) GotoState(tess,s)
+
+static void GotoState( GLUtesselator *tess, enum TessState newState )
+{
+ while( tess->state != newState ) {
+ /* We change the current state one level at a time, to get to
+ * the desired state.
+ */
+ if( tess->state < newState ) {
+ switch( tess->state ) {
+ case T_DORMANT:
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON );
+ gluTessBeginPolygon( tess, NULL );
+ break;
+ case T_IN_POLYGON:
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR );
+ gluTessBeginContour( tess );
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ } else {
+ switch( tess->state ) {
+ case T_IN_CONTOUR:
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR );
+ gluTessEndContour( tess );
+ break;
+ case T_IN_POLYGON:
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON );
+ /* gluTessEndPolygon( tess ) is too much work! */
+ MakeDormant( tess );
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+ }
+}
+
+
+void GLAPIENTRY
+gluDeleteTess( GLUtesselator *tess )
+{
+ RequireState( tess, T_DORMANT );
+ memFree( tess );
+}
+
+
+void GLAPIENTRY
+gluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value )
+{
+ GLenum windingRule;
+
+ switch( which ) {
+ case GLU_TESS_TOLERANCE:
+ if( value < 0.0 || value > 1.0 ) break;
+ tess->relTolerance = value;
+ return;
+
+ case GLU_TESS_WINDING_RULE:
+ windingRule = (GLenum) value;
+ if( windingRule != value ) break; /* not an integer */
+
+ switch( windingRule ) {
+ case GLU_TESS_WINDING_ODD:
+ case GLU_TESS_WINDING_NONZERO:
+ case GLU_TESS_WINDING_POSITIVE:
+ case GLU_TESS_WINDING_NEGATIVE:
+ case GLU_TESS_WINDING_ABS_GEQ_TWO:
+ tess->windingRule = windingRule;
+ return;
+ default:
+ break;
+ }
+
+ case GLU_TESS_BOUNDARY_ONLY:
+ tess->boundaryOnly = (value != 0);
+ return;
+
+ default:
+ CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
+ return;
+ }
+ CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE );
+}
+
+/* Returns tessellator property */
+void GLAPIENTRY
+gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value )
+{
+ switch (which) {
+ case GLU_TESS_TOLERANCE:
+ /* tolerance should be in range [0..1] */
+ assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0);
+ *value= tess->relTolerance;
+ break;
+ case GLU_TESS_WINDING_RULE:
+ assert(tess->windingRule == GLU_TESS_WINDING_ODD ||
+ tess->windingRule == GLU_TESS_WINDING_NONZERO ||
+ tess->windingRule == GLU_TESS_WINDING_POSITIVE ||
+ tess->windingRule == GLU_TESS_WINDING_NEGATIVE ||
+ tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO);
+ *value= tess->windingRule;
+ break;
+ case GLU_TESS_BOUNDARY_ONLY:
+ assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE);
+ *value= tess->boundaryOnly;
+ break;
+ default:
+ *value= 0.0;
+ CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
+ break;
+ }
+} /* gluGetTessProperty() */
+
+void GLAPIENTRY
+gluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z )
+{
+ tess->normal[0] = x;
+ tess->normal[1] = y;
+ tess->normal[2] = z;
+}
+
+void GLAPIENTRY
+gluTessCallback( GLUtesselator *tess, GLenum which, void (GLAPIENTRY *fn)())
+{
+ switch( which ) {
+ case GLU_TESS_BEGIN:
+ tess->callBegin = (fn == NULL) ? &noBegin : (void (GLAPIENTRY *)(GLenum)) fn;
+ return;
+ case GLU_TESS_BEGIN_DATA:
+ tess->callBeginData = (fn == NULL) ?
+ &__gl_noBeginData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
+ return;
+ case GLU_TESS_EDGE_FLAG:
+ tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag :
+ (void (GLAPIENTRY *)(GLboolean)) fn;
+ /* If the client wants boundary edges to be flagged,
+ * we render everything as separate triangles (no strips or fans).
+ */
+ tess->flagBoundary = (fn != NULL);
+ return;
+ case GLU_TESS_EDGE_FLAG_DATA:
+ tess->callEdgeFlagData= (fn == NULL) ?
+ &__gl_noEdgeFlagData : (void (GLAPIENTRY *)(GLboolean, void *)) fn;
+ /* If the client wants boundary edges to be flagged,
+ * we render everything as separate triangles (no strips or fans).
+ */
+ tess->flagBoundary = (fn != NULL);
+ return;
+ case GLU_TESS_VERTEX:
+ tess->callVertex = (fn == NULL) ? &noVertex :
+ (void (GLAPIENTRY *)(void *)) fn;
+ return;
+ case GLU_TESS_VERTEX_DATA:
+ tess->callVertexData = (fn == NULL) ?
+ &__gl_noVertexData : (void (GLAPIENTRY *)(void *, void *)) fn;
+ return;
+ case GLU_TESS_END:
+ tess->callEnd = (fn == NULL) ? &noEnd : (void (GLAPIENTRY *)(void)) fn;
+ return;
+ case GLU_TESS_END_DATA:
+ tess->callEndData = (fn == NULL) ? &__gl_noEndData :
+ (void (GLAPIENTRY *)(void *)) fn;
+ return;
+ case GLU_TESS_ERROR:
+ tess->callError = (fn == NULL) ? &noError : (void (GLAPIENTRY *)(GLenum)) fn;
+ return;
+ case GLU_TESS_ERROR_DATA:
+ tess->callErrorData = (fn == NULL) ?
+ &__gl_noErrorData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
+ return;
+ case GLU_TESS_COMBINE:
+ tess->callCombine = (fn == NULL) ? &noCombine :
+ (void (GLAPIENTRY *)(GLdouble [3],void *[4], GLfloat [4], void ** )) fn;
+ return;
+ case GLU_TESS_COMBINE_DATA:
+ tess->callCombineData = (fn == NULL) ? &__gl_noCombineData :
+ (void (GLAPIENTRY *)(GLdouble [3],
+ void *[4],
+ GLfloat [4],
+ void **,
+ void *)) fn;
+ return;
+ case GLU_TESS_MESH:
+ tess->callMesh = (fn == NULL) ? &noMesh : (void (GLAPIENTRY *)(GLUmesh *)) fn;
+ return;
+ default:
+ CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
+ return;
+ }
+}
+
+static int AddVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
+{
+ GLUhalfEdge *e;
+
+ e = tess->lastEdge;
+ if( e == NULL ) {
+ /* Make a self-loop (one vertex, one edge). */
+
+ e = __gl_meshMakeEdge( tess->mesh );
+ if (e == NULL) return 0;
+ if ( !__gl_meshSplice( e, e->Sym ) ) return 0;
+ } else {
+ /* Create a new vertex and edge which immediately follow e
+ * in the ordering around the left face.
+ */
+ if (__gl_meshSplitEdge( e ) == NULL) return 0;
+ e = e->Lnext;
+ }
+
+ /* The new vertex is now e->Org. */
+ e->Org->data = data;
+ e->Org->coords[0] = coords[0];
+ e->Org->coords[1] = coords[1];
+ e->Org->coords[2] = coords[2];
+
+ /* The winding of an edge says how the winding number changes as we
+ * cross from the edge''s right face to its left face. We add the
+ * vertices in such an order that a CCW contour will add +1 to
+ * the winding number of the region inside the contour.
+ */
+ e->winding = 1;
+ e->Sym->winding = -1;
+
+ tess->lastEdge = e;
+
+ return 1;
+}
+
+
+static void CacheVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
+{
+ CachedVertex *v = &tess->cache[tess->cacheCount];
+
+ v->data = data;
+ v->coords[0] = coords[0];
+ v->coords[1] = coords[1];
+ v->coords[2] = coords[2];
+ ++tess->cacheCount;
+}
+
+
+static int EmptyCache( GLUtesselator *tess )
+{
+ CachedVertex *v = tess->cache;
+ CachedVertex *vLast;
+
+ tess->mesh = __gl_meshNewMesh();
+ if (tess->mesh == NULL) return 0;
+
+ for( vLast = v + tess->cacheCount; v < vLast; ++v ) {
+ if ( !AddVertex( tess, v->coords, v->data ) ) return 0;
+ }
+ tess->cacheCount = 0;
+ tess->emptyCache = FALSE;
+
+ return 1;
+}
+
+
+void GLAPIENTRY
+gluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
+{
+ int i, tooLarge = FALSE;
+ GLdouble x, clamped[3];
+
+ RequireState( tess, T_IN_CONTOUR );
+
+ if( tess->emptyCache ) {
+ if ( !EmptyCache( tess ) ) {
+ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+ return;
+ }
+ tess->lastEdge = NULL;
+ }
+ for( i = 0; i < 3; ++i ) {
+ x = coords[i];
+ if( x < - GLU_TESS_MAX_COORD ) {
+ x = - GLU_TESS_MAX_COORD;
+ tooLarge = TRUE;
+ }
+ if( x > GLU_TESS_MAX_COORD ) {
+ x = GLU_TESS_MAX_COORD;
+ tooLarge = TRUE;
+ }
+ clamped[i] = x;
+ }
+ if( tooLarge ) {
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE );
+ }
+
+ if( tess->mesh == NULL ) {
+ if( tess->cacheCount < TESS_MAX_CACHE ) {
+ CacheVertex( tess, clamped, data );
+ return;
+ }
+ if ( !EmptyCache( tess ) ) {
+ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+ return;
+ }
+ }
+ if ( !AddVertex( tess, clamped, data ) ) {
+ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+ }
+}
+
+
+void GLAPIENTRY
+gluTessBeginPolygon( GLUtesselator *tess, void *data )
+{
+ RequireState( tess, T_DORMANT );
+
+ tess->state = T_IN_POLYGON;
+ tess->cacheCount = 0;
+ tess->emptyCache = FALSE;
+ tess->mesh = NULL;
+
+ tess->polygonData= data;
+}
+
+
+void GLAPIENTRY
+gluTessBeginContour( GLUtesselator *tess )
+{
+ RequireState( tess, T_IN_POLYGON );
+
+ tess->state = T_IN_CONTOUR;
+ tess->lastEdge = NULL;
+ if( tess->cacheCount > 0 ) {
+ /* Just set a flag so we don't get confused by empty contours
+ * -- these can be generated accidentally with the obsolete
+ * NextContour() interface.
+ */
+ tess->emptyCache = TRUE;
+ }
+}
+
+
+void GLAPIENTRY
+gluTessEndContour( GLUtesselator *tess )
+{
+ RequireState( tess, T_IN_CONTOUR );
+ tess->state = T_IN_POLYGON;
+}
+
+void GLAPIENTRY
+gluTessEndPolygon( GLUtesselator *tess )
+{
+ GLUmesh *mesh;
+
+ if (setjmp(tess->env) != 0) {
+ /* come back here if out of memory */
+ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+ return;
+ }
+
+ RequireState( tess, T_IN_POLYGON );
+ tess->state = T_DORMANT;
+
+ if( tess->mesh == NULL ) {
+ if( ! tess->flagBoundary && tess->callMesh == &noMesh ) {
+
+ /* Try some special code to make the easy cases go quickly
+ * (eg. convex polygons). This code does NOT handle multiple contours,
+ * intersections, edge flags, and of course it does not generate
+ * an explicit mesh either.
+ */
+ if( __gl_renderCache( tess )) {
+ tess->polygonData= NULL;
+ return;
+ }
+ }
+ if ( !EmptyCache( tess ) ) longjmp(tess->env,1); /* could've used a label*/
+ }
+
+ /* Determine the polygon normal and project vertices onto the plane
+ * of the polygon.
+ */
+ __gl_projectPolygon( tess );
+
+ /* __gl_computeInterior( tess ) computes the planar arrangement specified
+ * by the given contours, and further subdivides this arrangement
+ * into regions. Each region is marked "inside" if it belongs
+ * to the polygon, according to the rule given by tess->windingRule.
+ * Each interior region is guaranteed be monotone.
+ */
+ if ( !__gl_computeInterior( tess ) ) {
+ longjmp(tess->env,1); /* could've used a label */
+ }
+
+ mesh = tess->mesh;
+ if( ! tess->fatalError ) {
+ int rc = 1;
+
+ /* If the user wants only the boundary contours, we throw away all edges
+ * except those which separate the interior from the exterior.
+ * Otherwise we tessellate all the regions marked "inside".
+ */
+ if( tess->boundaryOnly ) {
+ rc = __gl_meshSetWindingNumber( mesh, 1, TRUE );
+ } else {
+ rc = __gl_meshTessellateInterior( mesh );
+ }
+ if (rc == 0) longjmp(tess->env,1); /* could've used a label */
+
+ __gl_meshCheckMesh( mesh );
+
+ if( tess->callBegin != &noBegin || tess->callEnd != &noEnd
+ || tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag
+ || tess->callBeginData != &__gl_noBeginData
+ || tess->callEndData != &__gl_noEndData
+ || tess->callVertexData != &__gl_noVertexData
+ || tess->callEdgeFlagData != &__gl_noEdgeFlagData )
+ {
+ if( tess->boundaryOnly ) {
+ __gl_renderBoundary( tess, mesh ); /* output boundary contours */
+ } else {
+ __gl_renderMesh( tess, mesh ); /* output strips and fans */
+ }
+ }
+ if( tess->callMesh != &noMesh ) {
+
+ /* Throw away the exterior faces, so that all faces are interior.
+ * This way the user doesn't have to check the "inside" flag,
+ * and we don't need to even reveal its existence. It also leaves
+ * the freedom for an implementation to not generate the exterior
+ * faces in the first place.
+ */
+ __gl_meshDiscardExterior( mesh );
+ (*tess->callMesh)( mesh ); /* user wants the mesh itself */
+ tess->mesh = NULL;
+ tess->polygonData= NULL;
+ return;
+ }
+ }
+ __gl_meshDeleteMesh( mesh );
+ tess->polygonData= NULL;
+ tess->mesh = NULL;
+}
+
+
+/*XXXblythe unused function*/
+#if 0
+void GLAPIENTRY
+gluDeleteMesh( GLUmesh *mesh )
+{
+ __gl_meshDeleteMesh( mesh );
+}
+#endif
+
+
+
+/*******************************************************/
+
+/* Obsolete calls -- for backward compatibility */
+
+#if 0
+void GLAPIENTRY
+gluBeginPolygon( GLUtesselator *tess )
+{
+ gluTessBeginPolygon( tess, NULL );
+ gluTessBeginContour( tess );
+}
+
+
+/*ARGSUSED*/
+void GLAPIENTRY
+gluNextContour( GLUtesselator *tess, GLenum type )
+{
+ gluTessEndContour( tess );
+ gluTessBeginContour( tess );
+}
+
+
+void GLAPIENTRY
+gluEndPolygon( GLUtesselator *tess )
+{
+ gluTessEndContour( tess );
+ gluTessEndPolygon( tess );
+}
+#endif
diff --git a/third_party/glu/libtess/tess.h b/third_party/glu/libtess/tess.h
new file mode 100644
index 0000000..d8d3d21
--- /dev/null
+++ b/third_party/glu/libtess/tess.h
@@ -0,0 +1,172 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/tess.h#6 $
+*/
+
+#ifndef __tess_h_
+#define __tess_h_
+
+#include <sk_glu.h>
+#include <setjmp.h>
+#include "mesh.h"
+#include "dict.h"
+#include "priorityq.h"
+
+/* The begin/end calls must be properly nested. We keep track of
+ * the current state to enforce the ordering.
+ */
+enum TessState { T_DORMANT, T_IN_POLYGON, T_IN_CONTOUR };
+
+/* We cache vertex data for single-contour polygons so that we can
+ * try a quick-and-dirty decomposition first.
+ */
+#define TESS_MAX_CACHE 100
+
+typedef struct CachedVertex {
+ GLdouble coords[3];
+ void *data;
+} CachedVertex;
+
+struct GLUtesselator {
+
+ /*** state needed for collecting the input data ***/
+
+ enum TessState state; /* what begin/end calls have we seen? */
+
+ GLUhalfEdge *lastEdge; /* lastEdge->Org is the most recent vertex */
+ GLUmesh *mesh; /* stores the input contours, and eventually
+ the tessellation itself */
+
+ void (GLAPIENTRY *callError)( GLenum errnum );
+
+ /*** state needed for projecting onto the sweep plane ***/
+
+ GLdouble normal[3]; /* user-specified normal (if provided) */
+ GLdouble sUnit[3]; /* unit vector in s-direction (debugging) */
+ GLdouble tUnit[3]; /* unit vector in t-direction (debugging) */
+
+ /*** state needed for the line sweep ***/
+
+ GLdouble relTolerance; /* tolerance for merging features */
+ GLenum windingRule; /* rule for determining polygon interior */
+ GLboolean fatalError; /* fatal error: needed combine callback */
+
+ Dict *dict; /* edge dictionary for sweep line */
+ PriorityQ *pq; /* priority queue of vertex events */
+ GLUvertex *event; /* current sweep event being processed */
+
+ void (GLAPIENTRY *callCombine)( GLdouble coords[3], void *data[4],
+ GLfloat weight[4], void **outData );
+
+ /*** state needed for rendering callbacks (see render.c) ***/
+
+ GLboolean flagBoundary; /* mark boundary edges (use EdgeFlag) */
+ GLboolean boundaryOnly; /* Extract contours, not triangles */
+ GLUface *lonelyTriList;
+ /* list of triangles which could not be rendered as strips or fans */
+
+ void (GLAPIENTRY *callBegin)( GLenum type );
+ void (GLAPIENTRY *callEdgeFlag)( GLboolean boundaryEdge );
+ void (GLAPIENTRY *callVertex)( void *data );
+ void (GLAPIENTRY *callEnd)( void );
+ void (GLAPIENTRY *callMesh)( GLUmesh *mesh );
+
+
+ /*** state needed to cache single-contour polygons for renderCache() */
+
+ GLboolean emptyCache; /* empty cache on next vertex() call */
+ int cacheCount; /* number of cached vertices */
+ CachedVertex cache[TESS_MAX_CACHE]; /* the vertex data */
+
+ /*** rendering callbacks that also pass polygon data ***/
+ void (GLAPIENTRY *callBeginData)( GLenum type, void *polygonData );
+ void (GLAPIENTRY *callEdgeFlagData)( GLboolean boundaryEdge,
+ void *polygonData );
+ void (GLAPIENTRY *callVertexData)( void *data, void *polygonData );
+ void (GLAPIENTRY *callEndData)( void *polygonData );
+ void (GLAPIENTRY *callErrorData)( GLenum errnum, void *polygonData );
+ void (GLAPIENTRY *callCombineData)( GLdouble coords[3], void *data[4],
+ GLfloat weight[4], void **outData,
+ void *polygonData );
+
+ jmp_buf env; /* place to jump to when memAllocs fail */
+
+ void *polygonData; /* client data for current polygon */
+};
+
+void GLAPIENTRY __gl_noBeginData( GLenum type, void *polygonData );
+void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, void *polygonData );
+void GLAPIENTRY __gl_noVertexData( void *data, void *polygonData );
+void GLAPIENTRY __gl_noEndData( void *polygonData );
+void GLAPIENTRY __gl_noErrorData( GLenum errnum, void *polygonData );
+void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], void *data[4],
+ GLfloat weight[4], void **outData,
+ void *polygonData );
+
+#define CALL_BEGIN_OR_BEGIN_DATA(a) \
+ if (tess->callBeginData != &__gl_noBeginData) \
+ (*tess->callBeginData)((a),tess->polygonData); \
+ else (*tess->callBegin)((a));
+
+#define CALL_VERTEX_OR_VERTEX_DATA(a) \
+ if (tess->callVertexData != &__gl_noVertexData) \
+ (*tess->callVertexData)((a),tess->polygonData); \
+ else (*tess->callVertex)((a));
+
+#define CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA(a) \
+ if (tess->callEdgeFlagData != &__gl_noEdgeFlagData) \
+ (*tess->callEdgeFlagData)((a),tess->polygonData); \
+ else (*tess->callEdgeFlag)((a));
+
+#define CALL_END_OR_END_DATA() \
+ if (tess->callEndData != &__gl_noEndData) \
+ (*tess->callEndData)(tess->polygonData); \
+ else (*tess->callEnd)();
+
+#define CALL_COMBINE_OR_COMBINE_DATA(a,b,c,d) \
+ if (tess->callCombineData != &__gl_noCombineData) \
+ (*tess->callCombineData)((a),(b),(c),(d),tess->polygonData); \
+ else (*tess->callCombine)((a),(b),(c),(d));
+
+#define CALL_ERROR_OR_ERROR_DATA(a) \
+ if (tess->callErrorData != &__gl_noErrorData) \
+ (*tess->callErrorData)((a),tess->polygonData); \
+ else (*tess->callError)((a));
+
+#endif
diff --git a/third_party/glu/libtess/tessmono.c b/third_party/glu/libtess/tessmono.c
new file mode 100644
index 0000000..2e2cc79
--- /dev/null
+++ b/third_party/glu/libtess/tessmono.c
@@ -0,0 +1,208 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/tessmono.c#5 $
+*/
+
+#include "gluos.h"
+#include <stdlib.h>
+#include "geom.h"
+#include "mesh.h"
+#include "tessmono.h"
+#include <assert.h>
+
+#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \
+ eDst->Sym->winding += eSrc->Sym->winding)
+
+/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
+ * (what else would it do??) The region must consist of a single
+ * loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
+ * case means that any vertical line intersects the interior of the
+ * region in a single interval.
+ *
+ * Tessellation consists of adding interior edges (actually pairs of
+ * half-edges), to split the region into non-overlapping triangles.
+ *
+ * The basic idea is explained in Preparata and Shamos (which I don''t
+ * have handy right now), although their implementation is more
+ * complicated than this one. The are two edge chains, an upper chain
+ * and a lower chain. We process all vertices from both chains in order,
+ * from right to left.
+ *
+ * The algorithm ensures that the following invariant holds after each
+ * vertex is processed: the untessellated region consists of two
+ * chains, where one chain (say the upper) is a single edge, and
+ * the other chain is concave. The left vertex of the single edge
+ * is always to the left of all vertices in the concave chain.
+ *
+ * Each step consists of adding the rightmost unprocessed vertex to one
+ * of the two chains, and forming a fan of triangles from the rightmost
+ * of two chain endpoints. Determining whether we can add each triangle
+ * to the fan is a simple orientation test. By making the fan as large
+ * as possible, we restore the invariant (check it yourself).
+ */
+int __gl_meshTessellateMonoRegion( GLUface *face )
+{
+ GLUhalfEdge *up, *lo;
+
+ /* All edges are oriented CCW around the boundary of the region.
+ * First, find the half-edge whose origin vertex is rightmost.
+ * Since the sweep goes from left to right, face->anEdge should
+ * be close to the edge we want.
+ */
+ up = face->anEdge;
+ assert( up->Lnext != up && up->Lnext->Lnext != up );
+
+ for( ; VertLeq( up->Dst, up->Org ); up = up->Lprev )
+ ;
+ for( ; VertLeq( up->Org, up->Dst ); up = up->Lnext )
+ ;
+ lo = up->Lprev;
+
+ while( up->Lnext != lo ) {
+ if( VertLeq( up->Dst, lo->Org )) {
+ /* up->Dst is on the left. It is safe to form triangles from lo->Org.
+ * The EdgeGoesLeft test guarantees progress even when some triangles
+ * are CW, given that the upper and lower chains are truly monotone.
+ */
+ while( lo->Lnext != up && (EdgeGoesLeft( lo->Lnext )
+ || EdgeSign( lo->Org, lo->Dst, lo->Lnext->Dst ) <= 0 )) {
+ GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
+ if (tempHalfEdge == NULL) return 0;
+ lo = tempHalfEdge->Sym;
+ }
+ lo = lo->Lprev;
+ } else {
+ /* lo->Org is on the left. We can make CCW triangles from up->Dst. */
+ while( lo->Lnext != up && (EdgeGoesRight( up->Lprev )
+ || EdgeSign( up->Dst, up->Org, up->Lprev->Org ) >= 0 )) {
+ GLUhalfEdge *tempHalfEdge= __gl_meshConnect( up, up->Lprev );
+ if (tempHalfEdge == NULL) return 0;
+ up = tempHalfEdge->Sym;
+ }
+ up = up->Lnext;
+ }
+ }
+
+ /* Now lo->Org == up->Dst == the leftmost vertex. The remaining region
+ * can be tessellated in a fan from this leftmost vertex.
+ */
+ assert( lo->Lnext != up );
+ while( lo->Lnext->Lnext != up ) {
+ GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
+ if (tempHalfEdge == NULL) return 0;
+ lo = tempHalfEdge->Sym;
+ }
+
+ return 1;
+}
+
+
+/* __gl_meshTessellateInterior( mesh ) tessellates each region of
+ * the mesh which is marked "inside" the polygon. Each such region
+ * must be monotone.
+ */
+int __gl_meshTessellateInterior( GLUmesh *mesh )
+{
+ GLUface *f, *next;
+
+ /*LINTED*/
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
+ /* Make sure we don''t try to tessellate the new triangles. */
+ next = f->next;
+ if( f->inside ) {
+ if ( !__gl_meshTessellateMonoRegion( f ) ) return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+/* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
+ * which are not marked "inside" the polygon. Since further mesh operations
+ * on NULL faces are not allowed, the main purpose is to clean up the
+ * mesh so that exterior loops are not represented in the data structure.
+ */
+void __gl_meshDiscardExterior( GLUmesh *mesh )
+{
+ GLUface *f, *next;
+
+ /*LINTED*/
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
+ /* Since f will be destroyed, save its next pointer. */
+ next = f->next;
+ if( ! f->inside ) {
+ __gl_meshZapFace( f );
+ }
+ }
+}
+
+#define MARKED_FOR_DELETION 0x7fffffff
+
+/* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
+ * winding numbers on all edges so that regions marked "inside" the
+ * polygon have a winding number of "value", and regions outside
+ * have a winding number of 0.
+ *
+ * If keepOnlyBoundary is TRUE, it also deletes all edges which do not
+ * separate an interior region from an exterior one.
+ */
+int __gl_meshSetWindingNumber( GLUmesh *mesh, int value,
+ GLboolean keepOnlyBoundary )
+{
+ GLUhalfEdge *e, *eNext;
+
+ for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
+ eNext = e->next;
+ if( e->Rface->inside != e->Lface->inside ) {
+
+ /* This is a boundary edge (one side is interior, one is exterior). */
+ e->winding = (e->Lface->inside) ? value : -value;
+ } else {
+
+ /* Both regions are interior, or both are exterior. */
+ if( ! keepOnlyBoundary ) {
+ e->winding = 0;
+ } else {
+ if ( !__gl_meshDelete( e ) ) return 0;
+ }
+ }
+ }
+ return 1;
+}
diff --git a/third_party/glu/libtess/tessmono.h b/third_party/glu/libtess/tessmono.h
new file mode 100644
index 0000000..6a71ee8
--- /dev/null
+++ b/third_party/glu/libtess/tessmono.h
@@ -0,0 +1,78 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/tessmono.h#5 $
+*/
+
+#ifndef __tessmono_h_
+#define __tessmono_h_
+
+/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
+ * (what else would it do??) The region must consist of a single
+ * loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
+ * case means that any vertical line intersects the interior of the
+ * region in a single interval.
+ *
+ * Tessellation consists of adding interior edges (actually pairs of
+ * half-edges), to split the region into non-overlapping triangles.
+ *
+ * __gl_meshTessellateInterior( mesh ) tessellates each region of
+ * the mesh which is marked "inside" the polygon. Each such region
+ * must be monotone.
+ *
+ * __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
+ * which are not marked "inside" the polygon. Since further mesh operations
+ * on NULL faces are not allowed, the main purpose is to clean up the
+ * mesh so that exterior loops are not represented in the data structure.
+ *
+ * __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
+ * winding numbers on all edges so that regions marked "inside" the
+ * polygon have a winding number of "value", and regions outside
+ * have a winding number of 0.
+ *
+ * If keepOnlyBoundary is TRUE, it also deletes all edges which do not
+ * separate an interior region from an exterior one.
+ */
+
+int __gl_meshTessellateMonoRegion( GLUface *face );
+int __gl_meshTessellateInterior( GLUmesh *mesh );
+void __gl_meshDiscardExterior( GLUmesh *mesh );
+int __gl_meshSetWindingNumber( GLUmesh *mesh, int value,
+ GLboolean keepOnlyBoundary );
+
+#endif
diff --git a/third_party/glu/sk_glu.h b/third_party/glu/sk_glu.h
new file mode 100644
index 0000000..7b2b261
--- /dev/null
+++ b/third_party/glu/sk_glu.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2010, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This header is a skeleton substitute for GL/glu.h which contains
+// only the definitions, constants and function declarations necessary
+// to compile the GLU tessellator.
+
+#ifndef SK_GLU_H_
+#define SK_GLU_H_
+
+#include "gluos.h"
+
+/* Primitives */
+#define GL_LINE_LOOP 0x0002
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+
+/* ErrorCode */
+#define GLU_INVALID_ENUM 100900
+#define GLU_INVALID_VALUE 100901
+#define GLU_OUT_OF_MEMORY 100902
+
+/* TessCallback */
+#define GLU_TESS_BEGIN 100100
+#define GLU_BEGIN 100100
+#define GLU_TESS_VERTEX 100101
+#define GLU_VERTEX 100101
+#define GLU_TESS_END 100102
+#define GLU_END 100102
+#define GLU_TESS_ERROR 100103
+#define GLU_TESS_EDGE_FLAG 100104
+#define GLU_EDGE_FLAG 100104
+#define GLU_TESS_COMBINE 100105
+#define GLU_TESS_BEGIN_DATA 100106
+#define GLU_TESS_VERTEX_DATA 100107
+#define GLU_TESS_END_DATA 100108
+#define GLU_TESS_ERROR_DATA 100109
+#define GLU_TESS_EDGE_FLAG_DATA 100110
+#define GLU_TESS_COMBINE_DATA 100111
+
+/* TessContour */
+#define GLU_CW 100120
+#define GLU_CCW 100121
+#define GLU_INTERIOR 100122
+#define GLU_EXTERIOR 100123
+#define GLU_UNKNOWN 100124
+
+/* TessProperty */
+#define GLU_TESS_WINDING_RULE 100140
+#define GLU_TESS_BOUNDARY_ONLY 100141
+#define GLU_TESS_TOLERANCE 100142
+
+/* TessError */
+#define GLU_TESS_ERROR1 100151
+#define GLU_TESS_ERROR2 100152
+#define GLU_TESS_ERROR3 100153
+#define GLU_TESS_ERROR4 100154
+#define GLU_TESS_ERROR5 100155
+#define GLU_TESS_ERROR6 100156
+#define GLU_TESS_ERROR7 100157
+#define GLU_TESS_ERROR8 100158
+#define GLU_TESS_MISSING_BEGIN_POLYGON 100151
+#define GLU_TESS_MISSING_BEGIN_CONTOUR 100152
+#define GLU_TESS_MISSING_END_POLYGON 100153
+#define GLU_TESS_MISSING_END_CONTOUR 100154
+#define GLU_TESS_COORD_TOO_LARGE 100155
+#define GLU_TESS_NEED_COMBINE_CALLBACK 100156
+
+/* TessWinding */
+#define GLU_TESS_WINDING_ODD 100130
+#define GLU_TESS_WINDING_NONZERO 100131
+#define GLU_TESS_WINDING_POSITIVE 100132
+#define GLU_TESS_WINDING_NEGATIVE 100133
+#define GLU_TESS_WINDING_ABS_GEQ_TWO 100134
+
+#define GLU_TESS_MAX_COORD 1.0e150
+
+typedef struct GLUtesselator GLUtesselator;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern GLUtesselator * GLAPIENTRY Sk_gluNewTess(void);
+extern void GLAPIENTRY Sk_gluDeleteTess(GLUtesselator *tess);
+extern void GLAPIENTRY Sk_gluTessProperty(GLUtesselator *tess,
+ GLenum which,
+ GLdouble value);
+extern void GLAPIENTRY Sk_gluGetTessProperty(GLUtesselator *tess,
+ GLenum which,
+ GLdouble *value);
+extern void GLAPIENTRY Sk_gluTessNormal(GLUtesselator *tess,
+ GLdouble x,
+ GLdouble y,
+ GLdouble z);
+extern void GLAPIENTRY Sk_gluTessCallback(GLUtesselator *tess,
+ GLenum which,
+ void (GLAPIENTRY *fn)());
+extern void GLAPIENTRY Sk_gluTessVertex(GLUtesselator *tess,
+ GLdouble coords[3],
+ void *data);
+extern void GLAPIENTRY Sk_gluTessBeginPolygon(GLUtesselator *tess,
+ void *data);
+extern void GLAPIENTRY Sk_gluTessBeginContour(GLUtesselator *tess);
+extern void GLAPIENTRY Sk_gluTessEndContour(GLUtesselator *tess);
+extern void GLAPIENTRY Sk_gluTessEndPolygon(GLUtesselator *tess);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SK_GLU_H_